Extension:FlaggedRevs

From eLinux.org
Jump to: navigation, search

For detailed usage information of this extension, see Help:Extension:FlaggedRevs

MediaWiki extensions manual
Crystal Clear action run.png
Flagged Revisions

Release status: stable

Implementation User interface, Special page, User rights, Database
Description Article validation allows for article content management by "editor" and "reviewer" classes.
Author(s) Aaron Schulz, Joerg Baach
MediaWiki 1.14a (r39052+)
License GPL
Download
Added rights

review, autoreview, validate, stablesettings, patrolother, movestable

Hooks used
UserGetRights

ArticleSaveComplete
LinksUpdateConstructed
ArticleUndelete
ArticleMergeComplete
ArticleRevisionUndeleted
ParserClearState
LocalFile::getHistory
BeforeParserFetchTemplateAndtitle
BeforeParserMakeImageLinkObj
ParserAfterTidy
OutputPageParserOutput
ArticleSaveComplete
NewRevisionFromEditComplete
userCan
LogLine
UserRights
GetAutoPromoteGroups
APIGetAllowedParams
APIQueryAfterExecute
MediaWikiPerformAction
BeforePageDisplay
ImagePageFindFile
CategoryPageView
SkinTemplateTabs
ArticleRollbackComplete
ArticleViewHeader
EditPage::showEditForm:initial
PageHistoryPager::getQueryInfo
PageHistoryLineEnding
ImagePageFileHistoryLine
ArticleUpdateBeforeRedirect
DiffViewHeader
EditPage::showEditForm:fields
PageHistoryBeforeList
InitializeArticleMaybeRedirect
HTMLCacheUpdate::doUpdate
ParserTestTables
ArticleDeleteComplete
SpecialPage_initList

Check usage and version matrix; code metrics

Article validation allows for Editor and Reviewer users to rate revisions of articles and set those revisions as the default revision to show upon normal page view. These revisions will remain the same even if included templates are changed or images are overwritten. This allows for MediaWiki to act more as a Content Management System (CMS).

Setup

  1. You must take care to match the version of FlaggedRevs to the version of MediaWiki that you are using! i.e. if you're using MediaWiki 1.13, use FlaggedRevs 1.13. Use the MediaWiki Download extension special page (here) to obtain the correct version of FlaggedRevs and extract it to your extensions directory.
  2. Run .../mwdir/maintenance/populateSha1.php if you haven't done so already.
  3. Make sure .../mwdir/extensions/FlaggedRevs/client (1.16) or .../mwdir/extensions/FlaggedRevs/ (<=1.15) is web-readable (required for CSS/JS).
  4. To enable article validation statistics, $wgPhpCli must be set correctly. This is not necessary if you set a cron job to run /FlaggedRevs/maintenance/updateStats.php every so often, which is preferable.
  5. Add the following line to LocalSettings.php:
    include_once('extensions/FlaggedRevs/FlaggedRevs.php');
    
  6. Run .../mwdir/maintenance/update.php. Note: If you can't do so (i.e. if you don't have command line access), you will need to import .../mwdir/extensions/FlaggedRevs/FlaggedRevs.sql into the database (after making the changes that are described in the file).
  7. Run .../mwdir/extensions/FlaggedRevs/maintenance/updateAutoPromote.php. You can ignore this if you aren't using $wgFlaggedRevsAutopromote.


Note: It is important that the sha1 column is populated (in the populateSha1.php step). This allows for image injection via key rather than the (name,timestamp) pair. In the future, image moves may be supported by MediaWiki, breaking the later method.

Be sure to set the $wgReviewCodes variable in FlaggedRevs.php. It should be an array of 2 string items:

$wgReviewCodes = array('one','two');

Any (secret) text will do, though it shouldn't be less than about 16 characters (less secure) or very long (waste of resources).

Initially, no user can see the reviewer's widget. To fix this, login as a wiki sysop and go to Special:UserRights. Promote a user to reviewer/editor and log out. When you login as the promoted user you will see the reviewer's widget on the bottom of an editable page.

Configuration

User rights

By default, nobody can review anything, so the first step is to set up user rights. FlaggedRevs creates or modifies the following user rights:

  • review -- user can review revisions
  • validate -- user can validate revisions
  • autoreview -- any edits made by the user are automatically marked as sighted
  • unreviewedpages -- user can view Special:UnreviewedPages

