|
|
(One intermediate revision by the same user not shown) |
Line 1: |
Line 1: |
− | = How do I file a new bug? =
| + | #REDIRECT [[Newbie_Guide:_How_to_Patch_Styles_and_Themes]] |
− | | + | |
− | * In Bugzilla, click on New. Select Dreamwidth Development. In Component, select Style System. Enter a Summary and a Description. Mention style and author(s) in the summary. If you're patching a color theme, add author names and submission URLs to the description. If you're patching a style, mention the style name, the number of themes it has, the name of the default theme, the author's name and the submission URL.
| + | |
− | | + | |
− | * Click on Show Advanced Fields. Set Initial State to IN_PROGRESS and enter your Bugzilla e-mail address in Assign To.
| + | |
− | | + | |
− | = Where are style files? =
| + | |
− | | + | |
− | * core2.s2 is in <code>~/dw/bin/upgrading/s2layers/</code>
| + | |
− | | + | |
− | * Theme and layout .s2 files are in <code>~/dw/bin/upgrading/s2layers/STYLENAME/</code> or <code>~/dw/ext/dw-nonfree/bin/upgrading/s2layers/STYLENAME/</code>
| + | |
− | | + | |
− | * .pm style files are in <code>~/dw/cgi-bin/LJ/S2Theme/</code> or <code>~/dw/ext/dw-nonfree/cgi-bin/LJ/S2Theme/</code>
| + | |
− | | + | |
− | * S2Theme.pm is in <code>~/dw/cgi-bin/LJ/</code> or <code>~/dw/ext/dw-nonfree/cgi-bin/LJ/</code>
| + | |
− | | + | |
− | FIXME: still called _local in nonfree.
| + | |
− | | + | |
− | * s2layers.dat is in <code>~/dw/cvs/dw-free/bin/upgrading/</code> or <code>~/dw/ext/dw-nonfree/bin/upgrading/</code>
| + | |
− | | + | |
− | | + | |
− | = Checking usage rights =
| + | |
− | | + | |
− | Before you patch any style or theme, make sure Dreamwidth is allowed to use it as well as the images it contains if there are any:
| + | |
− | * We must have the submitter's [[CLA|Contributor Licensing Agreement]] before we can use their submission. If it's from someone who already has live styles or themes on the site, we already do. If the submission entry has the '-needs cla' tag, we don't. Otherwise, check the comments to see if they've already been asked about it.
| + | |
− | * If design and images have been made entirely from scratch by the designer who submitted the style or theme, they need to explicitly state they made them themselves in their submission entry.
| + | |
− | * If design or images haven't been made entirely from scratch by the designer who submitted the style or theme, they must mention where they came from and how they're licensed. We can only use designs and images if commercial use is allowed, use in website templates is allowed and storage on one own's server is allowed. You must also check if they may only be used as-is or if any kind of transformation (also called 'remix') is allowed, and how crediting must be done.
| + | |
− | | + | |
− | When in doubt, comment on the bug.
| + | |
− | | + | |
− | | + | |
− | = Dw-free or dw-nonfree? =
| + | |
− | | + | |
− | Dreamwidth may be allowed to use designs and images on dreamwidth.org but may not be allowed to redistribute or sublicense them to other sites. If that's the case, elements need to go to dw-nonfree:
| + | |
− | | + | |
− | * Styles go to dw-nonfree if Dreamwidth can use them but can't redistribute/sublicense them.
| + | |
− | | + | |
− | * Themes go to dw-nonfree if they contain images Dreamwidth can use but can't redistribute/sublicense.
| + | |
− | | + | |
− | * Themes go to dw-nonfree if the base style is already in dw-nonfree. This the case for Transmogrified and Sunday Morning themes.
| + | |
− | | + | |
− | | + | |
− | = Adding a new style =
| + | |
− | | + | |
− | == Edit s2layers.dat ==
| + | |
− | | + | |
− | * If this is a new Core2 style, add:
| + | |
− | <syntaxhighlight lang="perl">
| + | |
− | stylename/layout layout core2
| + | |
− | stylename/themes theme+ stylename/layout
| + | |
− | </syntaxhighlight>
| + | |
− | | + | |
− | * If this is a child of Tabula Rasa, add:
| + | |
− | <syntaxhighlight lang="perl">
| + | |
− | stylename/layout layout(core2base/layout) core2
| + | |
− | stylename/themes theme+ stylename/layout
| + | |
− | </syntaxhighlight>
| + | |
− | | + | |
− | | + | |
− | == Edit S2Theme.pm ==
| + | |
− | | + | |
− | FIXME: still called _local in nonfree.
| + | |
− | | + | |
− | Scroll down to <code>%default_themes</code> and add the style and default theme:
| + | |
− | <syntaxhighlight lang="perl">layoutname => 'stylename/defaulttheme',</syntaxhighlight>
| + | |
− | | + | |
− | | + | |
− | == Create STYLENAME.pm ==
| + | |
− | | + | |
− | * Create STYLENAME.pm in <code>~/dw/cgi-bin/LJ/S2Theme/</code> or <code>~/dw/ext/dw-nonfree/cgi-bin/LJ/S2Theme/</code>.
| + | |
− | | + | |
− | * Add:
| + | |
− | <syntaxhighlight lang="perl">
| + | |
− | package LJ::S2Theme::layoutname;
| + | |
− | use base qw( LJ::S2Theme );
| + | |
− | use strict;
| + | |
− | | + | |
− | sub layouts { ( "1" => "one-column", "1s" => "one-column-split", "2l" => "two-columns-left", "2r" => "two-columns-right", "3" => "three-columns-sides", "3r" => "three-columns-right", "3l" => "three-columns-left" ) }
| + | |
− | sub layout_prop { "layout_type" }
| + | |
− | | + | |
− | 1;
| + | |
− | </syntaxhighlight>
| + | |
− | | + | |
− | * Remove layout options which don't apply to the style.
| + | |
− | | + | |
− | * If the style has new Customize properties which can be sorted into existing categories (such as Page, Header, Module, Entry, etc.) you can add them to these categories using <code>sub xxx_props</code>:
| + | |
− | | + | |
− | <syntaxhighlight lang="perl">
| + | |
− | sub module_props {
| + | |
− | my $self = shift;
| + | |
− | my @props = qw(
| + | |
− | new_property 1
| + | |
− | new_property 2
| + | |
− | new_property 3
| + | |
− | new_property 4
| + | |
− | new_property 5
| + | |
− | );
| + | |
− | return $self->_append_props( "module_props", @props );
| + | |
− | }
| + | |
− | </syntaxhighlight>
| + | |
− | | + | |
− | * Existing categories can be found in <code>~/dw/cgi-bin/LJ/S2Theme.pm</code>
| + | |
− | | + | |
− | * Note that, in Customize, they will be put after default properties, in the order you've listed them in in layout.s2.
| + | |
− | | + | |
− | | + | |
− | == Create the STYLENAME directory ==
| + | |
− | | + | |
− | Create a directory with the name of the style in <code>~/dw/bin/upgrading/s2layers/</code> or <code>~/dw/ext/dw-nonfree/bin/upgrading/s2layers/</code>.
| + | |
− | | + | |
− | | + | |
− | == Create layout.s2 ==
| + | |
− | | + | |
− | * In the directory you've created, create a file named <code>layout.s2</code>. Add:
| + | |
− | <syntaxhighlight lang="s2">
| + | |
− | layerinfo type = "layout";
| + | |
− | layerinfo name = "stylename";
| + | |
− | layerinfo redist_uniq = "stylename/layout";
| + | |
− | layerinfo author_name = "someuser";
| + | |
− | layerinfo lang = "en";
| + | |
− | | + | |
− | set layout_authors = [ { "name" => "someuser", "type" => "user" } ];
| + | |
− | </syntaxhighlight>
| + | |
− | | + | |
− | * Make sure to respect the designer's wishes concerning capitalization and that layerinfo author_name and layout_authors match.
| + | |
− | | + | |
− | * If the designer doesn't want their name to be displayed as a username, use this instead:
| + | |
− | <syntaxhighlight lang="s2">set layout_authors = [ { "name" => "someuser" } ];</syntaxhighlight>
| + | |
− | | + | |
− | * If there are resources to credit, add them:
| + | |
− | <syntaxhighlight lang="s2">set layout_resources = [ { "name" => "Name", "url" => "http://URL" } ];</syntaxhighlight>
| + | |
− | | + | |
− | * Add the style code using headers for options (presentation, colors, fonts, images, modules, text, other) and for the stylesheet:
| + | |
− | | + | |
− | <syntaxhighlight lang="s2">
| + | |
− | ##=============================== | + | |
− | ## Stylesheet
| + | |
− | ##===============================
| + | |
− | </syntaxhighlight>
| + | |
− | | + | |
− | | + | |
− | === Special case: custom properties ===
| + | |
− | | + | |
− | * If the style has custom properties, first try to see if you can find existing ones in Core2 which would fit just as well.
| + | |
− | | + | |
− | * If there aren't, make sure their names follow existing patterns: a) the property type (color, font, image, ...) b) the major area it applies to (header, entry, module,...) c) the precise element it applies to (text, link, background) and finally d) anything which might precise it further (alt, hover, active,...). The goal is to try to make it precise enough that anybody reading the code will know what it does without having to read to the description.
| + | |
− | | + | |
− | Here are some examples:
| + | |
− | | + | |
− | color_header_navlinks_link_visited
| + | |
− | | + | |
− | color_module_link_background_hover
| + | |
− | | + | |
− | font_entry_datetime
| + | |
− | | + | |
− | : A few exceptions to this rule:
| + | |
− | ::* image props mention whether they're background images or other sorts of images first ( e.g. image_background_entry_title, image_decoration_module_footer)
| + | |
− | ::* some custom properties can apply to an element wherever it may be displayed. In this case try to name this element as precisely as possible (e.g. font_titles for any H1, H2, H3, H4 headings or calendar_entryday_background if it applies to both the archive page calendar and the module calendar).
| + | |
− | | + | |
− | * Sort them into existing groups (presentation, colors, fonts, images, modules, text, other) by appending <code>_child</code> to the group name. For example:
| + | |
− | | + | |
− | <syntaxhighlight lang="s2">propgroup images_child {
| + | |
− | property string image_module_list { des = "Module list image"; }
| + | |
− | }</syntaxhighlight>
| + | |
− | | + | |
− | * Finally add a corresponding header (presentation, etc.).
| + | |
− | | + | |
− | | + | |
− | === Special case: custom module positions ===
| + | |
− | | + | |
− | * If a module has more or fewer available positions than other modules, you can customize the sections it can be set to by using <code>_override</code>. For example:
| + | |
− | | + | |
− | <syntaxhighlight lang="s2">property string module_navlinks_section_override {
| + | |
− | values = "none|(none)|header|Header|one|Group One|two|Group Two";
| + | |
− | grouped = 1;
| + | |
− | }
| + | |
− | | + | |
− | set grouped_property_override = { "module_navlinks_section" => "module_navlinks_section_override" };
| + | |
− | | + | |
− | set module_navlinks_section = "header";</syntaxhighlight>
| + | |
− | | + | |
− | * Don't forget to make sure it's printed correctly when set to every position, possibly by editing <code>function Page::print() { }</code>.
| + | |
− | | + | |
− | | + | |
− | === Special case: custom functions ===
| + | |
− | | + | |
− | * If there is any function to be added, add a 'functions' header then briefly explain why each function had to be edited in a comment (e.g. to add an extra DIV, to add a new section for modules).
| + | |
− | | + | |
− | | + | |
− | == Create themes.s2 ==
| + | |
− | | + | |
− | * In the directory you've created, create a file named <code>themes.s2</code>.
| + | |
− | | + | |
− | * Follow the steps outlined in [[#Adding a New Color Theme|the next section]].
| + | |
− | | + | |
− | | + | |
− | = Adding a new color theme =
| + | |
− | | + | |
− | | + | |
− | == Edit themes.s2 ==
| + | |
− | | + | |
− | * Make sure the color theme has the right header. As Afuna explained [http://dw-dev-training.dreamwidth.org/9656.html here] in <dwcomm>dw_dev_training</dwcomm>, it should look like this:
| + | |
− | <syntaxhighlight lang="s2">
| + | |
− | #NEWLAYER: stylename/themename
| + | |
− | layerinfo type = "theme";
| + | |
− | layerinfo name = "Theme Name";
| + | |
− | layerinfo redist_uniq = "stylename/themename";
| + | |
− | layerinfo author_name = "someuser";
| + | |
− | </syntaxhighlight>
| + | |
− | | + | |
− | * If the color theme author is not the style author, add this this line below, separated by a blank line:
| + | |
− | <syntaxhighlight lang="s2">set theme_authors = [ { "name" => "someuser", "type" => "user" } ];</syntaxhighlight>
| + | |
− | | + | |
− | * Make sure to respect the designer's wishes concerning capitalization and that layerinfo author_name and theme_authors match.
| + | |
− | | + | |
− | * If the designer doesn't want their name to be displayed as a username, use this instead:
| + | |
− | <syntaxhighlight lang="s2">set theme_authors = [ { "name" => "someuser" } ];</syntaxhighlight>
| + | |
− | | + | |
− | * If there are resources to credit, add them:
| + | |
− | <syntaxhighlight lang="s2">set layout_resources = [ { "name" => "Name", "url" => "http://URL" } ];</syntaxhighlight>
| + | |
− | | + | |
− | : If there were already resources credited in the style, don't forget to add them again.
| + | |
− | | + | |
− | * If the theme has any images, name them like this: <code>themename_imagename.xxx</code>. Keep the image name used in other themes if there are any.
| + | |
− | | + | |
− | : If there's only one image, give it the theme name: <code>themename.xxx</code>
| + | |
− | | + | |
− | : If the theme has generic images used in other themes, simply use <code>imagename.xxx</code>.
| + | |
− | | + | |
− | : In the theme, use <code>stylename/themename_imagename.xxx</code>, <code>stylename/themename.xxx</code> or <code>stylename/imagename.xxx</code> as the URL.
| + | |
− | | + | |
− | * If you need to add theme-specific CSS, use:
| + | |
− | <syntaxhighlight lang="s2">
| + | |
− | function Page::print_theme_stylesheet() {
| + | |
− | """
| + | |
− | CSS HERE
| + | |
− | """;
| + | |
− | }</syntaxhighlight>
| + | |
− | | + | |
− | * Make sure to add the theme code in the right place: themes should be alphabetically sorted.
| + | |
− | | + | |
− | * Each theme file must be separated by two blank lines. Leave one blank line after the last theme in the file.
| + | |
− | | + | |
− | | + | |
− | = Check and format your files =
| + | |
− | | + | |
− | == General rules ==
| + | |
− | | + | |
− | * No tabs or trailing spaces.
| + | |
− | | + | |
− | * No empty properties.
| + | |
− | | + | |
− | * No hardcoded colors, fonts or text except shadows, <code>:before</code>/<code>:after</code> characters, colors in <code>print_theme_stylesheet()</code> if the designer has used a non-safe combination (color_page_text on color_entry_background instead of color_entry_text on color_entry_background ) or colors which aren't used elsewhere.
| + | |
− | | + | |
− | * No redundant code.
| + | |
− | | + | |
− | * Use shorthand for color codes whenever possible: #555 instead of #555555 and #abc instead of #aabbcc.
| + | |
− | | + | |
− | * Fonts should be capitalized, and single-quoted if there are several words: 'News Gothic MT' instead of news gothic mt.
| + | |
− | | + | |
− | | + | |
− | == Sort S2 properties ==
| + | |
− | | + | |
− | * Sort properties into categories.
| + | |
− | | + | |
− | :In styles, possible categories are: Presentation, Colors, Fonts, Images, Modules, Text, Links List and Custom CSS in this order.
| + | |
− | | + | |
− | :In themes, possible categories are: Presentation, Page Colors, Entry Colors, Module Colors, Fonts and Images, in this order.
| + | |
− | | + | |
− | Use headers to separate each category:
| + | |
− | <syntaxhighlight lang="s2">
| + | |
− | ##===============================
| + | |
− | ## Page Colors
| + | |
− | ##===============================
| + | |
− | </syntaxhighlight>
| + | |
− | | + | |
− | * In themes, properties should be sorted alphabetically within each category, but sometimes logic should prevail. For example, generic properties such as color_page_background go before specific properties such as color_header_background. Look at other themes to keep the same order.
| + | |
− | | + | |
− | == Format CSS ==
| + | |
− | | + | |
− | * Format CSS to be easily readable and editable. Everything should be properly indented and spaced out, selectors should be listed in the order they're displayed in the source, properties should be alphabetized.
| + | |
− | | + | |
− | * In styles, add style name and style author at the top of the stylesheet:
| + | |
− | <syntaxhighlight lang="css">
| + | |
− | /* Style Name
| + | |
− | /* by style author
| + | |
− | ******************************/
| + | |
− | | + | |
− | * In styles, use comment headers to separate sections:
| + | |
− | <syntaxhighlight lang="css">
| + | |
− | /* Modules
| + | |
− | ******************************/
| + | |
− | | + | |
− | .module {
| + | |
− | margin: 2em .5em;
| + | |
− | padding: 2em;
| + | |
− | }</syntaxhighlight>
| + | |
− | | + | |
− | * Remove leading zeros from decimals: .5em instead of 0.5em.
| + | |
− | | + | |
− | * Use [http://www.scriptiny.com/2008/04/css-shorthand-cheat-sheet/ shorthand] whenever possible:
| + | |
− | <syntaxhighlight lang="css">
| + | |
− | border: 1px solid $*color_module_border;
| + | |
− | border-top: none;
| + | |
− | list-style: square inside url($*image_list_bullet);
| + | |
− | margin: 2em .5em 1em;</syntaxhighlight>
| + | |
− | | + | |
− | instead of:
| + | |
− | <syntaxhighlight lang="css">
| + | |
− | border-bottom: 1px solid $*color_module_border;
| + | |
− | border-left: 1px solid $*color_module_border;
| + | |
− | border-right: 1px solid $*color_module_border;
| + | |
− | list-style-image: url($*image_list_bullet);
| + | |
− | list-style-position: inside;
| + | |
− | list-style-type: square;
| + | |
− | margin-bottom: 1em;
| + | |
− | margin-left: .5em;
| + | |
− | margin-right: .5em;
| + | |
− | margin-top: 2em;</syntaxhighlight>
| + | |
− | | + | |
− | * Remove gratuitous specificity such as <code>div.entry</code> instead of <code>.entry</code>. Inserting .DIV and .SPAN when they're not needed makes it harder to override selectors and can cause conflicts or bugs down the line. Compare:
| + | |
− | | + | |
− | <syntaxhighlight lang="css">
| + | |
− | .entry-content {
| + | |
− | background: blue;
| + | |
− | }
| + | |
− | | + | |
− | div.entry-content {
| + | |
− | background: red;
| + | |
− | }
| + | |
− | | + | |
− | .entry .entry-content {
| + | |
− | background: green;
| + | |
− | }
| + | |
− | | + | |
− | div.entry div.entry-content {
| + | |
− | background: yellow;
| + | |
− | }</syntaxhighlight>
| + | |
− | | + | |
− | * Group selectors whenever possible.
| + | |
− | | + | |
− | | + | |
− | = Adding new files to your patch =
| + | |
− | | + | |
− | * If the style or theme has images, they go to ~/dw/htdocs/img/styles/stylename/. If the style folder doesn't exist already, you'll have to create it.
| + | |
− | | + | |
− | * Use <code>git add FILENAME</code> or <code>git add .</code> to add them to your patch.
| + | |
− | | + | |
− | = Test, test and test =
| + | |
− | | + | |
− | * For styles, see the [http://dreamscapes.dreamwidth.org/42341.html list of required features] in <dwcomm>dreamscapes</dwcomm>. Pay attention to color combinations in particular: the style must not only work with the original set of themes but also with dark on light themes, backgrounds where the original designer didn't set one, etc. Anticipate on what users and other designers could do with it.
| + | |
− | | + | |
− | * In Customize, make sure everything is correctly listed and named. For styles, also make sure you can select the page layouts working with your style, and customize your style.
| + | |
− | | + | |
− | * On your test account, check colors on all pages. Don't forget hover and visited links, comment subjects, bottom links, reply boxes and drop-down menus on comment pages, contextual pop-ups, the navigation strip, blockquotes in entries and comments if these have been customized. For styles, also make sure all types of layouts, all pages, all sorts of entries and comments are displayed correctly and do so in various screen resolutions and font sizes. Don't forget to check community journals too.
| + | |
− | | + | |
− | = Preview pictures =
| + | |
− | | + | |
− | * To make preview pictures, you need to take a screenshot of the Recent Pages of your test account. This account needs to have one or two dummy entries with dummy titles and a [http://wiki.dwscoalition.org/notes/Category:Dreamwidth_Icons generic Dreamwidth icon] (or the no-userpic default graphic), no navigation strip, and generally few sidebar modules and no footer modules.
| + | |
− | | + | |
− | * It is best if you take your screenshot when your screen is set to a size of 1366x768 or 1280x800 pixels as these are the most common resolutions used by Dreamwidth users, and your font size set to 14-16 pixels. None of this is mandatory, though.
| + | |
− | | + | |
− | * Screenshots must then be resized to 150x114 pixels. If doing so distorts the image, you need to either edit the original screenshot in a photo editor program or edit your test journal until your screenshot can be resized without any distortion. You may also need to sharpen your image.
| + | |
− | | + | |
− | * Final previews should be color-indexed .PNGs, and should NOT include any color profile.
| + | |
− | | + | |
− | * If you can't do preview pictures mention it on the bug so that someone can do them for you. You can also ask for help at <dwcomm>dreamscapes</dwcomm>.
| + | |
− | | + | |
− | * A few tips:
| + | |
− | | + | |
− | : It might be a good idea to create accounts specifically for making previews --one per style-- so that you don't lose your set-up.
| + | |
− | | + | |
− | : If your photo editor program has scripting functions, you can use them to automate resizing and saving.
| + | |
− | | + | |
− | : Mozilla Firefox has a few extensions to help you generate content, uncheck several modules at once, resize your window and take screenshots:
| + | |
− | | + | |
− | :: [https://addons.mozilla.org/en-US/firefox/addon/dummy-lipsum Dummy Lipsum]
| + | |
− | :: [https://addons.mozilla.org/en-US/firefox/addon/checkfox/ CheckFox]
| + | |
− | :: [https://addons.mozilla.org/en-US/firefox/addon/web-developer Web Developer]
| + | |
− | :: [https://addons.mozilla.org/en-US/firefox/addon/fireshot FireShot]
| + | |
− | | + | |
− | : Google Chrome has two handy extensions (probably more) to help with making screenshots:
| + | |
− | | + | |
− | :: [http://www.chromeextensions.org/appearance-functioning/window-resizer/ Window Resizer] will make your browser window a specified size. Especially useful, if you set "screen type" to "mobile device" then the content window is made to the specified size. Using 1280x973 will resize to 150x114 nicely.
| + | |
− | | + | |
− | :: [https://chrome.google.com/webstore/detail/cpngackimfmofbokmjmljamhdncknpmg Screen Capture] will take screen shots of the contents of a browser window (Macs, and maybe other OSs, let you screencap a window but it gives you content and menus, which isn't helpful). A bit buggy but does the job.
| + | |
− | | + | |
− | : If you use a Mac or a Linux machine, you can resize, sharpen, strip any color profiles and make sure the final result is an indexed png from the command line with ImageMagick/convert <strong>as long as your screenshot is already the right aspect ratio</strong>:
| + | |
− | | + | |
− | : <syntaxhighlight lang=bash>convert -resize '150x114' -sharpen 25 +dither -type Palette $inputfilename png8:$outputfilename</syntaxhighlight>
| + | |
− | | + | |
− | : You can also make this into a script:
| + | |
− | | + | |
− | #!/bin/bash
| + | |
− | for f in *.png; do
| + | |
− | convert -resize '150' -sharpen 25 +dither -type Palette "$f" png8:"$f"
| + | |
− | done
| + | |
− | | + | |
− | : This version also checks if any of the files have already been done (so doesn't do them again) and prints out the names of the files it resizes:
| + | |
− | | + | |
− | #!/bin/bash
| + | |
− |
| + | |
− | echo " Creating Dreamwidth previews..."
| + | |
− |
| + | |
− | for f in *.png; do
| + | |
− |
| + | |
− | w=$(identify -format "%w" "$f")
| + | |
− | h=$(identify -format "%h" "$f")
| + | |
− | t=$(identify -format "%r" "$f")
| + | |
− | c=$(identify -format "%k" "$f")
| + | |
− |
| + | |
− | if [ $w -ne 150 ] || [ $h -ne 114 ] || [ $t != "PseudoClassRGB" ] || [ $c -gt 256 ]; then
| + | |
− | echo " * $f"
| + | |
− | convert -resize '150' -sharpen 25 +dither -type Palette "$f" png8:"$f"
| + | |
− | fi
| + | |
− |
| + | |
− | done
| + | |
− |
| + | |
− | echo " ... done"
| + | |
− | | + | |
− | [[Category:Development]]
| + | |
− | [[Category:Styles]]
| + | |
− | [[Category:Getting Started]] | + | |