typo 3.99.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.DS_Store +0 -0
- data/CHANGELOG +718 -0
- data/MAINTAINERS +30 -0
- data/MIT-LICENSE +21 -0
- data/README +92 -0
- data/Rakefile +10 -0
- data/app/apis/blogger_service.rb +94 -0
- data/app/apis/meta_weblog_service.rb +197 -0
- data/app/apis/movable_type_service.rb +150 -0
- data/app/apis/typo_web_service.rb +26 -0
- data/app/controllers/accounts_controller.rb +52 -0
- data/app/controllers/admin/base_controller.rb +21 -0
- data/app/controllers/admin/blacklist_controller.rb +50 -0
- data/app/controllers/admin/cache_controller.rb +31 -0
- data/app/controllers/admin/categories_controller.rb +64 -0
- data/app/controllers/admin/comments_controller.rb +57 -0
- data/app/controllers/admin/content_controller.rb +147 -0
- data/app/controllers/admin/general_controller.rb +42 -0
- data/app/controllers/admin/pages_controller.rb +50 -0
- data/app/controllers/admin/resources_controller.rb +98 -0
- data/app/controllers/admin/sidebar_controller.rb +74 -0
- data/app/controllers/admin/textfilters_controller.rb +104 -0
- data/app/controllers/admin/themes_controller.rb +20 -0
- data/app/controllers/admin/trackbacks_controller.rb +54 -0
- data/app/controllers/admin/users_controller.rb +41 -0
- data/app/controllers/application.rb +66 -0
- data/app/controllers/articles_controller.rb +218 -0
- data/app/controllers/backend_controller.rb +11 -0
- data/app/controllers/content_controller.rb +98 -0
- data/app/controllers/live_controller.rb +10 -0
- data/app/controllers/redirect_controller.rb +16 -0
- data/app/controllers/sidebar_controller.rb +50 -0
- data/app/controllers/textfilter_controller.rb +22 -0
- data/app/controllers/theme_controller.rb +52 -0
- data/app/controllers/xml_controller.rb +111 -0
- data/app/helpers/accounts_helper.rb +2 -0
- data/app/helpers/admin/base_helper.rb +124 -0
- data/app/helpers/admin/blacklist_helper.rb +2 -0
- data/app/helpers/admin/cache_helper.rb +2 -0
- data/app/helpers/admin/comments_helper.rb +2 -0
- data/app/helpers/admin/content_helper.rb +2 -0
- data/app/helpers/admin/general_helper.rb +2 -0
- data/app/helpers/admin/pages_helper.rb +2 -0
- data/app/helpers/admin/resources_helper.rb +2 -0
- data/app/helpers/admin/sidebar_helper.rb +2 -0
- data/app/helpers/admin/textfilters_helper.rb +2 -0
- data/app/helpers/admin/themes_helper.rb +2 -0
- data/app/helpers/admin/trackbacks_helper.rb +2 -0
- data/app/helpers/admin/users_helper.rb +2 -0
- data/app/helpers/application_helper.rb +92 -0
- data/app/helpers/articles_helper.rb +163 -0
- data/app/helpers/backend_helper.rb +2 -0
- data/app/helpers/content_helper.rb +3 -0
- data/app/helpers/mail_helper.rb +6 -0
- data/app/helpers/redirect_helper.rb +2 -0
- data/app/helpers/sidebar_helper.rb +22 -0
- data/app/helpers/sidebars/plugin_helper.rb +2 -0
- data/app/helpers/text_filter_plugin_helper.rb +2 -0
- data/app/helpers/textfilter_helper.rb +2 -0
- data/app/helpers/theme_helper.rb +23 -0
- data/app/helpers/xml_helper.rb +21 -0
- data/app/models/aggregations/audioscrobbler.rb +54 -0
- data/app/models/aggregations/backpack.rb +57 -0
- data/app/models/aggregations/delicious.rb +57 -0
- data/app/models/aggregations/flickr.rb +89 -0
- data/app/models/aggregations/fortythree.rb +62 -0
- data/app/models/aggregations/magnolia.rb +81 -0
- data/app/models/aggregations/tada.rb +75 -0
- data/app/models/aggregations/technorati.rb +51 -0
- data/app/models/aggregations/upcoming.rb +74 -0
- data/app/models/article.rb +211 -0
- data/app/models/blacklist_pattern.rb +22 -0
- data/app/models/blog.rb +162 -0
- data/app/models/blog_sweeper.rb +23 -0
- data/app/models/category.rb +62 -0
- data/app/models/comment.rb +76 -0
- data/app/models/config_manager.rb +80 -0
- data/app/models/content.rb +222 -0
- data/app/models/content_observer.rb +5 -0
- data/app/models/content_state/base.rb +51 -0
- data/app/models/content_state/draft.rb +40 -0
- data/app/models/content_state/factory.rb +16 -0
- data/app/models/content_state/just_published.rb +47 -0
- data/app/models/content_state/new.rb +45 -0
- data/app/models/content_state/publication_pending.rb +43 -0
- data/app/models/content_state/published.rb +35 -0
- data/app/models/email_notifier.rb +9 -0
- data/app/models/notification_mailer.rb +34 -0
- data/app/models/page.rb +20 -0
- data/app/models/page_cache.rb +29 -0
- data/app/models/ping.rb +129 -0
- data/app/models/redirect.rb +3 -0
- data/app/models/resource.rb +76 -0
- data/app/models/sidebar.rb +32 -0
- data/app/models/simple_cache.rb +37 -0
- data/app/models/tag.rb +63 -0
- data/app/models/text_filter.rb +111 -0
- data/app/models/theme.rb +44 -0
- data/app/models/trackback.rb +51 -0
- data/app/models/trigger.rb +31 -0
- data/app/models/user.rb +113 -0
- data/app/models/web_notifier.rb +7 -0
- data/app/views/accounts/login.rhtml +24 -0
- data/app/views/accounts/logout.rhtml +12 -0
- data/app/views/accounts/signup.rhtml +26 -0
- data/app/views/accounts/welcome.rhtml +13 -0
- data/app/views/admin/base/_recent_comments.rhtml +10 -0
- data/app/views/admin/base/_recent_trackbacks.rhtml +10 -0
- data/app/views/admin/blacklist/_blacklist_patterns.rhtml +16 -0
- data/app/views/admin/blacklist/_form.rhtml +15 -0
- data/app/views/admin/blacklist/_quick_post.rhtml +16 -0
- data/app/views/admin/blacklist/destroy.rhtml +10 -0
- data/app/views/admin/blacklist/edit.rhtml +14 -0
- data/app/views/admin/blacklist/list.rhtml +13 -0
- data/app/views/admin/cache/list.rhtml +8 -0
- data/app/views/admin/categories/_categories.rhtml +14 -0
- data/app/views/admin/categories/_form.rhtml +7 -0
- data/app/views/admin/categories/_quick_post.rhtml +11 -0
- data/app/views/admin/categories/destroy.rhtml +10 -0
- data/app/views/admin/categories/edit.rhtml +13 -0
- data/app/views/admin/categories/list.rhtml +15 -0
- data/app/views/admin/categories/reorder.rhtml +9 -0
- data/app/views/admin/categories/show.rhtml +18 -0
- data/app/views/admin/comments/_form.rhtml +19 -0
- data/app/views/admin/comments/comments.rhtml +4 -0
- data/app/views/admin/comments/destroy.rhtml +11 -0
- data/app/views/admin/comments/edit.rhtml +18 -0
- data/app/views/admin/comments/list.rhtml +31 -0
- data/app/views/admin/comments/new.rhtml +15 -0
- data/app/views/admin/comments/show.rhtml +10 -0
- data/app/views/admin/content/_articles.rhtml +20 -0
- data/app/views/admin/content/_attachment.rhtml +17 -0
- data/app/views/admin/content/_form.rhtml +51 -0
- data/app/views/admin/content/_pages.rhtml +3 -0
- data/app/views/admin/content/_quick_post.rhtml +20 -0
- data/app/views/admin/content/_show_categories.rhtml +9 -0
- data/app/views/admin/content/_show_resources.rhtml +9 -0
- data/app/views/admin/content/destroy.rhtml +11 -0
- data/app/views/admin/content/edit.rhtml +28 -0
- data/app/views/admin/content/list.rhtml +20 -0
- data/app/views/admin/content/new.rhtml +27 -0
- data/app/views/admin/content/preview.rhtml +3 -0
- data/app/views/admin/content/show.rhtml +25 -0
- data/app/views/admin/general/index.rhtml +216 -0
- data/app/views/admin/general/update_database.rhtml +44 -0
- data/app/views/admin/pages/_form.rhtml +19 -0
- data/app/views/admin/pages/_pages.rhtml +18 -0
- data/app/views/admin/pages/_quick_post.rhtml +21 -0
- data/app/views/admin/pages/destroy.rhtml +11 -0
- data/app/views/admin/pages/edit.rhtml +28 -0
- data/app/views/admin/pages/list.rhtml +13 -0
- data/app/views/admin/pages/new.rhtml +24 -0
- data/app/views/admin/pages/preview.rhtml +1 -0
- data/app/views/admin/pages/show.rhtml +14 -0
- data/app/views/admin/resources/_itunes_category_add.rhtml +11 -0
- data/app/views/admin/resources/_itunes_category_edit.rhtml +32 -0
- data/app/views/admin/resources/_metadata_add.rhtml +22 -0
- data/app/views/admin/resources/_metadata_edit.rhtml +22 -0
- data/app/views/admin/resources/_mime_edit.rhtml +8 -0
- data/app/views/admin/resources/_pages.rhtml +3 -0
- data/app/views/admin/resources/_resources.rhtml +40 -0
- data/app/views/admin/resources/destroy.rhtml +11 -0
- data/app/views/admin/resources/list.rhtml +9 -0
- data/app/views/admin/resources/new.rhtml +12 -0
- data/app/views/admin/sidebar/_active.rhtml +14 -0
- data/app/views/admin/sidebar/_actives.rhtml +9 -0
- data/app/views/admin/sidebar/_available.rhtml +5 -0
- data/app/views/admin/sidebar/_availables.rhtml +5 -0
- data/app/views/admin/sidebar/_publish.rhtml +2 -0
- data/app/views/admin/sidebar/_target.rhtml +1 -0
- data/app/views/admin/sidebar/index.rhtml +34 -0
- data/app/views/admin/sidebar/publish.rjs +6 -0
- data/app/views/admin/sidebar/remove.rjs +5 -0
- data/app/views/admin/sidebar/set_active.rjs +10 -0
- data/app/views/admin/textfilters/_form.rhtml +45 -0
- data/app/views/admin/textfilters/_macros.rhtml +16 -0
- data/app/views/admin/textfilters/_textfilters.rhtml +20 -0
- data/app/views/admin/textfilters/destroy.rhtml +10 -0
- data/app/views/admin/textfilters/edit.rhtml +17 -0
- data/app/views/admin/textfilters/list.rhtml +15 -0
- data/app/views/admin/textfilters/macro_help.rhtml +3 -0
- data/app/views/admin/textfilters/new.rhtml +15 -0
- data/app/views/admin/textfilters/preview.rhtml +3 -0
- data/app/views/admin/textfilters/show.rhtml +34 -0
- data/app/views/admin/textfilters/show_help.rhtml +8 -0
- data/app/views/admin/themes/index.rhtml +12 -0
- data/app/views/admin/trackbacks/_form.rhtml +19 -0
- data/app/views/admin/trackbacks/destroy.rhtml +6 -0
- data/app/views/admin/trackbacks/edit.rhtml +14 -0
- data/app/views/admin/trackbacks/list.rhtml +31 -0
- data/app/views/admin/trackbacks/new.rhtml +15 -0
- data/app/views/admin/trackbacks/show.rhtml +14 -0
- data/app/views/admin/users/_form.rhtml +48 -0
- data/app/views/admin/users/_user.rhtml +9 -0
- data/app/views/admin/users/destroy.rhtml +14 -0
- data/app/views/admin/users/edit.rhtml +14 -0
- data/app/views/admin/users/list.rhtml +9 -0
- data/app/views/admin/users/new.rhtml +15 -0
- data/app/views/admin/users/show.rhtml +18 -0
- data/app/views/articles/_article.rhtml +4 -0
- data/app/views/articles/_comment.rhtml +7 -0
- data/app/views/articles/_comment_box.rhtml +43 -0
- data/app/views/articles/_comment_error.rhtml +1 -0
- data/app/views/articles/_trackback.rhtml +7 -0
- data/app/views/articles/archives.rhtml +22 -0
- data/app/views/articles/comment_preview.rhtml +3 -0
- data/app/views/articles/error.rhtml +3 -0
- data/app/views/articles/groupings.rhtml +14 -0
- data/app/views/articles/index.rhtml +11 -0
- data/app/views/articles/read.rhtml +70 -0
- data/app/views/articles/trackback.rxml +5 -0
- data/app/views/articles/view_page.rhtml +3 -0
- data/app/views/layouts/accounts.rhtml +22 -0
- data/app/views/layouts/administration.rhtml +75 -0
- data/app/views/layouts/sidebar.rhtml +40 -0
- data/app/views/live/search.rhtml +10 -0
- data/app/views/notification_mailer/_mail_footer.rhtml +7 -0
- data/app/views/notification_mailer/_mail_header.rhtml +1 -0
- data/app/views/notification_mailer/article.rhtml +6 -0
- data/app/views/notification_mailer/comment.rhtml +11 -0
- data/app/views/notification_mailer/trackback.rhtml +3 -0
- data/app/views/settings/done.rhtml +2 -0
- data/app/views/settings/install.rhtml +12 -0
- data/app/views/shared/_search.rhtml +10 -0
- data/app/views/sidebar/_row.rhtml +1 -0
- data/app/views/sidebar/_sidebar.rhtml +5 -0
- data/app/views/sidebar/display_plugins.rhtml +5 -0
- data/app/views/sidebar/show.rhtml +1 -0
- data/app/views/theme/static_view_test.rhtml +1 -0
- data/app/views/xml/_atom10_item_article.rxml +39 -0
- data/app/views/xml/_atom10_item_comment.rxml +13 -0
- data/app/views/xml/_atom10_item_trackback.rxml +16 -0
- data/app/views/xml/_itunes_item_resource.rxml +30 -0
- data/app/views/xml/_rss20_item_article.rxml +35 -0
- data/app/views/xml/_rss20_item_comment.rxml +7 -0
- data/app/views/xml/_rss20_item_trackback.rxml +7 -0
- data/app/views/xml/atom10_feed.rxml +18 -0
- data/app/views/xml/itunes_feed.rxml +29 -0
- data/app/views/xml/rsd.rxml +19 -0
- data/app/views/xml/rss20_feed.rxml +18 -0
- data/bin/typo +12 -0
- data/cache/META/DATA/ACTION_PARAM/localhost.3000/articles/index/.cache +540 -0
- data/cache/META/DATA/ACTION_PARAM/localhost.3000/articles/permalink/day=09&month=09&title=i-need-a-new-keyboard-and-mouse&year=2005.cache +414 -0
- data/cache/META/META/ACTION_PARAM/localhost.3000/articles/index/.cache +3 -0
- data/cache/META/META/ACTION_PARAM/localhost.3000/articles/permalink/day=09&month=09&title=i-need-a-new-keyboard-and-mouse&year=2005.cache +3 -0
- data/components/plugins/sidebars/aimpresence/content.rhtml +4 -0
- data/components/plugins/sidebars/aimpresence_controller.rb +10 -0
- data/components/plugins/sidebars/amazon/content.rhtml +4 -0
- data/components/plugins/sidebars/amazon_controller.rb +17 -0
- data/components/plugins/sidebars/archives/content.rhtml +11 -0
- data/components/plugins/sidebars/archives_controller.rb +24 -0
- data/components/plugins/sidebars/audioscrobbler/content.rhtml +10 -0
- data/components/plugins/sidebars/audioscrobbler_controller.rb +10 -0
- data/components/plugins/sidebars/backpack/content.rhtml +12 -0
- data/components/plugins/sidebars/backpack_controller.rb +17 -0
- data/components/plugins/sidebars/category/content.rhtml +10 -0
- data/components/plugins/sidebars/category_controller.rb +13 -0
- data/components/plugins/sidebars/delicious/content.rhtml +20 -0
- data/components/plugins/sidebars/delicious_controller.rb +29 -0
- data/components/plugins/sidebars/flickr/content.rhtml +15 -0
- data/components/plugins/sidebars/flickr_controller.rb +16 -0
- data/components/plugins/sidebars/fortythree/content.rhtml +8 -0
- data/components/plugins/sidebars/fortythree_controller.rb +12 -0
- data/components/plugins/sidebars/fortythreeplaces/content.rhtml +8 -0
- data/components/plugins/sidebars/fortythreeplaces_controller.rb +12 -0
- data/components/plugins/sidebars/magnolia/content.rhtml +12 -0
- data/components/plugins/sidebars/magnolia_controller.rb +17 -0
- data/components/plugins/sidebars/recent_comments/content.rhtml +12 -0
- data/components/plugins/sidebars/recent_comments_controller.rb +23 -0
- data/components/plugins/sidebars/static/content.rhtml +2 -0
- data/components/plugins/sidebars/static_controller.rb +23 -0
- data/components/plugins/sidebars/tada/content.rhtml +12 -0
- data/components/plugins/sidebars/tada_controller.rb +12 -0
- data/components/plugins/sidebars/tag/content.rhtml +8 -0
- data/components/plugins/sidebars/tag_controller.rb +18 -0
- data/components/plugins/sidebars/technorati/content.rhtml +8 -0
- data/components/plugins/sidebars/technorati_controller.rb +12 -0
- data/components/plugins/sidebars/upcoming/content.rhtml +8 -0
- data/components/plugins/sidebars/upcoming_controller.rb +11 -0
- data/components/plugins/sidebars/xbox/content.rhtml +2 -0
- data/components/plugins/sidebars/xbox_controller.rb +6 -0
- data/components/plugins/sidebars/xml/content.rhtml +12 -0
- data/components/plugins/sidebars/xml_controller.rb +11 -0
- data/components/plugins/textfilters/amazon_controller.rb +39 -0
- data/components/plugins/textfilters/code_controller.rb +59 -0
- data/components/plugins/textfilters/flickr_controller.rb +75 -0
- data/components/plugins/textfilters/htmlfilter_controller.rb +8 -0
- data/components/plugins/textfilters/lightbox_controller.rb +122 -0
- data/components/plugins/textfilters/macropost_controller.rb +14 -0
- data/components/plugins/textfilters/macropre_controller.rb +14 -0
- data/components/plugins/textfilters/markdown_controller.rb +32 -0
- data/components/plugins/textfilters/none_controller.rb +8 -0
- data/components/plugins/textfilters/smartypants_controller.rb +8 -0
- data/components/plugins/textfilters/sparkline_controller.rb +87 -0
- data/components/plugins/textfilters/textile_controller.rb +8 -0
- data/components/sidebars/README +36 -0
- data/config/boot.rb +44 -0
- data/config/database.yml +17 -0
- data/config/database.yml-pgsql +17 -0
- data/config/database.yml.example +18 -0
- data/config/environment.rb +145 -0
- data/config/environments/development.rb +17 -0
- data/config/environments/production.rb +19 -0
- data/config/environments/test.rb +26 -0
- data/config/iTunes.yml +72 -0
- data/config/lighttpd.conf +46 -0
- data/config/mail.yml +8 -0
- data/config/mail.yml.example +8 -0
- data/config/routes.rb +92 -0
- data/db/DB +0 -0
- data/db/DB.test +0 -0
- data/db/converters/README +14 -0
- data/db/converters/feed.rb +68 -0
- data/db/converters/mt-import.rb +72 -0
- data/db/converters/mt3.rb +172 -0
- data/db/converters/rss.rb +67 -0
- data/db/converters/s9y.rb +182 -0
- data/db/converters/textpattern.rb +137 -0
- data/db/converters/wordpress.rb +187 -0
- data/db/development_structure.sql +691 -0
- data/db/migrate/001_initial_schema.rb +127 -0
- data/db/migrate/002_add_user_email.rb +17 -0
- data/db/migrate/003_add_article_user_id.rb +20 -0
- data/db/migrate/004_add_sidebars.rb +31 -0
- data/db/migrate/005_add_cache_table.rb +20 -0
- data/db/migrate/006_add_pages.rb +17 -0
- data/db/migrate/007_add_permalink.rb +36 -0
- data/db/migrate/008_add_page_title.rb +9 -0
- data/db/migrate/009_add_article_guid.rb +10 -0
- data/db/migrate/010_add_tags.rb +19 -0
- data/db/migrate/011_add_article_id.rb +17 -0
- data/db/migrate/012_enlarge_settings.rb +11 -0
- data/db/migrate/013_add_textfilters.rb +33 -0
- data/db/migrate/014_move_text_filter_to_text_filter_id.rb +43 -0
- data/db/migrate/015_convert_mysql_to_innodb.rb +19 -0
- data/db/migrate/016_fix_is_primary_postgres.rb +19 -0
- data/db/migrate/017_add_comment_user_id.rb +23 -0
- data/db/migrate/018_add_guids.rb +13 -0
- data/db/migrate/019_add_whiteboards_to_content.rb +15 -0
- data/db/migrate/020_superclass_articles.rb +167 -0
- data/db/migrate/021_superclass_comments.rb +94 -0
- data/db/migrate/022_superclass_trackbacks.rb +71 -0
- data/db/migrate/023_superclass_pages.rb +64 -0
- data/db/migrate/024_cleanup_contents.rb +54 -0
- data/db/migrate/025_add_itunes_metadata.rb +29 -0
- data/db/migrate/026_add_redirect_table.rb +13 -0
- data/db/migrate/027_set_comment_published_flag.rb +19 -0
- data/db/migrate/028_rename_redirect_to.rb +12 -0
- data/db/migrate/029_add_user_notification.rb +29 -0
- data/db/migrate/030_index_sessions.rb +9 -0
- data/db/migrate/031_add_notifications_table.rb +14 -0
- data/db/migrate/032_add_jabber_notification.rb +11 -0
- data/db/migrate/033_add_count_caching.rb +34 -0
- data/db/migrate/034_boolify_published.rb +36 -0
- data/db/migrate/035_boolify_content_allow_foo.rb +36 -0
- data/db/migrate/036_add_tag_display_name.rb +53 -0
- data/db/migrate/037_enlarge_ip_field.rb +9 -0
- data/db/migrate/038_add_blog_object.rb +52 -0
- data/db/migrate/039_serialize_blog_attributes.rb +160 -0
- data/db/migrate/040_attach_content_to_blog.rb +28 -0
- data/db/migrate/041_fixup_default_sidebars.rb +18 -0
- data/db/migrate/042_remove_sidebar_staged_config.rb +22 -0
- data/db/migrate/043_create_triggers.rb +14 -0
- data/db/migrate/044_add_published_at_to_content.rb +18 -0
- data/db/migrate/045_fix_contents_published_default.rb +9 -0
- data/db/migrate/046_fixup_forthcoming_publications.rb +40 -0
- data/db/schema.mysql-v3.sql +218 -0
- data/db/schema.mysql.sql +218 -0
- data/db/schema.postgresql.sql +218 -0
- data/db/schema.rb +169 -0
- data/db/schema.sqlite.sql +218 -0
- data/db/schema.sqlserver.sql +232 -0
- data/db/schema_version +1 -0
- data/db/scripts/fix_permalinks.rb +5 -0
- data/db/updates/update.168.to.200.mysql.sql +33 -0
- data/db/updates/update.168.to.200.psql.sql +30 -0
- data/doc/Installer.txt +55 -0
- data/doc/README_FOR_APP +2 -0
- data/installer/rails-installer.rb +488 -0
- data/installer/rails_installer_defaults.yml +4 -0
- data/installer/typo-installer.rb +35 -0
- data/lib/backpack_api.rb +202 -0
- data/lib/bare_migration.rb +142 -0
- data/lib/email_notify.rb +32 -0
- data/lib/format.rb +19 -0
- data/lib/generators/sidebar/sidebar_generator.rb +13 -0
- data/lib/generators/sidebar/templates/components/plugins/sidebars/controller_template.rb +20 -0
- data/lib/generators/sidebar/templates/components/plugins/sidebars/views/content_template.rhtml +4 -0
- data/lib/jabber_notify.rb +32 -0
- data/lib/login_system.rb +85 -0
- data/lib/migrator.rb +28 -0
- data/lib/rails_patch/active_record.rb +36 -0
- data/lib/rails_patch/components.rb +14 -0
- data/lib/sidebars/component_plugin.rb +5 -0
- data/lib/sidebars/plugin.rb +241 -0
- data/lib/spam_protection.rb +126 -0
- data/lib/tasks/release.rake +171 -0
- data/lib/tasks/schemas.rake +6 -0
- data/lib/tasks/sweep_cache.rake +6 -0
- data/lib/text_filter_plugin.rb +97 -0
- data/lib/transforms.rb +26 -0
- data/lib/typo_guid.rb +10 -0
- data/lib/typo_plugins.rb +19 -0
- data/lib/typo_version.rb +1 -0
- data/lib/xmlrpc_fix.rb +13 -0
- data/public/.htaccess +34 -0
- data/public/404.html +8 -0
- data/public/500.html +8 -0
- data/public/dispatch.cgi +10 -0
- data/public/dispatch.fcgi +24 -0
- data/public/dispatch.rb +10 -0
- data/public/favicon.ico +0 -0
- data/public/images/admin/dot-vertical.gif +0 -0
- data/public/images/admin/h-tile.gif +0 -0
- data/public/images/admin/hdr-tile.gif +0 -0
- data/public/images/admin/toggle.gif +0 -0
- data/public/images/bg.jpg +0 -0
- data/public/images/bgcolor.jpg +0 -0
- data/public/images/body_bg.png +0 -0
- data/public/images/branding_bg.png +0 -0
- data/public/images/branding_logo.png +0 -0
- data/public/images/checked.gif +0 -0
- data/public/images/content_bg.png +0 -0
- data/public/images/delete.png +0 -0
- data/public/images/footer.jpg +0 -0
- data/public/images/footer.png +0 -0
- data/public/images/global_bg.png +0 -0
- data/public/images/global_logo.png +0 -0
- data/public/images/go.png +0 -0
- data/public/images/header.jpg +0 -0
- data/public/images/loading.gif +0 -0
- data/public/images/not-checked copy.gif +0 -0
- data/public/images/not-checked.gif +0 -0
- data/public/images/overlay.png +0 -0
- data/public/images/powered.gif +0 -0
- data/public/images/section_bg.png +0 -0
- data/public/images/sections_bg.png +0 -0
- data/public/images/sections_hilite.png +0 -0
- data/public/images/sections_hover.png +0 -0
- data/public/images/spinner-blue.gif +0 -0
- data/public/images/spinner.gif +0 -0
- data/public/images/spot-header.gif +0 -0
- data/public/images/spot-title.gif +0 -0
- data/public/images/x-ed.gif +0 -0
- data/public/javascripts/application.js +2 -0
- data/public/javascripts/controls.js +815 -0
- data/public/javascripts/cookies.js +60 -0
- data/public/javascripts/dragdrop.js +724 -0
- data/public/javascripts/effects.js +953 -0
- data/public/javascripts/lightbox.js +348 -0
- data/public/javascripts/prototype.js +1985 -0
- data/public/javascripts/scriptaculous.js +47 -0
- data/public/javascripts/slider.js +258 -0
- data/public/javascripts/typo.js +85 -0
- data/public/robots.txt +2 -0
- data/public/stylesheets/administration.css +585 -0
- data/public/stylesheets/lightbox.css +22 -0
- data/public/stylesheets/rss.css +54 -0
- data/public/stylesheets/user-styles.css +0 -0
- data/script/about +3 -0
- data/script/benchmarker +19 -0
- data/script/breakpointer +3 -0
- data/script/console +3 -0
- data/script/destroy +3 -0
- data/script/generate +3 -0
- data/script/lighttpd +2 -0
- data/script/logreport +79 -0
- data/script/migrate +31 -0
- data/script/performance/benchmarker +3 -0
- data/script/performance/profiler +3 -0
- data/script/plugin +3 -0
- data/script/process/reaper +3 -0
- data/script/process/spawner +3 -0
- data/script/process/spinner +3 -0
- data/script/profiler +34 -0
- data/script/runner +3 -0
- data/script/server +3 -0
- data/script/spacecheck +40 -0
- data/test/fixtures/articles_categories.yml +31 -0
- data/test/fixtures/articles_tags.yml +19 -0
- data/test/fixtures/blacklist_patterns.yml +10 -0
- data/test/fixtures/blogs.yml +74 -0
- data/test/fixtures/categories.yml +35 -0
- data/test/fixtures/contents.yml +297 -0
- data/test/fixtures/notification_mailer/article +3 -0
- data/test/fixtures/notification_mailer/comment +3 -0
- data/test/fixtures/notification_mailer/trackback +3 -0
- data/test/fixtures/notifications.yml +0 -0
- data/test/fixtures/page_caches.yml +7 -0
- data/test/fixtures/redirects.yml +13 -0
- data/test/fixtures/resources.yml +24 -0
- data/test/fixtures/sidebars.yml +5 -0
- data/test/fixtures/tags.yml +13 -0
- data/test/fixtures/text_filters.yml +42 -0
- data/test/fixtures/triggers.yml +1 -0
- data/test/fixtures/users.yml +56 -0
- data/test/functional/accounts_controller_test.rb +82 -0
- data/test/functional/admin/article_preview_test.rb +67 -0
- data/test/functional/admin/blacklist_controller_test.rb +63 -0
- data/test/functional/admin/categories_controller_test.rb +112 -0
- data/test/functional/admin/comments_controller_test.rb +78 -0
- data/test/functional/admin/content_controller_test.rb +234 -0
- data/test/functional/admin/general_controller_test.rb +26 -0
- data/test/functional/admin/pages_controller_test.rb +103 -0
- data/test/functional/admin/resources_controller_test.rb +49 -0
- data/test/functional/admin/textfilters_controller_test.rb +29 -0
- data/test/functional/admin/themes_controller_test.rb +34 -0
- data/test/functional/admin/trackbacks_controller_test.rb +76 -0
- data/test/functional/admin/users_controller_test.rb +72 -0
- data/test/functional/articles_controller_test.rb +525 -0
- data/test/functional/backend_controller_test.rb +273 -0
- data/test/functional/redirect_controller_test.rb +40 -0
- data/test/functional/textfilter_controller_test.rb +275 -0
- data/test/functional/theme_controller_test.rb +45 -0
- data/test/functional/xml_controller_test.rb +353 -0
- data/test/mocks/test/dns_mock.rb +13 -0
- data/test/mocks/test/flickr_mock.rb +30 -0
- data/test/mocks/test/http_mock.rb +38 -0
- data/test/mocks/test/theme_mock.rb +5 -0
- data/test/mocks/test/xmlrpc_mock.rb +27 -0
- data/test/mocks/themes/123-numbers-in-path/about.markdown +0 -0
- data/test/mocks/themes/CamelCaseDirectory/about.markdown +0 -0
- data/test/mocks/themes/azure/about.markdown +5 -0
- data/test/mocks/themes/azure/layouts/default.rhtml +50 -0
- data/test/mocks/themes/azure/preview.png +0 -0
- data/test/mocks/themes/azure/views/theme/static_view_test.rhtml +1 -0
- data/test/mocks/themes/i-have-special-chars/about.markdown +0 -0
- data/test/test_helper.rb +95 -0
- data/test/unit/article_test.rb +245 -0
- data/test/unit/assumptions_tests.rb +54 -0
- data/test/unit/audioscrobbler_test.rb +132 -0
- data/test/unit/blacklist_pattern_test.rb +14 -0
- data/test/unit/blog_test.rb +83 -0
- data/test/unit/category_test.rb +37 -0
- data/test/unit/comment_test.rb +117 -0
- data/test/unit/configuration_test.rb +21 -0
- data/test/unit/content_state/factory_test.rb +84 -0
- data/test/unit/delicious_test.rb +96 -0
- data/test/unit/flickr_test.rb +134 -0
- data/test/unit/fortythree_test.rb +66 -0
- data/test/unit/magnolia_test.rb +87 -0
- data/test/unit/metafragment_test.rb +63 -0
- data/test/unit/notification_mailer_test.rb +55 -0
- data/test/unit/observer_test.rb +40 -0
- data/test/unit/page_cache_test.rb +34 -0
- data/test/unit/page_test.rb +25 -0
- data/test/unit/ping_test.rb +111 -0
- data/test/unit/redirect_test.rb +19 -0
- data/test/unit/resource_test.rb +71 -0
- data/test/unit/sidebar_test.rb +14 -0
- data/test/unit/tag_test.rb +66 -0
- data/test/unit/text_filter_test.rb +126 -0
- data/test/unit/theme_test.rb +44 -0
- data/test/unit/trackback_test.rb +45 -0
- data/test/unit/trigger_test.rb +40 -0
- data/test/unit/user_test.rb +111 -0
- data/themes/azure/about.markdown +5 -0
- data/themes/azure/images/bg-tile.gif +0 -0
- data/themes/azure/images/bracket.gif +0 -0
- data/themes/azure/images/bullet.gif +0 -0
- data/themes/azure/images/hdr.gif +0 -0
- data/themes/azure/images/q-close.gif +0 -0
- data/themes/azure/images/q-open.gif +0 -0
- data/themes/azure/images/sbar-tile.gif +0 -0
- data/themes/azure/images/spinner.gif +0 -0
- data/themes/azure/images/xlink.gif +0 -0
- data/themes/azure/layouts/default.rhtml +50 -0
- data/themes/azure/preview.png +0 -0
- data/themes/azure/stylesheets/azure.css +436 -0
- data/themes/azure/stylesheets/print.css +30 -0
- data/themes/azure/views/theme/static_view_test.rhtml +1 -0
- data/vendor/akismet/Akismet.rb +140 -0
- data/vendor/bluecloth/CHANGES +366 -0
- data/vendor/bluecloth/LICENSE +340 -0
- data/vendor/bluecloth/README +99 -0
- data/vendor/bluecloth/bin/bluecloth +83 -0
- data/vendor/bluecloth/install.rb +150 -0
- data/vendor/bluecloth/lib/bluecloth.rb +1144 -0
- data/vendor/bluecloth/test.rb +117 -0
- data/vendor/bluecloth/tests/00_Class.tests.rb +71 -0
- data/vendor/bluecloth/tests/05_Markdown.tests.rb +1527 -0
- data/vendor/bluecloth/tests/10_Bug.tests.rb +57 -0
- data/vendor/bluecloth/tests/15_Contrib.tests.rb +132 -0
- data/vendor/bluecloth/tests/bctestcase.rb +274 -0
- data/vendor/bluecloth/tests/data/antsugar.txt +34 -0
- data/vendor/bluecloth/tests/data/ml-announce.txt +17 -0
- data/vendor/bluecloth/tests/data/re-overflow.txt +67 -0
- data/vendor/bluecloth/tests/data/re-overflow2.txt +281 -0
- data/vendor/bluecloth/utils.rb +553 -0
- data/vendor/flickr/Rakefile +36 -0
- data/vendor/flickr/flickr.rb +490 -0
- data/vendor/flickr/index.html +129 -0
- data/vendor/flickr/test_flickr.rb +173 -0
- data/vendor/jabber4r/CHANGES +8 -0
- data/vendor/jabber4r/LICENSE.txt +12 -0
- data/vendor/jabber4r/README +180 -0
- data/vendor/jabber4r/Rakefile.rb +143 -0
- data/vendor/jabber4r/lib/jabber4r/jabber4r.rb +22 -0
- data/vendor/jabber4r/lib/jabber4r/jid.rb +93 -0
- data/vendor/jabber4r/lib/jabber4r/protocol.rb +1384 -0
- data/vendor/jabber4r/lib/jabber4r/rexml_1.8_patch.rb +16 -0
- data/vendor/jabber4r/lib/jabber4r/roster.rb +322 -0
- data/vendor/jabber4r/lib/jabber4r/session.rb +615 -0
- data/vendor/jabber4r/lib/jabber4r/vcard.rb +42 -0
- data/vendor/plugins/expiring_action_cache/init.rb +2 -0
- data/vendor/plugins/expiring_action_cache/lib/actionparamcache.rb +113 -0
- data/vendor/plugins/expiring_action_cache/lib/metafragment.rb +46 -0
- data/vendor/plugins/upload_progress/CHANGELOG +3 -0
- data/vendor/plugins/upload_progress/MIT-LICENSE +20 -0
- data/vendor/plugins/upload_progress/README +45 -0
- data/vendor/plugins/upload_progress/Rakefile +23 -0
- data/vendor/plugins/upload_progress/init.rb +7 -0
- data/vendor/plugins/upload_progress/lib/multipart_progress.rb +169 -0
- data/vendor/plugins/upload_progress/lib/progress.rb +145 -0
- data/vendor/plugins/upload_progress/lib/upload_progress.rb +303 -0
- data/vendor/plugins/upload_progress/lib/upload_progress_helper.rb +424 -0
- data/vendor/plugins/upload_progress/public/stylesheets/upload_progress.css +21 -0
- data/vendor/plugins/upload_progress/test/multipart_progress_testx.rb +364 -0
- data/vendor/plugins/upload_progress/test/upload_progress_helper_testx.rb +134 -0
- data/vendor/plugins/upload_progress/test/upload_progress_testx.rb +88 -0
- data/vendor/redcloth/RedCloth.gemspec +52 -0
- data/vendor/redcloth/bin/redcloth +3 -0
- data/vendor/redcloth/doc/CHANGELOG +160 -0
- data/vendor/redcloth/doc/COPYING +25 -0
- data/vendor/redcloth/doc/README +106 -0
- data/vendor/redcloth/doc/REFERENCE +216 -0
- data/vendor/redcloth/doc/make.rb +359 -0
- data/vendor/redcloth/install.rb +1032 -0
- data/vendor/redcloth/lib/redcloth.rb +1130 -0
- data/vendor/redcloth/run-tests.rb +28 -0
- data/vendor/redcloth/setup.rb +1376 -0
- data/vendor/redcloth/tests/code.yml +105 -0
- data/vendor/redcloth/tests/hard_breaks.yml +26 -0
- data/vendor/redcloth/tests/images.yml +171 -0
- data/vendor/redcloth/tests/instiki.yml +39 -0
- data/vendor/redcloth/tests/links.yml +155 -0
- data/vendor/redcloth/tests/lists.yml +77 -0
- data/vendor/redcloth/tests/markdown.yml +218 -0
- data/vendor/redcloth/tests/poignant.yml +64 -0
- data/vendor/redcloth/tests/table.yml +198 -0
- data/vendor/redcloth/tests/textism.yml +406 -0
- data/vendor/ruby-mp3info/lib/mp3info.rb +720 -0
- data/vendor/rubypants/README +114 -0
- data/vendor/rubypants/Rakefile +55 -0
- data/vendor/rubypants/html/classes/RubyPants.html +924 -0
- data/vendor/rubypants/html/created.rid +1 -0
- data/vendor/rubypants/html/files/README.html +248 -0
- data/vendor/rubypants/html/files/rubypants_rb.html +125 -0
- data/vendor/rubypants/html/fr_class_index.html +27 -0
- data/vendor/rubypants/html/fr_file_index.html +28 -0
- data/vendor/rubypants/html/fr_method_index.html +38 -0
- data/vendor/rubypants/html/index.html +24 -0
- data/vendor/rubypants/html/rdoc-style.css +172 -0
- data/vendor/rubypants/install.rb +9 -0
- data/vendor/rubypants/rubypants.rb +490 -0
- data/vendor/rubypants/test_rubypants.rb +162 -0
- data/vendor/sparklines/README.txt +47 -0
- data/vendor/sparklines/USAGE +14 -0
- data/vendor/sparklines/lib/sparklines.rb +435 -0
- data/vendor/sparklines/samples/sparklinestest.rb +26 -0
- data/vendor/sparklines/sparklines_generator.rb +9 -0
- data/vendor/sparklines/templates/sparklines_controller.rb +30 -0
- data/vendor/sparklines/templates/sparklines_helper.rb +30 -0
- data/vendor/syntax/LICENSE +27 -0
- data/vendor/syntax/NEWS +16 -0
- data/vendor/syntax/README +38 -0
- data/vendor/syntax/Rakefile +194 -0
- data/vendor/syntax/api/classes/Syntax.html +173 -0
- data/vendor/syntax/api/classes/Syntax/Convertors.html +91 -0
- data/vendor/syntax/api/classes/Syntax/Convertors/Abstract.html +159 -0
- data/vendor/syntax/api/classes/Syntax/Convertors/HTML.html +149 -0
- data/vendor/syntax/api/classes/Syntax/Default.html +123 -0
- data/vendor/syntax/api/classes/Syntax/Ruby.html +319 -0
- data/vendor/syntax/api/classes/Syntax/Token.html +151 -0
- data/vendor/syntax/api/classes/Syntax/Tokenizer.html +324 -0
- data/vendor/syntax/api/classes/Syntax/Version.html +109 -0
- data/vendor/syntax/api/classes/Syntax/XML.html +205 -0
- data/vendor/syntax/api/classes/Syntax/YAML.html +189 -0
- data/vendor/syntax/api/created.rid +1 -0
- data/vendor/syntax/api/files/README.html +155 -0
- data/vendor/syntax/api/files/lib/syntax/common_rb.html +96 -0
- data/vendor/syntax/api/files/lib/syntax/convertors/abstract_rb.html +96 -0
- data/vendor/syntax/api/files/lib/syntax/convertors/html_rb.html +96 -0
- data/vendor/syntax/api/files/lib/syntax/lang/ruby_rb.html +96 -0
- data/vendor/syntax/api/files/lib/syntax/lang/xml_rb.html +96 -0
- data/vendor/syntax/api/files/lib/syntax/lang/yaml_rb.html +96 -0
- data/vendor/syntax/api/files/lib/syntax/version_rb.html +92 -0
- data/vendor/syntax/api/files/lib/syntax_rb.html +96 -0
- data/vendor/syntax/api/fr_class_index.html +56 -0
- data/vendor/syntax/api/fr_file_index.html +54 -0
- data/vendor/syntax/api/fr_method_index.html +65 -0
- data/vendor/syntax/api/index.html +26 -0
- data/vendor/syntax/api/rdoc-style.css +175 -0
- data/vendor/syntax/doc/manual-html/chapter-1.html +198 -0
- data/vendor/syntax/doc/manual-html/chapter-2.html +262 -0
- data/vendor/syntax/doc/manual-html/chapter-3.html +266 -0
- data/vendor/syntax/doc/manual-html/chapter-4.html +267 -0
- data/vendor/syntax/doc/manual-html/index.html +152 -0
- data/vendor/syntax/doc/manual-html/stylesheets/manual.css +270 -0
- data/vendor/syntax/doc/manual-html/stylesheets/ruby.css +17 -0
- data/vendor/syntax/doc/manual/chapter.erb +38 -0
- data/vendor/syntax/doc/manual/example.erb +18 -0
- data/vendor/syntax/doc/manual/index.erb +29 -0
- data/vendor/syntax/doc/manual/manual.rb +311 -0
- data/vendor/syntax/doc/manual/manual.yml +43 -0
- data/vendor/syntax/doc/manual/page.erb +87 -0
- data/vendor/syntax/doc/manual/parts/0000.txt +5 -0
- data/vendor/syntax/doc/manual/parts/0001.txt +16 -0
- data/vendor/syntax/doc/manual/parts/0002.txt +24 -0
- data/vendor/syntax/doc/manual/parts/0003.txt +6 -0
- data/vendor/syntax/doc/manual/parts/0004.txt +32 -0
- data/vendor/syntax/doc/manual/parts/0005.txt +18 -0
- data/vendor/syntax/doc/manual/parts/0006.txt +62 -0
- data/vendor/syntax/doc/manual/parts/0007.txt +3 -0
- data/vendor/syntax/doc/manual/parts/0008.txt +5 -0
- data/vendor/syntax/doc/manual/parts/0009.txt +29 -0
- data/vendor/syntax/doc/manual/parts/0010.txt +21 -0
- data/vendor/syntax/doc/manual/stylesheets/manual.css +270 -0
- data/vendor/syntax/doc/manual/stylesheets/ruby.css +17 -0
- data/vendor/syntax/doc/manual/tutorial.erb +30 -0
- data/vendor/syntax/lib/syntax.rb +38 -0
- data/vendor/syntax/lib/syntax/common.rb +163 -0
- data/vendor/syntax/lib/syntax/convertors/abstract.rb +27 -0
- data/vendor/syntax/lib/syntax/convertors/html.rb +51 -0
- data/vendor/syntax/lib/syntax/lang/ruby.rb +317 -0
- data/vendor/syntax/lib/syntax/lang/xml.rb +108 -0
- data/vendor/syntax/lib/syntax/lang/yaml.rb +105 -0
- data/vendor/syntax/lib/syntax/version.rb +9 -0
- data/vendor/syntax/setup.rb +1331 -0
- data/vendor/syntax/syntax.gemspec +24 -0
- data/vendor/syntax/test/ALL-TESTS.rb +5 -0
- data/vendor/syntax/test/syntax/tc_ruby.rb +871 -0
- data/vendor/syntax/test/syntax/tc_xml.rb +202 -0
- data/vendor/syntax/test/syntax/tc_yaml.rb +228 -0
- data/vendor/syntax/test/syntax/tokenizer_testcase.rb +40 -0
- data/vendor/syntax/test/tc_syntax.rb +22 -0
- data/vendor/uuidtools/CHANGELOG +4 -0
- data/vendor/uuidtools/README +13 -0
- data/vendor/uuidtools/install.rb +30 -0
- data/vendor/uuidtools/lib/uuidtools.rb +555 -0
- data/vendor/uuidtools/rakefile +112 -0
- metadata +1022 -0
@@ -0,0 +1,7 @@
|
|
1
|
+
</div>
|
2
|
+
|
3
|
+
<p><em>This is being sent to <%=h @user.name %> because you asked to be notified via email whenever
|
4
|
+
new content is posted to <%= link_to @blog_name, @controller.url_for(:controller => 'articles', :action => 'index') %>
|
5
|
+
To unsubscribe, go to
|
6
|
+
<a href="<%= @link_url = @controller.url_for(:controller => 'admin/users', :action => 'edit', :id => @user.id) %>"><%=h @link_url%></a>
|
7
|
+
and change your user settings.</p>
|
@@ -0,0 +1 @@
|
|
1
|
+
<div style="margin:1em;padding:4px;background:#eee;border:1px solid black">
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<p>A new comment has been posted on
|
2
|
+
<%= link_to @blog_name, @controller.url_for(:controller => 'articles', :action => 'index') %>, responding to
|
3
|
+
<%= link_to h(@comment.article.title), article_url(@controller, @comment.article) %>.</p>
|
4
|
+
|
5
|
+
<%= render :partial => './mail_header' %>
|
6
|
+
<h2><%=h @comment.title %></h2>
|
7
|
+
<cite><strong><%= (@comment.url.blank?) ? h(@comment.author) : link_to(h(@comment.author), @comment.url) %></strong> </cite>
|
8
|
+
<%= link_to 'said', article_url(@controller, @comment.article,true,"comment-#{@comment.id}") %>
|
9
|
+
<%= distance_of_time_in_words @article.published_at, @comment.created_at %> later:<br />
|
10
|
+
<%= @comment.body_html %>
|
11
|
+
<%= render :partial => './mail_footer' %>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<%= start_form_tag({:controller => 'articles', :action => 'search'}, {:method => 'get', :id => 'sform'}) %>
|
2
|
+
<label for="q">Live Search:</label><input type="text" id="q" name="q" value="" size="15" />
|
3
|
+
<%= image_tag "spinner-blue.gif", :id => 'search_spinner', :style => 'display:none;' %>
|
4
|
+
<%= end_form_tag %>
|
5
|
+
<%= observe_field "q", :frequency => 1,
|
6
|
+
:url => { :controller => "live", :action => "search" },
|
7
|
+
:loading => "Element.show('search_spinner')",
|
8
|
+
:complete => "Element.hide('search_spinner')",
|
9
|
+
:update => "search-results",
|
10
|
+
:with => "'q=' + escape($F('q'))" -%>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= row.line_html(@sidebar) %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render :partial => 'sidebar', :object => @sidebar %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<!-- Static View Test from app/ -->
|
@@ -0,0 +1,39 @@
|
|
1
|
+
xm.entry do
|
2
|
+
xm.author do
|
3
|
+
name = item.user.name rescue item.author
|
4
|
+
email = item.user.email rescue nil
|
5
|
+
xm.name name
|
6
|
+
xm.email email if this_blog.link_to_author unless email.blank?
|
7
|
+
end
|
8
|
+
xm.id "urn:uuid:#{item.guid}"
|
9
|
+
|
10
|
+
xm.published item.published_at.xmlschema
|
11
|
+
xm.updated item.updated_at.xmlschema
|
12
|
+
xm.title post_title(item), "type"=>"html"
|
13
|
+
|
14
|
+
xm.link "rel" => "alternate", "type" => "text/html", "href" => post_link(item)
|
15
|
+
|
16
|
+
item.categories.each do |category|
|
17
|
+
xm.category "term" => category.permalink, "label" => category.name, "scheme" => (url_for :controller => "articles", :action => "category", :id => category.permalink, :only_path => false)
|
18
|
+
end
|
19
|
+
item.tags.each do |tag|
|
20
|
+
xm.category "term" => tag.display_name, "scheme" => (url_for :controller => "articles", :action => "tag", :id => tag.name, :only_path => false)
|
21
|
+
end
|
22
|
+
|
23
|
+
item.resources.each do |resource|
|
24
|
+
if resource.size > 0 # The Atom spec disallows files with size=0
|
25
|
+
xm.link "rel" => "enclosure",
|
26
|
+
:type => resource.mime,
|
27
|
+
:title => item.title,
|
28
|
+
:href => server_url_for(:controller => "files", :action => resource.filename),
|
29
|
+
:length => resource.size
|
30
|
+
else
|
31
|
+
xm.link "rel" => "enclosure",
|
32
|
+
:type => resource.mime,
|
33
|
+
:title => item.title,
|
34
|
+
:href => server_url_for(:controller => "files", :action => resource.filename)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
xm.summary item.body_html, "type"=>"html"
|
38
|
+
xm.content item.full_html, "type"=>"html" if this_blog.show_extended_on_rss
|
39
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
xm.entry do
|
2
|
+
xm.author { xm.name item.author }
|
3
|
+
xm.id "urn:uuid:#{item.guid}"
|
4
|
+
|
5
|
+
xm.published item.created_at.xmlschema
|
6
|
+
xm.updated item.updated_at.xmlschema
|
7
|
+
xm.title "Comment on #{item.article.title} by #{item.author}", "type"=>"html"
|
8
|
+
|
9
|
+
xm.link "rel" => "alternate", "type" => "text/html", "href" => comment_link(item)
|
10
|
+
|
11
|
+
content = item.full_html
|
12
|
+
xm.content content, "type"=>"html"
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
xm.entry do
|
2
|
+
xm.id "urn:uuid:#{item.guid}"
|
3
|
+
|
4
|
+
xm.author do
|
5
|
+
xm.name item.blog_name
|
6
|
+
xm.uri item.url
|
7
|
+
end
|
8
|
+
xm.published item.created_at.xmlschema
|
9
|
+
xm.updated item.updated_at.xmlschema
|
10
|
+
xm.title "Trackback from #{item.blog_name}: #{item.title} on #{item.article.title}", "type"=>"html"
|
11
|
+
|
12
|
+
xm.link "rel" => "alternate", "type" => "text/html", "href" => comment_link(item)
|
13
|
+
|
14
|
+
content = item.excerpt
|
15
|
+
xm.summary content, "type"=>"html"
|
16
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
xm.item do
|
2
|
+
xm.title(item.itunes_subtitle)
|
3
|
+
xm.enclosure(
|
4
|
+
:url => server_url_for(:controller => "files",
|
5
|
+
:action => item.filename),
|
6
|
+
:length => item.size,
|
7
|
+
:type => item.mime)
|
8
|
+
xm.pubDate pub_date(item.created_at)
|
9
|
+
xm.guid server_url_for(:controller => "files",
|
10
|
+
:action => item.filename), "isPermaLink" => "false"
|
11
|
+
xm.itunes :author,(item.itunes_author)
|
12
|
+
xm.itunes :subtitle,(item.itunes_subtitle)
|
13
|
+
xm.itunes :summary,(item.itunes_summary)
|
14
|
+
xm.itunes :duration,(item.itunes_duration)
|
15
|
+
xm.itunes :keywords,(item.itunes_keywords)
|
16
|
+
if item.itunes_explicit?
|
17
|
+
xm.itunes :explicit,('yes')
|
18
|
+
end
|
19
|
+
|
20
|
+
category_list = YAML::load(item.itunes_category)
|
21
|
+
category_list.each do |parent_cat,sub_array|
|
22
|
+
xm.itunes(:category, 'text' => parent_cat.gsub(/\&/,'&')) do |xm|
|
23
|
+
sub_array.each do |sub_cat|
|
24
|
+
unless sub_cat.nil?
|
25
|
+
xm.itunes :category, :text => sub_cat
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
xm.item do
|
2
|
+
xm.title post_title(item)
|
3
|
+
if this_blog.show_extended_on_rss
|
4
|
+
content = item.full_html
|
5
|
+
else
|
6
|
+
content = item.body_html
|
7
|
+
end
|
8
|
+
xm.description content
|
9
|
+
xm.pubDate pub_date(item.published_at)
|
10
|
+
xm.guid "urn:uuid:#{item.guid}", "isPermaLink" => "false"
|
11
|
+
author = item.user.name rescue item.author
|
12
|
+
email = item.user.email rescue nil
|
13
|
+
author = "#{email} (#{author})" if this_blog.link_to_author unless email.blank?
|
14
|
+
xm.author author
|
15
|
+
xm.link post_link(item)
|
16
|
+
for category in item.categories
|
17
|
+
xm.category category.name
|
18
|
+
end
|
19
|
+
for tag in item.tags
|
20
|
+
xm.category tag.display_name
|
21
|
+
end
|
22
|
+
|
23
|
+
# RSS 2.0 only allows a single enclosure per item, so only include the first one here.
|
24
|
+
if not item.resources.empty?
|
25
|
+
resource = item.resources.first
|
26
|
+
xm.enclosure(
|
27
|
+
:url => server_url_for(:controller => "files",
|
28
|
+
:action => resource.filename),
|
29
|
+
:length => resource.size,
|
30
|
+
:type => resource.mime)
|
31
|
+
end
|
32
|
+
if item.allow_pings?
|
33
|
+
xm.trackback :ping, server_url_for(:controller => "articles", :action =>"trackback", :id => item.id)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
2
|
+
xml.feed "xml:lang" => "en-US", "xmlns" => 'http://www.w3.org/2005/Atom' do
|
3
|
+
xml.title @feed_title
|
4
|
+
if(not this_blog.blog_subtitle.blank?)
|
5
|
+
xml.subtitle this_blog.blog_subtitle, "type"=>"html"
|
6
|
+
end
|
7
|
+
xml.id "tag:#{@controller.request.host},2005:Typo"
|
8
|
+
xml.generator "Typo", :uri => "http://www.typosphere.org", :version => '4.0'
|
9
|
+
xml.link "rel" => "self", "type" => "application/atom+xml", "href" => url_for(:only_path => false)
|
10
|
+
xml.link "rel" => "alternate", "type" => "text/html", "href" => @link
|
11
|
+
|
12
|
+
xml.updated @items.first.updated_at.xmlschema unless @items.empty?
|
13
|
+
|
14
|
+
@items.each do |item|
|
15
|
+
render :partial => "atom10_item_#{item.class.name.to_s.downcase}",
|
16
|
+
:locals => {:item => item, :xm => xml}
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
2
|
+
xml.instruct! 'xml-stylesheet', :type=>"text/css", :href => url_for("/stylesheets/rss.css")
|
3
|
+
|
4
|
+
xml.rss "version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/",
|
5
|
+
"xmlns:trackback" => "http://madskills.com/public/xml/rss/module/trackback/",
|
6
|
+
"xmlns:itunes" => "http://www.itunes.com/dtds/podcast-1.0.dtd" do
|
7
|
+
|
8
|
+
xml.channel do
|
9
|
+
xml.title @feed_title
|
10
|
+
xml.link @link
|
11
|
+
xml.language "en-us"
|
12
|
+
xml.ttl "40"
|
13
|
+
xml.description this_blog.blog_subtitle
|
14
|
+
|
15
|
+
xml.itunes :author,(this_blog.itunes_author)
|
16
|
+
xml.itunes :subtitle,(this_blog.itunes_subtitle)
|
17
|
+
xml.itunes :summary,(this_blog.itunes_summary)
|
18
|
+
xml.itunes :owner do
|
19
|
+
xml.itunes :name,(this_blog.itunes_name)
|
20
|
+
xml.itunes :email,(this_blog.itunes_email)
|
21
|
+
end
|
22
|
+
xml.copyright(this_blog.itunes_copyright)
|
23
|
+
end
|
24
|
+
|
25
|
+
@items.each do |item|
|
26
|
+
render :partial => "itunes_item_resource",
|
27
|
+
:locals => {:item => item, :xm => xml}
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
2
|
+
xml.rsd "version"=>"1.0", "xmlns"=>"http://archipelago.phrasewise.com/rsd" do
|
3
|
+
xml.service do
|
4
|
+
xml.engineName "Typo"
|
5
|
+
xml.engineLink "http://www.typosphere.org"
|
6
|
+
xml.homePageLink server_url_for(:controller => "articles")
|
7
|
+
xml.apis do
|
8
|
+
xml.api "name" => "Movable Type", "preferred"=>"true",
|
9
|
+
"apiLink" => server_url_for(:controller => "backend", :action => "xmlrpc"),
|
10
|
+
"blogID" => "1"
|
11
|
+
xml.api "name" => "MetaWeblog", "preferred"=>"false",
|
12
|
+
"apiLink" => server_url_for(:controller => "backend", :action => "xmlrpc"),
|
13
|
+
"blogID" => "1"
|
14
|
+
xml.api "name" => "Blogger", "preferred"=>"false",
|
15
|
+
"apiLink" => server_url_for(:controller => "backend", :action => "xmlrpc"),
|
16
|
+
"blogID" => "1"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
2
|
+
xml.instruct! 'xml-stylesheet', :type=>"text/css", :href => url_for("/stylesheets/rss.css")
|
3
|
+
|
4
|
+
xml.rss "version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/",
|
5
|
+
"xmlns:trackback" => "http://madskills.com/public/xml/rss/module/trackback/" do
|
6
|
+
xml.channel do
|
7
|
+
xml.title @feed_title
|
8
|
+
xml.link @link
|
9
|
+
xml.language "en-us"
|
10
|
+
xml.ttl "40"
|
11
|
+
xml.description this_blog.blog_subtitle
|
12
|
+
|
13
|
+
@items.each do |item|
|
14
|
+
render :partial => "rss20_item_#{item.class.name.to_s.downcase}",
|
15
|
+
:locals => {:item => item, :xm => xml}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/bin/typo
ADDED
@@ -0,0 +1,540 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
3
|
+
<head>
|
4
|
+
<title>*scottstuff*</title>
|
5
|
+
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
6
|
+
<meta content="47.774196,-122.20184" name="ICBM" />
|
7
|
+
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://localhost:3000/xml/rsd" />
|
8
|
+
<link rel="alternate" type="application/rss+xml" title="RSS" href="http://localhost:3000/xml/rss20/feed.xml" />
|
9
|
+
<link rel="alternate" type="application/atom+xml" title="Atom" href="http://localhost:3000/xml/atom10/feed.xml" />
|
10
|
+
<script src="/javascripts/cookies.js" type="text/javascript"></script>
|
11
|
+
<script src="/javascripts/prototype.js" type="text/javascript"></script>
|
12
|
+
<script src="/javascripts/effects.js" type="text/javascript"></script>
|
13
|
+
<script src="/javascripts/typo.js" type="text/javascript"></script>
|
14
|
+
|
15
|
+
<script type="text/javascript"></script>
|
16
|
+
<link href="/stylesheets/theme/azure.css" media="all" rel="Stylesheet" type="text/css" />
|
17
|
+
<link href="/stylesheets/user-styles.css" media="all" rel="Stylesheet" type="text/css" />
|
18
|
+
<link href="/stylesheets/theme/print.css" media="print" rel="Stylesheet" type="text/css" />
|
19
|
+
</head>
|
20
|
+
|
21
|
+
<body>
|
22
|
+
<div id="container" class="clearfix">
|
23
|
+
<div id="header">
|
24
|
+
<div id="logo">
|
25
|
+
<h1 id="sitename"><a href="/">*scottstuff*</a></h1>
|
26
|
+
<h2 id="subtitle"></h2>
|
27
|
+
</div>
|
28
|
+
</div>
|
29
|
+
|
30
|
+
<div id="search"> <form action="/articles/search" id="sform" method="get">
|
31
|
+
<label for="q">Live Search:</label><input type="text" id="q" name="q" value="" size="15" />
|
32
|
+
<img alt="Spinner-blue" id="search_spinner" src="/images/spinner-blue.gif" style="display:none;" />
|
33
|
+
</form>
|
34
|
+
<script type="text/javascript">
|
35
|
+
//<![CDATA[
|
36
|
+
new Form.Element.Observer('q', 1, function(element, value) {new Ajax.Updater('search-results', '/live/search', {asynchronous:true, evalScripts:true, onComplete:function(request){Element.hide('search_spinner')}, onLoading:function(request){Element.show('search_spinner')}, parameters:'q=' + escape($F('q'))})})
|
37
|
+
//]]>
|
38
|
+
</script></div>
|
39
|
+
|
40
|
+
|
41
|
+
<div id="content" class="clearfix">
|
42
|
+
<div id="main">
|
43
|
+
<div class="post">
|
44
|
+
<h2><a href="/articles/2006/01/20/foo">foo</a></h2>
|
45
|
+
<p class="auth">Posted by Scott Laird
|
46
|
+
<span class="typo_date" title="Sat, 21 Jan 2006 05:48:00 GMT">Sat, 21 Jan 2006 05:48:00 GMT</span></p>
|
47
|
+
<p>sadfsadfasdf</p>
|
48
|
+
|
49
|
+
|
50
|
+
<p class="meta"><a href="/articles/2006/01/20/foo#comments">no comments</a> <strong>|</strong> <a href="/articles/2006/01/20/foo#trackbacks">no trackbacks</a></p>
|
51
|
+
</div>
|
52
|
+
<div class="post">
|
53
|
+
<h2><a href="/articles/2005/11/03/to_proc">to_proc</a></h2>
|
54
|
+
<p class="auth">Posted by Scott Laird
|
55
|
+
<span class="typo_date" title="Thu, 03 Nov 2005 23:02:49 GMT">Thu, 03 Nov 2005 23:02:49 GMT</span></p>
|
56
|
+
<p><a href="http://blogs.pragprog.com/cgi-bin/pragdave.cgi">Dave Thomas</a> just <a href="http://blogs.pragprog.com/cgi-bin/pragdave.cgi/Tech/Ruby/ToProc.rdoc">pointed out</a> a great little hack from the <a href="http://extensions.rubyforge.org/">Ruby Extensions Project</a>. They added this little snippet to <code>Object</code>:</p>
|
57
|
+
|
58
|
+
<div class="typocode"><pre><code class="typocode_ruby "><span class="keyword">def </span><span class="method">to_proc</span>
|
59
|
+
<span class="ident">proc</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">obj</span><span class="punct">,</span> <span class="punct">*</span><span class="ident">args</span><span class="punct">|</span> <span class="ident">obj</span><span class="punct">.</span><span class="ident">send</span><span class="punct">(</span><span class="constant">self</span><span class="punct">,</span> <span class="punct">*</span><span class="ident">args</span><span class="punct">)</span> <span class="punct">}</span>
|
60
|
+
<span class="keyword">end</span></code></pre></div>
|
61
|
+
|
62
|
+
<p>and now instead of writing this:</p>
|
63
|
+
|
64
|
+
<div class="typocode"><pre><code class="typocode_ruby "><span class="ident">result</span> <span class="punct">=</span> <span class="ident">names</span><span class="punct">.</span><span class="ident">map</span> <span class="punct">{|</span><span class="ident">name</span><span class="punct">|</span> <span class="ident">name</span><span class="punct">.</span><span class="ident">upcase</span><span class="punct">}</span></code></pre></div>
|
65
|
+
|
66
|
+
<p>you can write this:</p>
|
67
|
+
|
68
|
+
<div class="typocode"><pre><code class="typocode_ruby "><span class="ident">result</span> <span class="punct">=</span> <span class="ident">names</span><span class="punct">.</span><span class="ident">map</span><span class="punct">(&</span><span class="symbol">:upcase</span><span class="punct">)</span></code></pre></div>
|
69
|
+
|
70
|
+
<p>The “wave this method over all objects in a collection” idiom is very common in Ruby, and Ruby’s native block syntax isn’t <em>too</em> bad for this use, but it’s not as clean as Python’s list comprehension syntax would be:</p>
|
71
|
+
|
72
|
+
<div class="typocode"><pre><code class="typocode_python ">result = [n.upper() for n in names]</code></pre></div>
|
73
|
+
|
74
|
+
<p>With the <code>to_proc</code> hack in place, Ruby’s code is a bit cleaner, at the cost of using a non-standard extension to the language. Personally, I’d prefer to see <code>map</code> extended to take an optional symbol, then we could ditch the ugly <code>&</code> when we’re using a single method with no parameters.</p>
|
75
|
+
|
76
|
+
|
77
|
+
<p class="meta">Tags <a href="/articles/tag/programming" rel="tag">programming</a>, <a href="/articles/tag/ruby" rel="tag">ruby</a></p>
|
78
|
+
</div>
|
79
|
+
<div class="post">
|
80
|
+
<h2><a href="/articles/2005/10/31/migrating-in-two-dimensions">Migrating in two dimensions</a></h2>
|
81
|
+
<p class="auth">Posted by Scott Laird
|
82
|
+
<span class="typo_date" title="Mon, 31 Oct 2005 16:32:42 GMT">Mon, 31 Oct 2005 16:32:42 GMT</span></p>
|
83
|
+
<p>This seems to be the season for <a href="http://glu.ttono.us/articles/2005/10/27/the-joy-of-migrations">talking about</a> <a href="http://api.rubyonrails.com/classes/ActiveRecord/Migration.html">Rails migrations</a>. A lot of people are finally discovering them and finding that they’re very useful for maintaining your database schema over time. I’m a big fan of Rails migrations; we’ve been using them with <a href="http://typo.leetsoft.com">Typo</a> since the middle of July, when they were all new and shiny. We’re currently up to 24 migrations in the <a href="http://typo.leetsoft.com/trac/browser/trunk/db/migrate/">Typo source tree</a>. We’re even using migrations to create our initial database, via my <a href="http://scottstuff.net/blog/articles/tag/schema">Schema Generator</a>. I haven’t done a formal survey, but I suspect that Typo is the biggest open-source user of migrations, and may actually be the biggest user overall.</p>
|
84
|
+
|
85
|
+
<p>The big problem is that we’ve been using migrations wrong the whole time, and we just realized it.</p>
|
86
|
+
|
87
|
+
<p>There are probably a dozen bugs in Typo’s bug tracker that boil down to “I fell behind the trunk and now <code>rake migrate</code> throws exceptions and I can’t upgrade anymore.” The problem is that migrations are designed to run against an earlier version of your database, but they use the <em>current</em> version of your code. The first time that this caused problems was with the migration from Typo 2.0 to 2.5–we’d added two new fields to <code>articles</code>. Migration number 7 added the <code>permalink</code> field and a <code>before_save</code> hook to make sure that all saved articles have permalinks. Then migration number 9 added GUIDs and a second <code>before_save</code> hook to fill the <code>guid</code> field. Both migrations did <code>Articles.find(:all).each { |a| a.save }</code> to update each <code>Article</code> and populate the new fields.</p>
|
88
|
+
|
89
|
+
<p>This worked great for developers who frequently upgraded. A few days after the GUID migration went in, though, we started getting weird bug reports–users who tried to do both upgrades at the same time found that migration number 7 was dying. What was happening was that migration number 7 added the new <code>permalink</code> field to <code>articles</code>, but when it went to run the <code>save</code> loop <em>both</em> <code>before_save</code> hooks ran, and Typo tried to add a GUID to each article. However, the <code>guid</code> field didn’t exist yet, so the migration threw a bunch of exceptions and died.</p>
|
90
|
+
|
91
|
+
<p>This caused a bunch of grumbling on the Typo IRC channel. We threw around a bunch of possible fixes. Our favorite was separating migrations into two parts–a schema change part and a data change part. First we’d run all of the schema changes, and then update all of the data. As a work-around, we added a hack that checked the current schema version and disabled specific <code>before_save</code> filters for older versions.</p>
|
92
|
+
|
93
|
+
<p>We managed to keep this little bandaid working until a couple weeks ago, when a huge set of new migrations went it; they renamed the <code>articles</code> table and merged several other tables into the new <code>contents</code> table using <a href="http://wiki.rubyonrails.com/rails/pages/SingleTableInheritance">STI</a>. And, again, we found that older migrations broke when users tried to upgrade from Typo 2.5.6 to the current dev tree. Unlink the permalink/guid case, this time there was no simple workaround. We couldn’t just add a couple <code>if</code> statements in a filter and make it all go away.</p>
|
94
|
+
|
95
|
+
<p>The fundamental problem is that we were using the wrong mental model for migrations. I saw migrations as a one-dimensional thing–a list of steps for migrating old data into the new format. In this view, the migration for going from schema version 6 to schema version 7 is constant–once it’s been written, the only reason to change it is if a bug turns up in the logic for that migration. Otherwise, the migration code should remain unchanged over time.</p>
|
96
|
+
|
97
|
+
<p>And that’s the problem–migrations <em>aren’t</em> one-dimensional. They are (and <em>need to be</em>) two dimensional–the schema version is one dimension and the code version is the other. Individual migrations exist to migrate from a specific old schema version to the current version, <em>using the current code</em>. Each migration <em>should</em> change over time to adapt to the changes in the code. So, the right fix for the <code>permalink</code> migration that caused so many problems <em>wasn’t</em> to add a bunch of logic to <code>before_save</code>. Instead, we should have deleted the entire <code>save</code> loop from the migration, and trusted the GUID migration to update both fields. If that wasn’t good enough, then we should have added a new migration at the end to do permalink cleanup after the GUIDs were added.</p>
|
98
|
+
|
99
|
+
<p>Once I came to grips with this, the migration changes needed to allow 2.5.x users to upgrade to the current trunk were pretty simple, and took about 5 minutes to write and test.</p>
|
100
|
+
|
101
|
+
<p>Or was I the only person in the Rails universe who thought about migrations this way?</p>
|
102
|
+
|
103
|
+
|
104
|
+
<p class="meta">Tags <a href="/articles/tag/database" rel="tag">database</a>, <a href="/articles/tag/migrations" rel="tag">migrations</a>, <a href="/articles/tag/ruby" rel="tag">ruby</a>, <a href="/articles/tag/rubyonrails" rel="tag">rubyonrails</a>, <a href="/articles/tag/typo" rel="tag">typo</a></p>
|
105
|
+
</div>
|
106
|
+
<div class="post">
|
107
|
+
<h2><a href="/articles/2005/10/30/have-you-seen-my-shutter">Have you seen my shutter?</a></h2>
|
108
|
+
<p class="auth">Posted by Scott Laird
|
109
|
+
<span class="typo_date" title="Mon, 31 Oct 2005 03:49:49 GMT">Mon, 31 Oct 2005 03:49:49 GMT</span></p>
|
110
|
+
<p>This was one of those weekends where I practically lived with a camera in my hand; I took around 500 halloween pictures yesterday and then moved on to Christmas-card pictures of the kids today. Everything was going well enough until late in the day, when I was trying to get a nice black and white shot of my son. In the middle of shooting I took a quick peek at my camera’s LCD display and noticed that the last shot had been <em>completely</em> underexposed. So I scrolled back a few shots and discovered that I’d been shooting nothing but black frames for about 30 seconds. One second it worked, the next it didn’t. All of the camera settings were the same–same aperture, ISO, and shutter speed. Same light. But no picture.</p>
|
111
|
+
|
112
|
+
<p>I double-checked things, but I was still getting nothing but black. With a sinking feeling, I popped the lens off and took a multi-second exposure while staring into the camera. I could see the mirror flip up, but instead of seeing the sensor, I was left staring at a closed shutter, which strongly suggests that my shutter has died. The shutter on my D60 is rated for 30,000 exposures, and I think I’m around 25,000 right now, so it’s a bit earlier then normal, but not utterly unexpected.</p>
|
113
|
+
|
114
|
+
<p>So, I guess I’ll be packing it up and shipping it off to Canon for service this week. I’m not sure how long it’ll take to get back, but I was hoping to use it at <a href="http://www.seattlemind.com">Mind Camp</a> next weekend. It looks like I’m going to have to make alternate plans.</p>
|
115
|
+
|
116
|
+
|
117
|
+
<p class="meta">Tags <a href="/articles/tag/broken" rel="tag">broken</a>, <a href="/articles/tag/camera" rel="tag">camera</a>, <a href="/articles/tag/photography" rel="tag">photography</a></p>
|
118
|
+
</div>
|
119
|
+
<div class="post">
|
120
|
+
<h2><a href="/articles/2005/10/27/flickr-adds-printing">Flickr adds printing</a></h2>
|
121
|
+
<p class="auth">Posted by Scott Laird
|
122
|
+
<span class="typo_date" title="Thu, 27 Oct 2005 14:01:05 GMT">Thu, 27 Oct 2005 14:01:05 GMT</span></p>
|
123
|
+
<p><a href="http://flickr.com">Flickr</a> has finally added <a href="http://blog.flickr.com/flickrblog/2005/10/your_photos_on_.html">photo printing</a>. As of today, US Flickr members can get 4x6 prints for $0.15. They also sell other sizes (5x7, 8x10, wallet, 5x5, [458]xD, and 20x30), but the other prices aren’t quite as enticing.</p>
|
124
|
+
|
125
|
+
<p>By default, you’re the only one allowed to print your pictures; it’s a safe default for Flickr, but I don’t really care <em>who</em> prints my pictures any more then I care who looks at them. If I wanted them to be private, I wouldn’t have put them on Flickr. You can change the setting via your flickr preference page; I changed mine so any Flickr member can order prints.</p>
|
126
|
+
|
127
|
+
<p>Er, well, <em>some</em> Flickr members can order prints. For now, the printing service is US-only. Considering that Flickr was a Canadian company (until Yahoo snapped them up), I find the US-centric printing kind of funny. They claim that they’re working on adding more countries.</p>
|
128
|
+
|
129
|
+
<p>I’ll probably order a few prints to test it out, but I doubt I’ll use Flickr’s printing service much, for the same reason that I’ve never been willing to use <em>any</em> of the online photo-printing places: they don’t do color management, so there’s no guarantee that your prints will look anything like the images on your screen. Instead, I use the profiles from <a href="http://drycreekphoto.com/">Dry Creek Photo</a>, burn a CD, and take it to my local Costco. I’ve had very good luck this way–I’ve churned out batches of 300 images without <em>any</em> problems or rejects before. The only problem is that I need to burn a CD and then make a couple trips to Costco; one to drop off the CD and another to pick up the prints. Most of the time, I’d rather just click “print” and wait a few days for a package to show up in the mail. There are a number of professional photo finishers that will accept color-managed images via FTP, but none of them are even close to being price-competitive with Flickr or Costco, and for big batches of 4x6 or 5x7 prints, price matters.</p>
|
130
|
+
|
131
|
+
<p>Which brings me back around to Apple’s <a href="http://www.apple.com/aperture/">Aperture</a> again. One of the minor features that they’re touting is color-managed printing from within Aperture. I’d <em>love</em> that. Unfortunately, I’m not about to run out and buy a PowerMac and Aperture just to make photo printing easier, but it’s definitely a step in the right direction.</p>
|
132
|
+
|
133
|
+
<p>On the other hand, while Flickr’s non-color-managed prints may not be quite what <em>I’m</em> looking for, they’ll almost certainly save me a lot of hassle–I get a lot of requests for prints from friends and family, and I hate doing one-off prints for people. Now I can just point them to Flickr and let them do it themselves.</p>
|
134
|
+
|
135
|
+
|
136
|
+
<p class="meta">Tags <a href="/articles/tag/aperture" rel="tag">aperture</a>, <a href="/articles/tag/flickr" rel="tag">flickr</a>, <a href="/articles/tag/photography" rel="tag">photography</a>, <a href="/articles/tag/printing" rel="tag">printing</a></p>
|
137
|
+
</div>
|
138
|
+
<div class="post">
|
139
|
+
<h2><a href="/articles/2005/10/24/the-great-typo-memory-leak">The Great Typo Memory Leak</a></h2>
|
140
|
+
<p class="auth">Posted by Scott Laird
|
141
|
+
<span class="typo_date" title="Mon, 24 Oct 2005 19:30:55 GMT">Mon, 24 Oct 2005 19:30:55 GMT</span></p>
|
142
|
+
<p>A number of users <a href="http://rubyforge.org/pipermail/typo-list/2005-October/000893.html">complained</a> this weekend that <a href="http://typo.leetsoft.com">Typo</a> was using <em>way</em> too much memory, with reports of 100+ MB per FastCGI dispatcher. Typo usually uses around 20 MB, and even that’s too much; 100 MB is enough to cause big problems with hosting providers like <a href="http://www.textdrive.com">TextDrive</a>.</p>
|
143
|
+
|
144
|
+
<p>The first step that I took was to verify that the problem actually exists outside of TextDrive. I set up a test Apache/FastCGI/Typo server, disabled caching, and then pounded on it using <code>curl</code>:</p>
|
145
|
+
|
146
|
+
<div class="typocode"><pre><code class="typocode_default "># while true; do curl http://typo1/ > /dev/null; done</code></pre></div>
|
147
|
+
|
148
|
+
<p>I let that run for a few seconds and watched while my <code>dispatch.fcgi</code> processes grew from 22 MB to 80 MB. I then did a bit of experimenting:</p>
|
149
|
+
|
150
|
+
<ul>
|
151
|
+
<li>The main index page leaked</li>
|
152
|
+
<li>RSS feeds <strong>didn’t</strong> leak</li>
|
153
|
+
<li>Individual article pages leak</li>
|
154
|
+
<li>Static pages, like <code>/pages/about</code> leak</li>
|
155
|
+
<li>Error pages even leak</li>
|
156
|
+
</ul>
|
157
|
+
|
158
|
+
<p>Disabling the layout for a leaking page and then re-testing it showed that the leak followed the layout. Turning layouts back on and removing the sidebar block fixed the leak.</p>
|
159
|
+
|
160
|
+
<p>Entertainingly enough, disabling the sidebar from <em>inside</em> of the sidebar infrastructure didn’t fix the leak. The mere act of calling <code>render_component</code> to generate the sidebars seemed to be causing the memory leak. Since Typo is one of the very few users of Rails components, this suggests that <code>render_component</code> may have a leak that no one else has noticed, so I created a new test Rails app with only two files. First, <code>app/controllers/foo_controller.rb</code>:</p>
|
161
|
+
|
162
|
+
<div class="typocode"><pre><code class="typocode_ruby "><span class="keyword">class </span><span class="class">FooController</span> <span class="punct"><</span> <span class="constant">ApplicationController</span>
|
163
|
+
<span class="keyword">def </span><span class="method">bar</span>
|
164
|
+
<span class="ident">render_component</span> <span class="symbol">:layout</span> <span class="punct">=></span> <span class="constant">false</span><span class="punct">,</span>
|
165
|
+
<span class="symbol">:controller</span> <span class="punct">=></span> <span class="punct">'</span><span class="string">sidebars/sidebar</span><span class="punct">',</span> <span class="symbol">:action</span> <span class="punct">=></span> <span class="punct">'</span><span class="string">index</span><span class="punct">'</span>
|
166
|
+
<span class="keyword">end</span>
|
167
|
+
<span class="keyword">end</span></code></pre></div>
|
168
|
+
|
169
|
+
<p>Then <code>components/sidebars/sidebar_controller.rb</code>:</p>
|
170
|
+
|
171
|
+
<div class="typocode"><pre><code class="typocode_ruby "><span class="keyword">module </span><span class="module">Sidebars</span>
|
172
|
+
<span class="keyword">class </span><span class="class">SidebarController</span> <span class="punct"><</span> <span class="constant">ApplicationController</span>
|
173
|
+
<span class="keyword">def </span><span class="method">index</span>
|
174
|
+
<span class="ident">render</span> <span class="symbol">:text</span> <span class="punct">=></span> <span class="punct">'</span><span class="string">test</span><span class="punct">',</span> <span class="symbol">:layout</span> <span class="punct">=></span> <span class="constant">false</span>
|
175
|
+
<span class="keyword">end</span>
|
176
|
+
<span class="keyword">end</span>
|
177
|
+
<span class="keyword">end</span></code></pre></div>
|
178
|
+
|
179
|
+
<p>This is about as minimal as a Rails app can get. Then I set up a FastCGI server running this project, and ran <code>curl</code> against <code>/foo/bar</code>, and watched the process size climb. So the leak is part of Rails, not really part of Typo.</p>
|
180
|
+
|
181
|
+
<p>Unfortunately, I’m not sure where the leak is coming from. I read <code>component.rb</code> and made a few small changes, but the leak hasn’t stopped. So I’m going to file this as a Rails bug and see if we can get it fixed before 1.0.</p>
|
182
|
+
|
183
|
+
<p><strong>Update</strong>: Rails bug <a href="http://dev.rubyonrails.com/ticket/2589">2589</a>.</p>
|
184
|
+
|
185
|
+
<p><strong>Update</strong>: Thanks to <a href="http://scott.elitists.net/">Scott Barron</a>, the bug has been <a href="http://dev.rubyonrails.com/changeset/2722">fixed</a>. Users with memory problems should probably install the patch, although a bit of testing would obviously be recommended first. The next release of Rails (either 1.0rc3 or 1.0; I’m not sure what they’re planning) should include this fix.</p>
|
186
|
+
|
187
|
+
|
188
|
+
<p class="meta">Posted in <a href="/articles/category/Typo" rel="tag">Typo</a> <strong>|</strong> Tags <a href="/articles/tag/memoryleak" rel="tag">memoryleak</a>, <a href="/articles/tag/ruby" rel="tag">ruby</a>, <a href="/articles/tag/rubyonrails" rel="tag">rubyonrails</a>, <a href="/articles/tag/typo" rel="tag">typo</a></p>
|
189
|
+
</div>
|
190
|
+
<div class="post">
|
191
|
+
<h2><a href="/articles/2005/10/24/rails-schema-generator-0-2-0">Rails Schema Generator 0.2.0</a></h2>
|
192
|
+
<p class="auth">Posted by Scott Laird
|
193
|
+
<span class="typo_date" title="Mon, 24 Oct 2005 17:25:30 GMT">Mon, 24 Oct 2005 17:25:30 GMT</span></p>
|
194
|
+
<p>I just uploaded <a href="http://rubyforge.org/projects/schemagenerator/">version 0.2.0</a> of my <a href="http://scottstuff.net/blog/articles/2005/09/03/rails-schema-generator-0-1-0">Rails Schema Generator</a> to <a href="http://rubyforge.org">Rubyforge</a>. This is a minor update, but it was needed to make the schema generator work with <a href="http://rubyonrails.com">Rails</a> 1.0rc2 (AKA 0.14.1).</p>
|
195
|
+
|
196
|
+
<p>The schema generator is sort of the flip side of the new <a href="http://documentation.rubyonrails.com/release_notes/rc2.html">schema code</a> in Rails 1.0. It takes a set of Rails migrations, aggregates them all together, and spits out a SQL file that describes the DB that you’d get if you ran all of the migrations. Or, viewed in a more useful light, it gives you a SQL file that you can use to create a new DB from scratch. The current version actually produces three different schema files, one for PostgreSQL, one for MySQL, and one for SQLite, each with DB-appropriate syntax and types.</p>
|
197
|
+
|
198
|
+
<p>This is an outgrowth of <a href="http://typo.leetsoft.com">Typo</a>; we’re up to 25 migrations now, and we actively support 3 different DBs. It was getting really painful to maintain 3 distinct schema files in addition to the collection of migrations, so I wrote this schema generator. Now we’re back to DRY-land–we create new migrations and let the schema generator do all of the hard work.</p>
|
199
|
+
|
200
|
+
|
201
|
+
<p class="meta">Tags <a href="/articles/tag/database" rel="tag">database</a>, <a href="/articles/tag/generator" rel="tag">generator</a>, <a href="/articles/tag/ruby" rel="tag">ruby</a>, <a href="/articles/tag/rubyonrails" rel="tag">rubyonrails</a>, <a href="/articles/tag/schema" rel="tag">schema</a>, <a href="/articles/tag/schemagenerator" rel="tag">schemagenerator</a></p>
|
202
|
+
</div>
|
203
|
+
<div class="post">
|
204
|
+
<h2><a href="/articles/2005/10/24/tom-douglass-iron-chef-party">Tom Douglas's Iron Chef Party</a></h2>
|
205
|
+
<p class="auth">Posted by Scott Laird
|
206
|
+
<span class="typo_date" title="Mon, 24 Oct 2005 12:25:55 GMT">Mon, 24 Oct 2005 12:25:55 GMT</span></p>
|
207
|
+
<p>It looks like the long-fabled <a href="http://www.foodnetwork.com/food/show_ia">Iron Chef America</a> episode featuring <a href="http://tomdouglas.com/">Tom Douglas</a> is finally going to air.</p>
|
208
|
+
|
209
|
+
<p>And he’s throwing a party. From the <a href="http://seattlepi.nwsource.com/food/245517_tf224.html">Seattle P-I</a>:</p>
|
210
|
+
|
211
|
+
<blockquote>
|
212
|
+
<p>The “Battle Salmon” pitting Masaharu Morimoto against our own Tom Douglas will air on Nov. 6, and Douglas is hosting a dinner-and-viewing that night, starting at 6:30 p.m. at the Palace Ballroom, 2100 Fifth Ave.</p>
|
213
|
+
|
214
|
+
<p>Douglas promises slightly kitschy festivities featuring the same five-course meal he and colleagues Mark Fuller and Eric Tanaka presented in the Food Network show, plus a Japanese hachimaki headband, two cocktails, and a chance to watch the show ($95/person). For reservations call 206-448-2001.</p>
|
215
|
+
</blockquote>
|
216
|
+
|
217
|
+
<p>That’s a bit steep for me, but I’d still be tempted if it wasn’t the same day as <a href="http://seattlemind.com">Mind Camp</a>.</p>
|
218
|
+
|
219
|
+
|
220
|
+
<p class="meta">Tags <a href="/articles/tag/ironchef" rel="tag">ironchef</a>, <a href="/articles/tag/salmon" rel="tag">salmon</a>, <a href="/articles/tag/seattle" rel="tag">seattle</a>, <a href="/articles/tag/tomdouglas" rel="tag">tomdouglas</a></p>
|
221
|
+
</div>
|
222
|
+
<div class="post">
|
223
|
+
<h2><a href="/articles/2005/10/21/seattle-mind-camp">Seattle Mind Camp</a></h2>
|
224
|
+
<p class="auth">Posted by Scott Laird
|
225
|
+
<span class="typo_date" title="Fri, 21 Oct 2005 15:42:57 GMT">Fri, 21 Oct 2005 15:42:57 GMT</span></p>
|
226
|
+
<p>Apparently I need to track more local blogs, because I missed the original announcement of the <a href="http://seattlemind.com">Seattle MindCamp</a>. Fortunately, <a href="http://www.sauria.com/blog">Ted Leung</a> pointed it out to me, or I probably would have missed it entirely. This should be interesting–it’s essentially a local version of <a href="http://wiki.oreillynet.com/foocamp05/index.cgi">Foo Camp</a> (or <a href="http://barcamp.org/">Bar Camp</a>), held in an office building over a 26-hour span during the first weekend in November.</p>
|
227
|
+
|
228
|
+
<p>From the MindCamp website:</p>
|
229
|
+
|
230
|
+
<blockquote>
|
231
|
+
<p>Seattle Mind Camp is a self-organizing, digitally minded, entrepreneur-driven, overnight Seattle confab. What happens when you put 150 of Seattle’s smartest geeks in an empty office building for 24 hours? We’re not sure either, but we’d like to find out. It’s time to meet and connect with those involved in the interesting projects going on in Seattle in a relaxed environment.</p>
|
232
|
+
|
233
|
+
<p><em>What</em>: A weekend, 24-hour, multi-track event. Think huge space with breakout rooms, broadband Wi-Fi, projectors, white boards - and you.</p>
|
234
|
+
|
235
|
+
<p><em>Who</em>: 150 of Seattle’s forward thinkers: techies, entrepreneurs, executives, gamers, musicians, and anyone else with a great idea.</p>
|
236
|
+
|
237
|
+
<p><em>When</em>: Mind Camp will take place on November 5-6</p>
|
238
|
+
|
239
|
+
<p><em>Why?</em>: You know all those hallway conversations that never get to flourish during a “normal” conference? Now they will.</p>
|
240
|
+
|
241
|
+
<p>Seattle Mind Camp is completely free of charge, and registration will begin very soon. In the meantime, check out the <a href="http://www.seattlemind.com/index.php/mindcamp/about/">About page</a> for a little more information.</p>
|
242
|
+
</blockquote>
|
243
|
+
|
244
|
+
<p>It looks like there are still a few spots left, but I doubt they’ll last very long.</p>
|
245
|
+
|
246
|
+
<p><strong>Update</strong>: In the spirit of information spreading, I should probably mention <a href="http://pacwest.ms/codecamp/sea/1/">Seattle Code Camp</a>, which is happening this weekend. From looking at the code camp website, it looks a bit more organized, with pre-scheduled talks, and there seems to be a big Microsoft/C#/.NET focus on a lot of the events. There are a couple Perl/Linux sessions and an introduction to Ruby, as well as a pair of Cocoa/Objective C talks, but most of the content seems to be “cool new stuff in C#.” Which is fine, but it’s not really my sort of conference. MindCamp, on the other hand, seems to be drawing a more diverse crowd, with a number of open source people on the roster.</p>
|
247
|
+
|
248
|
+
|
249
|
+
<p class="meta">Posted in <a href="/articles/category/Seattle" rel="tag">Seattle</a> <strong>|</strong> Tags <a href="/articles/tag/hacking" rel="tag">hacking</a>, <a href="/articles/tag/mindcamp" rel="tag">mindcamp</a>, <a href="/articles/tag/seattle" rel="tag">seattle</a>, <a href="/articles/tag/seattlemindcamp" rel="tag">seattlemindcamp</a></p>
|
250
|
+
</div>
|
251
|
+
<div class="post">
|
252
|
+
<h2><a href="/articles/2005/10/20/the-rails-book-is-number-one-on-amazon">The Rails Book is number one on Amazon</a></h2>
|
253
|
+
<p class="auth">Posted by Scott Laird
|
254
|
+
<span class="typo_date" title="Thu, 20 Oct 2005 23:30:21 GMT">Thu, 20 Oct 2005 23:30:21 GMT</span></p>
|
255
|
+
<p><a href="http://blogs.pragprog.com/cgi-bin/pragdave.cgi">Dave Thomas</a> has a nice little <a href="http://blogs.pragprog.com/cgi-bin/pragdave.cgi/Tech/Ruby/TopTen.htm">announcement</a>, complete with screenshot: <a href="http://www.amazon.com/exec/obidos/ASIN/097669400X/scottstuff-20">Agile Web Development with Rails</a> is the best-selling programming book on Amazon.com. Even better, <a href="http://www.amazon.com/exec/obidos/ASIN/0974514055/scottstuff-20">Programming Ruby</a> has the number two spot. Corgratulations.</p>
|
256
|
+
|
257
|
+
|
258
|
+
<p class="meta">Posted in <a href="/articles/category/Ruby" rel="tag">Ruby</a> <strong>|</strong> Tags <a href="/articles/tag/rubyonrails" rel="tag">rubyonrails</a></p>
|
259
|
+
</div>
|
260
|
+
<div class="post">
|
261
|
+
<h2><a href="/articles/2005/10/19/typo-2-5-6-and-rails-1-0">Typo 2.5.6 and Rails 1.0</a></h2>
|
262
|
+
<p class="auth">Posted by Scott Laird
|
263
|
+
<span class="typo_date" title="Thu, 20 Oct 2005 01:37:53 GMT">Thu, 20 Oct 2005 01:37:53 GMT</span></p>
|
264
|
+
<p>As far as I can see, <a href="http://typo.leetsoft.com">Typo</a> 2.5.6 (the most recently released stable version) should work fine with <a href="http://www.rubyonrails.com">Rails</a> 1.0. I just did a brief round of testing with 1.0rc2, and all of the tests pass. Er, except for one test that had a stupid typo that somehow still worked with Rails 0.13.1; the bug is in the test itself, though, so it’s not worth releasing Typo 2.5.7 just for that. If we ever release Typo 2.5.7, then I’ll make sure that the fixed test is included.</p>
|
265
|
+
|
266
|
+
<p>Also, Typo 2.5.6 should work just fine with Ruby 1.8.3, too, as long as you’re using Rails 1.0. I haven’t actually tested this yet, but I’d be surprised if it doesn’t work perfectly.</p>
|
267
|
+
|
268
|
+
<p>Surprisingly enough, the current Typo trunk (r683 or so) <em>doesn’t</em> work with Rails 1.0. All of the filtering code is broken; I’ll fix it shortly and check in the fix. Fortunately, the current Typo trunk is pinned to Rails 0.13.1 for now, so it should be safe to upgrade the version of Rails on the box; Typo will just ignore the new Rails for now.</p>
|
269
|
+
|
270
|
+
<p><strong>Update</strong>: the Typo trunk r685 or later should be compatible with Rails 1.0rc2. I’ll probably break Rails 0.13.1 compatibility soon, so it’s time to upgrade.</p>
|
271
|
+
|
272
|
+
|
273
|
+
<p class="meta">Posted in <a href="/articles/category/Typo" rel="tag">Typo</a> <strong>|</strong> Tags <a href="/articles/tag/ruby" rel="tag">ruby</a>, <a href="/articles/tag/rubyonrails" rel="tag">rubyonrails</a>, <a href="/articles/tag/typo" rel="tag">typo</a></p>
|
274
|
+
</div>
|
275
|
+
<div class="post">
|
276
|
+
<h2><a href="/articles/2005/10/19/typo-and-ruby-1-8-3">Typo and Ruby 1.8.3</a></h2>
|
277
|
+
<p class="auth">Posted by Scott Laird
|
278
|
+
<span class="typo_date" title="Wed, 19 Oct 2005 14:51:48 GMT">Wed, 19 Oct 2005 14:51:48 GMT</span></p>
|
279
|
+
<p>Just for the record, current versions of <a href="http://typo.leetsoft.com">Typo</a> (either 2.5.6 or the current Subversion trunk) don’t work with Ruby 1.8.3. There are two problems–the <code>Logger</code> bug that keeps Rails 0.13.1 from working with Ruby 1.8.3 (this is easy to fix), and a second bug that I haven’t read about anywhere else–apparently YAML serialization is broken with Ruby 1.8.3 and Rails 0.13.1. This keeps Typo’s sidebar from working properly.</p>
|
280
|
+
|
281
|
+
<p>I’m going to see what it’ll take to get the Typo trunk working with Rails 1.0 (rc1 or rc2, if it’s out today), and then see if it works properly with Ruby 1.8.3. Once that’s done, the trunk will probably shift from 0.13.1-only to 1.0-only.</p>
|
282
|
+
|
283
|
+
<p><strong>Update</strong>: That was quick. ChrisNolan on IRC pointed out that Rails bug <a href="http://dev.rubyonrails.com/ticket/2304">#2304</a> contains a patch to fix this. The patch is already a part of the current Rails trunk, but you’ll need to patch 0.13.1 manually if you want to use it with Ruby 1.8.3.</p>
|
284
|
+
|
285
|
+
|
286
|
+
<p class="meta">Posted in <a href="/articles/category/Typo" rel="tag">Typo</a> <strong>|</strong> Tags <a href="/articles/tag/ruby" rel="tag">ruby</a>, <a href="/articles/tag/rubyonrails" rel="tag">rubyonrails</a>, <a href="/articles/tag/typo" rel="tag">typo</a></p>
|
287
|
+
</div>
|
288
|
+
<div class="post">
|
289
|
+
<h2><a href="/articles/2005/10/17/benchmarking-typo">Benchmarking Typo</a></h2>
|
290
|
+
<p class="auth">Posted by Scott Laird
|
291
|
+
<span class="typo_date" title="Mon, 17 Oct 2005 16:51:13 GMT">Mon, 17 Oct 2005 16:51:13 GMT</span></p>
|
292
|
+
<p>I finally had a bit of time to do some <a href="http://typo.leetsoft.com">Typo</a> benchmarking over the weekend and (as usual) found that my instincts were all wrong.</p>
|
293
|
+
|
294
|
+
<p>I was specifically interested in the performance difference between the <a href="http://api.rubyonrails.com/classes/ActionController/Caching/Pages.html">page cache</a> and the <a href="http://api.rubyonrails.com/classes/ActionController/Caching/Actions.html">action cache</a>–my guess was that the action cache was a 10x performance hit.</p>
|
295
|
+
|
296
|
+
<p>So I set up a test environment under Xen, running Typo r683, PostgreSQL, Apache 2, FastCGI, Ruby 1.8.2, and Rails 0.13.1. I didn’t do any Apache or Postgres tuning–I just ran them out of the box.</p>
|
297
|
+
|
298
|
+
<p>Then I ran <a href="http://httpd.apache.org/docs/2.1/programs/ab.html"><code>ab</code></a> against a snapshot of <a href="http://scottstuff.net">scottstuff.net</a> from a couple weeks ago. I used the index page for my testing, as it’s a fairly large page and I wanted to give Typo a real workout.</p>
|
299
|
+
|
300
|
+
<p>Here’s what I found:</p>
|
301
|
+
|
302
|
+
<div align="center">
|
303
|
+
<table>
|
304
|
+
<tr><th>Cache Type</th><th>Requests per second</th></tr>
|
305
|
+
<tr><td>Page Cache</td><td align="right">2357</td></tr>
|
306
|
+
<tr><td>Action Cache</td><td align="right">10.6</td></tr>
|
307
|
+
<tr><td>No cache</td><td align="right">1.01</td></tr>
|
308
|
+
</table>
|
309
|
+
</div>
|
310
|
+
|
311
|
+
<p>That really wasn’t what I’d expected. The action cache underperformed my expectations by a factor of 20.</p>
|
312
|
+
|
313
|
+
<p>I then did a bit of experimentation. I created a new uncached action in my test Typo setup that did nothing but <code>render :text => 'foo', :layout => false</code>, just to see if the caching system was slowing things down. Result? 10 requests/second. Then I created a new Rails project from scratch and added a new controller with the same action, and saw the same results. Still 10 requests/second.</p>
|
314
|
+
|
315
|
+
<p>However, in Rails’s logs, it said that it handled the request in 2 ms, and I should be seeing 500 hits/sec for the “foo” page. So something is adding an extra 98 ms to each request. I’m still hunting for this–I don’t know if it’s something Xen-related on my system, an artifact of my Apache config, or what.</p>
|
316
|
+
|
317
|
+
<p>I’ve tried upgrading to Rails 0.14.0, but that’s a whole <em>other</em> article.</p>
|
318
|
+
|
319
|
+
<p>Conclusions:</p>
|
320
|
+
|
321
|
+
<ol>
|
322
|
+
<li>The page cache is really, really fast.</li>
|
323
|
+
<li>The action cache is a substantial improvement over the uncached case–about 10x on this system–but can’t touch the performance of the page cache.</li>
|
324
|
+
<li>Changing the concurrency settings on <code>ab</code> and/or the number of FastCGI backends in use didn’t make a substantial performance difference. Settings 2-15 gave roughly the same results.</li>
|
325
|
+
<li>My <a href="http://typo.leetsoft.com/trac/attachment/ticket/437/action_cache.patch"><code>caches_action_with_params</code></a> is slightly faster then the stock action cache.</li>
|
326
|
+
<li>Moving the action/fragment cache from the FileStore (Typo default) to MemoryStore gives no real performance boost. Moving to the MemCacheStore is a substantial performance hit (~2 hits/sec vs 10 hits/sec).</li>
|
327
|
+
<li>Adding a new uncached action in ArticlesController that simply returns a fixed string (<code>render :layout => false, :text => 'foo'</code>) is no faster then the action cache.</li>
|
328
|
+
<li>Moving the new action from the previous step to a Controller of its own doesn’t help.</li>
|
329
|
+
<li>Removing all of the routes except the default <code>:controller/:action/:id</code> route doesn’t help, either.</li>
|
330
|
+
</ol>
|
331
|
+
|
332
|
+
<p>Frankly, on this hardware, I don’t seem to be able to get more then 10 requests/sec out of Rails no matter what I do. I’m pretty sure that this is a mistake, so I’ll post a followup when I figure out what’s wrong.</p>
|
333
|
+
|
334
|
+
<p><strong>Update 1</strong>: Another datapoint. Running an <a href="http://www.rubygarden.org/ruby?FCGIExampleProgramThatPrintsTheEnvironment">example Ruby FCGI</a> on this box gives me 832 hits per second. So whatever the problem is, it’s not fundamental to Ruby FCGI on this box. So I need to look into Rails and see what’s happening.</p>
|
335
|
+
|
336
|
+
<p><strong>Update 2</strong>: Making some progress. Apparently I screwed up when I tested a new, standalone Rails FCGI app before (forgot to restart FCGI?). This time, I got 130 req/sec, which is a vast improvement over the 10 req/sec that I was seeing before. Most of that speed hit seems to come from using Postgres for session storage. Unfortunately, even after making that change, my null controller is still only getting 40 req/sec with Typo. Transporting the same controller to a blank Rails project gives me 130 req/sec with the same code. Watching strace, it looks like something is forcing Typo to reload the <code>digest/md5</code> module for every hit. Unfortunately, I can’t figure out how that’s happening–my <code>environment.rb</code> is identical between the two trees, as is my <code>database.yml</code>. I’ll get back to this later; I have other things that I need to finish today.</p>
|
337
|
+
|
338
|
+
|
339
|
+
<p class="meta">Posted in <a href="/articles/category/Typo" rel="tag">Typo</a> <strong>|</strong> Tags <a href="/articles/tag/apache" rel="tag">apache</a>, <a href="/articles/tag/benchmark" rel="tag">benchmark</a>, <a href="/articles/tag/caching" rel="tag">caching</a>, <a href="/articles/tag/rubyonrails" rel="tag">rubyonrails</a>, <a href="/articles/tag/typo" rel="tag">typo</a></p>
|
340
|
+
</div>
|
341
|
+
<div class="post">
|
342
|
+
<h2><a href="/articles/2005/10/12/nokia-e-series">Nokia E-series</a></h2>
|
343
|
+
<p class="auth">Posted by Scott Laird
|
344
|
+
<span class="typo_date" title="Wed, 12 Oct 2005 16:43:22 GMT">Wed, 12 Oct 2005 16:43:22 GMT</span></p>
|
345
|
+
<p>Nokia <a href="http://news.com.com/E-mail+gets+top+billing+in+new+Nokia+phones/2100-1037_3-5893624.html?part=rss&tag=5893624&subj=news">announced</a> a new block of phones today: the E60, E61, and E70. Unlike the earlier (and still pending) <a href="http://www.nokia.com/nseries/">N-series</a>, these are aimed towards corporate users. All three run Series 60 3rd edition and include 802.11g and Bluetooth. They also come with a SIP client so they can interact with business VoIP systems. The low-end model, the <a href="http://www.mobileburn.com/news.jsp?Id=1710&source=RELATED">E60</a> is yet another Series 60 candybar phone, like the 6682 and N70, but with WiFi. The <a href="http://www.mobileburn.com/news.jsp?Id=1711&source=HOME">E61</a> is a Blackberry-like model with a QWERTY keyboard and landscape display. Finally, the <a href="http://www.mobileburn.com/news.jsp?Id=1712&source=RELATED">E70</a> is a “handlebar” style phone that flips open to reveal a keyboard, half on the left side of the display and half on the right.</p>
|
346
|
+
|
347
|
+
<p>After playing with the Nokia 6682 and 9300 yesterday, I’m starting to think that a keyboard would be really nice. I might actually be more interested in the E70 then the <a href="http://scottstuff.net/blog/articles/2005/07/08/nokia-n91-lust">N91</a>. Here’s how they compare:</p>
|
348
|
+
|
349
|
+
<p>Same:</p>
|
350
|
+
|
351
|
+
<ul>
|
352
|
+
<li>802.11g, bluetooth, 3G</li>
|
353
|
+
<li>Series 60, 3rd edition</li>
|
354
|
+
<li>2 MP camera</li>
|
355
|
+
<li>Scheduled for 1Q 2006 release</li>
|
356
|
+
<li>Similar sizes: (N91: 113.1x55.2x22, E70: 117x53x22)</li>
|
357
|
+
</ul>
|
358
|
+
|
359
|
+
<p>N91’s favor:</p>
|
360
|
+
|
361
|
+
<ul>
|
362
|
+
<li>4 GB hard drive</li>
|
363
|
+
<li>3.5mm headphone jack</li>
|
364
|
+
</ul>
|
365
|
+
|
366
|
+
<p>E70’s favor:</p>
|
367
|
+
|
368
|
+
<ul>
|
369
|
+
<li>built-in SIP client (might be on N91 also)</li>
|
370
|
+
<li>high-res display (352x416, 4x the pixel count)</li>
|
371
|
+
<li>QWERTY keyboard</li>
|
372
|
+
<li>miniSD slot (1 GB for $75, partially counters the HD on the N91)</li>
|
373
|
+
<li>lighter (127g vs 160g)</li>
|
374
|
+
</ul>
|
375
|
+
|
376
|
+
<p>I’m not sure if the E70 includes the video player that comes on the N91. It’s <em>possible</em> that it includes a 3.5mm headphone jack–the specs list a MP3/AAC player application. The pricing rumors that I’ve seen put the whole E-series around €500 or so, which means that they may actually be cheaper then the N91.</p>
|
377
|
+
|
378
|
+
<p>Of course, availability is the key. The N91 was announced <em>months</em> ago, while the E70 is new. However, the E70 isn’t quite as innovative as the N91, so there’s a chance that they’ll arrive on the market (in Europe at least) in a similar timeframe. I have no idea which one will make it through the FCC first. I’m not particularly concerned about US carriers carrying the phone, now that Nokia is <a href="http://scottstuff.net/blog/articles/2005/07/22/nokias-selling-phones-directly-to-us-consumers-now">selling directly to US consumers</a>. With any luck, our local <a href="http://scottstuff.net/blog/articles/2005/10/08/nokia-kiosk-at-alderwood">Nokia demo kiosk</a> will have both and I’ll be able to compare them in person.</p>
|
379
|
+
|
380
|
+
|
381
|
+
<p class="meta">Tags <a href="/articles/tag/nokia" rel="tag">nokia</a>, <a href="/articles/tag/nokiaeseries" rel="tag">nokiaeseries</a>, <a href="/articles/tag/nokian91" rel="tag">nokian91</a>, <a href="/articles/tag/phones" rel="tag">phones</a></p>
|
382
|
+
</div>
|
383
|
+
<div class="post">
|
384
|
+
<h2><a href="/articles/2005/10/10/asterisk-extension-language">Asterisk extension language</a></h2>
|
385
|
+
<p class="auth">Posted by Scott Laird
|
386
|
+
<span class="typo_date" title="Mon, 10 Oct 2005 19:28:54 GMT">Mon, 10 Oct 2005 19:28:54 GMT</span></p>
|
387
|
+
<p>While I really like all of the things that <a href="http://www.asterisk.org">Asterisk</a> allows me to do with my phone system, I’m really not very fond of its configuration language. The language provided in Asterisk 1.0 is slightly better then <a href="http://pfaff.newton.cam.ac.uk/jhnc/hanoi-cf.html"><code>sendmail.cf</code></a>, but it’s still a lousy language. They made a few <a href="http://scottstuff.net/blog/articles/2004/10/09/asterisk-configuration-language-improvements">small improvements</a> early in the Asterisk 1.2 development process that helped a bit, but I assumed that we’d have to wait for another year or two before someone broke down and wrote a decent language for Asterisk.</p>
|
388
|
+
|
389
|
+
<p>It looks like I may have been overly pessimestic. I discovered the <a href="http://www.voip-info.org/tiki-index.php?page=Asterisk+AEL">Asterisk extension language</a> on a list of new features for Asterisk 1.2 today. Somehow I’d missed this when it first went into Asterisk.</p>
|
390
|
+
|
391
|
+
<p>Here’s a chunk out of my old config file. It’s not perfect, but it’s what you get when you’re stuck dealing with line numbers:</p>
|
392
|
+
|
393
|
+
<div class="typocode"><pre><code class="typocode_asterisk ">[macro-diallocal]
|
394
|
+
exten => s,1,AbsoluteTimeout(7200)
|
395
|
+
exten => s,n,SetAMAFlags(default)
|
396
|
+
exten => s,n(analog),Dial(${TRUNK}/${ARG1})
|
397
|
+
exten => s,n,Congestion
|
398
|
+
exten => s,analog+101,Macro(condsetcid)
|
399
|
+
exten => s,n,SetCIDName(LAIRD SCOTT)
|
400
|
+
exten => s,n,SetAMAFlags(billing)
|
401
|
+
exten => s,n(nufone),Dial(${NUFONE}/1${ARG1})
|
402
|
+
exten => s,n,Congestion
|
403
|
+
exten => s,nufone+101,Busy</code></pre></div>
|
404
|
+
|
405
|
+
<p>And here’s the equivalent using the new configuration language:</p>
|
406
|
+
|
407
|
+
<div class="typocode"><pre><code class="typocode_asterisk ">macro diallocal( number ) {
|
408
|
+
AbsoluteTimeout(7200);
|
409
|
+
SetAMAFlags(default);
|
410
|
+
Dial(${TRUNK}/${number});
|
411
|
+
if(${DIALSTATUS} = "CONGESTION" || ${DIALSTATUS} = "CHANUNAVAILABLE") {
|
412
|
+
&condsetcid();
|
413
|
+
SetCIDName("LAIRD SCOTT");
|
414
|
+
SetAMAFlags(billing);
|
415
|
+
Dial(${NUFONE}/1${number});
|
416
|
+
switch(${DIALSTATUS}) {
|
417
|
+
case BUSY:
|
418
|
+
Busy;
|
419
|
+
default:
|
420
|
+
Congestion;
|
421
|
+
}
|
422
|
+
}
|
423
|
+
}</code></pre></div>
|
424
|
+
|
425
|
+
<p>It’s still not ideal–<code>${VAR}</code> is ugly–but it’s vastly better then the old syntax. This plus a bit of <a href="http://scottstuff.net/blog/articles/2005/09/12/rails-and-asterisk">Rails integration</a> should give us a really nice phone environment. I’m rapidly approaching the “tear it down and rebuild it” point with my Asterisk system–there’s a lot of stuff that I’d like to add that just doesn’t fit in with my current configuration files–so I’ll have a set of articles on integrating Asterisk, AEL, and Rails in a few weeks.</p>
|
426
|
+
|
427
|
+
|
428
|
+
<p class="meta">Posted in <a href="/articles/category/Asterisk" rel="tag">Asterisk</a> <strong>|</strong> Tags <a href="/articles/tag/ael" rel="tag">ael</a>, <a href="/articles/tag/asterisk" rel="tag">asterisk</a>, <a href="/articles/tag/rubyonrails" rel="tag">rubyonrails</a>, <a href="/articles/tag/voip" rel="tag">voip</a></p>
|
429
|
+
</div>
|
430
|
+
|
431
|
+
|
432
|
+
<p id="pagination">Older posts: 1 <a href="/articles/page/2">2</a> <a href="/articles/page/3">3</a> ... <a href="/articles/page/38">38</a></p>
|
433
|
+
|
434
|
+
<script type="text/javascript">
|
435
|
+
//<![CDATA[
|
436
|
+
show_dates_as_local_time()
|
437
|
+
//]]>
|
438
|
+
</script>
|
439
|
+
</div>
|
440
|
+
|
441
|
+
<div id="sidebar">
|
442
|
+
|
443
|
+
<div id="search-results"></div>
|
444
|
+
|
445
|
+
|
446
|
+
|
447
|
+
<div class="sidebar-node">
|
448
|
+
<h3>Tags</h3>
|
449
|
+
<p style="overflow:hidden">
|
450
|
+
<span style="font-size:115.789473684211%"><a href="/articles/tag/apple">apple</a></span>
|
451
|
+
<span style="font-size:140.350877192982%"><a href="/articles/tag/asterisk">asterisk</a></span>
|
452
|
+
<span style="font-size:126.315789473684%"><a href="/articles/tag/blog">blog</a></span>
|
453
|
+
<span style="font-size:133.333333333333%"><a href="/articles/tag/broken">broken</a></span>
|
454
|
+
<span style="font-size:66.6666666666667%"><a href="/articles/tag/hardware">hardware</a></span>
|
455
|
+
<span style="font-size:66.6666666666667%"><a href="/articles/tag/home">home</a></span>
|
456
|
+
<span style="font-size:80.7017543859649%"><a href="/articles/tag/linux">linux</a></span>
|
457
|
+
<span style="font-size:122.80701754386%"><a href="/articles/tag/macosx">macosx</a></span>
|
458
|
+
<span style="font-size:94.7368421052632%"><a href="/articles/tag/palm">palm</a></span>
|
459
|
+
<span style="font-size:66.6666666666667%"><a href="/articles/tag/phone">phone</a></span>
|
460
|
+
<span style="font-size:105.263157894737%"><a href="/articles/tag/photography">photography</a></span>
|
461
|
+
<span style="font-size:66.6666666666667%"><a href="/articles/tag/rails">rails</a></span>
|
462
|
+
<span style="font-size:126.315789473684%"><a href="/articles/tag/ruby">ruby</a></span>
|
463
|
+
<span style="font-size:129.824561403509%"><a href="/articles/tag/rubyonrails">rubyonrails</a></span>
|
464
|
+
<span style="font-size:77.1929824561403%"><a href="/articles/tag/rumors">rumors</a></span>
|
465
|
+
<span style="font-size:84.2105263157895%"><a href="/articles/tag/seattle">seattle</a></span>
|
466
|
+
<span style="font-size:66.6666666666667%"><a href="/articles/tag/tiger">tiger</a></span>
|
467
|
+
<span style="font-size:66.6666666666667%"><a href="/articles/tag/treo">treo</a></span>
|
468
|
+
<span style="font-size:164.912280701754%"><a href="/articles/tag/typo">typo</a></span>
|
469
|
+
<span style="font-size:150.877192982456%"><a href="/articles/tag/voip">voip</a></span>
|
470
|
+
</p>
|
471
|
+
|
472
|
+
|
473
|
+
</div>
|
474
|
+
|
475
|
+
|
476
|
+
<div class="sidebar-node">
|
477
|
+
<div id="flickr">
|
478
|
+
<h3>Scott Laird's Photos (<a href="http://www.flickr.com/photos/scottlaird/">flickr</a>)</h3>
|
479
|
+
<div class="flickrsquare"><a href="http://www.flickr.com/photos/scottlaird/105291159/"><img alt="capistrano-023.jpg" src="http://static.flickr.com/37/105291159_eafcb88801_s.jpg" title="capistrano-023.jpg" /></a>
|
480
|
+
</div>
|
481
|
+
<div class="flickrsquare"><a href="http://www.flickr.com/photos/scottlaird/105290749/"><img alt="capistrano-037.jpg" src="http://static.flickr.com/41/105290749_64b3c28822_s.jpg" title="capistrano-037.jpg" /></a>
|
482
|
+
</div>
|
483
|
+
<div class="flickrsquare"><a href="http://www.flickr.com/photos/scottlaird/105290368/"><img alt="capistrano-044.jpg" src="http://static.flickr.com/38/105290368_9a67846c00_s.jpg" title="capistrano-044.jpg" /></a>
|
484
|
+
</div>
|
485
|
+
<div class="flickrsquare"><a href="http://www.flickr.com/photos/scottlaird/105289942/"><img alt="capistrano-060.jpg" src="http://static.flickr.com/41/105289942_9128bdb76a_s.jpg" title="capistrano-060.jpg" /></a>
|
486
|
+
</div>
|
487
|
+
<div class="flickrsquare"><a href="http://www.flickr.com/photos/scottlaird/105289656/"><img alt="capistrano-071.jpg" src="http://static.flickr.com/36/105289656_52e0b32ef0_s.jpg" title="capistrano-071.jpg" /></a>
|
488
|
+
</div>
|
489
|
+
<div class="flickrsquare"><a href="http://www.flickr.com/photos/scottlaird/105289242/"><img alt="capistrano-075.jpg" src="http://static.flickr.com/19/105289242_5eebabf709_s.jpg" title="capistrano-075.jpg" /></a>
|
490
|
+
</div>
|
491
|
+
<div class="flickrsquare"><a href="http://www.flickr.com/photos/scottlaird/105288847/"><img alt="capistrano-079.jpg" src="http://static.flickr.com/42/105288847_5252a96202_s.jpg" title="capistrano-079.jpg" /></a>
|
492
|
+
</div>
|
493
|
+
<div class="flickrsquare"><a href="http://www.flickr.com/photos/scottlaird/105288463/"><img alt="capistrano-101.jpg" src="http://static.flickr.com/35/105288463_eb213558d6_s.jpg" title="capistrano-101.jpg" /></a>
|
494
|
+
</div>
|
495
|
+
<div class="flickrsquare"><a href="http://www.flickr.com/photos/scottlaird/105288130/"><img alt="capistrano-102.jpg" src="http://static.flickr.com/19/105288130_6b20edccf2_s.jpg" title="capistrano-102.jpg" /></a>
|
496
|
+
</div>
|
497
|
+
<div class="flickrsquare"><a href="http://www.flickr.com/photos/scottlaird/105287717/"><img alt="capistrano-109.jpg" src="http://static.flickr.com/42/105287717_60eb1580ec_s.jpg" title="capistrano-109.jpg" /></a>
|
498
|
+
</div>
|
499
|
+
</div>
|
500
|
+
|
501
|
+
</div>
|
502
|
+
|
503
|
+
|
504
|
+
<div class="sidebar-node">
|
505
|
+
<h3>Random tracking bits</h3>
|
506
|
+
<script language="javascript" src="http://www.truthlaidbear.com/MyDetails.php?url=http://scottstuff.net/&style=javascript"></script>
|
507
|
+
<br/>
|
508
|
+
<!-- Site Meter XHTML Strict 1.0 -->
|
509
|
+
<script type="text/javascript">var site="sm6scottstuff"</script>
|
510
|
+
<script type="text/javascript" src="http://sm6.sitemeter.com/js/counter.js?site=sm6scottstuff">
|
511
|
+
</script>
|
512
|
+
<noscript><div>
|
513
|
+
<a href="http://sm6.sitemeter.com/stats.asp?site=sm6scottstuff">
|
514
|
+
<img src="http://sm6.sitemeter.com/meter.asp?site=sm6scottstuff" alt="Site Meter" /></a>
|
515
|
+
</div></noscript>
|
516
|
+
<!-- Copyright (c)2005 Site Meter -->
|
517
|
+
|
518
|
+
|
519
|
+
</div>
|
520
|
+
|
521
|
+
|
522
|
+
|
523
|
+
|
524
|
+
|
525
|
+
|
526
|
+
<a href="http://www.typosphere.org/" class="powered"><img alt="Powered" src="/images/powered.gif" /></a>
|
527
|
+
</div>
|
528
|
+
|
529
|
+
<br clear="all" />
|
530
|
+
</div>
|
531
|
+
<div id="footer">
|
532
|
+
<ul>
|
533
|
+
<li><a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.0</a></li>
|
534
|
+
<li><a href="http://jigsaw.w3.org/css-validator/validator?uri=http://localhost:3000/">Valid CSS</a></li>
|
535
|
+
</ul>
|
536
|
+
</div>
|
537
|
+
</div>
|
538
|
+
</body>
|
539
|
+
</html>
|
540
|
+
|