and the following new user groups:

  • Editors -- receive autoreview, autoconfirmed, autopatrol, patrol, review and unreviewedpages
  • Reviewers -- receive review and validate
  • Autoreviewers -- receive autoreview

Either assign these user rights to existing user groups in LocalSettings.php:

$wgGroupPermissions['sysop']['review'] = true; //allow administrators to review revisions 

or manually add user accounts to the appropriate groups via Special:UserRights. By default, Bureaucrats can add/remove both Editors and Reviewers, and Administrators can add/remove Editors.

Basic settings

FlaggedRevs.php comes with a number of configurable variables. These should be configured in LocalSettings.php.

  • $wgFlaggedRevsNamespaces - Sets what namespaces to allow for reviewing. This is an array of integers. Look at the beginning of includes/defines.php to see what integer the default namespaces map to.
  • $wgFlaggedRevsPatrolNamespaces - Sets what namespaces allow for recent changes patrol. This is ignored for pages in reviewable namespaces.
  • $wgFlaggedRevTags - An associative array with keys corresponding to each flag type and values that are arrays of three settings - 'levels','quality', and 'pristine. 'levels' controls the number of review levels, while 'quality' decides what level the tag must be for a revision to be 'quality'. The same goes for 'pristine'.

For example, for the tag configurations, suppose one wants to have "accuracy", "depth", and "tone" tags, with 3 levels each. The admin also want revisions with at least "accuracy" and "depth" of the 2nd levels to count as "quality". The following settings will do that:

$wgFlaggedRevTags = array(
	'accuracy' => array( 'levels' => 3, 'quality' => 2, 'pristine' => 4 ),
	'depth'    => array( 'levels' => 3, 'quality' => 2, 'pristine' => 4 ),
	'tone'     => array( 'levels' => 3, 'quality' => 1, 'pristine' => 4 ),
);

Each tag corresponds to a MediaWiki namespace page. For example, the first level of the "accuracy" tag corresponds to the text at MediaWiki:revreview-accuracy-1. This can therefore be customized.

  • $wgFlaggedRevsOverride - Whether flagged revisions override the default revision or simply give a tag notice to the stable version.
  • $wgFlaggedRevsExceptions - Makes users in these groups see the current revision by default.
  • $wgFlaggedRevsReviewForDefault - Makes FlaggedRevs available only for pages that are set to use them by default. This is affected by $wgFlaggedRevsOverride if there is no per-page setting.
  • $wgFlaggedRevsComments - Allow Editors/reviewers to add notes to the bottom of the page.
  • $wgFlagRestrictions - An array with keys corresponding to each flag type, and values that are arrays of rights and how high users with it can rate the flags (integral tag level).

For example:

$wgFlagRestrictions = array(
	'accuracy' => array( 'review' => 1 ),
	'depth'	   => array( 'review' => 2 ),
	'style'	   => array( 'review' => 3 ),
);
  • $wgFlaggedRevsWhitelist - Array of string titles. These titles are exempt from FlaggedRevs.

User interface

  • $wgFlaggedRevTabs - Whether to use "stable" and "draft" revision tabs.
  • $wgSimpleFlaggedRevsUI - When enabled, a simpler, icon based UI is used. Does not affect the tags shown in edit mode.
  • $wgFlaggedRevsLowProfile - This setting hides the review status box/bar for pages that are reviewed in their latest version. Explanatory text is also removed from some places.

Workflow

  • $wgReviewChangesAfterEdit - If enabled, Editors will jump to the diff against the last stable version after they make edits, unless it could be auto-reviewed or the page has no stable version.
  • $wgFlaggedRevsAutoReview - If enabled, every edit by a reviewer user is automatically reviewed upon save. There is no need to hit the "submit review" button. This feature requires that the previous revision was also reviewed. Otherwise, auto review will be disabled.
    • Auto review will create a review where accuracy, depth and style are set to 1. In general, such low values will earn the review a "sighted" designation. Remember that "quality" has higher precedence than "sighted". The presence of a "quality" revision will block out a "sighted" revision. If you don't want to be blocked out by a "quality" revision, you can redefine the meaning of quality. $wgFlaggedRevTags = array( 'accuracy'=>1, 'depth'=>1, 'style'=>1 );
    • 18px <translate> Note:</translate> Changes in templates and images are auto-reviewed (per-page). This could possibly cause bad versions to be reviewed. Users should be encouraged to use preview or review the page after saving. You may want to set $wgNamespaceProtection[NS_IMAGE] and $wgNamespaceProtection[NS_TEMPLATE] as array('editor') or array('autoconfirmed');
  • $wgFlaggedRevsAutoReviewNew - Whether to automatically review new pages by editors to the basic minimal level.

