* Salvatore Ingala
* Santhosh Thottingal
* Scott Colcord
+* se4598
* Sébastien Santoro
* Simon Walker
* Solitarius
the system message 'emailsender' should be modified (default: "{{SITENAME}}").
* $wgDBAhandler was removed as the only class using it was also removed
* The 'max threads' setting was removed from $wgDBservers.
+* Support for AdminSettings.php has been completely removed. All configuration
+ belongs in LocalSettings.php.
=== New features in 1.23 ===
* ResourceLoader can utilize the Web Storage API to cache modules client-side.
compiled without support for MySQL yet with support for another DBMS.
* (bug 56199) Raw option of parser functions must now match complete word,
to take effect.
+* (bug 60543) Special:PrefixIndex forgot stripprefix=1 for "Next page" link
=== Web API changes in 1.23 ===
* (bug 54884) action=parse&prop=categories now indicates hidden and missing
'WebInstallerPage' => 'includes/installer/WebInstallerPage.php',
# includes/job
+ 'IJobSpecification' => 'includes/job/JobSpecification.php',
'Job' => 'includes/job/Job.php',
'JobQueue' => 'includes/job/JobQueue.php',
'JobQueueAggregator' => 'includes/job/aggregator/JobQueueAggregator.php',
'JobQueueGroup' => 'includes/job/JobQueueGroup.php',
'JobQueueFederated' => 'includes/job/JobQueueFederated.php',
'JobQueueRedis' => 'includes/job/JobQueueRedis.php',
+ 'JobSpecification' => 'includes/job/JobSpecification.php',
# includes/job/jobs
'DoubleRedirectJob' => 'includes/job/jobs/DoubleRedirectJob.php',
* Do a binary search, and return the index of the largest item that sorts
* less than or equal to the target value.
*
- * @deprecated in 1.22; use ArrayUtils::findLowerBound() instead
+ * @deprecated in 1.23; use ArrayUtils::findLowerBound() instead
*
* @param array $valueCallback A function to call to get the value with
* a given array index.
* sorts before all items.
*/
function findLowerBound( $valueCallback, $valueCount, $comparisonCallback, $target ) {
- wfDeprecated( __METHOD__, '1.22' );
+ wfDeprecated( __METHOD__, '1.23' );
return ArrayUtils::findLowerBound( $valueCallback, $valueCount, $comparisonCallback, $target );
}
* Date format selectors; used in user preference storage and by
* Language::date() and co.
*/
-/*define( 'MW_DATE_DEFAULT', '0' );
-define( 'MW_DATE_MDY', '1' );
-define( 'MW_DATE_DMY', '2' );
-define( 'MW_DATE_YMD', '3' );
-define( 'MW_DATE_ISO', 'ISO 8601' );*/
define( 'MW_DATE_DEFAULT', 'default' );
define( 'MW_DATE_MDY', 'mdy' );
define( 'MW_DATE_DMY', 'dmy' );
$undo = $wgRequest->getInt( 'undo' );
if ( $undo > 0 && $undoafter > 0 ) {
- if ( $undo < $undoafter ) {
- # If they got undoafter and undo round the wrong way, switch them
- list( $undo, $undoafter ) = array( $undoafter, $undo );
- }
$undorev = Revision::newFromId( $undo );
$oldrev = Revision::newFromId( $undoafter );
# the revisions exist and they were not deleted.
# Otherwise, $content will be left as-is.
if ( !is_null( $undorev ) && !is_null( $oldrev ) &&
- $undorev->getPage() == $oldrev->getPage() &&
- $undorev->getPage() == $this->mTitle->getArticleID() &&
!$undorev->isDeleted( Revision::DELETED_TEXT ) &&
!$oldrev->isDeleted( Revision::DELETED_TEXT ) ) {
*/
static function getEditToolbar() {
global $wgStylePath, $wgContLang, $wgLang, $wgOut;
- global $wgUseTeX, $wgEnableUploads, $wgForeignFileRepos;
+ global $wgEnableUploads, $wgForeignFileRepos;
$imagesAvailable = $wgEnableUploads || count( $wgForeignFileRepos );
'tip' => wfMessage( 'media_tip' )->text(),
'key' => 'M'
) : false,
- $wgUseTeX ? array(
+ class_exists( 'MathRenderer' ) ? array(
'image' => $wgLang->getImageFile( 'button-math' ),
'id' => 'mw-editbutton-math',
'open' => "<math>",
* @param string|Message $msg Message key (string) for error text, or a Message object
* @param array $params with parameters to wfMessage()
*/
- function __construct( $title, $msg, $params = null ) {
+ function __construct( $title, $msg, $params = array() ) {
$this->title = $title;
$this->msg = $msg;
$this->params = $params;
* @param string|Message $msg A message key (default: 'badtitletext')
* @param array $params parameter to wfMessage()
*/
- function __construct( $msg = 'badtitletext', $params = null ) {
+ function __construct( $msg = 'badtitletext', $params = array() ) {
parent::__construct( 'badtitle', $msg, $params );
}
parent::__construct(
'readonly',
'readonlytext',
- wfReadOnlyReason()
+ wfReadOnlyReason() ?: array()
);
}
}
* @param string $titleMsg A message key to set the page title.
* Optional, default: 'exception-nologin'
* @param array $params Parameters to wfMessage().
- * Optional, default: null
+ * Optional, default: array()
*/
public function __construct(
$reasonMsg = 'exception-nologin-text',
$titleMsg = 'exception-nologin',
- $params = null
+ $params = array()
) {
parent::__construct( $titleMsg, $reasonMsg, $params );
}
}
if ( !wfShellExecDisabled() && is_executable( $wgPhpCli ) ) {
- // Start a background process to run some of the jobs.
- // This will be asynchronous on *nix though not on Windows.
+ // Start a background process to run some of the jobs
wfProfileIn( __METHOD__ . '-exec' );
$retVal = 1;
$cmd = wfShellWikiCmd( "$IP/maintenance/runJobs.php", array( '--maxjobs', $n ) );
- wfShellExec( "$cmd &", $retVal );
+ $cmd .= " >" . wfGetNull() . " 2>&1"; // don't hang PHP on pipes
+ if ( wfIsWindows() ) {
+ // Using START makes this async and also works around a bug where using
+ // wfShellExec() with a quoted script name causes a filename syntax error.
+ $cmd = "START /B \"bg\" $cmd";
+ } else {
+ $cmd = "$cmd &";
+ }
+ wfShellExec( $cmd, $retVal );
wfProfileOut( __METHOD__ . '-exec' );
} else {
try {
} elseif ( is_array( $subElemValue ) ) {
$subElements[$subElemId] = $subElemValue;
unset( $elemValue[$subElemId] );
+ } elseif ( is_bool( $subElemValue ) ) {
+ // treat true as empty string, skip false in xml format
+ if ( $subElemValue === true ) {
+ $subElemValue = '';
+ } else {
+ unset( $elemValue[$subElemId] );
+ }
}
}
if ( !$difftoRev ) {
$this->dieUsageMsg( array( 'nosuchrevid', $params['diffto'] ) );
}
- if ( !$diffToRev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) {
+ if ( !$difftoRev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) {
$this->setWarning( "Couldn't diff to r{$difftoRev->getID()}: content is hidden" );
$params['diffto'] = null;
}
if ( $this->isVForm() ) {
// mw-ui-block is necessary because the buttons aren't necessarily in an
// immediate child div of the vform.
- array_push( $attribs['class'], 'mw-ui-button', 'mw-ui-big', 'mw-ui-primary', 'mw-ui-block' );
+ // TODO Let client specify if the primary submit button is progressive or destructive
+ array_push( $attribs['class'], 'mw-ui-button', 'mw-ui-big', 'mw-ui-constructive', 'mw-ui-block' );
}
$html .= Xml::submitButton( $this->getSubmitText(), $attribs ) . "\n";
}
/**
- * Determine if LocalSettings.php exists. If it does, return its variables,
- * merged with those from AdminSettings.php, as an array.
+ * Determine if LocalSettings.php exists. If it does, return its variables.
*
* @return Array
*/
require "$IP/includes/DefaultSettings.php";
require "$IP/LocalSettings.php";
- if ( file_exists( "$IP/AdminSettings.php" ) ) {
- require "$IP/AdminSettings.php";
- }
return get_defined_vars();
}
"INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('archive_ar_id_seq')" ),
array( 'addPgField', 'externallinks', 'el_id',
"INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('externallinks_el_id_seq')" ),
+ array( 'addPgField', 'uploadstash', 'us_props', "BYTEA" ),
# type changes
array( 'changeField', 'archive', 'ar_deleted', 'smallint', '' ),
/**
* Initiate an upgrade of the existing database
- * @param array $vars Variables from LocalSettings.php and AdminSettings.php
+ * @param array $vars Variables from LocalSettings.php
* @return Status
*/
protected function handleExistingUpgrade( $vars ) {
<?php
/**
- * Job queue base code.
+ * Job queue task base code.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/**
* Class to both describe a background job and handle jobs.
* The queue aspects of this class are now deprecated.
+ * Using the class to push jobs onto queues is deprecated (use JobSpecification).
*
* @ingroup JobQueue
*/
-abstract class Job {
+abstract class Job implements IJobSpecification {
/** @var string */
public $command;
}
/**
- * @param Job $job
+ * @param IJobSpecification $job
* @return array
*/
- protected function insertFields( Job $job ) {
+ protected function insertFields( IJobSpecification $job ) {
$dbw = $this->getMasterDB();
return array(
$jobsByType = array(); // (job type => list of jobs)
foreach ( $jobs as $job ) {
- if ( $job instanceof Job ) {
+ if ( $job instanceof IJobSpecification ) {
$jobsByType[$job->getType()][] = $job;
} else {
throw new MWException( "Attempted to push a non-Job object into a queue." );
}
/**
- * @param Job $job
+ * @param IJobSpecification $job
* @return array
*/
- protected function getNewJobFields( Job $job ) {
+ protected function getNewJobFields( IJobSpecification $job ) {
return array(
// Fields that describe the nature of the job
'type' => $job->getType(),
// Additional job metadata
'uuid' => UIDGenerator::newRawUUIDv4( UIDGenerator::QUICK_RAND ),
'sha1' => $job->ignoreDuplicates()
- ? wfBaseConvert( sha1( serialize( $job->getDeduplicationInfo() ) ), 16, 36, 31 )
- : '',
+ ? wfBaseConvert( sha1( serialize( $job->getDeduplicationInfo() ) ), 16, 36, 31 )
+ : '',
'timestamp' => time() // UNIX timestamp
);
}
--- /dev/null
+<?php
+/**
+ * Job queue task description base code.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup JobQueue
+ */
+
+/**
+ * Job queue task description interface
+ *
+ * @ingroup JobQueue
+ * @since 1.23
+ */
+interface IJobSpecification {
+ /**
+ * @return string Job type
+ */
+ public function getType();
+
+ /**
+ * @return array
+ */
+ public function getParams();
+
+ /**
+ * @return int|null UNIX timestamp to delay running this job until, otherwise null
+ */
+ public function getReleaseTimestamp();
+
+ /**
+ * @return bool Whether only one of each identical set of jobs should be run
+ */
+ public function ignoreDuplicates();
+
+ /**
+ * Subclasses may need to override this to make duplication detection work.
+ * The resulting map conveys everything that makes the job unique. This is
+ * only checked if ignoreDuplicates() returns true, meaning that duplicate
+ * jobs are supposed to be ignored.
+ *
+ * @return array Map of key/values
+ */
+ public function getDeduplicationInfo();
+
+ /**
+ * @return Title Descriptive title (this can simply be informative)
+ */
+ public function getTitle();
+}
+
+/**
+ * Job queue task description base code
+ *
+ * Example usage:
+ * <code>
+ * $job = new JobSpecification(
+ * 'null',
+ * array( 'lives' => 1, 'usleep' => 100, 'pi' => 3.141569 ),
+ * array( 'removeDuplicates' => 1 ),
+ * Title::makeTitle( NS_SPECIAL, 'nullity' )
+ * );
+ * JobQueueGroup::singleton()->push( $job )
+ * </code>
+ *
+ * @ingroup JobQueue
+ * @since 1.23
+ */
+class JobSpecification implements IJobSpecification {
+ /** @var string */
+ protected $type;
+
+ /** @var array Array of job parameters or false if none */
+ protected $params;
+
+ /** @var Title */
+ protected $title;
+
+ /** @var bool Expensive jobs may set this to true */
+ protected $ignoreDuplicates;
+
+ /**
+ * @param string $type
+ * @param array $params Map of key/values
+ * @param array $opts Map of key/values
+ * @param Title $title Optional descriptive title
+ */
+ public function __construct(
+ $type, array $params, array $opts = array(), Title $title = null
+ ) {
+ $this->validateParams( $params );
+
+ $this->type = $type;
+ $this->params = $params;
+ $this->title = $title ?: Title::newMainPage();
+ $this->ignoreDuplicates = !empty( $opts['removeDuplicates'] );
+ }
+
+ /**
+ * @param array $params
+ */
+ protected function validateParams( array $params ) {
+ foreach ( $params as $p => $v ) {
+ if ( is_array( $v ) ) {
+ $this->validateParams( $v );
+ } elseif ( !is_scalar( $v ) && $v !== null ) {
+ throw new UnexpectedValueException( 'Job parameters are not JSON serializable.' );
+ }
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function getType() {
+ return $this->type;
+ }
+
+ /**
+ * @return Title
+ */
+ public function getTitle() {
+ return $this->title;
+ }
+
+ /**
+ * @return array
+ */
+ public function getParams() {
+ return $this->params;
+ }
+
+ /**
+ * @return int|null UNIX timestamp to delay running this job until, otherwise null
+ */
+ public function getReleaseTimestamp() {
+ return isset( $this->params['jobReleaseTimestamp'] )
+ ? wfTimestampOrNull( TS_UNIX, $this->params['jobReleaseTimestamp'] )
+ : null;
+ }
+
+ /**
+ * @return bool Whether only one of each identical set of jobs should be run
+ */
+ public function ignoreDuplicates() {
+ return $this->ignoreDuplicates;
+ }
+
+ /**
+ * Subclasses may need to override this to make duplication detection work.
+ * The resulting map conveys everything that makes the job unique. This is
+ * only checked if ignoreDuplicates() returns true, meaning that duplicate
+ * jobs are supposed to be ignored.
+ *
+ * @return array Map of key/values
+ */
+ public function getDeduplicationInfo() {
+ $info = array(
+ 'type' => $this->getType(),
+ 'namespace' => $this->getTitle()->getNamespace(),
+ 'title' => $this->getTitle()->getDBkey(),
+ 'params' => $this->getParams()
+ );
+ if ( is_array( $info['params'] ) ) {
+ // Identical jobs with different "root" jobs should count as duplicates
+ unset( $info['params']['rootJobSignature'] );
+ unset( $info['params']['rootJobTimestamp'] );
+ // Likewise for jobs with different delay times
+ unset( $info['params']['jobReleaseTimestamp'] );
+ }
+
+ return $info;
+ }
+}
* @ingroup JobQueue
*/
class RefreshLinksJob extends Job {
+ const PARSE_THRESHOLD_SEC = 1.0;
+
function __construct( $title, $params = '' ) {
parent::__construct( 'refreshLinks', $title, $params );
// Base backlink update jobs and per-title update jobs can be de-duplicated.
wfGetLB()->waitFor( $this->params['masterPos'] );
}
+ $page = WikiPage::factory( $title );
+
// Fetch the current revision...
$revision = Revision::newFromTitle( $title, false, Revision::READ_NORMAL );
if ( !$revision ) {
}
$parserOutput = false;
+ $parserOptions = $page->makeParserOptions( 'canonical' );
// If page_touched changed after this root job (with a good slave lag skew factor),
// then it is likely that any views of the pages already resulted in re-parses which
// are now in cache. This can be reused to avoid expensive parsing in some cases.
if ( isset( $this->params['rootJobTimestamp'] ) ) {
- $page = WikiPage::factory( $title );
$skewedTimestamp = wfTimestamp( TS_UNIX, $this->params['rootJobTimestamp'] ) + 5;
if ( $page->getLinksTimestamp() > wfTimestamp( TS_MW, $skewedTimestamp ) ) {
// Something already updated the backlinks since this job was made
return true;
}
if ( $page->getTouched() > wfTimestamp( TS_MW, $skewedTimestamp ) ) {
- $parserOptions = $page->makeParserOptions( 'canonical' );
$parserOutput = ParserCache::singleton()->getDirty( $page, $parserOptions );
if ( $parserOutput && $parserOutput->getCacheTime() <= $skewedTimestamp ) {
$parserOutput = false; // too stale
}
// Fetch the current revision and parse it if necessary...
if ( $parserOutput == false ) {
+ $start = microtime( true );
// Revision ID must be passed to the parser output to get revision variables correct
- $parserOutput = $content->getParserOutput( $title, $revision->getId(), null, false );
+ $parserOutput = $content->getParserOutput(
+ $title, $revision->getId(), $parserOptions, false );
+ $ellapsed = microtime( true ) - $start;
+ // If it took a long time to render, then save this back to the cache to avoid
+ // wasted CPU by other apaches or job runners. We don't want to always save to
+ // cache as this cause cause high cache I/O and LRU churn when a template changes.
+ if ( $ellapsed >= self::PARSE_THRESHOLD_SEC
+ && $page->isParserCacheUsed( $parserOptions, $revision->getId() )
+ && $parserOutput->isCacheable()
+ ) {
+ $ctime = wfTimestamp( TS_MW, (int)$start ); // cache time
+ ParserCache::singleton()->save( $parserOutput, $page, $parserOptions, $ctime );
+ }
}
$updates = $content->getSecondaryDataUpdates( $title, null, false, $parserOutput );
return $ruleWithRemapped;
}
}, $source );
-
- return $source;
}
/**
* - wrap String Wrap the message in html (usually something like "<div ...>$1</div>").
* - flags Integer display flags (NO_ACTION_LINK,NO_EXTRA_USER_LINKS)
* - useRequestParams boolean Set true to use Pager-related parameters in the WebRequest
+ * - useMaster boolean Use master DB
* @return int Number of total log items (not limited by $lim)
*/
public static function showLogExtract(
'wrap' => "$1",
'flags' => 0,
'useRequestParams' => false,
+ 'useMaster' => false,
);
# The + operator appends elements of remaining keys from the right
# handed array to the left handed, whereas duplicated keys are NOT overwritten.
$pager->mIsBackwards = false;
}
+ if ( $param['useMaster'] ) {
+ $pager->mDb = wfGetDB( DB_MASTER );
+ }
if ( isset( $param['offset'] ) ) { # Tell pager to ignore WebRequest offset
$pager->setOffset( $param['offset'] );
}
global $wgSharpenReductionThreshold, $wgSharpenParameter, $wgMaxAnimatedGifArea,
$wgImageMagickTempDir, $wgImageMagickConvertCommand;
- $quality = '';
- $sharpen = '';
+ $quality = array();
+ $sharpen = array();
$scene = false;
- $animation_pre = '';
- $animation_post = '';
- $decoderHint = '';
+ $animation_pre = array();
+ $animation_post = array();
+ $decoderHint = array();
if ( $params['mimeType'] == 'image/jpeg' ) {
- $quality = "-quality 80"; // 80%
+ $quality = array( '-quality', '80' ); // 80%
# Sharpening, see bug 6193
if ( ( $params['physicalWidth'] + $params['physicalHeight'] )
/ ( $params['srcWidth'] + $params['srcHeight'] )
< $wgSharpenReductionThreshold
) {
- $sharpen = "-sharpen " . wfEscapeShellArg( $wgSharpenParameter );
+ $sharpen = array( '-sharpen', $wgSharpenParameter );
}
if ( version_compare( $this->getMagickVersion(), "6.5.6" ) >= 0 ) {
// JPEG decoder hint to reduce memory, available since IM 6.5.6-2
- $decoderHint = "-define jpeg:size={$params['physicalDimensions']}";
+ $decoderHint = array( '-define', "jpeg:size={$params['physicalDimensions']}" );
}
} elseif ( $params['mimeType'] == 'image/png' ) {
- $quality = "-quality 95"; // zlib 9, adaptive filtering
+ $quality = array( '-quality', '95' ); // zlib 9, adaptive filtering
} elseif ( $params['mimeType'] == 'image/gif' ) {
if ( $this->getImageArea( $image ) > $wgMaxAnimatedGifArea ) {
$scene = 0;
} elseif ( $this->isAnimatedImage( $image ) ) {
// Coalesce is needed to scale animated GIFs properly (bug 1017).
- $animation_pre = '-coalesce';
+ $animation_pre = array( '-coalesce' );
// We optimize the output, but -optimize is broken,
// use optimizeTransparency instead (bug 11822)
if ( version_compare( $this->getMagickVersion(), "6.3.5" ) >= 0 ) {
- $animation_post = '-fuzz 5% -layers optimizeTransparency';
+ $animation_post = array( '-fuzz', '5%', '-layers', 'optimizeTransparency' );
}
}
} elseif ( $params['mimeType'] == 'image/x-xcf' ) {
- $animation_post = '-layers merge';
+ $animation_post = array( '-layers', 'merge' );
}
// Use one thread only, to avoid deadlock bugs on OOM
$rotation = $this->getRotation( $image );
list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
- $cmd =
- wfEscapeShellArg( $wgImageMagickConvertCommand ) .
+ $cmd = call_user_func_array( 'wfEscapeShellArg', array_merge(
+ array( $wgImageMagickConvertCommand ),
+ $quality,
// Specify white background color, will be used for transparent images
// in Internet Explorer/Windows instead of default black.
- " {$quality} -background white" .
- " {$decoderHint} " .
- wfEscapeShellArg( $this->escapeMagickInput( $params['srcPath'], $scene ) ) .
- " {$animation_pre}" .
+ array( '-background', 'white' ),
+ $decoderHint,
+ array( $this->escapeMagickInput( $params['srcPath'], $scene ) ),
+ $animation_pre,
// For the -thumbnail option a "!" is needed to force exact size,
// or ImageMagick may decide your ratio is wrong and slice off
// a pixel.
- " -thumbnail " . wfEscapeShellArg( "{$width}x{$height}!" ) .
+ array( '-thumbnail', "{$width}x{$height}!" ),
// Add the source url as a comment to the thumb, but don't add the flag if there's no comment
( $params['comment'] !== ''
- ? " -set comment " . wfEscapeShellArg( $this->escapeMagickProperty( $params['comment'] ) )
- : '' ) .
- " -depth 8 $sharpen " .
- " -rotate -$rotation " .
- " {$animation_post} " .
- wfEscapeShellArg( $this->escapeMagickOutput( $params['dstPath'] ) );
+ ? array( '-set', 'comment', $this->escapeMagickProperty( $params['comment'] ) )
+ : array() ),
+ array( '-depth', 8 ),
+ $sharpen,
+ array( '-rotate', "-$rotation" ),
+ $animation_post,
+ array( $this->escapeMagickOutput( $params['dstPath'] ) ) ) );
wfDebug( __METHOD__ . ": running ImageMagick: $cmd\n" );
wfProfileIn( 'convert' );
$dst = wfEscapeShellArg( $params['dstPath'] );
$cmd = $wgCustomConvertCommand;
$cmd = str_replace( '%s', $src, str_replace( '%d', $dst, $cmd ) ); # Filenames
- $cmd = str_replace( '%h', $params['physicalHeight'],
- str_replace( '%w', $params['physicalWidth'], $cmd ) ); # Size
+ $cmd = str_replace( '%h', wfEscapeShellArg( $params['physicalHeight'] ),
+ str_replace( '%w', wfEscapeShellArg( $params['physicalWidth'] ), $cmd ) ); # Size
wfDebug( __METHOD__ . ": Running custom convert command $cmd\n" );
wfProfileIn( 'convert' );
$retval = 0;
case 'im':
$cmd = wfEscapeShellArg( $wgImageMagickConvertCommand ) . " " .
wfEscapeShellArg( $this->escapeMagickInput( $params['srcPath'], $scene ) ) .
- " -rotate -$rotation " .
+ " -rotate " . wfEscapeShellArg( "-$rotation" ) . " " .
wfEscapeShellArg( $this->escapeMagickOutput( $params['dstPath'] ) );
wfDebug( __METHOD__ . ": running ImageMagick: $cmd\n" );
wfProfileIn( 'convert' );
$srcPath = $image->getLocalRefPath();
# Use a subshell (brackets) to aggregate stderr from both pipeline commands
# before redirecting it to the overall stdout. This works in both Linux and Windows XP.
- $cmd = '(' . wfEscapeShellArg( $wgDjvuRenderer ) . " -format=ppm -page={$page}" .
- " -size={$params['physicalWidth']}x{$params['physicalHeight']} " .
- wfEscapeShellArg( $srcPath );
+ $cmd = '(' . wfEscapeShellArg(
+ $wgDjvuRenderer,
+ "-format=ppm",
+ "-page={$page}",
+ "-size={$params['physicalWidth']}x{$params['physicalHeight']}",
+ $srcPath );
if ( $wgDjvuPostProcessor ) {
$cmd .= " | {$wgDjvuPostProcessor}";
}
if ( !isset( $params['page'] ) ) {
$params['page'] = 1;
} else {
+ $params['page'] = intval( $params['page'] );
if ( $params['page'] > $image->pageCount() ) {
$params['page'] = $image->pageCount();
}
}
static function localurle( $parser, $s = '', $arg = null ) {
- return htmlspecialchars( self::urlFunction( 'getLocalURL', $s, $arg ) );
+ $temp = self::urlFunction( 'getLocalURL', $s, $arg );
+ if( !is_string( $temp ) ) {
+ return $temp;
+ } else {
+ return htmlspecialchars( $temp );
+ }
}
static function fullurl( $parser, $s = '', $arg = null ) {
}
static function fullurle( $parser, $s = '', $arg = null ) {
- return htmlspecialchars( self::urlFunction( 'getFullURL', $s, $arg ) );
+ $temp = self::urlFunction( 'getFullURL', $s, $arg );
+ if( !is_string( $temp ) ) {
+ return $temp;
+ } else {
+ return htmlspecialchars( $temp );
+ }
}
static function canonicalurl( $parser, $s = '', $arg = null ) {
public $mDb;
public $preventClickjacking = false;
+ /** @var DatabaseBase */
+ public $mDbSecondary;
+
/**
* @var array
*/
$month = isset( $options['month'] ) ? $options['month'] : false;
$this->getDateCond( $year, $month );
+ // Most of this code will use the 'contributions' group DB, which can map to slaves
+ // with extra user based indexes or partioning by user. The additional metadata
+ // queries should use a regular slave since the lookup pattern is not all by user.
+ $this->mDbSecondary = wfGetDB( DB_SLAVE ); // any random slave
$this->mDb = wfGetDB( DB_SLAVE, 'contributions' );
}
$batch->add( $row->page_namespace, $row->page_title );
}
}
- $this->mParentLens = Revision::getParentLengths( $this->getDatabase(), $revIds );
+ $this->mParentLens = Revision::getParentLengths( $this->mDbSecondary, $revIds );
$batch->execute();
$this->mResult->seek( 0 );
}
'from' => $s->page_title,
'prefix' => $prefix,
'hideredirects' => $this->hideRedirects,
+ 'stripprefix' => $this->stripPrefix,
);
if ( $namespace || $prefix == '' ) {
/** The RevDel_List object, storing the list of items to be deleted/undeleted */
var $list;
+ /** Was the DB modified in this request */
+ protected $wasSaved = false;
+
/**
* UI labels for each type.
*/
# Show relevant lines from the deletion log
$deleteLogPage = new LogPage( 'delete' );
$output->addHTML( "<h2>" . $deleteLogPage->getName()->escaped() . "</h2>\n" );
- LogEventsList::showLogExtract( $output, 'delete',
- $this->targetObj, '', array( 'lim' => 25, 'conds' => $qc ) );
+ LogEventsList::showLogExtract(
+ $output,
+ 'delete',
+ $this->targetObj,
+ '', /* user */
+ array( 'lim' => 25, 'conds' => $qc, 'useMaster' => $this->wasSaved )
+ );
# Show relevant lines from the suppression log
if ( $user->isAllowed( 'suppressionlog' ) ) {
$suppressLogPage = new LogPage( 'suppress' );
$output->addHTML( "<h2>" . $suppressLogPage->getName()->escaped() . "</h2>\n" );
- LogEventsList::showLogExtract( $output, 'suppress',
- $this->targetObj, '', array( 'lim' => 25, 'conds' => $qc ) );
+ LogEventsList::showLogExtract(
+ $output,
+ 'suppress',
+ $this->targetObj,
+ '',
+ array( 'lim' => 25, 'conds' => $qc, 'useMaster' => $this->wasSaved )
+ );
}
}
protected function success() {
$this->getOutput()->setPageTitle( $this->msg( 'actioncomplete' ) );
$this->getOutput()->wrapWikiMsg( "<span class=\"success\">\n$1\n</span>", $this->typeLabels['success'] );
+ $this->wasSaved = true;
$this->list->reloadFromMaster();
$this->showForm();
}
$out .= Html::hidden( 'fulltext', 'Search' ) . "\n";
$out .= Xml::submitButton(
$this->msg( 'searchbutton' )->text(),
- array( 'class' => array( 'mw-ui-button', 'mw-ui-primary' ) )
+ array( 'class' => array( 'mw-ui-button', 'mw-ui-progressive' ) )
) . "\n";
return $out . $this->didYouMeanHtml;
}
$this->getMsg( $this->data['loggedin'] ? 'createacct-another-submit' : 'createacct-submit' ),
'submit',
array(
- 'class' => "mw-ui-button mw-ui-big mw-ui-block mw-ui-primary",
+ 'class' => "mw-ui-button mw-ui-big mw-ui-block mw-ui-constructive",
'id' => 'wpCreateaccount',
'tabindex' => $tabIndex++
)
echo Html::input( 'wpLoginAttempt', $this->getMsg( 'login' )->text(), 'submit', array(
'id' => 'wpLoginAttempt',
'tabindex' => '6',
- 'class' => 'mw-ui-button mw-ui-big mw-ui-block mw-ui-primary'
+ 'class' => 'mw-ui-button mw-ui-big mw-ui-block mw-ui-constructive'
) );
?>
</div>
</div>
<?php } else { ?>
<div id="mw-createaccount-cta">
- <h3 id="mw-userloginlink"><?php $this->msg( 'userlogin-noaccount' ); ?><a href="<?php $this->text( 'createOrLoginHref' ); ?>" id="mw-createaccount-join" tabindex="7" class="mw-ui-button mw-ui-constructive"><?php $this->msg( 'userlogin-joinproject' ); ?></a></h3>
+ <h3 id="mw-userloginlink"><?php $this->msg( 'userlogin-noaccount' ); ?><a href="<?php $this->text( 'createOrLoginHref' ); ?>" id="mw-createaccount-join" tabindex="7" class="mw-ui-button mw-ui-progressive"><?php $this->msg( 'userlogin-joinproject' ); ?></a></h3>
</div>
<?php } ?>
<?php } ?>
'us_key' => $key,
'us_orig_path' => $path,
'us_path' => $stashPath, // virtual URL
- 'us_props' => serialize( $fileProps ),
+ 'us_props' => $dbw->encodeBlob( serialize( $fileProps ) ),
'us_size' => $fileProps['size'],
'us_sha1' => $fileProps['sha1'],
'us_mime' => $fileProps['mime'],
/**
* A collection of static methods to play with arrays.
+ *
+ * @since 1.21
*/
class ArrayUtils {
/**
* Do a binary search, and return the index of the largest item that sorts
* less than or equal to the target value.
*
+ * @since 1.23
+ *
* @param array $valueCallback A function to call to get the value with
* a given array index.
- * @param $valueCount int The number of items accessible via $valueCallback,
+ * @param int $valueCount The number of items accessible via $valueCallback,
* indexed from 0 to $valueCount - 1
- * @param $comparisonCallback array A callback to compare two values, returning
+ * @param array $comparisonCallback A callback to compare two values, returning
* -1, 0 or 1 in the style of strcmp().
- * @param $target string The target value to find.
+ * @param string $target The target value to find.
*
* @return int|bool The item index of the lower bound, or false if the target value
* sorts before all items.
*
* Note: empty arrays are removed.
*
- * @param $array1 array The array to compare from
- * @param $array2 array An array to compare against
- * @param ... array More arrays to compare against
+ * @since 1.23
+ *
+ * @param array $array1 The array to compare from
+ * @param array $array2 An array to compare against
+ * @param array ... More arrays to compare against
* @return array An array containing all the values from array1
* that are not present in any of the other arrays.
*/
if ( file_exists( "$IP/LocalSettings.php" ) ) {
$this->mFiles[] = "$IP/LocalSettings.php";
}
- if ( file_exists( "$IP/AdminSettings.php" ) ) {
- $this->mFiles[] = "$IP/AdminSettings.php";
- }
$this->output( 'done.', 'listfiles' );
}
require $maintenance->loadSettings();
}
-if ( $maintenance->getDbType() === Maintenance::DB_ADMIN
- && is_readable( "$IP/AdminSettings.php" )
-) {
- require "$IP/AdminSettings.php";
-}
-
if ( $maintenance->getDbType() === Maintenance::DB_NONE ) {
if ( $wgLocalisationCacheConf['storeClass'] === false && ( $wgLocalisationCacheConf['store'] == 'db' || ( $wgLocalisationCacheConf['store'] == 'detect' && !$wgCacheDirectory ) ) ) {
$wgLocalisationCacheConf['storeClass'] = 'LCStoreNull';
}
$useReadline = function_exists( 'readline_add_history' )
- && Maintenance::posix_isatty( 0 /*STDIN*/ );
+ && Maintenance::posix_isatty( 0 /*STDIN*/ );
if ( $useReadline ) {
$historyFile = isset( $_ENV['HOME'] ) ?
readline_read_history( $historyFile );
}
+$e = null; // PHP exception
while ( ( $line = Maintenance::readconsole() ) !== false ) {
+ if ( $e && !preg_match( '/^(exit|die);?$/', $line ) ) {
+ // Internal state may be corrupted or fatals may occur later due
+ // to some object not being set. Don't drop out of eval in case
+ // lines were being pasted in (which would then get dumped to the shell).
+ // Instead, just absorb the remaning commands. Let "exit" through per DWIM.
+ echo "Exception was thrown before; please restart eval.php\n";
+ continue;
+ }
if ( $useReadline ) {
readline_add_history( $line );
readline_write_history( $historyFile );
}
- $val = eval( $line . ";" );
+ try {
+ $val = eval( $line . ";" );
+ } catch ( Exception $e ) {
+ echo "Caught exception " . get_class( $e ) .
+ ": {$e->getMessage()}\n" . $e->getTraceAsString() . "\n";
+ continue;
+ }
if ( wfIsHHVM() || is_null( $val ) ) {
echo "\n";
} elseif ( is_string( $val ) || is_numeric( $val ) ) {
us_key TEXT,
us_orig_path TEXT,
us_path TEXT,
+ us_props BYTEA,
us_source_type TEXT,
us_timestamp TIMESTAMPTZ,
us_status TEXT,
// Get the original values of some form elements
$( '#wpTextbox1, #wpSummary' ).each( function () {
$( this ).data( 'origtext', $( this ).val() );
- });
+ } );
var savedWindowOnBeforeUnload;
$( window )
.on( 'beforeunload.editwarning', function () {
* Hebrew (עברית) language functions
*/
-mediaWiki.language.convertGrammar = function( word, form ) {
+mediaWiki.language.convertGrammar = function ( word, form ) {
var grammarForms = mediaWiki.language.getData( 'he', 'grammarForms' );
if ( grammarForms && grammarForms[form] ) {
return grammarForms[form][word];
-webkit-transition: @string;
transition: @string;
}
+
+@-webkit-keyframes rotate {
+ from {
+ -webkit-transform:rotate(0deg);
+ }
+ to {
+ -webkit-transform:rotate(360deg);
+ }
+}
+
+@keyframes rotate {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+.rotation(@time) {
+ -webkit-animation-name: rotate;
+ -webkit-animation-duration: @time;
+ -webkit-animation-iteration-count: infinite;
+ -webkit-animation-timing-function: linear;
+ animation-name: rotate;
+ animation-duration: @time;
+ animation-iteration-count: infinite;
+ animation-timing-function: linear;
+}
margin-left: 0.4em;
}
.mw-search-results li {
- padding-bottom: 1em;
+ padding-bottom: 1.2em;
list-style: none;
list-style-image: none;
}
keyRight = 39,
$el;
- if( event.keyCode === keyLeft ) {
+ if ( event.keyCode === keyLeft ) {
$el = $( '#preftoc li.selected' ).prev().find( 'a' );
} else if ( event.keyCode === keyRight ) {
$el = $( '#preftoc li.selected' ).next().find( 'a' );
+@import "mediawiki.mixins";
@import "../../settings/typography";
@import "../../mixins/effects";
// Buttons
//
+// All buttons start with mw-ui-button class, modified by other classes.
+// It can be any element. Due to a lack of a CSS reset, the exact styling of
+// the button depends on what type of element is used.
+// There are two kinds of buttons, the default is a "Call to Action" with an obvious border
+// and there is a quiet kind without a border.
+//
// Styleguide 2.
@buttonBorderRadius: 3px;
+@transitionDuration: .1s;
+@transitionFunction: ease-in-out;
-// Button styling
-//
-// Basic button styling to be used on desktop skins. Can be any element.
-// Due to a lack of a CSS reset, the exact styling of the button depends on what type of element is used.
+// Neutral button styling
//
// Markup:
-// <div class="mw-ui-button">button.mw-ui-button</div>
+// <button class="mw-ui-button">.mw-ui-button</button>
+// <button class="mw-ui-button" disabled>.mw-ui-button</button>
//
// Styleguide 2.1.
.mw-ui-button {
// Container layout
display: inline-block;
- padding: 0.4em 1em 0.4em 1em;
+ padding: .5em 1em;
margin: 0;
// IE6/IE7 hack
zoom: 1;
// Container styling
- .buttonColors();
+ .button-colors(@colorWhite);
border-radius: @buttonBorderRadius;
// Ensure that buttons and inputs are nicely aligned when they have differing heights
// Content styling
text-align: center;
- text-decoration: none;
-
font-weight: bold;
+ white-space: nowrap;
+ text-shadow: 0 1px rgba(0, 0, 0, .1);
// Interaction styling
cursor: pointer;
- &:disabled,
- &.mw-ui-disabled {
+ &:disabled {
+ text-shadow: none;
cursor: default;
}
+ .transition(background @transitionDuration @transitionFunction, color @transitionDuration @transitionFunction, box-shadow @transitionDuration @transitionFunction;);
+
// Styling for specific button types
// -----------------------------------------
+
+ // Big buttons
+ //
+ // Not all buttons are equal. You can emphasise certain actions over others
+ // using the mw-ui-big class.
+ //
+ // Markup:
+ // <button class="mw-ui-button mw-ui-big">.mw-ui-button</button>
+ // <button class="mw-ui-button mw-ui-progressive mw-ui-big">.mw-ui-progressive</button>
+ // <button class="mw-ui-button mw-ui-constructive mw-ui-big">.mw-ui-constructive</button>
+ // <button class="mw-ui-button mw-ui-destructive mw-ui-big">.mw-ui-destructive</button>
+ //
+ // Styleguide 2.1.6.
&.mw-ui-big {
font-size: @baseFontSize * 1.3;
}
+ // Block buttons
+ //
+ // Some buttons might need to be stacked.
+ //
+ // Markup:
+ // <button class="mw-ui-button mw-ui-block">.mw-ui-button</button>
+ // <button class="mw-ui-button mw-ui-progressive mw-ui-block">.mw-ui-progressive</button>
+ // <button class="mw-ui-button mw-ui-constructive mw-ui-block">.mw-ui-constructive</button>
+ // <button class="mw-ui-button mw-ui-destructive mw-ui-block">.mw-ui-destructive</button>
+ //
+ // Styleguide 2.1.5.
&.mw-ui-block {
display: block;
width: 100%;
}
- // Primary buttons
+ // Progressive buttons
//
- // Do not use the mw-ui-primary class use mw-ui-constructive instead. For blue buttons
- // use mw-ui-progressive (coming soon)
+ // Use progressive buttons for actions which lead to a next step in the process.
+ // .mw-ui-primary is deprecated, kept for compatibility.
//
// Markup:
- // <button class="mw-ui-button mw-ui-primary">mw-ui-primary</button>
+ // <button class="mw-ui-button mw-ui-progressive">.mw-ui-progressive</button>
+ // <button class="mw-ui-button mw-ui-progressive" disabled>.mw-ui-progressive</button>
//
// Styleguide 2.1.1.
+ &.mw-ui-progressive,
&.mw-ui-primary {
- .buttonColors(@agoraBlue);
+ .button-colors(@colorProgressive);
+
+ &.mw-ui-quiet {
+ .button-colors-quiet(@colorProgressive);
+ }
}
// Constructive buttons
// e.g. save changes button
//
// Markup:
- // <button class="mw-ui-button mw-ui-constructive">mw-ui-constructive</button>
+ // <button class="mw-ui-button mw-ui-constructive">.mw-ui-constructive</button>
+ // <button class="mw-ui-button mw-ui-constructive" disabled>.mw-ui-constructive</button>
//
// Styleguide 2.1.2.
&.mw-ui-constructive {
- .buttonColors(@agoraGreen);
+ .button-colors(@colorConstructive);
+
+ &.mw-ui-quiet {
+ .button-colors-quiet(@colorConstructive);
+ }
}
// Destructive buttons
// This should not be used for cancel buttons.
//
// Markup:
- // <button class="mw-ui-button mw-ui-destructive">mw-ui-destructive</button>
+ // <button class="mw-ui-button mw-ui-destructive">.mw-ui-destructive</button>
+ // <button class="mw-ui-button mw-ui-destructive" disabled>.mw-ui-destructive</button>
//
// Styleguide 2.1.3.
&.mw-ui-destructive {
- .buttonColors(@agoraRed);
+ .button-colors(@colorDestructive);
+
+ &.mw-ui-quiet {
+ .button-colors-quiet(@colorDestructive);
+ }
+ }
+
+ // Quiet buttons
+ //
+ // Use quiet buttons when they are less important and alongisde other progressive/destructive/progressive buttons.
+ //
+ // Markup:
+ // <button class="mw-ui-button mw-ui-quiet">.mw-ui-button</button>
+ // <button class="mw-ui-button mw-ui-constructive mw-ui-quiet">.mw-ui-constructive</button>
+ // <button class="mw-ui-button mw-ui-constructive mw-ui-quiet" disabled>.mw-ui-constructive</button>
+ // <button class="mw-ui-button mw-ui-destructive mw-ui-quiet">.mw-ui-destructive</button>
+ // <button class="mw-ui-button mw-ui-destructive mw-ui-quiet" disabled>.mw-ui-destructive</button>
+ // <button class="mw-ui-button mw-ui-progressive mw-ui-quiet">.mw-ui-progressive</button>
+ // <button class="mw-ui-button mw-ui-progressive mw-ui-quiet" disabled>.mw-ui-progressive</button>
+ //
+ // Styleguide 2.1.4.
+ &.mw-ui-quiet {
+ background: transparent;
+ border: none;
+ text-shadow: none;
+ .button-colors-quiet(@colorGrayDark);
+
+ &:hover,
+ &:focus {
+ box-shadow: none;
+ }
+
+ &:active,
+ &:disabled {
+ background: transparent;
+ }
}
}
-// This overrides an underline declaration on a:hover and a:focus in commonElements.css, which the
-// class alone isn't specific enough to do
a.mw-ui-button {
text-decoration: none;
+
+ // This overrides an underline declaration on a:hover and a:focus in
+ // commonElements.css, which the class alone isn't specific enough to do.
+ &:hover,
+ &:focus {
+ text-decoration: none;
+ }
}
// Button groups
-/* Mixins for visual effects in CSS3 */
-
@import "../settings/colors";
-
-// ----------------------------------------------------------------------------
-// Gradients
-// ----------------------------------------------------------------------------
-.vertical-gradient(@startColor: lighten(@agoraGray, 95%), @endColor: @agoraGray, @startPos: 0, @endPos: 100%) {
- background-color: @endColor;
- background-image: -moz-linear-gradient( top, @startColor @startPos, @endColor @endPos ); // Firefox 3.6+
- background-image: -webkit-gradient( linear, left top, left bottom, color-stop( @startPos, @startColor ), color-stop( @endPos, @endColor ) ); // Safari 4+, Chrome 2+
- background-image: -webkit-linear-gradient( top, @startColor @startPos, @endColor @endPos ); // Safari 5.1+, Chrome 10+
- background-image: linear-gradient( @startColor @startPos, @endColor @endPos ); // Standard
-}
-
// ----------------------------------------------------------------------------
// Button styling
// ----------------------------------------------------------------------------
-.buttonColors(@baseColor: @agoraGray) {
- // Background color
- .vertical-gradient(lighten(@baseColor, 7.5%), @baseColor);
-
- border: 1px solid darken(@baseColor, 2%);
+.button-colors(@bgColor) {
+ background: @bgColor;
&:hover,
- &.mw-ui-hover {
- .vertical-gradient(lighten(@baseColor, 12.5%), lighten(@baseColor, 7.5%));
- text-decoration: none;
+ &:focus {
+ // The inner bottom bevel should match the active background color.
+ box-shadow: 0 1px rgba(0, 0, 0, 10%), inset 0 -3px rgba(0, 0, 0, 20%);
+ outline: none;
+ // remove outline in Firefox
+ &::-moz-focus-inner {
+ border-color: transparent;
+ }
}
- &:active,
- &.mw-ui-active {
- background-image: none;
- background-color: darken(@baseColor, 3%);
+ &:active {
+ // lessphp doesn't implement shade (https://github.com/leafo/lessphp/issues/528);
+ // it passes it through, then ResourceLoader drops it.
+ // background: shade(@bgColor, 20%);
+ background: mix(#000, @bgColor, 20%);
+ box-shadow: none;
}
+}
+
+.button-colors(@bgColor) when (lightness(@bgColor) >= 70%) {
+ color: @colorGrayDark;
+ border: 1px solid @colorGrayLight;
+
+ &:disabled {
+ color: @colorGrayLight;
- &:disabled,
- &.mw-ui-disabled {
- background-image: none;
- background-color: @baseColor;
- opacity: 0.5;
+ // make sure disabled buttons don't have hover and active states
+ &:hover,
+ &:active {
+ background: @bgColor;
+ box-shadow: none;
+ }
}
}
-.buttonColors(@baseColor: @agoraGray) when (lightness(@baseColor) >= 50%) {
- color: #000;
+.button-colors(@bgColor) when (lightness(@bgColor) < 70%) {
+ color: @colorWhite;
+ border: none;
+
+ &:disabled {
+ background: @colorGrayLight;
+
+ // make sure disabled buttons don't have hover and active states
+ &:hover,
+ &:active {
+ box-shadow: none;
+ }
+ }
}
-.buttonColors(@baseColor: @agoraGray) when (lightness(@baseColor) < 50%) {
- color: #fff;
+.button-colors-quiet(@textColor) {
+ // Quiet buttons all start gray, and reveal
+ // constructive/progressive/destructive color on hover and active.
+ color: @colorGrayDark;
+
+ &:hover,
+ &:focus {
+ // lessphp doesn't implement tint, see above
+ // color: tint(@textColor, 20%);
+ color: mix(#fff, @textColor, 20%);
+ }
+
+ &:active {
+ // lessphp doesn't implement shade, see above
+ // color: shade(@textColor, 20%);
+ color: mix(#000, @textColor, 20%);
+ }
+
+ &:disabled {
+ color: @colorGrayLight;
+ }
}
// For Vector, that should be layered on top with vector-type
.agora-field-styling() {
- border: 1px solid @agoraGray;
+ border: 1px solid @colorGrayLight;
&:focus {
// Styling focus of native checkboxes etc on Mac is almost impossible.
outline: 0; // Removes OS field focus
}
- box-shadow: @agoraBlueShadow 0px 0px 5px;
+ box-shadow: @colorProgressiveShadow 0px 0px 5px;
- border-color: @agoraBlueShadow;
+ border-color: @colorProgressiveShadow;
}
- color: @agoraTextColor;
+ color: @colorText;
padding: 0.35em 0.5em 0.35em 0.5em;
// Ensure that buttons and inputs are nicely aligned when they have differing heights
.agora-label-styling() {
//font-weight: bold;
font-size: 0.9em;
- color: darken(@agoraGray, 50%);
+ color: darken(@colorGrayLight, 50%);
* {
font-weight: normal;
height: auto;
margin: 0 0.1em 0em 0;
padding: 0;
- border: 1px solid @agoraGray;
+ border: 1px solid @colorGrayLight;
cursor: pointer;
}
}
-// Grays
-// -----------------------------------------
-@agoraGray: #c9c9c9;
-@agoraTextColor: #252525;
-
-// Blues
-// -----------------------------------------
-@agoraBlue: #3366bb;
-@agoraBlueShadow: #4091ed;
-
-// Greens
-// -----------------------------------------
-@agoraGreen: #27aa65;
-
-// Reds
-// -----------------------------------------
-@agoraRed: #cc0000;
+@colorWhite: #fff;
+@colorGrayLight: #ccc;
+@colorGrayDark: #898989;
+@colorText: #252525;
+@colorProgressive: #347bff;
+// FIXME: remove @colorProgressiveShadow (shadows should be generated
+// in LESS by dimming the original colors)
+@colorProgressiveShadow: #4091ed;
+@colorConstructive: #00af89;
+@colorDestructive: #d11d13;
@baseFontSize: 1em;
@baseLineHeight: 1.4 * @baseFontSize;
-@baseFontColor: @agoraTextColor;
+@baseFontColor: @colorText;
@smallFontSize: 0.75em;
// try to invoke it.
console.table.call( console, data );
return;
- } catch (e) {}
+ } catch ( e ) {}
try {
console.log( $.toJSON( data, null, 2 ) );
return;
- } catch (e) {}
+ } catch ( e ) {}
mw.log( data );
},
try {
css = module.style.css.join();
- } catch (e) { return; } // skip
+ } catch ( e ) { return; } // skip
stats = inspect.auditSelectors( css );
modules.push( {
try {
raw = localStorage.getItem( mw.loader.store.getStoreKey() );
stats.totalSize = humanSize( $.byteLength( raw ) );
- } catch (e) {}
+ } catch ( e ) {}
}
return [stats];
}
* the current selector. Bindings to passed-in jquery elements are preserved. Functions become click handlers for [$1 linktext] links.
* e.g.
* $.fn.msg = mediaWiki.parser.getJqueryPlugin( options );
- * var userlink = $( '<a>' ).click( function () { alert( "hello!!") } );
+ * var userlink = $( '<a>' ).click( function () { alert( "hello!!" ) } );
* $( 'p#headline' ).msg( 'hello-user', userlink );
*
* @param {Array} parser options
mw.loader.work();
}
- function sortQuery(o) {
+ function sortQuery( o ) {
var sorted = {}, key, a = [];
for ( key in o ) {
if ( hasOwn.call( o, key ) ) {
mw.config.get( 'skin' ),
mw.config.get( 'wgResourceLoaderStorageVersion' ),
mw.config.get( 'wgUserLanguage' )
- ].join(':');
+ ].join( ':' );
},
/**
mw.loader.store.items = data.items;
return;
}
- } catch (e) {}
+ } catch ( e ) {}
if ( raw === undefined ) {
// localStorage failed; disable store
return;
}
- mw.loader.store.items[key] = 'mw.loader.implement(' + args.join(',') + ');';
+ mw.loader.store.items[key] = 'mw.loader.implement(' + args.join( ',' ) + ');';
mw.loader.store.update();
},
$form = context.config.$region.closest( 'form' );
formAction = $form.attr( 'action' );
- baseHref = formAction + ( formAction.match(/\?/) ? '&' : '?' );
+ baseHref = formAction + ( formAction.match( /\?/ ) ? '&' : '?' );
linkParams = {};
$.each( $form.serializeArray(), function ( idx, obj ) {
// Generic selector for skins with multiple searchboxes (used by CologneBlue)
'.mw-searchInput'
];
- $( searchboxesSelectors.join(', ') )
+ $( searchboxesSelectors.join( ', ' ) )
.suggestions( {
fetch: function ( query ) {
var $el;
margin-top: -0.8em !ie;
height: 0;
overflow: hidden;
- .background-image('images/watch-icons.png');
+ background-position: 5px 60%;
}
#ca-unwatch.icon a {
- background-position: -43px 60%;
+ .background-image-svg('images/unwatch-icon.svg', 'images/unwatch-icon.png');
}
#ca-watch.icon a {
- background-position: 5px 60%;
+ .background-image-svg('images/watch-icon.svg', 'images/watch-icon.png');
}
#ca-unwatch.icon a:hover,
#ca-unwatch.icon a:focus {
- background-position: -67px 60%;
+ .background-image-svg('images/unwatch-icon-hl.svg', 'images/unwatch-icon-hl.png');
}
#ca-watch.icon a:hover,
#ca-watch.icon a:focus {
- background-position: -19px 60%;
+ .background-image-svg('images/watch-icon-hl.svg', 'images/watch-icon-hl.png');
}
#ca-unwatch.icon a.loading,
#ca-watch.icon a.loading {
- .background-image('images/watch-icon-loading.gif');
- background-position: 5px 60%;
+ .background-image-svg('images/watch-icon-loading.svg', 'images/watch-icon-loading.png');
+ .rotation(700ms);
+ background-position: 50% 60%;
+ -webkit-transform-origin: 50% 57%;
+ transform-origin: 50% 57%;
}
#ca-unwatch.icon a span,
#ca-watch.icon a span {
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="watch-icon-hl.svg"
+ inkscape:export-filename="/home/m4tx/Pulpit/LOCAL/watch-icon-hl.png"
+ inkscape:export-xdpi="87.436836"
+ inkscape:export-ydpi="87.436836">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3788">
+ <stop
+ style="stop-color:#c2edff;stop-opacity:1;"
+ offset="0"
+ id="stop3790" />
+ <stop
+ id="stop3796"
+ offset="0.5"
+ style="stop-color:#68bdff;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop3792" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3788"
+ id="linearGradient3804"
+ x1="13.470111"
+ y1="14.363379"
+ x2="4.596477"
+ y2="3.3969929"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3788"
+ id="linearGradient3808"
+ gradientUnits="userSpaceOnUse"
+ x1="13.470111"
+ y1="14.363379"
+ x2="4.596477"
+ y2="3.3969929" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="8"
+ inkscape:cx="-3.451911"
+ inkscape:cy="5.714676"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1920"
+ inkscape:window-height="1041"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Mateusz "m4tx" Maćkowski</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-693.14288,-698.64789)">
+ <path
+ inkscape:transform-center-y="-0.70705002"
+ transform="matrix(0.86225302,0,0,0.86225302,694.06156,700.58832)"
+ d="M 8.3337586,-0.92098331 10.85748,4.1926362 16.500695,5.0126434 12.417226,8.9930409 13.381202,14.613453 8.3337584,11.959854 3.286314,14.613452 4.2502902,8.9930409 0.16682217,5.012643 5.8100362,4.1926362 z"
+ inkscape:randomized="0"
+ inkscape:rounded="0"
+ inkscape:flatsided="false"
+ sodipodi:arg2="-0.9424778"
+ sodipodi:arg1="-1.5707963"
+ sodipodi:r2="4.2936125"
+ sodipodi:r1="8.587225"
+ sodipodi:cy="7.6662416"
+ sodipodi:cx="8.3337584"
+ sodipodi:sides="5"
+ id="path3768"
+ style="fill:url(#linearGradient3804);fill-opacity:1;stroke:#c8b250;stroke-width:1.15975237000000009;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ sodipodi:type="star" />
+ </g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="watch-icon-fav.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3788">
+ <stop
+ style="stop-color:#c2edff;stop-opacity:1;"
+ offset="0"
+ id="stop3790" />
+ <stop
+ id="stop3796"
+ offset="0.5"
+ style="stop-color:#68bdff;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop3792" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3788"
+ id="linearGradient3804"
+ x1="13.470111"
+ y1="14.363379"
+ x2="4.596477"
+ y2="3.3969929"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3788"
+ id="linearGradient3808"
+ gradientUnits="userSpaceOnUse"
+ x1="13.470111"
+ y1="14.363379"
+ x2="4.596477"
+ y2="3.3969929" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="8"
+ inkscape:cx="-6.951911"
+ inkscape:cy="5.714676"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1920"
+ inkscape:window-height="1014"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Mateusz "m4tx" Maćkowski</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-693.14288,-698.64789)">
+ <path
+ inkscape:transform-center-y="-0.70705002"
+ transform="matrix(0.86225302,0,0,0.86225302,694.06156,700.58832)"
+ d="M 8.3337586,-0.92098331 10.85748,4.1926362 16.500695,5.0126434 12.417226,8.9930409 13.381202,14.613453 8.3337584,11.959854 3.286314,14.613452 4.2502902,8.9930409 0.16682217,5.012643 5.8100362,4.1926362 z"
+ inkscape:randomized="0"
+ inkscape:rounded="0"
+ inkscape:flatsided="false"
+ sodipodi:arg2="-0.9424778"
+ sodipodi:arg1="-1.5707963"
+ sodipodi:r2="4.2936125"
+ sodipodi:r1="8.587225"
+ sodipodi:cy="7.6662416"
+ sodipodi:cx="8.3337584"
+ sodipodi:sides="5"
+ id="path3768"
+ style="fill:url(#linearGradient3804);fill-opacity:1;stroke:#7cb5d1;stroke-width:1.15975237;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ sodipodi:type="star" />
+ </g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="watch-icon-hl.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3788">
+ <stop
+ style="stop-color:#c2edff;stop-opacity:1;"
+ offset="0"
+ id="stop3790" />
+ <stop
+ id="stop3796"
+ offset="0.5"
+ style="stop-color:#68bdff;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop3792" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3788"
+ id="linearGradient3804"
+ x1="13.470111"
+ y1="14.363379"
+ x2="4.596477"
+ y2="3.3969929"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3788"
+ id="linearGradient3808"
+ gradientUnits="userSpaceOnUse"
+ x1="13.470111"
+ y1="14.363379"
+ x2="4.596477"
+ y2="3.3969929" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="8"
+ inkscape:cx="-6.97632"
+ inkscape:cy="6.2476517"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1920"
+ inkscape:window-height="1014"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Mateusz "m4tx" Maćkowski</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-693.14288,-698.64789)">
+ <path
+ sodipodi:type="star"
+ style="fill:#ffffff;fill-opacity:1;stroke:#c8b250;stroke-width:1.15975237;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path3770"
+ sodipodi:sides="5"
+ sodipodi:cx="8.3337584"
+ sodipodi:cy="7.6662416"
+ sodipodi:r1="8.587225"
+ sodipodi:r2="4.2936125"
+ sodipodi:arg1="-1.5707963"
+ sodipodi:arg2="-0.9424778"
+ inkscape:flatsided="false"
+ inkscape:rounded="0"
+ inkscape:randomized="0"
+ d="M 8.3337586,-0.92098331 10.85748,4.1926362 16.500695,5.0126434 12.417226,8.9930409 13.381202,14.613453 8.3337584,11.959854 3.286314,14.613452 4.2502902,8.9930409 0.16682217,5.012643 5.8100362,4.1926362 z"
+ transform="matrix(0.86225302,0,0,0.86225302,694.06156,700.58832)"
+ inkscape:transform-center-y="-0.70705002" />
+ </g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="watch-icon-loading.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3788">
+ <stop
+ style="stop-color:#c2edff;stop-opacity:1;"
+ offset="0"
+ id="stop3790" />
+ <stop
+ id="stop3796"
+ offset="0.5"
+ style="stop-color:#68bdff;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop3792" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3788"
+ id="linearGradient3804"
+ x1="13.470111"
+ y1="14.363379"
+ x2="4.596477"
+ y2="3.3969929"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3788"
+ id="linearGradient3808"
+ gradientUnits="userSpaceOnUse"
+ x1="13.470111"
+ y1="14.363379"
+ x2="4.596477"
+ y2="3.3969929" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.627417"
+ inkscape:cx="7.2850048"
+ inkscape:cy="6.4582896"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1920"
+ inkscape:window-height="1014"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Mateusz "m4tx" Maćkowski</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-693.14288,-698.64789)">
+ <path
+ sodipodi:type="star"
+ style="fill:#ffffff;fill-opacity:1;stroke:#d1d1d1;stroke-width:1.15975237;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path2998"
+ sodipodi:sides="5"
+ sodipodi:cx="8.3337584"
+ sodipodi:cy="7.6662416"
+ sodipodi:r1="8.587225"
+ sodipodi:r2="4.2936125"
+ sodipodi:arg1="-1.5707963"
+ sodipodi:arg2="-0.9424778"
+ inkscape:flatsided="false"
+ inkscape:rounded="0"
+ inkscape:randomized="0"
+ d="M 8.3337586,-0.92098331 10.85748,4.1926362 16.500695,5.0126434 12.417226,8.9930409 13.381202,14.613453 8.3337584,11.959854 3.286314,14.613452 4.2502902,8.9930409 0.16682217,5.012643 5.8100362,4.1926362 z"
+ transform="matrix(0.86225302,0,0,0.86225302,694.06156,700.58832)"
+ inkscape:transform-center-y="-0.70705002" />
+ </g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="watch-icon.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3788">
+ <stop
+ style="stop-color:#c2edff;stop-opacity:1;"
+ offset="0"
+ id="stop3790" />
+ <stop
+ id="stop3796"
+ offset="0.5"
+ style="stop-color:#68bdff;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop3792" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3788"
+ id="linearGradient3804"
+ x1="13.470111"
+ y1="14.363379"
+ x2="4.596477"
+ y2="3.3969929"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3788"
+ id="linearGradient3808"
+ gradientUnits="userSpaceOnUse"
+ x1="13.470111"
+ y1="14.363379"
+ x2="4.596477"
+ y2="3.3969929" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="8"
+ inkscape:cx="17.836203"
+ inkscape:cy="7.206728"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1920"
+ inkscape:window-height="1014"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Mateusz "m4tx" Maćkowski</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-693.14288,-698.64789)">
+ <path
+ sodipodi:type="star"
+ style="fill:#ffffff;fill-opacity:1;stroke:#7cb5d1;stroke-width:1.15975237;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path2998"
+ sodipodi:sides="5"
+ sodipodi:cx="8.3337584"
+ sodipodi:cy="7.6662416"
+ sodipodi:r1="8.587225"
+ sodipodi:r2="4.2936125"
+ sodipodi:arg1="-1.5707963"
+ sodipodi:arg2="-0.9424778"
+ inkscape:flatsided="false"
+ inkscape:rounded="0"
+ inkscape:randomized="0"
+ d="M 8.3337586,-0.92098331 10.85748,4.1926362 16.500695,5.0126434 12.417226,8.9930409 13.381202,14.613453 8.3337584,11.959854 3.286314,14.613452 4.2502902,8.9930409 0.16682217,5.012643 5.8100362,4.1926362 z"
+ transform="matrix(0.86225302,0,0,0.86225302,694.06156,700.58832)"
+ inkscape:transform-center-y="-0.70705002" />
+ </g>
+</svg>