.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .ie \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .el \{\ . de IX .. .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "Jifty::Manual::Tutorial 3pm" .TH Jifty::Manual::Tutorial 3pm "2010-12-08" "perl v5.14.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Jifty::Manual::Tutorial \- Zero to Jifty in a Jiffy .SH "DESCRIPTION" .IX Header "DESCRIPTION" This tutorial should give you everything you need to build your first application with Jifty. .SH "HOW TO" .IX Header "HOW TO" .SS "The requirements" .IX Subsection "The requirements" Here's what you need to have installed \*(-- at least when we write it. .SS "Installing Jifty" .IX Subsection "Installing Jifty" No bones about it. We believe pretty strongly in the \s-1DRY\s0 (Don't Repeat Yourself) principle. That's one of the big reasons we love Perl and \&\s-1CPAN\s0. Jifty makes use of lots of amazing code from \s-1CPAN\s0. At last count, it directly depended on 100 packages from \s-1CPAN\s0. Most of these libraries are cross-platform pure-Perl packages and should run great out of the box on any platform you can get Perl onto. .PP We've gone to lengths to make sure you don't spend your day downloading library after library by bundling everything we can inside the Jifty package. The Jifty installer is capable of determining what modules your system needs, and downloading and installing them all in one go. Don't worry, it will ask you first before it makes any changes. .PP On most systems you can use Perl's bundled \s-1CPAN\s0 module to download and install Jifty: .PP .Vb 1 \& # perl \-MCPAN \-e\*(Aqinstall Jifty\*(Aq .Ve .PP If you've downloaded a \f(CW\*(C`.tar.gz\*(C'\fR of Jifty, you can do a manual install: .PP .Vb 6 \& # tar xzvf jifty\-.tgz \& # cd jifty\- \& # perl Makefile.PL \& # make \& # make test \& # make install .Ve .PP If the tests don't pass, we want to hear about it. Please join us on \f(CW\*(C`jifty\-devel@lists.jifty.org\*(C'\fR and report the failure. (See \&\*(L"\s-1GETTING\s0 \s-1HELP\s0\*(R" below for info on how to join the list.) .SS "Setting up the Scaffolding" .IX Subsection "Setting up the Scaffolding" Once you have Jifty happily installed, you're ready to create your first application. .PP All you \fIreally\fR need to make an application go is a copy of the \fIjifty\fR command-line tool (inside your new application's \fIbin/\fR directory.) .PP Of course, it's often helpful to have a bit more structure around to help guide your work. Jifty comes with tools to build that structure for you. .PP Change directory to some place it will be safe to create a new Jifty application. (Jifty will create a subdirectory for you.) .PP .Vb 10 \& # jifty app \-\-name MyWeblog \& Creating new application MyWeblog \& Creating directory MyWeblog/lib \& Creating directory MyWeblog/lib/MyWeblog \& Creating directory MyWeblog/bin \& Creating directory MyWeblog/etc \& Creating directory MyWeblog/doc \& Creating directory MyWeblog/log \& Creating directory MyWeblog/var \& Creating directory MyWeblog/var/mason \& Creating directory MyWeblog/share \& Creating directory MyWeblog/share/po \& Creating directory MyWeblog/share/web \& Creating directory MyWeblog/share/web/templates \& Creating directory MyWeblog/share/web/static \& Creating directory MyWeblog/lib/MyWeblog/Model \& Creating directory MyWeblog/lib/MyWeblog/Action \& Creating directory MyWeblog/t \& Creating configuration file MyWeblog/etc/config.yml .Ve .PP Let's take those one by one. .IP "lib" 4 .IX Item "lib" Inside \fIlib/\fR is where all of your application Perl code goes. Your application generally consists of a set of classes. .IP "bin" 4 .IX Item "bin" Inside \fIbin/\fR is \fIjifty\fR, the Jifty command dispatcher. The most important command is \f(CW\*(C`jifty server\*(C'\fR which starts a standalone webserver. To find out what commands your \fIjifty\fR comes with, run: .Sp .Vb 1 \& jifty help .Ve .IP "etc" 4 .IX Item "etc" Configuration files live in \fIetc/\fR. Jifty generates a basic config file for your application, \fIetc/config.yml\fR. .IP "doc" 4 .IX Item "doc" Jifty can't magically write your documentation for you, but when \fByou\fR write your docs, put them in \fIdoc/\fR. .IP "log" 4 .IX Item "log" Jifty uses Log::Log4perl to configure its logging. By default, it dumps logs named \fIserver.log\fR and \fIerror.log\fR into the \fIlog/\fR directory. .IP "var" 4 .IX Item "var" Jifty stores cache files here while the server is running. You shouldn't ever have to touch this directory. .IP "share/web/po" 4 .IX Item "share/web/po" Jifty supports internationalization. \fIshare/web/po/\fR is where your translations (\*(L"portable object templates\*(R") will go. .IP "share/web/templates" 4 .IX Item "share/web/templates" Though modern Jifty applications are encouraged to use Template::Declare for templating, we also support HTML::Mason templates. Put your application's Mason templates in \fIshare/web/templates/\fR. Out of the box, Jifty comes with an application \fIskeleton\fR that it installs in \&\fIshare/web/templates/\fR. This default application is a convenient way to get a basic application up and running quickly, but probably needs some customization as you build a more advanced application. .Sp You can find where Perl stuck Jifty's default templates with: .Sp .Vb 1 \& perl \-MJifty::Util \-le \*(Aqprint Jifty::Util\->share_root\*(Aq .Ve .IP "share/web/static" 4 .IX Item "share/web/static" Some nontrivial percentage of the content your web application serves out doesn't need to (or \fIshouldn't\fR) pass through your templating engine. This includes, for example, images. .Sp Just drop your static files into \fIshare/web/static/\fR and Jifty will serve them out if it can't find a template with the right name. .Sp Out of the box, Jifty comes with plenty of \s-1CSS\s0 stylesheets, JavaScript libraries, and even a Pony. Look in \fIshare/web/static\fR in the Jifty distribution, or in the same place Jifty stuck its default templates. .IP "lib/MyWeblog/Model" 4 .IX Item "lib/MyWeblog/Model" The real base of your application lives in \&\f(CW\*(C`lib/MyWeblog/Model\*(C'\fR. Classes here define your application's data structures and how they relate to each other. Jifty will use your model classes to set up and upgrade your database's schema when it needs to. .Sp For a full treatment of the Jifty object model see Jifty::Manual::ObjectModel. .IP "lib/MyWeblog/Action" 4 .IX Item "lib/MyWeblog/Action" Actions are an \s-1API\s0 for your model classes. One way you might think of them is that an action is an \s-1HTML\s0 form, but generalized. Jifty will generate basic database-interaction (\f(CW\*(C`CREATE\*(C'\fR, \f(CW\*(C`READ\*(C'\fR, \f(CW\*(C`UPDATE\*(C'\fR, \f(CW\*(C`DELETE\*(C'\fR) \fBActions\fR for your \fBModels\fR on-the-fly. .Sp You can also create your own actions for any kind of application logic. .IP "t" 4 .IX Item "t" Jifty starts off your application with a basic harness, but can't yet write all your tests for you. It does, however, build some simple tests for model and action classes you generate. .SS "Building your data model" .IX Subsection "Building your data model" As you might imagine by the fact that this tutorial application is named \&\fBMyWeblog\fR, the example here is a simple weblog application. Future tutorials will add authentication, comments, and \s-1RSS\s0 and Atom feeds. .PP \fIPosts\fR .IX Subsection "Posts" .PP Weblogs tend to center around posts, so it's no surprise that the first model to create is the \f(CW\*(C`post\*(C'\fR: .PP .Vb 4 \& # cd MyWeblog \& # jifty model \-\-name Post \& Writing file /tmp/MyWeblog/lib/MyWeblog/Model/Post.pm \& Writing file /tmp/MyWeblog/t/00\-model\-Post.t .Ve .PP Great! Now you have a \fBPost\fR model (not that it models anything yet). .PP Open \fIlib/MyWeblog/Model/Post.pm\fR in your favorite text editor. .PP You should see something like this: .PP .Vb 2 \& use strict; \& use warnings; \& \& package MyWeblog::Model::Post; \& use Jifty::DBI::Schema; \& \& use MyWeblog::Record schema { \& \& }; \& \& # Your model\-specific methods go here. \& \& 1; .Ve .PP Now it's time to tell the model class about what comprises a post. We'll start out by giving our post a \f(CW\*(C`body\*(C'\fR and a \f(CW\*(C`title\*(C'\fR. (In a future tutorial, the application will become fully folksonomy-compliant by adding a \f(CW\*(C`category\*(C'\fR and upgrading that \f(CW\*(C`category\*(C'\fR to a \f(CW\*(C`tags\*(C'\fR table.) .PP Position your cursor right after: .PP .Vb 1 \& use MyWeblog::Record schema { .Ve .PP Add the lines: .PP .Vb 4 \& column title => \& type is \*(Aqtext\*(Aq, \& label is \*(AqTitle\*(Aq, \& default is \*(AqUntitled post\*(Aq; \& \& column body => \& type is \*(Aqtext\*(Aq, \& label is \*(AqContent\*(Aq, \& render as \*(AqTextarea\*(Aq; .Ve .PP Save your model class. .PP Don't be mistaken, these are lines of actual Perl code. Jifty provides you with a human-readable language for declaring your models' columns. .SS "Starting the Jifty application server" .IX Subsection "Starting the Jifty application server" You now have a working, if simplistic, application. Start up the Jifty web server by typing \f(CW\*(C`jifty server\*(C'\fR. For some platforms, you may have to type \&\f(CW\*(C`./bin/jifty server\*(C'\fR. .PP The first thing you'll see is that Jifty notices you have no database, so it creates one for you. By default, Jifty sets up your application with the SQLite database engine. If you'd rather use PostgreSQL or MySQL, you need to add some content to \fIetc/config.yml\fR. See Jifty::Config for a bit more information. .PP .Vb 9 \& # jifty server \& WARN \- Application schema has no version in the database. \& WARN \- Automatically creating your database. \& INFO \- Generating SQL for application MyWeblog... \& INFO \- Using MyWeblog::Model::Post, as it appears to be new. \& INFO \- Using Jifty::Model::Session, as it appears to be new. \& INFO \- Using Jifty::Model::Metadata, as it appears to be new. \& INFO \- Set up version 0.0.1, jifty version 0.81208 \& INFO \- You can connect to your server at http://localhost:8888/ .Ve .PP Everything but the last line was database setup information that you'll only see when Jifty changes your database. .PP The last line tells you the \s-1URL\s0 you can go to with your web browser. Have a look around. Be sure to check out the AJAX-enabled administrative \s-1UI\s0, the online documentation browser, and the Pony. .SS "Building a user interface" .IX Subsection "Building a user interface" The administrative web does give you everything you need to work with your application's data. You can create, update, and delete posts. However, it's not much of a weblog. .PP \fIPosting\fR .IX Subsection "Posting" .PP Let's start building our user interface with a page to create new posts. .PP Open a new file called \fIlib/MyWeblog/View.pm\fR in your text editor. Make it look like this: .PP .Vb 4 \& package MyWeblog::View; \& use strict; \& use warnings; \& use Jifty::View::Declare \-base; \& \& template post => page { title => \*(AqPost Entry\*(Aq } content { \& my $action = new_action(class => \*(AqCreatePost\*(Aq); \& \& form { \& render_action $action; \& form_submit(label => \*(AqPost\*(Aq); \& } \& }; \& \& 1; .Ve .PP Jifty provides very concise syntax for generating \s-1HTML\s0 using Template::Declare. We'll see plenty more soon. .PP \fIViewing\fR .IX Subsection "Viewing" .PP It's really easy to get a \fIbasic\fR listing of entries and a little bit more complex to get a pretty AJAXified paged list. Here's how to do both; you can decide which one works best for you. .PP The quick and dirty way .IX Subsection "The quick and dirty way" .PP Open your \fIlib/MyWeblog/View.pm\fR file and add this between the \f(CW\*(C`post\*(C'\fR template and the \*(L"1;\*(R" at the very end of the file: .PP .Vb 4 \& template \*(Aq/\*(Aq => page { \& # Get all posts. \& my $posts = MyWeblog::Model::PostCollection\->new; \& $posts\->unlimit; \& \& # Display each post in a
. \& dl { \& while (my $post = $posts\->next) { \& dt { $post\->title } \& dd { $post\->body } \& } \& } \& }; .Ve .PP Now when you go to \f(CW\*(C`http://localhost:8888\*(C'\fR, you'll be greeted with all of your blog posts. .PP The complex way that gets you lots of cool toys .IX Subsection "The complex way that gets you lots of cool toys" .PP The \fIcomplex way\fR involves using one of Jifty's advanced features: \&\fIPage regions\fR. These regions let your application reload page sections independently, either using \s-1AJAX\s0 on modern high-end browsers or regular \s-1GET\s0 requests with downlevel browsers such as \f(CW\*(C`lynx\*(C'\fR and \f(CW\*(C`w3m\*(C'\fR. .PP The downside of this approach is that each separate region needs to live in its own template. Happily, this is a good design practice even without regions. .PP The complex way starts off about the same as the easy way. Replace (or add, if you shied away from simplicity) the \f(CW\*(C`/\*(C'\fR template in your \&\fIlib/MyWeblog/View.pm\fR: .PP .Vb 6 \& template \*(Aq/\*(Aq => page { \& render_region( \& name => \*(Aqmyweblog\-posts\*(Aq, \& path => \*(Aq/fragments/page_of_posts\*(Aq, \& ); \& }; .Ve .PP If you're on the ball, you've probably already guessed that you need to create a template called \f(CW\*(C`/fragments/page_of_posts\*(C'\fR in your \fIlib/MyWeblog/View.pm\fR. Make it contain the following: .PP .Vb 3 \& template \*(Aq/fragments/page_of_posts\*(Aq => sub { \& # Retrieve the current page argument, defaulting to 1. \& my $page = get(\*(Aqpage\*(Aq) || 1; \& \& # Get all posts. \& my $posts = MyWeblog::Model::PostCollection\->new; \& $posts\->unlimit; \& \& # Display up to three posts on the current page. \& $posts\->set_page_info( \& current_page => $page, \& per_page => 3, \& ); \& \& # Notify the user what page they\*(Aqre on if there are multiple. \& if ($posts\->pager\->last_page > 1) { \& p { "Page $page of " . $posts\->pager\->last_page } \& } \& \& # Display the current page of posts. \& dl { \& attr { class => \*(Aqlist\*(Aq }; \& \& while (my $post = $posts\->next) { \& dt { $post\->title } \& dd { $post\->body } \& } \& }; \& \& # Previous page link, the \*(Aqpage\*(Aq argument here will set a new value when \& # this region is invoked again. \& if ($posts\->pager\->previous_page) { \& hyperlink( \& label => \*(AqPrevious Page\*(Aq, \& onclick => { \& args => { \& page => $posts\->pager\->previous_page, \& }, \& }, \& ); \& } \& \& # Next page link. \& if ($posts\->pager\->next_page) { \& hyperlink( \& label => \*(AqNext Page\*(Aq, \& onclick => { \& args => { \& page => $posts\->pager\->next_page, \& }, \& }, \& ); \& } \& }; .Ve .PP Now fire up your Jifty webserver again. Browse to \f(CW\*(C`/post\*(C'\fR and create more than three posts. Return to the home page and check out the nifty \s-1AJAX\s0 \f(CW\*(C`Next Page\*(C'\fR and \f(CW\*(C`Previous Page\*(C'\fR links you now have. Turn off JavaScript or view the page in \f(CW\*(C`lynx\*(C'\fR, and notice how the \s-1AJAX\s0 automatically falls-back to page loads for you. All for free, thanks to Jifty! .PP \fIHey, where did that class come from?\fR .IX Subsection "Hey, where did that class come from?" .PP You may have wondered about \f(CW\*(C`MyWeblog::Model::PostCollection\*(C'\fR, since there's no file called \fIPostCollection.pm\fR. Jifty uses Jifty::ClassLoader to auto-generate a bunch of classes for you. Of course, you can override these definitions if you like. See Jifty::ClassLoader for more details. .SS "Navigation" .IX Subsection "Navigation" Of course, having to remember the \s-1URL\s0 to get to the posting page is a bit annoying. To get a \fBPost\fR button in the menu, you need to override the default menus. .PP We're going to set up a dispatcher for your weblog. A dispatcher handles \*(L"doing things\*(R" based on the \s-1URL\s0 of each incoming request. We can set up additional menu items by adding them in a \*(L"before rendering any template\*(R" dispatcher rule. .PP Open up a new file called \fIlib/MyWeblog/Dispatcher.pm\fR and stick this content into it: .PP .Vb 4 \& package MyWeblog::Dispatcher; \& use strict; \& use warnings; \& use Jifty::Dispatcher \-base; \& \& before \*(Aq*\*(Aq => run { \& my $top = Jifty\->web\->navigation; \& $top\->child(Home => url => \*(Aq/\*(Aq); \& $top\->child(Post => url => \*(Aq/post\*(Aq, label => \*(AqPost Article\*(Aq); \& }; \& \& 1; .Ve .PP Jifty provides nice syntax (yet again!) for declaring dispatcher rules. For more information about dispatching, see Jifty::Dispatcher. For more information about the menu system, see the documentation in Jifty::Web::Menu. .SS "That's it!" .IX Subsection "That's it!" That's just about everything you need to get started building Jifty applications. We're working hard to make Jifty even easier to use and to obsolete the \fIhard bits\fR of this tutorial as quickly as we can. .PP Please join us on the \f(CW\*(C`jifty\-devel\*(C'\fR mailing list to talk about how you're using Jifty or what you find difficult or hard to use about it. .SH "MORE TUTORIALS" .IX Header "MORE TUTORIALS" .IP "\(bu" 4 Managing your datastore .Sp Jifty::Manual::Models .IP "\(bu" 4 Doing Stuff With Jifty .Sp Jifty::Manual::Actions .IP "\(bu" 4 Using page regions .Sp Jifty::Manual::PageRegions .IP "\(bu" 4 \&\s-1CSS\s0 and \s-1JS\s0 .Sp Jifty::Manual::UsingCSSandJS, Jifty::Manual::JavaScript .IP "\(bu" 4 Web Services .Sp See Jifty::Manual::TutorialRest for a quick overview. .IP "\(bu" 4 Continuations \- \*(L"There And Back Again\*(R" .Sp Jifty::Manual::Continuations .IP "\(bu" 4 Access Control and Security .Sp Jifty::Manual::AccessControl .IP "\(bu" 4 Deploying your application in production .Sp Jifty::Manual::Deploying .IP "\(bu" 4 Upgrading your application's data model .Sp Jifty::Manual::Upgrading .IP "\(bu" 4 Recipes for common tasks in Jifty .Sp Jifty::Manual::Cookbook .SH "GETTING HELP" .IX Header "GETTING HELP" .SS "Online Help" .IX Subsection "Online Help" The \f(CW\*(C`jifty\*(C'\fR command-line application comes with builtin help. .PP .Vb 1 \& jifty help \& \& jifty help .Ve .PP If your server is running with administration mode enabled (the configuration file \f(CW\*(C`AdminMode\*(C'\fR setting is missing or non-zero), you can click the \*(L"Online Docs\*(R" link in your browser for an extensive list of per-module Jifty documentation. .SS "Joining the mailing list" .IX Subsection "Joining the mailing list" \&\f(CW\*(C`jifty\-devel@lists.jifty.org\*(C'\fR is where we discuss how we're building Jifty, what we're having trouble with and so on. .PP To join the list, send mail to \f(CW\*(C`jifty\-devel\-subscribe@lists.jifty.org\*(C'\fR. .SS "Browsing the wiki" .IX Subsection "Browsing the wiki" We have a wiki! (Actually, the wiki is Jifty's primary website) .PP Please visit , browse and contribute. .PP The wiki is powered by \fIWifty\fR, a Wiki built on Jifty. Its code is freely available from the Jifty subversion repository. .SH "REPORTING BUGS" .IX Header "REPORTING BUGS" Please report bugs in Jifty to \f(CW\*(C`jifty\-devel@lists.jifty.org\*(C'\fR.