Automatic user promotion

  • $wgFlaggedRevsAutopromote - An array with keys for days, edits, time spacing, benchmarks, emailconfirmed, recent content page edits, total content edits, content pages edited, edit summaries used, IP uniqueness, and userpage existence as keys. The values correspond to how many days/edits are needed for a user account to be autopromoted to Editor status and whether they must be emailconfirmed and have a user page do so. The user must have at least X edits that are Y or more days apart, where X is the number of benchmarks and Y is the time spacing. Set this variable to false to disable this entirely.
    • 18px <translate> Note:</translate> If a user has their Editor rights removed, they will not automatically be re-granted (the editor status log is checked for revocations).
    • 18px <translate> Note:</translate> Some of these counts are not retroactive, so you may notice a delay in promotions.

For example, for $wgFlaggedRevsAutopromote, one might have:

$wgFlaggedRevsAutopromote['days'] = 60; # days since registration
$wgFlaggedRevsAutopromote['edits'] = 150; # total edit count
$wgFlaggedRevsAutopromote['excludeDeleted'] = true; # exclude deleted edits from 'edits' count above?
$wgFlaggedRevsAutopromote['spacing'] = 3; # spacing of edit intervals
$wgFlaggedRevsAutopromote['benchmarks'] = 15; # how many edit intervals are needed?
$wgFlaggedRevsAutopromote['recentContentEdits'] = 10; # $wgContentNamespaces edits in recent changes
$wgFlaggedRevsAutopromote['totalContentEdits'] = 30; # $wgContentNamespaces edits
$wgFlaggedRevsAutopromote['uniqueContentPages'] = 10; # $wgContentNamespaces unique pages edited
$wgFlaggedRevsAutopromote['editComments'] = 5; # how many edit comments used?
$wgFlaggedRevsAutopromote['email'] = true; # user must be emailconfirmed?
$wgFlaggedRevsAutopromote['userpageBytes'] = 0; # if userpage is needed, what is the min size?
$wgFlaggedRevsAutopromote['uniqueIPAddress'] = true; # If $wgPutIPinRC is true, users sharing IPs won't be promoted

Site access

If you need per-page or partial page access restrictions, you are advised to install an appropriate content management package. MediaWiki was not written to provide per-page access restrictions, and almost all hacks or patches promising to add them will likely have flaws somewhere, which could lead to exposure of confidential data. We are not responsible for anything being leaked, leading to loss of funds or one's job.
For further details, see Security issues with authorization extensions


  • $wgFlaggedRevsVisible - For sites that restrict viewing of the wiki, this settings makes the stable version of pages visible to people in certain groups (or all visitors). This variable is an array of user groups. Setting it to array('*') will let all visitors be able to see the stable version of pages. To restrict viewing of your wiki, set $wgGroupPermissions['*']['read'] = false; and $wgGroupPermissions['*']['edit'] = false;. This is useful for smaller wikis with an internal team of writers/editors.
    • Warning Warning: This does not work well with img_auth.php, as non-user viewers will not be able to see images. You will probably just want to leave images public but under hashed directories to make them harder to find. This is acceptable if there are no private files and the main concern is just not to release unverified content.
    • 18px <translate> Note:</translate> This will probably be useless without having $wgFlaggedRevsOverride = true.
    • 18px <translate> Note:</translate> Make sure that $wgWhitelistRead is set properly. You will at least want something like $wgWhitelistRead = array( 'Main Page', 'Special:Search' ). You may also want visible directory or category pages. Otherwise, the wiki will be hard to browse for readers.
    • 18px <translate> Note:</translate> Use $wgFlaggedRevsTalkVisible to allow viewing of all talk pages by these users.
    • 18px <translate> Note:</translate> You will probably want to edit MediaWiki:loginreqpagetext to make it more detailed. It will come up in various situations and thus should explain the approval system setup.

Advanced

See FlaggedRevs.php for a complete list of configuration options (with some explanatory comments). Be sure to change only localsettings.php to set configuration options rather than editing this file.

Use

See also: Help:FlaggedRevs

Approving pages

Users with some level of review status will have a small rating form on page view and diffs that lets them review revisions. Each tag must at least meet the minimal level of approval. Users should look at the whole page, included templates and images, before reviewing. The (diff to stable) link is very useful for speeding up this process.

A user cannot review a page he cannot edit. They cannot lower the level of a revision from a level they cannot set. Blocked users cannot do anything.

Revreview2.png

At Special:Stableversions, you can list out all of the reviewed revisions for a certain page or view reviewed revisions.

Stableversions.PNG

Upkeep

At Special:Unreviewedpages, there is a list of pages that have not yet been reviewed, for Editors only. A namespace must be selected and an optional category filter is also present.

Unreviewedpages.PNG

At Special:OldReviewedpages, there is a list of pages that have been reviewed, but have edits pending. This is for Editors only. An optional category filter is also present.

OldReviewedpages.PNG

Pages that cannot be reviewed can still be patrolled for anti-vandalism purposes by Editors to see what has been checked already.

A list of reviewed pages at the main review levels can be found at Special:Reviewedpages.

Reviewedpages.PNG

Logging

All relevant actions are permanently logged, so everything can be tracked and overseen properly.

  • A log of promotion/demotion of editors and the reasons is kept at Special:Log/userrights.
  • A log of the approval/unapproval of revisions is kept at Special:Log/review.
  • A log of changes to the stable versioning configuration to pages is logged at Special:Log/stable.

Also, a new page, Special:QualityOversight shows only flaggings log entries related to quality revisions. This is useful if the main log is too flooded with page "sightings".

Notes

  • $wgUseRCPatrol is enabled with the extension. Flagged revisions are marked as patrolled. Patrolling and autopatrolling of pages in reviewable namespaces is disabled. Other namespaces can be patrolled by Editors. This will mean that the only way to patrol a reviewable revision is to tag it as approved. The advantage is that patrolled edits will always correlate with a reviewed revision.
  • Sysops can change whether quality revision have precedence or whether the stable version is shown by default for specific pages. To disable this, add $wgGroupPermissions['sysop']['stablesettings'] = false; to localsettings.php.
  • External text storage is supported. If you already have external text storage on, then the same is applied for fr_text.
  • Page links, category, image, template, language, and external links will become the UNION of the current and the stable version.
  • Users cannot move pages they cannot review.
  • Autoconfirmed users have their edits to non-reviewable pages autopatrolled by default. To disable this, use $wgGroupPermissions['autoconfirmed']['autopatrolother'] = false;
  • You can demote Editors either temporarily by blocking them or permanently via Special:Userrights. An extra demotion log item will appear for tracking purposes.

API

FlaggedRevs adds API modules for reviewing revisions and configuring "stabilization" of pages, a module for retrieving flag configuration, and three list modules corresponding to the special pages for reviewed pages, unreviewed pages and "old" reviewed pages.

action = review

Reviews a page.

Parameters
  • revid: The revision ID for which to set the flags
  • token: An edit token retrieved through prop=info
  • comment: Comment for the review (optional)
  • flag_accuracy: Set the flag named "accuracy" to the specified value; (replace "accuracy" with the flag name to set another flag)
Example

Review revision 12345

<api>
  <review revid="12345" />
</api>

action = stabilize

Changes page stabilization settings.

Parameters
  • title: Title of page to be stabilized
  • reason: Reason for stabilization
  • default: Default revision to show (latest | stable)
  • precedence: Which stable revision should be shown (pristine | quality | latest). Default: quality
  • autoreview: Whether to restrict auto-review to administrators (sysop | none). Default: none
  • expiry: (Deprecated?) Stabilization expiry. Default: infinite
  • review: Whether to auto-review the page
  • watch: Whether to watch the page
  • token: An edit token retrieved through prop=info
Example

Configure the page "Foo" such that only quality revisions are shown by default

<api>
  <stabilize title="Foo" default="stable" precedence="quality" autoreview="none" expiry="infinite" />
</api>

action = flagconfig

Shows information about review flag configuration.

The following parameters are returned for each tag:

  • name: the name of the flag
  • levels: the number of possible levels the flag has (not counting the "unreviewed" level)
  • tier2: level the flag must be for the revision to be considered "quality"
  • tier3: level the flag must be for the revision to be considered "pristine"

The displayed name for each flag and the different level names for each flag are MediaWiki messages, so can be set and retrieved through the appropriate page; for example the name for the first level of the "accuracy" flag is located at MediaWiki:revreview-accuracy-1.

Example

Retrieve flag configuration

<api>
  <flagconfig>
    <tag name="accuracy" levels="3" tier2="2" tier3="4" />
    <tag name="depth" levels="3" tier2="1" tier3="4" />
    <tag name="style" levels="3" tier2="1" tier3="4" />
  </flagconfig>
</api>

list = reviewedpages

Lists pages that have been reviewed.

Parameters
  • rpstart: Start listing at this page id.
  • rpend: Stop listing at this page id.
  • rpdir: In which direction to list.
  • rpnamespace: The namespaces to enumerate.
  • rpfilterredir: How to filter for redirects
  • rpfilterlevel: How to filter by quality (0=sighted,1=quality)
  • rplimit: How many total pages to return.
Example

List "sighted" pages in main namespace

<api>
  <query-continue>
    <reviewedpages rpstart="14" />
  </query-continue>
  <query>
    <reviewedpages>
      <p pageid="1" ns="0" title="Alan Smithee" revid="62675112" stable_revid="62675112" flagged_level="0" flagged_level_text="stable" />
      <p pageid="3" ns="0" title="Actinium" revid="64593870" stable_revid="64593870" flagged_level="0" flagged_level_text="stable" />
      <p pageid="5" ns="0" title="Ang Lee" revid="64742530" stable_revid="64742530" flagged_level="0" flagged_level_text="stable" />
      <p pageid="6" ns="0" title="Andy Warhol" revid="65008103" stable_revid="65008103" flagged_level="0" flagged_level_text="stable" />
      <p pageid="7" ns="0" title="Anschluss (Soziologie)" revid="59086434" stable_revid="59086434" flagged_level="0" flagged_level_text="stable" />
      <p pageid="8" ns="0" title="Anschlussfähigkeit" revid="38028819" stable_revid="38028819" flagged_level="0" flagged_level_text="stable" />
      <p pageid="10" ns="0" title="Aussagenlogik" revid="64401094" stable_revid="64401094" flagged_level="0" flagged_level_text="stable" />
      <p pageid="11" ns="0" title="Autopoiese" revid="6746470" stable_revid="6746470" flagged_level="0" flagged_level_text="stable" />
      <p pageid="12" ns="0" title="A.A." revid="6746471" stable_revid="6746471" flagged_level="0" flagged_level_text="stable" />
      <p pageid="13" ns="0" title="Liste der Autoren/A" revid="63870061" stable_revid="63870061" flagged_level="0" flagged_level_text="stable" />
    </reviewedpages>
  </query>
</api>

list = unreviewedpages

Lists pages which have never been reviewed.

Parameters
  • urstart: Start listing at this page title.
  • urend: Stop listing at this page title.
  • urnamespace: The namespaces to enumerate.
  • urfilterredir: How to filter for redirects
  • urfilterlevel: How to filter by quality (0=sighted,1=quality)
  • urlimit: How many total pages to return.
Example

List pages in the main namespace that have not been "sighted"

<api>
  <query-continue>
    <unreviewedpages urstart="Arbeitgeberverband_Chemie_und_verwandte_Industrien_für_das_Land_Hessen" />
  </query-continue>
  <query>
    <unreviewedpages>
      <p pageid="4762806" ns="0" title="Aaftink" revid="65175047" />
      <p pageid="4747500" ns="0" title="Abt RS6" revid="64976429" />
      <p pageid="4749877" ns="0" title="Acht Vorlesungen über den Konstruktiven Realismus" revid="65089962" />
      <p pageid="4758156" ns="0" title="Alkylglycerole" revid="65169004" />
      <p pageid="4719044" ns="0" title="All Riot" revid="64767732" />
      <p pageid="4745418" ns="0" title="Allgäu-Panorama-Marathon" revid="64974783" />
      <p pageid="4729976" ns="0" title="An- und Einpressen" revid="64742640" />
      <p pageid="4742559" ns="0" title="Anjara I. Bartz" revid="64925772" />
      <p pageid="4740681" ns="0" title="Anthony Norris Groves" revid="65064712" />
      <p pageid="4759964" ns="0" title="Antonino Asta" revid="65169073" />
    </unreviewedpages>
  </query>
</api>

list = oldreviewedpages

Lists pages that have at some point been reviewed, but for which the most recent revision is not reviewed.

Parameters
  • orstart: Start listing from this timestamp
  • orend: Stop listing at this timestamp.
  • ordir: In which direction to list.
  • ornamespace: The namespaces to enumerate.
  • orfilterredir: How to filter for redirects
  • orlimit: How many total pages to return.
Example

List pages in the main namespace with recent unreviewed revisions

<api>
  <query-continue>
    <oldreviewedpages orstart="2009-09-15T20:23:05Z" />
  </query-continue>
  <query>
    <oldreviewedpages>
      <p pageid="144735" ns="0" title="Two International Finance Centre" revid="64562654" stable_revid="62769201" pending_since="2009-09-15T16:16:33Z" flagged_level="0" flagged_level_text="stable" />
      <p pageid="1629949" ns="0" title="Porta San Sebastiano" revid="64791898" stable_revid="61610797" pending_since="2009-09-15T16:19:32Z" flagged_level="0" flagged_level_text="stable" />
      <p pageid="2157354" ns="0" title="Entwicklungspolitik der Europäischen Union" revid="64640078" stable_revid="59929751" pending_since="2009-09-15T16:38:33Z" flagged_level="0" flagged_level_text="stable" />
      <p pageid="971904" ns="0" title="Federpendel" revid="65142775" stable_revid="59587441" pending_since="2009-09-15T17:37:29Z" flagged_level="0" flagged_level_text="stable" />
      <p pageid="3106812" ns="0" title="Soultzbach-les-Bains" revid="64552516" stable_revid="60455707" pending_since="2009-09-15T19:04:07Z" flagged_level="0" flagged_level_text="stable" />
      <p pageid="1223029" ns="0" title="VfR Bürstadt" revid="65150048" stable_revid="62925935" pending_since="2009-09-15T19:35:30Z" flagged_level="0" flagged_level_text="stable" />
      <p pageid="829158" ns="0" title="GSP" revid="64553869" stable_revid="62913440" pending_since="2009-09-15T19:38:46Z" flagged_level="0" flagged_level_text="stable" />
      <p pageid="3453867" ns="0" title="Agios Dimitrios" revid="65103799" stable_revid="64544222" pending_since="2009-09-15T19:47:10Z" flagged_level="0" flagged_level_text="stable" />
      <p pageid="2583263" ns="0" title="Jörg Kudlich" revid="64554475" stable_revid="62429967" pending_since="2009-09-15T20:03:24Z" flagged_level="0" flagged_level_text="stable" />
      <p pageid="325478" ns="0" title="Liste deutscher Komponisten klassischer Musik" revid="65089571" stable_revid="63582610" pending_since="2009-09-15T20:21:55Z" flagged_level="0" flagged_level_text="stable" />
    </oldreviewedpages>
  </query>
</api>

Limitations

  • Transclusions across wikis are not stabilized
  • External images (aside from Commons) are not stabilized
  • Metatemplates that conditionally include other templates may have the condition change between the time a reviewer loaded a page and when they reviewed it. Therefore, there would be no pointers to the revision id for this different template to load from, making it blue linked. You will be notified if this happens during review.
  • Using parser function variable to determine what templates to include (such as one template for each day) will not work for a stable revision. The revision will show as it was upon the time of review.

Uninstalling

  • Remove the include line from LocalSettings.php
  • Drop the tables in FlaggedRevs.sql.
  • Drop the columns 'page_ext_reviewed', 'page_ext_quality', and 'page_ext_stable', and the index 'ext_namespace_reviewed' from the page table (if they exist, only older versions used these)
  • Run maintenance/refreshLinks.php from the command line to flush out the stable version links
  • Run maintenance/rebuildFileCache.php 0 overwrite from the command line if you use $wgFileCache

Testing platforms

See also

External links

Licensing

© GPL, Aaron Schulz, Joerg Baach, 2007


GNU head This work is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the license, or (at your option) any later version. This work is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.