rebase from live enviornment

This commit is contained in:
Rachit Bhargava
2024-01-09 22:14:20 -05:00
parent ff0b49a046
commit 3a22fcaa4a
15968 changed files with 2344674 additions and 45234 deletions

View File

@@ -0,0 +1,16 @@
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} \.php$
RewriteRule .* - [F,L,NC]
</IfModule>
<IfModule !mod_rewrite.c>
<FilesMatch "\.php$">
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
</FilesMatch>
</IfModule>

View File

@@ -0,0 +1,176 @@
<?php
/**
* Diff
*
* A comprehensive library for generating differences between two strings
* in multiple formats (unified, side by side HTML etc)
*
* PHP version 5
*
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the Chris Boulton nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package Diff
* @author Chris Boulton <chris.boulton@interspire.com>
* @copyright (c) 2009 Chris Boulton
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
* @version 1.1
* @link http://github.com/chrisboulton/php-diff
*/
class Diff
{
/**
* @var array The "old" sequence to use as the basis for the comparison.
*/
private $a = null;
/**
* @var array The "new" sequence to generate the changes for.
*/
private $b = null;
/**
* @var array Array containing the generated opcodes for the differences between the two items.
*/
private $groupedCodes = null;
/**
* @var array Associative array of the default options available for the diff class and their default value.
*/
private $defaultOptions = array(
'context' => 3,
'ignoreNewLines' => false,
'ignoreWhitespace' => false,
'ignoreCase' => false
);
/**
* @var array Array of the options that have been applied for generating the diff.
*/
private $options = array();
/**
* The constructor.
*
* @param array $a Array containing the lines of the first string to compare.
* @param array $b Array containing the lines for the second string to compare.
*/
public function __construct($a, $b, $options=array())
{
$this->a = $a;
$this->b = $b;
$this->options = array_merge($this->defaultOptions, $options);
}
/**
* Render a diff using the supplied rendering class and return it.
*
* @param object $renderer An instance of the rendering object to use for generating the diff.
* @return mixed The generated diff. Exact return value depends on the rendered.
*/
public function render(Diff_Renderer_Abstract $renderer)
{
$renderer->diff = $this;
return $renderer->render();
}
/**
* Get a range of lines from $start to $end from the first comparison string
* and return them as an array. If no values are supplied, the entire string
* is returned. It's also possible to specify just one line to return only
* that line.
*
* @param int $start The starting number.
* @param int $end The ending number. If not supplied, only the item in $start will be returned.
* @return array Array of all of the lines between the specified range.
*/
public function getA($start=0, $end=null)
{
if($start == 0 && $end === null) {
return $this->a;
}
if($end === null) {
$length = 1;
}
else {
$length = $end - $start;
}
return array_slice($this->a, $start, $length);
}
/**
* Get a range of lines from $start to $end from the second comparison string
* and return them as an array. If no values are supplied, the entire string
* is returned. It's also possible to specify just one line to return only
* that line.
*
* @param int $start The starting number.
* @param int $end The ending number. If not supplied, only the item in $start will be returned.
* @return array Array of all of the lines between the specified range.
*/
public function getB($start=0, $end=null)
{
if($start == 0 && $end === null) {
return $this->b;
}
if($end === null) {
$length = 1;
}
else {
$length = $end - $start;
}
return array_slice($this->b, $start, $length);
}
/**
* Generate a list of the compiled and grouped opcodes for the differences between the
* two strings. Generally called by the renderer, this class instantiates the sequence
* matcher and performs the actual diff generation and return an array of the opcodes
* for it. Once generated, the results are cached in the diff class instance.
*
* @return array Array of the grouped opcodes for the generated diff.
*/
public function getGroupedOpcodes()
{
if(!is_null($this->groupedCodes)) {
return $this->groupedCodes;
}
require_once(dirname(__FILE__) . '/Diff/SequenceMatcher.php');
$sequenceMatcher = new Diff_SequenceMatcher($this->a, $this->b, null, $this->options);
$this->groupedCodes = $sequenceMatcher->getGroupedOpcodes();
return $this->groupedCodes;
}
}

View File

@@ -0,0 +1,82 @@
<?php
/**
* Abstract class for diff renderers in PHP DiffLib.
*
* PHP version 5
*
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the Chris Boulton nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package DiffLib
* @author Chris Boulton <chris.boulton@interspire.com>
* @copyright (c) 2009 Chris Boulton
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
* @version 1.1
* @link http://github.com/chrisboulton/php-diff
*/
abstract class Diff_Renderer_Abstract
{
/**
* @var object Instance of the diff class that this renderer is generating the rendered diff for.
*/
public $diff;
/**
* @var array Array of the default options that apply to this renderer.
*/
protected $defaultOptions = array();
/**
* @var array Array containing the user applied and merged default options for the renderer.
*/
protected $options = array();
/**
* The constructor. Instantiates the rendering engine and if options are passed,
* sets the options for the renderer.
*
* @param array $options Optionally, an array of the options for the renderer.
*/
public function __construct(array $options = array())
{
$this->setOptions($options);
}
/**
* Set the options of the renderer to those supplied in the passed in array.
* Options are merged with the default to ensure that there aren't any missing
* options.
*
* @param array $options Array of options to set.
*/
public function setOptions(array $options)
{
$this->options = array_merge($this->defaultOptions, $options);
}
}

View File

@@ -0,0 +1,236 @@
<?php
/**
* Base renderer for rendering HTML based diffs for PHP DiffLib.
*
* PHP version 5
*
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the Chris Boulton nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package DiffLib
* @author Chris Boulton <chris.boulton@interspire.com>
* @copyright (c) 2009 Chris Boulton
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
* @version 1.1
* @link http://github.com/chrisboulton/php-diff
*/
require_once(dirname(__FILE__) . '/../Abstract.php');
class Diff_Renderer_Html_Array extends Diff_Renderer_Abstract
{
/**
* @var array Array of the default options that apply to this renderer.
*/
protected $defaultOptions = array(
'tabSize' => 4
);
/**
* Render and return an array structure suitable for generating HTML
* based differences. Generally called by subclasses that generate a
* HTML based diff and return an array of the changes to show in the diff.
*
* @return array An array of the generated chances, suitable for presentation in HTML.
*/
public function render()
{
// As we'll be modifying a & b to include our change markers,
// we need to get the contents and store them here. That way
// we're not going to destroy the original data
$a = $this->diff->getA();
$b = $this->diff->getB();
$changes = array();
$opCodes = $this->diff->getGroupedOpcodes();
foreach($opCodes as $group) {
$blocks = array();
$lastTag = null;
$lastBlock = 0;
foreach($group as $code) {
list($tag, $i1, $i2, $j1, $j2) = $code;
if($tag == 'replace' && $i2 - $i1 == $j2 - $j1) {
for($i = 0; $i < ($i2 - $i1); ++$i) {
$fromLine = $a[$i1 + $i];
$toLine = $b[$j1 + $i];
list($start, $end) = $this->getChangeExtent($fromLine, $toLine);
if($start != 0 || $end != 0) {
$last = $end + strlen($fromLine);
$fromLine = substr_replace($fromLine, "\0", $start, 0);
$fromLine = substr_replace($fromLine, "\1", $last + 1, 0);
$last = $end + strlen($toLine);
$toLine = substr_replace($toLine, "\0", $start, 0);
$toLine = substr_replace($toLine, "\1", $last + 1, 0);
$a[$i1 + $i] = $fromLine;
$b[$j1 + $i] = $toLine;
}
}
}
if($tag != $lastTag) {
$blocks[] = array(
'tag' => $tag,
'base' => array(
'offset' => $i1,
'lines' => array()
),
'changed' => array(
'offset' => $j1,
'lines' => array()
)
);
$lastBlock = count($blocks)-1;
}
$lastTag = $tag;
if($tag == 'equal') {
$lines = array_slice($a, $i1, ($i2 - $i1));
$blocks[$lastBlock]['base']['lines'] += $this->formatLines($lines);
$lines = array_slice($b, $j1, ($j2 - $j1));
$blocks[$lastBlock]['changed']['lines'] += $this->formatLines($lines);
}
else {
if($tag == 'replace' || $tag == 'delete') {
$lines = array_slice($a, $i1, ($i2 - $i1));
$lines = $this->formatLines($lines);
$lines = str_replace(array("\0", "\1"), array('<del>', '</del>'), $lines);
$blocks[$lastBlock]['base']['lines'] += $lines;
}
if($tag == 'replace' || $tag == 'insert') {
$lines = array_slice($b, $j1, ($j2 - $j1));
$lines = $this->formatLines($lines);
$lines = str_replace(array("\0", "\1"), array('<ins>', '</ins>'), $lines);
$blocks[$lastBlock]['changed']['lines'] += $lines;
}
}
}
$changes[] = $blocks;
}
return $changes;
}
/**
* Given two strings, determine where the changes in the two strings
* begin, and where the changes in the two strings end.
*
* @param string $fromLine The first string.
* @param string $toLine The second string.
* @return array Array containing the starting position (0 by default) and the ending position (-1 by default)
*/
private function getChangeExtent($fromLine, $toLine)
{
$start = 0;
$limit = min(strlen($fromLine), strlen($toLine));
while($start < $limit && $fromLine[$start] == $toLine[$start]) {
++$start;
}
$end = -1;
$limit = $limit - $start;
while(-$end <= $limit && substr($fromLine, $end, 1) == substr($toLine, $end, 1)) {
--$end;
}
return array(
$start,
$end + 1
);
}
/**
* Format a series of lines suitable for output in a HTML rendered diff.
* This involves replacing tab characters with spaces, making the HTML safe
* for output, ensuring that double spaces are replaced with &nbsp; etc.
*
* @param array $lines Array of lines to format.
* @return array Array of the formatted lines.
*/
private function formatLines($lines)
{
$lines = array_map(array($this, 'ExpandTabs'), $lines);
$lines = array_map(array($this, 'HtmlSafe'), $lines);
foreach($lines as &$line) {
$line = preg_replace_callback('# ( +)|^ #', array($this, 'fixSpacesCallback'), $line);
}
return $lines;
}
/**
* Using a callback here instead of the /e modifier in preg_replace (now deprecated).
*
* @param $matches
* @return string
*/
private function fixSpacesCallback($matches)
{
$spaces = (isset($matches[1]) ? $matches[1] : '');
return $this->fixSpaces($spaces);
}
/**
* Replace a string containing spaces with a HTML representation using &nbsp;.
*
* @param string $spaces The string of spaces.
* @return string The HTML representation of the string.
*/
function fixSpaces($spaces='')
{
$count = strlen($spaces);
if($count == 0) {
return '';
}
$div = floor($count / 2);
$mod = $count % 2;
return str_repeat('&nbsp; ', $div).str_repeat('&nbsp;', $mod);
}
/**
* Replace tabs in a single line with a number of spaces as defined by the tabSize option.
*
* @param string $line The containing tabs to convert.
* @return string The line with the tabs converted to spaces.
*/
private function expandTabs($line)
{
return str_replace("\t", str_repeat(' ', $this->options['tabSize']), $line);
}
/**
* Make a string containing HTML safe for output on a page.
*
* @param string $string The string.
* @return string The string with the HTML characters replaced by entities.
*/
private function htmlSafe($string)
{
return @htmlspecialchars($string, ENT_NOQUOTES, 'UTF-8');
}
}

View File

@@ -0,0 +1,163 @@
<?php
/**
* Side by Side HTML diff generator for PHP DiffLib.
*
* PHP version 5
*
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the Chris Boulton nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package DiffLib
* @author Chris Boulton <chris.boulton@interspire.com>
* @copyright (c) 2009 Chris Boulton
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
* @version 1.1
* @link http://github.com/chrisboulton/php-diff
*/
require_once(dirname(__FILE__) . '/Array.php');
class Diff_Renderer_Html_SideBySide extends Diff_Renderer_Html_Array
{
/**
* Render a and return diff with changes between the two sequences
* displayed side by side.
*
* @return string The generated side by side diff.
*/
public function render()
{
$changes = parent::render();
$html = '';
if(empty($changes)) {
return $html;
}
$html .= '<table class="Differences DifferencesSideBySide">';
$html .= '<thead>';
$html .= '<tr>';
$html .= '<th colspan="2" width="50%">The Original Version of the file</th>';
$html .= '<th colspan="2" width="50%">The Modified Version on your WordPress system</th>';
$html .= '</tr>';
$html .= '</thead>';
foreach($changes as $i => $blocks) {
if($i > 0) {
$html .= '<tbody class="Skipped">';
$html .= '<th>&hellip;</th><td>&nbsp;</td>';
$html .= '<th>&hellip;</th><td>&nbsp;</td>';
$html .= '</tbody>';
}
foreach($blocks as $change) {
$html .= '<tbody class="Change'.ucfirst($change['tag']).'">';
// Equal changes should be shown on both sides of the diff
if($change['tag'] == 'equal') {
foreach($change['base']['lines'] as $no => $line) {
$fromLine = $change['base']['offset'] + $no + 1;
$toLine = $change['changed']['offset'] + $no + 1;
$html .= '<tr>';
$html .= '<th>'.$fromLine.'</th>';
$html .= '<td class="Left"><span>'.$line.'</span>&nbsp;</span></td>';
$html .= '<th>'.$toLine.'</th>';
$html .= '<td class="Right"><span>'.$line.'</span>&nbsp;</span></td>';
$html .= '</tr>';
}
}
// Added lines only on the right side
else if($change['tag'] == 'insert') {
foreach($change['changed']['lines'] as $no => $line) {
$toLine = $change['changed']['offset'] + $no + 1;
$html .= '<tr>';
$html .= '<th>&nbsp;</th>';
$html .= '<td class="Left">&nbsp;</td>';
$html .= '<th>'.$toLine.'</th>';
$html .= '<td class="Right"><ins>'.$line.'</ins>&nbsp;</td>';
$html .= '</tr>';
}
}
// Show deleted lines only on the left side
else if($change['tag'] == 'delete') {
foreach($change['base']['lines'] as $no => $line) {
$fromLine = $change['base']['offset'] + $no + 1;
$html .= '<tr>';
$html .= '<th>'.$fromLine.'</th>';
$html .= '<td class="Left"><del>'.$line.'</del>&nbsp;</td>';
$html .= '<th>&nbsp;</th>';
$html .= '<td class="Right">&nbsp;</td>';
$html .= '</tr>';
}
}
// Show modified lines on both sides
else if($change['tag'] == 'replace') {
if(count($change['base']['lines']) >= count($change['changed']['lines'])) {
foreach($change['base']['lines'] as $no => $line) {
$fromLine = $change['base']['offset'] + $no + 1;
$html .= '<tr>';
$html .= '<th>'.$fromLine.'</th>';
$html .= '<td class="Left"><span>'.$line.'</span>&nbsp;</td>';
if(!isset($change['changed']['lines'][$no])) {
$toLine = '&nbsp;';
$changedLine = '&nbsp;';
}
else {
$toLine = $change['base']['offset'] + $no + 1;
$changedLine = '<span>'.$change['changed']['lines'][$no].'</span>';
}
$html .= '<th>'.$toLine.'</th>';
$html .= '<td class="Right">'.$changedLine.'</td>';
$html .= '</tr>';
}
}
else {
foreach($change['changed']['lines'] as $no => $changedLine) {
if(!isset($change['base']['lines'][$no])) {
$fromLine = '&nbsp;';
$line = '&nbsp;';
}
else {
$fromLine = $change['base']['offset'] + $no + 1;
$line = '<span>'.$change['base']['lines'][$no].'</span>';
}
$html .= '<tr>';
$html .= '<th>'.$fromLine.'</th>';
$html .= '<td class="Left"><span>'.$line.'</span>&nbsp;</td>';
$toLine = $change['changed']['offset'] + $no + 1;
$html .= '<th>'.$toLine.'</th>';
$html .= '<td class="Right">'.$changedLine.'</td>';
$html .= '</tr>';
}
}
}
$html .= '</tbody>';
}
}
$html .= '</table>';
return $html;
}
}

View File

@@ -0,0 +1,692 @@
<?php
/**
* Sequence matcher for Diff
*
* PHP version 5
*
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the Chris Boulton nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package Diff
* @author Chris Boulton <chris.boulton@interspire.com>
* @copyright (c) 2009 Chris Boulton
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
* @version 1.1
* @link http://github.com/chrisboulton/php-diff
*/
class Diff_SequenceMatcher
{
/**
* @var string|array Either a string or an array containing a callback function to determine if a line is "junk" or not.
*/
private $junkCallback = null;
/**
* @var array The first sequence to compare against.
*/
private $a = null;
/**
* @var array The second sequence.
*/
private $b = null;
/**
* @var array Array of characters that are considered junk from the second sequence. Characters are the array key.
*/
private $junkDict = array();
/**
* @var array Array of indices that do not contain junk elements.
*/
private $b2j = array();
private $options = array();
private $defaultOptions = array(
'ignoreNewLines' => false,
'ignoreWhitespace' => false,
'ignoreCase' => false
);
/**
* The constructor. With the sequences being passed, they'll be set for the
* sequence matcher and it will perform a basic cleanup & calculate junk
* elements.
*
* @param string|array $a A string or array containing the lines to compare against.
* @param string|array $b A string or array containing the lines to compare.
* @param string|array $junkCallback Either an array or string that references a callback function (if there is one) to determine 'junk' characters.
*/
public function __construct($a, $b, $junkCallback=null, $options=array())
{
$this->a = null;
$this->b = null;
$this->junkCallback = $junkCallback;
$this->setOptions($options);
$this->setSequences($a, $b);
}
public function setOptions($options)
{
$this->options = array_merge($this->defaultOptions, $options);
}
/**
* Set the first and second sequences to use with the sequence matcher.
*
* @param string|array $a A string or array containing the lines to compare against.
* @param string|array $b A string or array containing the lines to compare.
*/
public function setSequences($a, $b)
{
$this->setSeq1($a);
$this->setSeq2($b);
}
/**
* Set the first sequence ($a) and reset any internal caches to indicate that
* when calling the calculation methods, we need to recalculate them.
*
* @param string|array $a The sequence to set as the first sequence.
*/
public function setSeq1($a)
{
if(!is_array($a)) {
$a = str_split($a);
}
if($a == $this->a) {
return;
}
$this->a= $a;
$this->matchingBlocks = null;
$this->opCodes = null;
}
/**
* Set the second sequence ($b) and reset any internal caches to indicate that
* when calling the calculation methods, we need to recalculate them.
*
* @param string|array $b The sequence to set as the second sequence.
*/
public function setSeq2($b)
{
if(!is_array($b)) {
$b = str_split($b);
}
if($b == $this->b) {
return;
}
$this->b = $b;
$this->matchingBlocks = null;
$this->opCodes = null;
$this->fullBCount = null;
$this->chainB();
}
/**
* Generate the internal arrays containing the list of junk and non-junk
* characters for the second ($b) sequence.
*/
private function chainB()
{
$length = count ($this->b);
$this->b2j = array();
$popularDict = array();
for($i = 0; $i < $length; ++$i) {
$char = $this->b[$i];
if(isset($this->b2j[$char])) {
if($length >= 200 && count($this->b2j[$char]) * 100 > $length) {
$popularDict[$char] = 1;
unset($this->b2j[$char]);
}
else {
$this->b2j[$char][] = $i;
}
}
else {
$this->b2j[$char] = array(
$i
);
}
}
// Remove leftovers
foreach(array_keys($popularDict) as $char) {
unset($this->b2j[$char]);
}
$this->junkDict = array();
if(is_callable($this->junkCallback)) {
foreach(array_keys($popularDict) as $char) {
if(call_user_func($this->junkCallback, $char)) {
$this->junkDict[$char] = 1;
unset($popularDict[$char]);
}
}
foreach(array_keys($this->b2j) as $char) {
if(call_user_func($this->junkCallback, $char)) {
$this->junkDict[$char] = 1;
unset($this->b2j[$char]);
}
}
}
}
/**
* Checks if a particular character is in the junk dictionary
* for the list of junk characters.
*
* @return boolean $b True if the character is considered junk. False if not.
*/
private function isBJunk($b)
{
if(isset($this->juncDict[$b])) {
return true;
}
return false;
}
/**
* Find the longest matching block in the two sequences, as defined by the
* lower and upper constraints for each sequence. (for the first sequence,
* $alo - $ahi and for the second sequence, $blo - $bhi)
*
* Essentially, of all of the maximal matching blocks, return the one that
* startest earliest in $a, and all of those maximal matching blocks that
* start earliest in $a, return the one that starts earliest in $b.
*
* If the junk callback is defined, do the above but with the restriction
* that the junk element appears in the block. Extend it as far as possible
* by matching only junk elements in both $a and $b.
*
* @param int $alo The lower constraint for the first sequence.
* @param int $ahi The upper constraint for the first sequence.
* @param int $blo The lower constraint for the second sequence.
* @param int $bhi The upper constraint for the second sequence.
* @return array Array containing the longest match that includes the starting position in $a, start in $b and the length/size.
*/
public function findLongestMatch($alo, $ahi, $blo, $bhi)
{
$a = $this->a;
$b = $this->b;
$bestI = $alo;
$bestJ = $blo;
$bestSize = 0;
$j2Len = array();
$nothing = array();
for($i = $alo; $i < $ahi; ++$i) {
$newJ2Len = array();
$jDict = $this->arrayGetDefault($this->b2j, $a[$i], $nothing);
foreach($jDict as $jKey => $j) {
if($j < $blo) {
continue;
}
else if($j >= $bhi) {
break;
}
$k = $this->arrayGetDefault($j2Len, $j -1, 0) + 1;
$newJ2Len[$j] = $k;
if($k > $bestSize) {
$bestI = $i - $k + 1;
$bestJ = $j - $k + 1;
$bestSize = $k;
}
}
$j2Len = $newJ2Len;
}
while($bestI > $alo && $bestJ > $blo && !$this->isBJunk($b[$bestJ - 1]) &&
!$this->linesAreDifferent($bestI - 1, $bestJ - 1)) {
--$bestI;
--$bestJ;
++$bestSize;
}
while($bestI + $bestSize < $ahi && ($bestJ + $bestSize) < $bhi &&
!$this->isBJunk($b[$bestJ + $bestSize]) && !$this->linesAreDifferent($bestI + $bestSize, $bestJ + $bestSize)) {
++$bestSize;
}
while($bestI > $alo && $bestJ > $blo && $this->isBJunk($b[$bestJ - 1]) &&
!$this->isLineDifferent($bestI - 1, $bestJ - 1)) {
--$bestI;
--$bestJ;
++$bestSize;
}
while($bestI + $bestSize < $ahi && $bestJ + $bestSize < $bhi &&
$this->isBJunk($b[$bestJ + $bestSize]) && !$this->linesAreDifferent($bestI + $bestSize, $bestJ + $bestSize)) {
++$bestSize;
}
return array(
$bestI,
$bestJ,
$bestSize
);
}
/**
* Check if the two lines at the given indexes are different or not.
*
* @param int $aIndex Line number to check against in a.
* @param int $bIndex Line number to check against in b.
* @return boolean True if the lines are different and false if not.
*/
public function linesAreDifferent($aIndex, $bIndex)
{
$lineA = $this->a[$aIndex];
$lineB = $this->b[$bIndex];
if($this->options['ignoreWhitespace']) {
$replace = array("\t", ' ');
$lineA = str_replace($replace, '', $lineA);
$lineB = str_replace($replace, '', $lineB);
}
if($this->options['ignoreCase']) {
$lineA = strtolower($lineA);
$lineB = strtolower($lineB);
}
if($lineA != $lineB) {
return true;
}
return false;
}
/**
* Return a nested set of arrays for all of the matching sub-sequences
* in the strings $a and $b.
*
* Each block contains the lower constraint of the block in $a, the lower
* constraint of the block in $b and finally the number of lines that the
* block continues for.
*
* @return array Nested array of the matching blocks, as described by the function.
*/
public function getMatchingBlocks()
{
if(!empty($this->matchingBlocks)) {
return $this->matchingBlocks;
}
$aLength = count($this->a);
$bLength = count($this->b);
$queue = array(
array(
0,
$aLength,
0,
$bLength
)
);
$matchingBlocks = array();
while(!empty($queue)) {
list($alo, $ahi, $blo, $bhi) = array_pop($queue);
$x = $this->findLongestMatch($alo, $ahi, $blo, $bhi);
list($i, $j, $k) = $x;
if($k) {
$matchingBlocks[] = $x;
if($alo < $i && $blo < $j) {
$queue[] = array(
$alo,
$i,
$blo,
$j
);
}
if($i + $k < $ahi && $j + $k < $bhi) {
$queue[] = array(
$i + $k,
$ahi,
$j + $k,
$bhi
);
}
}
}
usort($matchingBlocks, array($this, 'tupleSort'));
$i1 = 0;
$j1 = 0;
$k1 = 0;
$nonAdjacent = array();
foreach($matchingBlocks as $block) {
list($i2, $j2, $k2) = $block;
if($i1 + $k1 == $i2 && $j1 + $k1 == $j2) {
$k1 += $k2;
}
else {
if($k1) {
$nonAdjacent[] = array(
$i1,
$j1,
$k1
);
}
$i1 = $i2;
$j1 = $j2;
$k1 = $k2;
}
}
if($k1) {
$nonAdjacent[] = array(
$i1,
$j1,
$k1
);
}
$nonAdjacent[] = array(
$aLength,
$bLength,
0
);
$this->matchingBlocks = $nonAdjacent;
return $this->matchingBlocks;
}
/**
* Return a list of all of the opcodes for the differences between the
* two strings.
*
* The nested array returned contains an array describing the opcode
* which includes:
* 0 - The type of tag (as described below) for the opcode.
* 1 - The beginning line in the first sequence.
* 2 - The end line in the first sequence.
* 3 - The beginning line in the second sequence.
* 4 - The end line in the second sequence.
*
* The different types of tags include:
* replace - The string from $i1 to $i2 in $a should be replaced by
* the string in $b from $j1 to $j2.
* delete - The string in $a from $i1 to $j2 should be deleted.
* insert - The string in $b from $j1 to $j2 should be inserted at
* $i1 in $a.
* equal - The two strings with the specified ranges are equal.
*
* @return array Array of the opcodes describing the differences between the strings.
*/
public function getOpCodes()
{
if(!empty($this->opCodes)) {
return $this->opCodes;
}
$i = 0;
$j = 0;
$this->opCodes = array();
$blocks = $this->getMatchingBlocks();
foreach($blocks as $block) {
list($ai, $bj, $size) = $block;
$tag = '';
if($i < $ai && $j < $bj) {
$tag = 'replace';
}
else if($i < $ai) {
$tag = 'delete';
}
else if($j < $bj) {
$tag = 'insert';
}
if($tag) {
$this->opCodes[] = array(
$tag,
$i,
$ai,
$j,
$bj
);
}
$i = $ai + $size;
$j = $bj + $size;
if($size) {
$this->opCodes[] = array(
'equal',
$ai,
$i,
$bj,
$j
);
}
}
return $this->opCodes;
}
/**
* Return a series of nested arrays containing different groups of generated
* opcodes for the differences between the strings with up to $context lines
* of surrounding content.
*
* Essentially what happens here is any big equal blocks of strings are stripped
* out, the smaller subsets of changes are then arranged in to their groups.
* This means that the sequence matcher and diffs do not need to include the full
* content of the different files but can still provide context as to where the
* changes are.
*
* @param int $context The number of lines of context to provide around the groups.
* @return array Nested array of all of the grouped opcodes.
*/
public function getGroupedOpcodes($context=3)
{
$opCodes = $this->getOpCodes();
if(empty($opCodes)) {
$opCodes = array(
array(
'equal',
0,
1,
0,
1
)
);
}
if($opCodes[0][0] == 'equal') {
$opCodes[0] = array(
$opCodes[0][0],
max($opCodes[0][1], $opCodes[0][2] - $context),
$opCodes[0][2],
max($opCodes[0][3], $opCodes[0][4] - $context),
$opCodes[0][4]
);
}
$lastItem = count($opCodes) - 1;
if($opCodes[$lastItem][0] == 'equal') {
list($tag, $i1, $i2, $j1, $j2) = $opCodes[$lastItem];
$opCodes[$lastItem] = array(
$tag,
$i1,
min($i2, $i1 + $context),
$j1,
min($j2, $j1 + $context)
);
}
$maxRange = $context * 2;
$groups = array();
$group = array();
foreach($opCodes as $code) {
list($tag, $i1, $i2, $j1, $j2) = $code;
if($tag == 'equal' && $i2 - $i1 > $maxRange) {
$group[] = array(
$tag,
$i1,
min($i2, $i1 + $context),
$j1,
min($j2, $j1 + $context)
);
$groups[] = $group;
$group = array();
$i1 = max($i1, $i2 - $context);
$j1 = max($j1, $j2 - $context);
}
$group[] = array(
$tag,
$i1,
$i2,
$j1,
$j2
);
}
if(!empty($group) && !(count($group) == 1 && $group[0][0] == 'equal')) {
$groups[] = $group;
}
return $groups;
}
/**
* Return a measure of the similarity between the two sequences.
* This will be a float value between 0 and 1.
*
* Out of all of the ratio calculation functions, this is the most
* expensive to call if getMatchingBlocks or getOpCodes is yet to be
* called. The other calculation methods (quickRatio and realquickRatio)
* can be used to perform quicker calculations but may be less accurate.
*
* The ratio is calculated as (2 * number of matches) / total number of
* elements in both sequences.
*
* @return float The calculated ratio.
*/
public function Ratio()
{
$matches = array_reduce($this->getMatchingBlocks(), array($this, 'ratioReduce'), 0);
return $this->calculateRatio($matches, count ($this->a) + count ($this->b));
}
/**
* Helper function to calculate the number of matches for Ratio().
*
* @param int $sum The running total for the number of matches.
* @param array $triple Array containing the matching block triple to add to the running total.
* @return int The new running total for the number of matches.
*/
private function ratioReduce($sum, $triple)
{
return $sum + ($triple[count($triple) - 1]);
}
/**
* Helper function for calculating the ratio to measure similarity for the strings.
* The ratio is defined as being 2 * (number of matches / total length)
*
* @param int $matches The number of matches in the two strings.
* @param int $length The length of the two strings.
* @return float The calculated ratio.
*/
private function calculateRatio($matches, $length=0)
{
if($length) {
return 2 * ($matches / $length);
}
else {
return 1;
}
}
/**
* Helper function that provides the ability to return the value for a key
* in an array of it exists, or if it doesn't then return a default value.
* Essentially cleaner than doing a series of if(isset()) {} else {} calls.
*
* @param array $array The array to search.
* @param string $key The key to check that exists.
* @param mixed $default The value to return as the default value if the key doesn't exist.
* @return mixed The value from the array if the key exists or otherwise the default.
*/
private function arrayGetDefault($array, $key, $default)
{
if(isset($array[$key])) {
return $array[$key];
}
else {
return $default;
}
}
/**
* Sort an array by the nested arrays it contains. Helper function for getMatchingBlocks
*
* @param array $a First array to compare.
* @param array $b Second array to compare.
* @return int -1, 0 or 1, as expected by the usort function.
*/
private function tupleSort($a, $b)
{
$max = max(count($a), count($b));
for($i = 0; $i < $max; ++$i) {
if($a[$i] < $b[$i]) {
return -1;
}
else if($a[$i] > $b[$i]) {
return 1;
}
}
if(count($a) == $count($b)) {
return 0;
}
else if(count($a) < count($b)) {
return -1;
}
else {
return 1;
}
}
}

Binary file not shown.

View File

@@ -0,0 +1,16 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<?php if(! wfUtils::isAdmin()){ exit(); } ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel='stylesheet' id='wordfence-main-style-css' href='<?php echo wfUtils::getBaseURL() . wfUtils::versionedAsset('css/iptraf.css'); ?>?ver=<?php echo WORDFENCE_VERSION; ?>' type='text/css' media='all' />
</head>
<body>
<h1><?php echo esc_html(sprintf(
/* translators: IP address. */
__('Wordfence: All recent hits for IP address %s', 'wordfence'), wp_kses($IP, array()) . (($reverseLookup) ? '[' . wp_kses($reverseLookup, array()) . ']' : ''))) ?></h1>
<div class="footer"><?php echo wp_kses(sprintf(
/* translators: 1. year (2011). 2. year (2020) */
__('&copy;&nbsp;%d to %d Wordfence &mdash; Visit <a href="http://wordfence.com/">Wordfence.com</a> for help, security updates and more.', 'wordfence'), date_i18n('Y', WORDFENCE_EPOCH), date_i18n('Y')), array('a'=>array('href'=>array()))) ?></div>
</body>
</html>

View File

@@ -0,0 +1,76 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<?php
if (!wfUtils::isAdmin()) {
exit();
}
/**
* @var array $results
*/
?>
<table border="0" cellpadding="2" cellspacing="0" class="wf-recent-traffic-table">
<?php foreach ($results as $key => $v) { ?>
<tr>
<th><?php esc_html_e('Time:', 'wordfence') ?></th>
<td><?php esc_html_e(sprintf(
/* translators: 1. Time ago, example: 2 hours, 40 seconds. 2. Localized date. 3. Unix timestamp. */
__('%1$s ago -- %2$s -- %3$s in Unixtime', 'wordfence'), $v['timeAgo'], date(DATE_RFC822, (int) $v['ctime']), $v['ctime'])) ?></td>
</tr>
<?php if ($v['timeSinceLastHit']) {
echo '<th>' . esc_html__('Seconds since last hit:', 'wordfence') . '</th><td>' . $v['timeSinceLastHit'] . '</td></tr>';
} ?>
<tr>
<th><?php esc_html_e('URL:', 'wordfence') ?></th>
<td>
<a href="<?php echo esc_url($v['URL']) ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html($v['URL']); ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a>
</td>
</tr>
<tr>
<th>Type:</th>
<td><?php
if ($v['statusCode'] == '404') {
echo '<span style="color: #F00;">' . esc_html('Page not found', 'wordfence') . '</span>';
}
else if ($v['type'] == 'hit') {
esc_html_e('Normal request', 'wordfence');
} ?></td>
</tr>
<?php if ($v['referer']) { ?>
<tr>
<th><?php esc_html_e('Referrer:', 'wordfence') ?></th>
<td>
<a href="<?php echo esc_url($v['referer']); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html($v['referer']); ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a>
</td></tr><?php } ?>
<tr>
<th><?php esc_html_e('Full Browser ID:', 'wordfence') ?></th>
<td><?php echo esc_html($v['UA']); ?></td>
</tr>
<?php if ($v['user']) { ?>
<tr>
<th><?php esc_html_e('User:', 'wordfence') ?></th>
<td>
<a href="<?php echo esc_url($v['user']['editLink']); ?>" target="_blank" rel="noopener noreferrer"><span data-userid="<?php echo esc_attr($v['user']['ID']); ?>" class="wfAvatar"></span><?php echo esc_html($v['user']['display_name']); ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a>
</td>
</tr>
<?php } ?>
<?php if ($v['loc']) { ?>
<tr>
<th><?php esc_html_e('Location:', 'wordfence') ?></th>
<td>
<span class="wf-flag <?php echo esc_attr('wf-flag-' . strtolower($v['loc']['countryCode'])); ?>" title="<?php echo esc_attr($v['loc']['countryName']); ?>"></span>
<?php if ($v['loc']['city']) {
echo esc_html($v['loc']['city']) . ', ';
} ?>
<?php
if ($v['loc']['region'] && wfUtils::shouldDisplayRegion($v['loc']['countryName'])) {
echo esc_html($v['loc']['region']) . ', ';
} ?>
<?php echo esc_html($v['loc']['countryName']); ?>
</td>
</tr>
<?php } ?>
<tr class="wf-recent-traffic-table-row-border">
<td colspan="2"><div></div></td>
</tr>
<?php } ?>
</table>

View File

@@ -0,0 +1,40 @@
<?php
/**
* Class WFLSPHP52Compatability
*
* This class exists solely to contain syntax incompatible with PHP 5.2 into a single file.
*/
class WFLSPHP52Compatability {
public static function install_plugin() {
\WordfenceLS\Controller_WordfenceLS::shared()->_install_plugin();
}
public static function uninstall_plugin() {
\WordfenceLS\Controller_WordfenceLS::shared()->_uninstall_plugin();
}
public static function import_2fa($import) {
$imported = \WordfenceLS\Controller_Users::shared()->import_2fa($import);
if ($imported && wfConfig::get('loginSec_requireAdminTwoFactor')) {
\WordfenceLS\Controller_Settings::shared()->set(\WordfenceLS\Controller_Settings::OPTION_REQUIRE_2FA_ADMIN, true);
}
return $imported;
}
public static function secrets_table() {
return \WordfenceLS\Controller_DB::shared()->secrets;
}
public static function ntp_time() {
return \WordfenceLS\Controller_Time::ntp_time();
}
public static function using_ntp_time() {
return \WordfenceLS\Controller_Settings::shared()->get_bool(\WordfenceLS\Controller_Settings::OPTION_USE_NTP);
}
public static function using_wf_time() {
return !self::using_ntp_time() && defined('WORDFENCE_LS_FROM_CORE') && WORDFENCE_LS_FROM_CORE && ((int) wfConfig::get('timeoffset_wf', false)) != 0;
}
}

View File

@@ -0,0 +1,17 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; }
if (!function_exists('str_getcsv')) {
function str_getcsv($input, $delimiter = ',', $enclosure = '"', $escape = null, $eol = null) {
$temp = fopen("php://memory", "rw");
fwrite($temp, $input);
fseek($temp, 0);
$r = array();
while (($data = fgetcsv($temp, 0, $delimiter, $enclosure, $escape)) !== false) {
$r[] = $data;
}
fclose($temp);
return $r;
}
}

View File

@@ -0,0 +1,19 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<?php //$data is defined here as an array of login attempts: array('IP' => binary ip, 'countryCode' => string, 'blockCount' => int, 'unixday' => int, 'totalIPs' => int, 'totalBlockCount' => int, 'countryName' => string) ?>
<table class="wf-table wf-table-hover">
<thead>
<tr>
<th colspan="2"><?php esc_html_e('Country', 'wordfence') ?></th>
<th><?php esc_html_e('Block Count', 'wordfence') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($data as $l): ?>
<tr>
<td><?php echo esc_html($l['countryName']); ?></td>
<td><span class="wf-flag <?php echo esc_attr('wf-flag-' . strtolower($l['countryCode'])); ?>" title="<?php echo esc_attr($l['countryName']); ?>"></span></td>
<td><?php echo esc_html(number_format_i18n($l['totalBlockCount'])); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>

View File

@@ -0,0 +1,21 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<?php //$data is defined here as an array of login attempts: array('IP' => binary ip, 'countryCode' => string, 'blockCount' => int, 'unixday' => int, 'countryName' => string) ?>
<table class="wf-table wf-table-hover">
<thead>
<tr>
<th><?php esc_html_e('IP', 'wordfence') ?></th>
<th colspan="2"><?php esc_html_e('Country', 'wordfence') ?></th>
<th><?php esc_html_e('Block Count', 'wordfence') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($data as $l): ?>
<tr>
<td><?php echo esc_html(wfUtils::inet_ntop($l['IP'])); ?></td>
<td><?php echo esc_html($l['countryName']); ?></td>
<td><span class="wf-flag <?php echo esc_attr('wf-flag-' . strtolower($l['countryCode'])); ?>" title="<?php echo esc_attr($l['countryName']); ?>"></span></td>
<td><?php echo esc_html(number_format_i18n($l['blockCount'])); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>

View File

@@ -0,0 +1,27 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<?php //$data is defined here as an array of login attempts: array('t' => timestamp, 'name' => username, 'ip' => IP address) ?>
<table class="wf-table wf-table-hover">
<thead>
<tr>
<th><?php esc_html_e('Username', 'wordfence') ?></th>
<th><?php esc_html_e('IP', 'wordfence') ?></th>
<th><?php esc_html_e('Date', 'wordfence') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($data as $l): ?>
<tr>
<td><?php echo esc_html($l['name']); ?></td>
<td><?php echo esc_html($l['ip']); ?></td>
<td><?php
if (time() - $l['t'] < 86400) {
echo esc_html(wfUtils::makeTimeAgo(time() - $l['t']) . ' ago');
}
else {
echo esc_html(wfUtils::formatLocalTime(get_option('date_format') . ' ' . get_option('time_format'), (int) $l['t']));
}
?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>

View File

@@ -0,0 +1,64 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<?php //$d is defined here as a wfDashboard instance ?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-dashboard-item active">
<div class="wf-dashboard-item-inner">
<div class="wf-dashboard-item-content">
<div class="wf-dashboard-item-title">
<strong><?php esc_html_e('Top Countries by Number of Attacks - Last 7 Days', 'wordfence') ?></strong>
</div>
<div class="wf-dashboard-item-action"><div class="wf-dashboard-item-action-disclosure"></div></div>
</div>
</div>
<div class="wf-dashboard-item-extra">
<?php if ($firewall->learningModeStatus() !== false): ?>
<div class="wf-widget-learning-mode"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100.11 100.44"><path d="M96.14,30.67a50.7,50.7,0,0,0-10.66-16A50,50,0,0,0,69.51,4,49.57,49.57,0,0,0,30.6,4a50,50,0,0,0-16,10.69A50.69,50.69,0,0,0,4,30.67,50,50,0,0,0,4,69.74a50.62,50.62,0,0,0,10.66,16,50,50,0,0,0,16,10.69,49.54,49.54,0,0,0,38.91,0,50,50,0,0,0,16-10.69,50.56,50.56,0,0,0,10.66-16,50,50,0,0,0,0-39.07Zm-75.74,39a35.77,35.77,0,0,1-1-37.35,35.21,35.21,0,0,1,12.91-13A34.65,34.65,0,0,1,50.06,14.6a34.22,34.22,0,0,1,19.55,5.93ZM82.71,64a35.4,35.4,0,0,1-7.56,11.37A36,36,0,0,1,63.84,83a34.32,34.32,0,0,1-13.79,2.84A34.85,34.85,0,0,1,30.7,80L79.84,31a34.57,34.57,0,0,1,5.67,19.23A35.17,35.17,0,0,1,82.71,64Zm0,0"/></svg><span><?php esc_html_e('No Data Available During Learning Mode', 'wordfence'); ?></span></div>
<?php else: ?>
<ul class="wf-dashboard-item-list">
<li>
<div>
<?php if (isset($d->countriesNetwork) && count($d->countriesNetwork) > 0): ?>
<div class="wf-dashboard-toggle-btns">
<ul class="wf-pagination wf-pagination-sm">
<li class="wf-active"><a href="#" class="wf-dashboard-countries" data-grouping="local" role="button">Local Site</a></li>
<li><a href="#" class="wf-dashboard-countries" data-grouping="network" role="button"><?php esc_html_e('Wordfence Network', 'wordfence') ?></a></li>
</ul>
</div>
<?php endif; ?>
<div class="wf-countries wf-countries-local">
<?php if (!isset($d->countriesLocal) || count($d->countriesLocal) == 0): ?>
<div class="wf-dashboard-item-list-text"><p><em><?php esc_html_e('No blocks have been recorded.', 'wordfence') ?></em></p></div>
<?php else: ?>
<?php $data = array_slice($d->countriesLocal, 0, min(10, count($d->countriesLocal)), true); include(dirname(__FILE__) . '/widget_content_countries.php'); ?>
<?php endif; ?>
</div>
<div class="wf-countries wf-countries-network wf-hidden">
<?php if (!isset($d->countriesNetwork) || count($d->countriesNetwork) == 0): ?>
<div class="wf-dashboard-item-list-text"><p><em><?php esc_html_e('No blocks have been recorded.', 'wordfence') ?></em></p></div>
<?php else: ?>
<?php $data = array_slice($d->countriesNetwork, 0, min(10, count($d->countriesNetwork)), true); include(dirname(__FILE__) . '/widget_content_countries.php'); ?>
<?php endif; ?>
</div>
<script type="application/javascript">
(function($) {
$('.wf-dashboard-countries').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
$(this).closest('ul').find('li').removeClass('wf-active');
$(this).closest('li').addClass('wf-active');
$('.wf-countries').addClass('wf-hidden');
$('.wf-countries-' + $(this).data('grouping')).removeClass('wf-hidden');
});
})(jQuery);
</script>
</div>
</li>
</ul>
<?php endif; ?>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,131 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<?php
//$d is defined here as a wfDashboard instance
$initial = false;
if (!isset($limit)) { $limit = 10; $initial = true; }
?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-dashboard-item active">
<div class="wf-dashboard-item-inner">
<div class="wf-dashboard-item-content">
<div class="wf-dashboard-item-title">
<strong><?php esc_html_e('Top IPs Blocked', 'wordfence') ?></strong>
</div>
<div class="wf-dashboard-item-action"><div class="wf-dashboard-item-action-disclosure"></div></div>
</div>
</div>
<div class="wf-dashboard-item-extra">
<?php if ($firewall->learningModeStatus() !== false): ?>
<div class="wf-widget-learning-mode"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100.11 100.44"><path d="M96.14,30.67a50.7,50.7,0,0,0-10.66-16A50,50,0,0,0,69.51,4,49.57,49.57,0,0,0,30.6,4a50,50,0,0,0-16,10.69A50.69,50.69,0,0,0,4,30.67,50,50,0,0,0,4,69.74a50.62,50.62,0,0,0,10.66,16,50,50,0,0,0,16,10.69,49.54,49.54,0,0,0,38.91,0,50,50,0,0,0,16-10.69,50.56,50.56,0,0,0,10.66-16,50,50,0,0,0,0-39.07Zm-75.74,39a35.77,35.77,0,0,1-1-37.35,35.21,35.21,0,0,1,12.91-13A34.65,34.65,0,0,1,50.06,14.6a34.22,34.22,0,0,1,19.55,5.93ZM82.71,64a35.4,35.4,0,0,1-7.56,11.37A36,36,0,0,1,63.84,83a34.32,34.32,0,0,1-13.79,2.84A34.85,34.85,0,0,1,30.7,80L79.84,31a34.57,34.57,0,0,1,5.67,19.23A35.17,35.17,0,0,1,82.71,64Zm0,0"/></svg><span><?php esc_html_e('No Data Available During Learning Mode', 'wordfence'); ?></span></div>
<?php else: ?>
<ul class="wf-dashboard-item-list">
<li>
<div>
<div class="wf-dashboard-toggle-btns">
<ul class="wf-pagination wf-pagination-sm">
<li class="wf-active"><a href="#" class="wf-dashboard-ips" data-grouping="24h" role="button"><?php esc_html_e('24 Hours', 'wordfence') ?></a></li>
<li><a href="#" class="wf-dashboard-ips" data-grouping="7d" role="button"><?php esc_html_e('7 Days', 'wordfence') ?></a></li>
<li><a href="#" class="wf-dashboard-ips" data-grouping="30d" role="button"><?php esc_html_e('30 Days', 'wordfence') ?></a></li>
</ul>
</div>
<div class="wf-ips wf-ips-24h">
<?php if (count($d->ips24h) == 0): ?>
<div class="wf-dashboard-item-list-text"><p><em><?php esc_html_e('No blocks have been recorded.', 'wordfence') ?></em></p></div>
<?php else: ?>
<?php $data = array_slice($d->ips24h, 0, min($limit, count($d->ips24h)), true); include(dirname(__FILE__) . '/widget_content_ips.php'); ?>
<?php if (count($d->ips24h) > $limit && $initial): ?>
<div class="wf-dashboard-item-list-text"><div class="wf-dashboard-show-more" data-grouping="ips" data-period="24h"><a href="#" role="button"><?php esc_html_e('Show more', 'wordfence') ?></a></div></div>
<?php endif; ?>
<?php endif; ?>
</div>
<div class="wf-ips wf-ips-7d wf-hidden">
<?php if (count($d->ips7d) == 0): ?>
<div class="wf-dashboard-item-list-text"><p><em><?php esc_html_e('No blocks have been recorded.', 'wordfence') ?></em></p></div>
<?php else: ?>
<?php $data = array_slice($d->ips7d, 0, min($limit, count($d->ips7d)), true); include(dirname(__FILE__) . '/widget_content_ips.php'); ?>
<?php if (count($d->ips7d) > $limit && $initial): ?>
<div class="wf-dashboard-item-list-text"><div class="wf-dashboard-show-more" data-grouping="ips" data-period="7d"><a href="#" role="button"><?php esc_html_e('Show more', 'wordfence') ?></a></div></div>
<?php endif; ?>
<?php endif; ?>
</div>
<div class="wf-ips wf-ips-30d wf-hidden">
<?php if (count($d->ips30d) == 0): ?>
<div class="wf-dashboard-item-list-text"><p><em><?php esc_html_e('No blocks have been recorded.', 'wordfence') ?></em></p></div>
<?php else: ?>
<?php $data = array_slice($d->ips30d, 0, min($limit, count($d->ips30d)), true); include(dirname(__FILE__) . '/widget_content_ips.php'); ?>
<?php if (count($d->ips30d) > $limit && $initial): ?>
<div class="wf-dashboard-item-list-text"><div class="wf-dashboard-show-more" data-grouping="ips" data-period="30d"><a href="#" role="button"><?php esc_html_e('Show more', 'wordfence') ?></a></div></div>
<?php endif; ?>
<?php endif; ?>
</div>
<script type="application/javascript">
(function($) {
$('.wf-dashboard-ips').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
$(this).closest('ul').find('li').removeClass('wf-active');
$(this).closest('li').addClass('wf-active');
$('.wf-ips').addClass('wf-hidden');
$('.wf-ips-' + $(this).data('grouping')).removeClass('wf-hidden');
});
$('.wf-ips .wf-dashboard-show-more a').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var grouping = $(this).parent().data('grouping');
var period = $(this).parent().data('period');
$(this).closest('.wf-dashboard-item-list-text').fadeOut();
var self = this;
WFAD.ajax('wordfence_dashboardShowMore', {
grouping: grouping,
period: period
}, function(res) {
if (res.ok) {
var table = $('#ips-data-template').tmpl(res);
$(self).closest('.wf-ips').css('overflow-y', 'auto');
$(self).closest('.wf-ips').find('table').replaceWith(table);
}
else {
WFAD.colorboxModal('300px', <?php echo json_encode(__('An error occurred', 'wordfence')) ?>, <?php echo json_encode(__('We encountered an error trying load more data.', 'wordfence')) ?>);
$(this).closest('.wf-dashboard-item-list-text').fadeIn();
}
});
});
})(jQuery);
</script>
</div>
</li>
</ul>
<?php endif; ?>
</div>
</div>
</div>
</div>
<script type="text/x-jquery-template" id="ips-data-template">
<table class="wf-table wf-table-hover">
<thead>
<tr>
<th><?php esc_html_e('IP', 'wordfence') ?></th>
<th colspan="2"><?php esc_html_e('Country', 'wordfence') ?></th>
<th><?php esc_html_e('Block Count', 'wordfence') ?></th>
</tr>
</thead>
<tbody>
{{each(idx, d) data}}
<tr>
<td>${d.IP}</td>
<td>${d.countryName}</td>
<td><span class="wf-flag ${d.countryFlag}" title="${d.countryName}"></td>
<td>${d.blockCount}</td>
</tr>
{{/each}}
</tbody>
</table>
</script>

View File

@@ -0,0 +1,78 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-dashboard-item active">
<div class="wf-dashboard-item-inner">
<div class="wf-dashboard-item-content">
<div class="wf-dashboard-item-title">
<strong><?php esc_html_e('Firewall Summary:', 'wordfence'); ?> </strong><?php echo esc_html(sprintf(
/* translators: The site's domain name. */
__('Attacks Blocked for %s', 'wordfence'), preg_replace('/^[^:]+:\/\//', '', network_site_url()))); ?>
</div>
<div class="wf-dashboard-item-action"><div class="wf-dashboard-item-action-disclosure"></div></div>
</div>
</div>
<div class="wf-dashboard-item-extra">
<?php if ($firewall->learningModeStatus() !== false): ?>
<div class="wf-widget-learning-mode"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100.11 100.44"><path d="M96.14,30.67a50.7,50.7,0,0,0-10.66-16A50,50,0,0,0,69.51,4,49.57,49.57,0,0,0,30.6,4a50,50,0,0,0-16,10.69A50.69,50.69,0,0,0,4,30.67,50,50,0,0,0,4,69.74a50.62,50.62,0,0,0,10.66,16,50,50,0,0,0,16,10.69,49.54,49.54,0,0,0,38.91,0,50,50,0,0,0,16-10.69,50.56,50.56,0,0,0,10.66-16,50,50,0,0,0,0-39.07Zm-75.74,39a35.77,35.77,0,0,1-1-37.35,35.21,35.21,0,0,1,12.91-13A34.65,34.65,0,0,1,50.06,14.6a34.22,34.22,0,0,1,19.55,5.93ZM82.71,64a35.4,35.4,0,0,1-7.56,11.37A36,36,0,0,1,63.84,83a34.32,34.32,0,0,1-13.79,2.84A34.85,34.85,0,0,1,30.7,80L79.84,31a34.57,34.57,0,0,1,5.67,19.23A35.17,35.17,0,0,1,82.71,64Zm0,0"/></svg><span><?php esc_html_e('No Data Available During Learning Mode', 'wordfence'); ?></span></div>
<?php else: ?>
<ul class="wf-dashboard-item-list">
<li class="wf-flex-vertical wf-flex-full-width">
<?php
$hasSome = false;
foreach ($d->localBlocks as $row) {
if ($row['24h'] > 0 || $row['7d'] > 0 || $row['30d'] > 0) {
$hasSome = true;
break;
}
}
if (!$hasSome):
?>
<div class="wf-dashboard-item-list-text"><p><em><?php esc_html_e('No blocks have been recorded.', 'wordfence'); ?></em></p></div>
<?php else: ?>
<table class="wf-blocks-summary">
<thead>
<tr>
<th><?php echo wp_kses(__('<span class="wf-hidden-xs">Block </span>Type', 'wordfence'), array('span'=>array('class'=>array()))); ?></th>
<?php
$totals = array('24h' => 0, '7d' => 0, '30d' => 0);
foreach ($d->localBlocks as $row): ?>
<th width="25%"<?php if ($row['type'] == wfActivityReport::BLOCK_TYPE_BLACKLIST && !wfConfig::get('isPaid')) { echo ' class="wf-premium"'; } ?>><?php echo esc_html($row['title']); ?></th>
<?php $totals['24h'] += $row['24h']; $totals['7d'] += $row['7d']; $totals['30d'] += $row['30d']; ?>
<?php endforeach; ?>
<th width="25%"><?php esc_html_e('Total', 'wordfence'); ?></th>
</tr>
</thead>
<tbody>
<?php
$keys = array('24h' => __('Today', 'wordfence'), '7d' => __('Week', 'wordfence'), '30d' => __('Month', 'wordfence'));
foreach ($keys as $k => $title): ?>
<tr>
<th><?php echo esc_html($title); ?></th>
<?php foreach ($d->localBlocks as $row): ?>
<td<?php if ($row['type'] == wfActivityReport::BLOCK_TYPE_BLACKLIST && !wfConfig::get('isPaid')) { echo ' class="wf-premium"'; } ?>><?php echo ($row['type'] == wfActivityReport::BLOCK_TYPE_BLACKLIST && !wfConfig::get('isPaid')) ? '&mdash;' : esc_html(number_format_i18n($row[$k])); ?></td>
<?php endforeach; ?>
<td><?php echo esc_html(number_format_i18n($totals[$k])); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot>
<tr>
<th></th>
<?php foreach ($d->localBlocks as $row): ?>
<td<?php if ($row['type'] == wfActivityReport::BLOCK_TYPE_BLACKLIST && !wfConfig::get('isPaid')) { echo ' class="wf-premium"'; } ?>><?php if ($row['type'] == wfActivityReport::BLOCK_TYPE_BLACKLIST && !wfConfig::get('isPaid')) { esc_html_e('Premium', 'wordfence'); } ?></td>
<?php endforeach; ?>
<td></td>
</tr>
</tfoot>
</table>
<p class="wf-right wf-no-top"><a href="<?php echo wfSupportController::esc_supportURL(wfSupportController::ITEM_WIDGET_LOCAL_ATTACKS); ?>" target="_blank" rel="noopener noreferrer"><i class="wf-fa wf-fa-question-circle-o" aria-hidden="true"></i> <?php esc_html_e('How are these categorized?', 'wordfence'); ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a></p>
<?php endif; ?>
</li>
</ul>
<?php endif; ?>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,110 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<?php //$d is defined here as a wfDashboard instance ?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-dashboard-item active">
<div class="wf-dashboard-item-inner">
<div class="wf-dashboard-item-content">
<div class="wf-dashboard-item-title">
<strong><?php esc_html_e('Login Attempts', 'wordfence') ?></strong>
</div>
<div class="wf-dashboard-item-action"><div class="wf-dashboard-item-action-disclosure"></div></div>
</div>
</div>
<div class="wf-dashboard-item-extra">
<ul class="wf-dashboard-item-list">
<li>
<div>
<div class="wf-dashboard-toggle-btns">
<ul class="wf-pagination wf-pagination-sm">
<li class="wf-active"><a href="#" class="wf-dashboard-login-attempts" data-grouping="success" role="button"><?php esc_html_e('Successful', 'wordfence') ?></a></li>
<li><a href="#" class="wf-dashboard-login-attempts" data-grouping="fail" role="button"><?php esc_html_e('Failed', 'wordfence') ?></a></li>
</ul>
</div>
<div class="wf-recent-logins wf-recent-logins-success">
<?php if (count($d->loginsSuccess) == 0): ?>
<div class="wf-dashboard-item-list-text"><p><em><?php esc_html_e('No successful logins have been recorded.', 'wordfence') ?></em></p></div>
<?php else: ?>
<?php $data = array_slice($d->loginsSuccess, 0, min(10, count($d->loginsSuccess)), true); include(dirname(__FILE__) . '/widget_content_logins.php'); ?>
<?php if (count($d->loginsSuccess) > 10): ?>
<div class="wf-dashboard-item-list-text"><div class="wf-dashboard-show-more" data-grouping="logins" data-period="success"><a href="#" role="button"><?php esc_html_e('Show more', 'wordfence') ?></a></div></div>
<?php endif; ?>
<?php endif; ?>
</div>
<div class="wf-recent-logins wf-recent-logins-fail wf-hidden">
<?php if (count($d->loginsFail) == 0): ?>
<div class="wf-dashboard-item-list-text"><p><em><?php esc_html_e('No failed logins have been recorded.', 'wordfence') ?></em></p></div>
<?php else: ?>
<?php $data = array_slice($d->loginsFail, 0, min(10, count($d->loginsFail)), true); include(dirname(__FILE__) . '/widget_content_logins.php'); ?>
<?php if (count($d->loginsFail) > 10): ?>
<div class="wf-dashboard-item-list-text"><div class="wf-dashboard-show-more" data-grouping="logins" data-period="fail"><a href="#" role="button"><?php esc_html_e('Show more', 'wordfence') ?></a></div></div>
<?php endif; ?>
<?php endif; ?>
</div>
<script type="application/javascript">
(function($) {
$('.wf-dashboard-login-attempts').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
$(this).closest('ul').find('li').removeClass('wf-active');
$(this).closest('li').addClass('wf-active');
$('.wf-recent-logins').addClass('wf-hidden');
$('.wf-recent-logins-' + $(this).data('grouping')).removeClass('wf-hidden');
});
$('.wf-recent-logins .wf-dashboard-show-more a').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var grouping = $(this).parent().data('grouping');
var period = $(this).parent().data('period');
$(this).closest('.wf-dashboard-item-list-text').fadeOut();
var self = this;
WFAD.ajax('wordfence_dashboardShowMore', {
grouping: grouping,
period: period
}, function(res) {
if (res.ok) {
var table = $('#logins-data-template').tmpl(res);
$(self).closest('.wf-recent-logins').css('overflow-y', 'auto');
$(self).closest('.wf-recent-logins').find('table').replaceWith(table);
}
else {
WFAD.colorboxModal('300px', <?php echo json_encode(__('An error occurred', 'wordfence')) ?>, <?php echo json_encode(__('We encountered an error trying load more data.', 'wordfence')) ?>);
$(this).closest('.wf-dashboard-item-list-text').fadeIn();
}
});
});
})(jQuery);
</script>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
<script type="text/x-jquery-template" id="logins-data-template">
<table class="wf-table wf-table-hover">
<thead>
<tr>
<th><?php esc_html_e('Username', 'wordfence') ?></th>
<th><?php esc_html_e('IP', 'wordfence') ?></th>
<th><?php esc_html_e('Date', 'wordfence') ?></th>
</tr>
</thead>
<tbody>
{{each(idx, d) data}}
<tr>
<td>${d.name}</td>
<td>${d.ip}</td>
<td>${d.t}</td>
</tr>
{{/each}}
</tbody>
</table>
</script>

View File

@@ -0,0 +1,212 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-dashboard-item active">
<div class="wf-dashboard-item-inner">
<div class="wf-dashboard-item-content">
<div class="wf-dashboard-item-title">
<strong><?php esc_html_e('Total Attacks Blocked:', 'wordfence'); ?> </strong><?php esc_html_e('Wordfence Network', 'wordfence'); ?>
</div>
<div class="wf-dashboard-item-action"><div class="wf-dashboard-item-action-disclosure"></div></div>
</div>
</div>
<div class="wf-dashboard-item-extra">
<ul class="wf-dashboard-item-list">
<li>
<?php if ($d->networkBlock24h === null): ?>
<div class="wf-dashboard-item-list-text"><p><em><?php esc_html_e('Blocked attack counts not available yet.', 'wordfence'); ?></em></p></div>
<?php else: ?>
<div class="wf-dashboard-graph-wrapper">
<div class="wf-dashboard-toggle-btns">
<ul class="wf-pagination wf-pagination-sm">
<li class="wf-active"><a href="#" class="wf-dashboard-graph-attacks" data-grouping="24h" role="button"><?php esc_html_e('24 Hours', 'wordfence'); ?></a></li>
<li><a href="#" class="wf-dashboard-graph-attacks" data-grouping="30d" role="button"><?php esc_html_e('30 Days', 'wordfence'); ?></a></li>
</ul>
</div>
<div class="wf-dashboard-network-blocks"><canvas id="wf-dashboard-network-blocks-24h"></canvas></div>
<div class="wf-dashboard-network-blocks wf-hidden"><canvas id="wf-dashboard-network-blocks-7d"></canvas></div>
<div class="wf-dashboard-network-blocks wf-hidden"><canvas id="wf-dashboard-network-blocks-30d"></canvas></div>
</div>
<script type="application/javascript">
<?php
$totalAttacksString = json_encode(__("Total Attacks", 'wordfence'));
$styling = <<<STYLING
label: $totalAttacksString,
fill: false,
lineTension: 0.1,
backgroundColor: "rgba(75,192,192,0.4)",
borderColor: "#16bc9b",
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: "rgba(75,192,192,1)",
pointBackgroundColor: "#fff",
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: "rgba(75,192,192,1)",
pointHoverBorderColor: "rgba(220,220,220,1)",
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
spanGaps: false,
STYLING;
?>
(function($) {
$(document).ready(function() {
new Chart($('#wf-dashboard-network-blocks-24h'), {
type: 'line',
data: {
<?php
$blocks = $d->networkBlock24h;
$labels = array();
$values = array();
foreach ($blocks as $b) {
$values[] = $b['c'];
$labels[] = "'" . wfUtils::formatLocalTime('g a', $b['t']) . "'";
}
?>
labels: [<?php echo implode(',', $labels); ?>],
datasets: [
{
<?php echo $styling; ?>
data: [<?php echo implode(',', $values) ?>]
}
]
},
options: {
scales: {
y: {
beginAtZero: true,
ticks: {
callback: function(value, index, values) {
return value.toLocaleString();
}
}
}
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || 'Other';
var label = parseInt(tooltipItem.yLabel).toLocaleString();
return datasetLabel + ': ' + label;
}
}
}
}
});
new Chart($('#wf-dashboard-network-blocks-7d'), {
type: 'line',
data: {
<?php
$blocks = $d->networkBlock7d;
$labels = array();
$values = array();
foreach ($blocks as $b) {
$values[] = $b['c'];
$labels[] = "'" . wfUtils::formatLocalTime('M j', $b['t']) . "'";
}
?>
labels: [<?php echo implode(',', $labels); ?>],
datasets: [
{
<?php echo $styling; ?>
data: [<?php echo implode(',', $values) ?>]
}
]
},
options: {
scales: {
y: {
beginAtZero: true,
ticks: {
callback: function(value, index, values) {
return value.toLocaleString();
}
}
}
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || 'Other';
var label = parseInt(tooltipItem.yLabel).toLocaleString();
return datasetLabel + ': ' + label;
}
}
}
}
});
new Chart($('#wf-dashboard-network-blocks-30d'), {
type: 'line',
data: {
<?php
$blocks = $d->networkBlock30d;
$labels = array();
$values = array();
foreach ($blocks as $b) {
$values[] = $b['c'];
$labels[] = "'" . wfUtils::formatLocalTime('M j', $b['t']) . "'";
}
?>
labels: [<?php echo implode(',', $labels); ?>],
datasets: [
{
<?php echo $styling; ?>
data: [<?php echo implode(',', $values) ?>]
}
]
},
options: {
scales: {
y: {
beginAtZero: true,
ticks: {
callback: function(value, index, values) {
return value.toLocaleString();
}
}
}
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || 'Other';
var label = parseInt(tooltipItem.yLabel).toLocaleString();
return datasetLabel + ': ' + label;
}
}
}
}
});
});
$('.wf-dashboard-graph-attacks').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
$(this).closest('ul').find('li').removeClass('wf-active');
$(this).closest('li').addClass('wf-active');
$('.wf-dashboard-network-blocks').addClass('wf-hidden');
$('#wf-dashboard-network-blocks-' + $(this).data('grouping')).closest('.wf-dashboard-network-blocks').removeClass('wf-hidden');
});
})(jQuery);
</script>
<?php endif; ?>
</li>
</ul>
<p class="wf-dashboard-last-updated"><?php echo esc_html(sprintf(
/* translators: Time since. Example: 1 minute, 2 seconds */
__('Last Updated: %s ago', 'wordfence'), wfUtils::makeTimeAgo(time() - $d->lastGenerated))); ?></p>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,138 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<div class="wf-flex-row wf-flex-row-full-height wf-flex-row-vertical-xs">
<div class="wf-flex-col-xs-100 <?php if (wfCentral::isSupported() && wfConfig::get('showWfCentralUI', false)): ?>wf-flex-col-lg-50 wf-col-lg-half-padding-right wf-dashboard-item-flex-wrapper<?php endif ?>">
<div class="wf-dashboard-item active">
<div class="wf-dashboard-item-inner">
<div class="wf-dashboard-item-content">
<div class="wf-dashboard-item-title">
<strong><?php esc_html_e('Notifications', 'wordfence') ?></strong><span class="wf-dashboard-badge wf-notification-count-container wf-notification-count-value<?php echo (count($d->notifications) == 0 ? ' wf-hidden' : ''); ?>"><?php echo number_format_i18n(count($d->notifications)); ?></span>
</div>
<div class="wf-dashboard-item-action"><div class="wf-dashboard-item-action-disclosure"></div></div>
</div>
</div>
<div class="wf-dashboard-item-extra">
<ul class="wf-dashboard-item-list wf-dashboard-item-list-striped">
<?php foreach ($d->notifications as $n): ?>
<li class="wf-notification<?php if ($n->priority % 10 == 1) { echo ' wf-notification-critical'; } else if ($n->priority % 10 == 2) { echo ' wf-notification-warning'; } ?>" data-notification="<?php echo esc_html($n->id); ?>">
<div class="wf-dashboard-item-list-title"><?php echo $n->html; ?></div>
<?php foreach ($n->links as $l): ?>
<div class="wf-dashboard-item-list-action"><a href="<?php echo esc_html($l['link']); ?>"<?php if (preg_match('/^https?:\/\//i', $l['link'])) { echo ' target="_blank" rel="noopener noreferrer"'; } ?>><?php echo esc_html($l['label']); ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a></div>
<?php endforeach; ?>
<div class="wf-dashboard-item-list-dismiss"><a href="#" class="wf-dismiss-notification" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</li>
<?php endforeach; ?>
<?php if (count($d->notifications) == 0): ?>
<li class="wf-notifications-empty"><?php esc_html_e('No notifications received', 'wordfence') ?></li>
<?php endif; ?>
</ul>
</div>
</div>
</div>
<?php if (wfCentral::isSupported() && wfConfig::get('showWfCentralUI', false)): ?>
<div class="wf-flex-col-xs-100 wf-flex-col-lg-50 wf-col-lg-half-padding-left wf-dashboard-item-flex-wrapper wf-central-connected">
<div class="wf-dashboard-item active wf-flex-row-1">
<div class="wf-central-dashboard">
<img class="wf-central-dashboard-logo" src="<?php echo wfUtils::getBaseURL() ?>images/wf-central-logo.svg" alt="Wordfence Central">
<div class="wf-central-dashboard-copy">
<p id="wf-central-status"><strong><?php esc_html_e('Wordfence Central Status', 'wordfence') ?></strong></p>
<p><?php
if ($d->wordfenceCentralConnected) {
echo esc_html(sprintf(
/* translators: 1. Email address. 2. Localized date. */
__('Connected by %1$s on %2$s', 'wordfence'), $d->wordfenceCentralConnectEmail, date_i18n(get_option('date_format'), $d->wordfenceCentralConnectTime)));
} elseif ($d->wordfenceCentralDisconnected) {
echo esc_html(sprintf(
/* translators: 1. Email address. 2. Localized date. */
__('Disconnected by %1$s on %2$s', 'wordfence'), $d->wordfenceCentralDisconnectEmail, date_i18n(get_option('date_format'), $d->wordfenceCentralDisconnectTime)));
} elseif (wfCentral::isPartialConnection()) {
_e('It looks like you\'ve tried to connect this site to Wordfence Central, but the installation did not finish.', 'wordfence');
} else {
_e('Wordfence Central allows you to manage Wordfence on multiple sites from one location. It makes security monitoring and configuring Wordfence easier.', 'wordfence');
}
?></p>
<div class="wf-flex-row">
<?php if (wfCentral::isPartialConnection()): ?>
<p>
<a href="<?php echo WORDFENCE_CENTRAL_URL_SEC ?>/sites/connection-issues?complete-setup=<?php echo esc_attr(wfConfig::get('wordfenceCentralSiteID')) ?>"
class="wf-central-resume wf-btn wf-btn-sm wf-btn-primary"
><?php esc_html_e('Resume Installation', 'wordfence') ?></a>
<a href="#" class="wf-central-disconnect wf-btn wf-btn-sm wf-btn-default" role="button"><strong><?php esc_html_e('Disconnect This Site', 'wordfence') ?></strong></a>
</p>
<?php else: ?>
<p class="wf-flex-row-1">
<?php if ($d->wordfenceCentralConnected): ?>
<a href="#" class="wf-central-disconnect" role="button"><strong><?php esc_html_e('Disconnect This Site', 'wordfence') ?></strong></a>
<?php else: ?>
<a href="<?php echo WORDFENCE_CENTRAL_URL_SEC ?>?newsite=<?php echo esc_attr(home_url()) ?>"><strong><?php $d->wordfenceCentralDisconnected ? esc_html_e('Reconnect This Site', 'wordfence') : esc_html_e('Connect This Site', 'wordfence') ?></strong></a>
<?php endif; ?>
</p>
<p class="wf-flex-row-1 wf-right wf-nowrap"><a href="<?php echo esc_url(WORDFENCE_CENTRAL_URL_SEC) ?>" target="_blank" rel="noopener noreferrer"><strong><?php esc_html_e('Visit Wordfence Central', 'wordfence') ?></strong><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a></p>
<?php endif ?>
</div>
</div>
</div>
</div>
</div>
<?php endif ?>
</div>
<script type="application/javascript">
(function($) {
$('.wf-dismiss-notification').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var n = $(this).closest('.wf-notification');
var id = n.data('notification');
n.fadeOut(400, function() {
n.remove();
var count = $('.wf-dismiss-notification').length;
WFDash.updateNotificationCount(count);
});
WFAD.ajax('wordfence_dismissNotification', {
id: id
}, function(res) {
//Do nothing
});
});
$('.wf-central-disconnect').on('click', function(e) {
e.preventDefault();
var prompt = $('#wfTmpl_wfCentralDisconnectPrompt').tmpl();
var promptHTML = $("<div />").append(prompt).html();
WFAD.colorboxHTML('400px', promptHTML, {
overlayClose: false, closeButton: false, className: 'wf-modal', onComplete: function() {
$('#wf-central-prompt-cancel').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
WFAD.colorboxClose();
});
$('#wf-central-prompt-disconnect').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
WFAD.ajax('wordfence_wfcentral_disconnect', {}, function(response) {
window.location.reload(true);
});
});
}
});
return false;
});
})(jQuery);
</script>
<script type="text/x-jquery-template" id="wfTmpl_wfCentralDisconnectPrompt">
<?php
echo wfView::create('common/modal-prompt', array(
'title' => __('Confirm Disconnect', 'wordfence'),
'message' => __('Are you sure you want to disconnect your site from Wordfence Central?', 'wordfence'),
'primaryButton' => array('id' => 'wf-central-prompt-cancel', 'label' => __('Cancel', 'wordfence'), 'link' => '#'),
'secondaryButtons' => array(array('id' => 'wf-central-prompt-disconnect', 'label' => __('Disconnect', 'wordfence'), 'link' => '#')),
))->render();
?>
</script>

View File

@@ -0,0 +1,46 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel='stylesheet' id='wordfence-main-style-css' href='<?php echo wfUtils::getBaseURL() . wfUtils::versionedAsset('css/diff.css'); ?>?ver=<?php echo WORDFENCE_VERSION; ?>' type='text/css' media='all' />
</head>
<body>
<h1><?php esc_html_e('Wordfence: Viewing File Differences', 'wordfence') ?></h1>
<p style="width: 800px; font-size: 16px; font-family: Verdana;">
<?php esc_html_e('The two panels below show a before and after view of a file on your system that has been modified. The left panel shows the original file before modification. The right panel shows your version of the file that has been modified. Use this view to determine if a file has been modified by an attacker or if this is a change that you or another trusted person made. If you are happy with the modifications you see here, then you should choose to ignore this file the next time Wordfence scans your system.', 'wordfence') ?>
</p>
<table border="0" style="margin: 0 0 20px 0;" class="summary">
<tr><td><?php esc_html_e('Filename:', 'wordfence') ?></td><td><?php echo wp_kses($_GET['file'], array()); ?></td></tr>
<tr><td><?php esc_html_e('File type:', 'wordfence') ?></td><td><?php
$cType = $_GET['cType'];
if($cType == 'core'){
esc_html_e('WordPress Core File', 'wordfence') . "</td></tr>";
} else if($cType == 'theme'){
echo esc_html__('Theme File', 'wordfence') . "</td></tr><tr><td>" .
esc_html__('Theme Name:', 'wordfence')
. "</td><td>" . wp_kses($_GET['cName'], array()) . "</td></tr><tr><td>" .
esc_html__('Theme Version:', 'wordfence') . "</td><td>" . wp_kses($_GET['cVersion'], array()) . "</td></tr>";
} else if($cType == 'plugin'){
echo esc_html__('Plugin File', 'wordfence') . "</td></tr><tr><td>" .
esc_html__('Plugin Name:', 'wordfence') . "</td><td>" . wp_kses($_GET['cName'], array()) . "</td></tr><tr><td>" .
esc_html__('Plugin Version:', 'wordfence') . "</td><td>" . wp_kses($_GET['cVersion'], array()) . "</td></tr>";
} else {
echo esc_html__('Unknown Type', 'wordfence') . "</td></tr>";
}
?>
</table>
<?php
if($diffResult){
echo $diffResult;
} else {
echo "<br />" . esc_html__('There are no differences between the original file and the file in the repository.', 'wordfence');
}
?>
<div class="diffFooter"><?php echo wp_kses(sprintf(__('&copy;&nbsp;%1$d to %2$d Wordfence &mdash; Visit <a href="http://wordfence.com/">Wordfence.com</a> for help, security updates and more.', 'wordfence'), date_i18n('Y', WORDFENCE_EPOCH), date_i18n('Y')), array('a'=>array('href'=>array()))) ?></div>
</body>
</html>

View File

@@ -0,0 +1,36 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<?php printf(
/* translators: 1. Blog name/title. 2. Date. */
__('This email was sent from your website "%1$s" by the Wordfence plugin at %2$s', 'wordfence'), $blogName, $date); ?>
<?php printf(
/* translators: URL to the WordPress admin panel. */
__('The Wordfence administrative URL for this site is: %s', 'wordfence'), wfUtils::wpAdminURL('admin.php?page=Wordfence')); ?>
<?php echo $alertMsg; ?>
<?php if($IPMsg){ echo "\n$IPMsg\n"; } ?>
<?php if(! $isPaid){ ?>
<?php esc_html_e('NOTE: You are using the free version of Wordfence. Upgrade today:
- Receive real-time Firewall and Scan engine rule updates for protection as threats emerge
- Real-time IP Blocklist blocks the most malicious IPs from accessing your site
- Country blocking
- IP reputation monitoring
- Schedule scans to run more frequently and at optimal times
- Access to Premium Support
- Discounts for multi-year and multi-license purchases
Click here to upgrade to Wordfence Premium:
https://www.wordfence.com/zz1/wordfence-signup/', 'wordfence'); ?>
<?php } ?>
--
<?php printf(
/* translators: URL to the WordPress admin panel. */
__("To change your alert options for Wordfence, visit:\n%s", 'wordfence'), $myOptionsURL); ?>
<?php printf(
/* translators: URL to the WordPress admin panel. */
__("To see current Wordfence alerts, visit:\n%s", 'wordfence'), $myHomeURL); ?>

View File

@@ -0,0 +1,164 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<?php $scanOptions = $scanController->scanOptions(); ?>
<p><?php echo esc_html(sprintf(
/* translators: URL to the site's homepage. */
__('This email was sent from your website "%s" by the Wordfence plugin.', 'wordfence'), get_bloginfo('name', 'raw'))); ?></p>
<p><?php
if (count($previousIssues) > 0) {
printf(
/* translators: 1. URL to the site's homepage. 2. Number of scan results. */
_n('Wordfence found the following new issues on "%1$s" (%2$d existing issue was also found again).',
'Wordfence found the following new issues on "%1$s" (%2$d existing issues were also found again).',
count($previousIssues),
'wordfence'),
esc_html(get_bloginfo('name', 'raw')),
count($previousIssues)
);
} else {
echo esc_html(sprintf(
/* translators: 1. URL to the site's homepage. */
__('Wordfence found the following new issues on "%1$s".', 'wordfence'),
get_bloginfo('name', 'raw')
));
}
?></p>
<p><?php echo esc_html(sprintf(
/* translators: Localized date. */
__('Alert generated at %s', 'wordfence'), wfUtils::localHumanDate())); ?></p>
<br>
<p><?php echo esc_html(sprintf(
/* translators: URL to WordPress admin panel. */
__('See the details of these scan results on your site at: %s', 'wordfence'), wfUtils::wpAdminURL('admin.php?page=WordfenceScan'))); ?></p>
<?php if ($scanOptions['scansEnabled_highSense']): ?>
<div style="margin: 12px 0;padding: 8px; background-color: #ffffe0; border: 1px solid #ffd975; border-width: 1px 1px 1px 10px;">
<em><?php esc_html_e('HIGH SENSITIVITY scanning is enabled, it may produce false positives', 'wordfence'); ?></em>
</div>
<?php endif ?>
<?php if ($timeLimitReached): ?>
<div style="margin: 12px 0;padding: 8px; background-color: #ffffe0; border: 1px solid #ffd975; border-width: 1px 1px 1px 10px;">
<em><?php echo wp_kses(sprintf(
/* translators: 1. URL to WordPress admin panel. 2. URL to WordPress admin panel. 3. URL to Wordfence support page. 4. URL to Wordfence support page. */
__('The scan was terminated early because it reached the time limit for scans. If you would like to allow your scans to run longer, you can customize the limit on the options page: <a href="%1$s">%2$s</a> or read more about scan options to improve scan speed here: <a href="%3$s">%4$s</a>', 'wordfence'), esc_attr(wfUtils::wpAdminURL('admin.php?page=WordfenceScan&subpage=scan_options#wf-scanner-options-performance')), esc_attr(wfUtils::wpAdminURL('admin.php?page=WordfenceScan&subpage=scan_options')), wfSupportController::esc_supportURL(wfSupportController::ITEM_SCAN_TIME_LIMIT), esc_html(wfSupportController::supportURL(wfSupportController::ITEM_SCAN_TIME_LIMIT))), array('a'=>array('href'=>array()))); ?></em>
</div>
<?php endif ?>
<?php
$severitySections = array(
wfIssues::SEVERITY_CRITICAL => __('Critical Problems:', 'wordfence'),
wfIssues::SEVERITY_HIGH => __('High Severity Problems:', 'wordfence'),
wfIssues::SEVERITY_MEDIUM => __('Medium Severity Problems:', 'wordfence'),
wfIssues::SEVERITY_LOW => __('Low Severity Problems:', 'wordfence'),
);
?>
<?php
foreach ($severitySections as $severityLevel => $severityLabel):
if ($severityLevel < $level) {
continue;
}
$hasIssuesAtSeverity = false;
foreach($issues as $i){ if($i['severity'] == $severityLevel){ ?>
<?php if (!$hasIssuesAtSeverity): $hasIssuesAtSeverity = true; ?>
<p><?php echo esc_html($severityLabel) ?></p>
<?php endif ?>
<p>* <?php echo htmlspecialchars($i['shortMsg']) ?></p>
<?php
if ((isset($i['tmplData']['wpRemoved']) && $i['tmplData']['wpRemoved']) || (isset($i['tmplData']['abandoned']) && $i['tmplData']['abandoned'])) {
if (isset($i['tmplData']['vulnerable']) && $i['tmplData']['vulnerable']) {
echo '<p><strong>' . esc_html__('Plugin contains an unpatched security vulnerability.', 'wordfence') . '</strong>';
if (isset($i['tmplData']['cvssScore'])) {
echo ' <br>' . esc_html__('Vulnerability Severity', 'wordfence') . ': ' . number_format($i['tmplData']['cvssScore'], 1) . '/10.0 (<span style="color:' . wfUpdateCheck::cvssScoreSeverityHexColor($i['tmplData']['cvssScore']) . '">' . wfUpdateCheck::cvssScoreSeverityLabel($i['tmplData']['cvssScore']) . '</span>)';
}
if (isset($i['tmplData']['vulnerabilityLink'])) {
echo ' <br><a href="' . $i['tmplData']['vulnerabilityLink'] . '" target="_blank" rel="nofollow noreferrer noopener">' . esc_html__('Vulnerability Information', 'wordfence') . '</a>';
}
echo '</p>';
}
}
if ($i['type'] == 'coreUnknown') {
echo '<p>' . esc_html__('The core files scan has not run because this version is not currently indexed by Wordfence. New WordPress versions may take up to a day to be indexed.', 'wordfence') . '</p>';
}
else if ($i['type'] == 'wafStatus') {
echo '<p>' . esc_html__('Firewall issues may be caused by file permission changes or other technical problems.', 'wordfence') . ' <a href="' . wfSupportController::esc_supportURL(wfSupportController::ITEM_SCAN_RESULT_WAF_DISABLED) . '" target="_blank" rel="nofollow noreferrer noopener">' . esc_html__('More Details and Instructions', 'wordfence') . '</a></p>';
}
else if ($i['type'] == 'skippedPaths') {
echo '<p>' . esc_html__('Scanning additional paths is optional and is not always necessary.', 'wordfence') . ' <a href="' . wfSupportController::esc_supportURL(wfSupportController::ITEM_SCAN_RESULT_SKIPPED_PATHS) . '" target="_blank" rel="nofollow noreferrer noopener">' . esc_html__('Learn More', 'wordfence') . '</a></p>';
}
$showWPParagraph = !empty($i['tmplData']['vulnerable']) || isset($i['tmplData']['wpURL']);
if ($showWPParagraph) {
echo '<p>';
}
if (!empty($i['tmplData']['vulnerable'])) {
if (isset($i['tmplData']['updateAvailable']) && $i['tmplData']['updateAvailable'] !== false)
echo '<strong>' . esc_html__('Update includes security-related fixes.', 'wordfence') . '</strong>';
if (isset($i['tmplData']['cvssScore'])) {
echo ' <br>' . esc_html__('Vulnerability Severity', 'wordfence') . ': ' . number_format($i['tmplData']['cvssScore'], 1) . '/10.0 (<span style="color:' . wfUpdateCheck::cvssScoreSeverityHexColor($i['tmplData']['cvssScore']) . '">' . wfUpdateCheck::cvssScoreSeverityLabel($i['tmplData']['cvssScore']) . '</span>)';
}
if (isset($i['tmplData']['vulnerabilityLink'])) {
echo ' <a href="' . $i['tmplData']['vulnerabilityLink'] . '" target="_blank" rel="nofollow noreferrer noopener">' . esc_html__('Vulnerability Information', 'wordfence') . '</a>';
}
}
if (isset($i['tmplData']['wpURL'])) {
if(!empty($i['tmplData']['vulnerable']))
echo '<br>';
echo $i['tmplData']['wpURL'] . '/#developers';
}
if ($showWPParagraph) {
echo '</p>';
}
?>
<?php
if (!empty($i['tmplData']['badURL'])):
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
$url = set_url_scheme($api->getTextImageURL($i['tmplData']['badURL']), 'https');
?>
<p><img src="<?php echo esc_url($url) ?>" alt="<?php esc_html_e('The malicious URL matched', 'wordfence') ?>" /></p>
<?php endif ?>
<?php } } ?>
<?php endforeach; ?>
<?php
$sentences = array();
if (count($previousIssues)) {
$sentences[] = sprintf(/* translators: Number of scan results */_n('%d existing issue was found again and is not shown.', '%d existing issues were found again and are not shown.', count($previousIssues), 'wordfence'), count($previousIssues));
}
if ($issuesNotShown > 0) {
$sentences[] = sprintf(/* translators: Number of scan results */ _n('%d issue was omitted from this email due to length limits.', '%d issues were omitted from this email due to length limits.', $issuesNotShown, 'wordfence'), $issuesNotShown);
$sentences[] = esc_html__('View every issue:', 'wordfence') . sprintf(' <a href="%s">%s</a>', esc_attr(wfUtils::wpAdminURL('admin.php?page=WordfenceScan')), esc_html(wfUtils::wpAdminURL('admin.php?page=WordfenceScan')));
}
if (count($sentences)) {
printf('<p>%s</p>', implode(' ', $sentences));
}
?>
<?php if(! $isPaid){ ?>
<p><?php esc_html_e('NOTE: You are using the free version of Wordfence. Upgrade today:', 'wordfence'); ?></p>
<ul>
<li><?php esc_html_e('Receive real-time Firewall and Scan engine rule updates for protection as threats emerge', 'wordfence'); ?></li>
<li><?php esc_html_e('Real-time IP Blocklist blocks the most malicious IPs from accessing your site', 'wordfence'); ?></li>
<li><?php esc_html_e('Country blocking', 'wordfence'); ?></li>
<li><?php esc_html_e('IP reputation monitoring', 'wordfence'); ?></li>
<li><?php esc_html_e('Schedule scans to run more frequently and at optimal times', 'wordfence'); ?></li>
<li><?php esc_html_e('Access to Premium Support', 'wordfence'); ?></li>
<li><?php esc_html_e('Discounts for multi-year and multi-license purchases', 'wordfence'); ?></li>
</ul>
<p><?php esc_html_e('Click here to upgrade to Wordfence Premium:', 'wordfence'); ?><br><a href="https://www.wordfence.com/zz2/wordfence-signup/">https://www.wordfence.com/zz2/wordfence-signup/</a></p>
<?php } ?>
<p><!-- ##UNSUBSCRIBE## --></p>

View File

@@ -0,0 +1,22 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<?php echo wp_kses(sprintf(
/* translators: 1. IP address. 2. Site URL. 3. Site name. */
__('Either you or someone else at IP address <b>%1$s</b> requested instructions to regain access to the website <a href="%2$s"><b>%3$s</b></a>.', 'wordfence'), esc_html($IP), esc_attr(wfUtils::getSiteBaseURL()), esc_html($siteName)), array('a'=>array('href'=>array()), 'b'=>array())); ?>
<br><br>
<?php printf(
/* translators: Localized date. */
__('Request was generated at: %s', 'wordfence'), wfUtils::localHumanDate()); ?>
<br><br>
<?php esc_html_e('If you did not request these instructions then you can safely ignore them.', 'wordfence'); ?><br>
<?php echo wp_kses(__('These instructions <b>will be valid for 30 minutes</b> from the time they were sent.', 'wordfence'), array('b'=>array())); ?>
<ul>
<li>
<a href="<?php echo $unlockHref; ?>&func=unlockMyIP"><?php esc_html_e('Click here to unlock your ability to sign-in and to access to the site.', 'wordfence'); ?></a> <?php esc_html_e('Do this if you simply need to regain access because you were accidentally locked out. If you received an "Insecure Password" message before getting locked out, you may also need to reset your password.', 'wordfence'); ?> <a href="<?php echo wfSupportController::esc_supportURL(wfSupportController::ITEM_USING_BREACH_PASSWORD); ?>"><?php esc_html_e('Learn More', 'wordfence'); ?></a>
</li>
<li>
<a href="<?php echo $unlockHref; ?>&func=unlockAllIPs"><?php esc_html_e('Click here to unblock all IP addresses.', 'wordfence'); ?></a> <?php esc_html_e('Do this if you still can\'t regain access using the link above. It causes everyone who is blocked or locked out to be able to access your site again.', 'wordfence'); ?>
</li>
<li>
<a href="<?php echo $unlockHref; ?>&func=disableRules"><?php esc_html_e('Click here to unlock all IP addresses and disable the Wordfence Firewall and Wordfence login security for all users', 'wordfence'); ?></a>. <?php esc_html_e('Do this if you keep getting locked out or blocked and can\'t access your site. You can re-enable login security and the firewall once you sign-in to the site by visiting the Wordfence Firewall menu, clicking and then turning on the firewall and login security options. If you use country blocking, you will also need to choose which countries to block.', 'wordfence'); ?>
</li>
</ul>

View File

@@ -0,0 +1,14 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<?php echo wp_kses(sprintf(
/* translators: 1. IP address. 2. Site URL. 3. Site name. */
__('Either you or someone at IP address <b>%1$s</b> requested an alert unsubscribe link for the website <a href="%2$s"><b>%3$s</b></a>.', 'wordfence'), esc_html($IP), esc_attr($siteURL), esc_html($siteName)), array('a'=>array('href'=>array()), 'b'=>array())); ?>
<br><br>
<?php echo esc_html(sprintf(
/* translators: Localized date. */
__('Request was generated at: %s', 'wordfence'), wfUtils::localHumanDate())); ?>
<br><br>
<?php esc_html_e('If you did not request this, you can safely ignore it.', 'wordfence'); ?>
<br><br>
<?php echo wp_kses(sprintf(
/* translators: URL to WordPress admin panel. */
__('<a href="%s" target="_blank">Click here<span class="screen-reader-text"> (' . esc_html__('opens in new tab', 'wordfence') . ')</span></a> to stop receiving security alerts.', 'wordfence'), wfUtils::getSiteBaseURL() . '?_wfsf=removeAlertEmail&jwt=' . $jwt), array('a'=>array('href'=>array(), 'target'=>array()))); ?>

View File

@@ -0,0 +1,264 @@
<?php
$flags = array (
'__' => '-0px -0px',
'ad' => '-16px -0px',
'ae' => '-32px -0px',
'af' => '-48px -0px',
'ag' => '-64px -0px',
'ai' => '-80px -0px',
'al' => '-96px -0px',
'am' => '-112px -0px',
'an' => '-128px -0px',
'ao' => '-144px -0px',
'ap' => '-160px -0px',
'aq' => '-176px -0px',
'ar' => '-0px -11px',
'as' => '-16px -11px',
'at' => '-32px -11px',
'au' => '-48px -11px',
'aw' => '-64px -11px',
'ax' => '-80px -11px',
'az' => '-96px -11px',
'ba' => '-112px -11px',
'bb' => '-128px -11px',
'bd' => '-144px -11px',
'be' => '-160px -11px',
'bf' => '-176px -11px',
'bg' => '-0px -22px',
'bh' => '-16px -22px',
'bi' => '-32px -22px',
'bj' => '-48px -22px',
'bl' => '-64px -22px',
'bm' => '-80px -22px',
'bn' => '-96px -22px',
'bo' => '-112px -22px',
'bq' => '-128px -22px',
'br' => '-144px -22px',
'bs' => '-160px -22px',
'bt' => '-176px -22px',
'bv' => '-0px -33px',
'bw' => '-16px -33px',
'by' => '-32px -33px',
'bz' => '-48px -33px',
'ca' => '-64px -33px',
'cc' => '-80px -33px',
'cd' => '-96px -33px',
'cf' => '-112px -33px',
'cg' => '-128px -33px',
'ch' => '-144px -33px',
'ci' => '-160px -33px',
'ck' => '-176px -33px',
'cl' => '-0px -44px',
'cm' => '-16px -44px',
'cn' => '-32px -44px',
'co' => '-48px -44px',
'cr' => '-64px -44px',
'cs' => '-80px -44px',
'cu' => '-96px -44px',
'cv' => '-112px -44px',
'cw' => '-128px -44px',
'cx' => '-144px -44px',
'cy' => '-160px -44px',
'cz' => '-176px -44px',
'de' => '-0px -55px',
'dj' => '-16px -55px',
'dk' => '-32px -55px',
'dm' => '-48px -55px',
'do' => '-64px -55px',
'dz' => '-80px -55px',
'ec' => '-96px -55px',
'ee' => '-112px -55px',
'eg' => '-128px -55px',
'eh' => '-144px -55px',
'england' => '-160px -55px',
'er' => '-176px -55px',
'es' => '-0px -66px',
'et' => '-16px -66px',
'eu' => '-32px -66px',
'fam' => '-48px -66px',
'fi' => '-64px -66px',
'fj' => '-80px -66px',
'fk' => '-96px -66px',
'fm' => '-112px -66px',
'fo' => '-128px -66px',
'fr' => '-144px -66px',
'ga' => '-160px -66px',
'gb' => '-176px -66px',
'gd' => '-0px -77px',
'ge' => '-16px -77px',
'gf' => '-32px -77px',
'gg' => '-48px -77px',
'gh' => '-64px -77px',
'gi' => '-80px -77px',
'gl' => '-96px -77px',
'gm' => '-112px -77px',
'gn' => '-128px -77px',
'gp' => '-144px -77px',
'gq' => '-160px -77px',
'gr' => '-176px -77px',
'gs' => '-0px -88px',
'gt' => '-16px -88px',
'gu' => '-32px -88px',
'gw' => '-48px -88px',
'gy' => '-64px -88px',
'hk' => '-80px -88px',
'hm' => '-96px -88px',
'hn' => '-112px -88px',
'hr' => '-128px -88px',
'ht' => '-144px -88px',
'hu' => '-160px -88px',
'id' => '-176px -88px',
'ie' => '-0px -99px',
'il' => '-16px -99px',
'im' => '-32px -99px',
'in' => '-48px -99px',
'io' => '-64px -99px',
'iq' => '-80px -99px',
'ir' => '-96px -99px',
'is' => '-112px -99px',
'it' => '-128px -99px',
'je' => '-144px -99px',
'jm' => '-160px -99px',
'jo' => '-176px -99px',
'jp' => '-0px -110px',
'ke' => '-16px -110px',
'kg' => '-32px -110px',
'kh' => '-48px -110px',
'ki' => '-64px -110px',
'km' => '-80px -110px',
'kn' => '-96px -110px',
'kp' => '-112px -110px',
'kr' => '-128px -110px',
'kw' => '-144px -110px',
'ky' => '-160px -110px',
'kz' => '-176px -110px',
'la' => '-0px -121px',
'lb' => '-16px -121px',
'lc' => '-32px -121px',
'li' => '-48px -121px',
'lk' => '-64px -121px',
'lr' => '-80px -121px',
'ls' => '-96px -121px',
'lt' => '-112px -121px',
'lu' => '-128px -121px',
'lv' => '-144px -121px',
'ly' => '-160px -121px',
'ma' => '-176px -121px',
'mc' => '-0px -132px',
'md' => '-16px -132px',
'me' => '-32px -132px',
'mf' => '-48px -132px',
'mg' => '-64px -132px',
'mh' => '-80px -132px',
'mk' => '-96px -132px',
'ml' => '-112px -132px',
'mm' => '-128px -132px',
'mn' => '-144px -132px',
'mo' => '-160px -132px',
'mp' => '-176px -132px',
'mq' => '-0px -143px',
'mr' => '-16px -143px',
'ms' => '-32px -143px',
'mt' => '-48px -143px',
'mu' => '-64px -143px',
'mv' => '-80px -143px',
'mw' => '-96px -143px',
'mx' => '-112px -143px',
'my' => '-128px -143px',
'mz' => '-144px -143px',
'na' => '-160px -143px',
'nc' => '-176px -143px',
'ne' => '-0px -154px',
'nf' => '-16px -154px',
'ng' => '-32px -154px',
'ni' => '-48px -154px',
'nl' => '-64px -154px',
'no' => '-80px -154px',
'np' => '-96px -154px',
'nr' => '-112px -154px',
'nu' => '-128px -154px',
'nz' => '-144px -154px',
'om' => '-160px -154px',
'pa' => '-176px -154px',
'pe' => '-0px -165px',
'pf' => '-16px -165px',
'pg' => '-32px -165px',
'ph' => '-48px -165px',
'pk' => '-64px -165px',
'pl' => '-80px -165px',
'pm' => '-96px -165px',
'pn' => '-112px -165px',
'pr' => '-128px -165px',
'ps' => '-144px -165px',
'pt' => '-160px -165px',
'pw' => '-176px -165px',
'py' => '-0px -176px',
'qa' => '-16px -176px',
're' => '-32px -176px',
'ro' => '-48px -176px',
'rs' => '-64px -176px',
'ru' => '-80px -176px',
'rw' => '-96px -176px',
'sa' => '-112px -176px',
'sb' => '-128px -176px',
'sc' => '-144px -176px',
'scotland' => '-160px -176px',
'sd' => '-176px -176px',
'se' => '-0px -187px',
'sg' => '-16px -187px',
'sh' => '-32px -187px',
'si' => '-48px -187px',
'sj' => '-64px -187px',
'sk' => '-80px -187px',
'sl' => '-96px -187px',
'sm' => '-112px -187px',
'sn' => '-128px -187px',
'so' => '-144px -187px',
'sr' => '-160px -187px',
'ss' => '-176px -187px',
'st' => '-0px -198px',
'sv' => '-16px -198px',
'sx' => '-32px -198px',
'sy' => '-48px -198px',
'sz' => '-64px -198px',
'tc' => '-80px -198px',
'td' => '-96px -198px',
'tf' => '-112px -198px',
'tg' => '-128px -198px',
'th' => '-144px -198px',
'tj' => '-160px -198px',
'tk' => '-176px -198px',
'tl' => '-0px -209px',
'tm' => '-16px -209px',
'tn' => '-32px -209px',
'to' => '-48px -209px',
'tr' => '-64px -209px',
'tt' => '-80px -209px',
'tv' => '-96px -209px',
'tw' => '-112px -209px',
'tz' => '-128px -209px',
'ua' => '-144px -209px',
'ug' => '-160px -209px',
'uk' => '-176px -209px',
'um' => '-0px -220px',
'un' => '-16px -220px',
'us' => '-32px -220px',
'uy' => '-48px -220px',
'uz' => '-64px -220px',
'va' => '-80px -220px',
'vc' => '-96px -220px',
've' => '-112px -220px',
'vg' => '-128px -220px',
'vi' => '-144px -220px',
'vn' => '-160px -220px',
'vu' => '-176px -220px',
'wales' => '-0px -231px',
'wf' => '-16px -231px',
'ws' => '-32px -231px',
'xk' => '-48px -231px',
'ye' => '-64px -231px',
'yt' => '-80px -231px',
'za' => '-96px -231px',
'zm' => '-112px -231px',
'zw' => '-128px -231px',
);

View File

@@ -0,0 +1,12 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<div class="wf-live-activity" data-mode="auto">
<div class="wf-live-activity-inner">
<div class="wf-live-activity-content">
<div class="wf-live-activity-title"><?php esc_html_e('Wordfence Live Activity:', 'wordfence') ?></div>
<div class="wf-live-activity-message"></div>
</div>
<?php if (wfConfig::get('liveActivityPauseEnabled')): ?>
<div class="wf-live-activity-state"><p><?php esc_html_e('Live Updates Paused &mdash; Click inside window to resume', 'wordfence') ?></p></div>
<?php endif; ?>
</div>
</div>

View File

@@ -0,0 +1,488 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
$firewall = new wfFirewall();
$scanner = wfScanner::shared();
$d = new wfDashboard();
?>
<?php
if (!wfOnboardingController::shouldShowAttempt3() && wfConfig::get('touppPromptNeeded')) {
echo wfView::create('gdpr/disabled-overlay')->render();
echo wfView::create('gdpr/banner')->render();
}
?>
<div class="wrap wordfence" id="wf-dashboard">
<div class="wf-container-fluid">
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wp-header-end"></div>
<?php
echo wfView::create('common/section-title', array(
'title' => __('Wordfence Dashboard', 'wordfence'),
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_DASHBOARD),
'helpLabelHTML' => wp_kses(__('Learn more<span class="wf-hidden-xs"> about the Dashboard</span>', 'wordfence'), array('span'=>array('class'=>array()))),
'showIcon' => true,
))->render();
?>
</div>
</div>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-block wf-active wf-add-bottom">
<div class="wf-block-content">
<ul class="wf-block-list">
<li>
<?php
echo wfView::create('dashboard/global-status', array(
'firewall' => $firewall,
'scanner' => $scanner,
'dashboard' => $d,
))->render();
?>
</li>
<li>
<ul class="wf-block-list wf-block-list-horizontal wf-block-list-nowrap wf-waf-coverage">
<li>
<?php
echo wfView::create('common/status-detail', array(
'id' => 'waf-coverage',
'percentage' => $firewall->overallStatus(),
'activeColor' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? '#ececec' : null /* automatic */),
'title' => __('Firewall', 'wordfence'),
'subtitle' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? __('WAF Currently in Learning Mode', 'wordfence') : __('Protection from known and emerging threats', 'wordfence')),
'link' => wfPage::pageURL(wfPage::PAGE_FIREWALL_OPTIONS, wfPage::PAGE_DASHBOARD),
'linkLabel' => __('Manage Firewall', 'wordfence'),
'statusTitle' => __('Firewall Status', 'wordfence'),
'statusList' => $firewall->statusList(),
'statusExtra' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? wfView::create('waf/status-tooltip-learning-mode')->render() : ''),
'helpLink' => __('https://www.wordfence.com/help/dashboard/#dashboard-status', 'wordfence'),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('common/status-detail', array(
'id' => 'wf-scanner-type',
'percentage' => $scanner->scanTypeStatus(),
'activeColor' => (!$scanner->isEnabled() ? '#ececec' : null /* automatic */),
'title' => __('Scan', 'wordfence'),
'subtitle' => __('Detection of security issues', 'wordfence'),
'link' => wfPage::pageURL(wfPage::PAGE_SCAN_OPTIONS, wfPage::PAGE_DASHBOARD),
'linkLabel' => __('Manage Scan', 'wordfence'),
'statusTitle' => __('Scan Status', 'wordfence'),
'statusList' => $scanner->scanTypeStatusList(),
'helpLink' => __('https://www.wordfence.com/help/dashboard/#dashboard-status', 'wordfence'),
))->render();
?>
</li>
<li>
<?php if (wfConfig::get('hasKeyConflict')): ?>
<?php
echo wfView::create('common/status-critical', array(
'id' => 'wf-premium-alert',
'title' => __('Premium License Conflict', 'wordfence'),
'subtitle' => __('License already in use', 'wordfence'),
'link' => 'https://www.wordfence.com/gnl1manageConflict/manage-wordfence-api-keys/',
'linkLabel' => __('Reset License', 'wordfence'),
'linkNewWindow' => true,
))->render();
?>
<?php elseif (wfConfig::get('keyType') == wfLicense::KEY_TYPE_PAID_EXPIRED): ?>
<?php
echo wfView::create('common/status-critical', array(
'id' => 'wf-premium-alert',
'title' => __('Premium Protection Disabled', 'wordfence'),
'subtitle' => __('License is expired', 'wordfence'),
'link' => 'https://www.wordfence.com/gnl1renewExpired/manage-wordfence-api-keys/',
'linkLabel' => __('Renew License', 'wordfence'),
'linkNewWindow' => true,
))->render();
?>
<?php elseif (wfConfig::get('keyType') == wfLicense::KEY_TYPE_PAID_DELETED): ?>
<?php
echo wfView::create('common/status-critical', array(
'id' => 'wf-premium-alert',
'title' => __('Premium Protection Disabled', 'wordfence'),
'subtitleHtml' => wp_kses(__('The license you were using has been removed from your account. Please reach out to <a href="mailto:billing@wordfence.com">billing@wordfence.com</a> or create a Premium support case at <a href="https://support.wordfence.com/support/tickets" target="_blank">https://support.wordfence.com/support/tickets<span class="screen-reader-text"> (opens in new tab)</span></a> for more information. Our staff is happy to help.', 'wordfence'), array('a'=>array('href'=>array(), 'target'=>array()), 'span'=>array('class'=>array()))),
'link' => null,
'linkLabel' => null
))->render();
?>
<?php elseif (wfConfig::get('keyType') == wfLicense::KEY_TYPE_FREE || wfConfig::get('keyType') === false): ?>
<div>
<p><h3><?php esc_html_e('Premium Protection Disabled', 'wordfence'); ?></h3></p>
<p><?php esc_html_e('As a free Wordfence user, you are currently using the Community version of the Threat Defense Feed. Premium users are protected by additional firewall rules and malware signatures. Upgrade to Premium today to improve your protection.', 'wordfence'); ?></p>
<p><a class="wf-btn wf-btn-primary wf-btn-callout-subtle" href="https://www.wordfence.com/gnl1dashboardUpgrade/products/wordfence-premium/" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Upgrade to Premium', 'wordfence'); ?></a>&nbsp;&nbsp;<a class="wf-btn wf-btn-callout-subtle wf-btn-default" href="https://www.wordfence.com/gnl1dashboardLearn/products/pricing/" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Learn More', 'wordfence'); ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a></p>
</div>
<?php elseif (wfConfig::get('keyExpDays') < 30 && (wfConfig::get('premiumAutoRenew', null) === '0' || wfConfig::get('premiumAutoRenew', null) === 0)): ?>
<?php
echo wfView::create('common/status-critical', array(
'id' => 'wf-premium-alert',
'title' => __('Premium License Expiring', 'wordfence'),
'subtitle' => __('Auto-renew is disabled', 'wordfence'),
'link' => 'https://www.wordfence.com/gnl1renewExpiring/manage-wordfence-api-keys/',
'linkLabel' => __('Renew License', 'wordfence'),
'linkNewWindow' => true,
))->render();
?>
<?php elseif (wfConfig::get('keyExpDays') < 30): ?>
<?php
if (wfConfig::get('premiumPaymentExpiring')) {
$title = __('Payment Method Expiring', 'wordfence');
}
else if (wfConfig::get('premiumPaymentExpired')) {
$title = __('Payment Method Expired', 'wordfence');
}
else if (wfConfig::get('premiumPaymentMissing')) {
$title = __('Payment Method Missing', 'wordfence');
}
else if (wfConfig::get('premiumPaymentHold')) {
$title = __('Payment Method Invalid', 'wordfence');
}
if (isset($title)) {
$days = floor(((int) wfConfig::get('premiumNextRenew') - time()) / 86400);
if ($days <= 0) {
$subtitle = __('License renews today', 'wordfence');
}
else if ($days == 1) {
$subtitle = __('License renews tomorrow', 'wordfence');
}
else {
$subtitle = sprintf(
/* translators: Number of days */
__('License renews in %d days', 'wordfence'), $days);
}
echo wfView::create('dashboard/status-payment-expiring', array(
'id' => 'wf-premium-alert',
'title' => $title,
'subtitle' => $subtitle,
'link' => 'https://www.wordfence.com/gnl1renewExpiring/manage-wordfence-api-keys/',
'linkLabel' => __('Update Payment Method', 'wordfence'),
'linkNewWindow' => true,
))->render();
}
else {
$days = floor(((int) wfConfig::get('premiumNextRenew') - time()) / 86400);
if ($days == 0) {
$subtitle = __('License renews today', 'wordfence');
}
else if ($days == 1) {
$subtitle = __('License renews in 1 day', 'wordfence');
}
else {
$subtitle = sprintf(__('License renews in %d days', 'wordfence'), $days);
}
echo wfView::create('dashboard/status-renewing', array(
'id' => 'wf-premium-alert',
'title' => __('Premium License Expiring', 'wordfence'),
'subtitle' => $subtitle,
'link' => 'https://www.wordfence.com/gnl1reviewExpiring/manage-wordfence-api-keys/',
'linkLabel' => __('Review Payment Method', 'wordfence'),
'linkNewWindow' => true,
))->render();
}
?>
<?php elseif (wfLicense::current()->isPaidAndCurrent()): ?>
<div class="wf-block-labeled-value wf-protection-status wf-protection-status-<?php echo esc_attr($firewall->ruleMode()); ?>">
<div class="wf-block-labeled-value-value"><i class="wf-fa wf-fa-check" aria-hidden="true"></i></div>
<div class="wf-block-labeled-value-label"><?php echo esc_html(sprintf(__('%s Enabled', 'wordfence'), wfLicense::current()->getTypeLabel(true))); ?></div>
<?php if (wfLicense::current()->isBelowResponse()): ?>
<p>
<?php if (wfLicense::current()->isBelowCare()): ?>
<a href="https://www.wordfence.com/gnl1dashboardLearnCareResponse/products/pricing/"><?php esc_html_e('Learn about Wordfence Care and Wordfence Response', 'wordfence') ?></a>
<?php else: ?>
<a href="https://www.wordfence.com/gnl1dashboardLearnResponse/products/wordfence-response/"><?php esc_html_e('Learn about Wordfence Response', 'wordfence') ?></a>
<?php endif ?>
</p>
<?php endif ?>
</div>
<?php endif; ?>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
<!-- begin notifications -->
<?php include(dirname(__FILE__) . '/dashboard/widget_notifications.php'); ?>
<!-- end notifications -->
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-block wf-active wf-add-bottom">
<div class="wf-block-content">
<ul class="wf-block-list">
<li>
<ul class="wf-block-list wf-block-list-horizontal wf-dashboard-navigation">
<li>
<?php
echo wfView::create('common/block-navigation-option', array(
'id' => 'wf-dashboard-option-tools',
'img' => 'tools.svg',
'title' => __('Tools', 'wordfence'),
'subtitle' => __('Live Traffic, Whois Lookup, Import/Export, and Diagnostics', 'wordfence'),
'link' => network_admin_url('admin.php?page=WordfenceTools'),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('common/block-navigation-option', array(
'id' => 'wf-dashboard-option-support',
'img' => 'support.svg',
'title' => __('Help', 'wordfence'),
'subtitle' => __('Find the documentation and help you need', 'wordfence'),
'link' => network_admin_url('admin.php?page=WordfenceSupport'),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('common/block-navigation-option', array(
'id' => 'wf-dashboard-option-options',
'img' => 'options.svg',
'title' => __('Global Options', 'wordfence'),
'subtitle' => __('Manage global options for Wordfence such as alerts, premium status, and more', 'wordfence'),
'link' => network_admin_url('admin.php?page=Wordfence&subpage=global_options'),
))->render();
?>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="wf-row">
<div class="wf-col-xs-12 wf-col-lg-6 wf-col-lg-half-padding-right">
<!-- begin firewall summary site -->
<?php include(dirname(__FILE__) . '/dashboard/widget_localattacks.php'); ?>
<!-- end firewall summary site -->
</div> <!-- end content block -->
<div class="wf-col-xs-12 wf-col-lg-6 wf-col-lg-half-padding-left">
<!-- begin total attacks blocked network -->
<?php include(dirname(__FILE__) . '/dashboard/widget_networkattacks.php'); ?>
<!-- end total attacks blocked network -->
</div> <!-- end content block -->
</div> <!-- end row -->
</div> <!-- end container -->
</div>
<?php if (wfOnboardingController::willShowNewTour(wfOnboardingController::TOUR_DASHBOARD)): ?>
<script type="application/javascript">
(function($) {
$(function() {
WFAD.tour1 = function() {
WFAD.tour('wfNewTour1', 'wfStatusTourMarker', 'top', 'left', null, WFAD.tour2);
};
WFAD.tour2 = function() {
WFAD.tour('wfNewTour2', 'waf-coverage', 'top', 'left', WFAD.tour1, WFAD.tour3);
};
WFAD.tour3 = function() {
WFAD.tour('wfNewTour3', 'wf-dashboard-option-options', 'right', 'right', WFAD.tour2, WFAD.tourComplete);
};
WFAD.tourComplete = function() { WFAD.tourFinish('<?php echo esc_attr(wfOnboardingController::TOUR_DASHBOARD); ?>'); };
<?php if (wfOnboardingController::shouldShowNewTour(wfOnboardingController::TOUR_DASHBOARD) && !isset($_GET['onboarding'])): ?>
if (!WFAD.isSmallScreen) { WFAD.tour1(); }
<?php endif; ?>
});
})(jQuery);
</script>
<script type="text/x-jquery-template" id="wfNewTour1">
<div>
<h3><?php esc_html_e('This is your Dashboard', 'wordfence'); ?></h3>
<p><?php esc_html_e('The Wordfence Dashboard provides valuable insights into the current state of your site\'s security. You\'ll find useful data summarized here as well as important status updates and notifications.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li class="wf-active">&bullet;</li>
<li>&bullet;</li>
<li>&bullet;</li>
</ul>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Next', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<script type="text/x-jquery-template" id="wfNewTour2">
<div>
<h3><?php esc_html_e('Easily Monitor Your Wordfence Protection', 'wordfence'); ?></h3>
<p><?php esc_html_e('Each feature contains a status that reminds you what\'s enabled, disabled or needs attention. The Notifications section will highlight actions you need to take.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li>&bullet;</li>
<li class="wf-active">&bullet;</li>
<li>&bullet;</li>
</ul>
<div id="wf-tour-previous"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-default" role="button"><?php esc_html_e('Previous', 'wordfence'); ?></a></div>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Next', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<script type="text/x-jquery-template" id="wfNewTour3">
<div>
<h3><?php esc_html_e('Global Wordfence Options', 'wordfence'); ?></h3>
<p class="wf-center"><svg viewBox="0 0 100.11 100.11" class="wf-icon"><path d="M99.59,41.42a2.06,2.06,0,0,0-1.37-.82L86.3,38.78a39.34,39.34,0,0,0-2.67-6.39q1.17-1.63,3.52-4.6t3.32-4.33A2.52,2.52,0,0,0,91,22a2.1,2.1,0,0,0-.46-1.43Q88.18,17.2,79.78,9.45a2.52,2.52,0,0,0-1.63-.65,2.12,2.12,0,0,0-1.57.59l-9.25,7a40.09,40.09,0,0,0-5.87-2.41L59.64,2a1.92,1.92,0,0,0-.75-1.4A2.46,2.46,0,0,0,57.29,0H42.82a2.19,2.19,0,0,0-2.34,1.82,106,106,0,0,0-1.89,12.12,37.62,37.62,0,0,0-5.93,2.48l-9-7A2.78,2.78,0,0,0,22,8.8q-1.44,0-6.16,4.66a64.88,64.88,0,0,0-6.42,7A2.75,2.75,0,0,0,8.8,22a2.44,2.44,0,0,0,.65,1.56q4.37,5.28,7,9a32.38,32.38,0,0,0-2.54,6L1.76,40.34a2,2,0,0,0-1.24.85A2.5,2.5,0,0,0,0,42.69V57.16a2.44,2.44,0,0,0,.52,1.53,2,2,0,0,0,1.37.82l11.93,1.76a31.91,31.91,0,0,0,2.67,6.45Q15.31,69.35,13,72.31T9.65,76.65a2.54,2.54,0,0,0-.07,3q2.54,3.52,10.75,11a2.25,2.25,0,0,0,1.63.71,2.35,2.35,0,0,0,1.63-.59l9.19-7a40.54,40.54,0,0,0,5.87,2.41l1.82,12a1.92,1.92,0,0,0,.75,1.4,2.45,2.45,0,0,0,1.6.55H57.29a2.2,2.2,0,0,0,2.35-1.82,107.41,107.41,0,0,0,1.89-12.12,37.19,37.19,0,0,0,5.93-2.48l9,7a3.18,3.18,0,0,0,1.69.59q1.43,0,6.13-4.62a65.86,65.86,0,0,0,6.45-7,2.16,2.16,0,0,0,.59-1.5,2.51,2.51,0,0,0-.65-1.63q-4.69-5.74-7-9a41.57,41.57,0,0,0,2.54-5.93l12.06-1.82a2,2,0,0,0,1.3-.85,2.52,2.52,0,0,0,.52-1.5V43a2.46,2.46,0,0,0-.52-1.53ZM61.85,61.86a16.08,16.08,0,0,1-11.8,4.89A16.69,16.69,0,0,1,33.37,50.06,16.69,16.69,0,0,1,50.06,33.37,16.69,16.69,0,0,1,66.74,50.06a16.08,16.08,0,0,1-4.89,11.8Zm0,0"></path></svg></p>
<p><?php echo wp_kses(__('You\'ll find this icon throughout the plugin. Clicking it will show you the options and features for each section of Wordfence. From the dashboard, you can find the <strong>Global Options</strong> for Wordfence such as alerts, automatic updates, and managing your site\'s Premium License.', 'wordfence'), array('strong'=>array())); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li>&bullet;</li>
<li>&bullet;</li>
<li class="wf-active">&bullet;</li>
</ul>
<div id="wf-tour-previous"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-default" role="button"><?php esc_html_e('Previous', 'wordfence'); ?></a></div>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Got it', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<?php endif; ?>
<?php if (wfOnboardingController::willShowUpgradeTour(wfOnboardingController::TOUR_DASHBOARD)): ?>
<script type="application/javascript">
(function($) {
$(function() {
WFAD.tour1 = function() {
WFAD.tour('wfUpgradeTour1', 'wfStatusTourMarker', 'top', 'left', null, WFAD.tour2);
};
WFAD.tour2 = function() {
WFAD.tour('wfUpgradeTour2', 'waf-coverage', 'top', 'left', WFAD.tour1, WFAD.tour3);
};
WFAD.tour3 = function() {
WFAD.tour('wfUpgradeTour3', 'wf-dashboard-option-options', 'right', 'right', WFAD.tour2, WFAD.tour4);
};
WFAD.tour4 = function() {
WFAD.tour('wfUpgradeTour4', 'toplevel_page_Wordfence', 'left', 'left', WFAD.tour3, WFAD.tourComplete);
};
WFAD.tourComplete = function() { WFAD.tourFinish('<?php echo esc_attr(wfOnboardingController::TOUR_DASHBOARD); ?>'); };
<?php if (wfOnboardingController::shouldShowUpgradeTour(wfOnboardingController::TOUR_DASHBOARD) && !isset($_GET['onboarding'])): ?>
if (!WFAD.isSmallScreen) { WFAD.tour1(); }
<?php endif; ?>
});
})(jQuery);
</script>
<script type="text/x-jquery-template" id="wfUpgradeTour1">
<div>
<h3><?php printf(
/* translators: Wordfence version. */
esc_html__('You have successfully updated to Wordfence %s', 'wordfence'), WORDFENCE_VERSION); ?></h3>
<p><?php esc_html_e('This update includes a number of significant interface changes. We\'d like to walk you through some of them, but you can bypass the tour for a section at any time by closing the dialogs.', 'wordfence'); ?></p>
<p><?php echo wp_kses(__('We welcome your feedback and comments at <a href="mailto:feedback@wordfence.com">feedback@wordfence.com</a>. For a deeper dive on all of the changes, <a href="https://www.wordfence.com/blog/2018/01/introducing-wordfence-7/" target="_blank" rel="noopener noreferrer">click here<span class="screen-reader-text"> (opens in new tab)</span></a>.', 'wordfence'), array('a'=>array('href'=>array(), 'target'=>array()), 'span'=>array('class'=>array()))); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li class="wf-active">&bullet;</li>
<li>&bullet;</li>
<li>&bullet;</li>
<li>&bullet;</li>
</ul>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Next', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<script type="text/x-jquery-template" id="wfUpgradeTour2">
<div>
<h3><?php esc_html_e('Monitor Your Wordfence Protection', 'wordfence'); ?></h3>
<p><?php esc_html_e('Each feature contains a status percentage reminding you at a high level of what\'s enabled, disabled, or needing your attention. The Notifications section highlights actions you need to take.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li>&bullet;</li>
<li class="wf-active">&bullet;</li>
<li>&bullet;</li>
<li>&bullet;</li>
</ul>
<div id="wf-tour-previous"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-default" role="button"><?php esc_html_e('Previous', 'wordfence'); ?></a></div>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Next', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<script type="text/x-jquery-template" id="wfUpgradeTour3">
<div>
<h3><?php esc_html_e('Global Wordfence Options', 'wordfence'); ?></h3>
<p class="wf-center"><svg viewBox="0 0 100.11 100.11" class="wf-icon"><path d="M99.59,41.42a2.06,2.06,0,0,0-1.37-.82L86.3,38.78a39.34,39.34,0,0,0-2.67-6.39q1.17-1.63,3.52-4.6t3.32-4.33A2.52,2.52,0,0,0,91,22a2.1,2.1,0,0,0-.46-1.43Q88.18,17.2,79.78,9.45a2.52,2.52,0,0,0-1.63-.65,2.12,2.12,0,0,0-1.57.59l-9.25,7a40.09,40.09,0,0,0-5.87-2.41L59.64,2a1.92,1.92,0,0,0-.75-1.4A2.46,2.46,0,0,0,57.29,0H42.82a2.19,2.19,0,0,0-2.34,1.82,106,106,0,0,0-1.89,12.12,37.62,37.62,0,0,0-5.93,2.48l-9-7A2.78,2.78,0,0,0,22,8.8q-1.44,0-6.16,4.66a64.88,64.88,0,0,0-6.42,7A2.75,2.75,0,0,0,8.8,22a2.44,2.44,0,0,0,.65,1.56q4.37,5.28,7,9a32.38,32.38,0,0,0-2.54,6L1.76,40.34a2,2,0,0,0-1.24.85A2.5,2.5,0,0,0,0,42.69V57.16a2.44,2.44,0,0,0,.52,1.53,2,2,0,0,0,1.37.82l11.93,1.76a31.91,31.91,0,0,0,2.67,6.45Q15.31,69.35,13,72.31T9.65,76.65a2.54,2.54,0,0,0-.07,3q2.54,3.52,10.75,11a2.25,2.25,0,0,0,1.63.71,2.35,2.35,0,0,0,1.63-.59l9.19-7a40.54,40.54,0,0,0,5.87,2.41l1.82,12a1.92,1.92,0,0,0,.75,1.4,2.45,2.45,0,0,0,1.6.55H57.29a2.2,2.2,0,0,0,2.35-1.82,107.41,107.41,0,0,0,1.89-12.12,37.19,37.19,0,0,0,5.93-2.48l9,7a3.18,3.18,0,0,0,1.69.59q1.43,0,6.13-4.62a65.86,65.86,0,0,0,6.45-7,2.16,2.16,0,0,0,.59-1.5,2.51,2.51,0,0,0-.65-1.63q-4.69-5.74-7-9a41.57,41.57,0,0,0,2.54-5.93l12.06-1.82a2,2,0,0,0,1.3-.85,2.52,2.52,0,0,0,.52-1.5V43a2.46,2.46,0,0,0-.52-1.53ZM61.85,61.86a16.08,16.08,0,0,1-11.8,4.89A16.69,16.69,0,0,1,33.37,50.06,16.69,16.69,0,0,1,50.06,33.37,16.69,16.69,0,0,1,66.74,50.06a16.08,16.08,0,0,1-4.89,11.8Zm0,0"></path></svg></p>
<p><?php esc_html_e('Manage your Wordfence license, see alerts and automatic plugin updates, and import/export your settings.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li>&bullet;</li>
<li>&bullet;</li>
<li class="wf-active">&bullet;</li>
<li>&bullet;</li>
</ul>
<div id="wf-tour-previous"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-default" role="button"><?php esc_html_e('Previous', 'wordfence'); ?></a></div>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Next', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<script type="text/x-jquery-template" id="wfUpgradeTour4">
<div>
<h3><?php esc_html_e('Updated Navigation', 'wordfence'); ?></h3>
<p><?php echo wp_kses(__('The main navigation no longer includes an <strong>Options</strong> link. Options are now accessed via the <strong>Options</strong> link on each feature\'s main page. Live Traffic is now located in the Tools section, and blocking is found under the Firewall. Shortcuts to add a <strong>Blocking</strong> link back to the main navigation are available under Blocking options.', 'wordfence'), array('strong'=>array())); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li>&bullet;</li>
<li>&bullet;</li>
<li>&bullet;</li>
<li class="wf-active">&bullet;</li>
</ul>
<div id="wf-tour-previous"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-default" role="button"><?php esc_html_e('Previous', 'wordfence'); ?></a></div>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Got it', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<?php endif; ?>
<?php
$hostSetting = false;
$recordAll = wfConfig::liveTrafficEnabled($hostSetting);
if ($recordAll && !$hostSetting && !wfUtils::truthyToBoolean(wfConfig::get('switchLiveTrafficSecurityOnlyChoice'))):
?>
<script type="application/javascript">
(function($) {
$(function() {
var prompt = $('#wfLiveTrafficMigration').tmpl();
var promptHTML = $("<div />").append(prompt).html();
WFAD.colorboxHTML((WFAD.isSmallScreen ? '300px' : '700px'), promptHTML, {overlayClose: false, closeButton: false, className: 'wf-modal', onComplete: function() {
$('#wf-livetrafficmigrate-no').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
wordfenceExt.switchLiveTrafficSecurityOnlyChoice('no');
WFAD.colorboxClose();
});
$('#wf-livetrafficmigrate-yes').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
wordfenceExt.switchLiveTrafficSecurityOnlyChoice('yes');
WFAD.colorboxClose();
});
}});
});
})(jQuery);
</script>
<script type="text/x-jquery-template" id="wfLiveTrafficMigration">
<?php
echo wfView::create('common/modal-prompt', array(
'title' => __('Recommended Settings Change', 'wordfence'),
'messageHTML' => '<p>' . esc_html__('Greetings! The default configuration for Wordfence Live Traffic has changed. The new default saves only logins and blocked requests, while this site is currently recording all traffic. Would you like to change to the new default?', 'wordfence') . '</p>' . (!wfRateLimit::identicalHumanBotRateLimits() ? '<p>' . __('Rate limiting based on type of request (human vs crawler) may be less accurate because this prevents loading the extra JavaScript used for that identification.', 'wordfence') . '</p>' : ''),
'primaryButton' => array('id' => 'wf-livetrafficmigrate-yes', 'label' => __('Yes Please', 'wordfence'), 'link' => '#', 'type' => 'wf-btn-primary'),
'secondaryButtons' => array(
array('id' => 'wf-livetrafficmigrate-no', 'label' => __('No Thanks', 'wordfence'), 'link' => '#', 'type' => 'wf-btn-default'),
array('id' => 'wf-livetrafficmigrate-learn', 'label' => __('Learn More', 'wordfence'), 'link' => wfSupportController::supportURL(wfSupportController::ITEM_NOTICE_SWITCH_LIVE_TRAFFIC), 'type' => 'wf-btn-default', 'target' => '_blank', 'rel' => 'noopener noreferrer'),
),
))->render();
?>
</script>
<?php endif; ?>

View File

@@ -0,0 +1,306 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
$dashboardURL = network_admin_url('admin.php?page=Wordfence');
$firewall = new wfFirewall();
$scanner = wfScanner::shared();
$d = new wfDashboard();
?>
<script type="application/javascript">
(function($) {
$(function() {
document.title = "<?php esc_attr_e('Wordfence Global Options', 'wordfence'); ?>" + " \u2039 " + WFAD.basePageName;
//Hash-based option block linking
if (window.location.hash) {
var hashes = WFAD.parseHashes();
var hash = hashes[hashes.length - 1];
var block = $('.wf-block[data-persistence-key="' + hash + '"]');
if (block) {
if (!block.hasClass('wf-active')) {
block.find('.wf-block-content').slideDown({
always: function() {
block.addClass('wf-active');
$('html, body').animate({
scrollTop: block.offset().top - 100
}, 1000);
}
});
WFAD.ajax('wordfence_saveDisclosureState', {name: block.data('persistenceKey'), state: true}, function() {});
}
else {
$('html, body').animate({
scrollTop: block.offset().top - 100
}, 1000);
}
history.replaceState('', document.title, window.location.pathname + window.location.search);
}
}
});
})(jQuery);
</script>
<div class="wf-options-controls">
<div class="wf-row">
<div class="wf-col-xs-12">
<?php
echo wfView::create('options/block-controls', array(
'backLink' => $dashboardURL,
'backLabelHTML' => wp_kses(__('Back<span class="wf-hidden-xs"> to Dashboard</span>', 'wordfence'), array('span'=>array('class'=>array()))),
'restoreDefaultsSection' => wfConfig::OPTIONS_TYPE_GLOBAL,
'restoreDefaultsMessage' => __('Are you sure you want to restore the default global settings? This will undo any custom changes you have made to the options on this page. Your configured license key and alert emails will not be changed.', 'wordfence'),
))->render();
?>
</div>
</div>
</div>
<div class="wf-options-controls-spacer"></div>
<?php
if (!wfOnboardingController::shouldShowAttempt3() && wfConfig::get('touppPromptNeeded')) {
echo wfView::create('gdpr/disabled-overlay')->render();
echo wfView::create('gdpr/banner')->render();
}
?>
<div class="wrap wordfence" id="wf-global-options">
<div class="wf-container-fluid">
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wp-header-end"></div>
</div>
</div>
<div class="wf-row">
<div class="<?php echo wfStyle::contentClasses(); ?>">
<div id="waf-options" class="wf-fixed-tab-content">
<?php
echo wfView::create('common/section-title', array(
'title' => __('Wordfence Global Options', 'wordfence'),
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_DASHBOARD_OPTIONS),
'helpLabelHTML' => wp_kses(__('Learn more<span class="wf-hidden-xs"> about Global Options</span>', 'wordfence'), array('span'=>array('class'=>array()))),
'showIcon' => true,
))->render();
?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-block wf-active">
<div class="wf-block-content">
<ul class="wf-block-list">
<li>
<ul class="wf-block-list wf-block-list-horizontal wf-block-list-nowrap wf-waf-coverage">
<li>
<?php
echo wfView::create('common/status-detail', array(
'id' => 'waf-coverage',
'percentage' => $firewall->overallStatus(),
'activeColor' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? '#ececec' : null /* automatic */),
'title' => __('Firewall', 'wordfence'),
'subtitle' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? __('WAF Currently in Learning Mode', 'wordfence') : __('Protection from known and emerging threats', 'wordfence')),
'link' => wfPage::pageURL(wfPage::PAGE_FIREWALL_OPTIONS, wfPage::PAGE_DASHBOARD_OPTIONS),
'linkLabel' => __('Manage Firewall', 'wordfence'),
'statusTitle' => __('Firewall Status', 'wordfence'),
'statusList' => $firewall->statusList(),
'statusExtra' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? wfView::create('waf/status-tooltip-learning-mode')->render() : ''),
'helpLink' => __('https://www.wordfence.com/help/dashboard/#dashboard-status', 'wordfence'),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('common/status-detail', array(
'id' => 'wf-scanner-type',
'percentage' => $scanner->scanTypeStatus(),
'activeColor' => (!$scanner->isEnabled() ? '#ececec' : null /* automatic */),
'title' => __('Scan', 'wordfence'),
'subtitle' => __('Detection of security issues', 'wordfence'),
'link' => wfPage::pageURL(wfPage::PAGE_SCAN_OPTIONS, wfPage::PAGE_DASHBOARD_OPTIONS),
'linkLabel' => __('Manage Scan', 'wordfence'),
'statusTitle' => __('Scan Status', 'wordfence'),
'statusList' => $scanner->scanTypeStatusList(),
'helpLink' => __('https://www.wordfence.com/help/dashboard/#dashboard-status', 'wordfence'),
))->render();
?>
</li>
<li>
<?php if (wfConfig::get('hasKeyConflict')): ?>
<?php
echo wfView::create('common/status-critical', array(
'id' => 'wf-premium-alert',
'title' => __('Premium License Conflict', 'wordfence'),
'subtitle' => __('License already in use', 'wordfence'),
'link' => 'https://www.wordfence.com/gnl1manageConflict/manage-wordfence-api-keys/',
'linkLabel' => __('Reset License', 'wordfence'),
'linkNewWindow' => true,
))->render();
?>
<?php elseif (wfConfig::get('keyType') == wfLicense::KEY_TYPE_PAID_EXPIRED): ?>
<?php
echo wfView::create('common/status-critical', array(
'id' => 'wf-premium-alert',
'title' => __('Premium Protection Disabled', 'wordfence'),
'subtitle' => __('License is expired', 'wordfence'),
'link' => 'https://www.wordfence.com/gnl1renewExpired/manage-wordfence-api-keys/',
'linkLabel' => __('Renew License', 'wordfence'),
'linkNewWindow' => true,
))->render();
?>
<?php elseif (wfConfig::get('keyType') == wfLicense::KEY_TYPE_PAID_DELETED): ?>
<?php
echo wfView::create('common/status-critical', array(
'id' => 'wf-premium-alert',
'title' => __('Premium Protection Disabled', 'wordfence'),
'subtitleHtml' => wp_kses(__('The license you were using has been removed from your account. Please reach out to <a href="mailto:billing@wordfence.com">billing@wordfence.com</a> or create a Premium support case at <a href="https://support.wordfence.com/support/tickets" target="_blank">https://support.wordfence.com/support/tickets<span class="screen-reader-text"> (opens in new tab)</span></a> for more information. Our staff is happy to help.', 'wordfence'), array('a'=>array('href'=>array(), 'target'=>array()), 'span'=>array('class'=>array()))),
'link' => null,
'linkLabel' => null
))->render();
?>
<?php elseif (wfConfig::get('keyType') == wfLicense::KEY_TYPE_FREE || wfConfig::get('keyType') === false): ?>
<div>
<p><h3><?php esc_html_e('Premium Protection Disabled', 'wordfence'); ?></h3></p>
<p><?php esc_html_e('As a free Wordfence user, you are currently using the Community version of the Threat Defense Feed. Premium users are protected by additional firewall rules and malware signatures. Upgrade to Premium today to improve your protection.', 'wordfence'); ?></p>
<p><a class="wf-btn wf-btn-primary wf-btn-callout-subtle" href="https://www.wordfence.com/gnl1dashboardOptionsUpgrade/products/wordfence-premium/" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Upgrade to Premium', 'wordfence'); ?></a>&nbsp;&nbsp;<a class="wf-btn wf-btn-callout-subtle wf-btn-default" href="https://www.wordfence.com/gnl1dashboardOptionsLearn/products/pricing/" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Learn More', 'wordfence'); ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a></p>
</div>
<?php elseif (wfConfig::get('keyExpDays') < 30 && (wfConfig::get('premiumAutoRenew', null) === '0' || wfConfig::get('premiumAutoRenew', null) === 0)): ?>
<?php
echo wfView::create('common/status-critical', array(
'id' => 'wf-premium-alert',
'title' => __('Premium License Expiring', 'wordfence'),
'subtitle' => __('Auto-renew is disabled', 'wordfence'),
'link' => 'https://www.wordfence.com/gnl1renewExpiring/manage-wordfence-api-keys/',
'linkLabel' => __('Renew License', 'wordfence'),
'linkNewWindow' => true,
))->render();
?>
<?php elseif (wfConfig::get('keyExpDays') < 30): ?>
<?php
if (wfConfig::get('premiumPaymentExpiring')) {
$title = __('Payment Method Expiring', 'wordfence');
}
else if (wfConfig::get('premiumPaymentExpired')) {
$title = __('Payment Method Expired', 'wordfence');
}
else if (wfConfig::get('premiumPaymentMissing')) {
$title = __('Payment Method Missing', 'wordfence');
}
else if (wfConfig::get('premiumPaymentHold')) {
$title = __('Payment Method Invalid', 'wordfence');
}
if (isset($title)) {
$days = floor(((int) wfConfig::get('premiumNextRenew') - time()) / 86400);
if ($days <= 0) {
$days = __('today', 'wordfence');
}
else if ($days == 1) {
$days = __('tomorrow', 'wordfence');
}
else {
$days = sprintf(/* translators: Number of days */ __('in %d days', 'wordfence'), $days);
}
echo wfView::create('dashboard/status-payment-expiring', array(
'id' => 'wf-premium-alert',
'title' => $title,
'subtitle' => sprintf(__('License renews %s', 'wordfence'), $days),
'link' => 'https://www.wordfence.com/gnl1renewExpiring/manage-wordfence-api-keys/',
'linkLabel' => __('Update Payment Method', 'wordfence'),
'linkNewWindow' => true,
))->render();
}
else {
$days = floor(((int) wfConfig::get('premiumNextRenew') - time()) / 86400);
if ($days == 0) {
$days = __('today', 'wordfence');
}
else if ($days == 1) {
$days = __('in 1 day', 'wordfence');
}
else {
$days = sprintf(__('in %d days', 'wordfence'), $days);
}
echo wfView::create('dashboard/status-renewing', array(
'id' => 'wf-premium-alert',
'title' => __('Premium License Expiring', 'wordfence'),
'subtitle' => sprintf(__('License renews %s', 'wordfence'), $days),
'link' => 'https://www.wordfence.com/gnl1reviewExpiring/manage-wordfence-api-keys/',
'linkLabel' => __('Review Payment Method', 'wordfence'),
'linkNewWindow' => true,
))->render();
}
?>
<?php elseif (wfConfig::get('keyType') == wfLicense::KEY_TYPE_PAID_CURRENT): ?>
<div class="wf-block-labeled-value wf-protection-status wf-protection-status-<?php echo esc_attr($firewall->ruleMode()); ?>">
<div class="wf-block-labeled-value-value"><i class="wf-fa wf-fa-check" aria-hidden="true"></i></div>
<div class="wf-block-labeled-value-label"><?php echo esc_html(sprintf(__('%s Enabled', 'wordfence'), wfLicense::current()->getPrefixedTypeLabel())); ?></div>
<?php if (wfLicense::current()->isBelowResponse()): ?>
<p>
<?php if (wfLicense::current()->isBelowCare()): ?>
<a href="https://www.wordfence.com/gnl1dashboardLearnCareResponse/products/pricing/"><?php esc_html_e('Learn about Wordfence Care and Wordfence Response', 'wordfence') ?></a>
<?php else: ?>
<a href="https://www.wordfence.com/gnl1dashboardLearnResponse/products/wordfence-response/"><?php esc_html_e('Learn about Wordfence Response', 'wordfence') ?></a>
<?php endif ?>
</p>
<?php endif ?>
</div>
<?php endif; ?>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
<?php
echo wfView::create('dashboard/options-group-license', array(
'stateKey' => 'global-options-license',
))->render();
echo wfView::create('dashboard/options-group-view-customization', array(
'stateKey' => 'global-options-view-customization',
))->render();
echo wfView::create('dashboard/options-group-general', array(
'stateKey' => 'global-options-general',
))->render();
echo wfView::create('dashboard/options-group-dashboard', array(
'stateKey' => 'global-options-dashboard',
))->render();
echo wfView::create('dashboard/options-group-alert', array(
'stateKey' => 'global-options-alert',
))->render();
echo wfView::create('dashboard/options-group-email-summary', array(
'stateKey' => 'global-options-email-summary',
))->render();
?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-block wf-always-active">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('Import/Export Options', 'wordfence'); ?></strong>
</div>
</div>
</div>
<div class="wf-block-content">
<ul class="wf-block-list">
<li>
<ul class="wf-flex-horizontal wf-flex-vertical-xs wf-flex-full-width wf-add-top wf-add-bottom">
<li><?php esc_html_e('Importing and exporting of options has moved to the Tools page', 'wordfence'); ?></li>
<li class="wf-right wf-left-xs wf-padding-add-top-xs-small">
<a href="<?php echo esc_url(network_admin_url('admin.php?page=WordfenceTools&subpage=importexport')); ?>" class="wf-btn wf-btn-primary wf-btn-callout-subtle" id="wf-export-options"><?php esc_html_e('Import/Export Options', 'wordfence'); ?></a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div> <!-- end import options -->
</div> <!-- end options block -->
</div> <!-- end content block -->
</div> <!-- end row -->
</div> <!-- end container -->
</div>

View File

@@ -0,0 +1,48 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
if (!wfOnboardingController::shouldShowAttempt3() && wfConfig::get('touppPromptNeeded')) {
echo wfView::create('gdpr/disabled-overlay')->render();
echo wfView::create('gdpr/banner')->render();
}
?>
<?php if (isset($storageExceptionMessage)): ?>
<div class="notice notice-error"><p><?php echo $storageExceptionMessage; ?></p></div>
<?php endif; ?>
<div class="wrap wordfence">
<div class="wf-container-fluid">
<?php
echo wfView::create('common/page-tabbar', array(
'tabs' => array(
new wfTab('waf', 'waf', __('Firewall', 'wordfence'), __('Web Application Firewall', 'wordfence')),
new wfTab('blocking', 'blocking', __('Blocking', 'wordfence'), __('Blocking', 'wordfence')),
),
))->render();
?>
<div class="wf-row">
<div class="<?php echo wfStyle::contentClasses(); ?>">
<div id="waf" class="wf-tab-content" data-title="Web Application Firewall">
<?php
echo wfView::create('common/section-title', array(
'title' => __('Firewall', 'wordfence'),
'headerID' => 'wf-section-firewall',
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_FIREWALL_WAF),
'helpLabelHTML' => wp_kses(__('Learn more<span class="wf-hidden-xs"> about the Firewall</span>', 'wordfence'), array('span'=>array('class'=>array()))),
))->render();
require(dirname(__FILE__) . '/menu_firewall_waf.php');
?>
</div> <!-- end waf block -->
<div id="blocking" class="wf-tab-content" data-title="Blocking">
<?php
echo wfView::create('common/section-title', array(
'title' => __('Blocking', 'wordfence'),
'headerID' => 'wf-section-blocking',
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_FIREWALL_BLOCKING),
'helpLabelHTML' => wp_kses(__('Learn more<span class="wf-hidden-xs"> about Blocking</span>', 'wordfence'), array('span'=>array('class'=>array()))),
))->render();
require(dirname(__FILE__) . '/menu_firewall_blocking.php');
?>
</div> <!-- end blocking block -->
</div> <!-- end content block -->
</div> <!-- end row -->
</div> <!-- end container -->
</div>

View File

@@ -0,0 +1,231 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-block wf-block-no-header wf-active">
<div class="wf-block-content">
<ul class="wf-block-list">
<li>
<?php
echo wfView::create('blocking/blocking-status', array(
))->render();
?>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-block wf-always-active">
<?php if (!wfConfig::get('firewallEnabled')): ?>
<ul class="wf-block-banner">
<li><?php echo wp_kses(__('<strong>Note:</strong> Blocking is disabled when the option "Enable Rate Limiting and Advanced Blocking" is off.', 'wordfence'), array('strong'=>array())); ?></li>
<li><a href="#" class="wf-btn wf-btn-default" id="wf-blocking-enable" role="button"><?php esc_html_e('Turn On', 'wordfence'); ?></a></li>
</ul>
<?php endif; ?>
<?php if (version_compare(phpversion(), '5.4') < 0 && wfConfig::get('isPaid') && wfBlock::hasCountryBlock()): ?>
<ul class="wf-block-banner">
<li><?php echo esc_html(sprintf(
/* translators: PHP version. */
__('<strong>Note:</strong> The GeoIP database that is required for country blocking has been updated to a new format. This new format requires sites to run PHP 5.4 or newer, and this site is on PHP %s. To ensure country blocking continues functioning, please update PHP.', 'wordfence'), wfUtils::cleanPHPVersion())); ?></li>
<li><a href="<?php echo wfSupportController::esc_supportURL(wfSupportController::ITEM_SCAN_RESULT_GEOIP_UPDATE); ?>" class="wf-btn wf-btn-default" target="_blank" rel="noopener noreferrer"><?php esc_html_e('More Information', 'wordfence'); ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a></li>
</ul>
<?php endif; ?>
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong id="wf-block-parameters-title" data-new-title="<?php esc_attr_e('Create a Blocking Rule', 'wordfence'); ?>" data-edit-title="<?php esc_attr_e('Edit Blocking Rule', 'wordfence'); ?>"><?php esc_html_e('Create a Blocking Rule', 'wordfence'); ?></strong>
</div>
</div>
</div>
<div class="wf-block-content">
<?php
echo wfView::create('blocking/blocking-create', array(
))->render();
?>
</div>
</div>
</div>
</div> <!-- end firewall status -->
<?php
echo wfView::create('blocking/block-list', array(
))->render();
?>
<div id="wf-overlay-wrapper" style="display: none">
<div class="wf-overlay">
<div class="wf-overlay-header"></div>
<div class="wf-overlay-body"></div>
<span class="wf-overlay-close wf-ion-android-close"></span>
</div>
</div>
<script type="application/javascript">
(function($) {
$(function() {
$('#wf-blocking-enable').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
WFAD.setOption('firewallEnabled', 1, function() {
window.location.reload(true);
});
});
});
})(jQuery);
</script>
<?php if (wfOnboardingController::willShowNewTour(wfOnboardingController::TOUR_BLOCKING)): ?>
<script type="application/javascript">
(function($) {
$(function() {
WFAD.setUpBlockingTour = function() {
WFAD.tour1 = function () {
WFAD.tour('wfBlockingNewTour1', 'wf-section-blocking', 'top', 'left', null, WFAD.tour2);
};
WFAD.tour2 = function () {
WFAD.tour('wfBlockingNewTour2', 'wf-create-block', 'top', 'top', WFAD.tour1, WFAD.tour3);
};
WFAD.tour3 = function () {
WFAD.tour('wfBlockingNewTour3', 'wf-blocks-wrapper', 'bottom', 'bottom', WFAD.tour2, WFAD.tourComplete);
};
WFAD.tourComplete = function () {
WFAD.tourFinish('<?php echo esc_attr(wfOnboardingController::TOUR_BLOCKING); ?>');
};
}
WFAD.blockingTourShown = false;
<?php if (wfOnboardingController::shouldShowNewTour(wfOnboardingController::TOUR_BLOCKING)): ?>
$(window).on('wfTabChange', function(e, tab) {
if (tab == 'blocking' && !WFAD.blockingTourShown) {
WFAD.blockingTourShown = true;
WFAD.setUpBlockingTour();
if (!WFAD.isSmallScreen) { WFAD.tour1(); }
}
});
if ($('#blocking').hasClass('wf-active')) {
WFAD.blockingTourShown = true;
WFAD.setUpBlockingTour();
if (!WFAD.isSmallScreen) { WFAD.tour1(); }
}
<?php endif; ?>
});
})(jQuery);
</script>
<script type="text/x-jquery-template" id="wfBlockingNewTour1">
<div>
<h3><?php esc_html_e('Blocking', 'wordfence'); ?></h3>
<p><?php esc_html_e('Wordfence lets you take control of protecting your site with powerful blocking features. Block traffic based on IP, IP range, hostname, browser, or referrer. Country blocking is available for Premium customers.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li class="wf-active">&bullet;</li>
<li>&bullet;</li>
<li>&bullet;</li>
</ul>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Next', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<script type="text/x-jquery-template" id="wfBlockingNewTour2">
<div>
<h3><?php esc_html_e('Blocking Builder', 'wordfence'); ?></h3>
<p><?php esc_html_e('All of your blocking rules are in one central location. Choose the Block Type, then enter the details for the rule. Once it has been added, you\'ll see it saved as a rule for your site.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li>&bullet;</li>
<li class="wf-active">&bullet;</li>
<li>&bullet;</li>
</ul>
<div id="wf-tour-previous"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-default" role="button"><?php esc_html_e('Previous', 'wordfence'); ?></a></div>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Next', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<script type="text/x-jquery-template" id="wfBlockingNewTour3">
<div>
<h3><?php esc_html_e('Manage Blocking Rules', 'wordfence'); ?></h3>
<p><?php esc_html_e('Here\'s where you\'ll see all the blocking rules you\'ve created. You can also manage them as well as remove or modify them from this table.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li>&bullet;</li>
<li>&bullet;</li>
<li class="wf-active">&bullet;</li>
</ul>
<div id="wf-tour-previous"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-default" role="button"><?php esc_html_e('Previous', 'wordfence'); ?></a></div>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Got it', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<?php endif; ?>
<?php if (wfOnboardingController::willShowUpgradeTour(wfOnboardingController::TOUR_BLOCKING)): ?>
<script type="application/javascript">
(function($) {
$(function() {
WFAD.setUpBlockingTour = function() {
WFAD.tour1 = function () {
WFAD.tour('wfBlockingUpgradeTour1', 'wf-create-block', 'top', 'top', null, WFAD.tour2);
};
WFAD.tour2 = function () {
WFAD.tour('wfBlockingUpgradeTour2', 'wf-blocks-wrapper', 'bottom', 'bottom', WFAD.tour1, WFAD.tourComplete);
};
WFAD.tourComplete = function () {
WFAD.tourFinish('<?php echo esc_attr(wfOnboardingController::TOUR_BLOCKING); ?>');
};
};
WFAD.blockingTourShown = false;
<?php if (wfOnboardingController::shouldShowUpgradeTour(wfOnboardingController::TOUR_BLOCKING)): ?>
$(window).on('wfTabChange', function(e, tab) {
if (tab == 'blocking' && !WFAD.blockingTourShown) {
WFAD.blockingTourShown = true;
WFAD.setUpBlockingTour();
if (!WFAD.isSmallScreen) { WFAD.tour1(); }
}
});
if ($('#blocking').hasClass('wf-active')) {
WFAD.blockingTourShown = true;
WFAD.setUpBlockingTour();
if (!WFAD.isSmallScreen) { WFAD.tour1(); }
}
<?php endif; ?>
});
})(jQuery);
</script>
<script type="text/x-jquery-template" id="wfBlockingUpgradeTour1">
<div>
<h3><?php esc_html_e('Blocking Builder', 'wordfence'); ?></h3>
<p><?php echo wp_kses(__('All of the blocking rules you create are now in one central location. Simply choose the block type and enter the details for the rule you want to create. Premium users have access to advanced country blocking options, found via the <strong>Options</strong> link.', 'wordfence'), array('strong'=>array())); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li class="wf-active">&bullet;</li>
<li>&bullet;</li>
</ul>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Next', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<script type="text/x-jquery-template" id="wfBlockingUpgradeTour2">
<div>
<h3><?php esc_html_e('Manage Blocking Rules', 'wordfence'); ?></h3>
<p><?php esc_html_e('All blocking rules you create will show here. You can manage them as well as remove or modify them from the same location.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li>&bullet;</li>
<li class="wf-active">&bullet;</li>
</ul>
<div id="wf-tour-previous"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-default" role="button"><?php esc_html_e('Previous', 'wordfence'); ?></a></div>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Got it', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<?php endif; ?>

View File

@@ -0,0 +1,133 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
$backPage = new wfPage(wfPage::PAGE_BLOCKING);
if (isset($_GET['source']) && wfPage::isValidPage($_GET['source'])) {
$backPage = new wfPage($_GET['source']);
}
?>
<script type="application/javascript">
(function($) {
$(function() {
document.title = "<?php esc_attr_e('Blocking Options', 'wordfence'); ?>" + " \u2039 " + WFAD.basePageName;
//Hash-based option block linking
if (window.location.hash) {
var hashes = WFAD.parseHashes();
var hash = hashes[hashes.length - 1];
var block = $('.wf-block[data-persistence-key="' + hash + '"]');
if (block) {
if (!block.hasClass('wf-active')) {
block.find('.wf-block-content').slideDown({
always: function() {
block.addClass('wf-active');
$('html, body').animate({
scrollTop: block.offset().top - 100
}, 1000);
}
});
WFAD.ajax('wordfence_saveDisclosureState', {name: block.data('persistenceKey'), state: true}, function() {});
}
else {
$('html, body').animate({
scrollTop: block.offset().top - 100
}, 1000);
}
history.replaceState('', document.title, window.location.pathname + window.location.search);
}
}
});
})(jQuery);
</script>
<div class="wf-options-controls">
<div class="wf-row">
<div class="wf-col-xs-12">
<?php
echo wfView::create('options/block-controls', array(
'backLink' => $backPage->url(),
'backLabelHTML' => wp_kses(sprintf(
/* translators: Page title/label. */
__('<span class="wf-hidden-xs">Back to </span>%s', 'wordfence'), $backPage->label()), array('span'=>array('class'=>array()))),
'restoreDefaultsSection' => wfConfig::OPTIONS_TYPE_BLOCKING,
'restoreDefaultsMessage' => __('Are you sure you want to restore the default Blocking settings? This will undo any custom changes you have made to the options on this page. Any existing blocks will be preserved.', 'wordfence'),
))->render();
?>
</div>
</div>
</div>
<div class="wf-options-controls-spacer"></div>
<?php
if (!wfOnboardingController::shouldShowAttempt3() && wfConfig::get('touppPromptNeeded')) {
echo wfView::create('gdpr/disabled-overlay')->render();
echo wfView::create('gdpr/banner')->render();
}
?>
<div class="wrap wordfence">
<div class="wf-container-fluid">
<?php
if (function_exists('network_admin_url') && is_multisite()) {
$firewallURL = network_admin_url('admin.php?page=WordfenceWAF#top#waf');
$blockingURL = network_admin_url('admin.php?page=WordfenceWAF#top#blocking');
}
else {
$firewallURL = admin_url('admin.php?page=WordfenceWAF#top#waf');
$blockingURL = admin_url('admin.php?page=WordfenceWAF#top#blocking');
}
?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wp-header-end"></div>
</div>
</div>
<div class="wf-row">
<div class="<?php echo wfStyle::contentClasses(); ?>">
<div id="waf-options" class="wf-fixed-tab-content">
<?php
echo wfView::create('common/section-title', array(
'title' => __('Blocking Options', 'wordfence'),
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_FIREWALL_BLOCKING),
'helpLabelHTML' => wp_kses(__('Learn more<span class="wf-hidden-xs"> about Blocking</span>', 'wordfence'), array('span'=>array('class'=>array()))),
'showIcon' => true,
))->render();
?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-block wf-always-active">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('General', 'wordfence'); ?></strong>
</div>
<div class="wf-block-header-action"></div>
</div>
</div>
<div class="wf-block-content">
<ul class="wf-block-list">
<li>
<?php
echo wfView::create('options/option-toggled', array(
'optionName' => 'displayTopLevelBlocking',
'enabledValue' => 1,
'disabledValue' => 0,
'value' => wfConfig::get('displayTopLevelBlocking') ? 1 : 0,
'title' => __('Display Blocking menu option', 'wordfence'),
))->render();
?>
</li>
</ul>
</div>
</div>
</div>
</div> <!-- end general options -->
<?php
echo wfView::create('blocking/options-group-advanced-country', array(
'stateKey' => 'blocking-options-country',
'collapseable' => false,
))->render();
?>
</div> <!-- end blocking options block -->
</div> <!-- end content block -->
</div> <!-- end row -->
</div> <!-- end container -->
</div>

View File

@@ -0,0 +1,359 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
$waf = wfWAF::getInstance();
$d = new wfDashboard(); unset($d->countriesNetwork);
$firewall = new wfFirewall();
$config = $waf->getStorageEngine();
$wafConfigURL = network_admin_url('admin.php?page=WordfenceWAF&subpage=waf_options#configureAutoPrepend');
$wafRemoveURL = network_admin_url('admin.php?page=WordfenceWAF&subpage=waf_options#removeAutoPrepend');
/** @var array $wafData */
?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-block wf-active">
<div class="wf-block-content">
<ul class="wf-block-list">
<li>
<?php
echo wfView::create('waf/firewall-status', array(
'firewall' => $firewall,
'dashboard' => $d,
))->render();
?>
</li>
<li>
<ul class="wf-block-list wf-block-list-horizontal wf-block-list-nowrap wf-waf-coverage">
<li>
<?php
if (function_exists('network_admin_url') && is_multisite()) { $optionsURL = network_admin_url('admin.php?page=WordfenceWAF&subpage=waf_options'); }
else { $optionsURL = admin_url('admin.php?page=WordfenceWAF&subpage=waf_options'); }
echo wfView::create('common/status-detail', array(
'id' => 'waf-coverage',
'percentage' => $firewall->wafStatus(),
'activeColor' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? '#ececec' : null /* automatic */),
'title' => __('Web Application Firewall', 'wordfence'),
'subtitle' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? __('Currently in Learning Mode', 'wordfence') : __('Stops Complex Attacks', 'wordfence')),
'link' => $optionsURL,
'linkLabel' => __('Manage WAF', 'wordfence'),
'statusTitle' => __('Web Application Firewall Status', 'wordfence'),
'statusList' => $firewall->wafStatusList(),
'statusExtra' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? wfView::create('waf/status-tooltip-learning-mode')->render() : ''),
'helpLink' => __('https://www.wordfence.com/help/firewall/#firewall-status', 'wordfence'),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('common/status-detail', array(
'id' => 'waf-rules',
'percentage' => $firewall->ruleStatus(),
'activeColor' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? '#ececec' : null /* automatic */),
'title' => __('Firewall Rules: ', 'wordfence') . ($firewall->ruleMode() == wfFirewall::RULE_MODE_PREMIUM ? __('Premium', 'wordfence') : __('Community', 'wordfence')),
'subtitle' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? __('Currently in Learning Mode', 'wordfence') : ($firewall->ruleMode() == wfFirewall::RULE_MODE_PREMIUM ? __('Rules updated in real-time', 'wordfence') : __('Rule updates delayed by 30 days', 'wordfence'))),
'link' => ($firewall->ruleMode() == wfFirewall::RULE_MODE_PREMIUM ? $optionsURL . '#waf-options-advanced' : 'https://www.wordfence.com/gnl1wafUpgrade/wordfence-signup/'),
'linkLabel' => ($firewall->ruleMode() == wfFirewall::RULE_MODE_PREMIUM ? __('Manage Firewall Rules', 'wordfence') : __('Upgrade to Premium', 'wordfence')),
'linkNewWindow' => ($firewall->ruleMode() != wfFirewall::RULE_MODE_PREMIUM),
'statusTitle' => __('Firewall Rules Status', 'wordfence'),
'statusList' => $firewall->wafStatusList('rules'),
'statusExtra' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? wfView::create('waf/status-tooltip-learning-mode')->render() : ''),
'helpLink' => __('https://www.wordfence.com/help/firewall/#firewall-status', 'wordfence'),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('common/status-detail', array(
'id' => 'waf-blacklist',
'percentage' => $firewall->blacklistStatus(),
'title' => __('Real-Time IP Blocklist: ', 'wordfence') . ($firewall->blacklistMode() == wfFirewall::BLACKLIST_MODE_ENABLED ? __('Enabled', 'wordfence') : __('Disabled', 'wordfence')),
'subtitle' => __('Blocks requests from known malicious IPs', 'wordfence'),
'link' => (($firewall->ruleMode() == wfFirewall::RULE_MODE_PREMIUM) ? network_admin_url('admin.php?page=WordfenceWAF&subpage=waf_options') : 'https://www.wordfence.com/gnl1wafUpgrade/wordfence-signup/'),
'linkLabel' => $firewall->firewallMode() == wfFirewall::FIREWALL_MODE_DISABLED ? null : ($firewall->ruleMode() == wfFirewall::RULE_MODE_PREMIUM ? ($firewall->blacklistMode() == wfFirewall::BLACKLIST_MODE_ENABLED ? __('Manage Real-Time IP Blocklist', 'wordfence') : ($firewall->isSubDirectoryInstallation() ? null : __('Enable', 'wordfence'))) : __('Upgrade to Premium', 'wordfence')),
'linkNewWindow' => ($firewall->ruleMode() != wfFirewall::RULE_MODE_PREMIUM),
'statusTitle' => __('Blocklist Status', 'wordfence'),
'statusList' => $firewall->wafStatusList('blacklist'),
'helpLink' => __('https://www.wordfence.com/help/firewall/#firewall-status', 'wordfence'),
))->render();
if ($firewall->ruleMode() == wfFirewall::RULE_MODE_PREMIUM && $firewall->blacklistMode() == wfFirewall::BLACKLIST_MODE_DISABLED):
?>
<script type="application/javascript">
(function($) {
$(function() {
$('#waf-blacklist a').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
WFAD.setOption('disableWAFBlacklistBlocking', 0, function() {
window.location.reload(true);
});
});
});
})(jQuery);
</script>
<?php endif; ?>
</li>
<li>
<?php
echo wfView::create('common/status-detail', array(
'id' => 'waf-brute',
'percentage' => $firewall->bruteForceStatus(),
'title' => __('Brute Force Protection', 'wordfence') . ($firewall->bruteForceStatus() == 0 ? __(': Disabled', 'wordfence') : ''),
'subtitle' => __('Stops Password Guessing Attacks', 'wordfence'),
'link' => network_admin_url('admin.php?page=WordfenceWAF&subpage=waf_options#waf-options-bruteforce'),
'linkLabel' => __('Manage Brute Force Protection', 'wordfence'),
'statusTitle' => __('Brute Force Protection Status', 'wordfence'),
'statusList' => $firewall->bruteForceStatusList(),
'helpLink' => __('https://www.wordfence.com/help/firewall/#firewall-status', 'wordfence'),
))->render();
?>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-block wf-active">
<div class="wf-block-content">
<ul class="wf-block-list">
<li>
<ul class="wf-block-list wf-block-list-horizontal wf-waf-navigation">
<li>
<?php
echo wfView::create('common/block-navigation-option', array(
'id' => 'waf-option-rate-limiting',
'img' => 'ratelimiting.svg',
'title' => __('Rate Limiting', 'wordfence'),
'subtitle' => __('Block crawlers that are using too many resources or stealing content', 'wordfence'),
'link' => network_admin_url('admin.php?page=WordfenceWAF&subpage=waf_options#waf-options-ratelimiting'),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('common/block-navigation-option', array(
'id' => 'waf-option-blocking',
'img' => 'blocking.svg',
'title' => __('Blocking', 'wordfence'),
'subtitle' => __('Block traffic by country, IP, IP range, user agent, referrer, or hostname', 'wordfence'),
'link' => '#top#blocking',
))->render();
?>
</li>
</ul>
</li>
<li>
<ul class="wf-block-list wf-block-list-horizontal wf-waf-navigation">
<li>
<?php
echo wfView::create('common/block-navigation-option', array(
'id' => 'waf-option-support',
'img' => 'support.svg',
'title' => __('Help', 'wordfence'),
'subtitle' => __('Find the documentation and help you need', 'wordfence'),
'link' => network_admin_url('admin.php?page=WordfenceSupport'),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('common/block-navigation-option', array(
'id' => 'waf-option-all-options',
'img' => 'options.svg',
'title' => __('All Firewall Options', 'wordfence'),
'subtitle' => __('Manage global and advanced firewall options', 'wordfence'),
'link' => network_admin_url('admin.php?page=WordfenceWAF&subpage=waf_options'),
))->render();
?>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="wf-row">
<div class="wf-col-xs-12 wf-col-lg-6 wf-col-lg-half-padding-right">
<!-- begin top ips blocked -->
<?php include(dirname(__FILE__) . '/dashboard/widget_ips.php'); ?>
<!-- end top ips blocked -->
<!-- begin countries blocked -->
<?php include(dirname(__FILE__) . '/dashboard/widget_countries.php'); ?>
<!-- end countries blocked -->
</div> <!-- end content block -->
<div class="wf-col-xs-12 wf-col-lg-6 wf-col-lg-half-padding-left">
<!-- begin firewall summary site -->
<?php include(dirname(__FILE__) . '/dashboard/widget_localattacks.php'); ?>
<!-- end firewall summary site -->
<!-- begin total attacks blocked network -->
<?php include(dirname(__FILE__) . '/dashboard/widget_networkattacks.php'); ?>
<!-- end total attacks blocked network -->
<!-- begin recent logins -->
<?php include(dirname(__FILE__) . '/dashboard/widget_logins.php'); ?>
<!-- end recent logins -->
</div> <!-- end content block -->
</div> <!-- end row -->
<?php if (wfOnboardingController::willShowNewTour(wfOnboardingController::TOUR_FIREWALL)): ?>
<script type="application/javascript">
(function($) {
$(function() {
WFAD.setUpFirewallTour = function() {
WFAD.tour1 = function () {
WFAD.tour('wfWAFNewTour1', 'wf-section-firewall', 'top', 'left', null, WFAD.tour2);
};
WFAD.tour2 = function () {
WFAD.tour('wfWAFNewTour2', 'waf-coverage', 'top', 'left', WFAD.tour1, WFAD.tour3);
};
WFAD.tour3 = function () {
WFAD.tour('wfWAFNewTour3', 'waf-brute', 'right', 'right', WFAD.tour2, WFAD.tour4);
};
WFAD.tour4 = function () {
WFAD.tour('wfWAFNewTour4', 'waf-option-all-options', 'right', 'right', WFAD.tour3, WFAD.tourComplete);
};
WFAD.tourComplete = function () {
WFAD.tourFinish('<?php echo esc_attr(wfOnboardingController::TOUR_FIREWALL); ?>');
};
};
WFAD.wafTourShown = false;
<?php if (wfOnboardingController::shouldShowNewTour(wfOnboardingController::TOUR_FIREWALL)): ?>
$(window).on('wfTabChange', function(e, tab) {
if (tab == 'waf' && !WFAD.wafTourShown) {
WFAD.wafTourShown = true;
WFAD.setUpFirewallTour();
if (!WFAD.isSmallScreen) { WFAD.tour1(); }
}
});
if ($('#waf').hasClass('wf-active')) {
WFAD.wafTourShown = true;
WFAD.setUpFirewallTour();
if (!WFAD.isSmallScreen) { WFAD.tour1(); }
}
<?php endif; ?>
});
})(jQuery);
</script>
<script type="text/x-jquery-template" id="wfWAFNewTour1">
<div>
<h3><?php esc_html_e('The Wordfence firewall protects your sites from attackers', 'wordfence'); ?></h3>
<p><?php esc_html_e('This is where you can monitor the work Wordfence is doing to protect your site and also where you can manage the options to optimize the firewall\'s configuration.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li class="wf-active">&bullet;</li>
<li>&bullet;</li>
<li>&bullet;</li>
<li>&bullet;</li>
</ul>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Next', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<script type="text/x-jquery-template" id="wfWAFNewTour2">
<div>
<h3><?php esc_html_e('Web Application Firewall (WAF)', 'wordfence'); ?></h3>
<p><?php esc_html_e('The Wordfence Web Application Firewall blocks known and emerging attacks using firewall rules. When you first install the WAF, it will be in learning mode. This allows Wordfence to learn about your site so that we can understand how to protect it and how to allow normal visitors through the firewall. We recommend you let Wordfence learn for a week before you enable the firewall.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li>&bullet;</li>
<li class="wf-active">&bullet;</li>
<li>&bullet;</li>
<li>&bullet;</li>
</ul>
<div id="wf-tour-previous"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-default" role="button"><?php esc_html_e('Previous', 'wordfence'); ?></a></div>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Next', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<script type="text/x-jquery-template" id="wfWAFNewTour3">
<div>
<h3><?php esc_html_e('Brute Force Protection', 'wordfence'); ?></h3>
<p><?php esc_html_e('Wordfence protects your site from password-guessing attacks by locking out attackers and helping you avoid weak passwords.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li>&bullet;</li>
<li>&bullet;</li>
<li class="wf-active">&bullet;</li>
<li>&bullet;</li>
</ul>
<div id="wf-tour-previous"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-default" role="button"><?php esc_html_e('Previous', 'wordfence'); ?></a></div>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Next', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<script type="text/x-jquery-template" id="wfWAFNewTour4">
<div>
<h3><?php esc_html_e('Firewall Options', 'wordfence'); ?></h3>
<p class="wf-center"><svg viewBox="0 0 100.11 100.11" class="wf-icon"><path d="M99.59,41.42a2.06,2.06,0,0,0-1.37-.82L86.3,38.78a39.34,39.34,0,0,0-2.67-6.39q1.17-1.63,3.52-4.6t3.32-4.33A2.52,2.52,0,0,0,91,22a2.1,2.1,0,0,0-.46-1.43Q88.18,17.2,79.78,9.45a2.52,2.52,0,0,0-1.63-.65,2.12,2.12,0,0,0-1.57.59l-9.25,7a40.09,40.09,0,0,0-5.87-2.41L59.64,2a1.92,1.92,0,0,0-.75-1.4A2.46,2.46,0,0,0,57.29,0H42.82a2.19,2.19,0,0,0-2.34,1.82,106,106,0,0,0-1.89,12.12,37.62,37.62,0,0,0-5.93,2.48l-9-7A2.78,2.78,0,0,0,22,8.8q-1.44,0-6.16,4.66a64.88,64.88,0,0,0-6.42,7A2.75,2.75,0,0,0,8.8,22a2.44,2.44,0,0,0,.65,1.56q4.37,5.28,7,9a32.38,32.38,0,0,0-2.54,6L1.76,40.34a2,2,0,0,0-1.24.85A2.5,2.5,0,0,0,0,42.69V57.16a2.44,2.44,0,0,0,.52,1.53,2,2,0,0,0,1.37.82l11.93,1.76a31.91,31.91,0,0,0,2.67,6.45Q15.31,69.35,13,72.31T9.65,76.65a2.54,2.54,0,0,0-.07,3q2.54,3.52,10.75,11a2.25,2.25,0,0,0,1.63.71,2.35,2.35,0,0,0,1.63-.59l9.19-7a40.54,40.54,0,0,0,5.87,2.41l1.82,12a1.92,1.92,0,0,0,.75,1.4,2.45,2.45,0,0,0,1.6.55H57.29a2.2,2.2,0,0,0,2.35-1.82,107.41,107.41,0,0,0,1.89-12.12,37.19,37.19,0,0,0,5.93-2.48l9,7a3.18,3.18,0,0,0,1.69.59q1.43,0,6.13-4.62a65.86,65.86,0,0,0,6.45-7,2.16,2.16,0,0,0,.59-1.5,2.51,2.51,0,0,0-.65-1.63q-4.69-5.74-7-9a41.57,41.57,0,0,0,2.54-5.93l12.06-1.82a2,2,0,0,0,1.3-.85,2.52,2.52,0,0,0,.52-1.5V43a2.46,2.46,0,0,0-.52-1.53ZM61.85,61.86a16.08,16.08,0,0,1-11.8,4.89A16.69,16.69,0,0,1,33.37,50.06,16.69,16.69,0,0,1,50.06,33.37,16.69,16.69,0,0,1,66.74,50.06a16.08,16.08,0,0,1-4.89,11.8Zm0,0"></path></svg></p>
<p><?php esc_html_e('Set up the way you want the firewall to protect your site including the web application firewall, brute force protection, rate limiting, and blocking.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li>&bullet;</li>
<li>&bullet;</li>
<li>&bullet;</li>
<li class="wf-active">&bullet;</li>
</ul>
<div id="wf-tour-previous"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-default" role="button"><?php esc_html_e('Previous', 'wordfence'); ?></a></div>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Got it', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<?php endif; ?>
<?php if (wfOnboardingController::willShowUpgradeTour(wfOnboardingController::TOUR_FIREWALL)): ?>
<script type="application/javascript">
(function($) {
$(function() {
WFAD.setUpFirewallTour = function() {
WFAD.tour1 = function() {
WFAD.tour('wfWAFUpgradeTour1', 'waf-option-all-options', 'right', 'right', null, WFAD.tourComplete);
};
WFAD.tourComplete = function() { WFAD.tourFinish('<?php echo esc_attr(wfOnboardingController::TOUR_FIREWALL); ?>'); };
};
WFAD.wafTourShown = false;
<?php if (wfOnboardingController::shouldShowUpgradeTour(wfOnboardingController::TOUR_FIREWALL)): ?>
$(window).on('wfTabChange', function(e, tab) {
if (tab == 'waf' && !WFAD.wafTourShown) {
WFAD.wafTourShown = true;
WFAD.setUpFirewallTour();
if (!WFAD.isSmallScreen) { WFAD.tour1(); }
}
});
if ($('#waf').hasClass('wf-active')) {
WFAD.wafTourShown = true;
WFAD.setUpFirewallTour();
if (!WFAD.isSmallScreen) { WFAD.tour1(); }
}
<?php endif; ?>
});
})(jQuery);
</script>
<script type="text/x-jquery-template" id="wfWAFUpgradeTour1">
<div>
<h3><?php esc_html_e('Firewall Options', 'wordfence'); ?></h3>
<p class="wf-center"><svg viewBox="0 0 100.11 100.11" class="wf-icon"><path d="M99.59,41.42a2.06,2.06,0,0,0-1.37-.82L86.3,38.78a39.34,39.34,0,0,0-2.67-6.39q1.17-1.63,3.52-4.6t3.32-4.33A2.52,2.52,0,0,0,91,22a2.1,2.1,0,0,0-.46-1.43Q88.18,17.2,79.78,9.45a2.52,2.52,0,0,0-1.63-.65,2.12,2.12,0,0,0-1.57.59l-9.25,7a40.09,40.09,0,0,0-5.87-2.41L59.64,2a1.92,1.92,0,0,0-.75-1.4A2.46,2.46,0,0,0,57.29,0H42.82a2.19,2.19,0,0,0-2.34,1.82,106,106,0,0,0-1.89,12.12,37.62,37.62,0,0,0-5.93,2.48l-9-7A2.78,2.78,0,0,0,22,8.8q-1.44,0-6.16,4.66a64.88,64.88,0,0,0-6.42,7A2.75,2.75,0,0,0,8.8,22a2.44,2.44,0,0,0,.65,1.56q4.37,5.28,7,9a32.38,32.38,0,0,0-2.54,6L1.76,40.34a2,2,0,0,0-1.24.85A2.5,2.5,0,0,0,0,42.69V57.16a2.44,2.44,0,0,0,.52,1.53,2,2,0,0,0,1.37.82l11.93,1.76a31.91,31.91,0,0,0,2.67,6.45Q15.31,69.35,13,72.31T9.65,76.65a2.54,2.54,0,0,0-.07,3q2.54,3.52,10.75,11a2.25,2.25,0,0,0,1.63.71,2.35,2.35,0,0,0,1.63-.59l9.19-7a40.54,40.54,0,0,0,5.87,2.41l1.82,12a1.92,1.92,0,0,0,.75,1.4,2.45,2.45,0,0,0,1.6.55H57.29a2.2,2.2,0,0,0,2.35-1.82,107.41,107.41,0,0,0,1.89-12.12,37.19,37.19,0,0,0,5.93-2.48l9,7a3.18,3.18,0,0,0,1.69.59q1.43,0,6.13-4.62a65.86,65.86,0,0,0,6.45-7,2.16,2.16,0,0,0,.59-1.5,2.51,2.51,0,0,0-.65-1.63q-4.69-5.74-7-9a41.57,41.57,0,0,0,2.54-5.93l12.06-1.82a2,2,0,0,0,1.3-.85,2.52,2.52,0,0,0,.52-1.5V43a2.46,2.46,0,0,0-.52-1.53ZM61.85,61.86a16.08,16.08,0,0,1-11.8,4.89A16.69,16.69,0,0,1,33.37,50.06,16.69,16.69,0,0,1,50.06,33.37,16.69,16.69,0,0,1,66.74,50.06a16.08,16.08,0,0,1-4.89,11.8Zm0,0"></path></svg></p>
<p><?php esc_html_e('All of the Firewall settings are now located here. This includes configuration options for the web application firewall, brute force protection, rate limiting, allowlisted URLs, and blocking.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li class="wf-active">&bullet;</li>
</ul>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Got it', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<?php endif; ?>

View File

@@ -0,0 +1,247 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
$waf = wfWAF::getInstance();
$d = new wfDashboard(); unset($d->countriesNetwork);
$firewall = new wfFirewall();
$config = $waf->getStorageEngine();
$wafURL = wfPage::pageURL(wfPage::PAGE_FIREWALL);
$wafConfigURL = network_admin_url('admin.php?page=WordfenceWAF&subpage=waf_options#configureAutoPrepend');
$wafRemoveURL = network_admin_url('admin.php?page=WordfenceWAF&subpage=waf_options#removeAutoPrepend');
/** @var array $wafData */
$backPage = new wfPage(wfPage::PAGE_FIREWALL);
if (isset($_GET['source']) && wfPage::isValidPage($_GET['source'])) {
$backPage = new wfPage($_GET['source']);
}
?>
<script type="application/javascript">
(function($) {
WFAD.wafData = <?php echo json_encode($wafData); ?>;
WFAD.restoreWAFData = JSON.parse(JSON.stringify(WFAD.wafData)); //Copied into wafData when canceling changes
$(function() {
document.title = "<?php esc_attr_e('Firewall Options', 'wordfence'); ?>" + " \u2039 " + WFAD.basePageName;
WFAD.wafConfigPageRender();
//Hash-based option block linking
if (window.location.hash) {
var hashes = WFAD.parseHashes();
var hash = hashes[hashes.length - 1];
var target = $("#" + hash);
var block = target.parents('.wf-block');
if (!block.length) {
block = $('.wf-block[data-persistence-key="' + hash + '"]');
target = block;
}
if (block.length) {
if (!block.hasClass('wf-active')) {
block.find('.wf-block-content').slideDown({
always: function() {
block.addClass('wf-active');
$('html, body').animate({
scrollTop: target.offset().top - 100
}, 1000);
}
});
WFAD.ajax('wordfence_saveDisclosureState', {name: block.data('persistenceKey'), state: true}, function() {});
}
else {
$('html, body').animate({
scrollTop: target.offset().top - 100
}, 1000);
}
history.replaceState('', document.title, window.location.pathname + window.location.search);
}
}
var updatePendingCircles = function() {
$('#circle-waf-coverage, #circle-waf-rules, #circle-waf-blacklist, #circle-waf-brute').wfCircularProgress({pendingOverlay: Object.keys(WFAD.pendingChanges).length > 0});
};
var coalescingUpdateTimer = false;
$('.wf-option, .wf-rule-toggle').on('change', function() {
clearTimeout(coalescingUpdateTimer);
coalescingUpdateTimer = setTimeout(updatePendingCircles, 100);
});
});
$(window).on('wfOptionsReset', function() {
WFAD.wafData = JSON.parse(JSON.stringify(WFAD.restoreWAFData));
WFAD.wafConfigPageRender();
});
})(jQuery);
</script>
<div class="wf-options-controls">
<div class="wf-row">
<div class="wf-col-xs-12">
<?php
echo wfView::create('options/block-controls', array(
'backLink' => $backPage->url(),
'backLabelHTML' => wp_kses(sprintf(__('<span class="wf-hidden-xs">Back to </span>%s', 'wordfence'), $backPage->label()), array('span'=>array('class'=>array()))),
'restoreDefaultsSection' => wfConfig::OPTIONS_TYPE_FIREWALL,
'restoreDefaultsMessage' => __('Are you sure you want to restore the default Firewall settings? This will undo any custom changes you have made to the options on this page. If you have manually disabled any rules or added any custom allowlisted URLs, those changes will not be overwritten.', 'wordfence'),
))->render();
?>
</div>
</div>
</div>
<div class="wf-options-controls-spacer"></div>
<?php
if (!wfOnboardingController::shouldShowAttempt3() && wfConfig::get('touppPromptNeeded')) {
echo wfView::create('gdpr/disabled-overlay')->render();
echo wfView::create('gdpr/banner')->render();
}
?>
<div class="wrap wordfence">
<div class="wf-container-fluid">
<?php
if (function_exists('network_admin_url') && is_multisite()) {
$firewallURL = network_admin_url('admin.php?page=WordfenceWAF#top#waf');
$blockingURL = network_admin_url('admin.php?page=WordfenceWAF#top#blocking');
}
else {
$firewallURL = admin_url('admin.php?page=WordfenceWAF#top#waf');
$blockingURL = admin_url('admin.php?page=WordfenceWAF#top#blocking');
}
?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wp-header-end"></div>
<?php if (isset($storageExceptionMessage)): ?>
<div class="notice notice-error"><p><?php echo $storageExceptionMessage; ?></p></div>
<?php endif; ?>
</div>
</div>
<div class="wf-row">
<div class="<?php echo wfStyle::contentClasses(); ?>">
<div id="waf-options" class="wf-fixed-tab-content">
<?php
echo wfView::create('common/section-title', array(
'title' => __('Firewall Options', 'wordfence'),
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_FIREWALL_WAF),
'helpLabelHTML' => wp_kses(__('Learn more<span class="wf-hidden-xs"> about the Firewall</span>', 'wordfence'), array('span'=>array('class'=>array()))),
'showIcon' => true,
))->render();
?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-block wf-active">
<div class="wf-block-content">
<ul class="wf-block-list wf-block-list-horizontal wf-block-list-nowrap wf-waf-coverage">
<li>
<?php
if (function_exists('network_admin_url') && is_multisite()) { $optionsURL = network_admin_url('admin.php?page=WordfenceWAF&subpage=waf_options'); }
else { $optionsURL = admin_url('admin.php?page=WordfenceWAF&subpage=waf_options'); }
echo wfView::create('common/status-detail', array(
'id' => 'waf-coverage',
'percentage' => $firewall->wafStatus(),
'activeColor' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? '#ececec' : null /* automatic */),
'title' => __('Web Application Firewall', 'wordfence'),
'subtitle' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? __('Currently in Learning Mode', 'wordfence') : __('Stops Complex Attacks', 'wordfence')),
'link' => $optionsURL,
'linkLabel' => null,
'statusTitle' => __('Web Application Firewall Status', 'wordfence'),
'statusList' => $firewall->wafStatusList(),
'statusExtra' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? wfView::create('waf/status-tooltip-learning-mode')->render() : ''),
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_FIREWALL_WAF_STATUS_OVERALL),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('common/status-detail', array(
'id' => 'waf-rules',
'percentage' => $firewall->ruleStatus(),
'activeColor' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? '#ececec' : null /* automatic */),
'title' => __('Firewall Rules: ', 'wordfence') . ($firewall->ruleMode() == wfFirewall::RULE_MODE_PREMIUM ? __('Premium', 'wordfence') : __('Community', 'wordfence')),
'subtitle' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? __('Currently in Learning Mode', 'wordfence') : ($firewall->ruleMode() == wfFirewall::RULE_MODE_PREMIUM ? __('Rules updated in real-time', 'wordfence') : __('Rule updates delayed by 30 days', 'wordfence'))),
'link' => 'https://www.wordfence.com/gnl1wafUpgrade/wordfence-signup/',
'linkLabel' => null,
'linkNewWindow' => true,
'statusTitle' => __('Firewall Rules Status', 'wordfence'),
'statusList' => $firewall->wafStatusList('rules'),
'statusExtra' => ($firewall->firewallMode() == wfFirewall::FIREWALL_MODE_LEARNING ? wfView::create('waf/status-tooltip-learning-mode')->render() : ''),
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_FIREWALL_WAF_STATUS_RULES),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('common/status-detail', array(
'id' => 'waf-blacklist',
'percentage' => $firewall->blacklistStatus(),
'title' => __('Real-Time IP Blocklist: ', 'wordfence') . ($firewall->blacklistMode() == wfFirewall::BLACKLIST_MODE_ENABLED ? __('Enabled', 'wordfence') : __('Disabled', 'wordfence')),
'subtitle' => __('Blocks requests from known malicious IPs', 'wordfence'),
'link' => (($firewall->ruleMode() == wfFirewall::RULE_MODE_PREMIUM && $firewall->blacklistMode() == wfFirewall::BLACKLIST_MODE_DISABLED) ? network_admin_url('admin.php?page=WordfenceWAF&subpage=waf_options#waf-options-advanced') : 'https://www.wordfence.com/gnl1wafUpgrade/wordfence-signup/'),
'linkLabel' => null,
'linkNewWindow' => !($firewall->ruleMode() == wfFirewall::RULE_MODE_PREMIUM && $firewall->blacklistMode() == wfFirewall::BLACKLIST_MODE_DISABLED),
'statusTitle' => __('Blocklist Status', 'wordfence'),
'statusList' => $firewall->wafStatusList('blacklist'),
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_FIREWALL_WAF_STATUS_BLACKLIST),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('common/status-detail', array(
'id' => 'waf-brute',
'percentage' => $firewall->bruteForceStatus(),
'title' => __('Brute Force Protection', 'wordfence') . ($firewall->bruteForceStatus() == 0 ? __(': Disabled', 'wordfence') : ''),
'subtitle' => __('Stops Password Guessing Attacks', 'wordfence'),
'link' => network_admin_url('admin.php?page=WordfenceWAF&subpage=waf_options#waf-options-bruteforce'),
'linkLabel' => null,
'statusTitle' => __('Brute Force Protection Status', 'wordfence'),
'statusList' => $firewall->bruteForceStatusList(),
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_FIREWALL_WAF_STATUS_BRUTE_FORCE),
))->render();
?>
</li>
</ul>
</div>
</div>
</div>
</div>
<?php
echo wfView::create('waf/options-group-basic-firewall', array(
'firewall' => $firewall,
'waf' => $waf,
'stateKey' => 'waf-options-basic',
'collapseable' => false,
))->render();
?>
<?php
echo wfView::create('waf/options-group-advanced-firewall', array(
'firewall' => $firewall,
'waf' => $waf,
'stateKey' => 'waf-options-advanced',
))->render();
?>
<?php
echo wfView::create('waf/options-group-brute-force', array(
'firewall' => $firewall,
'waf' => $waf,
'stateKey' => 'waf-options-bruteforce',
))->render();
?>
<?php
echo wfView::create('waf/options-group-rate-limiting', array(
'firewall' => $firewall,
'waf' => $waf,
'stateKey' => 'waf-options-ratelimiting',
))->render();
?>
<?php
echo wfView::create('waf/options-group-whitelisted', array(
'firewall' => $firewall,
'waf' => $waf,
'stateKey' => 'waf-options-whitelisted',
))->render();
?>
</div> <!-- end waf options block -->
</div> <!-- end content block -->
</div> <!-- end row -->
</div> <!-- end container -->
</div>

View File

@@ -0,0 +1,43 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
$errorMessage = null;
if (!$shouldShowOnboarding) {
$errorMessage = __('Wordfence is already installed on this site. If you need to replace the current license, you may do so by visiting the "All Options" page of the Wordfence menu.', 'wordfence');
}
elseif ($invalidLink) {
if ($payloadException instanceof wfWebsiteEphemeralPayloadRateLimitedException) {
$errorMessage = __('Too many installation requests have been made from your IP address. Please try again later.', 'wordfence');
}
elseif ($payloadException instanceof wfWebsiteEphemeralPayloadExpiredException) {
$errorMessage = __('The link you used to access this page has expired, has already been used, or is otherwise invalid.', 'wordfence');
}
else {
$errorMessage = __('An error occurred while retrieving your license information from the Wordfence servers. Please ensure that your server can reach www.wordfence.com on port 443.', 'wordfence');
}
}
?>
<div class="wrap wordfence" id="wf-install">
<div class="wf-container-fluid">
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wp-header-end"></div>
<?php
echo wfView::create('common/section-title', array(
'title' => __('Install Wordfence', 'wordfence'),
'showIcon' => true,
))->render();
?>
</div>
</div>
<div class="wf-row">
<div class="wf-col-xs-12">
<?php if ($errorMessage): ?>
<p class="wf-onboarding-error"><?php echo esc_html($errorMessage) ?></p>
<?php endif ?>
<?php if ($shouldShowOnboarding): ?>
<?php echo wfView::create('onboarding/registration-prompt', array('attempt' => 1, 'existing' => true, 'email' => $email, 'license' => $license)) ?>
<?php endif ?>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,435 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
$waf = wfWAF::getInstance();
$d = new wfDashboard(); unset($d->countriesNetwork);
$firewall = new wfFirewall();
$scanner = wfScanner::shared();
$config = $waf->getStorageEngine();
$wafURL = wfPage::pageURL(wfPage::PAGE_FIREWALL);
$wafConfigURL = network_admin_url('admin.php?page=WordfenceWAF&subpage=waf_options#configureAutoPrepend');
$wafRemoveURL = network_admin_url('admin.php?page=WordfenceWAF&subpage=waf_options#removeAutoPrepend');
/** @var array $wafData */
$backPage = new wfPage(wfPage::PAGE_FIREWALL);
if (isset($_GET['source']) && wfPage::isValidPage($_GET['source'])) {
$backPage = new wfPage($_GET['source']);
}
?>
<script type="application/javascript">
(function($) {
WFAD.wafData = <?php echo json_encode($wafData); ?>;
WFAD.restoreWAFData = JSON.parse(JSON.stringify(WFAD.wafData)); //Copied into wafData when canceling changes
$(function() {
document.title = "<?php esc_attr_e('All Options', 'wordfence'); ?>" + " \u2039 " + WFAD.basePageName;
WFAD.wafConfigPageRender();
//Hash-based option block linking
if (window.location.hash) {
var hashes = WFAD.parseHashes();
var hash = hashes[hashes.length - 1];
var block = $('.wf-block[data-persistence-key="' + hash + '"]');
if (block.length) {
if (!block.hasClass('wf-active')) {
block.find('.wf-block-content').slideDown({
always: function() {
block.addClass('wf-active');
$('html, body').animate({
scrollTop: block.offset().top - 100
}, 1000);
}
});
WFAD.ajax('wordfence_saveDisclosureState', {name: block.data('persistenceKey'), state: true}, function() {}, function() {}, true);
}
else {
$('html, body').animate({
scrollTop: block.offset().top - 100
}, 1000);
}
history.replaceState('', document.title, window.location.pathname + window.location.search);
}
}
});
$(window).on('wfOptionsReset', function() {
WFAD.wafData = JSON.parse(JSON.stringify(WFAD.restoreWAFData));
WFAD.wafConfigPageRender();
});
})(jQuery);
</script>
<div class="wf-options-controls">
<div class="wf-row">
<div class="wf-col-xs-12">
<?php
$indexOptions = array(
'wf-option-apiKey' => __('License Key', 'wordfence'),
'wf-option-displayTopLevelOptions' => __('Display All Options menu item', 'wordfence'),
'wf-option-displayTopLevelBlocking' => __('Display Blocking menu item', 'wordfence'),
'wf-option-displayTopLevelLiveTraffic' => __('Display Live Traffic menu item', 'wordfence'),
'wf-option-autoUpdate' => __('Update Wordfence automatically when a new version is released?', 'wordfence'),
'wf-option-alertEmails' => __('Where to email alerts', 'wordfence'),
'wf-option-howGetIPs' => __('How does Wordfence get IPs', 'wordfence'),
'wf-option-howGetIPs-trusted-proxies' => __('Trusted Proxies', 'wordfence'),
'wf-option-enableRemoteIpLookup' => __('Look up visitor IP locations via Wordfence servers', 'wordfence'),
'wf-option-other-hideWPVersion' => __('Hide WordPress version', 'wordfence'),
'wf-option-disableCodeExecutionUploads' => __('Disable Code Execution for Uploads directory', 'wordfence'),
'wf-option-liveActivityPauseEnabled' => __('Pause live updates when window loses focus', 'wordfence'),
'wf-option-actUpdateInterval' => __('Update interval in seconds', 'wordfence'),
'wf-option-other-bypassLitespeedNoabort' => __('Bypass the LiteSpeed "noabort" check', 'wordfence'),
'wf-option-deleteTablesOnDeact' => __('Delete Wordfence tables and data on deactivation', 'wordfence'),
'wf-option-notification-updatesNeeded' => __('Updates Needed (Plugin, Theme, or Core)', 'wordfence'),
'wf-option-notification-securityAlerts' => __('Security Alerts', 'wordfence'),
'wf-option-notification-promotions' => __('Promotions', 'wordfence'),
'wf-option-notification-blogHighlights' => __('Blog Highlights', 'wordfence'),
'wf-option-notification-productUpdates' => __('Product Updates', 'wordfence'),
'wf-option-notification-scanStatus' => __('Scan Status', 'wordfence'),
'wf-option-alertOn-update' => __('Email me when Wordfence is automatically updated', 'wordfence'),
'wf-option-alertOn-wordfenceDeactivated' => __('Email me if Wordfence is deactivated', 'wordfence'),
'wf-option-alertOn-wafDeactivated' => __('Email me if the Wordfence Web Application Firewall is turned off', 'wordfence'),
'wf-option-alertOn-scanIssues' => __('Alert me with scan results of this severity level or greater', 'wordfence'),
'wf-option-alertOn-block' => __('Alert when an IP address is blocked', 'wordfence'),
'wf-option-alertOn-loginLockout' => __('Alert when someone is locked out from login', 'wordfence'),
'wf-option-alertOn-lostPasswdForm' => __('Alert when the "lost password" form is used for a valid user', 'wordfence'),
'wf-option-alertOn-adminLogin' => __('Alert me when someone with administrator access signs in', 'wordfence'),
'wf-option-alertOn-firstAdminLoginOnly' => __('Only alert me when that administrator signs in from a new device', 'wordfence'),
'wf-option-alertOn-nonAdminLogin' => __('Alert me when a non-admin user signs in', 'wordfence'),
'wf-option-alertOn-firstNonAdminLoginOnly' => __('Only alert me when that user signs in from a new device', 'wordfence'),
'wf-option-wafAlertOnAttacks' => __('Alert me when there\'s a large increase in attacks detected on my site', 'wordfence'),
'wf-option-alert-maxHourly' => __('Maximum email alerts to send per hour', 'wordfence'),
'wf-option-email-summary-enabled' => __('Enable email summary', 'wordfence'),
'wf-option-email-summary-excluded-directories' => __('List of directories to exclude from recently modified file list', 'wordfence'),
'wf-option-email-summary-dashboard-widget-enabled' => __('Enable activity report widget on the WordPress dashboard', 'wordfence'),
'wf-option-wafStatus' => __('Web Application Firewall Status', 'wordfence'),
'wf-option-protectionMode' => __('Web Application Firewall Protection Level', 'wordfence'),
'wf-option-disableWAFBlacklistBlocking' => __('Real-Time IP Blocklist', 'wordfence'),
'wf-option-disableWAFIPBlocking' => __('Delay IP and Country blocking until after WordPress and plugins have loaded (only process firewall rules early)', 'wordfence'),
'wf-option-whitelisted' => __('Allowlisted IP addresses that bypass all rules', 'wordfence'),
'wf-option-whitelistedServices' => __('Allowlisted services', 'wordfence'),
'wf-option-bannedURLs' => __('Immediately block IPs that access these URLs', 'wordfence'),
'wf-option-wafAlertWhitelist' => __('Ignored IP addresses for Wordfence Web Application Firewall alerting', 'wordfence'),
'wf-option-wafRules' => __('Web Application Firewall Rules', 'wordfence'),
'wf-option-loginSecurityEnabled' => __('Enable brute force protection', 'wordfence'),
'wf-option-loginSec-maxFailures' => __('Lock out after how many login failures', 'wordfence'),
'wf-option-loginSec-maxForgotPasswd' => __('Lock out after how many forgot password attempts', 'wordfence'),
'wf-option-loginSec-countFailMins' => __('Count failures over what time period', 'wordfence'),
'wf-option-loginSec-lockoutMins' => __('Amount of time a user is locked out', 'wordfence'),
'wf-option-loginSec-lockInvalidUsers' => __('Immediately lock out invalid usernames', 'wordfence'),
'wf-option-loginSec-userBlacklist' => __('Immediately block the IP of users who try to sign in as these usernames', 'wordfence'),
'wf-option-loginSec-strongPasswds-enabled' => __('Enforce strong passwords', 'wordfence'),
'wf-option-loginSec-breachPasswds-enabled' => __('Prevent the use of passwords leaked in data breaches', 'wordfence'),
'wf-option-loginSec-maskLoginErrors' => __('Don\'t let WordPress reveal valid users in login errors', 'wordfence'),
'wf-option-loginSec-blockAdminReg' => __('Prevent users registering "admin" username if it doesn\'t exist', 'wordfence'),
'wf-option-loginSec-disableAuthorScan' => __('Prevent discovery of usernames through "/?author=N" scans, the oEmbed API, the WordPress REST API, and WordPress XML Sitemaps', 'wordfence'),
'wf-option-loginSec-disableApplicationPasswords' => __('Disable WordPress application passwords', 'wordfence'),
'wf-option-other-blockBadPOST' => __('Block IPs who send POST requests with blank User-Agent and Referer', 'wordfence'),
'wf-option-blockCustomText' => __('Custom text shown on block pages', 'wordfence'),
'wf-option-other-pwStrengthOnUpdate' => __('Check password strength on profile update', 'wordfence'),
'wf-option-other-WFNet' => __('Participate in the Real-Time Wordfence Security Network', 'wordfence'),
'wf-option-firewallEnabled' => __('Enable Rate Limiting and Advanced Blocking', 'wordfence'),
'wf-option-neverBlockBG' => __('How should we treat Google\'s crawlers', 'wordfence'),
'wf-option-maxGlobalRequests' => __('If anyone\'s requests exceed', 'wordfence'),
'wf-option-maxRequestsCrawlers' => __('If a crawler\'s page views exceed', 'wordfence'),
'wf-option-max404Crawlers' => __('If a crawler\'s pages not found (404s) exceed', 'wordfence'),
'wf-option-maxRequestsHumans' => __('If a human\'s page views exceed', 'wordfence'),
'wf-option-max404Humans' => __('If a human\'s pages not found (404s) exceed', 'wordfence'),
'wf-option-blockedTime' => __('How long is an IP address blocked when it breaks a rule', 'wordfence'),
'wf-option-allowed404s' => __('Allowlisted 404 URLs', 'wordfence'),
'wf-option-wafWhitelist' => __('Web Application Firewall Allowlisted URLs', 'wordfence'),
'wf-option-ajaxWatcherDisabled-front' => __('Monitor background requests from an administrator\'s web browser for false positives (Front-end Website)', 'wordfence'),
'wf-option-ajaxWatcherDisabled-admin' => __('Monitor background requests from an administrator\'s web browser for false positives (Admin Panel)', 'wordfence'),
'wf-option-cbl-action' => __('What to do when we block someone visiting from a blocked country', 'wordfence'),
'wf-option-cbl-redirURL' => __('URL to redirect blocked countries to', 'wordfence'),
'wf-option-cbl-loggedInBlocked' => __('Block countries even if they are logged in', 'wordfence'),
'wf-option-cbl-bypassRedirURL' => __('If user from a blocked country hits the relative URL ____ then redirect that user to ____ and set a cookie that will bypass all country blocking', 'wordfence'),
'wf-option-cbl-bypassViewURL' => __('If user who is allowed to access the site views the relative URL ____ then set a cookie that will bypass country blocking in future in case that user hits the site from a blocked country', 'wordfence'),
'wf-option-scheduledScansEnabled' => __('Schedule Wordfence Scans', 'wordfence'),
'wf-option-scanType' => __('Scan Type', 'wordfence'),
'wf-option-scansEnabled-checkGSB' => __('Check if this website is on a domain blocklist', 'wordfence'),
'wf-option-spamvertizeCheck' => __('Check if this website is being &quot;Spamvertised&quot;', 'wordfence'),
'wf-option-checkSpamIP' => __('Check if this website IP is generating spam', 'wordfence'),
'wf-option-scansEnabled-checkHowGetIPs' => __('Scan for misconfigured How does Wordfence get IPs', 'wordfence'),
'wf-option-scansEnabled-checkReadableConfig' => __('Scan for publicly accessible configuration, backup, or log files', 'wordfence'),
'wf-option-scansEnabled-suspectedFiles' => __('Scan for publicly accessible quarantined files', 'wordfence'),
'wf-option-scansEnabled-core' => __('Scan core files against repository versions for changes', 'wordfence'),
'wf-option-scansEnabled-themes' => __('Scan theme files against repository versions for changes', 'wordfence'),
'wf-option-scansEnabled-plugins' => __('Scan plugin files against repository versions for changes', 'wordfence'),
'wf-option-scansEnabled-coreUnknown' => __('Scan wp-admin and wp-includes for files not bundled with WordPress', 'wordfence'),
'wf-option-scansEnabled-malware' => __('Scan for signatures of known malicious files', 'wordfence'),
'wf-option-scansEnabled-fileContents' => __('Scan file contents for backdoors, trojans and suspicious code', 'wordfence'),
'wf-option-scansEnabled-fileContentsGSB' => __('Scan file contents for malicious URLs', 'wordfence'),
'wf-option-scansEnabled-posts' => __('Scan posts for known dangerous URLs and suspicious content', 'wordfence'),
'wf-option-scansEnabled-comments' => __('Scan comments for known dangerous URLs and suspicious content', 'wordfence'),
'wf-option-scansEnabled-suspiciousOptions' => __('Scan WordPress core, plugin, and theme options for known dangerous URLs and suspicious content', 'wordfence'),
'wf-option-scansEnabled-oldVersions' => __('Scan for out of date, abandoned, and vulnerable plugins, themes, and WordPress versions', 'wordfence'),
'wf-option-scansEnabled-suspiciousAdminUsers' => __('Scan for suspicious admin users created outside of WordPress', 'wordfence'),
'wf-option-scansEnabled-passwds' => __('Check the strength of passwords', 'wordfence'),
'wf-option-scansEnabled-diskSpace' => __('Monitor disk space', 'wordfence'),
'wf-option-scansEnabled-wafStatus' => __('Monitor Web Application Firewall status', 'wordfence'),
'wf-option-other-scanOutside' => __('Scan files outside your WordPress installation', 'wordfence'),
'wf-option-scansEnabled-scanImages' => __('Scan images, binary, and other files as if they were executable', 'wordfence'),
'wf-option-lowResourceScansEnabled' => __('Use low resource scanning (reduces server load by lengthening the scan duration)', 'wordfence'),
'wf-option-scan-maxIssues' => __('Limit the number of issues sent in the scan results email', 'wordfence'),
'wf-option-scan-maxDuration' => __('Time limit that a scan can run in seconds', 'wordfence'),
'wf-option-maxMem' => __('How much memory should Wordfence request when scanning', 'wordfence'),
'wf-option-maxExecutionTime' => __('Maximum execution time for each scan stage', 'wordfence'),
'wf-option-scan-exclude' => __('Exclude files from scan that match these wildcard patterns', 'wordfence'),
'wf-option-scan-include-extra' => __('Additional scan signatures', 'wordfence'),
'wf-option-scan-force-ipv4-start' => __('Use only IPv4 to start scans', 'wordfence'),
'wf-option-scan-max-resume-attempts' => __('Maximum number of attempts to resume each scan stage', 'wordfence'),
'wf-option-liveTrafficEnabled' => __('Traffic logging mode (Live Traffic)', 'wordfence'),
'wf-option-liveTraf-ignorePublishers' => __('Don\'t log signed-in users with publishing access', 'wordfence'),
'wf-option-liveTraf-ignoreUsers' => __('List of comma separated usernames to ignore', 'wordfence'),
'wf-option-liveTraf-ignoreIPs' => __('List of comma separated IP addresses to ignore', 'wordfence'),
'wf-option-liveTraf-ignoreUA' => __('Browser user-agent to ignore', 'wordfence'),
'wf-option-liveTraf-maxRows' => __('Amount of Live Traffic data to store (number of rows)', 'wordfence'),
'wf-option-liveTraf-maxAge' => __('Maximum days to keep Live Traffic data', 'wordfence'),
'wf-option-exportOptions' => __('Export this site\'s Wordfence options for import on another site', 'wordfence'),
'wf-option-importOptions' => __('Import Wordfence options from another site using a token', 'wordfence'),
);
if (wfCredentialsController::useLegacy2FA()) {
$indexOptions['wf-option-loginSec-requireAdminTwoFactor'] = __('Require Cellphone Sign-in for all Administrators', 'wordfence');
$indexOptions['wf-option-loginSec-enableSeparateTwoFactor'] = __('Enable Separate Prompt for Two Factor Code', 'wordfence');
}
$indexOptions = array_merge($indexOptions, wfModuleController::shared()->optionIndexes);
echo wfView::create('options/block-all-options-controls', array(
'showIcon' => false,
'indexOptions' => $indexOptions,
'restoreDefaultsSection' => wfConfig::OPTIONS_TYPE_ALL,
'restoreDefaultsMessage' => __('Are you sure you want to restore the default settings? This will undo any custom changes you have made to the options on this page. If you have manually disabled any rules or added any custom allowlisted URLs, those changes will not be overwritten.', 'wordfence'),
))->render();
?>
</div>
</div>
</div>
<div class="wf-options-controls-spacer"></div>
<?php
if (!wfOnboardingController::shouldShowAttempt3() && wfConfig::get('touppPromptNeeded')) {
echo wfView::create('gdpr/disabled-overlay')->render();
echo wfView::create('gdpr/banner')->render();
}
?>
<div class="wrap wordfence">
<div class="wf-container-fluid">
<?php
if (function_exists('network_admin_url') && is_multisite()) {
$firewallURL = network_admin_url('admin.php?page=WordfenceWAF#top#waf');
$blockingURL = network_admin_url('admin.php?page=WordfenceWAF#top#blocking');
}
else {
$firewallURL = admin_url('admin.php?page=WordfenceWAF#top#waf');
$blockingURL = admin_url('admin.php?page=WordfenceWAF#top#blocking');
}
?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wp-header-end"></div>
</div>
</div>
<div class="wf-row">
<div class="<?php echo wfStyle::contentClasses(); ?>">
<div id="wf-all-options" class="wf-fixed-tab-content">
<?php
$stateKeys = array(
'wf-unified-global-options-license',
'wf-unified-global-options-view-customization',
'wf-unified-global-options-general',
'wf-unified-global-options-dashboard',
'wf-unified-global-options-alert',
'wf-unified-global-options-email-summary',
'wf-unified-waf-options-basic',
'wf-unified-waf-options-advanced',
'wf-unified-waf-options-bruteforce',
'wf-unified-waf-options-ratelimiting',
'wf-unified-waf-options-whitelisted',
'wf-unified-blocking-options-country',
'wf-unified-scanner-options-schedule',
'wf-unified-scanner-options-basic',
'wf-unified-scanner-options-general',
'wf-unified-scanner-options-performance',
'wf-unified-scanner-options-custom',
'wf-unified-2fa-options',
'wf-unified-live-traffic-options',
);
echo wfView::create('options/options-title', array(
'title' => __('All Options', 'wordfence'),
'stateKeys' => $stateKeys,
'showIcon' => true,
))->render();
?>
<p><?php esc_html_e('These options are also available throughout the plugin pages, in the relevant sections. This page is provided for easier setup for experienced Wordfence users.', 'wordfence'); ?></p>
<?php
echo wfView::create('common/section-subtitle', array(
'title' => __('Wordfence Global Options', 'wordfence'),
'showIcon' => false,
))->render();
echo wfView::create('dashboard/options-group-license', array(
'stateKey' => 'wf-unified-global-options-license',
))->render();
echo wfView::create('dashboard/options-group-view-customization', array(
'stateKey' => 'wf-unified-global-options-view-customization',
))->render();
echo wfView::create('dashboard/options-group-general', array(
'stateKey' => 'wf-unified-global-options-general',
))->render();
echo wfView::create('dashboard/options-group-dashboard', array(
'stateKey' => 'wf-unified-global-options-dashboard',
))->render();
echo wfView::create('dashboard/options-group-alert', array(
'stateKey' => 'wf-unified-global-options-alert',
))->render();
echo wfView::create('dashboard/options-group-email-summary', array(
'stateKey' => 'wf-unified-global-options-email-summary',
))->render();
?>
<?php
echo wfView::create('common/section-subtitle', array(
'title' => __('Firewall Options', 'wordfence'),
'showIcon' => false,
))->render();
echo wfView::create('waf/options-group-basic-firewall', array(
'firewall' => $firewall,
'waf' => $waf,
'stateKey' => 'wf-unified-waf-options-basic',
))->render();
echo wfView::create('waf/options-group-advanced-firewall', array(
'firewall' => $firewall,
'waf' => $waf,
'stateKey' => 'wf-unified-waf-options-advanced',
))->render();
echo wfView::create('waf/options-group-brute-force', array(
'firewall' => $firewall,
'waf' => $waf,
'stateKey' => 'wf-unified-waf-options-bruteforce',
))->render();
echo wfView::create('waf/options-group-rate-limiting', array(
'firewall' => $firewall,
'waf' => $waf,
'stateKey' => 'wf-unified-waf-options-ratelimiting',
))->render();
echo wfView::create('waf/options-group-whitelisted', array(
'firewall' => $firewall,
'waf' => $waf,
'stateKey' => 'wf-unified-waf-options-whitelisted',
))->render();
?>
<?php
echo wfView::create('common/section-subtitle', array(
'title' => __('Blocking Options', 'wordfence'),
'showIcon' => false,
))->render();
echo wfView::create('blocking/options-group-advanced-country', array(
'stateKey' => 'wf-unified-blocking-options-country',
))->render();
?>
<?php
echo wfView::create('common/section-subtitle', array(
'title' => __('Scan Options', 'wordfence'),
'showIcon' => false,
))->render();
echo wfView::create('scanner/options-group-scan-schedule', array(
'scanner' => $scanner,
'stateKey' => 'wf-unified-scanner-options-schedule',
))->render();
echo wfView::create('scanner/options-group-basic', array(
'scanner' => $scanner,
'stateKey' => 'wf-unified-scanner-options-basic',
))->render();
echo wfView::create('scanner/options-group-general', array(
'scanner' => $scanner,
'stateKey' => 'wf-unified-scanner-options-general',
))->render();
echo wfView::create('scanner/options-group-performance', array(
'scanner' => $scanner,
'stateKey' => 'wf-unified-scanner-options-performance',
))->render();
echo wfView::create('scanner/options-group-advanced', array(
'scanner' => $scanner,
'stateKey' => 'wf-unified-scanner-options-custom',
))->render();
?>
<?php
echo wfView::create('common/section-subtitle', array(
'title' => __('Tool Options', 'wordfence'),
'showIcon' => false,
))->render();
if (wfCredentialsController::useLegacy2FA()) {
echo wfView::create('tools/options-group-2fa', array(
'stateKey' => 'wf-unified-2fa-options',
))->render();
}
echo wfView::create('tools/options-group-live-traffic', array(
'stateKey' => 'wf-unified-live-traffic-options',
'hideShowMenuItem' => true,
))->render();
?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-block wf-always-active" data-persistence-key="">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('Import/Export Options', 'wordfence'); ?></strong>
</div>
</div>
</div>
<div class="wf-block-content">
<ul class="wf-block-list">
<li>
<ul class="wf-flex-horizontal wf-flex-vertical-xs wf-flex-full-width wf-add-top wf-add-bottom">
<li><?php esc_html_e('Importing and exporting of options is available on the Tools page', 'wordfence'); ?></li>
<li class="wf-right wf-left-xs wf-padding-add-top-xs-small">
<a href="<?php echo esc_url(network_admin_url('admin.php?page=WordfenceTools&subpage=importexport')); ?>" class="wf-btn wf-btn-primary wf-btn-callout-subtle" id="wf-export-options"><?php esc_html_e('Import/Export Options', 'wordfence'); ?></a>
</li>
</ul>
<input type="hidden" id="wf-option-exportOptions">
<input type="hidden" id="wf-option-importOptions">
</li>
</ul>
</div>
</div>
</div>
</div> <!-- end import options -->
<?php
$moduleOptionBlocks = wfModuleController::shared()->optionBlocks;
foreach ($moduleOptionBlocks as $b) {
echo $b;
}
?>
</div> <!-- end options block -->
</div> <!-- end content block -->
</div> <!-- end row -->
</div> <!-- end container -->
</div>

View File

@@ -0,0 +1,393 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
$scanner = wfScanner::shared();
$issues = wfIssues::shared();
$dashboard = new wfDashboard();
?>
<?php if (wfConfig::get('liveActivityPauseEnabled')): ?>
<div id="wfLiveTrafficOverlayAnchor"></div>
<div id="wfLiveTrafficDisabledMessage">
<h2><?php echo wp_kses(__('Status Updates Paused<br /><small>Click inside window to resume</small>', 'wordfence'), array('small'=>array(), 'br'=>array())); ?></h2>
</div>
<?php endif; ?>
<?php
if (!wfOnboardingController::shouldShowAttempt3() && wfConfig::get('touppPromptNeeded')) {
echo wfView::create('gdpr/disabled-overlay')->render();
echo wfView::create('gdpr/banner')->render();
}
?>
<div id="wordfenceMode_scan"></div>
<div class="wrap wordfence">
<div class="wf-container-fluid">
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wp-header-end"></div>
<?php
echo wfView::create('common/section-title', array(
'title' => __('Scan', 'wordfence'),
'headerID' => 'wf-section-scan',
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_SCAN),
'helpLabelHTML' => wp_kses(__('Learn more<span class="wf-hidden-xs"> about the Scanner</span>', 'wordfence'), array('span'=>array('class'=>array()))),
'showIcon' => true,
))->render();
?>
</div>
<div class="wf-col-xs-12">
<div class="wf-block wf-active">
<div class="wf-block-content">
<ul class="wf-block-list">
<li>
<?php
echo wfView::create('scanner/scanner-status', array(
'scanner' => $scanner,
'dashboard' => $dashboard,
))->render();
?>
</li>
<li>
<ul class="wf-block-list wf-block-list-horizontal wf-block-list-nowrap wf-scanner-coverage">
<li>
<?php
if (function_exists('network_admin_url') && is_multisite()) { $optionsURL = network_admin_url('admin.php?page=WordfenceScan&subpage=scan_options'); }
else { $optionsURL = admin_url('admin.php?page=WordfenceScan&subpage=scan_options'); }
echo wfView::create('common/status-detail', array(
'id' => 'wf-scanner-type',
'percentage' => $scanner->scanTypeStatus(),
'activeColor' => (!$scanner->isEnabled() ? '#ececec' : null /* automatic */),
'title' => __('Scan Type: ', 'wordfence') . wfScanner::displayScanType($scanner->scanType()),
'subtitle' => wfScanner::displayScanTypeDetail($scanner->scanType()),
'link' => $optionsURL,
'linkLabel' => __('Manage Scan', 'wordfence'),
'statusTitle' => __('Scan Status', 'wordfence'),
'statusList' => $scanner->scanTypeStatusList(),
'helpLink' => __('https://www.wordfence.com/help/scan/#scan-status', 'wordfence'),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('common/status-detail', array(
'id' => 'wf-scanner-malware-type',
'percentage' => $scanner->signatureMode() == wfScanner::SIGNATURE_MODE_PREMIUM ? 1.0 : 0.7,
'activeColor' => (!$scanner->isEnabled() ? '#ececec' : null /* automatic */),
'title' => __('Malware Signatures: ', 'wordfence') . ($scanner->signatureMode() == wfScanner::SIGNATURE_MODE_PREMIUM ? __('Premium', 'wordfence') : __('Community', 'wordfence')),
'subtitle' => ($scanner->signatureMode() == wfScanner::SIGNATURE_MODE_PREMIUM ? __('Signatures updated in real-time', 'wordfence') : __('Signature updates delayed by 30 days', 'wordfence')),
'link' => 'https://www.wordfence.com/gnl1scanUpgrade/wordfence-signup/',
'linkLabel' => ($scanner->signatureMode() == wfScanner::SIGNATURE_MODE_PREMIUM ? __('Protect More Sites', 'wordfence') : __('Upgrade to Premium', 'wordfence')),
'linkNewWindow' => true,
'statusTitle' => __('Malware Signatures Status', 'wordfence'),
'statusList' => $scanner->signatureMode() == wfScanner::SIGNATURE_MODE_PREMIUM ? array() : array(array(
'percentage' => 0.30,
'title' => __('Enable Premium Scan Signatures.', 'wordfence'),
)),
'helpLink' => __('https://www.wordfence.com/help/scan/#scan-status', 'wordfence'),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('common/status-detail', array(
'id' => 'wf-scanner-reputation',
'percentage' => $scanner->reputationStatus(),
'activeColor' => (!$scanner->isEnabled() ? '#ececec' : null /* automatic */),
'title' => __('Reputation Checks', 'wordfence'),
'subtitle' => __('Check spam &amp; spamvertising blocklists', 'wordfence'),
'link' => $optionsURL . '#wf-scanner-options-general',
'linkLabel' => __('Manage Options', 'wordfence'),
'statusTitle' => __('Reputation Check Status', 'wordfence'),
'statusList' => $scanner->reputationStatusList(),
'helpLink' => __('https://www.wordfence.com/help/scan/#scan-status', 'wordfence'),
))->render();
?>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-block wf-active">
<div class="wf-block-content">
<ul class="wf-block-list">
<li>
<ul class="wf-block-list wf-block-list-horizontal wf-scan-navigation">
<li>
<?php
echo wfView::create('scanner/scan-starter', array(
'running' => wfScanner::shared()->isRunning(),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('common/block-navigation-option', array(
'id' => 'wf-scan-option-support',
'img' => 'support.svg',
'title' => __('Help', 'wordfence'),
'subtitle' => __('Find the documentation and help you need', 'wordfence'),
'link' => network_admin_url('admin.php?page=WordfenceSupport'),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('common/block-navigation-option', array(
'id' => 'wf-scan-option-all-options',
'img' => 'options.svg',
'title' => __('Scan Options and Scheduling', 'wordfence'),
'subtitle' => __('Manage scan options including scheduling', 'wordfence'),
'link' => network_admin_url('admin.php?page=WordfenceScan&subpage=scan_options'),
))->render();
?>
</li>
</ul>
</li>
<li id="wf-scan-progress-bar">
<?php
echo wfView::create('scanner/scan-progress', array(
'scanner' => $scanner,
'running' => wfScanner::shared()->isRunning(),
))->render();
?>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="wf-row">
<div class="wf-col-xs-12">
<?php
echo wfView::create('scanner/scan-progress-detailed', array(
'scanner' => $scanner,
))->render();
?>
</div>
</div>
<div class="wf-row">
<div class="wf-col-xs-12">
<?php
echo wfView::create('scanner/scan-results', array(
'scanner' => $scanner,
'issues' => $issues,
))->render();
?>
</div>
</div>
<div class="wf-row">
<div class="wf-col-xs-12">
<?php
echo wfView::create('scanner/site-cleaning-bottom', array(
))->render();
?>
</div>
</div>
</div> <!-- end container -->
</div>
<script type="application/javascript">
(function($) {
$(function() {
WFAD.updateActivityLog();
WFAD.startActivityLogUpdates();
});
})(jQuery);
</script>
<script type="text/x-jquery-template" id="wfTmpl_scannerDelete">
<?php
echo wfView::create('common/modal-prompt', array(
'title' => __('Are you sure you want to delete?', 'wordfence'),
'messageHTML' => '<p class="wf-callout-warning"><i class="wf-fa wf-fa-exclamation-triangle" aria-hidden="true"></i> ' . wp_kses(__('<strong>WARNING:</strong> If you delete the wrong file, it could cause your WordPress website to stop functioning, and you will probably have to restore from a backup.', 'wordfence'), array('strong'=>array())) . '</p>' .
'<p>' . wp_kses(sprintf(
/* translators: Support URL. */
__('Do not delete files on your system unless you\'re ABSOLUTELY sure you know what you\'re doing. If you delete the wrong file it could cause your WordPress website to stop functioning and you will probably have to restore from backups. If you\'re unsure, Cancel and work with your hosting provider to clean your system of infected files. If you\'d like to learn more, <a href="%s" target="_blank" rel="noopener noreferrer">click here for our help article<span class="screen-reader-text"> (opens in new tab)</span></a>.', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_SCAN_BULK_DELETE_WARNING)), array('a'=>array('href'=>array(), 'target'=>array(), 'rel'=>array()), 'span'=>array('class'=>array()))) . '</p>',
'primaryButton' => array('id' => 'wf-scanner-prompt-cancel', 'label' => __('Cancel', 'wordfence'), 'link' => '#', 'type' => 'wf-btn-default'),
'secondaryButtons' => array(array('id' => 'wf-scanner-prompt-confirm', 'label' => __('Delete Files', 'wordfence'), 'link' => '#', 'type' => 'wf-btn-danger')),
))->render();
?>
</script>
<script type="text/x-jquery-template" id="wfTmpl_scannerRepair">
<?php
echo wfView::create('common/modal-prompt', array(
'title' => __('Are you sure you want to repair?', 'wordfence'),
'message' => __('Do not repair files on your system unless you\'re ABSOLUTELY sure you know what you\'re doing. If you repair the wrong file it could cause your WordPress website to stop functioning and you will probably have to restore from backups. If you\'re unsure, Cancel and work with your hosting provider to clean your system of infected files.', 'wordfence'),
'primaryButton' => array('id' => 'wf-scanner-prompt-cancel', 'label' => __('Cancel', 'wordfence'), 'link' => '#'),
'secondaryButtons' => array(array('id' => 'wf-scanner-prompt-confirm', 'label' => __('Repair Files', 'wordfence'), 'link' => '#')),
))->render();
?>
</script>
<script type="text/x-jquery-template" id="wfTmpl_scannerStop">
<?php
echo wfView::create('common/modal-prompt', array(
'title' => '${title}',
'message' => '${message}',
'primaryButton' => array('id' => 'wf-generic-modal-close', 'label' => __('Close', 'wordfence'), 'link' => '#'),
))->render();
?>
</script>
<?php
echo wfView::create('scanner/site-cleaning')->render();
echo wfView::create('scanner/site-cleaning-high-sense')->render();
echo wfView::create('scanner/site-cleaning-beta-sigs')->render();
echo wfView::create('scanner/no-issues')->render();
echo wfView::create('scanner/issue-wfUpgrade')->render();
echo wfView::create('scanner/issue-wfUpgradeError')->render();
echo wfView::create('scanner/issue-wfPluginUpgrade')->render();
echo wfView::create('scanner/issue-wfThemeUpgrade')->render();
echo wfView::create('scanner/issue-wfPluginRemoved')->render();
echo wfView::create('scanner/issue-wfPluginAbandoned')->render();
echo wfView::create('scanner/issue-wfPluginVulnerable')->render();
echo wfView::create('scanner/issue-file')->render();
echo wfView::create('scanner/issue-skippedPaths')->render();
echo wfView::create('scanner/issue-knownfile')->render();
echo wfView::create('scanner/issue-configReadable')->render();
echo wfView::create('scanner/issue-publiclyAccessible')->render();
echo wfView::create('scanner/issue-coreUnknown')->render();
echo wfView::create('scanner/issue-diskSpace')->render();
echo wfView::create('scanner/issue-wafStatus')->render();
echo wfView::create('scanner/issue-geoipSupport')->render();
echo wfView::create('scanner/issue-easyPassword')->render();
echo wfView::create('scanner/issue-commentBadURL')->render();
echo wfView::create('scanner/issue-postBadURL')->render();
echo wfView::create('scanner/issue-postBadTitle')->render();
echo wfView::create('scanner/issue-optionBadURL')->render();
echo wfView::create('scanner/issue-database')->render();
echo wfView::create('scanner/issue-checkSpamIP')->render();
echo wfView::create('scanner/issue-spamvertizeCheck')->render();
echo wfView::create('scanner/issue-checkGSB')->render();
echo wfView::create('scanner/issue-checkHowGetIPs')->render();
echo wfView::create('scanner/issue-suspiciousAdminUsers')->render();
echo wfView::create('scanner/issue-timelimit')->render();
//Currently unused
echo wfView::create('scanner/issue-wpscan_fullPathDiscl')->render();
echo wfView::create('scanner/issue-wpscan_directoryList')->render();
if (wfOnboardingController::willShowNewTour(wfOnboardingController::TOUR_SCAN)): ?>
<script type="application/javascript">
(function($) {
$(function() {
WFAD.tour1 = function() {
WFAD.tour('wfNewTour1', 'wf-section-scan', 'top', 'left', null, WFAD.tour2);
};
WFAD.tour2 = function() {
WFAD.tour('wfNewTour2', 'wf-scan-option-all-options', 'right', 'right', WFAD.tour1, WFAD.tour3);
};
WFAD.tour3 = function() {
WFAD.tour('wfNewTour3', 'wf-scan-starter', 'left', 'left', WFAD.tour2, WFAD.tourComplete);
};
WFAD.tourComplete = function() { WFAD.tourFinish('<?php echo esc_attr(wfOnboardingController::TOUR_SCAN); ?>'); };
<?php if (wfOnboardingController::shouldShowNewTour(wfOnboardingController::TOUR_SCAN)): ?>
if (!WFAD.isSmallScreen) { WFAD.tour1(); }
<?php endif; ?>
});
})(jQuery);
</script>
<script type="text/x-jquery-template" id="wfNewTour1">
<div>
<h3><?php esc_html_e('Scan', 'wordfence'); ?></h3>
<p><?php esc_html_e('A Wordfence scan looks for malware, malicious URLs, and patterns of infections by examining all of the files, posts, and comments on your WordPress website. It also checks your server and monitors your site\'s online reputation.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li class="wf-active">&bullet;</li>
<li>&bullet;</li>
<li>&bullet;</li>
</ul>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Next', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<script type="text/x-jquery-template" id="wfNewTour2">
<div>
<h3><?php esc_html_e('Manage Scan Settings', 'wordfence'); ?></h3>
<p class="wf-center"><svg viewBox="0 0 100.11 100.11" class="wf-icon"><path d="M99.59,41.42a2.06,2.06,0,0,0-1.37-.82L86.3,38.78a39.34,39.34,0,0,0-2.67-6.39q1.17-1.63,3.52-4.6t3.32-4.33A2.52,2.52,0,0,0,91,22a2.1,2.1,0,0,0-.46-1.43Q88.18,17.2,79.78,9.45a2.52,2.52,0,0,0-1.63-.65,2.12,2.12,0,0,0-1.57.59l-9.25,7a40.09,40.09,0,0,0-5.87-2.41L59.64,2a1.92,1.92,0,0,0-.75-1.4A2.46,2.46,0,0,0,57.29,0H42.82a2.19,2.19,0,0,0-2.34,1.82,106,106,0,0,0-1.89,12.12,37.62,37.62,0,0,0-5.93,2.48l-9-7A2.78,2.78,0,0,0,22,8.8q-1.44,0-6.16,4.66a64.88,64.88,0,0,0-6.42,7A2.75,2.75,0,0,0,8.8,22a2.44,2.44,0,0,0,.65,1.56q4.37,5.28,7,9a32.38,32.38,0,0,0-2.54,6L1.76,40.34a2,2,0,0,0-1.24.85A2.5,2.5,0,0,0,0,42.69V57.16a2.44,2.44,0,0,0,.52,1.53,2,2,0,0,0,1.37.82l11.93,1.76a31.91,31.91,0,0,0,2.67,6.45Q15.31,69.35,13,72.31T9.65,76.65a2.54,2.54,0,0,0-.07,3q2.54,3.52,10.75,11a2.25,2.25,0,0,0,1.63.71,2.35,2.35,0,0,0,1.63-.59l9.19-7a40.54,40.54,0,0,0,5.87,2.41l1.82,12a1.92,1.92,0,0,0,.75,1.4,2.45,2.45,0,0,0,1.6.55H57.29a2.2,2.2,0,0,0,2.35-1.82,107.41,107.41,0,0,0,1.89-12.12,37.19,37.19,0,0,0,5.93-2.48l9,7a3.18,3.18,0,0,0,1.69.59q1.43,0,6.13-4.62a65.86,65.86,0,0,0,6.45-7,2.16,2.16,0,0,0,.59-1.5,2.51,2.51,0,0,0-.65-1.63q-4.69-5.74-7-9a41.57,41.57,0,0,0,2.54-5.93l12.06-1.82a2,2,0,0,0,1.3-.85,2.52,2.52,0,0,0,.52-1.5V43a2.46,2.46,0,0,0-.52-1.53ZM61.85,61.86a16.08,16.08,0,0,1-11.8,4.89A16.69,16.69,0,0,1,33.37,50.06,16.69,16.69,0,0,1,50.06,33.37,16.69,16.69,0,0,1,66.74,50.06a16.08,16.08,0,0,1-4.89,11.8Zm0,0"></path></svg></p>
<p><?php esc_html_e('Set up the way you want the scan to monitor your site security including custom scan configurations and scheduling.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li>&bullet;</li>
<li class="wf-active">&bullet;</li>
<li>&bullet;</li>
</ul>
<div id="wf-tour-previous"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-default" role="button"><?php esc_html_e('Previous', 'wordfence'); ?></a></div>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Next', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<script type="text/x-jquery-template" id="wfNewTour3">
<div>
<h3><?php esc_html_e('Start Your First Scan', 'wordfence'); ?></h3>
<p><?php esc_html_e('By default, Wordfence will scan your site daily. Start your first scan now to see if your site has any security issues that need to be addressed. From here you can run manual scans any time you like.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li>&bullet;</li>
<li>&bullet;</li>
<li class="wf-active">&bullet;</li>
</ul>
<div id="wf-tour-previous"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-default" role="button"><?php esc_html_e('Previous', 'wordfence'); ?></a></div>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Got it', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<?php endif; ?>
<?php if (wfOnboardingController::willShowUpgradeTour(wfOnboardingController::TOUR_SCAN)): ?>
<script type="application/javascript">
(function($) {
$(function() {
WFAD.tour1 = function() {
WFAD.tour('wfUpgradeTour1', 'wf-scan-option-all-options', 'right', 'right', null, WFAD.tour2);
};
WFAD.tour2 = function() {
WFAD.tour('wfUpgradeTour2', 'wf-scan-starter', 'left', 'left', WFAD.tour1, WFAD.tourComplete);
};
WFAD.tourComplete = function() { WFAD.tourFinish('<?php echo esc_attr(wfOnboardingController::TOUR_SCAN); ?>'); };
<?php if (wfOnboardingController::shouldShowUpgradeTour(wfOnboardingController::TOUR_SCAN)): ?>
if (!WFAD.isSmallScreen) { WFAD.tour1(); }
<?php endif; ?>
});
})(jQuery);
</script>
<script type="text/x-jquery-template" id="wfUpgradeTour1">
<div>
<h3><?php esc_html_e('Scan Options &amp; Settings', 'wordfence'); ?></h3>
<p class="wf-center"><svg viewBox="0 0 100.11 100.11" class="wf-icon"><path d="M99.59,41.42a2.06,2.06,0,0,0-1.37-.82L86.3,38.78a39.34,39.34,0,0,0-2.67-6.39q1.17-1.63,3.52-4.6t3.32-4.33A2.52,2.52,0,0,0,91,22a2.1,2.1,0,0,0-.46-1.43Q88.18,17.2,79.78,9.45a2.52,2.52,0,0,0-1.63-.65,2.12,2.12,0,0,0-1.57.59l-9.25,7a40.09,40.09,0,0,0-5.87-2.41L59.64,2a1.92,1.92,0,0,0-.75-1.4A2.46,2.46,0,0,0,57.29,0H42.82a2.19,2.19,0,0,0-2.34,1.82,106,106,0,0,0-1.89,12.12,37.62,37.62,0,0,0-5.93,2.48l-9-7A2.78,2.78,0,0,0,22,8.8q-1.44,0-6.16,4.66a64.88,64.88,0,0,0-6.42,7A2.75,2.75,0,0,0,8.8,22a2.44,2.44,0,0,0,.65,1.56q4.37,5.28,7,9a32.38,32.38,0,0,0-2.54,6L1.76,40.34a2,2,0,0,0-1.24.85A2.5,2.5,0,0,0,0,42.69V57.16a2.44,2.44,0,0,0,.52,1.53,2,2,0,0,0,1.37.82l11.93,1.76a31.91,31.91,0,0,0,2.67,6.45Q15.31,69.35,13,72.31T9.65,76.65a2.54,2.54,0,0,0-.07,3q2.54,3.52,10.75,11a2.25,2.25,0,0,0,1.63.71,2.35,2.35,0,0,0,1.63-.59l9.19-7a40.54,40.54,0,0,0,5.87,2.41l1.82,12a1.92,1.92,0,0,0,.75,1.4,2.45,2.45,0,0,0,1.6.55H57.29a2.2,2.2,0,0,0,2.35-1.82,107.41,107.41,0,0,0,1.89-12.12,37.19,37.19,0,0,0,5.93-2.48l9,7a3.18,3.18,0,0,0,1.69.59q1.43,0,6.13-4.62a65.86,65.86,0,0,0,6.45-7,2.16,2.16,0,0,0,.59-1.5,2.51,2.51,0,0,0-.65-1.63q-4.69-5.74-7-9a41.57,41.57,0,0,0,2.54-5.93l12.06-1.82a2,2,0,0,0,1.3-.85,2.52,2.52,0,0,0,.52-1.5V43a2.46,2.46,0,0,0-.52-1.53ZM61.85,61.86a16.08,16.08,0,0,1-11.8,4.89A16.69,16.69,0,0,1,33.37,50.06,16.69,16.69,0,0,1,50.06,33.37,16.69,16.69,0,0,1,66.74,50.06a16.08,16.08,0,0,1-4.89,11.8Zm0,0"></path></svg></p>
<p class="wf-center"><?php esc_html_e('All of your scan options, including scheduling, are now located here.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li class="wf-active">&bullet;</li>
<li>&bullet;</li>
</ul>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Next', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<script type="text/x-jquery-template" id="wfUpgradeTour2">
<div>
<h3><?php esc_html_e('Scan Progress and Activity', 'wordfence'); ?></h3>
<p><?php esc_html_e('Track each scan stage as Wordfence scans your entire site. Along the way you can see the activity log one line at a time or expand the activity log for a more detailed view. Clicking on scan results will reveal detailed scan findings.', 'wordfence'); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li>&bullet;</li>
<li class="wf-active">&bullet;</li>
</ul>
<div id="wf-tour-previous"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-default" role="button"><?php esc_html_e('Previous', 'wordfence'); ?></a></div>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Got it', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<?php endif; ?>

View File

@@ -0,0 +1,79 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
$scanner = wfScanner::shared();
$scanURL = network_admin_url('admin.php?page=WordfenceScan');
$action = @$_GET['action'];
if (!in_array($action, array('restoreFile', 'deleteFile'))) { $action = ''; }
$filesystemCredentialsAdminURL = network_admin_url('admin.php?' . http_build_query(array(
'page' => 'WordfenceScan',
'subpage' => 'scan_credentials',
'action' => $action,
'issueID' => (int) @$_GET['issueID'],
'nonce' => wp_create_nonce('wp-ajax'),
)));
switch ($action) {
case 'restoreFile':
$callback = array('wordfence', 'fsActionRestoreFileCallback');
break;
case 'deleteFile':
$callback = array('wordfence', 'fsActionDeleteFileCallback');
break;
}
?>
<div class="wf-options-controls">
<div class="wf-row">
<div class="wf-col-xs-12">
<?php
echo wfView::create('options/block-controls', array(
'backLink' => $scanURL,
'backLabel' => __('Back to Scan', 'wordfence'),
'suppressControls' => true,
))->render();
?>
</div>
</div>
</div>
<div class="wf-options-controls-spacer"></div>
<div class="wrap wordfence">
<div class="wf-container-fluid">
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wp-header-end"></div>
</div>
</div>
<div class="wf-row">
<div class="<?php echo wfStyle::contentClasses(); ?>">
<div id="wf-scan-permissions-prompt" class="wf-fixed-tab-content">
<?php
echo wfView::create('common/section-title', array(
'title' => __('File System Credentials Required', 'wordfence'),
))->render();
?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-block wf-active">
<div class="wf-block-content wf-padding-add-top wf-padding-add-bottom">
<?php
if (isset($_GET['nonce']) && wp_verify_nonce($_GET['nonce'], 'wp-ajax')) {
if (wordfence::requestFilesystemCredentials($filesystemCredentialsAdminURL, wfUtils::getHomePath(), true, true)) {
call_user_func_array($callback, isset($callbackArgs) && is_array($callbackArgs) ? $callbackArgs : array());
}
//else - outputs credentials form
}
else {
echo '<p>' . wp_kses(sprintf(
/* translators: URL to the WordPress admin panel. */
__('Security token has expired. Click <a href="%s">here</a> to return to the scan page.', 'wordfence'), esc_url($scanURL)), array('a'=>array('href'=>array()))) . '</p>';
}
?>
</div>
</div>
</div>
</div> <!-- end permissions -->
</div> <!-- end wf-scan-permissions-prompt block -->
</div> <!-- end content block -->
</div> <!-- end row -->
</div> <!-- end container -->
</div>

View File

@@ -0,0 +1,208 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
$scanner = wfScanner::shared();
$scanOptions = $scanner->scanOptions();
$backPage = new wfPage(wfPage::PAGE_SCAN);
if (isset($_GET['source']) && wfPage::isValidPage($_GET['source'])) {
$backPage = new wfPage($_GET['source']);
}
?>
<script type="application/javascript">
(function($) {
$(function() {
document.title = "<?php esc_attr_e('Scanner Options', 'wordfence'); ?>" + " \u2039 " + WFAD.basePageName;
//Hash-based option block linking
if (window.location.hash) {
var hashes = WFAD.parseHashes();
var hash = hashes[hashes.length - 1];
var block = $('.wf-block[data-persistence-key="' + hash + '"]');
if (block && block.length) {
if (!block.hasClass('wf-active')) {
block.find('.wf-block-content').slideDown({
always: function() {
block.addClass('wf-active');
if (hashes.length > 1 && $('#' + hashes[hashes.length - 2]).hasClass('wf-option')) {
$('html, body').animate({
scrollTop: $('#' + hashes[hashes.length - 2]).offset().top - 100
}, 1000);
}
else {
$('html, body').animate({
scrollTop: block.offset().top - 100
}, 1000);
}
}
});
WFAD.ajax('wordfence_saveDisclosureState', {name: block.data('persistenceKey'), state: true}, function() {});
}
else {
if (hashes.length > 1 && $('#' + hashes[hashes.length - 2]).hasClass('wf-option')) {
$('html, body').animate({
scrollTop: $('#' + hashes[hashes.length - 2]).offset().top - 100
}, 1000);
}
else {
$('html, body').animate({
scrollTop: block.offset().top - 100
}, 1000);
}
}
history.replaceState('', document.title, window.location.pathname + window.location.search);
}
}
});
})(jQuery);
</script>
<div class="wf-options-controls">
<div class="wf-row">
<div class="wf-col-xs-12">
<?php
echo wfView::create('options/block-controls', array(
'backLink' => $backPage->url(),
'backLabelHTML' => wp_kses(sprintf(__('<span class="wf-hidden-xs">Back to </span>%s', 'wordfence'), $backPage->label()), array('span'=>array('class'=>array()))),
'restoreDefaultsSection' => wfConfig::OPTIONS_TYPE_SCANNER,
'restoreDefaultsMessage' => __('Are you sure you want to restore the default Scan settings? This will undo any custom changes you have made to the options on this page.', 'wordfence'),
))->render();
?>
</div>
</div>
</div>
<div class="wf-options-controls-spacer"></div>
<?php
if (!wfOnboardingController::shouldShowAttempt3() && wfConfig::get('touppPromptNeeded')) {
echo wfView::create('gdpr/disabled-overlay')->render();
echo wfView::create('gdpr/banner')->render();
}
?>
<div class="wrap wordfence">
<div class="wf-container-fluid">
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wp-header-end"></div>
</div>
</div>
<div class="wf-row">
<div class="<?php echo wfStyle::contentClasses(); ?>">
<div id="wf-scan-options" class="wf-fixed-tab-content">
<?php
echo wfView::create('common/section-title', array(
'title' => __('Scan Options and Scheduling', 'wordfence'),
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_SCAN),
'helpLabelHTML' => wp_kses(__('Learn more<span class="wf-hidden-xs"> about Scanning</span>', 'wordfence'), array('span'=>array('classes'=>array()))),
'showIcon' => true,
))->render();
?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-block wf-active">
<div class="wf-block-content">
<ul class="wf-block-list wf-block-list-horizontal wf-block-list-nowrap wf-scanner-coverage">
<li>
<?php
if (function_exists('network_admin_url') && is_multisite()) { $optionsURL = network_admin_url('admin.php?page=WordfenceScan&subpage=scan_options'); }
else { $optionsURL = admin_url('admin.php?page=WordfenceScan&subpage=scan_options'); }
echo wfView::create('common/status-detail', array(
'id' => 'wf-scanner-type',
'percentage' => $scanner->scanTypeStatus(),
'activeColor' => (!$scanner->isEnabled() ? '#ececec' : null /* automatic */),
'title' => __('Scan Type: ', 'wordfence') . wfScanner::displayScanType($scanner->scanType()),
'subtitle' => wfScanner::displayScanTypeDetail($scanner->scanType()),
'link' => $optionsURL,
'linkLabel' => null,
'statusTitle' => __('Scan Status', 'wordfence'),
'statusList' => $scanner->scanTypeStatusList(),
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_SCAN_STATUS_OVERALL),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('common/status-detail', array(
'id' => 'wf-scanner-malware-type',
'percentage' => $scanner->signatureMode() == wfScanner::SIGNATURE_MODE_PREMIUM ? 1.0 : 0.7,
'activeColor' => (!$scanner->isEnabled() ? '#ececec' : null /* automatic */),
'title' => __('Malware Signatures: ', 'wordfence') . ($scanner->signatureMode() == wfScanner::SIGNATURE_MODE_PREMIUM ? __('Premium', 'wordfence') : __('Community', 'wordfence')),
'subtitle' => ($scanner->signatureMode() == wfScanner::SIGNATURE_MODE_PREMIUM ? __('Signatures updated in real-time', 'wordfence') : __('Signature updates delayed by 30 days', 'wordfence')),
'link' => 'https://www.wordfence.com/gnl1scanUpgrade/wordfence-signup/',
'linkLabel' => null,
'statusTitle' => __('Malware Signatures Status', 'wordfence'),
'statusList' => $scanner->signatureMode() == wfScanner::SIGNATURE_MODE_PREMIUM ? array() : array(array(
'percentage' => 0.30,
'title' => __('Enable Premium Scan Signatures.', 'wordfence'),
)),
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_SCAN_STATUS_MALWARE),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('common/status-detail', array(
'id' => 'wf-scanner-reputation',
'percentage' => $scanner->reputationStatus(),
'activeColor' => (!$scanner->isEnabled() ? '#ececec' : null /* automatic */),
'title' => __('Reputation Checks', 'wordfence'),
'subtitle' => __('Check spam &amp; spamvertising blocklists', 'wordfence'),
'link' => $optionsURL . '#wf-scanner-options-general',
'linkLabel' => null,
'statusTitle' => __('Reputation Check Status', 'wordfence'),
'statusList' => $scanner->reputationStatusList(),
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_SCAN_STATUS_REPUTATION),
))->render();
?>
</li>
</ul>
</div>
</div>
</div>
</div>
<?php
echo wfView::create('scanner/options-group-scan-schedule', array(
'scanner' => $scanner,
'stateKey' => 'wf-scanner-options-schedule',
))->render();
echo wfView::create('scanner/options-group-basic', array(
'scanner' => $scanner,
'stateKey' => 'wf-scanner-options-basic',
'collapseable' => false,
))->render();
echo wfView::create('scanner/options-group-general', array(
'scanner' => $scanner,
'stateKey' => 'wf-scanner-options-general',
))->render();
echo wfView::create('scanner/options-group-performance', array(
'scanner' => $scanner,
'stateKey' => 'wf-scanner-options-performance',
))->render();
echo wfView::create('scanner/options-group-advanced', array(
'scanner' => $scanner,
'stateKey' => 'wf-scanner-options-custom',
))->render();
?>
</div> <!-- end wf-scan-options block -->
</div> <!-- end content block -->
</div> <!-- end row -->
</div> <!-- end container -->
</div>
<script type="application/javascript">
(function($) {
$(function() {
var updatePendingCircles = function() {
$('#circle-wf-scanner-type, #circle-wf-scanner-reputation').wfCircularProgress({pendingOverlay: Object.keys(WFAD.pendingChanges).length > 0});
};
var coalescingUpdateTimer = false;
$('.wf-option').on('change', function() {
clearTimeout(coalescingUpdateTimer);
coalescingUpdateTimer = setTimeout(updatePendingCircles, 100);
});
});
})(jQuery);
</script>

View File

@@ -0,0 +1,310 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
if (!wfOnboardingController::shouldShowAttempt3() && wfConfig::get('touppPromptNeeded')) {
echo wfView::create('gdpr/banner')->render();
}
$support = @json_decode(wfConfig::get('supportContent'), true);
?>
<div class="wrap wordfence">
<div class="wf-container-fluid">
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wp-header-end"></div>
<?php
echo wfView::create('common/section-title', array(
'title' => __('Help', 'wordfence'),
'showIcon' => true,
))->render();
?>
</div>
<div class="wf-col-xs-12">
<div class="wf-block wf-active">
<div class="wf-block-content">
<ul class="wf-block-list">
<li>
<ul class="wf-block-list wf-block-list-horizontal">
<li class="wf-flex-vertical">
<?php if (wfLicense::current()->isPaidAndCurrent()): ?>
<h3><?php esc_html_e('Premium Support', 'wordfence'); ?></h3>
<p class="wf-center">
<?php if (wfLicense::current()->isResponse()): ?>
<?php esc_html_e('As a Wordfence Response customer you are entitled to hands-on priority support 24 hours a day 365 days a year. Our incident response team is available out of hours to handle urgent issues and security incidents. Our customer support team is available during business hours (Monday to Friday, 6am to 5pm Pacific and 9am to 8pm Eastern time) for product assistance. Both teams can sign-in to your site to assist, on request.', 'wordfence'); ?>
<?php elseif (wfLicense::current()->isCare()): ?>
<?php esc_html_e('As a Wordfence Care customer you are entitled to hands-on priority support and have access to our incident response team. Our senior support engineers and incident response team respond to requests quickly within business hours (Monday to Friday, 6am to 5pm Pacific and 9am to 8pm Eastern time) and can sign-in to your site on request to assist with complex issues.', 'wordfence'); ?>
<?php else: ?>
<?php esc_html_e('As a Wordfence Premium customer you\'re entitled to paid support via our ticketing system. Our senior support engineers respond to Premium tickets during regular business hours (Monday to Friday, 6am to 5pm Pacific and 9am to 8pm Eastern time) and have a direct line to our QA and development teams.', 'wordfence') ?>
<?php endif ?>
</p>
<p>
<a href="<?php echo esc_attr(wfLicense::current()->getSupportUrl('helpPageSupport')) ?>" target="_blank" rel="noopener noreferrer" class="wf-btn wf-btn-primary wf-btn-callout-subtle"><?php esc_html_e('Get Help', 'wordfence'); ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a>
<div>
<?php if (wfLicense::current()->isBelowCare()): ?>
<a href="https://www.wordfence.com/gnl1helpPageCare/products/wordfence-care/" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Upgrade to hands-on support with Wordfence Care', 'wordfence') ?></a>
<?php elseif (wfLicense::current()->isBelowResponse()): ?>
<a href="https://www.wordfence.com/gnl1helpPageResponse/products/wordfence-response/" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Upgrade to a 24/7 1-hour response time with Wordfence Response', 'wordfence') ?></a>
<?php endif ?>
</div>
</p>
<?php else: ?>
<h3><?php esc_html_e('Upgrade Now to Access Premium Support', 'wordfence'); ?></h3>
<p class="wf-center"><?php echo wp_kses(__('Our senior support engineers <strong>respond to Premium tickets within a few hours</strong> on average and have a direct line to our QA and development teams.', 'wordfence'), array('strong'=>array())); ?></p>
<p><a href="https://www.wordfence.com/gnl1supportUpgrade/wordfence-signup/" target="_blank" rel="noopener noreferrer" class="wf-btn wf-btn-primary wf-btn-callout-subtle"><?php esc_html_e('Upgrade to Premium', 'wordfence'); ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a></p>
<?php endif; ?>
</li>
<li class="wf-flex-vertical">
<h3><?php esc_html_e('Free Support', 'wordfence'); ?></h3>
<p class="wf-center"><?php echo wp_kses(__('Support for free customers is available via our forums page on wordpress.org. The majority of requests <strong>receive an answer within a few days.</strong>', 'wordfence'), array('strong'=>array())); ?></p>
<p><a href="<?php echo wfSupportController::esc_supportURL(wfSupportController::ITEM_FREE); ?>" target="_blank" rel="noopener noreferrer" class="wf-btn wf-btn-default wf-btn-callout-subtle"><?php esc_html_e('Go to Support Forums', 'wordfence'); ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a></p>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-block<?php echo (wfPersistenceController::shared()->isActive('support-gdpr') ? ' wf-active' : ''); ?>" data-persistence-key="support-gdpr">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('GDPR Information', 'wordfence'); ?></strong>
</div>
<div class="wf-block-header-action"><div class="wf-block-header-action-disclosure" role="checkbox" aria-checked="<?php echo (wfPersistenceController::shared()->isActive('support-gdpr') ? 'true' : 'false'); ?>" tabindex="0"></div></div>
</div>
</div>
<div class="wf-block-content">
<ul class="wf-block-list">
<li>
<ul class="wf-option wf-option-static">
<li class="wf-option-title">
<ul class="wf-flex-vertical wf-flex-align-left">
<li><?php esc_html_e('General Data Protection Regulation', 'wordfence'); ?> <a href="<?php echo wfSupportController::esc_supportURL(wfSupportController::ITEM_GDPR); ?>" target="_blank" rel="noopener noreferrer" class="wf-inline-help"><i class="wf-fa wf-fa-question-circle-o" aria-hidden="true"></i><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a></li>
<li class="wf-option-subtitle"><?php esc_html_e('The GDPR is a set of rules that provides more control over EU personal data. Defiant has updated its terms of service, privacy policies, and software, as well as made available standard contractual clauses to meet GDPR compliance.', 'wordfence'); ?></li>
</ul>
</li>
</ul>
</li>
<li>
<ul class="wf-option wf-option-static">
<li class="wf-option-title">
<ul class="wf-flex-vertical wf-flex-align-left">
<li><?php esc_html_e('Agreement to New Terms and Privacy Policies', 'wordfence'); ?></li>
<li class="wf-option-subtitle"><?php esc_html_e('To continue using Defiant products and services including the Wordfence plugin, all customers must review and agree to the updated terms and privacy policies. These changes reflect our commitment to follow data protection best practices and regulations. The Wordfence interface will remain disabled until these terms are agreed to.', 'wordfence'); ?></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div> <!-- end GDPR -->
<?php if (isset($support['all'])): ?>
<div class="wf-row">
<div class="wf-col-xs-12 wf-col-sm-9 wf-col-sm-half-padding-right wf-add-top">
<h3 class="wf-no-top"><?php esc_html_e('All Documentation', 'wordfence'); ?></h3>
</div>
</div>
<div class="wf-row">
<div class="wf-col-xs-12 wf-col-sm-3 wf-col-sm-push-9 wf-col-sm-half-padding-left">
<div class="wf-block wf-active">
<div class="wf-block-content">
<div class="wf-support-top-block">
<h4><?php esc_html_e('Top Topics and Questions', 'wordfence'); ?></h4>
<ol>
<?php
if (isset($support['top'])):
foreach ($support['top'] as $entry):
?>
<li><a href="<?php echo esc_url($entry['permalink']); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html($entry['title']); ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a></li>
<?php
endforeach;
endif;
?>
</ol>
</div>
</div>
</div>
</div>
<div class="wf-col-xs-12 wf-col-sm-9 wf-col-sm-pull-3 wf-col-sm-half-padding-right">
<?php
if (isset($support['all'])):
foreach ($support['all'] as $entry):
?>
<div class="wf-block wf-active wf-add-bottom">
<div class="wf-block-content">
<div class="wf-support-block">
<h4><a href="<?php echo esc_url($entry['permalink']); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html($entry['title']); ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a></h4>
<p><?php echo esc_html($entry['excerpt']); ?></p>
<?php if (isset($entry['children'])): ?>
<ul>
<?php foreach ($entry['children'] as $child): ?>
<li><a href="<?php echo esc_url($child['permalink']); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html($child['title']); ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>
</div>
</div>
<?php
endforeach;
endif;
?>
</div>
</div>
<?php else: ?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-block wf-active">
<div class="wf-block-content">
<div class="wf-support-missing-block">
<h4><?php esc_html_e('Documentation', 'wordfence'); ?></h4>
<p><?php echo wp_kses(__('Documentation about Wordfence may be found on our website by clicking the button below or by clicking the <i class="wf-fa wf-fa-question-circle-o" aria-hidden="true"></i> links on any of the plugin\'s pages.', 'wordfence'), array('i'=>array('class'=>array(), 'aria-hidden'=>array()))); ?></p>
<p class="wf-no-bottom"><a href="<?php echo wfSupportController::esc_supportURL(wfSupportController::ITEM_INDEX); ?>" target="_blank" rel="noopener noreferrer" class="wf-btn wf-btn-default wf-btn-callout-subtle"><?php esc_html_e('View Documentation', 'wordfence'); ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a></p>
</div>
</div>
</div>
</div>
</div>
<?php endif; ?>
</div> <!-- end container -->
</div>
<?php if (wfOnboardingController::shouldShowAttempt3()): ?>
<?php wfConfig::set('onboardingAttempt3Initial', true); ?>
<script type="text/x-jquery-template" id="wfTmpl_onboardingFinal">
<?php echo wfView::create('onboarding/modal-final-attempt')->render(); ?>
</script>
<script type="application/javascript">
(function($) {
$(function() {
var prompt = $('#wfTmpl_onboardingFinal').tmpl();
var promptHTML = $("<div />").append(prompt).html();
WFAD.colorboxHTML('800px', promptHTML, {overlayClose: false, closeButton: false, className: 'wf-modal', onComplete: function() {
setTimeout(function() {
$('#wf-onboarding-subscribe-controls > p').show();
$.wfcolorbox.resize();
}, 30000);
$('#wf-onboarding-subscribe .wf-switch > li').each(function(index, element) {
$(element).on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var control = $(this).closest('.wf-switch');
control.find('li').removeClass('wf-active');
$(this).addClass('wf-active');
$('#wf-onboarding-continue').toggleClass('wf-disabled', wordfenceExt.parseEmails($('#wf-onboarding-alerts').val()).length == 0 || !($('#wf-onboarding-agree').is(':checked')) || $('#wf-onboarding-subscribe .wf-switch > li.wf-active').length == 0);
});
});
$('#wf-onboarding-agree').on('change', function() {
$('#wf-onboarding-continue').toggleClass('wf-disabled', wordfenceExt.parseEmails($('#wf-onboarding-alerts').val()).length == 0 || !($('#wf-onboarding-agree').is(':checked')) || $('#wf-onboarding-subscribe .wf-switch > li.wf-active').length == 0);
});
$('#wf-onboarding-alerts').on('change paste keyup', function() {
setTimeout(function() {
$('#wf-onboarding-continue').toggleClass('wf-disabled', wordfenceExt.parseEmails($('#wf-onboarding-alerts').val()).length == 0 || !($('#wf-onboarding-agree').is(':checked')) || $('#wf-onboarding-subscribe .wf-switch > li.wf-active').length == 0);
}, 100);
}).trigger('change');
$('#wf-onboarding-continue').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var touppAgreed = !!$('#wf-onboarding-agree').is(':checked');
if (!touppAgreed) {
return;
}
var emails = wordfenceExt.parseEmails($('#wf-onboarding-alerts').val());
if (emails.length > 0) {
var subscribe = !!parseInt($('#wf-onboarding-subscribe .wf-switch > li.wf-active').data('optionValue'));
wordfenceExt.onboardingProcessEmails(emails, subscribe, touppAgreed);
<?php if (wfConfig::get('isPaid')): ?>
wordfenceExt.setOption('onboardingAttempt3', '<?php echo esc_attr(wfOnboardingController::ONBOARDING_LICENSE); ?>');
$('#wf-onboarding-banner').slideUp();
WFAD.colorboxClose();
if (WFAD.tour1) { setTimeout(function() { WFAD.tour1(); }, 500); }
<?php else: ?>
wordfenceExt.setOption('onboardingAttempt3', '<?php echo esc_attr(wfOnboardingController::ONBOARDING_EMAILS); ?>');
$('#wf-onboarding-final-attempt-1, .wf-modal-footer').fadeOut(400, function() {
$('#wf-onboarding-final-attempt-2').fadeIn();
$.wfcolorbox.resize();
});
<?php endif; ?>
}
});
$('#wf-onboarding-license input').on('change paste keyup', function() {
setTimeout(function() {
$('#wf-onboarding-license-install').toggleClass('wf-disabled', $('#wf-onboarding-license input').val().length == 0);
}, 100);
}).trigger('change');
$('#wf-onboarding-license-install').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
$('#wf-onboarding-license-status').fadeOut();
var license = $('#wf-onboarding-license input').val();
wordfenceExt.onboardingInstallLicense(license,
function(res) { //Success
if (res.isPaid) {
wordfenceExt.setOption('onboardingAttempt3', '<?php echo esc_attr(wfOnboardingController::ONBOARDING_LICENSE); ?>');
//$('#wf-onboarding-license-status').addClass('wf-green-dark').removeClass('wf-yellow-dark wf-red-dark').text('You have successfully installed a premium license.').fadeIn();
//$('#wf-onboarding-license-install').text('Installed').addClass('wf-disabled');
//$('#wf-onboarding-license input').attr('disabled', true);
$('#wf-onboarding-banner').slideUp();
$('#wf-onboarding-final-attempt .wf-modal-header-action-close').off('click');
/*$('#wf-onboarding-premium-cta, #wf-onboarding-license-footer, #wf-onboarding-or').fadeOut(400, function() {
$('#wf-onboarding-license-finished').fadeIn();
$.wfcolorbox.resize();
});*/
var html = '<div class="wf-modal wf-modal-success"><div class="wf-model-success-wrapper"><div class="wf-modal-header"><div class="wf-modal-header-content"><div class="wf-modal-title"><?php esc_html_e('Premium License Installed', 'wordfence'); ?></div></div></div><div class="wf-modal-content"><?php esc_html_e('Congratulations! Wordfence Premium is now active on your website. Please note that some Premium features are not enabled by default.', 'wordfence'); ?></div></div><div class="wf-modal-footer"><ul class="wf-onboarding-flex-horizontal wf-onboarding-flex-align-right wf-onboarding-full-width"><li><a href="<?php echo esc_url(network_admin_url('admin.php?page=Wordfence')); ?>" class="wf-onboarding-btn wf-onboarding-btn-primary"><?php esc_html_e('Continue', 'wordfence'); ?></a></li></ul></div></div>';
$.wfcolorbox({
width: (wordfenceExt.isSmallScreen ? '300px' : '500px'),
html: html,
overlayClose: true,
closeButton: false,
className: 'wf-modal'
});
<?php
//Congratulations! Wordfence Premium is now active on your website. Please note that some Premium features are not enabled by default. Read this brief article to learn more about <a href="#todo" target="_blank" rel="noopener noreferrer">getting the most out of Wordfence Premium</a>.
?>
}
else { //Unlikely to happen but possible
$('#wf-onboarding-license-status').addClass('wf-yellow-dark').removeClass('wf-green-dark wf-red-dark').text('You have successfully installed a free license.').fadeIn();
$.wfcolorbox.resize();
}
},
function(error) { //Error
$('#wf-onboarding-license-status').addClass('wf-red-dark').removeClass('wf-green-dark wf-yellow-dark').text(error || <?php echo json_encode(__('An unknown error occurred.', 'wordfence')) ?>).fadeIn();
$.wfcolorbox.resize();
});
});
$('#wf-onboarding-no-thanks, #wf-onboarding-final-attempt .wf-modal-header-action-close').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
if ($('#wf-onboarding-final-attempt-2').is(':visible')) {
wordfenceExt.setOption('onboardingAttempt3', '<?php echo esc_attr(wfOnboardingController::ONBOARDING_LICENSE); ?>');
$('#wf-onboarding-banner').slideUp();
}
WFAD.colorboxClose();
if (WFAD.tour1) { setTimeout(function() { WFAD.tour1(); }, 500); }
});
}});
});
})(jQuery);
</script>
<?php endif; ?>

View File

@@ -0,0 +1,45 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
/**
* @var string $subpage
*/
?>
<?php
if (!wfOnboardingController::shouldShowAttempt3() && wfConfig::get('touppPromptNeeded')) {
echo wfView::create('gdpr/disabled-overlay')->render();
echo wfView::create('gdpr/banner')->render();
}
?>
<div class="wrap wordfence">
<div class="wf-container-fluid">
<?php
$tabsArray = array();
if (wfCredentialsController::allowLegacy2FA()) {
$tabsArray[] = array('twofactor', __('Two-Factor Authentication', 'wordfence'));
}
$tabsArray[] = array('livetraffic', __('Live Traffic', 'wordfence'));
$tabsArray[] = array('whois', __('Whois Lookup', 'wordfence'));
$tabsArray[] = array('importexport', __('Import/Export Options', 'wordfence'));
$tabsArray[] = array('diagnostics', __('Diagnostics', 'wordfence'));
$tabs = array();
foreach ($tabsArray as $tab) {
list($tabID, $tabLabel) = $tab;
$tabs[] = new wfTab($tabID,
network_admin_url('admin.php?page=WordfenceTools&subpage=' . rawurlencode($tabID)),
$tabLabel, $tabLabel, $subpage === $tabID);
}
echo wfView::create('common/page-fixed-tabbar', array(
'tabs' => $tabs,
))->render();
?>
<div class="wf-row">
<div class="<?php echo wfStyle::contentClasses(); ?>">
<div class="wf-tab-content wf-active">
<?php echo $content ?>
</div>
</div> <!-- end content block -->
</div> <!-- end row -->
</div> <!-- end container -->
</div>

View File

@@ -0,0 +1,920 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
/** @var boolean $inEmail */
$diagnostic = new wfDiagnostic;
$plugins = get_plugins();
$activePlugins = array_flip(get_option('active_plugins'));
$activeNetworkPlugins = is_multisite() ? array_flip(wp_get_active_network_plugins()) : array();
$muPlugins = get_mu_plugins();
$themes = wp_get_themes();
$currentTheme = wp_get_theme();
$cols = 3;
$w = new wfConfig();
if (!isset($sendingDiagnosticEmail)) {
$sendingDiagnosticEmail = false;
}
?>
<?php if (!$sendingDiagnosticEmail): ?>
<script type="application/javascript">
(function($) {
$(function() {
document.title = "<?php esc_attr_e('Diagnostics', 'wordfence'); ?>" + " \u2039 " + WFAD.basePageName;
});
})(jQuery);
</script>
<?php endif; ?>
<div id="wf-diagnostics">
<?php if (!$sendingDiagnosticEmail): ?>
<div class="wf-diagnostics-wrapper">
<div class="wf-flex-row">
<div class="wf-flex-row-1">
<?php echo wp_kses(sprintf(__('This page shows information that can be used for troubleshooting conflicts, configuration issues, or compatibility with other plugins, themes, or a host\'s environment. Failing tests are not always a sign of something that you need to fix, but can help the Wordfence team when troubleshooting a problem. (<a href="%s" target="_blank" rel="noopener noreferrer">Learn More <span class="screen-reader-text">opens in new tab</span></a>)', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_DIAGNOSTICS)), array('a' => array('href' => array(), 'target' => array(), 'rel' => array()), 'span' => array('class' => array()))) ?>
</div>
<div class="wf-flex-row-0 wf-padding-add-left">
<div id="sendByEmailThanks" class="hidden">
<h3><?php esc_html_e('Thanks for sending your diagnostic page over email', 'wordfence'); ?></h3>
</div>
<div id="sendByEmailDiv" class="wf-add-bottom">
<span class="wf-nowrap">
<input class="wf-btn wf-btn-primary wf-btn-sm" type="submit" id="exportDiagnostics" value="Export"/>
<input class="wf-btn wf-btn-primary wf-btn-sm" type="submit" id="sendByEmail" value="Send Report by Email"/>
<input class="wf-btn wf-btn-default wf-btn-sm" type="button" id="expandAllDiagnostics" value="Expand All Diagnostics"/>
</span>
</div>
</div>
</div>
<div id="sendByEmailForm" class="wf-block wf-active hidden">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('Send Report by Email', 'wordfence') ?></strong>
</div>
</div>
</div>
<div class="wf-block-content wf-clearfix">
<ul class="wf-block-list">
<li>
<div><?php esc_html_e('Email address:', 'wordfence'); ?></div>
<div style="width: 40%">
<p><input class="wf-input-text" type="email" id="_email" value="wftest@wordfence.com"/>
</p>
</div>
</li>
<li>
<div><?php esc_html_e('Ticket Number/Forum Username:', 'wordfence'); ?></div>
<div style="width: 40%">
<p><input class="wf-input-text" type="text" id="_ticketnumber" required/></p>
</div>
</li>
<li>
<p>
<input class="wf-btn wf-btn-primary" type="button" id="doSendEmail" value="Send"/>
</p>
</li>
</ul>
</div>
</div>
</div>
<?php endif; ?>
<div class="wf-diagnostics-wrapper">
<?php foreach ($diagnostic->getResults() as $title => $tests):
$key = sanitize_key('wf-diagnostics-' . $title);
$hasFailingTest = false;
foreach ($tests['results'] as $result) {
$infoOnly = isset($result['infoOnly']) && $result['infoOnly'];
if (!$result['test'] && !$infoOnly) {
$hasFailingTest = true;
break;
}
}
if ($inEmail): ?>
<table>
<thead>
<tr>
<th colspan="2"><?php echo esc_html($title) ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($tests['results'] as $result): ?>
<?php
$infoOnly = isset($result['infoOnly']) && $result['infoOnly'];
?>
<tr>
<td style="width: 75%; min-width: 300px"><?php echo (is_array($result['label']) && isset($result['label']['raw']) && $result['label']['raw'] ? $result['label']['value'] : wp_kses($result['label'], array(
'code' => array(),
'strong' => array(),
'em' => array(),
'a' => array('href' => true),
'span' => array('class' => true)
))) ?></td>
<td>
<?php if ($infoOnly): ?>
<div class="wf-result-info"><?php echo (is_array($result['message']) && isset($result['message']['escaped']) ? $result['message']['escaped'] : nl2br(esc_html($result['message']))); ?></div>
<?php elseif ($result['test']): ?>
<div class="wf-result-success"><?php echo (is_array($result['message']) && isset($result['message']['escaped']) ? $result['message']['escaped'] : nl2br(esc_html($result['message']))); ?></div>
<?php else: ?>
<div class="wf-result-error"><?php echo (is_array($result['message']) && isset($result['message']['escaped']) ? $result['message']['escaped'] : nl2br(esc_html($result['message']))); ?></div>
<?php endif ?>
<?php if (isset($result['detail']) && !empty($result['detail'])): ?>
<p><strong><?php esc_html_e('Additional Detail', 'wordfence'); ?></strong><br><?php echo (is_array($result['detail']) && isset($result['detail']['escaped']) ? $result['detail']['escaped'] : nl2br(esc_html($result['detail']))); ?></p>
<?php endif; ?>
</td>
</tr>
<?php endforeach ?>
</tbody>
</table>
<?php else: ?>
<div class="wf-block<?php echo (wfPersistenceController::shared()->isActive($key) ? ' wf-active' : '') .
($hasFailingTest ? ' wf-diagnostic-fail' : '') ?>" data-persistence-key="<?php echo esc_attr($key) ?>">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php echo esc_html($title) ?></strong>
<span class="wf-text-small"><?php echo esc_html($tests['description']) ?></span>
</div>
<div class="wf-block-header-action">
<div class="wf-block-header-action-disclosure" role="checkbox" aria-checked="<?php echo (wfPersistenceController::shared()->isActive($key) ? 'true' : 'false'); ?>" tabindex="0"></div>
</div>
</div>
</div>
<div class="wf-block-content wf-clearfix">
<ul class="wf-block-list">
<?php foreach ($tests['results'] as $key => $result): ?>
<?php
$infoOnly = isset($result['infoOnly']) && $result['infoOnly'];
?>
<li>
<div style="width: 75%; min-width: 300px;"><?php echo (is_array($result['label']) && isset($result['label']['raw']) && $result['label']['raw'] ? $result['label']['value'] : wp_kses($result['label'], array(
'code' => array(),
'strong' => array(),
'em' => array(),
'a' => array('href' => true),
))) ?></div>
<div class="wf-right">
<?php if ($infoOnly): ?>
<div class="wf-result-info"><?php echo (is_array($result['message']) && isset($result['message']['escaped']) ? $result['message']['escaped'] : nl2br(esc_html($result['message']))); ?></div>
<?php elseif ($result['test']): ?>
<div class="wf-result-success"><?php echo (is_array($result['message']) && isset($result['message']['escaped']) ? $result['message']['escaped'] : nl2br(esc_html($result['message']))); ?></div>
<?php else: ?>
<div class="wf-result-error"><?php echo (is_array($result['message']) && isset($result['message']['escaped']) ? $result['message']['escaped'] : nl2br(esc_html($result['message']))); ?></div>
<?php endif ?>
<?php if (isset($result['detail']) && !empty($result['detail'])): ?>
<p><a href="#" onclick="jQuery('#wf-diagnostics-detail-<?php echo esc_attr($key); ?>').show(); jQuery(this).hide(); return false;" role="button"><?php esc_html_e('View Additional Detail', 'wordfence'); ?></a></p>
<pre class="wf-pre wf-split-word" id="wf-diagnostics-detail-<?php echo esc_attr($key); ?>" style="max-width: 600px; display: none;"><?php echo (is_array($result['detail']) && isset($result['detail']['escaped']) ? $result['detail']['escaped'] : nl2br(esc_html($result['detail']))); ?></pre>
<?php endif; ?>
</div>
</li>
<?php endforeach ?>
</ul>
</div>
</div>
<?php endif ?>
<?php endforeach ?>
<?php
$howGet = wfConfig::get('howGetIPs', false);
list($currentIP, $currentServerVarForIP) = wfUtils::getIPAndServerVariable();
$howGetHasErrors = $howGet && (! $currentServerVarForIP || $howGet !== $currentServerVarForIP);
?>
<div class="wf-block<?php echo ($howGetHasErrors ? ' wf-diagnostic-fail' : '') . (wfPersistenceController::shared()->isActive('wf-diagnostics-client-ip') ? ' wf-active' : '') ?>" data-persistence-key="<?php echo esc_attr('wf-diagnostics-client-ip') ?>">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('IP Detection', 'wordfence') ?></strong>
<span class="wf-text-small"><?php esc_html_e('Methods of detecting a visitor\'s IP address.', 'wordfence') ?></span>
</div>
<div class="wf-block-header-action">
<div class="wf-block-header-action-disclosure" role="checkbox" aria-checked="<?php echo (wfPersistenceController::shared()->isActive('wf-diagnostics-client-ip') ? 'true' : 'false'); ?>" tabindex="0"></div>
</div>
</div>
</div>
<div class="wf-block-content wf-clearfix wf-padding-no-left wf-padding-no-right">
<table class="wf-striped-table"<?php echo !empty($inEmail) ? ' border=1' : '' ?>>
<tbody class="thead">
<tr>
<th><?php esc_html_e('IPs', 'wordfence'); ?></th>
<th><?php esc_html_e('Value', 'wordfence'); ?></th>
<th><?php esc_html_e('Used', 'wordfence'); ?></th>
</tr>
</tbody>
<tbody>
<?php
$serverVariables = array(
'REMOTE_ADDR' => 'REMOTE_ADDR',
'HTTP_CF_CONNECTING_IP' => 'CF-Connecting-IP',
'HTTP_X_REAL_IP' => 'X-Real-IP',
'HTTP_X_FORWARDED_FOR' => 'X-Forwarded-For',
);
foreach (wfUtils::getAllServerVariableIPs() as $variable => $ip): ?>
<tr>
<td><?php echo isset($serverVariables[$variable]) ? $serverVariables[$variable] : $variable ?></td>
<td><?php
if (! $ip) {
_e('(not set)', 'wordfence');
} elseif (is_array($ip)) {
$output = array_map('esc_html', $ip);
echo str_replace($currentIP, "<strong>{$currentIP}</strong>", implode(', ', $output));
} else {
echo esc_html($ip);
}
?></td>
<?php if ($currentServerVarForIP && $currentServerVarForIP === $variable): ?>
<td class="wf-result-success"><?php esc_html_e('In use', 'wordfence'); ?></td>
<?php elseif ($howGet === $variable): ?>
<td class="wf-result-error"><?php esc_html_e('Configured but not valid', 'wordfence'); ?></td>
<?php else: ?>
<td></td>
<?php endif ?>
</tr>
<?php endforeach ?>
<tr>
<td><?php esc_html_e('Trusted Proxies', 'wordfence'); ?></td>
<td><?php $proxies = wfConfig::get('howGetIPs_trusted_proxies', ''); echo esc_html(implode(', ', explode("\n", empty($proxies) ? __('(not set)', 'wordfence') : $proxies))); ?></td>
<td></td>
</tr>
<tr>
<td><?php esc_html_e('Trusted Proxy Preset', 'wordfence'); ?></td>
<td><?php $preset = wfConfig::get('howGetIPs_trusted_proxy_preset'); $presets = wfConfig::getJSON('ipResolutionList', array()); echo esc_html((is_array($presets) && isset($presets[$preset])) ? $presets[$preset]['name'] : __('(not set)', 'wordfence')); ?></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="wf-block<?php echo(wfPersistenceController::shared()->isActive('wf-diagnostics-wordpress-constants') ? ' wf-active' : '') ?>" data-persistence-key="<?php echo esc_attr('wf-diagnostics-wordpress-constants') ?>">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('WordPress Settings', 'wordfence') ?></strong>
<span class="wf-text-small"><?php esc_html_e('WordPress version and internal settings/constants.', 'wordfence') ?></span>
</div>
<div class="wf-block-header-action">
<div class="wf-block-header-action-disclosure" role="checkbox" aria-checked="<?php echo (wfPersistenceController::shared()->isActive('wf-diagnostics-wordpress-constants') ? 'true' : 'false'); ?>" tabindex="0"></div>
</div>
</div>
</div>
<div class="wf-block-content wf-clearfix wf-padding-no-left wf-padding-no-right">
<table class="wf-striped-table"<?php echo !empty($inEmail) ? ' border=1' : '' ?>>
<tbody>
<?php
foreach (wfDiagnostic::getWordpressValues() as $settingName => $settingData):
$escapedName = esc_html($settingName);
$escapedDescription = '';
$escapedValue = __('(not set)', 'wordfence');
if (is_array($settingData)) {
$escapedDescription = esc_html($settingData['description']);
if (isset($settingData['value'])) {
$escapedValue = esc_html($settingData['value']);
}
} else {
$escapedDescription = esc_html($settingData);
if (defined($settingName)) {
$escapedValue = esc_html(constant($settingName));
}
}
?>
<tr>
<td><strong><?php echo $escapedName ?></strong></td>
<td><?php echo $escapedDescription ?></td>
<td><?php echo $escapedValue ?></td>
</tr>
<?php endforeach ?>
</tbody>
</table>
</div>
</div>
<div class="wf-block<?php echo(wfPersistenceController::shared()->isActive('wf-diagnostics-wordpress-plugins') ? ' wf-active' : '') ?>" data-persistence-key="<?php echo esc_attr('wf-diagnostics-wordpress-plugins') ?>">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('WordPress Plugins', 'wordfence') ?></strong>
<span class="wf-text-small"><?php esc_html_e('Status of installed plugins.', 'wordfence') ?></span>
</div>
<div class="wf-block-header-action">
<div class="wf-block-header-action-disclosure" role="checkbox" aria-checked="<?php echo (wfPersistenceController::shared()->isActive('wf-diagnostics-wordpress-plugins') ? 'true' : 'false'); ?>" tabindex="0"></div>
</div>
</div>
</div>
<div class="wf-block-content wf-clearfix wf-padding-no-left wf-padding-no-right">
<table class="wf-striped-table"<?php echo !empty($inEmail) ? ' border=1' : '' ?>>
<tbody>
<?php foreach ($plugins as $plugin => $pluginData): ?>
<?php
$slug = $plugin;
if (preg_match('/^([^\/]+)\//', $plugin, $matches)) {
$slug = $matches[1];
}
else if (preg_match('/^([^\/.]+)\.php$/', $plugin, $matches)) {
$slug = $matches[1];
}
?>
<tr>
<td>
<strong><?php echo esc_html($pluginData['Name']); ?> (<?php echo esc_html($slug); ?>)</strong>
<?php if (!empty($pluginData['Version'])): ?>
- <?php echo esc_html(sprintf(__('Version %s', 'wordfence'), $pluginData['Version'])); ?>
<?php endif ?>
</td>
<?php if (array_key_exists(trailingslashit(WP_PLUGIN_DIR) . $plugin, $activeNetworkPlugins)): ?>
<td class="wf-result-success"><?php esc_html_e('Network Activated', 'wordfence'); ?></td>
<?php elseif (array_key_exists($plugin, $activePlugins)): ?>
<td class="wf-result-success"><?php esc_html_e('Active', 'wordfence'); ?></td>
<?php else: ?>
<td class="wf-result-inactive"><?php esc_html_e('Inactive', 'wordfence'); ?></td>
<?php endif ?>
</tr>
<?php endforeach ?>
</tbody>
</table>
</div>
</div>
<div class="wf-block<?php echo(wfPersistenceController::shared()->isActive('wf-diagnostics-mu-wordpress-plugins') ? ' wf-active' : '') ?>" data-persistence-key="<?php echo esc_attr('wf-diagnostics-mu-wordpress-plugins') ?>">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('Must-Use WordPress Plugins', 'wordfence') ?></strong>
<span class="wf-text-small"><?php esc_html_e('WordPress "mu-plugins" that are always active, including those provided by hosts.', 'wordfence') ?></span>
</div>
<div class="wf-block-header-action">
<div class="wf-block-header-action-disclosure" role="checkbox" aria-checked="<?php echo (wfPersistenceController::shared()->isActive('wf-diagnostics-mu-wordpress-plugins') ? 'true' : 'false'); ?>" tabindex="0"></div>
</div>
</div>
</div>
<div class="wf-block-content wf-clearfix wf-padding-no-left wf-padding-no-right">
<table class="wf-striped-table"<?php echo !empty($inEmail) ? ' border=1' : '' ?>>
<?php if (!empty($muPlugins)): ?>
<tbody>
<?php foreach ($muPlugins as $plugin => $pluginData): ?>
<?php
$slug = $plugin;
if (preg_match('/^([^\/]+)\//', $plugin, $matches)) {
$slug = $matches[1];
}
else if (preg_match('/^([^\/.]+)\.php$/', $plugin, $matches)) {
$slug = $matches[1];
}
?>
<tr>
<td>
<strong><?php echo esc_html($pluginData['Name']) ?> (<?php echo esc_html($slug); ?>)</strong>
<?php if (!empty($pluginData['Version'])): ?>
- <?php echo esc_html(sprintf(/* translators: Plugin version. */ __('Version %s', 'wordfence'), $pluginData['Version'])); ?>
<?php endif ?>
</td>
<td class="wf-result-success"><?php esc_html_e('Active', 'wordfence'); ?></td>
</tr>
<?php endforeach ?>
</tbody>
<?php else: ?>
<tbody>
<tr>
<td><?php esc_html_e('No MU-Plugins', 'wordfence'); ?></td>
</tr>
</tbody>
<?php endif ?>
</table>
</div>
</div>
<div class="wf-block<?php echo(wfPersistenceController::shared()->isActive('wf-diagnostics-dropin-wordpress-plugins') ? ' wf-active' : '') ?>" data-persistence-key="<?php echo esc_attr('wf-diagnostics-dropin-wordpress-plugins') ?>">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('Drop-In WordPress Plugins', 'wordfence') ?></strong>
<span class="wf-text-small"><?php esc_html_e('WordPress "drop-in" plugins that are active.', 'wordfence') ?></span>
</div>
<div class="wf-block-header-action">
<div class="wf-block-header-action-disclosure" role="checkbox" aria-checked="<?php echo (wfPersistenceController::shared()->isActive('wf-diagnostics-dropin-wordpress-plugins') ? 'true' : 'false'); ?>" tabindex="0"></div>
</div>
</div>
</div>
<div class="wf-block-content wf-clearfix wf-padding-no-left wf-padding-no-right">
<table class="wf-striped-table"<?php echo !empty($inEmail) ? ' border=1' : '' ?>>
<tbody>
<?php
//Taken from plugin.php and modified to always show multisite drop-ins
$dropins = array(
'advanced-cache.php' => array( __( 'Advanced caching plugin', 'wordfence' ), 'WP_CACHE' ), // WP_CACHE
'db.php' => array( __( 'Custom database class', 'wordfence' ), true ), // auto on load
'db-error.php' => array( __( 'Custom database error message', 'wordfence' ), true ), // auto on error
'install.php' => array( __( 'Custom installation script', 'wordfence' ), true ), // auto on installation
'maintenance.php' => array( __( 'Custom maintenance message', 'wordfence' ), true ), // auto on maintenance
'object-cache.php' => array( __( 'External object cache', 'wordfence' ), true ), // auto on load
'php-error.php' => array( __( 'Custom PHP error message', 'wordfence' ), true ), // auto on error
'fatal-error-handler.php'=> array( __( 'Custom PHP fatal error handler', 'wordfence' ), true ), // auto on error
);
$dropins['sunrise.php' ] = array( __( 'Executed before Multisite is loaded', 'wordfence' ), is_multisite() && 'SUNRISE' ); // SUNRISE
$dropins['blog-deleted.php' ] = array( __( 'Custom site deleted message', 'wordfence' ), is_multisite() ); // auto on deleted blog
$dropins['blog-inactive.php' ] = array( __( 'Custom site inactive message', 'wordfence' ), is_multisite() ); // auto on inactive blog
$dropins['blog-suspended.php'] = array( __( 'Custom site suspended message', 'wordfence' ), is_multisite() ); // auto on archived or spammed blog
?>
<?php foreach ($dropins as $file => $data): ?>
<?php
$active = file_exists(WP_CONTENT_DIR . DIRECTORY_SEPARATOR . $file) && is_readable(WP_CONTENT_DIR . DIRECTORY_SEPARATOR . $file) && $data[1];
?>
<tr>
<td>
<strong><?php echo esc_html($data[0]) ?> (<?php echo esc_html($file); ?>)</strong>
</td>
<?php if ($active): ?>
<td class="wf-result-success"><?php esc_html_e('Active', 'wordfence'); ?></td>
<?php else: ?>
<td class="wf-result-inactive"><?php esc_html_e('Inactive', 'wordfence'); ?></td>
<?php endif; ?>
</tr>
<?php endforeach ?>
</tbody>
</table>
</div>
</div>
<div class="wf-block<?php echo(wfPersistenceController::shared()->isActive('wf-diagnostics-wordpress-themes') ? ' wf-active' : '') ?>" data-persistence-key="<?php echo esc_attr('wf-diagnostics-wordpress-themes') ?>">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('Themes', 'wordfence') ?></strong>
<span class="wf-text-small"><?php esc_html_e('Status of installed themes.', 'wordfence') ?></span>
</div>
<div class="wf-block-header-action">
<div class="wf-block-header-action-disclosure" role="checkbox" aria-checked="<?php echo (wfPersistenceController::shared()->isActive('wf-diagnostics-wordpress-themes') ? 'true' : 'false'); ?>" tabindex="0"></div>
</div>
</div>
</div>
<div class="wf-block-content wf-clearfix wf-padding-no-left wf-padding-no-right">
<table class="wf-striped-table"<?php echo !empty($inEmail) ? ' border=1' : '' ?>>
<?php if (!empty($themes)): ?>
<tbody>
<?php foreach ($themes as $theme => $themeData): ?>
<?php
$slug = $theme;
if (preg_match('/^([^\/]+)\//', $theme, $matches)) {
$slug = $matches[1];
}
else if (preg_match('/^([^\/.]+)\.php$/', $theme, $matches)) {
$slug = $matches[1];
}
?>
<tr>
<td>
<strong><?php echo esc_html($themeData['Name']) ?> (<?php echo esc_html($slug); ?>)</strong>
<?php if (!empty($themeData['Version'])): ?>
- <?php echo esc_html(sprintf(/* translators: Theme version. */ __('Version %s', 'wordfence'), $themeData['Version'])); ?>
<?php endif ?>
<?php if ($currentTheme instanceof WP_Theme && $theme === $currentTheme->get_stylesheet()): ?>
<td class="wf-result-success"><?php esc_html_e('Active', 'wordfence'); ?></td>
<?php else: ?>
<td class="wf-result-inactive"><?php esc_html_e('Inactive', 'wordfence'); ?></td>
<?php endif ?>
</tr>
<?php endforeach ?>
</tbody>
<?php else: ?>
<tbody>
<tr>
<td><?php esc_html_e('No Themes', 'wordfence'); ?></td>
</tr>
</tbody>
<?php endif ?>
</table>
</div>
</div>
<div class="wf-block<?php echo(wfPersistenceController::shared()->isActive('wf-diagnostics-wordpress-cron-jobs') ? ' wf-active' : '') ?>" data-persistence-key="<?php echo esc_attr('wf-diagnostics-wordpress-cron-jobs') ?>">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('Cron Jobs', 'wordfence') ?></strong>
<span class="wf-text-small"><?php esc_html_e('List of WordPress cron jobs scheduled by WordPress, plugins, or themes.', 'wordfence') ?></span>
</div>
<div class="wf-block-header-action">
<div class="wf-block-header-action-disclosure" role="checkbox" aria-checked="<?php echo (wfPersistenceController::shared()->isActive('wf-diagnostics-wordpress-cron-jobs') ? 'true' : 'false'); ?>" tabindex="0"></div>
</div>
</div>
</div>
<div class="wf-block-content wf-clearfix wf-padding-no-left wf-padding-no-right">
<table class="wf-striped-table"<?php echo !empty($inEmail) ? ' border=1' : '' ?>>
<tbody>
<?php
$cron = _get_cron_array();
foreach ($cron as $timestamp => $values) {
if (is_array($values)) {
foreach ($values as $cron_job => $v) {
if (is_numeric($timestamp)) {
$overdue = ((time() - 1800) > $timestamp);
?>
<tr<?php echo $overdue ? ' class="wf-overdue-cron"' : ''; ?>>
<td><?php echo esc_html(date('r', $timestamp)) . ($overdue ? ' <strong>(' . esc_html__('Overdue', 'wordfence') . ')</strong>' : '') ?></td>
<td><?php echo esc_html($cron_job) ?></td>
</tr>
<?php
}
}
}
}
?>
</tbody>
</table>
</div>
</div>
<?php
global $wpdb;
$wfdb = new wfDB();
//This must be done this way because MySQL with InnoDB tables does a full regeneration of all metadata if we don't. That takes a long time with a large table count.
$tables = $wfdb->querySelect('SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() ORDER BY TABLE_NAME ASC LIMIT 250');
$total = $wfdb->querySingle('SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE()');
foreach ($tables as &$t) {
$t = "'" . esc_sql($t['TABLE_NAME']) . "'";
}
unset($t);
$q = $wfdb->querySelect("SHOW TABLE STATUS WHERE Name IN (" . implode(',', $tables) . ')');
if ($q):
$databaseCols = count($q[0]);
?>
<div class="wf-block<?php echo(wfPersistenceController::shared()->isActive('wf-diagnostics-database-tables') ? ' wf-active' : '') ?>" data-persistence-key="<?php echo esc_attr('wf-diagnostics-database-tables') ?>">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('Database Tables', 'wordfence') ?></strong>
<span class="wf-text-small"><?php esc_html_e('Database table names, sizes, timestamps, and other metadata.', 'wordfence') ?></span>
</div>
<div class="wf-block-header-action">
<div class="wf-block-header-action-disclosure" role="checkbox" aria-checked="<?php echo (wfPersistenceController::shared()->isActive('wf-diagnostics-database-tables') ? 'true' : 'false'); ?>" tabindex="0"></div>
</div>
</div>
</div>
<div class="wf-block-content wf-clearfix wf-padding-no-left wf-padding-no-right">
<ul class="wf-block-list wf-padding-add-left-large wf-padding-add-right-large">
<li>
<div style="width: 75%; min-width: 300px;"><?php esc_html_e('Wordfence Table Check', 'wordfence'); ?></div>
<div class="wf-right">
<?php if ($total > 250): ?>
<div class="wf-result-info"><?php esc_html_e('Unable to verify - table count too high', 'wordfence'); ?></div>
<?php else:
$hasAll = true;
$schemaTables = wfSchema::tableList();
$existingTables = wfUtils::array_column($q, 'Name');
if (WFWAF_IS_WINDOWS) { $existingTables = wfUtils::array_strtolower($existingTables); } //Windows MySQL installations are case-insensitive
$missingTables = array();
foreach ($schemaTables as $t) {
$table = wfDB::networkTable($t);
if (WFWAF_IS_WINDOWS) { $table = strtolower($table); }
if (!in_array($table, $existingTables)) {
$hasAll = false;
$missingTables[] = $t;
}
}
foreach (
array(
\WordfenceLS\Controller_DB::TABLE_2FA_SECRETS,
\WordfenceLS\Controller_DB::TABLE_SETTINGS,
) as $t) {
$table = \WordfenceLS\Controller_DB::network_table($t);
if (!in_array($table, $existingTables)) {
$hasAll = false;
$missingTables[] = $t;
}
}
if ($hasAll): ?>
<div class="wf-result-success"><?php esc_html_e('All Tables Exist', 'wordfence'); ?></div>
<?php else: ?>
<div class="wf-result-error"><?php echo esc_html(sprintf(
/* translators: 1. WordPress table prefix. 2. Wordfence table case. 3. List of database tables. */
__('Tables missing (prefix %1$s, %2$s): %3$s', 'wordfence'), wfDB::networkPrefix(), wfSchema::usingLowercase() ? __('lowercase', 'wordfence') : __('regular case', 'wordfence'), implode(', ', $missingTables))); ?></div>
<?php endif; ?>
<?php endif; ?>
</div>
</li>
<li style="border-bottom: 1px solid #e2e2e2;">
<div style="width: 75%; min-width: 300px;"><?php esc_html_e('Number of Database Tables', 'wordfence'); ?></div>
<div class="wf-right">
<div class="wf-result-info"><?php echo esc_html( $total ); ?></div>
</div>
</li>
</ul>
<div class="wf-add-top-large" style="max-width: 100%; overflow: auto; padding: 1px;">
<table class="wf-striped-table"<?php echo !empty($inEmail) ? ' border=1' : '' ?>>
<tbody class="thead thead-subhead" style="font-size: 85%">
<?php
$val = wfUtils::array_first($q);
$actualKeyOrder = array_keys($val);
$preferredKeyOrder = array('Name', 'Comment', 'Engine', 'Rows', 'Avg_row_length', 'Data_length', 'Index_length', 'Auto_increment', 'Create_time', 'Row_format', 'Collation', 'Version', 'Max_data_length', 'Data_free', 'Update_time', 'Check_time', 'Checksum', 'Create_options');
$leftoverKeys = array();
$displayKeyOrder = array();
foreach ($preferredKeyOrder as $k) {
if (in_array($k, $actualKeyOrder)) {
$displayKeyOrder[] = $k;
}
}
$diff = array_diff($actualKeyOrder, $preferredKeyOrder);
$displayKeyOrder = array_merge($displayKeyOrder, $diff);
?>
<tr>
<?php foreach ($displayKeyOrder as $tkey): ?>
<th><?php echo esc_html($tkey) ?></th>
<?php endforeach; ?>
</tr>
</tbody>
<tbody style="font-size: 85%">
<?php
$count = 0;
foreach ($q as $val) {
?>
<tr>
<?php foreach ($displayKeyOrder as $tkey): ?>
<td><?php if (isset($val[$tkey])) { echo esc_html($val[$tkey]); } ?></td>
<?php endforeach; ?>
</tr>
<?php
$count++;
if ($count >= 250 && $total > $count) {
?>
<tr>
<td colspan="<?php echo $databaseCols; ?>"><?php echo esc_html(sprintf(/* translators: Row/record count. */ __('and %d more', 'wordfence'), $total - $count)); ?></td>
</tr>
<?php
break;
}
}
?>
</tbody>
</table>
</div>
</div>
</div>
<?php endif ?>
<div class="wf-block<?php echo(wfPersistenceController::shared()->isActive('wf-diagnostics-log-files') ? ' wf-active' : '') ?>" data-persistence-key="<?php echo esc_attr('wf-diagnostics-log-files') ?>">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('Log Files', 'wordfence') ?></strong>
<span class="wf-text-small"><?php esc_html_e('PHP error logs generated by your site, if enabled by your host.', 'wordfence') ?></span>
</div>
<div class="wf-block-header-action">
<div class="wf-block-header-action-disclosure" role="checkbox" aria-checked="<?php echo (wfPersistenceController::shared()->isActive('wf-diagnostics-log-files') ? 'true' : 'false'); ?>" tabindex="0"></div>
</div>
</div>
</div>
<div class="wf-block-content wf-clearfix wf-padding-no-left wf-padding-no-right">
<div style="max-width: 100%; overflow: auto; padding: 1px;">
<table class="wf-striped-table"<?php echo !empty($inEmail) ? ' border=1' : '' ?>>
<tbody class="thead thead-subhead" style="font-size: 85%">
<tr>
<th><?php esc_html_e('File', 'wordfence'); ?></th>
<th><?php esc_html_e('Download', 'wordfence'); ?></th>
</tr>
</tbody>
<tbody style="font-size: 85%">
<?php
$errorLogs = wfErrorLogHandler::getErrorLogs();
if (count($errorLogs) < 1): ?>
<tr>
<td colspan="2"><em><?php esc_html_e('No log files found.', 'wordfence'); ?></em></td>
</tr>
<?php else:
foreach ($errorLogs as $log => $readable): ?>
<?php
$metadata = array();
if (is_callable('filesize')) {
$rawSize = @filesize($log);
if ($rawSize !== false) {
$metadata[] = wfUtils::formatBytes(filesize($log));
}
}
if (is_callable('lstat')) {
$rawStat = @lstat($log);
if (is_array($rawStat) && isset($rawStat['mtime'])) {
$ts = $rawStat['mtime'];
$utc = new DateTimeZone('UTC');
$dtStr = gmdate("c", (int) $ts); //Have to do it this way because of PHP 5.2
$dt = new DateTime($dtStr, $utc);
$metadata[] = $dt->format('M j, Y G:i:s') . ' ' . __('UTC', 'wordfence');
}
}
$shortLog = $log;
if (strpos($shortLog, ABSPATH) === 0) {
$shortLog = '~/' . substr($shortLog, strlen(ABSPATH));
}
?>
<tr>
<td style="width: 100%"><?php echo esc_html($shortLog); if (!empty($metadata)) { echo ' (' . esc_html(implode(', ', $metadata)) . ')'; } ?></td>
<td style="white-space: nowrap; text-align: right;"><?php echo($readable ? '<a href="#" data-logfile="' . esc_attr($log) . '" class="downloadLogFile" target="_blank" rel="noopener noreferrer" role="button">' . esc_html__('Download', 'wordfence') . '<span class="screen-reader-text"> (' . esc_html__('opens in new tab', 'wordfence') . ')</span></a>' : '<em>' . esc_html__('Requires downloading from the server directly', 'wordfence') . '</em>'); ?></td>
</tr>
<?php endforeach;
endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<?php
if (!empty($inEmail)) {
echo '<h1>' . esc_html__('Scan Issues', 'wordfence') . "</h1>\n";
$issues = wfIssues::shared()->getIssues(0, 50, 0, 50);
$issueCounts = array_merge(array('new' => 0, 'ignoreP' => 0, 'ignoreC' => 0), wfIssues::shared()->getIssueCounts());
$issueTypes = wfIssues::validIssueTypes();
echo '<h2>' . esc_html(sprintf(/* translators: Number of scan issues. */ __('New Issues (%d total)', 'wordfence'), $issueCounts['new'])) . "</h2>\n";
if (isset($issues['new']) && count($issues['new'])) {
foreach ($issues['new'] as $i) {
if (!in_array($i['type'], $issueTypes)) {
continue;
}
$viewContent = '';
try {
$viewContent = wfView::create('scanner/issue-' . $i['type'], array('textOutput' => $i))->render();
}
catch (wfViewNotFoundException $e) {
//Ignore -- should never happen since we validate the type
}
if (!empty($viewContent)) {
echo nl2br($viewContent) . "<br><br>\n";
}
}
}
else {
echo '<h1>' . esc_html__('No New Issues', 'wordfence') . "</h1>\n";
}
}
?>
<?php if (!empty($inEmail)): ?>
<?php if (wfUtils::funcEnabled('phpinfo')) { phpinfo(); } else { echo '<strong>' . esc_html__('Unable to output phpinfo content because it is disabled', 'wordfence') . "</strong>\n"; } ?>
<?php endif ?>
<?php if (!empty($emailForm)): ?>
<div class="wf-diagnostics-wrapper">
<div id="wf-diagnostics-other-tests" class="wf-block<?php echo(wfPersistenceController::shared()->isActive('wf-diagnostics-other-tests') ? ' wf-active' : '') ?>" data-persistence-key="<?php echo esc_attr('wf-diagnostics-other-tests') ?>">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('Other Tests', 'wordfence') ?></strong>
<span class="wf-text-small"><?php esc_html_e('System configuration, memory test, send test email from this server.', 'wordfence') ?></span>
</div>
<div class="wf-block-header-action">
<div class="wf-block-header-action-disclosure" role="checkbox" aria-checked="<?php echo (wfPersistenceController::shared()->isActive('wf-diagnostics-other-tests') ? 'true' : 'false'); ?>" tabindex="0"></div>
</div>
</div>
</div>
<div class="wf-block-content wf-clearfix">
<ul class="wf-block-list">
<li>
<span>
<a href="<?php echo wfUtils::siteURLRelative(); ?>?_wfsf=sysinfo&nonce=<?php echo wp_create_nonce('wp-ajax'); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Click to view your system\'s configuration in a new window', 'wordfence'); ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a>
<a href="<?php echo wfSupportController::esc_supportURL(wfSupportController::ITEM_DIAGNOSTICS_SYSTEM_CONFIGURATION); ?>" target="_blank" rel="noopener noreferrer" class="wfhelp wf-inline-help"><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a>
</span>
</li>
<li>
<span>
<a href="<?php echo wfUtils::siteURLRelative(); ?>?_wfsf=testmem&nonce=<?php echo wp_create_nonce('wp-ajax'); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Test your WordPress host\'s available memory', 'wordfence'); ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a>
<a href="<?php echo wfSupportController::esc_supportURL(wfSupportController::ITEM_DIAGNOSTICS_TEST_MEMORY); ?>" target="_blank" rel="noopener noreferrer" class="wfhelp wf-inline-help"><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a>
</span>
</li>
<li>
<span>
<?php esc_html_e('Send a test email from this WordPress server to an email address:', 'wordfence'); ?> <a href="<?php echo wfSupportController::esc_supportURL(wfSupportController::ITEM_DIAGNOSTICS_TEST_EMAIL); ?>" target="_blank" rel="noopener noreferrer" class="wfhelp wf-inline-help"><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a>
<input type="text" id="testEmailDest" value="" size="20" maxlength="255" class="wfConfigElem"/>
<input class="wf-btn wf-btn-default wf-btn-sm" type="button" value="<?php esc_attr_e('Send Test Email', 'wordfence'); ?>" onclick="WFAD.sendTestEmail(jQuery('#testEmailDest').val());"/>
</span>
</li>
<li>
<span>
<?php esc_html_e('Send a test activity report email:', 'wordfence'); ?> <a href="<?php echo wfSupportController::esc_supportURL(wfSupportController::ITEM_DIAGNOSTICS_TEST_ACTIVITY_REPORT); ?>" target="_blank" rel="noopener noreferrer" class="wfhelp wf-inline-help"><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a>
<input type="email" id="email_summary_email_address_debug" value="" size="20" maxlength="255" class="wfConfigElem"/>
<input class="wf-btn wf-btn-default wf-btn-sm" type="button" value="<?php esc_attr_e('Send Test Activity Report', 'wordfence'); ?>" onclick="WFAD.sendTestActivityReport(jQuery('#email_summary_email_address_debug').val());"/>
</span>
</li>
<li>
<span>
<?php esc_html_e('Clear all Wordfence Central connection data', 'wordfence'); ?> <a href="<?php echo wfSupportController::esc_supportURL(wfSupportController::ITEM_DIAGNOSTICS_REMOVE_CENTRAL_DATA); ?>" target="_blank" rel="noopener noreferrer" class="wfhelp wf-inline-help"><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a>
<input class="wf-btn wf-btn-default wf-btn-sm" type="button" value="<?php esc_attr_e('Clear Connection Data', 'wordfence'); ?>" onclick="WFAD.ajax('wordfence_wfcentral_disconnect', {}, function() { WFAD.colorboxModal((self.isSmallScreen ? '300px' : '400px'), 'Successfully removed data', 'All associated Wordfence Central data has been removed from the database.'); });"/>
</span>
</li>
</ul>
</div>
</div>
<div class="wf-block<?php echo(wfPersistenceController::shared()->isActive('wf-diagnostics-debugging-options') ? ' wf-active' : '') ?>" data-persistence-key="<?php echo esc_attr('wf-diagnostics-debugging-options') ?>">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('Debugging Options', 'wordfence') ?></strong>
</div>
<div class="wf-block-header-action">
<div class="wf-block-header-action-disclosure" role="checkbox" aria-checked="<?php echo (wfPersistenceController::shared()->isActive('wf-diagnostics-debugging-options') ? 'true' : 'false'); ?>" tabindex="0"></div>
</div>
</div>
</div>
<div class="wf-block-content wf-clearfix">
<form action="#" id="wfDebuggingConfigForm">
<ul class="wf-block-list">
<li>
<?php
echo wfView::create('options/option-toggled', array(
'optionName' => 'debugOn',
'enabledValue' => 1,
'disabledValue' => 0,
'value' => $w->get('debugOn') ? 1 : 0,
'title' => __('Enable debugging mode (increases database load)', 'wordfence'),
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_DIAGNOSTICS_OPTION_DEBUGGING_MODE),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('options/option-toggled', array(
'optionName' => 'startScansRemotely',
'enabledValue' => 1,
'disabledValue' => 0,
'value' => $w->get('startScansRemotely') ? 1 : 0,
'title' => __('Start all scans remotely (Try this if your scans aren\'t starting and your site is publicly accessible)', 'wordfence'),
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_DIAGNOSTICS_OPTION_REMOTE_SCANS),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('options/option-toggled', array(
'optionName' => 'ssl_verify',
'enabledValue' => 1,
'disabledValue' => 0,
'value' => $w->get('ssl_verify') ? 1 : 0,
'title' => __('Enable SSL Verification (Disable this if you are consistently unable to connect to the Wordfence servers.)', 'wordfence'),
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_DIAGNOSTICS_OPTION_SSL_VERIFICATION),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('options/option-toggled', array(
'optionName' => 'avoid_php_input',
'enabledValue' => 1,
'disabledValue' => 0,
'value' => wfWAF::getInstance()->getStorageEngine()->getConfig('avoid_php_input', false) ? 1 : 0,
'title' => __('Disable reading of php://input', 'wordfence'),
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_DIAGNOSTICS_OPTION_DISABLE_PHP_INPUT),
))->render();
?>
</li>
<li>
<?php
echo wfView::create('options/option-toggled', array(
'optionName' => 'wordfenceI18n',
'enabledValue' => 1,
'disabledValue' => 0,
'value' => $w->get('wordfenceI18n') ? 1 : 0,
'title' => 'Enable Wordfence translations',
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_DIAGNOSTICS_OPTION_WORDFENCE_TRANSLATIONS),
))->render();
?>
</li>
<li>
<p>
<a id="wf-restore-defaults" class="wf-btn wf-btn-default wf-btn-callout-subtle" href="#" data-restore-defaults-section="<?php echo esc_attr(wfConfig::OPTIONS_TYPE_DIAGNOSTICS); ?>" role="button"><?php esc_html_e('Restore Defaults', 'wordfence'); ?></a>
<a id="wf-cancel-changes" class="wf-btn wf-btn-default wf-btn-callout-subtle wf-disabled" href="#" role="button"><?php esc_html_e('Cancel Changes', 'wordfence'); ?></a>
<a id="wf-save-changes" class="wf-btn wf-btn-primary wf-btn-callout-subtle wf-disabled" href="#" role="button"><?php esc_html_e('Save Changes', 'wordfence'); ?></a>
</p>
</li>
</ul>
</form>
</div>
</div>
</div>
<?php endif ?>
</div>
<div class="wf-scrollTop">
<a href="javascript:void(0);"><i class="wf-ionicons wf-ion-chevron-up"></i></a>
</div>
<script type="text/x-jquery-template" id="wfTmpl_restoreDefaultsPrompt">
<?php
echo wfView::create('common/modal-prompt', array(
'title' => __('Confirm Restore Defaults', 'wordfence'),
'message' => __('Are you sure you want to restore the default Diagnostics settings? This will undo any custom changes you have made to the options on this page.', 'wordfence'),
'primaryButton' => array('id' => 'wf-restore-defaults-prompt-cancel', 'label' => __('Cancel', 'wordfence'), 'link' => '#'),
'secondaryButtons' => array(array('id' => 'wf-restore-defaults-prompt-confirm', 'labelHTML' => wp_kses(/* translators: word order may be reversed as long as HTML remains around "Defaults" */ __('Restore<span class="wf-hidden-xs"> Defaults</span>', 'wordfence'), array('span'=>array('class'=>array()))), 'link' => '#')),
))->render();
?>
</script>

View File

@@ -0,0 +1,28 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
?>
<script type="application/javascript">
(function($) {
$(function() {
document.title = "<?php esc_attr_e('Import/Export Options', 'wordfence'); ?>" + " \u2039 " + WFAD.basePageName;
});
})(jQuery);
</script>
<div id="wf-tools-importexport">
<div class="wf-section-title">
<h2><?php esc_html_e('Import/Export Options', 'wordfence') ?></h2>
<span><?php echo wp_kses(sprintf(
/* translators: URL to support page. */
__('<a href="%s" target="_blank" rel="noopener noreferrer" class="wf-help-link">Learn more<span class="wf-hidden-xs"> about importing and exporting options</span><span class="screen-reader-text"> (opens in new tab)</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_TOOLS_IMPORT_EXPORT)), array('a'=>array('href'=>array(), 'target'=>array(), 'rel'=>array(), 'class'=>array()), 'span'=>array('class'=>array()))); ?>
<i class="wf-fa wf-fa-external-link" aria-hidden="true"></i></span>
</div>
<p><?php esc_html_e("To clone one site's configuration to another, use the import/export tools below.", 'wordfence') ?></p>
<?php
echo wfView::create('dashboard/options-group-import', array(
'stateKey' => 'global-options-import',
'collapseable' => false,
))->render();
?>
</div>

View File

@@ -0,0 +1,613 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
$w = new wfConfig();
?>
<script type="application/javascript">
(function($) {
$(function() {
document.title = "<?php esc_attr_e('Live Traffic', 'wordfence'); ?>" + " \u2039 " + WFAD.basePageName;
//Hash-based option block linking
if (window.location.hash) {
var hashes = WFAD.parseHashes();
var hash = hashes[hashes.length - 1];
var block = $('.wf-block[data-persistence-key="' + hash + '"]');
if (block.length) {
if (!block.hasClass('wf-active')) {
block.find('.wf-block-content').slideDown({
always: function() {
block.addClass('wf-active');
$('html, body').animate({
scrollTop: block.offset().top - 100
}, 1000);
}
});
WFAD.ajax('wordfence_saveDisclosureState', {name: block.data('persistenceKey'), state: true}, function() {});
}
else {
$('html, body').animate({
scrollTop: block.offset().top - 100
}, 1000);
}
history.replaceState('', document.title, window.location.pathname + window.location.search);
}
}
});
})(jQuery);
</script>
<div class="wf-section-title">
<h2><?php esc_html_e('Live Traffic', 'wordfence') ?></h2>
<span><?php echo wp_kses(sprintf(
/* translators: URL to support page. */
__('<a href="%s" target="_blank" rel="noopener noreferrer" class="wf-help-link">Learn more<span class="wf-hidden-xs"> about Live Traffic</span><span class="screen-reader-text"> (opens in new tab)</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_TOOLS_LIVE_TRAFFIC)), array('a'=>array('href'=>array(), 'target'=>array(), 'rel'=>array(), 'class'=>array()), 'span'=>array('class'=>array()))); ?>
<i class="wf-fa wf-fa-external-link" aria-hidden="true"></i></span>
</div>
<?php if (wfConfig::liveTrafficEnabled() && wfConfig::get('liveActivityPauseEnabled')): ?>
<div id="wfLiveTrafficOverlayAnchor"></div>
<div id="wfLiveTrafficDisabledMessage">
<h2><?php esc_html_e('Live Updates Paused', 'wordfence') ?><br/>
<small><?php esc_html_e('Click inside window to resume', 'wordfence') ?></small>
</h2>
</div>
<?php endif ?>
<p><?php esc_html_e("Wordfence Live Traffic shows you what is happening on your site in real-time, including user logins, hack attempts, and requests that were blocked by the Wordfence Firewall. You can choose to log security-related traffic only or all traffic. Traffic is logged directly on the server, which means it includes visits that don't execute JavaScript. Google and other JavaScript-based analytics packages typically only show visits from browsers that are operated by a human, while Live Traffic can show visits from crawlers like Google and Bing.", 'wordfence') ?></p>
<div class="wordfenceModeElem" id="wordfenceMode_liveTraffic"></div>
<?php
echo wfView::create('tools/options-group-live-traffic', array(
'stateKey' => 'live-traffic-options',
'showControls' => true,
))->render();
?>
<?php
$overridden = false;
if (!wfConfig::liveTrafficEnabled($overridden)):
?>
<div id="wordfenceLiveActivitySecurityOnly"><p>
<strong><?php esc_html_e('Traffic logging mode: Security-related traffic only', 'wordfence') ?><?php
if ($overridden) {
echo wp_kses(sprintf(
/* translators: URL to support page. */
__(' (host setting <a href="%s" class="wfhelp" target="_blank" rel="noopener noreferrer"><span class="screen-reader-text"> (opens in new tab)</span></a>)', 'wordfence'), wfSupportController::supportURL(wfSupportController::ITEM_TOOLS_LIVE_TRAFFIC_OPTION_ENABLE)), array('a'=>array('href'=>array(), 'target'=>array(), 'rel'=>array(), 'class'=>array()), 'span'=>array('class'=>array())));
} ?>.</strong> <?php esc_html_e('Login and firewall activity will appear below.', 'wordfence') ?></p>
</div>
<?php else: ?>
<div id="wordfenceLiveActivityAll"><p>
<strong><?php esc_html_e('Traffic logging mode: All traffic', 'wordfence') ?><?php
if ($overridden) {
echo wp_kses(sprintf(
/* translators: URL to support page. */
__(' (host setting <a href="%s" class="wfhelp" target="_blank" rel="noopener noreferrer"><span class="screen-reader-text"> (opens in new tab)</span></a>)', 'wordfence'), wfSupportController::supportURL(wfSupportController::ITEM_TOOLS_LIVE_TRAFFIC_OPTION_ENABLE)), array('a'=>array('href'=>array(), 'target'=>array(), 'rel'=>array(), 'class'=>array()), 'span'=>array('class'=>array())));
} ?>.</strong> <?php esc_html_e('Regular traffic and security-related traffic will appear below.', 'wordfence') ?></p>
</div>
<?php endif; ?>
<div id="wf-live-traffic" class="wf-row<?php echo wfConfig::get('liveTraf_displayExpandedRecords') ? ' wf-live-traffic-display-expanded' : '' ?>">
<div class="wf-col-xs-12">
<div class="wf-block wf-active">
<div class="wf-block-content">
<div class="wf-container-fluid">
<div class="wf-row">
<div class="<?php echo wfStyle::contentClasses(); ?>">
<div id="wf-live-traffic-legend">
<ul>
<li class="wfHuman"><?php esc_html_e('Human', 'wordfence') ?></li>
<li class="wfBot"><?php esc_html_e('Bot', 'wordfence') ?></li>
<li class="wfNotice"><?php esc_html_e('Warning', 'wordfence') ?></li>
<li class="wfBlocked"><?php esc_html_e('Blocked', 'wordfence') ?></li>
</ul>
</div>
<div class="wf-row wf-add-bottom-small">
<div class="wf-col-xs-12" id="wf-live-traffic-legend-wrapper">
<form data-bind="submit: reloadListings">
<ul class="wf-live-traffic-controls">
<li class="wf-live-traffic-filter">
<div class="wf-padding-no-left"><select id="wf-lt-preset-filters" data-bind="options: presetFiltersOptions, optionsText: presetFiltersOptionsText, value: selectedPresetFilter"></select></div>
&nbsp;&nbsp;
<input id="wf-live-traffic-filter-show-advanced" class="wf-option-checkbox" data-bind="checked: showAdvancedFilters" type="checkbox">
<label for="wf-live-traffic-filter-show-advanced">
<?php esc_html_e('Show Advanced Filters', 'wordfence') ?>
</label>
</li>
<li class="wf-live-traffic-show-expanded">
<ul class="wf-option wf-option-toggled-boolean-switch wf-option-no-spacing" data-option="liveTraf_displayExpandedRecords" data-enabled-value="1" data-disabled-value="0" data-original-value="<?php echo wfConfig::get('liveTraf_displayExpandedRecords') ? 1 : 0; ?>">
<li class="wf-boolean-switch<?php echo wfConfig::get('liveTraf_displayExpandedRecords') ? ' wf-active' : ''; ?>"><a href="#" class="wf-boolean-switch-handle"></a></li>
<li class="wf-option-title wf-padding-add-left wf-no-right wf-padding-no-right">
<?php esc_html_e('Expand All Results', 'wordfence'); ?>
</li>
</ul>
</li>
</ul>
<div data-bind="visible: showAdvancedFilters" id="wf-lt-advanced-filters">
<div class="wf-live-traffic-filter-detail">
<div>
<div data-bind="foreach: filters">
<div class="wf-live-traffic-filter-item">
<div class="wf-live-traffic-filter-item-parameters">
<div>
<select name="param[]" class="wf-lt-advanced-filters-param" data-bind="options: filterParamOptions, optionsText: filterParamOptionsText, value: selectedFilterParamOptionValue, optionsCaption: 'Filter...'"></select>
</div>
<div data-bind="visible: selectedFilterParamOptionValue() && selectedFilterParamOptionValue().type() != 'bool'">
<select name="operator[]" class="wf-lt-advanced-filters-operator" data-bind="options: filterOperatorOptions, optionsText: filterOperatorOptionsText, value: selectedFilterOperatorOptionValue"></select>
</div>
<div data-bind="attr: {colSpan: (selectedFilterParamOptionValue() && selectedFilterParamOptionValue().type() == 'bool' ? 2 : 1)}" class="wf-lt-advanced-filters-value-cell">
<span data-bind="if: selectedFilterParamOptionValue() && selectedFilterParamOptionValue().type() == 'enum'">
<select data-bind="options: selectedFilterParamOptionValue().values, optionsText: selectedFilterParamOptionValue().optionsText, value: value"></select>
</span>
<span data-bind="if: selectedFilterParamOptionValue() && selectedFilterParamOptionValue().type() == 'text'">
<input data-bind="value: value" type="text">
</span>
<span data-bind="if: selectedFilterParamOptionValue() && selectedFilterParamOptionValue().type() == 'bool'">
<label><?php esc_html_e('Yes', 'wordfence') ?> <input data-bind="checked: value" type="radio" value="1"></label>
<label><?php esc_html_e('No', 'wordfence') ?> <input data-bind="checked: value" type="radio" value="0"></label>
</span>
</div>
</div>
<div>
<!--<button data-bind="click: $root.removeFilter" type="button" class="wf-btn wf-btn-default">Remove</button> -->
<a href="#" data-bind="click: $root.removeFilter" class="wf-live-traffic-filter-remove" role="button"><i class="wf-ion-trash-a"></i></a>
</div>
</div>
</div>
<div>
<div class="wf-pad-small">
<button type="button" class="wf-btn wf-btn-default" data-bind="click: addFilter">
<?php esc_html_e('Add Filter', 'wordfence') ?>
</button>
</div>
</div>
</div>
<div class="wf-form wf-form-horizontal">
<div class="wf-form-group">
<label for="wf-live-traffic-from" class="wf-col-sm-2"><?php esc_html_e('From:', 'wordfence') ?>&nbsp;</label>
<div class="wf-col-sm-10">
<input placeholder="Start date" id="wf-live-traffic-from" type="text" class="wf-datetime" data-bind="value: startDate, datetimepicker: null, datepickerOptions: { timeFormat: 'hh:mm tt z' }">
<button data-bind="click: startDate('')" class="wf-btn wf-btn-default wf-btn-sm" type="button"><?php esc_html_e('Clear', 'wordfence') ?></button>
</div>
</div>
<div class="wf-form-group">
<label for="wf-live-traffic-to" class="wf-col-sm-2"><?php esc_html_e('To:', 'wordfence')?>&nbsp;</label>
<div class="wf-col-sm-10">
<input placeholder="End date" id="wf-live-traffic-to" type="text" class="wf-datetime" data-bind="value: endDate, datetimepicker: null, datepickerOptions: { timeFormat: 'hh:mm tt z' }">
<button data-bind="click: endDate('')" class="wf-btn wf-btn-default wf-btn-sm" type="button"><?php esc_html_e('Clear', 'wordfence') ?></button>
</div>
</div>
<div class="wf-form-group">
<label for="wf-live-traffic-group-by" class="wf-col-sm-2"><?php esc_html_e('Group By:', 'wordfence') ?>&nbsp;</label>
<div class="wf-col-sm-10">
<select id="wf-live-traffic-group-by" name="groupby" class="wf-lt-advanced-filters-groupby" data-bind="options: filterGroupByOptions, optionsText: filterGroupByOptionsText, value: groupBy, optionsCaption: 'None'"></select>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
<div class="wf-row">
<div class="wf-col-xs-12">
<div id="wf-live-traffic-group-by" class="wf-block" data-bind="if: groupBy(), visible: groupBy()">
<ul class="wf-filtered-traffic wf-block-list" data-bind="foreach: listings">
<li class="wf-flex-row wf-padding-add-top wf-padding-add-bottom">
<div class="wf-flex-row-1">
<!-- ko if: $root.groupBy().param() == 'ip' -->
<div data-bind="if: loc()">
<span data-bind="attr: { class: 'wf-flag wf-flag-' + loc().countryCode.toLowerCase(), title: loc().countryName }"></span>
<a data-bind="text: (loc().city ? loc().city + ', ' : '') + (loc().region ? loc().region + ', ' : '') + loc().countryName,
attr: { href: 'http://maps.google.com/maps?q=' + loc().lat + ',' + loc().lon + '&z=6' }"
target="_blank" rel="noopener noreferrer"><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a>
</div>
<div data-bind="if: !loc()">
<?php esc_html_e('An unknown location at IP', 'wordfence') ?>
<span data-bind="text: IP" target="_blank" rel="noopener noreferrer"></span>
</div>
<div>
<strong><?php esc_html_e('IP:', 'wordfence') ?></strong>
<span data-bind="text: IP" target="_blank" rel="noopener noreferrer"></span>
</div>
<div>
<span class="wfReverseLookup"><span data-bind="text: IP" style="display:none;"></span></span>
</div>
<!-- /ko -->
<!-- ko if: $root.groupBy().param() == 'type' -->
<div>
<strong><?php esc_html_e('Type:', 'wordfence') ?></strong>
<span data-bind="if: jsRun() == '1'"><?php esc_html_e('Human', 'wordfence') ?></span>
<span data-bind="if: jsRun() == '0'"><?php esc_html_e('Bot', 'wordfence') ?></span>
</div>
<!-- /ko -->
<!-- ko if: $root.groupBy().param() == 'user_login' -->
<div>
<strong><?php esc_html_e('Username:', 'wordfence') ?></strong>
<span data-bind="text: username()"></span>
</div>
<!-- /ko -->
<!-- ko if: $root.groupBy().param() == 'statusCode' -->
<div>
<strong><?php esc_html_e('HTTP Response Code:', 'wordfence') ?></strong>
<span data-bind="text: statusCode()"></span>
</div>
<!-- /ko -->
<!-- ko if: $root.groupBy().param() == 'action' -->
<div>
<strong><?php esc_html_e('Firewall Response:', 'wordfence') ?></strong>
<span data-bind="text: firewallAction()"></span>
</div>
<!-- /ko -->
<!-- ko if: $root.groupBy().param() == 'url' -->
<div>
<strong><?php esc_html_e('URL:', 'wordfence') ?></strong>
<span data-bind="text: displayURL()"></span>
</div>
<!-- /ko -->
<div>
<strong><?php esc_html_e('Last Hit:', 'wordfence') ?></strong> <span
data-bind="attr: { 'data-timestamp': ctime, text: <?php echo esc_attr(sprintf(json_encode(/* translators: Time ago. */ __('Last hit was %s ago.', 'wordfence')), '"+ ctime() + "')) ?> }"
class="wfTimeAgo wfTimeAgo-timestamp"></span>
</div>
<!-- ko if: $root.groupBy().param() == 'ip' -->
<div class="wf-add-top-small">
<span data-bind="if: blocked()">
<a class="wf-btn wf-btn-default wf-btn-sm" data-bind="click: unblockIP"><?php esc_html_e('Unblock IP', 'wordfence') ?></a>
</span>
<span data-bind="if: rangeBlocked()">
<a class="wf-btn wf-btn-default wf-btn-sm" data-bind="click: unblockNetwork"><?php esc_html_e('Unblock range', 'wordfence') ?></a>
</span>
<span data-bind="if: !blocked() && !rangeBlocked()">
<a class="wf-btn wf-btn-default wf-btn-sm" data-bind="click: blockIP"><?php esc_html_e('Block IP', 'wordfence') ?></a>
</span>
</div>
<!-- /ko -->
</div>
<div class="wf-flex-row-0 wf-padding-add-left">
<?php echo sprintf(/* translators: Number of HTTP requests. */ esc_html__('%s hits', 'wordfence'), '<span class="wf-filtered-traffic-hits" data-bind="text: hitCount"></span>') ?>
</div>
</li>
</ul>
</div>
<div id="wf-live-traffic-no-group-by" data-bind="if: !groupBy()">
<table class="wf-striped-table">
<thead>
<tr>
<th><?php esc_html_e('Type', 'wordfence') ?></th>
<th><?php esc_html_e('Location', 'wordfence') ?></th>
<th><?php esc_html_e('Page Visited', 'wordfence') ?></th>
<th><?php esc_html_e('Time', 'wordfence') ?></th>
<th><?php esc_html_e('IP Address', 'wordfence') ?></th>
<th><?php esc_html_e('Hostname', 'wordfence') ?></th>
<th><?php esc_html_e('Response', 'wordfence') ?></th>
<th><?php esc_html_e('View', 'wordfence') ?></th>
</tr>
</thead>
<tbody id="wf-lt-listings" class="wf-filtered-traffic" data-bind="foreach: listings">
<tr data-bind="click: toggleDetails, css: { odd: ($index() % 2 == 1), even: ($index() % 2 == 0), 'wf-details-open': showDetails, highlighted: highlighted }" class="wf-summary-row">
<td class="wf-center">
<span data-bind="attr: { 'class': cssClasses }"></span>
</td>
<td>
<span class="wf-flex-horizontal" data-bind="if: loc()">
<span data-bind="attr: { class: 'wf-flag wf-flag-' + loc().countryCode.toLowerCase(), title: loc().countryName }"></span>
<span class="wf-padding-add-left-small" data-bind="text: (loc().city ? loc().city + ', ' : '') + (loc().region ? loc().region + ', ' : '') + loc().countryName"></span>
</span>
<span class="wf-flex-horizontal" data-bind="if: !loc()">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 64.22 64.37" class="wf-flag wf-flag-unspecified"><path d="M64,28.21a30.32,30.32,0,0,0-5.8-14.73A31.6,31.6,0,0,0,37.43.56C35.7.26,33.94.18,32.2,0h-.35C30.22.18,28.58.3,27,.55A32.14,32.14,0,0,0,.2,35.61,31.4,31.4,0,0,0,10.4,55.87a31.24,31.24,0,0,0,25,8.33,30.5,30.5,0,0,0,18.94-8.79C62,47.94,65.15,38.8,64,28.21ZM57.21,44.68a23.94,23.94,0,0,1-2.3-5.08c-.66-2.45-2.27-.08-2.4,1.52s-1.2,2.8-3.33.4-2.54-1.87-3.2-1.87-1.87,1.6-1.6,9.07c.19,5.33,2.29,6.18,3.67,6.56a27.16,27.16,0,0,1-8.78,4A27.55,27.55,0,0,1,7.85,45.13C2.27,34.4,5,22.26,10.67,15.57c.15,1.21.3,2.29.43,3.37a27.63,27.63,0,0,1-.52,8.79,4.39,4.39,0,0,0,.08,1.94,1.3,1.3,0,0,0,.94.76c.27,0,.75-.41.86-.73a8.27,8.27,0,0,0,.27-1.86c0-.44,0-.89.07-1.58a10.67,10.67,0,0,1,1.06.86c.7.7,1.4,1.4,2,2.15a2.11,2.11,0,0,1,.56,1.21,3.44,3.44,0,0,0,.83,2.13,12.21,12.21,0,0,1,1.07,2.57c.14.37.17.78.33,1.13a2,2,0,0,0,1.8,1.32c1,.07,1.32.44,1.46,1.43l-.74.08c-1.17.11-1.75.65-1.71,1.83a8.43,8.43,0,0,0,2.69,6c.48.45,1,.87,1.46,1.33a3.35,3.35,0,0,1,.92,3.75,12.18,12.18,0,0,0-.69,2.09,6,6,0,0,0,.06,2.23c.18.75.1,2.37.86,2.24,1.36-.24,2.14,0,2.25-1.49a1.22,1.22,0,0,0-.08-.6c-.4-1.42,1.42-5.47,2.52-6.2a27.11,27.11,0,0,0,2.73-2,3.6,3.6,0,0,0,1.26-4,3.22,3.22,0,0,1,1.14-3.59,4.54,4.54,0,0,0,1.71-3.65c-.08-1.53-1.07-2.63-2.37-2.47a9.21,9.21,0,0,0-1.87.59,20.62,20.62,0,0,1-2.72.9c-1.31.23-2.11-.62-2.69-1.66-.47-.83-.63-.9-1.44-.38s-1.37.89-2.08,1.28S22,35.58,21.45,35a5.79,5.79,0,0,0-1.24-.88c-.31-.19-.73-.24-1-.48s-.8-.8-.75-1.15a1.69,1.69,0,0,1,.95-1.1,14.36,14.36,0,0,1,2.29-.51,7.33,7.33,0,0,0,1.22-.33c.52-.21.5-.56.1-.89a3.26,3.26,0,0,0-.69-.37l-3.52-1.39a4.74,4.74,0,0,1-.84-.43c-.74-.49-.83-1-.16-1.61,2.64-2.33,5.72-3,8.45.08.84,1,1.42,2.16,2.22,3.16a12.5,12.5,0,0,0,2.15,2.15,1.62,1.62,0,0,0,1.44.09,1.15,1.15,0,0,0,.29-1.56,8.43,8.43,0,0,0-.86-1.41,5.16,5.16,0,0,1,1.59-7.52,4.38,4.38,0,0,0,2.53-2.58c-.58.16-1,.26-1.42.39-2.3.71-.7-1,.36-1.31.65-.18-.58-.67-.58-.67s.82-.28,1.69-.65a6.85,6.85,0,0,0,1.7-.94,3.79,3.79,0,0,0,.66-1.17l-.16-.18-1.83.24c-1,.11-1.27-.09-1.37-1.14a1,1,0,0,0-1.48-.73c-.45.25-.85.61-1.29.9-1,.66-1.78.39-2.19-.75-.23-.68-.57-.81-1.19-.42-.31.18-.58.47-.89.64a11.53,11.53,0,0,1-1.62.79c-.55.19-1.21.33-1.58-.27a1.25,1.25,0,0,1,.46-1.68A14.78,14.78,0,0,1,27,10c1-.56,2.07-1,3-1.65a1.78,1.78,0,0,0,.79-2.07.88.88,0,0,0-1.37-.65c-.56.28-1.06.72-1.63,1a2.81,2.81,0,0,1-1.41.08c-.17,0-.35-.49-.35-.76s.31-.43.51-.46c1.4-.22,2.81-.41,4.22-.57a.76.76,0,0,1,.58.25,6.84,6.84,0,0,0,3.6,2.15c1.15.34,1.31.18,1.47-1,1.48-.34,3-1,4.46-.09A14.4,14.4,0,0,1,43.14,8c.18.17.07.7,0,1s-.36.87-.48,1.33a1.2,1.2,0,0,0,1.26,1.56c.29,0,.57-.07.86-.08.85,0,1.14.28,1.07,1.13-.11,1.21.09,1.35,1.31,1.15a2.07,2.07,0,0,1,1.67.64c1.14.86,2,.54,2.33-.86,0-.16,0-.32.06-.47.14-.63.49-.79.92-.35.9,1,1.74,2,2.66,3a3,3,0,0,0-.8,3.07,5.19,5.19,0,0,1-.55,3.27A24.63,24.63,0,0,0,52.2,25.5c-.45,1.57.06,2.3,1.66,2.65s1.78.64,1.84,2.14a4.85,4.85,0,0,0,2.92,4.35c.4.19.82.34,1.23.51a25.22,25.22,0,0,1-2.64,9.53Z"/></svg> <span class="wf-padding-add-left-small"><?php esc_html_e('Unspecified', 'wordfence') ?></span>
</span>
</td>
<td>
<span class="wf-lt-url wf-split-word-xs"
data-bind="text: displayURLShort, attr: { title: URL }"></span>
</td>
<td class="wf-nowrap" data-bind="text: timestamp"></td>
<td>
<span data-bind="attr: { title: IP }, text: $root.trimIP(IP())"></span>
</td>
<td>
<span class="wfReverseLookup" data-reverse-lookup-template="wf-live-traffic-hostname-template">
<span data-bind="text: IP" style="display:none;"></span>
</span>
</td>
<td data-bind="text: statusCode"></td>
<td class="wf-live-traffic-show-details">
<span class="wf-ion-eye"></span>
<span class="wf-ion-eye-disabled"></span>
</td>
</tr>
<tr data-bind="css: {
'wf-details-visible': showDetails,
'wf-details-hidden': !(showDetails()),
highlighted: highlighted,
odd: ($index() % 2 == 1), even: ($index() % 2 == 0) }" class="wf-details-row">
<td colspan="8" data-bind="attr: { id: ('wfActEvent_' + id()) }" class="wf-live-traffic-details">
<div class="wf-live-traffic-activity-detail-wrapper">
<div class="wf-live-traffic-activity-type">
<div data-bind="attr: { 'class': typeIconClass }"></div>
<div data-bind="text: typeText"></div>
</div>
<div class="wf-live-traffic-activity-detail">
<h2><?php esc_html_e('Activity Detail', 'wordfence') ?></h2>
<div>
<span data-bind="if: action() != 'loginOK' && action() != 'loginFailValidUsername' && action() != 'loginFailInvalidUsername' && user()">
<span data-bind="attr: {'data-userid': user().ID}" class="wfAvatar"></span>
<a data-bind="attr: { href: user().editLink }, text: user().display_name"
target="_blank" rel="noopener noreferrer"><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a>
</span>
<span data-bind="if: loc()">
<span data-bind="if: action() != 'loginOK' && action() != 'loginFailValidUsername' && action() != 'loginFailInvalidUsername' && user()"> in</span>
<span data-bind="attr: { class: 'wf-flag wf-flag-' + loc().countryCode.toLowerCase(), title: loc().countryName }"></span>
<a data-bind="text: (loc().city ? loc().city + ', ' : '') + (loc().region ? loc().region + ', ' : '') + loc().countryName,
attr: { href: 'http://maps.google.com/maps?q=' + loc().lat + ',' + loc().lon + '&z=6' }"
target="_blank" rel="noopener noreferrer"><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a>
</span>
<span data-bind="if: !loc()">
<span data-bind="if: action() != 'loginOK' && action() != 'loginFailValidUsername' && action() != 'loginFailInvalidUsername' && user()">
<?php echo wp_kses(sprintf(
/* translators: 1. User agent. 2. IP address */
__('%1$s at an unknown location at IP %2$s', 'wordfence'), '', '<a data-bind="text: IP, attr: { href: WFAD.makeIPTrafLink(IP()) }" target="_blank" rel="noopener noreferrer"><span class="screen-reader-text"> (opens in new tab)</span></a>'), array('a'=>array('href'=>array(), 'target'=>array(), 'rel'=>array(), 'data-bind'=>array()), 'span'=>array('class'=>array()))) ?>
</span>
<span data-bind="if: !(action() != 'loginOK' && action() != 'loginFailValidUsername' && action() != 'loginFailInvalidUsername' && user())">
<?php echo wp_kses(sprintf(
/* translators: IP address */
__('An unknown location at IP %s', 'wordfence'), '<a data-bind="text: IP, attr: { href: WFAD.makeIPTrafLink(IP()) }" target="_blank" rel="noopener noreferrer"><span class="screen-reader-text"> (opens in new tab)</span></a>'), array('a'=>array('href'=>array(), 'target'=>array(), 'rel'=>array(), 'data-bind'=>array()), 'span'=>array('class'=>array()))) ?>
</span>
</span>
<span data-bind="if: referer()">
<span data-bind="if: extReferer()">
<?php echo wp_kses(sprintf(
/* translators: 1. User agent. 2. HTTP referer. 3. Server response. */
__('%1$s arrived from %2$s and %3$s', 'wordfence'), '', '<a data-bind="text: LiveTrafficViewModel.truncateText(referer(), 100), attr: { title: referer, href: referer }" target="_blank" rel="noopener noreferrer" class="wf-split-word-xs"><span class="screen-reader-text"> (opens in new tab)</span></a>', ''), array('a'=>array('href'=>array(), 'target'=>array(), 'rel'=>array(), 'class'=>array(), 'data-bind'=>array()), 'span'=>array('class'=>array()))) ?>
</span>
<span data-bind="if: !extReferer()">
<?php echo wp_kses(sprintf(
/* translators: 1. User agent. 2. HTTP referer. 3. Server response. */
__('%1$s left %2$s and %3$s', 'wordfence'), '', '<a data-bind="text: LiveTrafficViewModel.truncateText(referer(), 100), attr: { title: referer, href: referer }" target="_blank" rel="noopener noreferrer" class="wf-split-word-xs"><span class="screen-reader-text"> (opens in new tab)</span></a>', ''), array('a'=>array('href'=>array(), 'target'=>array(), 'rel'=>array(), 'class'=>array(), 'data-bind'=>array()), 'span'=>array('class'=>array()))) ?>
</span>
</span>
<span data-bind="if: statusCode() == 404">
<?php echo wp_kses(sprintf(
/* translators: User agent. */
__('%s tried to access a <span style="color: #F00;">non-existent page</span>', 'wordfence'), ''), array('span'=>array('style'=>array()))) ?>
</span>
<span data-bind="if: statusCode() == 200 && !action()">
<?php echo esc_html(sprintf(
/* translators: 1. User agent. 2. URL of page visited. */
__('%1$s visited %2$s', 'wordfence'), '', '')) ?>
</span>
<span data-bind="if: (statusCode() == 301 || statusCode() == 302) && !action()">
<?php echo esc_html(sprintf(
/* translators: 1. User agent. 2. URL of page visited. */
__('%1$s was redirected when visiting %2$s', 'wordfence'), '', '')) ?>
</span>
<span data-bind="if: (statusCode() == 301 || statusCode() == 302) && action() && firewallAction()">
<?php echo wp_kses(sprintf(
/* translators: 1. User agent. 2. Firewall action (blocked, rate limited, etc). 3. Time ago. */
__('%1$s was %2$s at %3$s', 'wordfence'), '', '<span data-bind="text: firewallAction"></span>', ''), array('span'=>array('data-bind'=>array()))) ?>
</span>
<span data-bind="if: ((statusCode() == 403 || statusCode() == 503) && action() != 'loginFailValidUsername' && action() != 'loginFailInvalidUsername')">
<?php printf(
/* translators: 1. User agent. 2. Firewall action (blocked, rate limited, etc). 3. Time ago. */
esc_html(__('%1$s was %2$s at %3$s', 'wordfence')), '', '<span data-bind="text: firewallAction" style="color: #F00;"></span>', '') ?>
</span>
<span data-bind="if: action() == 'loginOK'">
<?php echo wp_kses(sprintf(
/* translators: 1. User agent. 2. WordPress username. */
__('%1$s logged in successfully as "%2$s".', 'wordfence'), '', '<strong data-bind="text: username"></strong>'), array('strong'=>array('data-bind'=>array()))) ?>
</span>
<span data-bind="if: action() == 'logout'">
<?php echo esc_html(sprintf(/* translators: WordPress username. */ __('%s logged out successfully.', 'wordfence'), '')) ?>
</span>
<span data-bind="if: action() == 'lostPassword'">
<?php echo esc_html(sprintf(/* translators: WordPress username. */__('%s requested a password reset.', 'wordfence'), '')) ?>
</span>
<span data-bind="if: action() == 'loginFailValidUsername'">
<?php echo wp_kses(sprintf(/* translators: 1. User agent. 2. WordPress username. */ __('%1$s attempted a <span style="color: #F00;">failed login</span> as "%2$s".', 'wordfence'), '', '<strong data-bind="text: username"></strong>'), array('span'=>array('style'=>array()), 'strong'=>array('data-bind'=>array()))) ?>
</span>
<span data-bind="if: action() == 'loginFailInvalidUsername'">
<?php echo wp_kses(sprintf(/* translators: 1. User agent. 2. WordPress username. */ __('%1$s attempted a <span style="color: #F00;">failed login</span> using an invalid username "%2$s".', 'wordfence'), '', '<strong data-bind="text: username"></strong>'), array('span'=>array('style'=>array()), 'strong'=>array('data-bind'=>array()))) ?>
</span>
<span data-bind="if: action() == 'user:passwordReset'">
<?php echo esc_html(sprintf(/* translators: WordPress username. */ __('%s changed their password.', 'wordfence'), '')) ?>
</span>
<a class="wf-lt-url wf-split-word-xs"
data-bind="text: displayURL, attr: { href: URL, title: URL }"
target="_blank" rel="noopener noreferrer"><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a>
</div>
<div>
<span data-bind="text: timeAgo, attr: { 'data-timestamp': ctime }"
class="wfTimeAgo-timestamp"></span>&nbsp;&nbsp;
</div>
<div>
<strong><?php esc_html_e('IP:', 'wordfence') ?></strong> <span data-bind="text: IP"></span>
<span class="wfReverseLookup">
<span data-bind="text: IP" style="display:none;"></span>
</span>
<span data-bind="if: blocked()">
<a class="wf-btn wf-btn-default wf-btn-sm wf-block-ip-btn"
data-bind="click: unblockIP">
<?php esc_html_e('Unblock IP', 'wordfence') ?>
</a>
</span>
<span data-bind="if: rangeBlocked()">
<a class="wf-btn wf-btn-default wf-btn-sm wf-block-ip-btn"
data-bind="click: unblockNetwork"><?php esc_html_e('Unblock range', 'wordfence') ?>
</a>
</span>
<span data-bind="if: !blocked() && !rangeBlocked()">
<a class="wf-btn wf-btn-default wf-btn-sm wf-block-ip-btn"
data-bind="click: blockIP">
<?php esc_html_e('Block IP', 'wordfence') ?>
</a>
</span>
</div>
<div data-bind="visible: (jQuery.inArray(parseInt(statusCode(), 10), [403, 503, 404]) !== -1 || action() == 'loginFailValidUsername' || action() == 'loginFailInvalidUsername')">
<strong><?php esc_html_e('Human/Bot:', 'wordfence') ?></strong> <span data-bind="text: (jsRun() === '1' ? <?php echo esc_attr(json_encode(__('Human', 'wordfence'))) ?> : <?php echo esc_attr(json_encode(__('Bot', 'wordfence'))) ?>)"></span>
</div>
<div class="wf-split-word" data-bind="text: UA"></div>
<div class="wf-live-traffic-actions">
<span data-bind="if: blocked()">
<a class="wf-btn wf-btn-default wf-btn-sm"
data-bind="click: unblockIP">
<?php esc_html_e('Unblock IP', 'wordfence') ?>
</a>
</span>
<span data-bind="if: rangeBlocked()">
<a class="wf-btn wf-btn-default wf-btn-sm"
data-bind="click: unblockNetwork">
<?php esc_html_e('Unblock range', 'wordfence') ?>
</a>
</span>
<span data-bind="if: !blocked() && !rangeBlocked()">
<a class="wf-btn wf-btn-default wf-btn-sm"
data-bind="click: blockIP">
<?php esc_html_e('Block IP', 'wordfence') ?>
</a>
</span>
<a class="wf-btn wf-btn-default wf-btn-sm" data-bind="click: showWhoisOverlay"
target="_blank" rel="noopener noreferrer"><?php esc_html_e('Run Whois', 'wordfence') ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a>
<a class="wf-btn wf-btn-default wf-btn-sm"
data-bind="click: showRecentTraffic" target="_blank" rel="noopener noreferrer">
<span class="wf-hidden-xs"><?php esc_html_e('See recent traffic', 'wordfence'); ?></span><span class="wf-visible-xs"><?php esc_html_e('Recent', 'wordfence'); ?></span>
</a>
<span data-bind="if: action() == 'blocked:waf' && actionData().path && actionData().paramKey && actionData().failedRules">
<a class="wf-btn wf-btn-default wf-btn-sm"
data-bind="click: function () { $root.whitelistWAFParamKey(actionData().path, actionData().paramKey, actionData().failedRules) }"
title="<?php esc_attr_e('If this is a false positive, you can exclude this parameter from being filtered by the firewall', 'wordfence') ?>">
<?php esc_html_e('Add Param to Firewall Allowlist', 'wordfence') ?>
</a>
<?php if (WFWAF_DEBUG): ?>
<a class="wf-btn wf-btn-default wf-btn-sm"
data-bind="attr: { href: '<?php echo esc_js(home_url()) ?>?_wfsf=debugWAF&nonce=' + WFAD.nonce + '&hitid=' + id() }" target="_blank" rel="noopener noreferrer">
Debug this Request
</a>
<?php endif ?>
</span>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="wf-live-traffic-none" data-bind="if: listings().length == 0">
<?php esc_html_e('No requests to report yet.', 'wordfence') ?>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="application/javascript">
(function($) {
$(function() {
$('.wf-option.wf-option-toggled-boolean-switch[data-option="liveTraf_displayExpandedRecords"]').on('change', function() {
delete WFAD.pendingChanges['liveTraf_displayExpandedRecords'];
var isOn = $(this).find('.wf-boolean-switch').hasClass('wf-active');
WFAD.setOption($(this).data('option'), (isOn ? $(this).data('enabledValue') : $(this).data('disabledValue')), function() {
$('#wf-live-traffic').toggleClass('wf-live-traffic-display-expanded', isOn);
});
});
$(document).on('heartbeat-tick', function(heartbeat) {
WFAD.serverMicrotime = heartbeat.timeStamp / 1000;
WFAD.updateTimeAgo();
})
});
})(jQuery);
</script>
<div id="wf-live-traffic-util-overlay-wrapper" style="display: none">
<div class="wf-live-traffic-util-overlay">
<div class="wf-live-traffic-util-overlay-header"></div>
<div class="wf-live-traffic-util-overlay-body"></div>
<span class="wf-live-traffic-util-overlay-close wf-ion-android-close"></span>
</div>
</div>
<div id="wfrawhtml"></div>
<script type="text/x-jquery-template" id="wf-live-traffic-hostname-template">
<span title="${ip}">${(ip && ip.length > 22) ? '...' + ip.substring(ip.length - 22) : ip}</span>
</script>
<?php if (wfOnboardingController::willShowNewTour(wfOnboardingController::TOUR_LIVE_TRAFFIC)): ?>
<script type="application/javascript">
(function($) {
$(function() {
WFAD.tour1 = function() {
WFAD.tour('wfNewTour1', 'wf-live-traffic', 'bottom', 'bottom', null, WFAD.tourComplete);
};
WFAD.tourComplete = function() { WFAD.tourFinish('<?php echo esc_attr(wfOnboardingController::TOUR_LIVE_TRAFFIC); ?>'); };
<?php if (wfOnboardingController::shouldShowNewTour(wfOnboardingController::TOUR_LIVE_TRAFFIC)): ?>
if (!WFAD.isSmallScreen) { WFAD.tour1(); }
<?php endif; ?>
});
})(jQuery);
</script>
<script type="text/x-jquery-template" id="wfNewTour1">
<div>
<h3><?php esc_html_e('Live Traffic', 'wordfence'); ?></h3>
<p><?php echo wp_kses(__('Live traffic defaults to a summary view of all security-related traffic. Details are viewable by clicking anywhere within the summary record. To switch to the expanded view, click the <strong>Expand All Records</strong> switch.', 'wordfence'), array('strong'=>array())); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li class="wf-active">&bullet;</li>
</ul>
<div id="wf-tour-continue"><a href="#" class="wf-onboarding-btn wf-onboarding-btn-primary" role="button"><?php esc_html_e('Got it', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<?php endif; ?>
<?php if (wfOnboardingController::willShowUpgradeTour(wfOnboardingController::TOUR_LIVE_TRAFFIC)): ?>
<script type="application/javascript">
(function($) {
$(function() {
WFAD.tour1 = function() {
WFAD.tour('wfUpgradeTour1', 'wf-live-traffic', 'bottom', 'bottom', null, WFAD.tourComplete);
};
WFAD.tourComplete = function() { WFAD.tourFinish('<?php echo esc_attr(wfOnboardingController::TOUR_LIVE_TRAFFIC); ?>'); };
<?php if (wfOnboardingController::shouldShowUpgradeTour(wfOnboardingController::TOUR_LIVE_TRAFFIC)): ?>
if (!WFAD.isSmallScreen) { WFAD.tour1(); }
<?php endif; ?>
});
})(jQuery);
</script>
<script type="text/x-jquery-template" id="wfUpgradeTour1">
<div>
<h3><?php esc_html_e('Live Traffic', 'wordfence'); ?></h3>
<p><?php echo wp_kses(__('Live traffic now defaults to a summary view. Details are viewable by clicking anywhere within the summary record. To switch to the expanded view, click the <strong>Expand All Records</strong> switch. New installations will only log security-related traffic by default, though your previous setting has been preserved.', 'wordfence'), array('strong'=>array())); ?></p>
<div class="wf-pointer-footer">
<ul class="wf-tour-pagination">
<li class="wf-active">&bullet;</li>
</ul>
<div id="wf-tour-continue"><a href="#" role="button" class="wf-onboarding-btn wf-onboarding-btn-primary"><?php esc_html_e('Got it', 'wordfence'); ?></a></div>
</div>
<div id="wf-tour-close"><a href="#" role="button"><i class="wf-fa wf-fa-times-circle" aria-hidden="true"></i></a></div>
</div>
</script>
<?php endif; ?>

View File

@@ -0,0 +1,430 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
$helpLink = wfSupportController::supportURL(wfSupportController::ITEM_TOOLS_TWO_FACTOR);
if (function_exists('network_admin_url') && is_multisite()) {
$lsModuleURL = network_admin_url('admin.php?page=WFLS');
}
else {
$lsModuleURL = admin_url('admin.php?page=WFLS');
}
echo wfView::create('common/section-title', array(
'title' => __('Two-Factor Authentication', 'wordfence'),
'helpLink' => $helpLink,
'helpLabelHTML' => wp_kses(__('Learn more<span class="wf-hidden-xs"> about Two-Factor Authentication</span>', 'wordfence'), array('span'=>array('class'=>array()))),
))->render();
?>
<script type="application/javascript">
(function($) {
$(function() {
document.title = "<?php esc_attr_e('Two-Factor Authentication', 'wordfence'); ?>" + " \u2039 " + WFAD.basePageName;
});
})(jQuery);
</script>
<div id="wordfenceMode_twoFactor"></div>
<div id="wf-tools-two-factor">
<?php if (wfCredentialsController::useLegacy2FA()): ?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div id="wordfenceTwoFactorLegacy">
<p><strong><?php esc_html_e('2FA Mode: Legacy', 'wordfence') ?>.</strong> <?php esc_html_e('Two-factor authentication is using legacy support, which enables SMS-based codes but is less compatible. An improved interface and use by non-administrators is available by activating the new login security module.', 'wordfence'); ?></p>
<p><a id="wf-migrate2fanew-start" class="wf-btn wf-btn-default wf-btn-sm wf-dismiss-link" href="#" role="button"><?php esc_html_e('Switch to New 2FA', 'wordfence'); ?></a></p>
</div>
</div>
</div>
<?php if (!wfConfig::get('isPaid')): ?>
<div class="wf-premium-callout wf-add-bottom">
<h3><?php esc_html_e("Take Login Security to the next level with Two-Factor Authentication", 'wordfence') ?></h3>
<p><?php echo wp_kses(__('Used by banks, government agencies, and military worldwide, two-factor authentication is one of the most secure forms of remote system authentication available. With it enabled, an attacker needs to know your username, password, <em>and</em> have control of your phone to log into your site. Upgrade to Premium now to enable this powerful feature.', 'wordfence'), array('em'=>array())) ?></p>
<p class="wf-nowrap">
<img id="wf-two-factor-img1" src="<?php echo wfUtils::getBaseURL() . 'images/2fa1.svg' ?>" alt="">
<img id="wf-two-factor-img2" src="<?php echo wfUtils::getBaseURL() . 'images/2fa2.svg' ?>" alt="">
</p>
<p class="center">
<a class="wf-btn wf-btn-primary wf-btn-callout" href="https://www.wordfence.com/gnl1twoFac1/wordfence-signup/" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Upgrade to Premium', 'wordfence') ?><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a>
</p>
</div>
<?php else: ?>
<div class="wf-row">
<div class="wf-col-xs-12 wf-flex-row">
<div class="wf-flex-row-1">
<p><?php echo wp_kses(__('With Two-Factor Authentication enabled, an attacker needs to know your username, password <em>and</em> have control of your phone to log in to your site. We recommend you enable Two-Factor Authentication for all Administrator level accounts.', 'wordfence'), array('em'=>array())) ?></p>
</div>
<div class="wf-flex-row-0 wf-padding-add-left">
<?php
echo wfView::create('options/block-controls', array(
'suppressLogo' => true,
'restoreDefaultsSection' => wfConfig::OPTIONS_TYPE_TWO_FACTOR,
'restoreDefaultsMessage' => __('Are you sure you want to restore the default Two-Factor Authentication settings? This will undo any custom changes you have made to the options on this page. If you have configured any users to use two-factor authentication, they will not be changed.', 'wordfence'),
))->render();
?>
</div>
</div>
</div>
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wf-block wf-active">
<?php if (!wfConfig::get('loginSecurityEnabled')): ?>
<ul class="wf-block-banner">
<li><?php echo wp_kses(__('<strong>Note:</strong> Two-Factor Authentication is disabled when the option "Enable Brute Force Protection" is off.', 'wordfence'), array('strong'=>array())); ?></li>
<li><a href="#" class="wf-btn wf-btn-default" id="wf-2fa-enable" role="button"><?php esc_html_e('Turn On', 'wordfence'); ?></a></li>
</ul>
<?php endif; ?>
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('Enable Two-Factor Authentication', 'wordfence') ?></strong>
</div>
</div>
</div>
<div class="wf-block-content">
<ul class="wf-block-list">
<li>
<ul class="wf-form-field">
<li style="width: 450px;" class="wf-option-text">
<input placeholder="<?php echo esc_attr(__('Enter username to enable Two-Factor Authentication for', 'wordfence')) ?>" type="text" id="wfUsername" class="wf-form-control" value="">
</li>
</ul>
</li>
<li>
<ul class="wf-form-field">
<li>
<input class="wf-option-radio" type="radio" name="wf2faMode" id="wf2faMode-authenticator" value="authenticator" checked>
<label for="wf2faMode-authenticator">&nbsp;&nbsp;</label>
</li>
<li class="wf-option-title"><?php esc_html_e('Use authenticator app', 'wordfence') ?></li>
</ul>
</li>
<li>
<ul class="wf-form-field">
<li>
<input class="wf-option-radio" type="radio" name="wf2faMode" id="wf2faMode-phone" value="phone">
<label for="wf2faMode-phone">&nbsp;&nbsp;</label>
</li>
<li class="wf-option-title"><?php esc_html_e('Send code to a phone number:', 'wordfence') ?>&nbsp;&nbsp;</li>
<li class="wf-option-text">
<input class="wf-form-control" type="text" value="" id="wfPhone" placeholder="<?php echo esc_attr(__('+1 (000) 000 0000', 'wordfence')) ?>">
</li>
</ul>
</li>
<li>
<p>
<input type="button" class="wf-btn wf-btn-primary pull-right" value="Enable User" onclick="WFAD.addTwoFactor(jQuery('#wfUsername').val(), jQuery('#wfPhone').val(), jQuery('input[name=wf2faMode]:checked').val());">
</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="wf-row">
<div class="wf-col-xs-12">
<h2><?php esc_html_e('Two-Factor Authentication Users', 'wordfence') ?></h2>
<div id="wfTwoFacUsers"></div>
</div>
</div>
<?php
echo wfView::create('tools/options-group-2fa', array(
'stateKey' => 'wf-2fa-options',
))->render();
?>
<script type="text/javascript">
jQuery('.twoFactorOption').on('click', function() {
WFAD.updateConfig(jQuery(this).attr('name'), jQuery(this).is(':checked') ? 1 : 0, function() {
});
});
jQuery('input[name=wf2faMode]').on('change', function() {
var selectedMode = jQuery('input[name=wf2faMode]:checked').val();
jQuery('#wfPhone').prop('disabled', selectedMode != 'phone');
}).triggerHandler('change');
(function($) {
$(function() {
$('#wf-2fa-enable').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
WFAD.setOption('loginSecurityEnabled', 1, function() {
window.location.reload(true);
});
});
});
})(jQuery);
</script>
<script type="text/x-jquery-template" id="wfTwoFacUserTmpl">
<table class="wf-striped-table wf-table-twofactor">
<thead>
<tr>
<th><?php esc_html_e('User', 'wordfence') ?></th>
<th><?php esc_html_e('Mode', 'wordfence') ?></th>
<th><?php esc_html_e('Status', 'wordfence') ?></th>
<th class="wf-center"><?php esc_html_e('Delete', 'wordfence') ?></th>
</tr>
</thead>
<tbody>
{{each(idx, user) users}}
<tr id="twoFactorUser-${user.userID}">
<td style="white-space: nowrap;">${user.username}</td>
{{if user.mode == 'phone'}}
<td style="white-space: nowrap;"><?php echo esc_html(sprintf(/* translators: Phone number. */ __('Phone (%s)', 'wordfence'), '${user.phone}')) ?></td>
{{else}}
<td style="white-space: nowrap;"><?php esc_html_e('Authenticator', 'wordfence') ?></td>
{{/if}}
<td style="white-space: nowrap;">
{{if user.status == 'activated'}}
<span style="color: #0A0;"><?php esc_html_e('Cellphone Sign-in Enabled', 'wordfence') ?></span>
{{else}}
<div class="wf-form-inline">
<div class="wf-form-group">
<label class="wf-plain wf-hidden-xs" style="margin: 0;" for="wfActivate-${user.userID}"><?php esc_html_e('Enter activation code:', 'wordfence') ?></label>
<input class="wf-form-control" type="text" id="wfActivate-${user.userID}" size="6" placeholder="<?php esc_attr_e('Code', 'wordfence') ?>">
</div>
<input class="wf-btn wf-btn-default" type="button" value="<?php esc_attr_e('Activate', 'wordfence') ?>" onclick="WFAD.twoFacActivate('${user.userID}', jQuery('#wfActivate-${user.userID}').val());">
</div>
{{/if}}
</td>
<td style="white-space: nowrap; text-align: center;" class="wf-twofactor-delete">
<a href="#" onclick="WFAD.delTwoFac('${user.userID}'); return false;" role="button"><i class="wf-ion-ios-trash-outline"></i></a>
</td>
</tr>
{{/each}}
{{if (users.length == 0)}}
<tr id="twoFactorUser-none">
<td colspan="4"><?php esc_html_e('No users currently have cellphone sign-in enabled.', 'wordfence') ?></td>
</tr>
{{/if}}
</tbody>
</table>
</script>
<?php endif; ?>
<?php else: ?>
<div class="wf-row">
<div class="wf-col-xs-12">
<div id="wordfenceTwoFactorModern">
<p><strong><?php esc_html_e('2FA Mode: Normal', 'wordfence') ?>.</strong> <?php esc_html_e('Legacy support for SMS-based two-factor authentication is being phased out, as it is less secure than using a modern authenticator app.', 'wordfence') ?></p>
<p><?php esc_html_e('If you have a conflict with the new 2FA method, you can temporarily switch back to the Legacy version.', 'wordfence'); ?></p>
<p><a id="wf-migrate2faold-start" class="wf-btn wf-btn-default wf-btn-sm wf-dismiss-link" href="#" role="button"><?php esc_html_e('Revert to Legacy 2FA', 'wordfence'); ?></a></p>
</div>
</div>
</div>
<?php endif; ?>
</div>
<script type="text/x-jquery-template" id="wfTmpl_migrate2FANew">
<?php
echo wfView::create('common/modal-prompt', array(
'title' => __('Migrate or switch to new two-factor authentication?', 'wordfence'),
'message' => __('Use the buttons below to migrate to the new two-factor authentication system or switch without migration. Migration will copy all existing authenticator-based user activations over to the new system while switching will use only users already set up in the new system. Existing SMS-based two-factor authentication activations must be disabled prior to migration.', 'wordfence'),
'primaryButton' => array('id' => 'wf-migrate2fanew-prompt-confirm', 'label' => __('Migrate', 'wordfence'), 'link' => '#'),
'secondaryButtons' => array(array('id' => 'wf-migrate2fanew-prompt-switch', 'label' => __('Switch', 'wordfence'), 'link' => '#'), array('id' => 'wf-migrate2fanew-prompt-cancel', 'label' => __('Cancel', 'wordfence'), 'link' => '#')),
'progressIndicator' => 'wf-migrate2fanew-progress',
))->render();
?>
</script>
<script type="text/x-jquery-template" id="wfTmpl_migrate2FANewComplete">
<?php
echo wfView::create('common/modal-prompt', array(
'title' => __('New Two-Factor Authentication Active', 'wordfence'),
'message' => __('Your site is now using the new login security module and two-factor authentication. Before logging out, we recommend testing your login in a different browser or a private/incognito window. If any plugins or your theme cause conflicts with logging in, you can revert to the old 2FA method.', 'wordfence'),
'primaryButton' => array('id' => 'wf-migrate2fanewcomplete-prompt-navigate', 'label' => __('Go To New 2FA', 'wordfence'), 'link' => $lsModuleURL),
'secondaryButtons' => array(array('id' => 'wf-migrate2fanewcomplete-prompt-close', 'label' => __('Close', 'wordfence'), 'link' => '#')),
))->render();
?>
</script>
<script type="text/x-jquery-template" id="wfTmpl_migrate2FASMSActive">
<?php
echo wfView::create('common/modal-prompt', array(
'title' => __('Migration Cannot Proceed', 'wordfence'),
'message' => __('One or more users with two-factor authentication active are using SMS, which is unsupported in the new login security module. Please either deactivate two-factor authentication for those users or change them to use an authenticator app prior to migration.', 'wordfence'),
'primaryButton' => array('id' => 'wf-migrate2fasmsactive-prompt-close', 'label' => __('Close', 'wordfence'), 'link' => '#'),
))->render();
?>
</script>
<script type="text/x-jquery-template" id="wfTmpl_migrate2FANewFail">
<?php
echo wfView::create('common/modal-prompt', array(
'title' => __('Migration Failed', 'wordfence'),
'message' => __('Automatic migration of the 2FA-enabled accounts failed. Please verify that your server is reachable via the internet and try again.', 'wordfence'),
'primaryButton' => array('id' => 'wf-migrate2fanewfail-prompt-close', 'label' => __('Close', 'wordfence'), 'link' => '#'),
))->render();
?>
</script>
<script type="text/x-jquery-template" id="wfTmpl_migrate2FAOld">
<?php
echo wfView::create('common/modal-prompt', array(
'title' => __('Revert back to legacy two-factor authentication?', 'wordfence'),
'message' => __('All two-factor authentication settings and users\' codes will revert to your older settings. If any users had set up two-factor authentication after the update, they will no longer have 2FA enabled until you switch to the new version again.', 'wordfence'),
'primaryButton' => array('id' => 'wf-migrate2faold-prompt-cancel', 'label' => __('Cancel', 'wordfence'), 'link' => '#'),
'secondaryButtons' => array(array('id' => 'wf-migrate2faold-prompt-switch', 'label' => __('Revert', 'wordfence'), 'link' => '#')),
'progressIndicator' => 'wf-migrate2faold-progress',
))->render();
?>
</script>
<script type="text/x-jquery-template" id="wfTmpl_migrate2FAOldComplete">
<?php
echo wfView::create('common/modal-prompt', array(
'title' => __('Legacy Two-Factor Authentication Active', 'wordfence'),
'message' => __('Your site is now using the legacy two-factor authentication system.', 'wordfence'),
'primaryButton' => array('id' => 'wf-migrate2faoldcomplete-prompt-close', 'label' => __('Close', 'wordfence'), 'link' => '#'),
))->render();
?>
</script>
<script type="application/javascript">
(function($) {
$(function() {
$('#wf-migrate2fanew-start').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var prompt = $('#wfTmpl_migrate2FANew').tmpl();
var promptHTML = $("<div />").append(prompt).html();
WFAD.colorboxHTML((WFAD.isSmallScreen ? '300px' : '500px'), promptHTML, {overlayClose: false, closeButton: false, className: 'wf-modal', onComplete: function() {
$('#wf-migrate2fanew-prompt-cancel').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
WFAD.colorboxClose();
});
$('#wf-migrate2fanew-prompt-switch').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
$('#wf-migrate2fanew-progress').show();
$('#wf-migrate2fanew-prompt-cancel, #wf-migrate2fanew-prompt-confirm').addClass('wf-disabled');
WFAD.ajax('wordfence_switchTo2FANew', {migrate: false}, function(res) {
var prompt = $('#wfTmpl_migrate2FANewComplete').tmpl();
var promptHTML = $("<div />").append(prompt).html();
WFAD.colorboxClose();
setTimeout(function() {
WFAD.colorboxHTML((WFAD.isSmallScreen ? '300px' : '500px'), promptHTML, {overlayClose: false, closeButton: false, className: 'wf-modal', onComplete: function() {
$('#wf-migrate2fanewcomplete-prompt-close').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
window.location.reload();
WFAD.colorboxClose();
});
}});
}, 500);
});
});
$('#wf-migrate2fanew-prompt-confirm').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
$('#wf-migrate2fanew-progress').show();
$('#wf-migrate2fanew-prompt-cancel, #wf-migrate2fanew-prompt-confirm').addClass('wf-disabled');
WFAD.ajax('wordfence_switchTo2FANew', {migrate: true}, function(res) {
if (res.ok) {
var prompt = $('#wfTmpl_migrate2FANewComplete').tmpl(res);
var promptHTML = $("<div />").append(prompt).html();
WFAD.colorboxClose();
setTimeout(function() {
WFAD.colorboxHTML((WFAD.isSmallScreen ? '300px' : '500px'), promptHTML, {overlayClose: false, closeButton: false, className: 'wf-modal', onComplete: function() {
$('#wf-migrate2fanewcomplete-prompt-close').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
WFAD.colorboxClose();
});
}});
}, 500);
}
else if (res.smsActive) {
var prompt = $('#wfTmpl_migrate2FASMSActive').tmpl();
var promptHTML = $("<div />").append(prompt).html();
WFAD.colorboxClose();
setTimeout(function() {
WFAD.colorboxHTML((WFAD.isSmallScreen ? '300px' : '500px'), promptHTML, {overlayClose: false, closeButton: false, className: 'wf-modal', onComplete: function() {
$('#wf-migrate2fasmsactive-prompt-close').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
WFAD.colorboxClose();
});
}});
}, 500);
}
else {
var prompt = $('#wfTmpl_migrate2FANewFail').tmpl();
var promptHTML = $("<div />").append(prompt).html();
WFAD.colorboxClose();
setTimeout(function() {
WFAD.colorboxHTML((WFAD.isSmallScreen ? '300px' : '500px'), promptHTML, {overlayClose: false, closeButton: false, className: 'wf-modal', onComplete: function() {
$('#wf-migrate2fanewfail-prompt-close').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
WFAD.colorboxClose();
});
}});
}, 500);
}
});
});
}});
});
$('#wf-migrate2faold-start').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var prompt = $('#wfTmpl_migrate2FAOld').tmpl();
var promptHTML = $("<div />").append(prompt).html();
WFAD.colorboxHTML((WFAD.isSmallScreen ? '300px' : '500px'), promptHTML, {overlayClose: false, closeButton: false, className: 'wf-modal', onComplete: function() {
$('#wf-migrate2faold-prompt-cancel').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
WFAD.colorboxClose();
});
$('#wf-migrate2faold-prompt-switch').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
$('#wf-migrate2faold-progress').show();
$('#wf-migrate2faold-prompt-cancel, #wf-migrate2faold-prompt-switch').addClass('wf-disabled');
WFAD.ajax('wordfence_switchTo2FAOld', {migrate: false}, function(res) {
var prompt = $('#wfTmpl_migrate2FAOldComplete').tmpl();
var promptHTML = $("<div />").append(prompt).html();
WFAD.colorboxClose();
setTimeout(function() {
WFAD.colorboxHTML((WFAD.isSmallScreen ? '300px' : '500px'), promptHTML, {overlayClose: false, closeButton: false, className: 'wf-modal', onComplete: function() {
$('#wf-migrate2faoldcomplete-prompt-close').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
window.location.reload();
WFAD.colorboxClose();
});
}});
}, 500);
});
});
}});
});
});
})(jQuery);
</script>

View File

@@ -0,0 +1,115 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
?>
<script type="application/javascript">
(function($) {
$(function() {
document.title = "<?php esc_attr_e('Whois Lookup', 'wordfence'); ?>" + " \u2039 " + WFAD.basePageName;
});
})(jQuery);
</script>
<div class="wordfenceModeElem" id="wordfenceMode_whois"></div>
<div id="wf-tools-whois">
<div class="wf-section-title">
<h2><?php esc_html_e('Whois Lookup', 'wordfence') ?></h2>
<span><?php echo wp_kses(sprintf(
/* translators: URL to support page. */
__('<a href="%s" target="_blank" rel="noopener noreferrer" class="wf-help-link">Learn more<span class="wf-hidden-xs"> about Whois Lookup</span><span class="screen-reader-text"> (opens in new tab)</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_TOOLS_WHOIS_LOOKUP)), array('a'=>array('href'=>array(), 'target'=>array(), 'rel'=>array(), 'class'=>array()), 'span'=>array('class'=>array()))); ?>
<i class="wf-fa wf-fa-external-link" aria-hidden="true"></i></span>
</div>
<p><?php esc_html_e("The whois service gives you a way to look up who owns an IP address or domain name that is visiting your website or is engaging in malicious activity on your website.", 'wordfence') ?></p>
<div>
<div class="wf-form wf-flex-row">
<div class="wf-flex-row-1">
<input type="text" class="wf-form-control" name="whois" id="wfwhois" value="" maxlength="255" onkeydown="if(event.keyCode == 13){ whois(jQuery('#wfwhois').val()) }"/>
</div>
<div class="wf-flex-row-0 wf-padding-add-left">
<input type="button" name="whoisbutton" id="whoisbutton" class="wf-btn wf-btn-primary" value="Look up IP or Domain" onclick="whois(jQuery('#wfwhois').val());">
</div>
</div>
<?php if (isset($_GET['wfnetworkblock']) && $_GET['wfnetworkblock']) { ?>
<h2><?php esc_html_e('How to block a network', 'wordfence') ?></h2>
<p style="width: 600px;">
<?php echo wp_kses(sprintf(
/* translators: Hostname or IP address. */
__("You've chosen to block the network that <span style=\"color: #F00;\">%s</span> is part of. We've marked the networks we found that this IP address belongs to in red below. Make sure you read all the WHOIS information so that you see all networks this IP belongs to. We recommend blocking the network with the lowest number of addresses. You may find this is listed at the end as part of the 'rWHOIS' query which contacts the local WHOIS server that is run by the network administrator.", 'wordfence'), esc_html($_GET['whoisval'])), array('span'=>array('style'=>array()))); ?>
</p>
<?php } ?>
<div id="wfrawhtml" class="wf-padding-add-top"></div>
</div>
<script type="text/x-jquery-template" id="wfBlockedRangesTmpl">
<div>
<div style="border-bottom: 1px solid #CCC; padding-bottom: 10px; margin-bottom: 10px;">
<table border="0" style="width: 100%">
{{each(idx, elem) results}}
<tr>
<td></td>
</tr>
{{/each}}
</table>
</div>
</div>
</script>
<script type="text/javascript">
var whoisval = "<?php if (isset($_GET['whoisval'])) {
echo esc_js($_GET['whoisval']);
} ?>";
if (whoisval) {
jQuery(function() {
jQuery('#wfwhois').val(whoisval);
whois(whoisval);
});
}
</script>
<script type="text/x-jquery-template" id="wfWhoisBlock">
<div class="wf-block wf-active">
<div class="wf-block-header">
<div class="wf-block-header-content">
<div class="wf-block-title">
<strong><?php esc_html_e('Whois Lookup', 'wordfence') ?> <a>${ip}</a></strong>
</div>
</div>
</div>
<div class="wf-block-content wf-clearfix">
<ul class="wf-block-list">
<li>
<div class="wf-padding-add-top">{{html whois}}</div>
</li>
</ul>
</div>
</div>
</script>
</div>
<script type="text/javascript">
function whois(ip) {
var val = ip.replace(' ', '');
if (!/\w+/.test(val)) {
WFAD.colorboxModal('300px', <?php echo json_encode(__("Enter a valid IP or domain", 'wordfence')) ?>, <?php echo json_encode(__("Please enter a valid IP address or domain name for your whois lookup.", 'wordfence')) ?>);
return;
}
var whoisButton = jQuery('#whoisbutton').attr('disabled', 'disabled')
.attr('value', <?php echo json_encode(__('Loading...', 'wordfence')) ?>);
WFAD.ajax('wordfence_whois', {
val: val
}, function(res) {
whoisButton.removeAttr('disabled')
.attr('value', <?php echo json_encode(__('Look up IP or Domain', 'wordfence')) ?>);
var whoisHTML = WFAD.completeWhois(res, true);
var content = jQuery('#wfWhoisBlock').tmpl({
ip: val,
whois: whoisHTML
});
if (!res.ok)
content.addClass('failed');
jQuery('#wfrawhtml').html(content);
});
}
</script>

View File

@@ -0,0 +1,252 @@
<?php
if (!defined('WORDFENCE_VERSION')) {
exit;
}
/**
* @var string $subpage
*/
$stepContent = array(
1 => __('Testing initial communication with Wordfence Central.', 'wordfence'),
2 => __('Passing public key to Wordfence Central.', 'wordfence'),
3 => __('Testing public key authentication with Wordfence Central.', 'wordfence'),
4 => __('Testing that Wordfence Central is able to communicate with this site.', 'wordfence'),
5 => __('Retrieving access token using authorization grant.', 'wordfence'),
6 => __('Redirecting back to Wordfence Central.', 'wordfence'),
);
$connected = wfCentral::isConnected();
$partialConnection = wfCentral::isPartialConnection();
?>
<?php
if (!wfOnboardingController::shouldShowAttempt3() && wfConfig::get('touppPromptNeeded')) {
echo wfView::create('gdpr/disabled-overlay')->render();
echo wfView::create('gdpr/banner')->render();
}
if (function_exists('network_admin_url') && is_multisite()) {
$wordfenceURL = network_admin_url('admin.php?page=Wordfence');
}
else {
$wordfenceURL = admin_url('admin.php?page=Wordfence');
}
?>
<div class="wrap wordfence">
<div class="wf-container-fluid">
<div class="wf-row">
<div class="wf-col-xs-12">
<div class="wp-header-end"></div>
<?php
echo wfView::create('common/section-title', array(
'title' => __('Wordfence Central', 'wordfence'),
'showIcon' => true,
))->render();
?>
</div>
<?php if ($connected): ?>
<div class="wf-col-xs-12 wf-central-connected">
<div class="wf-flex-row wf-flex-grow-all">
<div class="wf-flex-row-1 wf-block wf-active">
<div class="wf-central-dashboard">
<img class="wf-central-dashboard-logo" src="<?php echo wfUtils::getBaseURL() ?>images/wf-central-logo.svg" alt="Wordfence Central">
<div class="wf-central-dashboard-copy">
<p><strong><?php esc_html_e('Wordfence Central', 'wordfence') ?></strong></p>
<p><?php esc_html_e('Wordfence Central allows you to manage Wordfence on multiple sites from one location. It makes security monitoring and configuring Wordfence easier.', 'wordfence') ?></p>
<p class="wf-right-lg"><a href="https://www.wordfence.com/central" target="_blank" rel="noopener noreferrer"><strong><?php esc_html_e('Visit Wordfence Central', 'wordfence') ?></strong><span class="screen-reader-text"> (<?php esc_html_e('opens in new tab', 'wordfence') ?>)</span></a></p>
</div>
</div>
</div>
<div class="wf-flex-row-1 wf-block wf-active">
<p><strong><?php esc_html_e('Wordfence Central Status', 'wordfence') ?></strong></p>
<p><?php echo esc_html(sprintf(
/* translators: 1. Email address. 2. Localized date. */
__('Activated - connected by %1$s on %2$s', 'wordfence'), wfConfig::get('wordfenceCentralConnectEmail'), date_i18n('F j, Y', (int) wfConfig::get('wordfenceCentralConnectTime')))) ?></p>
<p class="wf-right-lg"><a href="<?php echo esc_url($wordfenceURL); ?>"><strong><?php esc_html_e('Disconnect This Site', 'wordfence') ?></strong></a></p>
</div>
</div>
</div>
<?php elseif (isset($_GET['grant'])): ?>
<div class="wf-col-xs-12">
<div class="wf-block wf-active">
<div class="wf-block-header">
<div class="wf-block-header-content">
<strong><?php esc_html_e('Wordfence Central Installation Process', 'wordfence') ?></strong>
</div>
</div>
<div class="wf-block-content">
<ul class="wf-block-list" id="wf-central-progress">
<?php for ($i = 1; $i <= 6; $i++): ?>
<li id="wf-central-progress-step<?php echo $i ?>" class="pending">
<div class="wf-central-progress-icon">
<div class="wf-step-pending"></div>
<div class="wf-step-running">
<?php
echo wfView::create('common/indeterminate-progress', array(
'size' => 50,
))->render();
?>
</div>
<div class="wf-step-complete-success"></div>
<div class="wf-step-complete-warning"></div>
</div>
<div class="wf-central-progress-content">
<p><?php echo esc_html($stepContent[$i]) ?></p>
</div>
</li>
<?php endfor ?>
</ul>
</div>
</div>
</div>
<?php elseif ($partialConnection): ?>
<div class="wf-center-lg">
<p><?php esc_html_e('It looks like you\'ve tried to connect this site to Wordfence Central, but the installation did not finish.', 'wordfence') ?></p>
<p>
<a href="<?php echo WORDFENCE_CENTRAL_URL_SEC ?>/sites/connection-issues?complete-setup=<?php echo esc_attr(wfConfig::get('wordfenceCentralSiteID')) ?>"
class="wf-btn wf-btn-primary"
><?php esc_html_e('Resume Installation', 'wordfence') ?></a>
<a href="<?php echo esc_url($wordfenceURL); ?>" class="wf-btn wf-btn-warning"><?php esc_html_e('Disconnect Site', 'wordfence') ?></a>
</p>
</div>
<?php else: ?>
<div class="wf-center-lg">
<p><?php esc_html_e('Wordfence Central allows you to manage Wordfence on multiple sites from one location. It makes security monitoring and configuring Wordfence easier.', 'wordfence') ?></p>
<p><?php esc_html_e('To connect your site your site to Wordfence Central, use the link below:', 'wordfence') ?></p>
<p class="wf-center">
<a href="<?php echo WORDFENCE_CENTRAL_URL_SEC ?>?newsite=<?php echo esc_attr(home_url()) ?>" class="wf-btn wf-btn-primary"><?php esc_html_e('Connect Site', 'wordfence') ?></a>
</p>
</div>
<?php endif ?>
</div>
</div>
</div>
<script>
(function($) {
var authGrant = '<?php echo esc_js(isset($_GET['grant']) ? $_GET['grant'] : '') ?>';
var currentStep = <?php echo json_encode(wfConfig::getInt('wordfenceCentralCurrentStep', 1)) ?>;
var connected = <?php echo json_encode($connected) ?>;
function wfConnectError(error) {
WFAD.colorboxError(error);
}
function wfCentralStepAjax(step, action, data, cb, cbErr, noLoading) {
var el = $('#wf-central-progress-' + step);
el.removeClass('pending')
.addClass('running');
WFAD.ajax(action, data, function(response) {
if (response && response.success) {
el.removeClass('running')
.addClass('complete-success');
cb && cb(response);
} else if (response && response.err) {
el.removeClass('running')
.addClass('complete-warning');
}
}, function(response) {
el.removeClass('running')
.addClass('complete-warning');
cbErr && cbErr(response);
}, noLoading);
}
var WFCentralInstaller = {};
window.WFCentralInstaller = WFCentralInstaller;
// Step 1: Makes GET request to `/central/api/site/access-token` endpoint authenticated with the auth grant supplied by the user.
// - Receives site GUID, public key, short lived JWT.
WFCentralInstaller.step1 = function() {
wfCentralStepAjax('step1', 'wordfence_wfcentral_step1', {
'auth-grant': authGrant
}, function(response) {
$(window).trigger('step2', response);
}, wfConnectError);
};
// Step 2: Makes PATCH request to `/central/api/wf/site/<guid>` endpoint passing in the new public key.
// Uses JWT from auth grant endpoint as auth.
WFCentralInstaller.step2 = function() {
wfCentralStepAjax('step2', 'wordfence_wfcentral_step2', {}, function(response) {
$(window).trigger('step3', response);
}, wfConnectError);
};
$(window).on('step2', WFCentralInstaller.step2);
// Step 3: Makes GET request to `/central/api/wf/site/<guid>` endpoint signed using Wordfence plugin private key.
// - Expects 200 response with site data.
WFCentralInstaller.step3 = function() {
wfCentralStepAjax('step3', 'wordfence_wfcentral_step3', {}, function(response) {
var callback = function() {
$(window).trigger('step4')
};
var interval = setInterval(callback, 4000);
$(window).on('step3-clearInterval', function() {
clearInterval(interval);
});
callback();
}, wfConnectError);
};
$(window).on('step3', WFCentralInstaller.step3);
// Step 4: Poll for PUT request at `/wp-json/wp/v2/wordfence-auth-grant/` endpoint signed using Wordfence Central private key with short lived JWT.
// - Expects verifiable signature of incoming request from Wordfence Central.
// - Stores auth grant JWT.
WFCentralInstaller.step4 = function() {
wfCentralStepAjax('step4', 'wordfence_wfcentral_step4', {}, function(response) {
if (response && response.success) {
$(window).trigger('step3-clearInterval');
$(window).trigger('step5');
}
}, wfConnectError);
};
$(window).on('step4', WFCentralInstaller.step4);
// Step 5: Makes GET request to `/central/api/site/<guid>/access-token` endpoint signed using Wordfence plugin private key with auth grant JWT.
// - Expects 200 response with access token.
WFCentralInstaller.step5 = function() {
wfCentralStepAjax('step5', 'wordfence_wfcentral_step5', {
'auth-grant': authGrant
}, function(response) {
$(window).trigger('step6', response);
}, wfConnectError);
};
$(window).on('step5', WFCentralInstaller.step5);
// Step 6: Installation complete. Redirect user back to Wordfence Central with access token.
WFCentralInstaller.step6 = function(response) {
wfCentralStepAjax('step6', 'wordfence_wfcentral_step6', {}, function(response) {
document.location.href = response['redirect-url'];
}, wfConnectError);
};
$(window).on('step6', WFCentralInstaller.step6);
var self = this;
$(function() {
// if (!authGrant) {
// wfConnectError('Auth grant not found.');
// return;
// }
if (!connected && authGrant) {
for (var i = 0; i < currentStep; i++) {
var el = $('#wf-central-progress-step' + i);
el.removeClass('pending')
.addClass('complete-success');
}
WFCentralInstaller['step' + currentStep]();
}
});
})(jQuery);
</script>

View File

@@ -0,0 +1,28 @@
-----BEGIN CERTIFICATE-----
MIIErTCCAxWgAwIBAgIJAOj4d3hU6MEPMA0GCSqGSIb3DQEBCwUAMG0xCzAJBgNV
BAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMRIw
EAYDVQQKDAlXb3JkZmVuY2UxCzAJBgNVBAsMAklUMRYwFAYDVQQDDA13b3JkZmVu
Y2UuY29tMB4XDTE5MDEwOTE5MDQzMloXDTM5MDEwNDE5MDQzMlowbTELMAkGA1UE
BhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxEjAQ
BgNVBAoMCVdvcmRmZW5jZTELMAkGA1UECwwCSVQxFjAUBgNVBAMMDXdvcmRmZW5j
ZS5jb20wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDBkaEjT0/Gmxi7
tl7qaX2/TiHXdP4SgqQepP/gIgKTdj71oBZzVvZPztlStQEUO1u0m6eZT3BHQPV7
inzsjz5SpCjChjH6se/DwnAJNaU7c2WUWhVATvwSX0gwDYCCbcS2IG0KUllvtWh9
8JOGG46X/51vxwR3wiJoVvziZJIs8A4n9/qYBWxL7IKAl//EGwm4SacrUVJNxAXo
h3MaIJ5TlEi1xO8NQ/mUzFOJcKhNq94wcco1sffDoe4ctWxydhlpS5GCW/uGveOX
ZLpwiOXVaG1HQx2YoI3Y9RK8y9eXM3IbdKwKSbV7l0TEQBuh20PLk/8DNG4Ba3Gg
yFEMzPjQnyp5OzohLdm4WphRHiA631UcX7ZSrDDfET7a+YsYX2EDcnZRmO/KLkuk
+yXYXRF/1bfuR5sI8l9nPakKXRlG6KbPHKdP//J0ZKVAJyZOhEXfB+X3zFyowUyh
2hjgSZuwS9DYAidNXq/hSMQLALEnwB9YFdxpxSs3sWdbKkDQGHMCAwEAAaNQME4w
HQYDVR0OBBYEFNHk65/wXrYwxPt2wapRH9XU4rRjMB8GA1UdIwQYMBaAFNHk65/w
XrYwxPt2wapRH9XU4rRjMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggGB
AGU/5CxUCxFrVY9qoTRwsx24Prphu8H9Y/je7G+HoZJPj70Qv+8EuzxTmsAeNgG4
xcLIO1WWgAgsvb6XilEaYGO5GOCHctIMjnbauegcmkM4NMTNfzStu+v1mjV/cw/9
bzEM9Rr1Jc+mQXq8K6zXTaBXo7GU+WqTAadHhbUCWD5afQ9Kq8OCKaM4NBf2guQl
PU2HQts8reYn7VeqWz063RLuRAAwf59vZbi3foqTBYSiDHjAykDe4LsvUWtS1y7t
Dxyz+YSATCxpnkDWEoad+kKZ1qpgqiewp/tLnDR1LOIDmWu9KongslEHUAmAN/T1
otTWmQOeg/cnT1W/yqapxzpOmvLb28f9shMbGvmQpvle/JNVeoQyM3NF7t1rCbGT
aqCI9kjWOoLd7t4svtGyR6IOKUbXqT5U9q1bMXIWH+ty8KmxzsvEBHXmYF6+jYr+
tWlXyhcN+OyPcBDHaNlFtQi+eKzjTUhSVvxJaKo3R6q4j8SVR613aa4AxunY2jdi
zQ==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,183 @@
<?php
class wfRESTAuthenticationController {
const NONCE_AGE = 600;
public static function generateNonce($tickOffset = 0) {
add_filter('nonce_life', 'wfRESTAuthenticationController::nonceAge');
$i = wp_nonce_tick();
$salt = wp_salt('nonce');
$nonce = hash_hmac('sha256', ($i + $tickOffset) . '|wordfence-rest-api-auth', $salt);
remove_filter('nonce_life', 'wfRESTAuthenticationController::nonceAge');
return $nonce;
}
public static function generateToken() {
return new wfJWT(wfConfig::get('wordfenceCentralSiteID'));
}
public static function nonceAge() {
return self::NONCE_AGE;
}
public function registerRoutes() {
register_rest_route('wordfence/v1', '/authenticate', array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'nonce'),
'permission_callback' => '__return_true',
));
register_rest_route('wordfence/v1', '/authenticate', array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array($this, 'authenticate'),
'permission_callback' => '__return_true',
));
register_rest_route('wordfence/v1', '/authenticate-premium', array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array($this, 'authenticatePremium'),
'permission_callback' => '__return_true',
));
}
/**
* @param WP_REST_Request $request
* @return mixed|WP_REST_Response
*/
public function nonce($request) {
$response = rest_ensure_response(array(
'nonce' => self::generateNonce(),
'admin_url' => network_admin_url(),
));
return $response;
}
/**
* @param WP_REST_Request $request
* @return mixed|WP_REST_Response
*/
public function authenticate($request) {
require_once(WORDFENCE_PATH . '/lib/sodium_compat_fast.php');
$siteID = wfConfig::get('wordfenceCentralSiteID');
if (!$siteID) {
return new WP_Error('rest_forbidden_context',
__('Site is not connected to Wordfence Central.', 'wordfence'),
array('status' => rest_authorization_required_code()));
}
// verify signature.
$data = $request->get_param('data');
$dataChunks = explode('|', $data, 2);
if (count($dataChunks) !== 2) {
return new WP_Error('rest_forbidden_context',
__('Data is invalid.', 'wordfence'),
array('status' => rest_authorization_required_code()));
}
if (!preg_match('/[0-9a-f]{64}/i', $dataChunks[0])) {
return new WP_Error('rest_forbidden_context',
__('Nonce format is invalid.', 'wordfence'),
array('status' => rest_authorization_required_code()));
}
if (!preg_match('/[0-9a-f\-]{36}/i', $dataChunks[1])) {
return new WP_Error('rest_forbidden_context',
__('Site ID is invalid.', 'wordfence'),
array('status' => rest_authorization_required_code()));
}
if (!hash_equals($siteID, $dataChunks[1])) {
return new WP_Error('rest_forbidden_context',
__('Site ID is invalid.', 'wordfence'),
array('status' => rest_authorization_required_code()));
}
$signature = $request->get_param('signature');
$nonce1 = self::generateNonce();
$nonce2 = self::generateNonce(-1);
$verfiedNonce = hash_equals($nonce1, $dataChunks[0]) || hash_equals($nonce2, $dataChunks[0]);
if (!$verfiedNonce) {
return new WP_Error('rest_forbidden_context',
__('Nonce is invalid.', 'wordfence'),
array('status' => rest_authorization_required_code()));
}
$signature = pack('H*', $signature);
if (!ParagonIE_Sodium_Compat::crypto_sign_verify_detached($signature, $data, wfConfig::get('wordfenceCentralPK'))) {
return new WP_Error('rest_forbidden_context',
__('Signature is invalid.', 'wordfence'),
array('status' => rest_authorization_required_code()));
}
$response = rest_ensure_response(array(
'token' => (string) self::generateToken(),
));
return $response;
}
/**
* @param WP_REST_Request $request
* @return mixed|WP_REST_Response
*/
public function authenticatePremium($request) {
require_once(WORDFENCE_PATH . '/lib/sodium_compat_fast.php');
// verify signature.
$data = $request->get_param('data');
$dataChunks = explode('|', $data, 2);
if (count($dataChunks) !== 2) {
return new WP_Error('rest_forbidden_context',
__('Data is invalid.', 'wordfence'),
array('status' => rest_authorization_required_code()));
}
if (!preg_match('/[0-9a-f]{64}/i', $dataChunks[0])) {
return new WP_Error('rest_forbidden_context',
__('Nonce format is invalid.', 'wordfence'),
array('status' => rest_authorization_required_code()));
}
if (!is_email($dataChunks[1])) {
return new WP_Error('rest_forbidden_context',
__('Email address is invalid.', 'wordfence'),
array('status' => rest_authorization_required_code()));
}
$adminEmail = $dataChunks[1];
$signature = $request->get_param('signature');
$nonce1 = self::generateNonce();
$nonce2 = self::generateNonce(-1);
$verfiedNonce = hash_equals($nonce1, $dataChunks[0]) || hash_equals($nonce2, $dataChunks[0]);
if (!$verfiedNonce) {
return new WP_Error('rest_forbidden_context',
__('Nonce is invalid.', 'wordfence'),
array('status' => rest_authorization_required_code()));
}
$signature = pack('H*', $signature);
if (!ParagonIE_Sodium_Compat::crypto_sign_verify_detached($signature, $data, WORDFENCE_CENTRAL_PUBLIC_KEY)) {
return new WP_Error('rest_forbidden_context',
__('Signature is invalid.', 'wordfence'),
array('status' => rest_authorization_required_code()));
}
$user_query = new WP_User_Query(array(
'role' => 'administrator',
'search' => $adminEmail,
'search_columns' => array('user_email')
));
$users = $user_query->get_results();
if (is_array($users) && count($users) === 1) {
$jwt = new wfJWT('wordfence-central-premium');
$jwt->addClaims(array('email' => $adminEmail));
$response = rest_ensure_response(array(
'token' => (string) $jwt,
));
return $response;
}
return new WP_Error('rest_forbidden_context',
__('Admin user with this email address not found.', 'wordfence'),
array('status' => rest_authorization_required_code()));
}
}

View File

@@ -0,0 +1,87 @@
<?php
abstract class wfRESTBaseController {
protected $tokenData;
/**
* @param WP_REST_Request $request
* @return WP_Error|bool
*/
public function verifyToken($request) {
$validToken = $this->isTokenValid($request);
if ($validToken &&
!is_wp_error($validToken) &&
$this->tokenData['body']['sub'] === wfConfig::get('wordfenceCentralSiteID')
) {
return true;
}
if (is_wp_error($validToken)) {
return $validToken;
}
return new WP_Error('rest_forbidden_context',
__('Token is invalid.', 'wordfence'),
array('status' => rest_authorization_required_code()));
}
/**
* @param WP_REST_Request $request
* @return WP_Error|bool
*/
public function verifyTokenPremium($request) {
$validToken = $this->isTokenValid($request);
if ($validToken &&
!is_wp_error($validToken) &&
$this->tokenData['body']['sub'] === 'wordfence-central-premium'
) {
return true;
}
if (is_wp_error($validToken)) {
return $validToken;
}
return new WP_Error('rest_forbidden_context',
__('Token is invalid.', 'wordfence'),
array('status' => rest_authorization_required_code()));
}
/**
* @param WP_REST_Request $request
* @return bool|WP_Error
*/
public function isTokenValid($request) {
$authHeader = $request->get_header('Authorization');
if (!$authHeader) {
$authHeader = $request->get_header('X-Authorization');
}
if (stripos($authHeader, 'bearer ') !== 0) {
return new WP_Error('rest_forbidden_context',
__('Authorization header format is invalid.', 'wordfence'),
array('status' => rest_authorization_required_code()));
}
$token = trim(substr($authHeader, 7));
$jwt = new wfJWT();
try {
$this->tokenData = $jwt->decode($token);
} catch (wfJWTException $e) {
return new WP_Error('rest_forbidden_context',
$e->getMessage(),
array('status' => rest_authorization_required_code()));
} catch (Exception $e) {
return new WP_Error('rest_forbidden_context',
__('Token is invalid.', 'wordfence'),
array('status' => rest_authorization_required_code()));
}
return true;
}
}

View File

@@ -0,0 +1,341 @@
<?php
use WordfenceLS\Controller_Settings;
require_once(dirname(__FILE__) . '/wfRESTBaseController.php');
class wfRESTConfigController extends wfRESTBaseController {
public static function disconnectConfig($adminEmail = null) {
global $wpdb;
delete_transient('wordfenceCentralJWT' . wfConfig::get('wordfenceCentralSiteID'));
if (is_null($adminEmail)) {
$adminEmail = wfConfig::get('wordfenceCentralConnectEmail');
}
$result = $wpdb->query('DELETE FROM ' . wfDB::networkTable('wfConfig') . " WHERE name LIKE 'wordfenceCentral%'");
wfConfig::set('wordfenceCentralDisconnected', true);
wfConfig::set('wordfenceCentralDisconnectTime', time());
wfConfig::set('wordfenceCentralDisconnectEmail', $adminEmail);
wfConfig::set('wordfenceCentralConfigurationIssue', false);
return !!$result;
}
public function registerRoutes() {
register_rest_route('wordfence/v1', '/config', array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'getConfig'),
'permission_callback' => array($this, 'verifyToken'),
'fields' => array(
'description' => __('Specific config options to return.', 'wordfence'),
'type' => 'array',
'required' => false,
),
));
register_rest_route('wordfence/v1', '/config', array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array($this, 'setConfig'),
'permission_callback' => array($this, 'verifyToken'),
'fields' => array(
'description' => __('Specific config options to set.', 'wordfence'),
'type' => 'array',
'required' => true,
),
));
register_rest_route('wordfence/v1', '/disconnect', array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array($this, 'disconnect'),
'permission_callback' => array($this, 'verifyToken'),
));
register_rest_route('wordfence/v1', '/premium-connect', array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array($this, 'premiumConnect'),
'permission_callback' => array($this, 'verifyTokenPremium'),
));
}
/**
* @param WP_REST_Request $request
* @return mixed|WP_REST_Response
*/
public function getConfig($request) {
$fields = (array) $request['fields'];
$config = array();
$firewall = new wfFirewall();
$wafFields = array(
'autoPrepend' => $firewall->protectionMode() === wfFirewall::PROTECTION_MODE_EXTENDED,
'avoid_php_input' => wfWAF::getInstance()->getStorageEngine()->getConfig('avoid_php_input', false) ? 1 : 0,
'disabledRules' => array_keys((array) wfWAF::getInstance()->getStorageEngine()->getConfig('disabledRules')),
'ruleCount' => count((array) wfWAF::getInstance()->getRules()),
'disableWAFBlacklistBlocking' => wfWAF::getInstance()->getStorageEngine()->getConfig('disableWAFBlacklistBlocking'),
'enabled' => $firewall->wafStatus() !== wfFirewall::FIREWALL_MODE_DISABLED,
'firewallMode' => $firewall->firewallMode(),
'learningModeGracePeriod' => wfWAF::getInstance()->getStorageEngine()->getConfig('learningModeGracePeriod'),
'learningModeGracePeriodEnabled' => wfWAF::getInstance()->getStorageEngine()->getConfig('learningModeGracePeriodEnabled'),
'subdirectoryInstall' => $firewall->isSubDirectoryInstallation(),
'wafStatus' => $firewall->wafStatus(),
);
$lsFields = array(
Controller_Settings::OPTION_XMLRPC_ENABLED => Controller_Settings::shared()->get(Controller_Settings::OPTION_XMLRPC_ENABLED),
Controller_Settings::OPTION_2FA_WHITELISTED => Controller_Settings::shared()->get(Controller_Settings::OPTION_2FA_WHITELISTED),
Controller_Settings::OPTION_IP_SOURCE => Controller_Settings::shared()->get(Controller_Settings::OPTION_IP_SOURCE),
Controller_Settings::OPTION_IP_TRUSTED_PROXIES => Controller_Settings::shared()->get(Controller_Settings::OPTION_IP_TRUSTED_PROXIES),
Controller_Settings::OPTION_REQUIRE_2FA_ADMIN => Controller_Settings::shared()->get(Controller_Settings::OPTION_REQUIRE_2FA_ADMIN),
Controller_Settings::OPTION_REQUIRE_2FA_GRACE_PERIOD_ENABLED => Controller_Settings::shared()->get(Controller_Settings::OPTION_REQUIRE_2FA_GRACE_PERIOD_ENABLED),
Controller_Settings::OPTION_GLOBAL_NOTICES => Controller_Settings::shared()->get(Controller_Settings::OPTION_GLOBAL_NOTICES),
Controller_Settings::OPTION_REMEMBER_DEVICE_ENABLED => Controller_Settings::shared()->get(Controller_Settings::OPTION_REMEMBER_DEVICE_ENABLED),
Controller_Settings::OPTION_REMEMBER_DEVICE_DURATION => Controller_Settings::shared()->get(Controller_Settings::OPTION_REMEMBER_DEVICE_DURATION),
Controller_Settings::OPTION_ALLOW_XML_RPC => Controller_Settings::shared()->get(Controller_Settings::OPTION_ALLOW_XML_RPC),
Controller_Settings::OPTION_ENABLE_AUTH_CAPTCHA => Controller_Settings::shared()->get(Controller_Settings::OPTION_ENABLE_AUTH_CAPTCHA),
Controller_Settings::OPTION_RECAPTCHA_THRESHOLD => Controller_Settings::shared()->get(Controller_Settings::OPTION_RECAPTCHA_THRESHOLD),
Controller_Settings::OPTION_LAST_SECRET_REFRESH => Controller_Settings::shared()->get(Controller_Settings::OPTION_LAST_SECRET_REFRESH),
);
// Convert the database strings to typed values.
foreach ($lsFields as $lsField => $value) {
$lsFields[$lsField] = Controller_Settings::shared()->clean($lsField, $value);
}
if (!$fields) {
foreach (wfConfig::$defaultConfig as $group => $groupOptions) {
foreach ($groupOptions as $field => $values) {
$fields[] = $field;
}
}
foreach ($wafFields as $wafField => $value) {
$fields[] = 'waf.' . $wafField;
}
foreach ($lsFields as $lsField => $value) {
$fields[] = 'wfls_settings_' . $lsField;
}
}
foreach ($fields as $field) {
if (strpos($field, 'waf.') === 0) {
$wafField = substr($field, 4);
if (array_key_exists($wafField, $wafFields)) {
$config['waf'][$wafField] = $wafFields[$wafField];
}
continue;
}
if (strpos($field, 'wfls_settings_') === 0) {
$lsField = substr($field, 14);
if (array_key_exists($lsField, $lsFields)) {
$config['wfls_settings_' . $lsField] = $lsFields[$lsField];
}
continue;
}
if (array_key_exists($field, wfConfig::$defaultConfig['checkboxes'])) {
$config[$field] = (bool) wfConfig::get($field);
} else if (array_key_exists($field, wfConfig::$defaultConfig['otherParams']) ||
array_key_exists($field, wfConfig::$defaultConfig['defaultsOnly'])) {
$configConfig = !empty(wfConfig::$defaultConfig['otherParams'][$field]) ?
wfConfig::$defaultConfig['otherParams'][$field] : wfConfig::$defaultConfig['defaultsOnly'][$field];
if (!empty($configConfig['validation']['type'])) {
switch ($configConfig['validation']['type']) {
case wfConfig::TYPE_INT:
$config[$field] = wfConfig::getInt($field);
break;
case wfConfig::TYPE_DOUBLE:
case wfConfig::TYPE_FLOAT:
$config[$field] = floatval(wfConfig::get($field));
break;
case wfConfig::TYPE_BOOL:
$config[$field] = (bool) wfConfig::get($field);
break;
case wfConfig::TYPE_ARRAY:
$config[$field] = wfConfig::get_ser($field);
break;
case wfConfig::TYPE_STRING:
default:
$config[$field] = wfConfig::get($field);
break;
}
} else {
$config[$field] = wfConfig::get($field);
}
} else if (in_array($field, wfConfig::$serializedOptions)) {
$config[$field] = wfConfig::get_ser($field);
}
}
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
parse_str($api->makeAPIQueryString(), $qs);
$systemInfo = json_decode(wfUtils::base64url_decode($qs['s']), true);
$systemInfo['output_buffering'] = ini_get('output_buffering');
$systemInfo['ip'] = wfUtils::getIPAndServerVariable();
$systemInfo['detected_ips'] = wfUtils::getAllServerVariableIPs();
$systemInfo['admin_url'] = network_admin_url();
$response = rest_ensure_response(array(
'config' => $config,
'info' => $systemInfo,
));
return $response;
}
/**
* @param WP_REST_Request $request
* @return mixed|WP_REST_Response
*/
public function setConfig($request) {
wfCentral::preventConfigurationSync();
$fields = $request['fields'];
if (is_array($fields) && $fields) {
$loginSecurityConfig = array();
foreach ($fields as $key => $value) {
if (strpos($key, 'wfls_settings_') === 0) {
$lsField = substr($key, 14);
$loginSecurityConfig[$lsField] = $value;
}
}
if ($loginSecurityConfig) {
$errors = Controller_Settings::shared()->validate_multiple($loginSecurityConfig);
if ($errors !== true) {
if (count($errors) == 1) {
return new WP_Error('rest_set_config_error',
sprintf(
/* translators: Error message. */
__('An error occurred while saving the configuration: %s', 'wordfence'), $errors[0]['error']),
array('status' => 422));
} else if (count($errors) > 1) {
$compoundMessage = array();
foreach ($errors as $e) {
$compoundMessage[] = $e['error'];
}
return new WP_Error('rest_set_config_error',
sprintf(
/* translators: Error message. */
__('Errors occurred while saving the configuration: %s', 'wordfence'), implode(', ', $compoundMessage)),
array('status' => 422));
}
return new WP_Error('rest_set_config_error',
__('Errors occurred while saving the configuration.', 'wordfence'),
array('status' => 422));
}
try {
Controller_Settings::shared()->set_multiple($loginSecurityConfig);
foreach ($fields as $key => $value) {
if (strpos($key, 'wfls_settings_') === 0) {
unset($fields[$key]);
}
}
} catch (Exception $e) {
return new WP_Error('rest_save_config_error',
sprintf(
/* translators: Error message. */
__('A server error occurred while saving the configuration: %s', 'wordfence'), $e->getMessage()),
array('status' => 500));
}
}
$errors = wfConfig::validate($fields);
if ($errors !== true) {
if (count($errors) == 1) {
return new WP_Error('rest_set_config_error',
sprintf(
/* translators: Error message. */
__('An error occurred while saving the configuration: %s', 'wordfence'), $errors[0]['error']),
array('status' => 422));
} else if (count($errors) > 1) {
$compoundMessage = array();
foreach ($errors as $e) {
$compoundMessage[] = $e['error'];
}
return new WP_Error('rest_set_config_error',
sprintf(
/* translators: Error message. */
__('Errors occurred while saving the configuration: %s', 'wordfence'), implode(', ', $compoundMessage)),
array('status' => 422));
}
return new WP_Error('rest_set_config_error',
__('Errors occurred while saving the configuration.', 'wordfence'),
array('status' => 422));
}
try {
wfConfig::save($fields);
return rest_ensure_response(array(
'success' => true,
));
} catch (Exception $e) {
return new WP_Error('rest_save_config_error',
sprintf(
/* translators: Error message. */
__('A server error occurred while saving the configuration: %s', 'wordfence'), $e->getMessage()),
array('status' => 500));
}
}
return new WP_Error('rest_save_config_error',
__("Validation error: 'fields' parameter is empty or not an array.", 'wordfence'),
array('status' => 422));
}
/**
* @param WP_REST_Request $request
* @return mixed|WP_REST_Response
*/
public function disconnect($request) {
self::disconnectConfig();
return rest_ensure_response(array(
'success' => true,
));
}
/**
* @param WP_REST_Request $request
* @return mixed|WP_REST_Response
*/
public function premiumConnect($request) {
require_once(WORDFENCE_PATH . '/lib/sodium_compat_fast.php');
// Store values sent by Central.
$wordfenceCentralPK = $request['public-key'];
$wordfenceCentralSiteData = $request['site-data'];
$wordfenceCentralSiteID = $request['site-id'];
$keypair = ParagonIE_Sodium_Compat::crypto_sign_keypair();
$publicKey = ParagonIE_Sodium_Compat::crypto_sign_publickey($keypair);
$secretKey = ParagonIE_Sodium_Compat::crypto_sign_secretkey($keypair);
wfConfig::set('wordfenceCentralSecretKey', $secretKey);
wfConfig::set('wordfenceCentralConnected', 1);
wfConfig::set('wordfenceCentralCurrentStep', 6);
wfConfig::set('wordfenceCentralPK', pack("H*", $wordfenceCentralPK));
wfConfig::set('wordfenceCentralSiteData', json_encode($wordfenceCentralSiteData));
wfConfig::set('wordfenceCentralSiteID', $wordfenceCentralSiteID);
wfConfig::set('wordfenceCentralConnectTime', time());
wfConfig::set('wordfenceCentralConnectEmail', !empty($this->tokenData['adminEmail']) ? $this->tokenData['adminEmail'] : null);
// Return values created by Wordfence.
return rest_ensure_response(array(
'success' => true,
'public-key' => ParagonIE_Sodium_Compat::bin2hex($publicKey),
));
}
}

View File

@@ -0,0 +1,163 @@
<?php
require_once(dirname(__FILE__) . '/wfRESTBaseController.php');
class wfRESTScanController extends wfRESTBaseController {
/**
* @todo Setup routes to modify scan results.
*/
public function registerRoutes() {
register_rest_route('wordfence/v1', '/scan/issues', array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'getIssuesList'),
'permission_callback' => array($this, 'verifyToken'),
'group' => array(
'description' => __('Scan result group or all results.', 'wordfence'),
'type' => 'string',
'required' => false,
),
'offset' => array(
'description' => __('Offset of scan results to return.', 'wordfence'),
'type' => 'int',
'required' => false,
),
'limit' => array(
'description' => __('Number of scan results to return.', 'wordfence'),
'type' => 'int',
'required' => false,
),
));
register_rest_route('wordfence/v1', '/scan', array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array($this, 'startScan'),
'permission_callback' => array($this, 'verifyToken'),
));
register_rest_route('wordfence/v1', '/scan', array(
'methods' => WP_REST_Server::DELETABLE,
'callback' => array($this, 'stopScan'),
'permission_callback' => array($this, 'verifyToken'),
));
register_rest_route('wordfence/v1', '/scan/issue', array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array($this, 'updateIssue'),
'permission_callback' => array($this, 'verifyToken'),
));
}
/**
* @param WP_REST_Request $request
* @return mixed|WP_REST_Response
*/
public function getIssuesList($request) {
$group = $request['group'] ? $request['group'] : 'all';
$offset = absint($request['offset']);
$limit = absint($request['limit']);
if ($limit === 0) {
$limit = 100;
}
switch ($group) {
case 'pending':
$count = wfIssues::shared()->getPendingIssueCount();
$issues = wfIssues::shared()->getPendingIssues($offset, $limit);
break;
default: // Return all issues.
$count = wfIssues::shared()->getIssueCount();
$issues = wfIssues::shared()->getIssues($offset, $limit);
break;
}
$response = rest_ensure_response(array(
'count' => $count,
'last-scan-time' => wfConfig::get('scanTime'),
'issues' => $issues,
));
return $response;
}
/**
* @param WP_REST_Request $request
* @return mixed|WP_REST_Response
*/
public function startScan($request) {
wordfence::status(1, 'info', sprintf(/* translators: Localized date. */ __('Wordfence scan starting at %s from Wordfence Central', 'wordfence'),
date('l jS \of F Y h:i:s A', current_time('timestamp'))));
try {
wfScanEngine::startScan();
} catch (wfScanEngineTestCallbackFailedException $e) {
wfConfig::set('lastScanCompleted', $e->getMessage());
wfConfig::set('lastScanFailureType', wfIssues::SCAN_FAILED_CALLBACK_TEST_FAILED);
wfUtils::clearScanLock();
$response = rest_ensure_response(array(
'success' => false,
'error-code' => $e->getCode(),
'error' => $e->getMessage(),
));
return $response;
} catch (Exception $e) {
if ($e->getCode() != wfScanEngine::SCAN_MANUALLY_KILLED) {
wfConfig::set('lastScanCompleted', $e->getMessage());
wfConfig::set('lastScanFailureType', wfIssues::SCAN_FAILED_GENERAL);
$response = rest_ensure_response(array(
'success' => false,
'error-code' => $e->getCode(),
'error' => $e->getMessage(),
));
return $response;
}
}
$response = rest_ensure_response(array(
'success' => true,
));
return $response;
}
/**
* @param WP_REST_Request $request
* @return mixed|WP_REST_Response
*/
public function stopScan($request) {
wordfence::status(1, 'info', __('Scan stop request received from Wordfence Central.', 'wordfence'));
wordfence::status(10, 'info', __('SUM_KILLED:A request was received to stop the previous scan from Wordfence Central.', 'wordfence'));
wfUtils::clearScanLock(); //Clear the lock now because there may not be a scan running to pick up the kill request and clear the lock
wfScanEngine::requestKill();
wfConfig::remove('scanStartAttempt');
wfConfig::set('lastScanFailureType', false);
$response = rest_ensure_response(array(
'success' => true,
));
return $response;
}
/**
* @param WP_REST_Request $request
* @return mixed|WP_REST_Response
*/
public function updateIssue($request) {
$issue = $request['issue'];
$id = is_array($issue) && array_key_exists('id', $issue) ? $issue['id'] : null;
$status = is_array($issue) && array_key_exists('status', $issue) ? $issue['status'] : null;
if ($id) {
$wfdb = new wfDB();
$wfdb->queryWrite("update " . wfDB::networkTable('wfIssues') . " set status='%s' where id=%d", $status, $id);
$response = rest_ensure_response(array(
'success' => true,
));
return $response;
}
$response = rest_ensure_response(array(
'success' => false,
'error' => 'Issue not found.',
));
return $response;
}
}

View File

@@ -0,0 +1,6 @@
<?php
if (!class_exists('ParagonIE_Sodium_Compat')) {
require_once WORDFENCE_PATH . '/crypto/vendor/paragonie/sodium_compat/autoload.php';
}
ParagonIE_Sodium_Compat::$fastMult = true;

View File

@@ -0,0 +1,22 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<?php if(! wfUtils::isAdmin()){ exit(); } ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
<head>
<title><?php esc_html_e('Wordfence System Info', 'wordfence') ?></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel='stylesheet' id='wordfence-main-style-css' href='<?php echo wfUtils::getBaseURL() . wfUtils::versionedAsset('css/phpinfo.css'); ?>?ver=<?php echo WORDFENCE_VERSION; ?>' type='text/css' media='all' />
<body>
<?php
ob_start();
if (wfUtils::funcEnabled('phpinfo')) { phpinfo(INFO_ALL); } else { echo '<center><strong>' . esc_html__('Unable to output phpinfo content because it is disabled', 'wordfence') . "</strong></center>\n"; }
$out = ob_get_clean();
$out = str_replace('width="600"','width="900"', $out);
// $out = preg_replace('/<hr.*?PHP Credits.*?<\/h1>/s', '', $out);
$out = preg_replace('/<a [^>]+>/', '', $out);
$out = preg_replace('/<\/a>/', '', $out);
$out = preg_replace('/<title>[^<]*<\/title>/','', $out);
echo $out;
?>
<div class="diffFooter"><?php echo wp_kses(sprintf(__('&copy;&nbsp;%d to %d Wordfence &mdash; Visit <a href="http://wordfence.com/">Wordfence.com</a> for help, security updates and more.', 'wordfence'), date_i18n('Y', WORDFENCE_EPOCH), date_i18n('Y')), array('a'=>array('href'=>array()))) ?></div>
</body>
</html>

View File

@@ -0,0 +1,33 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<?php if(! wfUtils::isAdmin()){ exit(); } ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel='stylesheet' id='wordfence-main-style-css' href='<?php echo wfUtils::getBaseURL() . wfUtils::versionedAsset('css/fullLog.css'); ?>?ver=<?php echo WORDFENCE_VERSION; ?>' type='text/css' media='all' />
<style type="text/css">
</style>
</head>
<body>
<h1><?php esc_html_e('Wordfence Full Activity Log', 'wordfence') ?></h1>
<?php
$db = new wfDB();
global $wpdb;
$debugOn = wfConfig::get('debugOn', 0);
$table = wfDB::networkTable('wfStatus');
$offset = 0;
$timeOffset = 3600 * get_option('gmt_offset');
$q = $db->querySelect("SELECT ctime, level, type, msg FROM {$table} ORDER BY ctime DESC LIMIT %d, 100", $offset);
while (is_array($q) && count($q) > 0) {
foreach($q as $r){
if($r['level'] < 4 || $debugOn){
echo '<div' . ($r['type'] == 'error' ? ' class="error"' : '') . '>[' . date('M d H:i:s', (int) $r['ctime'] + $timeOffset) . ':' . $r['ctime'] . ':' . $r['level'] . ':' . $r['type'] . ']&nbsp;' . esc_html($r['msg']) . "</div>\n";
}
}
$offset += count($q);
$q = $db->querySelect("SELECT ctime, level, type, msg FROM {$table} ORDER BY ctime DESC LIMIT %d, 100", $offset);
}
?>
</body>
</html>
<?php exit(0); ?>

View File

@@ -0,0 +1,394 @@
<?php if (!defined('WORDFENCE_VERSION')) { exit; } ?>
<!DOCTYPE html>
<html>
<head>
<title><?php esc_html_e('Your access to this site has been limited', 'wordfence'); ?></title>
<style>
html {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 0.875rem;
line-height: 1.42857143;
color: #333;
background-color: #fff;
padding: 0;
margin: 0;
}
body {
padding: 0;
margin: 0;
}
a {
color:#00709e;
}
h1, h2, h3, h4, h5, h6 {
font-weight: 200;
line-height: 1.1;
}
h1, .h1 { font-size: 3rem; }
h2, .h2 { font-size: 2.5rem; }
h3, .h3 { font-size: 1.5rem; }
h4, .h4 { font-size: 1rem; }
h5, .h5 { font-size: 0.875rem; }
h6, .h6 { font-size: 0.75rem; }
h1, h2, h3 {
margin-top: 20px;
margin-bottom: 10px;
}
h4, h5, h6 {
margin-top: 10px;
margin-bottom: 10px;
}
.wf-btn {
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
text-transform: uppercase;
padding: .4rem 1rem;
font-size: .875rem;
line-height: 1.3125rem;
border-radius: 4px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none
}
@media (min-width: 768px) {
.wf-btn {
padding: .5rem 1.25rem;
font-size: .875rem;
line-height: 1.3125rem;
border-radius: 4px
}
}
.wf-btn:focus,
.wf-btn.wf-focus,
.wf-btn:active:focus,
.wf-btn:active.wf-focus,
.wf-btn.wf-active:focus,
.wf-btn.wf-active.wf-focus {
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px
}
.wf-btn:hover,
.wf-btn:focus,
.wf-btn.wf-focus {
color: #00709e;
text-decoration: none
}
.wf-btn:active,
.wf-btn.wf-active {
outline: 0;
background-image: none;
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125)
}
.wf-btn.wf-disabled,
.wf-btn[disabled],
.wf-btn[readonly],
fieldset[disabled] .wf-btn {
cursor: not-allowed;
-webkit-box-shadow: none;
box-shadow: none
}
a.wf-btn {
text-decoration: none
}
a.wf-btn.wf-disabled,
fieldset[disabled] a.wf-btn {
cursor: not-allowed;
pointer-events: none
}
.wf-btn-default {
color: #00709e;
background-color: #fff;
border-color: #00709e
}
.wf-btn-default:focus,
.wf-btn-default.focus {
color: #00709e;
background-color: #e6e6e6;
border-color: #00161f
}
.wf-btn-default:hover {
color: #00709e;
background-color: #e6e6e6;
border-color: #004561
}
.wf-btn-default:active,
.wf-btn-default.active {
color: #00709e;
background-color: #e6e6e6;
border-color: #004561
}
.wf-btn-default:active:hover,
.wf-btn-default:active:focus,
.wf-btn-default:active.focus,
.wf-btn-default.active:hover,
.wf-btn-default.active:focus,
.wf-btn-default.active.focus {
color: #00709e;
background-color: #d4d4d4;
border-color: #00161f
}
.wf-btn-default:active,
.wf-btn-default.wf-active {
background-image: none
}
.wf-btn-default.wf-disabled,
.wf-btn-default[disabled],
.wf-btn-default[readonly],
fieldset[disabled] .wf-btn-default {
color: #777;
background-color: #fff;
border-color: #e2e2e2;
cursor: not-allowed
}
.wf-btn-default.wf-disabled:hover,
.wf-btn-default.wf-disabled:focus,
.wf-btn-default.wf-disabled.wf-focus,
.wf-btn-default[disabled]:hover,
.wf-btn-default[disabled]:focus,
.wf-btn-default[disabled].wf-focus,
.wf-btn-default[readonly]:hover,
.wf-btn-default[readonly]:focus,
.wf-btn-default[readonly].wf-focus,
fieldset[disabled] .wf-btn-default:hover,
fieldset[disabled] .wf-btn-default:focus,
fieldset[disabled] .wf-btn-default.wf-focus {
background-color: #fff;
border-color: #00709e
}
input[type="text"], input.wf-input-text {
text-align: left;
max-width: 200px;
height: 30px;
border-radius: 0;
border: 0;
background-color: #ffffff;
box-shadow: 0px 0px 0px 1px rgba(215,215,215,0.65);
padding: 0.25rem;
}
hr {
margin-top: 1rem;
margin-bottom: 1rem;
border: 0;
border-top: 4px solid #eee
}
p {
font-size: 1.4rem;
font-weight: 300;
}
p.medium, div.medium p {
font-size: 1.1rem;
}
p.small, div.small p {
font-size: 1rem;
}
.container {
max-width: 900px;
padding: 0 1rem;
margin: 0 auto;
}
.top-accent {
height: 25px;
background-color: #00709e;
}
.block-data {
width: 100%;
border-top: 6px solid #00709e;
}
.block-data tr:nth-child(odd) th, .block-data tr:nth-child(odd) td {
background-color: #eeeeee;
}
.block-data th, .block-data td {
text-align: left;
padding: 1rem;
font-size: 1.1rem;
}
.block-data th.reason, .block-data td.reason {
color: #930000;
}
.block-data th {
font-weight: 300;
}
.block-data td {
font-weight: 500;
}
.about {
margin-top: 2rem;
display: flex;
flex-direction: row;
align-items: stretch;
}
.about .badge {
flex-basis: 116px;
flex-grow: 0;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: flex-start;
}
.about svg {
width: 100px;
height: 100px;
}
.about-text {
background-color: #00709e;
color: #ffffff;
padding: 1rem;
}
.about-text .h4 {
font-weight: 500;
margin-top: 0;
margin-bottom: 0.25rem;
font-size: 0.875rem;
}
.about-text p {
font-size: 0.875rem;
font-weight: 200;
margin-top: 0.3rem;
margin-bottom: 0.3rem;
}
.about-text p:first-of-type {
margin-top: 0;
}
.about-text p:last-of-type {
margin-bottom: 0;
}
.st0{fill:#00709e;}
.st1{fill:#FFFFFF;}
.generated {
color: #999999;
margin-top: 2rem;
}
/* Text meant only for screen readers. */
.screen-reader-text {
border: 0;
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
word-wrap: normal !important;
}
.screen-reader-text:focus {
background-color: #eee;
clip: auto !important;
clip-path: none;
color: #444;
display: block;
font-size: 1em;
height: auto;
left: 5px;
line-height: normal;
padding: 15px 23px 14px;
text-decoration: none;
top: 5px;
width: auto;
z-index: 100000; /* Above WP toolbar. */
}
</style>
</head>
<body>
<div class="top-accent"></div>
<div class="container">
<h1><?php esc_html_e('Your access to this site has been limited by the site owner', 'wordfence'); ?></h1>
<p><?php esc_html_e('Your access to this service has been limited. (HTTP response code 503)', 'wordfence'); ?></p>
<p><?php esc_html_e('If you think you have been blocked in error, contact the owner of this site for assistance.', 'wordfence'); ?></p>
<?php if (!empty($customText)): ?>
<hr>
<div class="medium"><?php echo $customText; ?></div>
<?php endif; ?>
<hr>
<?php require(dirname(__FILE__) . '/wfUnlockMsg.php'); ?>
<h2 class="h3"><?php esc_html_e('Block Technical Data', 'wordfence') ?></h2>
<table border="0" cellspacing="0" cellpadding="0" class="block-data">
<tr>
<th class="reason"><?php esc_html_e('Block Reason', 'wordfence'); ?>:</th>
<td class="reason"><?php echo htmlspecialchars($reason); ?></td>
</tr>
<tr>
<th class="time"><?php esc_html_e('Time', 'wordfence'); ?>:</th>
<td class="time"><?php echo htmlspecialchars(gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime())); ?></td>
</tr>
</table>
<div class="about">
<div class="badge">
<?php
$contents = file_get_contents(WORDFENCE_PATH . '/images/wf-error-badge.svg');
$contents = preg_replace('/^<\?xml.+?\?>\s*/i', '', $contents);
$contents = preg_replace('/^<!DOCTYPE.+?>\s*/i', '', $contents);
$contents = preg_replace('/<svg\s+xmlns="[^"]*"/i', '<svg', $contents);
echo $contents;
?>
</div>
<div class="about-text">
<h3 class="h4"><?php esc_html_e('About Wordfence', 'wordfence'); ?></h3>
<p><?php esc_html_e('Wordfence is a security plugin installed on over 4 million WordPress sites. The owner of this site is using Wordfence to manage access to their site.', 'wordfence'); ?></p>
<p><?php esc_html_e('You can also read the documentation to learn about Wordfence\'s blocking tools, or visit wordfence.com to learn more about Wordfence.', 'wordfence'); ?></p>
</div>
</div>
<p class="documentation small"><?php echo wp_kses(sprintf(/* translators: Support URL. */ __('Click here to learn more: <a href="%s" target="_blank" rel="noopener noreferrer">Documentation<span class="screen-reader-text"> (' . esc_html__('opens in new tab', 'wordfence') . ')</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_LOCKED_OUT)), array('a'=>array('href'=>array(), 'target'=>array(), 'rel'=>array()), 'span'=>array('class'=>array()))); ?></p>
<p class="generated small"><em><?php echo wp_kses(sprintf(/* translators: Localized date. */ __('Generated by Wordfence at %s', 'wordfence'), gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime())), array('a'=>array('href'=>array(), 'target'=>array(), 'rel'=>array()))); ?>.<br><?php esc_html_e('Your computer\'s time:', 'wordfence'); ?> <script type="application/javascript">document.write(new Date().toUTCString());</script>.</em></p>
</div>
</body>
</html>

View File

@@ -0,0 +1,245 @@
<?php
require_once(dirname(__FILE__) . '/wordfenceConstants.php');
require_once(dirname(__FILE__) . '/wordfenceClass.php');
require_once(dirname(__FILE__) . '/wfLicense.php');
class wfAPI {
public $lastHTTPStatus = '';
public $lastCurlErrorNo = '';
private $curlContent = 0;
private $APIKey = '';
private $wordpressVersion = '';
public function __construct($apiKey, $wordpressVersion) {
$this->APIKey = $apiKey;
$this->wordpressVersion = $wordpressVersion;
}
public function getStaticURL($url) { // In the form '/something.bin' without quotes
return $this->getURL(rtrim($this->getAPIURL(), '/') . '/' . ltrim($url, '/'));
}
public function call($action, $getParams = array(), $postParams = array(), $forceSSL = false, $timeout = 900) {
$apiURL = $this->getAPIURL();
//Sanity check. Developer should call wfAPI::SSLEnabled() to check if SSL is enabled before forcing SSL and return a user friendly msg if it's not.
if ($forceSSL && (!preg_match('/^https:/i', $apiURL))) {
//User's should never see this message unless we aren't calling SSLEnabled() to check if SSL is enabled before using call() with forceSSL
throw new wfAPICallSSLUnavailableException(__("SSL is not supported by your web server and is required to use this function. Please ask your hosting provider or site admin to install cURL with openSSL to use this feature.", 'wordfence'));
}
$json = $this->getURL(rtrim($apiURL, '/') . '/v' . WORDFENCE_API_VERSION . '/?' . $this->makeAPIQueryString() . '&' . self::buildQuery(
array_merge(
array('action' => $action),
$getParams
)), $postParams, $timeout);
if (!$json) {
throw new wfAPICallInvalidResponseException(sprintf(/* translators: API call/action/endpoint. */__("We received an empty data response from the Wordfence scanning servers when calling the '%s' function.", 'wordfence'), $action));
}
$dat = json_decode($json, true);
if (!is_array($dat)) {
throw new wfAPICallInvalidResponseException(sprintf(/* translators: API call/action/endpoint. */ __("We received a data structure that is not the expected array when contacting the Wordfence scanning servers and calling the '%s' function.", 'wordfence'), $action));
}
//Only process key data for responses that include it
if (array_key_exists('_isPaidKey', $dat))
$this->processKeyData($dat);
if (isset($dat['_touppChanged'])) {
wfConfig::set('touppPromptNeeded', wfUtils::truthyToBoolean($dat['_touppChanged']));
}
if (isset($dat['errorMsg'])) {
throw new wfAPICallErrorResponseException($dat['errorMsg']);
}
return $dat;
}
private function processKeyData($dat) {
$license = wfLicense::current()
->setApiKey($this->APIKey)
->setPaid($dat['_isPaidKey'])
->setRemainingDays($dat['_keyExpDays'])
->setType(array_key_exists('_licenseType', $dat) ? $dat['_licenseType'] : null);
if (isset($dat['_isPaidKey']) && !isset($dat['errorMsg'])) {
wfConfig::setOrRemove('premiumAutoRenew', isset($dat['_autoRenew']) ? wfUtils::truthyToInt($dat['_autoRenew']) : null);
wfConfig::setOrRemove('premiumNextRenew', isset($dat['_nextRenewAttempt']) ? time() + $dat['_nextRenewAttempt'] * 86400 : null);
wfConfig::setOrRemove('premiumPaymentExpiring', isset($dat['_paymentExpiring']) ? wfUtils::truthyToInt($dat['_paymentExpiring']) : null);
wfConfig::setOrRemove('premiumPaymentExpired', isset($dat['_paymentExpired']) ? wfUtils::truthyToInt($dat['_paymentExpired']) : null);
wfConfig::setOrRemove('premiumPaymentMissing', isset($dat['_paymentMissing']) ? wfUtils::truthyToInt($dat['_paymentMissing']) : null);
wfConfig::setOrRemove('premiumPaymentHold', isset($dat['_paymentHold']) ? wfUtils::truthyToInt($dat['_paymentHold']) : null);
}
$hasKeyConflict = false;
if (isset($dat['_hasKeyConflict'])) {
$hasKeyConflict = ($dat['_hasKeyConflict'] == 1);
if ($hasKeyConflict) {
new wfNotification(null, wfNotification::PRIORITY_HIGH_CRITICAL, '<a href="' . wfUtils::wpAdminURL('admin.php?page=Wordfence&subpage=global_options') . '">' . esc_html__('The Wordfence license you\'re using does not match this site\'s address. Premium features are disabled.', 'wordfence') . '</a>', 'wfplugin_keyconflict', null, array(array('link' => 'https://www.wordfence.com/manage-wordfence-api-keys/', 'label' => 'Manage Keys')));
$license->setConflicting();
}
}
$license->setDeleted(isset($dat['_keyNoLongerValid']) && $dat['_keyNoLongerValid'] == 1);
if (!$hasKeyConflict) {
$license->setConflicting(false);
$n = wfNotification::getNotificationForCategory('wfplugin_keyconflict');
if ($n !== null) {
wordfence::status(1, 'info', 'Idle');
$n->markAsRead();
}
}
$license->save(isset($dat['errorMsg']));
}
protected function getURL($url, $postParams = array(), $timeout = 900) {
wordfence::status(4, 'info', sprintf(/* translators: API version. */ __("Calling Wordfence API v%s:", 'wordfence'), WORDFENCE_API_VERSION) . $url);
if (!function_exists('wp_remote_post')) {
require_once(ABSPATH . WPINC . 'http.php');
}
$ssl_verify = (bool) wfConfig::get('ssl_verify');
$args = array(
'timeout' => $timeout,
'user-agent' => "Wordfence.com UA " . (defined('WORDFENCE_VERSION') ? WORDFENCE_VERSION : '[Unknown version]'),
'body' => $postParams,
'sslverify' => $ssl_verify,
'headers' => array('Referer' => false),
);
if (!$ssl_verify) {
// Some versions of cURL will complain that SSL verification is disabled but the CA bundle was supplied.
$args['sslcertificates'] = false;
}
$response = wp_remote_post($url, $args);
$this->lastHTTPStatus = (int) wp_remote_retrieve_response_code($response);
if (is_wp_error($response)) {
$error_message = $response->get_error_message();
if ($error_message) {
$apiExceptionMessage = sprintf(/* translators: Error message. */ __('There was an error connecting to the Wordfence scanning servers: %s', 'wordfence'), $error_message);
} else {
$apiExceptionMessage = __('There was an unknown error connecting to the Wordfence scanning servers.', 'wordfence');
}
throw new wfAPICallFailedException($apiExceptionMessage);
}
$dateHeader = @$response['headers']['date'];
if (!empty($dateHeader) && (time() - wfConfig::get('timeoffset_wf_updated', 0) > 3600)) {
if (function_exists('date_create_from_format')) {
$dt = DateTime::createFromFormat('D, j M Y G:i:s O', $dateHeader);
$timestamp = $dt->getTimestamp();
}
else {
$timestamp = strtotime($dateHeader);
}
$offset = $timestamp - time();
wfConfig::set('timeoffset_wf', $offset);
wfConfig::set('timeoffset_wf_updated', time());
}
if (!empty($response['response']['code'])) {
$this->lastHTTPStatus = (int) $response['response']['code'];
}
if (200 != $this->lastHTTPStatus) {
throw new wfAPICallFailedException(sprintf(/* translators: HTTP status code. */__("The Wordfence scanning servers are currently unavailable. This may be for maintenance or a temporary outage. If this still occurs in an hour, please contact support. [%s]", 'wordfence'), $this->lastHTTPStatus));
}
$content = wp_remote_retrieve_body($response);
return $content;
}
public function binCall($func, $postData) {
$url = rtrim($this->getAPIURL(), '/') . '/v' . WORDFENCE_API_VERSION . '/?' . $this->makeAPIQueryString() . '&action=' . $func;
$data = $this->getURL($url, $postData);
if (preg_match('/\{.*errorMsg/', $data)) {
$jdat = @json_decode($data, true);
if (is_array($jdat) && $jdat['errorMsg']) {
throw new Exception($jdat['errorMsg']);
}
}
return array('code' => $this->lastHTTPStatus, 'data' => $data);
}
public static function generateSiteStats($wordpressVersion = null) {
if ($wordpressVersion === null)
$wordpressVersion = wfUtils::getWPVersion();
$cv = null;
$cs = null;
if (function_exists('curl_version')) {
$curl = curl_version();
$cv = $curl['version'];
$cs = $curl['ssl_version'];
}
$values = array(
'wp' => $wordpressVersion,
'wf' => WORDFENCE_VERSION,
'ms' => (is_multisite() ? get_blog_count() : false),
'h' => wfUtils::wpHomeURL(),
'sslv' => function_exists('openssl_verify') && defined('OPENSSL_VERSION_NUMBER') ? OPENSSL_VERSION_NUMBER : null,
'pv' => phpversion(),
'pt' => php_sapi_name(),
'cv' => $cv,
'cs' => $cs,
'sv' => (isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : null),
'dv' => wfConfig::get('dbVersion', null),
'lang' => get_site_option('WPLANG'),
);
return wfUtils::base64url_encode(wfUtils::jsonEncodeSafely($values));
}
public function makeAPIQueryString() {
return self::buildQuery(array(
'k' => $this->APIKey,
's' => self::generateSiteStats($this->wordpressVersion)
));
}
private function buildQuery($data) {
if (version_compare(phpversion(), '5.1.2', '>=')) {
return http_build_query($data, '', '&'); //arg_separator parameter was only added in PHP 5.1.2. We do this because some PHP.ini's have arg_separator.output set to '&amp;'
} else {
return http_build_query($data);
}
}
private function getAPIURL() {
return self::SSLEnabled() ? WORDFENCE_API_URL_SEC : WORDFENCE_API_URL_NONSEC;
}
public static function SSLEnabled() {
if (!function_exists('wp_http_supports')) {
require_once(ABSPATH . WPINC . 'http.php');
}
return wp_http_supports(array('ssl'));
}
public function getTextImageURL($text) {
$apiURL = $this->getAPIURL();
return rtrim($apiURL, '/') . '/v' . WORDFENCE_API_VERSION . '/?' . $this->makeAPIQueryString() . '&' . self::buildQuery(array('action' => 'image', 'txt' => base64_encode($text)));
}
}
class wfAPICallSSLUnavailableException extends Exception {
}
class wfAPICallFailedException extends Exception {
}
class wfAPICallInvalidResponseException extends Exception {
}
class wfAPICallErrorResponseException extends Exception {
}

View File

@@ -0,0 +1,755 @@
<?php
if (defined('WORDFENCE_VERSION')) {
class wfActivityReport {
const BLOCK_TYPE_COMPLEX = 'complex';
const BLOCK_TYPE_BRUTE_FORCE = 'bruteforce';
const BLOCK_TYPE_BLACKLIST = 'blacklist';
/**
* @var int
*/
private $limit = 10;
/**
* @var wpdb
*/
private $db;
/**
* @param int $limit
*/
public function __construct($limit = 10) {
global $wpdb;
$this->db = $wpdb;
$this->limit = $limit;
}
/**
* Schedule the activity report cron job.
*/
public static function scheduleCronJob() {
self::clearCronJobs();
if (!wfConfig::get('email_summary_enabled', 1)) {
return;
}
if (is_main_site()) {
list(, $end_time) = wfActivityReport::getReportDateRange();
wp_schedule_single_event($end_time, 'wordfence_email_activity_report');
}
}
/**
* Remove the activity report cron job.
*/
public static function disableCronJob() {
self::clearCronJobs();
}
public static function clearCronJobs() {
wp_clear_scheduled_hook('wordfence_email_activity_report');
}
/**
* Send out the report and reschedule the next report's cron job.
*/
public static function executeCronJob() {
if (!wfConfig::get('email_summary_enabled', 1)) {
return;
}
$emails = wfConfig::getAlertEmails();
if (count($emails)) {
$report = new self();
$report->sendReportViaEmail($emails);
}
self::scheduleCronJob();
}
/**
* Output a compact version of the email for the WP dashboard.
*/
public static function outputDashboardWidget() {
$report = new self(5);
echo $report->toWidgetView();
}
/**
* @return array
*/
public static function getReportDateRange() {
$interval = wfConfig::get('email_summary_interval', 'weekly');
$offset = get_option('gmt_offset');
return self::_getReportDateRange($interval, $offset);
}
/**
* Testable code.
*
* @param string $interval
* @param int $offset
* @param null $time
* @return array
*/
public static function _getReportDateRange($interval = 'weekly', $offset = 0, $time = null) {
if ($time === null) {
$time = time();
}
$day = (int) gmdate('w', $time);
$month = (int) gmdate("n", $time);
$day_of_month = (int) gmdate("j", $time);
$year = (int) gmdate("Y", $time);
$start_time = 0;
$end_time = 0;
switch ($interval) {
// Send a report 4pm every day
case 'daily':
$start_time = gmmktime(16, 0, 0, $month, $day_of_month, $year) + (-$offset * 60 * 60);
$end_time = $start_time + 86400;
break;
// Send a report 4pm every Monday
case 'weekly':
$start_time = gmmktime(16, 0, 0, $month, $day_of_month - $day + 1, $year) + (-$offset * 60 * 60);
$end_time = $start_time + (86400 * 7);
break;
// Send a report at 4pm the first of every month
case 'monthly':
$start_time = gmmktime(16, 0, 0, $month, 1, $year) + (-$offset * 60 * 60);
$end_time = gmmktime(16, 0, 0, $month + 1, 1, $year) + (-$offset * 60 * 60);
break;
}
return array($start_time, $end_time);
}
/**
* @return int
*/
public static function getReportDateFrom() {
$interval = wfConfig::get('email_summary_interval', 'weekly');
return self::_getReportDateFrom($interval);
}
/**
* @param string $interval
* @param null $time
* @return int
*/
public static function _getReportDateFrom($interval = 'weekly', $time = null) {
if ($time === null) {
$time = time();
}
// weekly
$from = $time - (86400 * 7);
switch ($interval) {
case 'daily':
$from = $time - 86400;
break;
// Send a report at 4pm the first of every month
case 'monthly':
$from = strtotime('-1 month', $time);
break;
}
return $from;
}
/**
* @return array
*/
public function getFullReport() {
$start_time = microtime(true);
$remainder = 0;
$recent_firewall_activity = $this->getRecentFirewallActivity($this->limit, $remainder);
return array(
'top_ips_blocked' => $this->getTopIPsBlocked($this->limit),
'top_countries_blocked' => $this->getTopCountriesBlocked($this->limit),
'top_failed_logins' => $this->getTopFailedLogins($this->limit),
'recent_firewall_activity' => $recent_firewall_activity,
'omitted_firewall_activity'=> $remainder,
'recently_modified_files' => $this->getRecentFilesModified($this->limit),
'updates_needed' => $this->getUpdatesNeeded(),
'microseconds' => microtime(true) - $start_time,
);
}
/**
* @return array
*/
public function getWidgetReport() {
$start_time = microtime(true);
return array(
'top_ips_blocked' => $this->getTopIPsBlocked($this->limit),
'top_countries_blocked' => $this->getTopCountriesBlocked($this->limit),
'top_failed_logins' => $this->getTopFailedLogins($this->limit),
'updates_needed' => $this->getUpdatesNeeded(),
'microseconds' => microtime(true) - $start_time,
);
}
public function getBlockedCount($maxAgeDays = null, $grouping = null) {
$maxAgeDays = (int) $maxAgeDays;
if ($maxAgeDays <= 0) {
$interval = 'FLOOR(UNIX_TIMESTAMP(DATE_SUB(NOW(), interval 7 day)) / 86400)';
switch (wfConfig::get('email_summary_interval', 'weekly')) {
case 'daily':
$interval = 'FLOOR(UNIX_TIMESTAMP(DATE_SUB(NOW(), interval 1 day)) / 86400)';
break;
case 'monthly':
$interval = 'FLOOR(UNIX_TIMESTAMP(DATE_SUB(NOW(), interval 1 month)) / 86400)';
break;
}
}
else {
$interval = 'FLOOR(UNIX_TIMESTAMP(DATE_SUB(NOW(), interval ' . $maxAgeDays . ' day)) / 86400)';
}
//Possible values for blockType: throttle, manual, brute, fakegoogle, badpost, country, advanced, blacklist, waf
$groupingWHERE = '';
switch ($grouping) {
case self::BLOCK_TYPE_COMPLEX:
$groupingWHERE = ' AND blockType IN ("fakegoogle", "badpost", "country", "advanced", "waf")';
break;
case self::BLOCK_TYPE_BRUTE_FORCE:
$groupingWHERE = ' AND blockType IN ("throttle", "brute")';
break;
case self::BLOCK_TYPE_BLACKLIST:
$groupingWHERE = ' AND blockType IN ("blacklist", "manual")';
break;
}
$table_wfBlockedIPLog = wfDB::networkTable('wfBlockedIPLog');
$count = $this->db->get_var(<<<SQL
SELECT SUM(blockCount) as blockCount
FROM {$table_wfBlockedIPLog}
WHERE unixday >= {$interval}{$groupingWHERE}
SQL
);
return $count;
}
/**
* @param int $limit
* @return mixed
*/
public function getTopIPsBlocked($limit = 10, $maxAgeDays = null) {
$maxAgeDays = (int) $maxAgeDays;
if ($maxAgeDays <= 0) {
$interval = 'FLOOR(UNIX_TIMESTAMP(DATE_SUB(NOW(), interval 7 day)) / 86400)';
switch (wfConfig::get('email_summary_interval', 'weekly')) {
case 'daily':
$interval = 'FLOOR(UNIX_TIMESTAMP(DATE_SUB(NOW(), interval 1 day)) / 86400)';
break;
case 'monthly':
$interval = 'FLOOR(UNIX_TIMESTAMP(DATE_SUB(NOW(), interval 1 month)) / 86400)';
break;
}
}
else {
$interval = 'FLOOR(UNIX_TIMESTAMP(DATE_SUB(NOW(), interval ' . $maxAgeDays . ' day)) / 86400)';
}
$table_wfBlockedIPLog = wfDB::networkTable('wfBlockedIPLog');
$query=<<<SQL
SELECT IP, countryCode, unixday, blockType,
SUM(blockCount) as blockCount
FROM {$table_wfBlockedIPLog}
WHERE unixday >= {$interval}
GROUP BY IP
ORDER BY blockCount DESC
LIMIT %d
SQL;
$results = $this->db->get_results($this->db->prepare($query, $limit));
if ($results) {
foreach ($results as &$row) {
$row->countryName = $this->getCountryNameByCode($row->countryCode);
}
}
return $results;
}
/**
* @param int $limit
* @return array
*/
public function getTopCountriesBlocked($limit = 10, $maxAgeDays = null) {
$maxAgeDays = (int) $maxAgeDays;
if ($maxAgeDays <= 0) {
$interval = 'FLOOR(UNIX_TIMESTAMP(DATE_SUB(NOW(), interval 7 day)) / 86400)';
switch (wfConfig::get('email_summary_interval', 'weekly')) {
case 'daily':
$interval = 'FLOOR(UNIX_TIMESTAMP(DATE_SUB(NOW(), interval 1 day)) / 86400)';
break;
case 'monthly':
$interval = 'FLOOR(UNIX_TIMESTAMP(DATE_SUB(NOW(), interval 1 month)) / 86400)';
break;
}
}
else {
$interval = 'FLOOR(UNIX_TIMESTAMP(DATE_SUB(NOW(), interval ' . $maxAgeDays . ' day)) / 86400)';
}
$table_wfBlockedIPLog = wfDB::networkTable('wfBlockedIPLog');
$query=<<<SQL
SELECT *, COUNT(IP) as totalIPs, SUM(ipBlockCount) as totalBlockCount
FROM (SELECT *, SUM(blockCount) AS ipBlockCount FROM {$table_wfBlockedIPLog} WHERE unixday >= {$interval} GROUP BY IP) t
GROUP BY countryCode
ORDER BY totalBlockCount DESC
LIMIT %d
SQL;
$results = $this->db->get_results($this->db->prepare($query, $limit));
if ($results) {
foreach ($results as &$row) {
$row->countryName = $this->getCountryNameByCode($row->countryCode);
}
}
return $results;
}
/**
* @param int $limit
* @return mixed
*/
public function getTopFailedLogins($limit = 10) {
$interval = 'UNIX_TIMESTAMP(DATE_SUB(NOW(), interval 7 day))';
switch (wfConfig::get('email_summary_interval', 'weekly')) {
case 'daily':
$interval = 'UNIX_TIMESTAMP(DATE_SUB(NOW(), interval 1 day))';
break;
case 'monthly':
$interval = 'UNIX_TIMESTAMP(DATE_SUB(NOW(), interval 1 month))';
break;
}
$table_wfLogins = wfDB::networkTable('wfLogins');
$failedLogins = $this->db->get_results($this->db->prepare(<<<SQL
SELECT wfl.*,
sum(wfl.fail) as fail_count
FROM {$table_wfLogins} wfl
WHERE wfl.fail = 1
AND wfl.ctime > $interval
GROUP BY wfl.username
ORDER BY fail_count DESC
LIMIT %d
SQL
, $limit));
foreach ($failedLogins as &$login) {
$exists = $this->db->get_var($this->db->prepare(<<<SQL
SELECT !ISNULL(ID) FROM {$this->db->users} WHERE user_login = '%s' OR user_email = '%s'
SQL
, $login->username, $login->username));
$login->is_valid_user = $exists;
}
return $failedLogins;
}
/**
* Returns any updates needs or false if everything is up to date.
*
* @return array|bool
*/
public function getUpdatesNeeded($useCachedValued = true) {
$update_check = new wfUpdateCheck();
$needs_update = $update_check->checkAllUpdates($useCachedValued)
->needsAnyUpdates();
if ($needs_update) {
return array(
'core' => $update_check->getCoreUpdateVersion(),
'plugins' => $update_check->getPluginUpdates(),
'themes' => $update_check->getThemeUpdates(),
);
}
return false;
}
/**
* Returns list of firewall activity up to $limit number of entries.
*
* @param int $limit Max events to return in results
* @param int $remainder
* @return array
*/
public function getRecentFirewallActivity($limit, &$remainder) {
$dateRange = wfActivityReport::getReportDateRange();
$recent_firewall_activity = new wfRecentFirewallActivity(null, max(604800, $dateRange[1] - $dateRange[0]));
$recent_firewall_activity->run();
return $recent_firewall_activity->mostRecentActivity($limit, $remainder);
}
/**
* Returns list of files modified within given timeframe.
*
* @todo Add option to configure the regex used to filter files allowed in this list.
* @todo Add option to exclude directories (such as cache directories).
*
* @param string $directory Search for files within this directory
* @param int $time_range One week
* @param int $limit Max files to return in results
* @param int $directory_limit Hard limit for number of files to search within a directory.
* @return array
*/
public function getRecentFilesModified($limit = 300, $directory = ABSPATH, $time_range = 604800, $directory_limit = 20000) {
$recently_modified = new wfRecentlyModifiedFiles($directory);
$recently_modified->run();
return $recently_modified->mostRecentFiles($limit);
}
/**
* Remove entries older than a month in the IP log.
*/
public function rotateIPLog() {
$table_wfBlockedIPLog = wfDB::networkTable('wfBlockedIPLog');
$this->db->query(<<<SQL
DELETE FROM {$table_wfBlockedIPLog}
WHERE unixday < FLOOR(UNIX_TIMESTAMP(DATE_SUB(NOW(), interval 1 month)) / 86400)
SQL
);
}
/**
* @param mixed $ip_address
* @param int|null $unixday
*/
public static function logBlockedIP($ip_address, $unixday = null, $type = null) {
/** @var wpdb $wpdb */
global $wpdb;
//Possible values for $type: throttle, manual, brute, fakegoogle, badpost, country, advanced, blacklist, waf
if (wfUtils::isValidIP($ip_address)) {
$ip_bin = wfUtils::inet_pton($ip_address);
} else {
$ip_bin = $ip_address;
$ip_address = wfUtils::inet_ntop($ip_bin);
}
$blocked_table = wfDB::networkTable('wfBlockedIPLog');
$unixday_insert = 'FLOOR(UNIX_TIMESTAMP() / 86400)';
if (is_int($unixday)) {
$unixday_insert = absint($unixday);
}
if ($type === null) {
$type = 'generic';
}
$country = wfUtils::IP2Country($ip_address);
$wpdb->query($wpdb->prepare(<<<SQL
INSERT INTO $blocked_table (IP, countryCode, blockCount, unixday, blockType)
VALUES (%s, %s, 1, $unixday_insert, %s)
ON DUPLICATE KEY UPDATE blockCount = blockCount + 1
SQL
, $ip_bin, $country, $type));
}
/**
* @param $code
* @return string
*/
public function getCountryNameByCode($code) {
static $wfBulkCountries;
if (!isset($wfBulkCountries)) {
include(dirname(__FILE__) . '/wfBulkCountries.php');
}
return array_key_exists($code, $wfBulkCountries) ? $wfBulkCountries[$code] : "";
}
/**
* @return wfActivityReportView
*/
public function toView() {
return new wfActivityReportView('reports/activity-report', $this->getFullReport() + array(
'limit' => $this->getLimit(),
));
}
/**
* @return wfActivityReportView
*/
public function toWidgetView() {
return new wfActivityReportView('reports/activity-report', $this->getWidgetReport() + array(
'limit' => $this->getLimit(),
));
}
/**
* @return wfActivityReportView
*/
public function toEmailView() {
return new wfActivityReportView('reports/activity-report-email-inline', $this->getFullReport());
}
/**
* @param $email_addresses string|array
* @return bool
*/
public function sendReportViaEmail($email_addresses) {
$shortSiteURL = preg_replace('/^https?:\/\//i', '', site_url());
$content = $this->toEmailView()->__toString();
$success = true;
if (is_string($email_addresses)) { $email_addresses = explode(',', $email_addresses); }
foreach ($email_addresses as $email) {
$uniqueContent = str_replace('<!-- ##UNSUBSCRIBE## -->', wp_kses(sprintf(/* translators: URL to the WordPress admin panel. */ __('No longer an administrator for this site? <a href="%s" target="_blank">Click here</a> to stop receiving security alerts.', 'wordfence'), wfUtils::getSiteBaseURL() . '?_wfsf=removeAlertEmail&jwt=' . wfUtils::generateJWT(array('email' => $email))), array('a'=>array('href'=>array(), 'target'=>array()))), $content);
if (!wp_mail($email, sprintf(/* translators: 1. Site URL. 2. Localized date. */ __('Wordfence activity for %1$s on %2$s', 'wordfence'), date_i18n(get_option('date_format')), $shortSiteURL), $uniqueContent, 'Content-Type: text/html')) {
$success = false;
}
}
return $success;
}
/**
* @return string
* @throws wfViewNotFoundException
*/
public function render() {
return $this->toView()
->render();
}
/**
* @return string
*/
public function __toString() {
return $this->toView()
->__toString();
}
/**
* @return int
*/
public function getLimit() {
return $this->limit;
}
/**
* @param int $limit
*/
public function setLimit($limit) {
$this->limit = $limit;
}
}
class wfRecentFirewallActivity {
private $activity = array();
private $max_fetch = 2000;
private $time_range = 604800;
public function __construct($max_fetch = null, $time_range = null) {
if ($max_fetch !== null) {
$this->max_fetch = $max_fetch;
}
if ($time_range !== null) {
$this->time_range = $time_range;
}
}
public function run() {
global $wpdb;
$table_wfHits = wfDB::networkTable('wfHits');
$results = $wpdb->get_results($wpdb->prepare(<<<SQL
SELECT attackLogTime, IP, URL, UA, actionDescription, actionData
FROM {$table_wfHits}
WHERE action = 'blocked:waf' AND attackLogTime > (UNIX_TIMESTAMP() - %d)
ORDER BY attackLogTime DESC
LIMIT %d
SQL
, $this->time_range, $this->max_fetch));
if ($results) {
foreach ($results as &$row) {
$actionData = json_decode($row->actionData, true);
if (!is_array($actionData) || !isset($actionData['paramKey']) || !isset($actionData['paramValue'])) {
continue;
}
if (isset($actionData['failedRules']) && $actionData['failedRules'] == 'blocked') {
$row->longDescription = __("Blocked because the IP is blocklisted", 'wordfence');
}
else {
$row->longDescription = sprintf(__("Blocked for %s", 'wordfence'), $row->actionDescription);
}
$paramKey = base64_decode($actionData['paramKey']);
$paramValue = base64_decode($actionData['paramValue']);
if (strlen($paramValue) > 100) {
$paramValue = substr($paramValue, 0, 100) . '...';
}
if (preg_match('/([a-z0-9_]+\.[a-z0-9_]+)(?:\[(.+?)\](.*))?/i', $paramKey, $matches)) {
switch ($matches[1]) {
case 'request.queryString':
$row->longDescription = sprintf(__('Blocked for %1$s in query string: %2$s = %3$s', 'wordfence'), $row->actionDescription, $matches[2], $paramValue);
break;
case 'request.body':
$row->longDescription = sprintf(__('Blocked for %1$s in POST body: %2$s = %3$s', 'wordfence'), $row->actionDescription, $matches[2], $paramValue);
break;
case 'request.cookie':
$row->longDescription = sprintf(__('Blocked for %1$s in cookie: %2$s = %3$s', 'wordfence'), $row->actionDescription, $matches[2], $paramValue);
break;
case 'request.fileNames':
$row->longDescription = sprintf(__('Blocked for %1$s in file: %2$s = %3$s', 'wordfence'), $row->actionDescription, $matches[2], $paramValue);
break;
}
}
}
}
$this->activity = $results;
}
public function mostRecentActivity($limit, &$remainder = null) {
if ($remainder !== null) {
$remainder = count($this->activity) - $limit;
}
return array_slice($this->activity, 0, $limit);
}
}
class wfRecentlyModifiedFiles extends wfDirectoryIterator {
/**
* @var int
*/
private $time_range = 604800;
/**
* @var array
*/
private $files = array();
private $excluded_directories;
/**
* @param string $directory
* @param int $max_files_per_directory
* @param int $max_iterations
* @param int $time_range
*/
public function __construct($directory = ABSPATH, $max_files_per_directory = 20000, $max_iterations = 250000, $time_range = 604800) {
parent::__construct($directory, $max_files_per_directory, $max_iterations);
$this->time_range = $time_range;
$excluded_directories = explode("\n", wfUtils::cleanupOneEntryPerLine(wfConfig::get('email_summary_excluded_directories', '')));
$this->excluded_directories = array();
foreach ($excluded_directories as $index => $path) {
if (($dir = realpath(ABSPATH . $path)) !== false) {
$this->excluded_directories[$dir] = 1;
}
}
}
/**
* @param $dir
* @return bool
*/
protected function scan($dir) {
if (!array_key_exists(realpath($dir), $this->excluded_directories)) {
return parent::scan($dir);
}
return true;
}
/**
* @param string $file
*/
public function file($file) {
$mtime = filemtime($file);
if (time() - $mtime < $this->time_range) {
$this->files[] = array($file, $mtime);
}
}
/**
* @param int $limit
* @return array
*/
public function mostRecentFiles($limit = 300) {
usort($this->files, array(
$this,
'_sortMostRecentFiles',
));
return array_slice($this->files, 0, $limit);
}
/**
* Sort in descending order.
*
* @param $a
* @param $b
* @return int
*/
private function _sortMostRecentFiles($a, $b) {
if ($a[1] > $b[1]) {
return -1;
}
if ($a[1] < $b[1]) {
return 1;
}
return 0;
}
/**
* @return mixed
*/
public function getFiles() {
return $this->files;
}
}
class wfActivityReportView extends wfView {
/**
* @param $file
* @return string
*/
public function displayFile($file) {
$realPath = realpath($file);
if (stripos($realPath, ABSPATH) === 0) {
return substr($realPath, strlen(ABSPATH));
}
return $realPath;
}
/**
* @param null $unix_time
* @return string
*/
public function modTime($unix_time = null) {
if ($unix_time === null) {
$unix_time = time();
}
return wfUtils::formatLocalTime('F j, Y g:ia', $unix_time);
}
public function attackTime($unix_time = null) {
if ($unix_time === null) {
$unix_time = time();
}
return wfUtils::formatLocalTime('F j, Y', $unix_time) . "<br>" . wfUtils::formatLocalTime('g:ia', $unix_time);
}
public function displayIP($binaryIP) {
$readableIP = wfUtils::inet_ntop($binaryIP);
$country = wfUtils::countryCode2Name(wfUtils::IP2Country($readableIP));
return "{$readableIP} (" . ($country ? $country : __('Unknown', 'wordfence')) . ")";
}
}
}

View File

@@ -0,0 +1,195 @@
<?php
class wfAdminNoticeQueue {
protected static function _notices() {
return self::_purgeObsoleteNotices(wfConfig::get_ser('adminNoticeQueue', array()));
}
private static function _purgeObsoleteNotices($notices) {
$altered = false;
foreach ($notices as $id => $notice) {
if ($notice['category'] === 'php8') {
unset($notices[$id]);
$altered = true;
}
}
if ($altered)
self::_setNotices($notices);
return $notices;
}
protected static function _setNotices($notices) {
wfConfig::set_ser('adminNoticeQueue', $notices);
}
/**
* Adds an admin notice to the display queue.
*
* @param string $severity
* @param string $messageHTML
* @param bool|string $category If not false, notices with the same category will be removed prior to adding this one.
* @param bool|array $users If not false, an array of user IDs the notice should show for.
*/
public static function addAdminNotice($severity, $messageHTML, $category = false, $users = false) {
$notices = self::_notices();
foreach ($notices as $id => $n) {
$usersMatches = false;
if (isset($n['users'])) {
$usersMatches = wfUtils::sets_equal($n['users'], $users);
}
else if ($users === false) {
$usersMatches = true;
}
$categoryMatches = false;
if ($category !== false && isset($n['category']) && $n['category'] == $category) {
$categoryMatches = true;
}
if ($usersMatches && $categoryMatches) {
unset($notices[$id]);
}
}
$id = wfUtils::uuid();
$notices[$id] = array(
'severity' => $severity,
'messageHTML' => $messageHTML,
);
if ($category !== false) {
$notices[$id]['category'] = $category;
}
if ($users !== false) {
$notices[$id]['users'] = $users;
}
self::_setNotices($notices);
}
/**
* Removes an admin notice using one of three possible search methods:
*
* 1. If $id matches. $category and $users are ignored
* 2. If $category matches. $users must be false for this.
* 3. If $category matches and the notice's user IDs matches $users.
*
* @param bool|int $id
* @param bool|string $category
* @param bool|int[] $users
*/
public static function removeAdminNotice($id = false, $category = false, $users = false) {
if ($id === false && $category === false && $users === false) {
return;
}
else if ($id !== false) {
$category = false;
$users = false;
}
$notices = self::_notices();
$found = false;
foreach ($notices as $nid => $n) {
if ($id == $nid) { //ID match
unset($notices[$nid]);
$found=true;
break;
}
else if ($id !== false) {
continue;
}
if ($category !== false && isset($n['category']) && $category == $n['category']) {
if ($users !== false) {
if (isset($n['users']) && wfUtils::sets_equal($users, $n['users'])) {
unset($notices[$nid]);
$found=true;
}
}
else {
unset($notices[$nid]);
$found=true;
}
}
}
if($found)
self::_setNotices($notices);
}
public static function hasNotice($category = false, $users = false) {
$notices = self::_notices();
foreach ($notices as $nid => $n) {
$categoryMatches = false;
if (($category === false && !isset($n['category'])) || ($category !== false && isset($n['category']) && $category == $n['category'])) {
$categoryMatches = true;
}
$usersMatches = false;
if (($users === false && !isset($n['users'])) || ($users !== false && isset($n['users']) && wfUtils::sets_equal($users, $n['users']))) {
$usersMatches = true;
}
if ($categoryMatches && $usersMatches) {
return true;
}
}
return false;
}
public static function enqueueAdminNotices() {
$user = wp_get_current_user();
if ($user->ID == 0) {
return false;
}
$networkAdmin = is_multisite() && is_network_admin();
$notices = self::_notices();
$added = false;
foreach ($notices as $nid => $n) {
if (isset($n['users']) && array_search($user->ID, $n['users']) === false) {
continue;
}
$notice = new wfAdminNotice($nid, $n['severity'], $n['messageHTML']);
if ($networkAdmin) {
add_action('network_admin_notices', array($notice, 'displayNotice'));
}
else {
add_action('admin_notices', array($notice, 'displayNotice'));
}
$added = true;
}
return $added;
}
}
class wfAdminNotice {
const SEVERITY_CRITICAL = 'critical';
const SEVERITY_WARNING = 'warning';
const SEVERITY_INFO = 'info';
private $_id;
private $_severity;
private $_messageHTML;
public function __construct($id, $severity, $messageHTML) {
$this->_id = $id;
$this->_severity = $severity;
$this->_messageHTML = $messageHTML;
}
public function displayNotice() {
$severityClass = 'notice-info';
if ($this->_severity == self::SEVERITY_CRITICAL) {
$severityClass = 'notice-error';
}
else if ($this->_severity == self::SEVERITY_WARNING) {
$severityClass = 'notice-warning';
}
echo '<div class="wf-admin-notice notice ' . $severityClass . '" data-notice-id="' . esc_attr($this->_id) . '"><p>' . $this->_messageHTML . '</p><p><a class="wf-btn wf-btn-default wf-btn-sm wf-dismiss-link" href="#" onclick="wordfenceExt.dismissAdminNotice(\'' . esc_attr($this->_id) . '\'); return false;" role="button">' . esc_html__('Dismiss', 'wordfence') . '</a></p></div>';
}
}

View File

@@ -0,0 +1,262 @@
<?php
abstract class wfBaseAlert {
public abstract function send();
}
class wfBlockAlert extends wfBaseAlert {
private $IP;
private $reason;
private $secsToGo;
/**
* wfBlockAlert constructor.
* @param $IP
* @param $reason
* @param $secsToGo
*/
public function __construct($IP, $reason, $secsToGo) {
$this->IP = $IP;
$this->reason = $reason;
$this->secsToGo = $secsToGo;
}
public function send() {
if (wfConfig::get('alertOn_block')) {
$message = sprintf(/* translators: IP address. */ __('Wordfence has blocked IP address %s.', 'wordfence'), $this->IP) . "\n";
$message .= sprintf(/* translators: Description of firewall action. */ __('The reason is: "%s".', 'wordfence'), $this->reason);
if ($this->secsToGo > 0) {
$message .= "\n" . sprintf(/* translators: Time until. */ __('The duration of the block is %s.', 'wordfence'), wfUtils::makeDuration($this->secsToGo, true));
}
wordfence::alert(sprintf(/* translators: IP address. */__('Blocking IP %s', 'wordfence'), $this->IP), $message, $this->IP);
}
}
}
class wfAutoUpdatedAlert extends wfBaseAlert {
private $version;
/**
* @param $version
*/
public function __construct($version) {
$this->version = $version;
}
public function send() {
if (wfConfig::get('alertOn_update') == '1' && $this->version) {
wordfence::alert(sprintf(/* translators: Software version. */ __("Wordfence Upgraded to version %s", 'wordfence'), $this->version), sprintf(/* translators: Software version. */ __("Your Wordfence installation has been upgraded to version %s", 'wordfence'), $this->version), false);
}
}
}
class wfWafDeactivatedAlert extends wfBaseAlert {
private $username;
private $IP;
/**
* @param $username
* @param $IP
*/
public function __construct($username, $IP) {
$this->username = $username;
$this->IP = $IP;
}
public function send() {
if (wfConfig::get('alertOn_wafDeactivated')) {
wordfence::alert(__('Wordfence WAF Deactivated', 'wordfence'), sprintf(/* translators: WP username. */__('A user with username "%s" deactivated the Wordfence Web Application Firewall on your WordPress site.', 'wordfence'), $this->username), $this->IP);
}
}
}
class wfWordfenceDeactivatedAlert extends wfBaseAlert {
private $username;
private $IP;
/**
* @param $username
* @param $IP
*/
public function __construct($username, $IP) {
$this->username = $username;
$this->IP = $IP;
}
public function send() {
if (wfConfig::get('alertOn_wordfenceDeactivated')) {
wordfence::alert(__("Wordfence Deactivated", 'wordfence'), sprintf(/* translators: WP username. */ __("A user with username \"%s\" deactivated Wordfence on your WordPress site.", 'wordfence'), $this->username), $this->IP);
}
}
}
class wfLostPasswdFormAlert extends wfBaseAlert {
private $user;
private $IP;
/**
* @param $user
* @param $IP
*/
public function __construct($user, $IP) {
$this->user = $user;
$this->IP = $IP;
}
public function send() {
if (wfConfig::get('alertOn_lostPasswdForm')) {
wordfence::alert(__("Password recovery attempted", 'wordfence'), sprintf(/* translators: Email address. */__("Someone tried to recover the password for user with email address: %s", 'wordfence'), wp_kses($this->user->user_email, array())), $this->IP);
}
}
}
class wfLoginLockoutAlert extends wfBaseAlert {
private $IP;
private $reason;
/**
* @param $IP
* @param $reason
*/
public function __construct($IP, $reason) {
$this->IP = $IP;
$this->reason = $reason;
}
public function send() {
if (wfConfig::get('alertOn_loginLockout')) {
$message = sprintf(
/* translators: 1. IP address. 2. Description of firewall action. */
__('A user with IP address %1$s has been locked out from signing in or using the password recovery form for the following reason: %2$s.', 'wordfence'), $this->IP, $this->reason);
if (wfBlock::lockoutDuration() > 0) {
$message .= "\n" . sprintf(/* translators: Time until. */ __('The duration of the lockout is %s.', 'wordfence'), wfUtils::makeDuration(wfBlock::lockoutDuration(), true));
}
wordfence::alert(__('User locked out from signing in', 'wordfence'), $message, $this->IP);
}
}
}
class wfAdminLoginAlert extends wfBaseAlert {
private $cookieName;
private $username;
private $IP;
private $cookieValue;
/**
* @param $cookieName
* @param $cookieValue
* @param $username
* @param $IP
*/
public function __construct($cookieName, $cookieValue, $username, $IP) {
$this->cookieName = $cookieName;
$this->cookieValue = $cookieValue;
$this->username = $username;
$this->IP = $IP;
}
public function send() {
if (wfConfig::get('alertOn_adminLogin')) {
$shouldAlert = true;
if (wfConfig::get('alertOn_firstAdminLoginOnly') && isset($_COOKIE[$this->cookieName])) {
$shouldAlert = !hash_equals($this->cookieValue, $_COOKIE[$this->cookieName]);
}
if ($shouldAlert) {
wordfence::alert(__("Admin Login", 'wordfence'), sprintf(/* translators: WP username. */ __("A user with username \"%s\" who has administrator access signed in to your WordPress site.", 'wordfence'), $this->username), $this->IP);
}
}
}
}
class wfNonAdminLoginAlert extends wfBaseAlert {
private $cookieName;
private $username;
private $IP;
private $cookieValue;
/**
* @param $cookieName
* @param $cookieValue
* @param $username
* @param $IP
*/
public function __construct($cookieName, $cookieValue, $username, $IP) {
$this->cookieName = $cookieName;
$this->cookieValue = $cookieValue;
$this->username = $username;
$this->IP = $IP;
}
public function send() {
if (wfConfig::get('alertOn_nonAdminLogin')) {
$shouldAlert = true;
if (wfConfig::get('alertOn_firstNonAdminLoginOnly') && isset($_COOKIE[$this->cookieName])) {
$shouldAlert = !hash_equals($this->cookieValue, $_COOKIE[$this->cookieName]);
}
if ($shouldAlert) {
wordfence::alert(__("User login", 'wordfence'), sprintf(/* translators: WP username. */ __("A non-admin user with username \"%s\" signed in to your WordPress site.", 'wordfence'), $this->username), $this->IP);
}
}
}
}
class wfBreachLoginAlert extends wfBaseAlert {
private $username;
private $lostPasswordUrl;
private $supportUrl;
private $IP;
/**
* @param $username
* @param $lostPasswordUrl
* @param $supportUrl
* @param $IP
*/
public function __construct($username, $lostPasswordUrl, $supportUrl, $IP) {
$this->username = $username;
$this->lostPasswordUrl = $lostPasswordUrl;
$this->supportUrl = $supportUrl;
$this->IP = $IP;
}
public function send() {
if (wfConfig::get('alertOn_breachLogin')) {
wordfence::alert(__('User login blocked for insecure password', 'wordfence'), sprintf(
/* translators: 1. WP username. 2. Reset password URL. 3. Support URL. */
__('A user with username "%1$s" tried to sign in to your WordPress site. Access was denied because the password being used exists on lists of passwords leaked in data breaches. Attackers use such lists to break into sites and install malicious code. Please change or reset the password (%2$s) to reactivate this account. Learn More: %3$s', 'wordfence'), $this->username, $this->lostPasswordUrl, $this->supportUrl), $this->IP);
}
}
}
class wfIncreasedAttackRateAlert extends wfBaseAlert {
private $message;
/**
* @param $message
*/
public function __construct($message) {
$this->message = $message;
}
public function send() {
wordfence::alert(__('Increased Attack Rate', 'wordfence'), $this->message, false);
}
}

View File

@@ -0,0 +1,46 @@
<?php
class wfArray {
private $data = "";
private $size = 0;
private $shiftPtr = 0;
private $keys;
public function __construct($keys){
$this->keys = $keys;
}
public function push($val){ //associative array with keys that match those given to constructor
foreach($this->keys as $key){
$this->data .= pack('N', wfUtils::strlen($val[$key])) . $val[$key];
}
$this->size++;
}
public function shift(){ //If you alternately call push and shift you must periodically call collectGarbage() or ->data will keep growing
$arr = array();
if(wfUtils::strlen($this->data) < 1){ return null; }
if($this->shiftPtr == wfUtils::strlen($this->data)){ return null; }
foreach($this->keys as $key){
$len = unpack('N', wfUtils::substr($this->data, $this->shiftPtr, 4));
$len = $len[1];
$arr[$key] = wfUtils::substr($this->data, $this->shiftPtr + 4, $len);
$this->shiftPtr += 4 + $len;
}
if($this->shiftPtr == wfUtils::strlen($this->data)){ //garbage collection
$this->data = ""; //we don't shorten with substr() because the assignment doubles peak mem
$this->shiftPtr = 0;
}
$this->size--;
return $arr;
}
public function collectGarbage(){ //only call collectGarbage if you're alternating between pushes and shifts and never emptying the array.
//If you don't collect garbage then the data that is shifted is never freed
$this->data = wfUtils::substr($this->data, $this->shiftPtr); //at this point memory usage doubles because of the = assignment (string copy is made), so try not to call collect garbage unless you have to.
$this->shiftPtr = 0;
}
public function zero(){ //Rather call this instead of collect garbage because it's way more mem efficient.
$this->data = "";
$this->shiftPtr = 0;
$this->size = 0;
}
public function size(){
return $this->size;
}
}

View File

@@ -0,0 +1,126 @@
<?php
class wfBrowscap {
protected $_cacheLoaded = false;
protected $_userAgents = array();
protected $_browsers = array();
protected $_patterns = array();
protected $_properties = array();
protected $resultCache = array();
const COMPRESSION_PATTERN_START = '@';
const COMPRESSION_PATTERN_DELIMITER = '|';
const REGEX_DELIMITER = '@';
public static function shared() {
static $_browscap = null;
if ($_browscap === null) {
$_browscap = new wfBrowscap();
}
return $_browscap;
}
public function getBrowser($user_agent){
if (!$this->_cacheLoaded) {
if (!$this->_loadCache(dirname(__FILE__) . '/wfBrowscapCache.php')) {
throw new Exception('Cannot load this cache version - the cache format is not compatible.');
}
}
$browser = array();
foreach ($this->_patterns as $pattern => $pattern_data) {
if (preg_match($pattern . 'i', $user_agent, $matches)) {
if (1 == count($matches)) {
$key = $pattern_data;
$simple_match = true;
} else {
$pattern_data = unserialize($pattern_data);
array_shift($matches);
$match_string = self::COMPRESSION_PATTERN_START
. implode(self::COMPRESSION_PATTERN_DELIMITER, $matches);
if (!isset($pattern_data[$match_string])) {
continue;
}
$key = $pattern_data[$match_string];
$simple_match = false;
}
$browser = array(
$user_agent,
trim(strtolower($pattern), self::REGEX_DELIMITER),
$this->_pregUnQuote($pattern, $simple_match ? false : $matches)
);
$browser = $value = $browser + unserialize($this->_browsers[$key]);
while (array_key_exists(3, $value)) {
$value = unserialize($this->_browsers[$value[3]]);
$browser += $value;
}
if (!empty($browser[3])) {
$browser[3] = $this->_userAgents[$browser[3]];
}
break;
}
}
$array = array();
foreach ($browser as $key => $value) {
if ($value === 'true') {
$value = true;
} elseif ($value === 'false') {
$value = false;
}
$array[$this->_properties[$key]] = $value;
}
return $array;
}
protected function _loadCache($cache_file){
$cache_version = null;
$browsers = array();
$userAgents = array();
$patterns = array();
$properties = array();
$this->_cacheLoaded = false;
require $cache_file;
$this->_browsers = $browsers;
$this->_userAgents = $userAgents;
$this->_patterns = $patterns;
$this->_properties = $properties;
$this->_cacheLoaded = true;
return true;
}
protected function _pregUnQuote($pattern, $matches){
$search = array(
'\\' . self::REGEX_DELIMITER, '\\.', '\\\\', '\\+', '\\[', '\\^', '\\]', '\\$', '\\(', '\\)', '\\{', '\\}',
'\\=', '\\!', '\\<', '\\>', '\\|', '\\:', '\\-', '.*', '.', '\\?'
);
$replace = array(
self::REGEX_DELIMITER, '\\?', '\\', '+', '[', '^', ']', '$', '(', ')', '{', '}', '=', '!', '<', '>', '|',
':', '-', '*', '?', '.'
);
$result = substr(str_replace($search, $replace, $pattern), 2, -2);
if ($matches) {
foreach ($matches as $one_match) {
$num_pos = strpos($result, '(\d)');
$result = substr_replace($result, $one_match, $num_pos, 4);
}
}
return $result;
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,255 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
$wfBulkCountries = array(
"AD" => __("Andorra", 'wordfence'),
"AE" => __("United Arab Emirates", 'wordfence'),
"AF" => __("Afghanistan", 'wordfence'),
"AG" => __("Antigua and Barbuda", 'wordfence'),
"AI" => __("Anguilla", 'wordfence'),
"AL" => __("Albania", 'wordfence'),
"AM" => __("Armenia", 'wordfence'),
"AO" => __("Angola", 'wordfence'),
"AQ" => __("Antarctica", 'wordfence'),
"AR" => __("Argentina", 'wordfence'),
"AS" => __("American Samoa", 'wordfence'),
"AT" => __("Austria", 'wordfence'),
"AU" => __("Australia", 'wordfence'),
"AW" => __("Aruba", 'wordfence'),
"AX" => __("Aland Islands", 'wordfence'),
"AZ" => __("Azerbaijan", 'wordfence'),
"BA" => __("Bosnia and Herzegovina", 'wordfence'),
"BB" => __("Barbados", 'wordfence'),
"BD" => __("Bangladesh", 'wordfence'),
"BE" => __("Belgium", 'wordfence'),
"BF" => __("Burkina Faso", 'wordfence'),
"BG" => __("Bulgaria", 'wordfence'),
"BH" => __("Bahrain", 'wordfence'),
"BI" => __("Burundi", 'wordfence'),
"BJ" => __("Benin", 'wordfence'),
"BL" => __("Saint Bartelemey", 'wordfence'),
"BM" => __("Bermuda", 'wordfence'),
"BN" => __("Brunei Darussalam", 'wordfence'),
"BO" => __("Bolivia", 'wordfence'),
"BQ" => __("Bonaire, Saint Eustatius and Saba", 'wordfence'),
"BR" => __("Brazil", 'wordfence'),
"BS" => __("Bahamas", 'wordfence'),
"BT" => __("Bhutan", 'wordfence'),
"BV" => __("Bouvet Island", 'wordfence'),
"BW" => __("Botswana", 'wordfence'),
"BY" => __("Belarus", 'wordfence'),
"BZ" => __("Belize", 'wordfence'),
"CA" => __("Canada", 'wordfence'),
"CC" => __("Cocos (Keeling) Islands", 'wordfence'),
"CD" => __("Congo, The Democratic Republic of the", 'wordfence'),
"CF" => __("Central African Republic", 'wordfence'),
"CG" => __("Congo", 'wordfence'),
"CH" => __("Switzerland", 'wordfence'),
"CI" => __("Cote dIvoire", 'wordfence'),
"CK" => __("Cook Islands", 'wordfence'),
"CL" => __("Chile", 'wordfence'),
"CM" => __("Cameroon", 'wordfence'),
"CN" => __("China", 'wordfence'),
"CO" => __("Colombia", 'wordfence'),
"CR" => __("Costa Rica", 'wordfence'),
"CU" => __("Cuba", 'wordfence'),
"CV" => __("Cape Verde", 'wordfence'),
"CW" => __("Curacao", 'wordfence'),
"CX" => __("Christmas Island", 'wordfence'),
"CY" => __("Cyprus", 'wordfence'),
"CZ" => __("Czech Republic", 'wordfence'),
"DE" => __("Germany", 'wordfence'),
"DJ" => __("Djibouti", 'wordfence'),
"DK" => __("Denmark", 'wordfence'),
"DM" => __("Dominica", 'wordfence'),
"DO" => __("Dominican Republic", 'wordfence'),
"DZ" => __("Algeria", 'wordfence'),
"EC" => __("Ecuador", 'wordfence'),
"EE" => __("Estonia", 'wordfence'),
"EG" => __("Egypt", 'wordfence'),
"EH" => __("Western Sahara", 'wordfence'),
"ER" => __("Eritrea", 'wordfence'),
"ES" => __("Spain", 'wordfence'),
"ET" => __("Ethiopia", 'wordfence'),
"EU" => __("Europe", 'wordfence'),
"FI" => __("Finland", 'wordfence'),
"FJ" => __("Fiji", 'wordfence'),
"FK" => __("Falkland Islands (Malvinas)", 'wordfence'),
"FM" => __("Micronesia, Federated States of", 'wordfence'),
"FO" => __("Faroe Islands", 'wordfence'),
"FR" => __("France", 'wordfence'),
"GA" => __("Gabon", 'wordfence'),
"GB" => __("United Kingdom", 'wordfence'),
"GD" => __("Grenada", 'wordfence'),
"GE" => __("Georgia", 'wordfence'),
"GF" => __("French Guiana", 'wordfence'),
"GG" => __("Guernsey", 'wordfence'),
"GH" => __("Ghana", 'wordfence'),
"GI" => __("Gibraltar", 'wordfence'),
"GL" => __("Greenland", 'wordfence'),
"GM" => __("Gambia", 'wordfence'),
"GN" => __("Guinea", 'wordfence'),
"GP" => __("Guadeloupe", 'wordfence'),
"GQ" => __("Equatorial Guinea", 'wordfence'),
"GR" => __("Greece", 'wordfence'),
"GS" => __("South Georgia and the South Sandwich Islands", 'wordfence'),
"GT" => __("Guatemala", 'wordfence'),
"GU" => __("Guam", 'wordfence'),
"GW" => __("Guinea-Bissau", 'wordfence'),
"GY" => __("Guyana", 'wordfence'),
"HK" => __("Hong Kong", 'wordfence'),
"HM" => __("Heard Island and McDonald Islands", 'wordfence'),
"HN" => __("Honduras", 'wordfence'),
"HR" => __("Croatia", 'wordfence'),
"HT" => __("Haiti", 'wordfence'),
"HU" => __("Hungary", 'wordfence'),
"ID" => __("Indonesia", 'wordfence'),
"IE" => __("Ireland", 'wordfence'),
"IL" => __("Israel", 'wordfence'),
"IM" => __("Isle of Man", 'wordfence'),
"IN" => __("India", 'wordfence'),
"IO" => __("British Indian Ocean Territory", 'wordfence'),
"IQ" => __("Iraq", 'wordfence'),
"IR" => __("Iran, Islamic Republic of", 'wordfence'),
"IS" => __("Iceland", 'wordfence'),
"IT" => __("Italy", 'wordfence'),
"JE" => __("Jersey", 'wordfence'),
"JM" => __("Jamaica", 'wordfence'),
"JO" => __("Jordan", 'wordfence'),
"JP" => __("Japan", 'wordfence'),
"KE" => __("Kenya", 'wordfence'),
"KG" => __("Kyrgyzstan", 'wordfence'),
"KH" => __("Cambodia", 'wordfence'),
"KI" => __("Kiribati", 'wordfence'),
"KM" => __("Comoros", 'wordfence'),
"KN" => __("Saint Kitts and Nevis", 'wordfence'),
"KP" => __("North Korea", 'wordfence'),
"KR" => __("South Korea", 'wordfence'),
"KW" => __("Kuwait", 'wordfence'),
"KY" => __("Cayman Islands", 'wordfence'),
"KZ" => __("Kazakhstan", 'wordfence'),
"LA" => __("Lao Peoples Democratic Republic", 'wordfence'),
"LB" => __("Lebanon", 'wordfence'),
"LC" => __("Saint Lucia", 'wordfence'),
"LI" => __("Liechtenstein", 'wordfence'),
"LK" => __("Sri Lanka", 'wordfence'),
"LR" => __("Liberia", 'wordfence'),
"LS" => __("Lesotho", 'wordfence'),
"LT" => __("Lithuania", 'wordfence'),
"LU" => __("Luxembourg", 'wordfence'),
"LV" => __("Latvia", 'wordfence'),
"LY" => __("Libyan Arab Jamahiriya", 'wordfence'),
"MA" => __("Morocco", 'wordfence'),
"MC" => __("Monaco", 'wordfence'),
"MD" => __("Moldova, Republic of", 'wordfence'),
"ME" => __("Montenegro", 'wordfence'),
"MF" => __("Saint Martin", 'wordfence'),
"MG" => __("Madagascar", 'wordfence'),
"MH" => __("Marshall Islands", 'wordfence'),
"MK" => __("North Macedonia, Republic of", 'wordfence'),
"ML" => __("Mali", 'wordfence'),
"MM" => __("Myanmar", 'wordfence'),
"MN" => __("Mongolia", 'wordfence'),
"MO" => __("Macao", 'wordfence'),
"MP" => __("Northern Mariana Islands", 'wordfence'),
"MQ" => __("Martinique", 'wordfence'),
"MR" => __("Mauritania", 'wordfence'),
"MS" => __("Montserrat", 'wordfence'),
"MT" => __("Malta", 'wordfence'),
"MU" => __("Mauritius", 'wordfence'),
"MV" => __("Maldives", 'wordfence'),
"MW" => __("Malawi", 'wordfence'),
"MX" => __("Mexico", 'wordfence'),
"MY" => __("Malaysia", 'wordfence'),
"MZ" => __("Mozambique", 'wordfence'),
"NA" => __("Namibia", 'wordfence'),
"NC" => __("New Caledonia", 'wordfence'),
"NE" => __("Niger", 'wordfence'),
"NF" => __("Norfolk Island", 'wordfence'),
"NG" => __("Nigeria", 'wordfence'),
"NI" => __("Nicaragua", 'wordfence'),
"NL" => __("Netherlands", 'wordfence'),
"NO" => __("Norway", 'wordfence'),
"NP" => __("Nepal", 'wordfence'),
"NR" => __("Nauru", 'wordfence'),
"NU" => __("Niue", 'wordfence'),
"NZ" => __("New Zealand", 'wordfence'),
"OM" => __("Oman", 'wordfence'),
"PA" => __("Panama", 'wordfence'),
"PE" => __("Peru", 'wordfence'),
"PF" => __("French Polynesia", 'wordfence'),
"PG" => __("Papua New Guinea", 'wordfence'),
"PH" => __("Philippines", 'wordfence'),
"PK" => __("Pakistan", 'wordfence'),
"PL" => __("Poland", 'wordfence'),
"PM" => __("Saint Pierre and Miquelon", 'wordfence'),
"PN" => __("Pitcairn", 'wordfence'),
"PR" => __("Puerto Rico", 'wordfence'),
"PS" => __("Palestinian Territory", 'wordfence'),
"PT" => __("Portugal", 'wordfence'),
"PW" => __("Palau", 'wordfence'),
"PY" => __("Paraguay", 'wordfence'),
"QA" => __("Qatar", 'wordfence'),
"RE" => __("Reunion", 'wordfence'),
"RO" => __("Romania", 'wordfence'),
"RS" => __("Serbia", 'wordfence'),
"RU" => __("Russian Federation", 'wordfence'),
"RW" => __("Rwanda", 'wordfence'),
"SA" => __("Saudi Arabia", 'wordfence'),
"SB" => __("Solomon Islands", 'wordfence'),
"SC" => __("Seychelles", 'wordfence'),
"SD" => __("Sudan", 'wordfence'),
"SE" => __("Sweden", 'wordfence'),
"SG" => __("Singapore", 'wordfence'),
"SH" => __("Saint Helena", 'wordfence'),
"SI" => __("Slovenia", 'wordfence'),
"SJ" => __("Svalbard and Jan Mayen", 'wordfence'),
"SK" => __("Slovakia", 'wordfence'),
"SL" => __("Sierra Leone", 'wordfence'),
"SM" => __("San Marino", 'wordfence'),
"SN" => __("Senegal", 'wordfence'),
"SO" => __("Somalia", 'wordfence'),
"SR" => __("Suriname", 'wordfence'),
"ST" => __("Sao Tome and Principe", 'wordfence'),
"SV" => __("El Salvador", 'wordfence'),
"SX" => __("Sint Maarten", 'wordfence'),
"SY" => __("Syrian Arab Republic", 'wordfence'),
"SZ" => __("Swaziland", 'wordfence'),
"TC" => __("Turks and Caicos Islands", 'wordfence'),
"TD" => __("Chad", 'wordfence'),
"TF" => __("French Southern Territories", 'wordfence'),
"TG" => __("Togo", 'wordfence'),
"TH" => __("Thailand", 'wordfence'),
"TJ" => __("Tajikistan", 'wordfence'),
"TK" => __("Tokelau", 'wordfence'),
"TL" => __("Timor-Leste", 'wordfence'),
"TM" => __("Turkmenistan", 'wordfence'),
"TN" => __("Tunisia", 'wordfence'),
"TO" => __("Tonga", 'wordfence'),
"TR" => __("Turkey", 'wordfence'),
"TT" => __("Trinidad and Tobago", 'wordfence'),
"TV" => __("Tuvalu", 'wordfence'),
"TW" => __("Taiwan", 'wordfence'),
"TZ" => __("Tanzania, United Republic of", 'wordfence'),
"UA" => __("Ukraine", 'wordfence'),
"UG" => __("Uganda", 'wordfence'),
"UM" => __("United States Minor Outlying Islands", 'wordfence'),
"US" => __("United States", 'wordfence'),
"UY" => __("Uruguay", 'wordfence'),
"UZ" => __("Uzbekistan", 'wordfence'),
"VA" => __("Holy See (Vatican City State)", 'wordfence'),
"VC" => __("Saint Vincent and the Grenadines", 'wordfence'),
"VE" => __("Venezuela", 'wordfence'),
"VG" => __("Virgin Islands, British", 'wordfence'),
"VI" => __("Virgin Islands, U.S.", 'wordfence'),
"VN" => __("Vietnam", 'wordfence'),
"VU" => __("Vanuatu", 'wordfence'),
"WF" => __("Wallis and Futuna", 'wordfence'),
"WS" => __("Samoa", 'wordfence'),
"XK" => __("Kosovo", 'wordfence'),
"YE" => __("Yemen", 'wordfence'),
"YT" => __("Mayotte", 'wordfence'),
"ZA" => __("South Africa", 'wordfence'),
"ZM" => __("Zambia", 'wordfence'),
"ZW" => __("Zimbabwe", 'wordfence'),
);

View File

@@ -0,0 +1,200 @@
<?php
class wfCache {
private static $cacheStats = array();
private static $cacheClearedThisRequest = false;
private static $lastRecursiveDeleteError = false;
public static function removeCaching() {
$cacheType = wfConfig::get('cacheType', false);
if ($cacheType === 'disabled') {
return;
}
if ($cacheType == 'falcon') {
self::addHtaccessCode('remove');
self::updateBlockedIPs('remove');
}
wfConfig::set('cacheType', 'disabled');
$cacheDir = WP_CONTENT_DIR . '/wfcache/';
if (file_exists($cacheDir . '.htaccess')) {
unlink($cacheDir . '.htaccess');
}
self::clearPageCacheSafe();
}
public static function clearPageCacheSafe(){
if(self::$cacheClearedThisRequest){ return; }
self::$cacheClearedThisRequest = true;
self::clearPageCache();
}
public static function clearPageCache(){ //If a clear is in progress this does nothing.
self::$cacheStats = array(
'dirsDeleted' => 0,
'filesDeleted' => 0,
'totalData' => 0,
'totalErrors' => 0,
'error' => '',
);
$cacheDir = WP_CONTENT_DIR . '/wfcache/';
if (!file_exists($cacheDir)) {
return self::$cacheStats;
}
$cacheClearLock = WP_CONTENT_DIR . '/wfcache/clear.lock';
if(! is_file($cacheClearLock)){
if(! touch($cacheClearLock)){
self::$cacheStats['error'] = "Could not create a lock file $cacheClearLock to clear the cache.";
self::$cacheStats['totalErrors']++;
return self::$cacheStats;
}
}
$fp = fopen($cacheClearLock, 'w');
if(! $fp){
self::$cacheStats['error'] = "Could not open the lock file $cacheClearLock to clear the cache. Please make sure the directory is writable by your web server.";
self::$cacheStats['totalErrors']++;
return self::$cacheStats;
}
if(flock($fp, LOCK_EX | LOCK_NB)){ //non blocking exclusive flock attempt. If we get a lock then it continues and returns true. If we don't lock, then return false, don't block and don't clear the cache.
// This logic means that if a cache clear is currently in progress we don't try to clear the cache.
// This prevents web server children from being queued up waiting to be able to also clear the cache.
self::$lastRecursiveDeleteError = false;
self::recursiveDelete(WP_CONTENT_DIR . '/wfcache/');
if(self::$lastRecursiveDeleteError){
self::$cacheStats['error'] = self::$lastRecursiveDeleteError;
self::$cacheStats['totalErrors']++;
}
flock($fp, LOCK_UN);
@unlink($cacheClearLock);
@rmdir($cacheDir);
}
fclose($fp);
return self::$cacheStats;
}
private static function recursiveDelete($dir) {
$files = array_diff(scandir($dir), array('.','..'));
foreach ($files as $file) {
if(is_dir($dir . '/' . $file)){
if(! self::recursiveDelete($dir . '/' . $file)){
return false;
}
} else {
if($file == 'clear.lock'){ continue; } //Don't delete our lock file
$size = filesize($dir . '/' . $file);
if($size){
self::$cacheStats['totalData'] += round($size / 1024);
}
if(strpos($dir, 'wfcache/') === false){
self::$lastRecursiveDeleteError = "Not deleting file in directory $dir because it appears to be in the wrong path.";
self::$cacheStats['totalErrors']++;
return false; //Safety check that we're in a subdir of the cache
}
if(@unlink($dir . '/' . $file)){
self::$cacheStats['filesDeleted']++;
} else {
self::$lastRecursiveDeleteError = "Could not delete file " . $dir . "/" . $file . " : " . wfUtils::getLastError();
self::$cacheStats['totalErrors']++;
return false;
}
}
}
if($dir != WP_CONTENT_DIR . '/wfcache/'){
if(strpos($dir, 'wfcache/') === false){
self::$lastRecursiveDeleteError = "Not deleting directory $dir because it appears to be in the wrong path.";
self::$cacheStats['totalErrors']++;
return false; //Safety check that we're in a subdir of the cache
}
if(@rmdir($dir)){
self::$cacheStats['dirsDeleted']++;
} else {
self::$lastRecursiveDeleteError = "Could not delete directory $dir : " . wfUtils::getLastError();
self::$cacheStats['totalErrors']++;
return false;
}
return true;
} else {
return true;
}
}
public static function addHtaccessCode($action){
if($action != 'remove'){
die("Error: addHtaccessCode must be called with 'remove' as param");
}
$htaccessPath = self::getHtaccessPath();
if(! $htaccessPath){
return "Wordfence could not find your .htaccess file.";
}
$fh = @fopen($htaccessPath, 'r+');
if(! $fh){
$err = error_get_last();
return $err['message'];
}
flock($fh, LOCK_EX);
fseek($fh, 0, SEEK_SET); //start of file
clearstatcache();
$contents = fread($fh, filesize($htaccessPath));
if(! $contents){
fclose($fh);
return "Could not read from $htaccessPath";
}
$contents = preg_replace('/#WFCACHECODE.*WFCACHECODE[\r\s\n\t]*/s', '', $contents);
ftruncate($fh, 0);
fflush($fh);
fseek($fh, 0, SEEK_SET);
fwrite($fh, $contents);
flock($fh, LOCK_UN);
fclose($fh);
return false;
}
/**
* @param $action
* @return bool|string|void
*/
public static function updateBlockedIPs($action){ //'add' or 'remove'
$htaccessPath = self::getHtaccessPath();
if(! $htaccessPath){
return "Wordfence could not find your .htaccess file.";
}
if($action == 'remove'){
$fh = @fopen($htaccessPath, 'r+');
if(! $fh){
$err = error_get_last();
return $err['message'];
}
flock($fh, LOCK_EX);
fseek($fh, 0, SEEK_SET); //start of file
clearstatcache();
$contents = @fread($fh, filesize($htaccessPath));
if(! $contents){
fclose($fh);
return "Could not read from $htaccessPath";
}
$contents = preg_replace('/#WFIPBLOCKS.*WFIPBLOCKS[\r\s\n\t]*/s', '', $contents);
ftruncate($fh, 0);
fflush($fh);
fseek($fh, 0, SEEK_SET);
@fwrite($fh, $contents);
flock($fh, LOCK_UN);
fclose($fh);
return false;
}
return false;
}
public static function getHtaccessPath(){
$homePath = wfUtils::getHomePath();
$htaccessFile = $homePath.'.htaccess';
return $htaccessFile;
}
public static function doNotCache(){
if(! defined('WFDONOTCACHE')){
define('WFDONOTCACHE', true);
}
}
}

View File

@@ -0,0 +1,824 @@
<?php
class wfCentralAPIRequest {
/**
* @var string
*/
private $endpoint;
/**
* @var string
*/
private $method;
/**
* @var null
*/
private $token;
/**
* @var array
*/
private $body;
/**
* @var array
*/
private $args;
/**
* @param string $endpoint
* @param string $method
* @param string|null $token
* @param array $body
* @param array $args
*/
public function __construct($endpoint, $method = 'GET', $token = null, $body = array(), $args = array()) {
$this->endpoint = $endpoint;
$this->method = $method;
$this->token = $token;
$this->body = $body;
$this->args = $args;
}
/**
* Handles an internal error when making a Central API request (e.g., a second sodium_compat library with an
* incompatible interface loading instead or in addition to ours).
*
* @param Exception|Throwable $e
*/
public static function handleInternalCentralAPIError($e) {
error_log('Wordfence encountered an internal Central API error: ' . $e->getMessage());
error_log('Wordfence stack trace: ' . $e->getTraceAsString());
}
public function execute() {
$args = array(
'timeout' => 10,
);
$args = wp_parse_args($this->getArgs(), $args);
$args['method'] = $this->getMethod();
if (empty($args['headers'])) {
$args['headers'] = array();
}
$token = $this->getToken();
if ($token) {
$args['headers']['Authorization'] = 'Bearer ' . $token;
}
if ($this->getBody()) {
$args['headers']['Content-Type'] = 'application/json';
$args['body'] = json_encode($this->getBody());
}
$http = _wp_http_get_object();
$response = $http->request(WORDFENCE_CENTRAL_API_URL_SEC . $this->getEndpoint(), $args);
if (!is_wp_error($response)) {
$body = wp_remote_retrieve_body($response);
$statusCode = wp_remote_retrieve_response_code($response);
// Check if site has been disconnected on Central's end, but the plugin is still trying to connect.
if ($statusCode === 404 && strpos($body, 'Site has been disconnected') !== false) {
// Increment attempt count.
$centralDisconnectCount = get_site_transient('wordfenceCentralDisconnectCount');
set_site_transient('wordfenceCentralDisconnectCount', ++$centralDisconnectCount, 86400);
// Once threshold is hit, disconnect Central.
if ($centralDisconnectCount > 3) {
wfRESTConfigController::disconnectConfig();
}
}
}
return new wfCentralAPIResponse($response);
}
/**
* @return string
*/
public function getEndpoint() {
return $this->endpoint;
}
/**
* @param string $endpoint
*/
public function setEndpoint($endpoint) {
$this->endpoint = $endpoint;
}
/**
* @return string
*/
public function getMethod() {
return $this->method;
}
/**
* @param string $method
*/
public function setMethod($method) {
$this->method = $method;
}
/**
* @return null
*/
public function getToken() {
return $this->token;
}
/**
* @param null $token
*/
public function setToken($token) {
$this->token = $token;
}
/**
* @return array
*/
public function getBody() {
return $this->body;
}
/**
* @param array $body
*/
public function setBody($body) {
$this->body = $body;
}
/**
* @return array
*/
public function getArgs() {
return $this->args;
}
/**
* @param array $args
*/
public function setArgs($args) {
$this->args = $args;
}
}
class wfCentralAPIResponse {
public static function parseErrorJSON($json) {
$data = json_decode($json, true);
if (is_array($data) && array_key_exists('message', $data)) {
return $data['message'];
}
return $json;
}
/**
* @var array|null
*/
private $response;
/**
* @param array $response
*/
public function __construct($response = null) {
$this->response = $response;
}
public function getStatusCode() {
return wp_remote_retrieve_response_code($this->getResponse());
}
public function getBody() {
return wp_remote_retrieve_body($this->getResponse());
}
public function getJSONBody() {
return json_decode($this->getBody(), true);
}
public function isError() {
if (is_wp_error($this->getResponse())) {
return true;
}
$statusCode = $this->getStatusCode();
return !($statusCode >= 200 && $statusCode < 300);
}
public function returnErrorArray() {
return array(
'err' => 1,
'errorMsg' => sprintf(
/* translators: 1. HTTP status code. 2. Error message. */
__('HTTP %1$d received from Wordfence Central: %2$s', 'wordfence'),
$this->getStatusCode(), $this->parseErrorJSON($this->getBody())),
);
}
/**
* @return array|null
*/
public function getResponse() {
return $this->response;
}
/**
* @param array|null $response
*/
public function setResponse($response) {
$this->response = $response;
}
}
class wfCentralAuthenticatedAPIRequest extends wfCentralAPIRequest {
private $retries = 3;
/**
* @param string $endpoint
* @param string $method
* @param array $body
* @param array $args
*/
public function __construct($endpoint, $method = 'GET', $body = array(), $args = array()) {
parent::__construct($endpoint, $method, null, $body, $args);
}
/**
* @return mixed|null
* @throws wfCentralAPIException
*/
public function getToken() {
$token = parent::getToken();
if ($token) {
return $token;
}
$token = get_transient('wordfenceCentralJWT' . wfConfig::get('wordfenceCentralSiteID'));
if ($token) {
return $token;
}
for ($i = 0; $i < $this->retries; $i++) {
try {
$token = $this->fetchToken();
break;
} catch (wfCentralConfigurationException $e) {
wfConfig::set('wordfenceCentralConfigurationIssue', true);
throw new wfCentralAPIException(__('Fetching token for Wordfence Central authentication due to configuration issue.', 'wordfence'));
} catch (wfCentralAPIException $e) {
continue;
}
}
if (empty($token)) {
if (isset($e)) {
throw $e;
} else {
throw new wfCentralAPIException(__('Unable to authenticate with Wordfence Central.', 'wordfence'));
}
}
$tokenContents = wfJWT::extractTokenContents($token);
if (!empty($tokenContents['body']['exp'])) {
set_transient('wordfenceCentralJWT' . wfConfig::get('wordfenceCentralSiteID'), $token, $tokenContents['body']['exp'] - time());
}
wfConfig::set('wordfenceCentralConfigurationIssue', false);
return $token;
}
public function fetchToken() {
require_once(WORDFENCE_PATH . '/lib/sodium_compat_fast.php');
$defaultArgs = array(
'timeout' => 6,
);
$siteID = wfConfig::get('wordfenceCentralSiteID');
if (!$siteID) {
throw new wfCentralAPIException(__('Wordfence Central site ID has not been created yet.', 'wordfence'));
}
$secretKey = wfConfig::get('wordfenceCentralSecretKey');
if (!$secretKey) {
throw new wfCentralAPIException(__('Wordfence Central secret key has not been created yet.', 'wordfence'));
}
// Pull down nonce.
$request = new wfCentralAPIRequest(sprintf('/site/%s/login', $siteID), 'GET', null, array(), $defaultArgs);
$nonceResponse = $request->execute();
if ($nonceResponse->isError()) {
$errorArray = $nonceResponse->returnErrorArray();
throw new wfCentralAPIException($errorArray['errorMsg']);
}
$body = $nonceResponse->getJSONBody();
if (!is_array($body) || !isset($body['nonce'])) {
throw new wfCentralAPIException(__('Invalid response received from Wordfence Central when fetching nonce.', 'wordfence'));
}
$nonce = $body['nonce'];
// Sign nonce to pull down JWT.
$data = $nonce . '|' . $siteID;
try {
$signature = ParagonIE_Sodium_Compat::crypto_sign_detached($data, $secretKey);
}
catch (SodiumException $e) {
throw new wfCentralConfigurationException('Signing failed, likely due to malformed secret key', $e);
}
$request = new wfCentralAPIRequest(sprintf('/site/%s/login', $siteID), 'POST', null, array(
'data' => $data,
'signature' => ParagonIE_Sodium_Compat::bin2hex($signature),
), $defaultArgs);
$authResponse = $request->execute();
if ($authResponse->isError()) {
$errorArray = $authResponse->returnErrorArray();
throw new wfCentralAPIException($errorArray['errorMsg']);
}
$body = $authResponse->getJSONBody();
if (!is_array($body)) {
throw new wfCentralAPIException(__('Invalid response received from Wordfence Central when fetching token.', 'wordfence'));
}
if (!isset($body['jwt'])) { // Possible authentication error.
throw new wfCentralAPIException(__('Unable to authenticate with Wordfence Central.', 'wordfence'));
}
return $body['jwt'];
}
}
class wfCentralAPIException extends Exception {
}
class wfCentralConfigurationException extends RuntimeException {
public function __construct($message, $previous = null) {
parent::__construct($message, 0, $previous);
}
}
class wfCentral {
/**
* @return bool
*/
public static function isSupported() {
return function_exists('register_rest_route') && version_compare(phpversion(), '5.3', '>=');
}
/**
* @return bool
*/
public static function isConnected() {
return self::isSupported() && ((bool) self::_isConnected());
}
/**
* @return bool
*/
public static function isPartialConnection() {
return !self::_isConnected() && wfConfig::get('wordfenceCentralSiteID');
}
public static function _isConnected($forceUpdate = false) {
static $isConnected;
if (!isset($isConnected) || $forceUpdate) {
$isConnected = wfConfig::get('wordfenceCentralConnected', false);
}
return $isConnected;
}
/**
* @param array $issue
* @return bool|wfCentralAPIResponse
*/
public static function sendIssue($issue) {
return self::sendIssues(array($issue));
}
/**
* @param $issues
* @return bool|wfCentralAPIResponse
*/
public static function sendIssues($issues) {
$data = array();
foreach ($issues as $issue) {
$issueData = array(
'type' => 'issue',
'attributes' => $issue,
);
if (array_key_exists('id', $issueData)) {
$issueData['id'] = $issue['id'];
}
$data[] = $issueData;
}
$siteID = wfConfig::get('wordfenceCentralSiteID');
$request = new wfCentralAuthenticatedAPIRequest('/site/' . $siteID . '/issues', 'POST', array(
'data' => $data,
));
try {
$response = $request->execute();
return $response;
}
catch (wfCentralAPIException $e) {
error_log($e);
}
catch (Exception $e) {
wfCentralAPIRequest::handleInternalCentralAPIError($e);
}
catch (Throwable $t) {
wfCentralAPIRequest::handleInternalCentralAPIError($t);
}
return false;
}
/**
* @param int $issueID
* @return bool|wfCentralAPIResponse
*/
public static function deleteIssue($issueID) {
return self::deleteIssues(array($issueID));
}
/**
* @param $issues
* @return bool|wfCentralAPIResponse
*/
public static function deleteIssues($issues) {
$siteID = wfConfig::get('wordfenceCentralSiteID');
$request = new wfCentralAuthenticatedAPIRequest('/site/' . $siteID . '/issues', 'DELETE', array(
'data' => array(
'type' => 'issue-list',
'attributes' => array(
'ids' => $issues,
)
),
));
try {
$response = $request->execute();
return $response;
}
catch (wfCentralAPIException $e) {
error_log($e);
}
catch (Exception $e) {
wfCentralAPIRequest::handleInternalCentralAPIError($e);
}
catch (Throwable $t) {
wfCentralAPIRequest::handleInternalCentralAPIError($t);
}
return false;
}
/**
* @return bool|wfCentralAPIResponse
*/
public static function deleteNewIssues() {
$siteID = wfConfig::get('wordfenceCentralSiteID');
$request = new wfCentralAuthenticatedAPIRequest('/site/' . $siteID . '/issues', 'DELETE', array(
'data' => array(
'type' => 'issue-list',
'attributes' => array(
'status' => 'new',
)
),
));
try {
$response = $request->execute();
return $response;
}
catch (wfCentralAPIException $e) {
error_log($e);
}
catch (Exception $e) {
wfCentralAPIRequest::handleInternalCentralAPIError($e);
}
catch (Throwable $t) {
wfCentralAPIRequest::handleInternalCentralAPIError($t);
}
return false;
}
/**
* @param array $types Array of issue types to delete
* @param string $status Issue status to delete
* @return bool|wfCentralAPIResponse
*/
public static function deleteIssueTypes($types, $status = 'new') {
$siteID = wfConfig::get('wordfenceCentralSiteID');
$request = new wfCentralAuthenticatedAPIRequest('/site/' . $siteID . '/issues', 'DELETE', array(
'data' => array(
'type' => 'issue-list',
'attributes' => array(
'types' => $types,
'status' => $status,
)
),
));
try {
$response = $request->execute();
return $response;
}
catch (wfCentralAPIException $e) {
error_log($e);
}
catch (Exception $e) {
wfCentralAPIRequest::handleInternalCentralAPIError($e);
}
catch (Throwable $t) {
wfCentralAPIRequest::handleInternalCentralAPIError($t);
}
return false;
}
public static function requestConfigurationSync() {
if (! wfCentral::isConnected() || !self::$syncConfig) {
return;
}
$endpoint = '/site/'.wfConfig::get('wordfenceCentralSiteID').'/config';
$args = array('timeout' => 0.01, 'blocking' => false);
$request = new wfCentralAuthenticatedAPIRequest($endpoint, 'POST', array(), $args);
try {
$request->execute();
}
catch (Exception $e) {
// We can safely ignore an error here for now.
}
catch (Throwable $t) {
wfCentralAPIRequest::handleInternalCentralAPIError($t);
}
}
protected static $syncConfig = true;
public static function preventConfigurationSync() {
self::$syncConfig = false;
}
/**
* @param $scan
* @param $running
* @return bool|wfCentralAPIResponse
*/
public static function updateScanStatus($scan = null) {
if ($scan === null) {
$scan = wfConfig::get_ser('scanStageStatuses');
if (!is_array($scan)) {
$scan = array();
}
}
wfScanner::shared()->flushSummaryItems();
$siteID = wfConfig::get('wordfenceCentralSiteID');
$running = wfScanner::shared()->isRunning();
$request = new wfCentralAuthenticatedAPIRequest('/site/' . $siteID . '/scan', 'PATCH', array(
'data' => array(
'type' => 'scan',
'attributes' => array(
'running' => $running,
'scan' => $scan,
'scan-summary' => wfConfig::get('wf_summaryItems'),
),
),
));
try {
$response = $request->execute();
return $response;
}
catch (wfCentralAPIException $e) {
error_log($e);
}
catch (Exception $e) {
wfCentralAPIRequest::handleInternalCentralAPIError($e);
}
catch (Throwable $t) {
wfCentralAPIRequest::handleInternalCentralAPIError($t);
}
return false;
}
/**
* @param string $event
* @param array $data
* @param callable|null $alertCallback
*/
public static function sendSecurityEvent($event, $data = array(), $alertCallback = null, $sendImmediately = false) {
return self::sendSecurityEvents(array(array('type' => $event, 'data' => $data, 'event_time' => microtime(true))), $alertCallback, $sendImmediately);
}
public static function sendSecurityEvents($events, $alertCallback = null, $sendImmediately = false) {
if (empty($events)) {
return true;
}
if (!$sendImmediately && defined('DISABLE_WP_CRON') && DISABLE_WP_CRON) {
$sendImmediately = true;
}
$alerted = false;
if (!self::pluginAlertingDisabled() && is_callable($alertCallback)) {
call_user_func($alertCallback);
$alerted = true;
}
if ($sendImmediately) {
$payload = array();
foreach ($events as $e) {
$payload[] = array(
'type' => 'security-event',
'attributes' => array(
'type' => $e['type'],
'data' => $e['data'],
'event_time' => $e['event_time'],
),
);
}
$siteID = wfConfig::get('wordfenceCentralSiteID');
$request = new wfCentralAuthenticatedAPIRequest('/site/' . $siteID . '/security-events', 'POST', array(
'data' => $payload,
));
try {
// Attempt to send the security events to Central.
$response = $request->execute();
}
catch (wfCentralAPIException $e) {
// If we didn't alert previously, notify the user now in the event Central is down.
if (!$alerted && is_callable($alertCallback)) {
call_user_func($alertCallback);
}
return false;
}
catch (Exception $e) {
wfCentralAPIRequest::handleInternalCentralAPIError($e);
return false;
}
catch (Throwable $t) {
wfCentralAPIRequest::handleInternalCentralAPIError($t);
return false;
}
}
else {
$wfdb = new wfDB();
$table_wfSecurityEvents = wfDB::networkTable('wfSecurityEvents');
$query = "INSERT INTO {$table_wfSecurityEvents} (`type`, `data`, `event_time`, `state`, `state_timestamp`) VALUES ";
$query .= implode(', ', array_fill(0, count($events), "('%s', '%s', %f, 'new', NOW())"));
$immediateSendTypes = array('adminLogin',
'adminLoginNewLocation',
'nonAdminLogin',
'nonAdminLoginNewLocation',
'wordfenceDeactivated',
'wafDeactivated',
'autoUpdate');
$args = array();
foreach ($events as $e) {
$sendImmediately = $sendImmediately || in_array($e['type'], $immediateSendTypes);
$args[] = $e['type'];
$args[] = json_encode($e['data']);
$args[] = $e['event_time'];
}
$wfdb->queryWriteArray($query, $args);
if (($ts = self::isScheduledSecurityEventCronOverdue()) || $sendImmediately) {
if ($ts) {
self::unscheduleSendPendingSecurityEvents($ts);
}
self::sendPendingSecurityEvents();
}
else {
self::scheduleSendPendingSecurityEvents();
}
}
return true;
}
public static function sendPendingSecurityEvents() {
$wfdb = new wfDB();
$table_wfSecurityEvents = wfDB::networkTable('wfSecurityEvents');
$rawEvents = $wfdb->querySelect("SELECT * FROM {$table_wfSecurityEvents} WHERE `state` = 'new' ORDER BY `id` ASC LIMIT 100");
if (empty($rawEvents))
return;
$ids = array();
$events = array();
foreach ($rawEvents as $r) {
$ids[] = intval($r['id']);
$events[] = array(
'type' => $r['type'],
'data' => json_decode($r['data'], true),
'event_time' => $r['event_time'],
);
}
$idParam = '(' . implode(', ', $ids) . ')';
$wfdb->queryWrite("UPDATE {$table_wfSecurityEvents} SET `state` = 'sending', `state_timestamp` = NOW() WHERE `id` IN {$idParam}");
if (self::sendSecurityEvents($events, null, true)) {
$wfdb->queryWrite("UPDATE {$table_wfSecurityEvents} SET `state` = 'sent', `state_timestamp` = NOW() WHERE `id` IN {$idParam}");
self::checkForUnsentSecurityEvents();
}
else {
$wfdb->queryWrite("UPDATE {$table_wfSecurityEvents} SET `state` = 'new', `state_timestamp` = NOW() WHERE `id` IN {$idParam}");
self::scheduleSendPendingSecurityEvents();
}
}
public static function scheduleSendPendingSecurityEvents() {
if (!defined('DONOTCACHEDB')) { define('DONOTCACHEDB', true); }
$notMainSite = is_multisite() && !is_main_site();
if ($notMainSite) {
global $current_site;
switch_to_blog($current_site->blog_id);
}
if (!wp_next_scheduled('wordfence_batchSendSecurityEvents')) {
wp_schedule_single_event(time() + 300, 'wordfence_batchSendSecurityEvents');
}
if ($notMainSite) {
restore_current_blog();
}
}
public static function unscheduleSendPendingSecurityEvents($timestamp) {
if (!defined('DONOTCACHEDB')) { define('DONOTCACHEDB', true); }
$notMainSite = is_multisite() && !is_main_site();
if ($notMainSite) {
global $current_site;
switch_to_blog($current_site->blog_id);
}
if (!wp_next_scheduled('wordfence_batchSendSecurityEvents')) {
wp_unschedule_event($timestamp, 'wordfence_batchSendSecurityEvents');
}
if ($notMainSite) {
restore_current_blog();
}
}
public static function isScheduledSecurityEventCronOverdue() {
if (!defined('DONOTCACHEDB')) { define('DONOTCACHEDB', true); }
$notMainSite = is_multisite() && !is_main_site();
if ($notMainSite) {
global $current_site;
switch_to_blog($current_site->blog_id);
}
$overdue = false;
if ($ts = wp_next_scheduled('wordfence_batchSendSecurityEvents')) {
if ((time() - $ts) > 900) {
$overdue = $ts;
}
}
if ($notMainSite) {
restore_current_blog();
}
return $overdue;
}
public static function checkForUnsentSecurityEvents() {
$wfdb = new wfDB();
$table_wfSecurityEvents = wfDB::networkTable('wfSecurityEvents');
$wfdb->queryWrite("UPDATE {$table_wfSecurityEvents} SET `state` = 'new', `state_timestamp` = NOW() WHERE `state` = 'sending' AND `state_timestamp` < DATE_SUB(NOW(), INTERVAL 30 MINUTE)");
$count = $wfdb->querySingle("SELECT COUNT(*) AS cnt FROM {$table_wfSecurityEvents} WHERE `state` = 'new'");
if ($count) {
self::scheduleSendPendingSecurityEvents();
}
}
public static function trimSecurityEvents() {
$wfdb = new wfDB();
$table_wfSecurityEvents = wfDB::networkTable('wfSecurityEvents');
$count = $wfdb->querySingle("SELECT COUNT(*) AS cnt FROM {$table_wfSecurityEvents}");
if ($count > 20000) {
$wfdb->truncate($table_wfSecurityEvents); //Similar behavior to other logged data, assume possible DoS so truncate
}
else if ($count > 1000) {
$wfdb->queryWrite("DELETE FROM {$table_wfSecurityEvents} ORDER BY id ASC LIMIT %d", $count - 1000);
}
}
/**
* @param $event
* @param array $data
* @param callable|null $alertCallback
*/
public static function sendAlertCallback($event, $data = array(), $alertCallback = null) {
if (is_callable($alertCallback)) {
call_user_func($alertCallback);
}
}
public static function pluginAlertingDisabled() {
if (!self::isConnected()) {
return false;
}
return wfConfig::get('wordfenceCentralPluginAlertingDisabled', false);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,192 @@
<?php
require_once(dirname(__FILE__) . '/wfUtils.php');
class wfCrawl {
const GOOGLE_BOT_VERIFIED = 'verified';
const GOOGLE_BOT_FAKE = 'fakeBot';
const GOOGLE_BOT_UNDETERMINED = 'undetermined';
public static function isCrawler($UA){
$browscap = new wfBrowscap();
$b = $browscap->getBrowser($UA);
if (!$b || $b['Parent'] == 'DefaultProperties') {
$IP = wfUtils::getIP();
return !wfLog::isHumanRequest($IP, $UA);
}
else if (isset($b['Crawler']) && $b['Crawler']) {
return true;
}
return false;
}
public static function verifyCrawlerPTR($hostPattern, $IP){
$table = wfDB::networkTable('wfCrawlers');
$db = new wfDB();
$IPn = wfUtils::inet_pton($IP);
$status = $db->querySingle("select status from $table where IP=%s and patternSig=UNHEX(MD5('%s')) and lastUpdate > unix_timestamp() - %d", $IPn, $hostPattern, WORDFENCE_CRAWLER_VERIFY_CACHE_TIME);
if($status){
if($status == 'verified'){
return true;
} else {
return false;
}
}
$host = wfUtils::reverseLookup($IP);
if(! $host){
$db->queryWrite("insert into $table (IP, patternSig, status, lastUpdate, PTR) values (%s, UNHEX(MD5('%s')), '%s', unix_timestamp(), '%s') ON DUPLICATE KEY UPDATE status='%s', lastUpdate=unix_timestamp(), PTR='%s'", $IPn, $hostPattern, 'noPTR', '', 'noPTR', '');
return false;
}
if(preg_match($hostPattern, $host)){
$resultIPs = wfUtils::resolveDomainName($host);
$addrsMatch = false;
foreach($resultIPs as $resultIP){
if($resultIP == $IP){
$addrsMatch = true;
break;
}
}
if($addrsMatch){
$db->queryWrite("insert into $table (IP, patternSig, status, lastUpdate, PTR) values (%s, UNHEX(MD5('%s')), '%s', unix_timestamp(), '%s') ON DUPLICATE KEY UPDATE status='%s', lastUpdate=unix_timestamp(), PTR='%s'", $IPn, $hostPattern, 'verified', $host, 'verified', $host);
return true;
} else {
$db->queryWrite("insert into $table (IP, patternSig, status, lastUpdate, PTR) values (%s, UNHEX(MD5('%s')), '%s', unix_timestamp(), '%s') ON DUPLICATE KEY UPDATE status='%s', lastUpdate=unix_timestamp(), PTR='%s'", $IPn, $hostPattern, 'fwdFail', $host, 'fwdFail', $host);
return false;
}
} else {
$db->queryWrite("insert into $table (IP, patternSig, status, lastUpdate, PTR) values (%s, UNHEX(MD5('%s')), '%s', unix_timestamp(), '%s') ON DUPLICATE KEY UPDATE status='%s', lastUpdate=unix_timestamp(), PTR='%s'", $IPn, $hostPattern, 'badPTR', $host, 'badPTR', $host);
return false;
}
}
public static function isGooglebot($userAgent = null){
if ($userAgent === null) {
$userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
}
return (bool) preg_match('/Googlebot\/\d\.\d/', $userAgent);
}
public static function isGoogleCrawler($userAgent = null){
if ($userAgent === null) {
$userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
}
foreach (self::$googPat as $pat) {
if (preg_match($pat . 'i', $userAgent)) {
return true;
}
}
return false;
}
private static $googPat = array(
'@^Mozilla/5\\.0 \\(.*Google Keyword Tool.*\\)$@',
'@^Mozilla/5\\.0 \\(.*Feedfetcher\\-Google.*\\)$@',
'@^Feedfetcher\\-Google\\-iGoogleGadgets.*$@',
'@^searchbot admin\\@google\\.com$@',
'@^Google\\-Site\\-Verification.*$@',
'@^Google OpenSocial agent.*$@',
'@^.*Googlebot\\-Mobile/2\\..*$@',
'@^AdsBot\\-Google\\-Mobile.*$@',
'@^google \\(.*Enterprise.*\\)$@',
'@^Mediapartners\\-Google.*$@',
'@^GoogleFriendConnect.*$@',
'@^googlebot\\-urlconsole$@',
'@^.*Google Web Preview.*$@',
'@^Feedfetcher\\-Google.*$@',
'@^AppEngine\\-Google.*$@',
'@^Googlebot\\-Video.*$@',
'@^Googlebot\\-Image.*$@',
'@^Google\\-Sitemaps.*$@',
'@^Googlebot/Test.*$@',
'@^Googlebot\\-News.*$@',
'@^.*Googlebot/2\\.1.*$@',
'@^AdsBot\\-Google.*$@',
'@^Google$@'
);
/**
* Has correct user agent and PTR record points to .googlebot.com domain.
*
* @param string|null $ip
* @param string|null $ua
* @return bool
*/
public static function isVerifiedGoogleCrawler($ip = null, $ua = null) {
static $verified;
if (!isset($verified)) {
$verified = array();
}
if ($ip === null) {
$ip = wfUtils::getIP();
}
if ($ip === null || $ip === false) { //Likely a CLI execution
return false;
}
if (array_key_exists($ip, $verified)) {
return $verified[$ip];
}
if (self::isGoogleCrawler($ua)) {
if (self::verifyCrawlerPTR(wordfence::getLog()->getGooglePattern(), $ip)) {
$verified[$ip] = true;
return $verified[$ip];
}
$noc1Status = self::verifyGooglebotViaNOC1($ip);
if ($noc1Status == self::GOOGLE_BOT_VERIFIED) {
$verified[$ip] = true;
return $verified[$ip];
}
else if ($noc1Status == self::GOOGLE_BOT_FAKE) {
$verified[$ip] = false;
return $verified[$ip];
}
return true; //We were unable to successfully validate Googlebot status so default to being permissive
}
$verified[$ip] = false;
return $verified[$ip];
}
/**
* Attempts to verify whether an IP claiming to be Googlebot is actually Googlebot.
*
* @param string|null $ip
* @return string
*/
public static function verifyGooglebotViaNOC1($ip = null) {
$table = wfDB::networkTable('wfCrawlers');
if ($ip === null) {
$ip = wfUtils::getIP();
}
$db = new wfDB();
$IPn = wfUtils::inet_pton($ip);
$patternSig = 'googlenoc1';
$status = $db->querySingle("select status from $table
where IP=%s
and patternSig=UNHEX(MD5('%s'))
and lastUpdate > unix_timestamp() - %d",
$IPn,
$patternSig,
WORDFENCE_CRAWLER_VERIFY_CACHE_TIME);
if ($status === 'verified') {
return self::GOOGLE_BOT_VERIFIED;
} else if ($status === 'fakeBot') {
return self::GOOGLE_BOT_FAKE;
}
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
try {
$data = $api->call('verify_googlebot', array(
'ip' => $ip,
));
if (is_array($data) && !empty($data['verified'])) {
// Cache results
$db->queryWrite("INSERT INTO {$table} (IP, patternSig, status, lastUpdate) VALUES ('%s', UNHEX(MD5('%s')), '%s', unix_timestamp()) ON DUPLICATE KEY UPDATE status = VALUES(status), lastUpdate = VALUES(lastUpdate)", $IPn, $patternSig, 'verified');
return self::GOOGLE_BOT_VERIFIED;
} else {
$db->queryWrite("INSERT INTO {$table} (IP, patternSig, status, lastUpdate) VALUES ('%s', UNHEX(MD5('%s')), '%s', unix_timestamp()) ON DUPLICATE KEY UPDATE status = VALUES(status), lastUpdate = VALUES(lastUpdate)", $IPn, $patternSig, 'fakeBot');
self::GOOGLE_BOT_FAKE;
}
} catch (Exception $e) {
// Do nothing, bail
}
return self::GOOGLE_BOT_UNDETERMINED;
}
}

View File

@@ -0,0 +1,183 @@
<?php
class wfCredentialsController {
const UNCACHED = 'uncached';
const NOT_LEAKED = 'not-leaked';
const LEAKED = 'leaked';
const ALLOW_LEGACY_2FA_OPTION = 'allowLegacy2FA';
const DISABLE_LEGACY_2FA_OPTION = 'disableLegacy2FA';
public static function allowLegacy2FA() {
return wfConfig::get(self::ALLOW_LEGACY_2FA_OPTION, false);
}
public static function useLegacy2FA() {
if (!self::allowLegacy2FA()) {
return false;
}
return !wfConfig::get(self::DISABLE_LEGACY_2FA_OPTION, false);
}
public static function hasOld2FARecords() {
$twoFactorUsers = wfConfig::get_ser('twoFactorUsers', array());
if (is_array($twoFactorUsers) && !empty($twoFactorUsers)) {
foreach ($twoFactorUsers as &$t) {
if ($t[3] == 'activated') {
$user = new WP_User($t[0]);
if ($user instanceof WP_User && $user->exists()) {
return true;
}
}
}
}
return false;
}
public static function hasNew2FARecords() {
if (version_compare(phpversion(), '5.3', '>=') && class_exists('\WordfenceLS\Controller_DB')) {
global $wpdb;
$table = WFLSPHP52Compatability::secrets_table();
return !!intval($wpdb->get_var("SELECT COUNT(*) FROM `{$table}`"));
}
return false;
}
/**
* Queries the API and returns whether or not the password exists in the breach database.
*
* @param string $login
* @param string $password
* @return bool
*/
public static function isLeakedPassword($login, $password) {
$sha1 = strtoupper(hash('sha1', $password));
$prefix = substr($sha1, 0, 5);
$ssl_verify = (bool) wfConfig::get('ssl_verify');
$args = array(
'timeout' => 5,
'user-agent' => "Wordfence.com UA " . (defined('WORDFENCE_VERSION') ? WORDFENCE_VERSION : '[Unknown version]'),
'sslverify' => $ssl_verify,
'headers' => array('Referer' => false),
);
if (!$ssl_verify) { // Some versions of cURL will complain that SSL verification is disabled but the CA bundle was supplied.
$args['sslcertificates'] = false;
}
$response = wp_remote_get(sprintf(WORDFENCE_BREACH_URL_BASE_SEC . "%s.txt", $prefix), $args);
if (!is_wp_error($response)) {
$data = wp_remote_retrieve_body($response);
$lines = explode("\n", $data);
foreach ($lines as $l) {
$components = explode(":", $l);
$teshSHA1 = $prefix . strtoupper($components[0]);
if (hash_equals($sha1, $teshSHA1)) {
return true;
}
}
}
return false;
}
/**
* Returns the transient key for the given user.
*
* @param WP_User $user
* @return string
*/
protected static function _cachedCredentialStatusKey($user) {
$key = 'wfcredentialstatus_' . $user->ID;
return $key;
}
/**
* Returns the cached credential status for the given user: self::UNCACHED, self::NOT_LEAKED, or self::LEAKED.
*
* @param WP_User $user
* @return string
*/
public static function cachedCredentialStatus($user) {
$key = self::_cachedCredentialStatusKey($user);
$value = get_transient($key);
if ($value === false) {
return self::UNCACHED;
}
$status = substr($value, 0, 1);
if (strlen($value) > 1) {
if (!hash_equals(substr($value, 1), hash('sha256', $user->user_pass))) { //Different hash but our clear function wasn't called so treat it as uncached
return self::UNCACHED;
}
}
if ($status) {
return self::LEAKED;
}
return self::NOT_LEAKED;
}
/**
* Stores a cached leak value for the given user.
*
* @param WP_User $user
* @param bool $isLeaked
*/
public static function setCachedCredentialStatus($user, $isLeaked) {
$key = self::_cachedCredentialStatusKey($user);
set_transient($key, ($isLeaked ? '1' : '0') . hash('sha256', $user->user_pass), 3600);
}
/**
* Clears the cache for the given user.
*
* @param WP_User $user
*/
public static function clearCachedCredentialStatus($user) {
$key = self::_cachedCredentialStatusKey($user);
delete_transient($key);
}
/**
* Returns whether or not we've seen a successful login from $ip for the given user.
*
* @param WP_User $user
* @param string $ip
* @return bool
*/
public static function hasPreviousLoginFromIP($user, $ip) {
global $wpdb;
$table_wfLogins = wfDB::networkTable('wfLogins');
$id = property_exists($user, 'ID') ? $user->ID : 0;
if ($id == 0) {
return false;
}
$result = $wpdb->get_row($wpdb->prepare("SELECT id FROM {$table_wfLogins} WHERE action = 'loginOK' AND userID = %d AND IP = %s LIMIT 0,1", $id, wfUtils::inet_pton($ip)), ARRAY_A);
if (is_array($result)) {
return true;
}
$lastAdminLogin = wfConfig::get_ser('lastAdminLogin');
if (is_array($lastAdminLogin) && isset($lastAdminLogin['userID']) && isset($lastAdminLogin['IP'])) {
if ($lastAdminLogin['userID'] == $id && wfUtils::inet_pton($lastAdminLogin['IP']) == wfUtils::inet_pton($ip)) {
return true;
}
return false;
}
//Final check -- if the IP recorded at plugin activation matches, let it through. This is __only__ checked when we don't have any other record of an admin login.
$activatingIP = wfConfig::get('activatingIP');
if (wfUtils::isValidIP($activatingIP)) {
if (wfUtils::inet_pton($activatingIP) == wfUtils::inet_pton($ip)) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,86 @@
<?php
class wfCrypt {
private static function getPubKey(){
#Command to generate our keypair was: openssl req -x509 -newkey rsa:2048 -keyout mycert.key -out mycert.pem -nodes -subj "/C=US/ST=Washington/L=Seattle/O=Wordfence/OU=IT/CN=wordfence.com" -days 7300
#This is a 2048 bit key using SHA256 with RSA.
$key = <<<ENDKEY
-----BEGIN CERTIFICATE-----
MIIDrTCCApWgAwIBAgIJAIg6Va5tcvwyMA0GCSqGSIb3DQEBCwUAMG0xCzAJBgNV
BAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMRIw
EAYDVQQKDAlXb3JkZmVuY2UxCzAJBgNVBAsMAklUMRYwFAYDVQQDDA13b3JkZmVu
Y2UuY29tMB4XDTE1MDMxMjA1NTIzMFoXDTM1MDMwNzA1NTIzMFowbTELMAkGA1UE
BhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxEjAQ
BgNVBAoMCVdvcmRmZW5jZTELMAkGA1UECwwCSVQxFjAUBgNVBAMMDXdvcmRmZW5j
ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/9Ogj1PIQsuZu
dTUNWlG0zaDNWpeY1ZiB/6oBS/YXkGFuG8R/nZ/kYsRmBm6yRp/3jC/HiPjg+7Zc
bA/CKoHdUlNjFZ+10DmS369wVX+c0oV9f720b/a0xN0qeKxJTiN2NsAl5szYv2CQ
Bvzjeb5VfKgrfV9tgYr38swudxvexponYaK0OlDL3u/Xca4SLRKmB+ZYCcZJttoG
SNFsQMlLHWWmM0FJH9qZ3x8MtRM5KsNEWO+/op511Rr36ZnLJdzUnETsaxHKwuCv
0+D9b0mwk8K/c67l63v4+zywXNkdYIslgo7Aeeyb6t0lyyfruXutEyMinmApACT2
sDMAbYk7AgMBAAGjUDBOMB0GA1UdDgQWBBTstr/AoPQyLLIt4/peFSjj0FFXHzAf
BgNVHSMEGDAWgBTstr/AoPQyLLIt4/peFSjj0FFXHzAMBgNVHRMEBTADAQH/MA0G
CSqGSIb3DQEBCwUAA4IBAQA9HsK+XdZh2MGP2SDdggA+MxkNBCCFBtcsmQrpiLUW
67xt59FPRMwTgSA9Lt8uqcWaXoHXiaTnXTRtN/BKZR0F71HQfiV6zy511blIRlk2
nV+vYzwLUENCZ31hQEZsY+uYqBSTiHecUKohn8A9pOOEpis2YEn2zVo4cobdyGa1
zCnaAN99KT8s9lOO0UW0J52qZhvv4y8YhELtrXKBsFatGEsVIM0NFI+ZDsNpMnSQ
cmUtLiIJtk5hxNbOaIz2vzbOkbzJ3ehzODJ1X5rya7X0v2akLLhwP9jqz5ua6ttP
duLv4Q6v3LY6pwDoyKQMDqNNxVjaFmx5HyFWRPofpu/T
-----END CERTIFICATE-----
ENDKEY;
return $key;
}
public static function makeSymHexKey($length){
return bin2hex(wfWAFUtils::random_bytes($length / 2));
}
public static function pubCrypt($symKey){ //encrypts a symmetric key and returns it base64
openssl_public_encrypt($symKey, $encSymKey, self::getPubKey(), OPENSSL_PKCS1_OAEP_PADDING); //The default OPENSSL_PKCS1_PADDING is deprecated.
return base64_encode($encSymKey);
}
/**
* Returns the payload symmetrically encrypted and signed by the noc1 public key. The payload is converted to JSON,
* encrypted using a randomly-generated symmetric key, and then hashed and signed with the noc1 public key.
*
* This is NOT cryptographically secure for verifying that this server sent or was aware of the context of the
* message, rather it is intended to be used in tandem with verification via another method (e.g., a call that
* validates due to the site URL matching the license key or noc1 does a call itself to the server to retrieve the
* encrypted payload). It is solely a means to provide data to noc1 that only it can read.
*
* @param array $payload
* @return array The encrypted and signed payload in the form array('message' => <encrypted message in hex>, 'signature' => <signature in hex>).
*/
public static function noc1_encrypt($payload) {
$payloadJSON = json_encode($payload);
$keyData = file_get_contents(dirname(__FILE__) . '/noc1.key');
$key = @openssl_get_publickey($keyData);
if ($key !== false) {
$symmetricKey = wfWAFUtils::random_bytes(32);
$iv = wfWAFUtils::random_bytes(16);
$encrypted = @openssl_encrypt($payloadJSON, 'aes-256-cbc', $symmetricKey, OPENSSL_RAW_DATA, $iv);
if ($encrypted !== false) {
$success = openssl_public_encrypt($symmetricKey, $symmetricKeyEncrypted, $key, OPENSSL_PKCS1_OAEP_PADDING);
if ($success) {
$message = $iv . $symmetricKeyEncrypted . $encrypted;
$signatureRaw = hash('sha256', $message, true);
$success = openssl_public_encrypt($signatureRaw, $signature, $key, OPENSSL_PKCS1_OAEP_PADDING);
if ($success) {
$package = array('message' => bin2hex($message), 'signature' => bin2hex($signature));
return $package;
}
}
}
}
return array();
}
/**
* Returns a SHA256 HMAC for $payload using the local long key.
*
* @param $payload
* @return false|string
*/
public static function local_sign($payload) {
return hash_hmac('sha256', $payload, wfConfig::get('longEncKey'));
}
}

View File

@@ -0,0 +1,46 @@
<?php
class wfCurlInterceptionFailedException extends RuntimeException {
}
class wfCurlInterceptor {
const HOOK_NAME = 'http_api_curl';
private $handle = null;
private $options = array();
private $requireInterception;
public function __construct($requireInterception = true) {
$this->requireInterception = $requireInterception;
}
private function reset() {
$this->handle = null;
}
public function setOption($option, $value) {
$this->options[$option] = $value;
}
public function getHandle() {
return $this->handle;
}
public function handleHook($handle) {
$this->handle = $handle;
curl_setopt_array($handle, $this->options);
}
public function intercept($callable) {
$this->reset();
$action = array($this, 'handleHook');
add_action(self::HOOK_NAME, $action);
$result = $callable();
if ($this->handle === null && $this->requireInterception)
throw new wfCurlInterceptionFailedException('Hook was not invoked with a valid cURL handle');
remove_action(self::HOOK_NAME, $action);
return $result;
}
}

View File

@@ -0,0 +1,328 @@
<?php
class wfDB {
public $errorMsg = false;
public static function shared() {
static $_shared = null;
if ($_shared === null) {
$_shared = new wfDB();
}
return $_shared;
}
/**
* Returns the table prefix for the main site on multisites and the site itself on single site installations.
*
* @return string
*/
public static function networkPrefix() {
global $wpdb;
return $wpdb->base_prefix;
}
/**
* Returns the table with the site (single site installations) or network (multisite) prefix added.
*
* @param string $table
* @param bool $applyCaseConversion Whether or not to convert the table case to what is actually in use.
* @return string
*/
public static function networkTable($table, $applyCaseConversion = true) {
if (wfSchema::usingLowercase() && $applyCaseConversion) {
$table = strtolower($table);
}
return self::networkPrefix() . $table;
}
/**
* Returns the table prefix for the given blog ID. On single site installations, this will be equivalent to wfDB::networkPrefix().
*
* @param int $blogID
* @return string
*/
public static function blogPrefix($blogID) {
global $wpdb;
return $wpdb->get_blog_prefix($blogID);
}
/**
* Returns the table with the site (single site installations) or blog-specific (multisite) prefix added.
*
* @param string $table
* @param bool $applyCaseConversion Whether or not to convert the table case to what is actually in use.
* @return string
*/
public static function blogTable($table, $blogID, $applyCaseConversion = true) {
if (wfSchema::usingLowercase() && $applyCaseConversion) {
$table = strtolower($table);
}
return self::blogPrefix($blogID) . $table;
}
public function querySingle(){
global $wpdb;
if(func_num_args() > 1){
$args = func_get_args();
return $wpdb->get_var(call_user_func_array(array($wpdb, 'prepare'), $args));
} else {
return $wpdb->get_var(func_get_arg(0));
}
}
public function querySingleRec(){ //queryInSprintfFormat, arg1, arg2, ... :: Returns a single assoc-array or null if nothing found.
global $wpdb;
if(func_num_args() > 1){
$args = func_get_args();
return $wpdb->get_row(call_user_func_array(array($wpdb, 'prepare'), $args), ARRAY_A);
} else {
return $wpdb->get_row(func_get_arg(0), ARRAY_A);
}
}
public function queryWrite(){
global $wpdb;
if(func_num_args() > 1){
$args = func_get_args();
return $wpdb->query(call_user_func_array(array($wpdb, 'prepare'), $args));
} else {
return $wpdb->query(func_get_arg(0));
}
}
public function queryWriteArray($query, $array) {
global $wpdb;
return $wpdb->query($wpdb->prepare($query, $array));
}
public function flush(){ //Clear cache
global $wpdb;
$wpdb->flush();
}
public function querySelect(){ //sprintfString, arguments :: always returns array() and will be empty if no results.
global $wpdb;
if(func_num_args() > 1){
$args = func_get_args();
return $wpdb->get_results(call_user_func_array(array($wpdb, 'prepare'), $args), ARRAY_A);
} else {
return $wpdb->get_results(func_get_arg(0), ARRAY_A);
}
}
public function queryWriteIgnoreError(){ //sprintfString, arguments
global $wpdb;
$oldSuppress = $wpdb->suppress_errors(true);
$args = func_get_args();
call_user_func_array(array($this, 'queryWrite'), $args);
$wpdb->suppress_errors($oldSuppress);
}
public function columnExists($table, $col){
$table = wfDB::networkTable($table);
$q = $this->querySelect("desc $table");
foreach($q as $row){
if($row['Field'] == $col){
return true;
}
}
return false;
}
public function dropColumn($table, $col){
$table = wfDB::networkTable($table);
$this->queryWrite("alter table $table drop column $col");
}
public function createKeyIfNotExists($table, $col, $keyName){
$table = wfDB::networkTable($table);
$exists = $this->querySingle(<<<SQL
SELECT TABLE_NAME FROM information_schema.TABLES
WHERE TABLE_SCHEMA=DATABASE()
AND TABLE_NAME='%s'
SQL
, $table);
$keyFound = false;
if($exists){
$q = $this->querySelect("show keys from $table");
foreach($q as $row){
if($row['Key_name'] == $keyName){
$keyFound = true;
}
}
}
if(! $keyFound){
$this->queryWrite("alter table $table add KEY $keyName($col)");
}
}
public function getMaxAllowedPacketBytes(){
$rec = $this->querySingleRec("show variables like 'max_allowed_packet'");
return intval($rec['Value']);
}
public function getMaxLongDataSizeBytes() {
$rec = $this->querySingleRec("show variables like 'max_long_data_size'");
return $rec['Value'];
}
public function truncate($table){ //Ensures everything is deleted if user is using MySQL >= 5.1.16 and does not have "drop" privileges
$this->queryWrite("truncate table $table");
$this->queryWrite("delete from $table");
}
public function getLastError(){
global $wpdb;
return $wpdb->last_error;
}
public function realEscape($str){
global $wpdb;
return $wpdb->_real_escape($str);
}
}
abstract class wfModel {
private $data;
private $db;
private $dirty = false;
/**
* Column name of the primary key field.
*
* @return string
*/
abstract public function getIDColumn();
/**
* Table name.
*
* @return mixed
*/
abstract public function getTable();
/**
* Checks if this is a valid column in the table before setting data on the model.
*
* @param string $column
* @return boolean
*/
abstract public function hasColumn($column);
/**
* wfModel constructor.
* @param array|int|string $data
*/
public function __construct($data = array()) {
if (is_array($data) || is_object($data)) {
$this->setData($data);
} else if (is_numeric($data)) {
$this->fetchByID($data);
}
}
public function fetchByID($id) {
$id = absint($id);
$data = $this->getDB()->get_row($this->getDB()->prepare('SELECT * FROM ' . $this->getTable() .
' WHERE ' . $this->getIDColumn() . ' = %d', $id));
if ($data) {
$this->setData($data);
return true;
}
return false;
}
/**
* @return bool
*/
public function save() {
if (!$this->dirty) {
return false;
}
$this->dirty = ($this->getPrimaryKey() ? $this->update() : $this->insert()) === false;
return !$this->dirty;
}
/**
* @return false|int
*/
public function insert() {
$data = $this->getData();
unset($data[$this->getPrimaryKey()]);
$rowsAffected = $this->getDB()->insert($this->getTable(), $data);
$this->setPrimaryKey($this->getDB()->insert_id);
return $rowsAffected;
}
/**
* @return false|int
*/
public function update() {
return $this->getDB()->update($this->getTable(), $this->getData(), array(
$this->getIDColumn() => $this->getPrimaryKey(),
));
}
/**
* @param $name string
* @return mixed
*/
public function __get($name) {
if (!$this->hasColumn($name)) {
return null;
}
return array_key_exists($name, $this->data) ? $this->data[$name] : null;
}
/**
* @param $name string
* @param $value mixed
*/
public function __set($name, $value) {
if (!$this->hasColumn($name)) {
return;
}
$this->data[$name] = $value;
$this->dirty = true;
}
/**
* @return array
*/
public function getData() {
return $this->data;
}
/**
* @param array $data
* @param bool $flagDirty
*/
public function setData($data, $flagDirty = true) {
$this->data = array();
foreach ($data as $column => $value) {
if ($this->hasColumn($column)) {
$this->data[$column] = $value;
$this->dirty = (bool) $flagDirty;
}
}
}
/**
* @return wpdb
*/
public function getDB() {
if ($this->db === null) {
global $wpdb;
$this->db = $wpdb;
}
return $this->db;
}
/**
* @param wpdb $db
*/
public function setDB($db) {
$this->db = $db;
}
/**
* @return int
*/
public function getPrimaryKey() {
return $this->{$this->getIDColumn()};
}
/**
* @param int $value
*/
public function setPrimaryKey($value) {
$this->{$this->getIDColumn()} = $value;
}
}

View File

@@ -0,0 +1,234 @@
<?php
class wfDashboard {
const SCAN_SUCCESS = 1;
const SCAN_FAILED = 0;
const SCAN_NEVER_RAN = -1;
const SCAN_WARNINGS = 2;
const FEATURE_ENABLED = 1;
const FEATURE_DISABLED = 0;
const FEATURE_PREMIUM = -1;
public $scanLastCompletion;
public $scanLastStatusMessage;
public $scanLastStatus;
public $notifications = array();
public $features = array();
public $lastGenerated;
public $tdfCommunity;
public $tdfPremium;
public $ips24h;
public $ips7d;
public $ips30d;
public $loginsSuccess;
public $loginsFail;
public $localBlocks;
public $networkBlock24h;
public $networkBlock7d;
public $networkBlock30d;
public $countriesLocal;
public $countriesNetwork;
public $wordfenceCentralConnected;
public $wordfenceCentralConnectTime;
public $wordfenceCentralConnectEmail;
public $wordfenceCentralDisconnected;
public $wordfenceCentralDisconnectTime;
public $wordfenceCentralDisconnectEmail;
public static function processDashboardResponse($data) {
if (isset($data['notifications'])) {
foreach ($data['notifications'] as $n) {
if (!isset($n['id']) || !isset($n['priority']) || !isset($n['html'])) {
continue;
}
new wfNotification($n['id'], $n['priority'], $n['html'], (isset($n['category']) ? $n['category'] : null));
}
unset($data['notifications']);
}
if (isset($data['revoked'])) {
foreach ($data['revoked'] as $r) {
if (!isset($r['id'])) {
continue;
}
$notification = wfNotification::getNotificationForID($r['id']);
if ($notification !== null) {
$notification->markAsRead();
}
}
unset($data['revoked']);
}
wfConfig::set_ser('dashboardData', $data);
}
public function __construct() {
// Scan values
$lastScanCompleted = wfConfig::get('lastScanCompleted');
if ($lastScanCompleted === false || empty($lastScanCompleted)) {
$this->scanLastStatus = self::SCAN_NEVER_RAN;
}
else if ($lastScanCompleted == 'ok') {
$this->scanLastStatus = self::SCAN_SUCCESS;
$i = new wfIssues();
$this->scanLastCompletion = (int) wfScanner::shared()->lastScanTime();
$issueCount = $i->getIssueCount();
if ($issueCount) {
$this->scanLastStatus = self::SCAN_WARNINGS;
$this->scanLastStatusMessage = "{$issueCount} issue" . ($issueCount == 1 ? ' found' : 's found');
}
}
else {
$this->scanLastStatus = self::SCAN_FAILED;
$n = wfNotification::getNotificationForCategory('wfplugin_scan', false);
if ($n !== null) {
$this->scanLastStatusMessage = $n->html;
}
else {
$this->scanLastStatusMessage = esc_html(substr($lastScanCompleted, 0, 100) . (strlen($lastScanCompleted) > 100 ? '...' : ''));
}
}
// Notifications
$this->notifications = wfNotification::notifications();
// Features
$countryBlocking = self::FEATURE_PREMIUM;
if (wfConfig::get('isPaid')) {
$countryBlocking = self::FEATURE_DISABLED;
$countryList = wfConfig::get('cbl_countries');
if (!empty($countryList) && (wfConfig::get('cbl_loggedInBlocked', false) || wfConfig::get('cbl_loginFormBlocked', false) || wfConfig::get('cbl_restOfSiteBlocked', false))) {
$countryBlocking = self::FEATURE_ENABLED;
}
}
$this->features = array(); //Deprecated
$data = wfConfig::get_ser('dashboardData');
$lastChecked = wfConfig::get('lastDashboardCheck', 0);
if ((!is_array($data) || (isset($data['generated']) && $data['generated'] + 3600 < time())) && $lastChecked + 3600 < time()) {
$wp_version = wfUtils::getWPVersion();
$apiKey = wfConfig::get('apiKey');
$api = new wfAPI($apiKey, $wp_version);
wfConfig::set('lastDashboardCheck', time());
try {
$json = $api->getStaticURL('/stats.json');
$data = @json_decode($json, true);
if ($json && is_array($data)) {
self::processDashboardResponse($data);
}
}
catch (Exception $e) {
//Do nothing
}
}
// Last Generated
if (is_array($data) && isset($data['generated'])) {
$this->lastGenerated = $data['generated'];
}
// TDF
if (is_array($data) && isset($data['tdf']) && isset($data['tdf']['community'])) {
$this->tdfCommunity = (int) $data['tdf']['community'];
$this->tdfPremium = (int) $data['tdf']['premium'];
}
// Top IPs Blocked
$activityReport = new wfActivityReport();
$this->ips24h = (array) $activityReport->getTopIPsBlocked(100, 1);
foreach ($this->ips24h as &$r24h) {
$r24h = (array) $r24h;
if (empty($r24h['countryName'])) { $r24h['countryName'] = 'Unknown'; }
}
$this->ips7d = (array) $activityReport->getTopIPsBlocked(100, 7);
foreach ($this->ips7d as &$r7d) {
$r7d = (array) $r7d;
if (empty($r7d['countryName'])) { $r7d['countryName'] = 'Unknown'; }
}
$this->ips30d = (array) $activityReport->getTopIPsBlocked(100, 30);
foreach ($this->ips30d as &$r30d) {
$r30d = (array) $r30d;
if (empty($r30d['countryName'])) { $r30d['countryName'] = 'Unknown'; }
}
// Recent Logins
$logins = wordfence::getLog()->getHits('logins', 'loginLogout', 0, 200);
$this->loginsSuccess = array();
$this->loginsFail = array();
foreach ($logins as $l) {
if ($l['fail']) {
$this->loginsFail[] = array('t' => $l['ctime'], 'name' => $l['username'], 'ip' => $l['IP']);
}
else if ($l['action'] != 'logout') {
$this->loginsSuccess[] = array('t' => $l['ctime'], 'name' => $l['username'], 'ip' => $l['IP']);
}
}
// Local Attack Data
$this->localBlocks = array();
$this->localBlocks[] = array('title' => __('Complex', 'wordfence'), 'type' => wfActivityReport::BLOCK_TYPE_COMPLEX,
'24h' => (int) $activityReport->getBlockedCount(1, wfActivityReport::BLOCK_TYPE_COMPLEX),
'7d' => (int) $activityReport->getBlockedCount(7, wfActivityReport::BLOCK_TYPE_COMPLEX),
'30d' => (int) $activityReport->getBlockedCount(30, wfActivityReport::BLOCK_TYPE_COMPLEX),
);
$this->localBlocks[] = array('title' => __('Brute Force', 'wordfence'), 'type' => wfActivityReport::BLOCK_TYPE_BRUTE_FORCE,
'24h' => (int) $activityReport->getBlockedCount(1, wfActivityReport::BLOCK_TYPE_BRUTE_FORCE),
'7d' => (int) $activityReport->getBlockedCount(7, wfActivityReport::BLOCK_TYPE_BRUTE_FORCE),
'30d' => (int) $activityReport->getBlockedCount(30, wfActivityReport::BLOCK_TYPE_BRUTE_FORCE),
);
$this->localBlocks[] = array('title' => __('Blocklist', 'wordfence'), 'type' => wfActivityReport::BLOCK_TYPE_BLACKLIST,
'24h' => (int) $activityReport->getBlockedCount(1, wfActivityReport::BLOCK_TYPE_BLACKLIST),
'7d' => (int) $activityReport->getBlockedCount(7, wfActivityReport::BLOCK_TYPE_BLACKLIST),
'30d' => (int) $activityReport->getBlockedCount(30, wfActivityReport::BLOCK_TYPE_BLACKLIST),
);
// Network Attack Data
if (is_array($data) && isset($data['attackdata']) && isset($data['attackdata']['24h'])) {
$this->networkBlock24h = $data['attackdata']['24h'];
$this->networkBlock7d = $data['attackdata']['7d'];
$this->networkBlock30d = $data['attackdata']['30d'];
}
// Blocked Countries
$this->countriesLocal = (array) $activityReport->getTopCountriesBlocked(10, 7);
foreach ($this->countriesLocal as &$rLocal) {
$rLocal = (array) $rLocal;
if (empty($rLocal['countryName'])) { $rLocal['countryName'] = 'Unknown'; }
}
if (is_array($data) && isset($data['countries']) && isset($data['countries']['7d'])) {
$networkCountries = array();
foreach ($data['countries']['7d'] as $rNetwork) {
$countryCode = $rNetwork['cd'];
$countryName = $activityReport->getCountryNameByCode($countryCode);
if (empty($countryName)) { $countryName = 'Unknown'; }
$totalBlockCount = $rNetwork['ct'];
$networkCountries[] = array('countryCode' => $countryCode, 'countryName' => $countryName, 'totalBlockCount' => $totalBlockCount);
}
$this->countriesNetwork = $networkCountries;
}
// Wordfence Central
$this->wordfenceCentralConnected = wfCentral::_isConnected(); // This value is cached.
$this->wordfenceCentralConnectTime = wfConfig::get('wordfenceCentralConnectTime');
$this->wordfenceCentralConnectEmail = wfConfig::get('wordfenceCentralConnectEmail');
$this->wordfenceCentralDisconnected = wfConfig::get('wordfenceCentralDisconnected');
$this->wordfenceCentralDisconnectTime = wfConfig::get('wordfenceCentralDisconnectTime');
$this->wordfenceCentralDisconnectEmail = wfConfig::get('wordfenceCentralDisconnectEmail');
}
}

View File

@@ -0,0 +1,326 @@
<?php
class wfDateLocalization {
static $localizations = array (
'af-ZA' => 'Date.CultureInfo={name:"af-ZA",englishName:"Afrikaans (South Africa)",nativeName:"Afrikaans (Suid Afrika)",dayNames:["Sondag","Maandag","Dinsdag","Woensdag","Donderdag","Vrydag","Saterdag"],abbreviatedDayNames:["Son","Maan","Dins","Woen","Dond","Vry","Sat"],shortestDayNames:["So","Ma","Di","Wo","Do","Vr","Sa"],firstLetterDayNames:["S","M","D","W","D","V","S"],monthNames:["Januarie","Februarie","Maart","April","Mei","Junie","Julie","Augustus","September","Oktober","November","Desember"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Aug","Sep","Okt","Nov","Des"],amDesignator:"",pmDesignator:"nm",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy/MM/dd",longDate:"dd MMMM yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uarie)?/i,feb:/^feb(ruarie)?/i,mar:/^maart/i,apr:/^apr(il)?/i,may:/^mei/i,jun:/^jun(ie)?/i,jul:/^jul(ie)?/i,aug:/^aug(ustus)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nov(ember)?/i,dec:/^des(ember)?/i,sun:/^so(n(dag)?)?/i,mon:/^ma(an(dag)?)?/i,tue:/^di(ns(dag)?)?/i,wed:/^wo(en(sdag)?)?/i,thu:/^do(nd(erdag)?)?/i,fri:/^vr(y(dag)?)?/i,sat:/^sa(t(erdag)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ar-AE' => 'Date.CultureInfo={name:"ar-AE",englishName:"Arabic (U.A.E.)",nativeName:"العربية (الإمارات العربية المتحدة)",dayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],abbreviatedDayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],shortestDayNames:["أ","ا","ث","أ","خ","ج","س"],firstLetterDayNames:["أ","ا","ث","أ","خ","ج","س"],monthNames:["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],abbreviatedMonthNames:["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],amDesignator:"ص",pmDesignator:"م",firstDayOfWeek:6,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM, yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM, yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^يناير/i,feb:/^فبراير/i,mar:/^مارس/i,apr:/^ابريل/i,may:/^مايو/i,jun:/^يونيو/i,jul:/^يوليو/i,aug:/^اغسطس/i,sep:/^سبتمبر/i,oct:/^اكتوبر/i,nov:/^نوفمبر/i,dec:/^ديسمبر/i,sun:/^الاحد/i,mon:/^ا(1)?/i,tue:/^الثلاثاء/i,wed:/^الاربعاء/i,thu:/^الخميس/i,fri:/^الجمعة/i,sat:/^السبت/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ar-BH' => 'Date.CultureInfo={name:"ar-BH",englishName:"Arabic (Bahrain)",nativeName:"العربية (البحرين)",dayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],abbreviatedDayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],shortestDayNames:["أ","ا","ث","أ","خ","ج","س"],firstLetterDayNames:["أ","ا","ث","أ","خ","ج","س"],monthNames:["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],abbreviatedMonthNames:["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],amDesignator:"ص",pmDesignator:"م",firstDayOfWeek:6,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM, yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM, yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^يناير/i,feb:/^فبراير/i,mar:/^مارس/i,apr:/^ابريل/i,may:/^مايو/i,jun:/^يونيو/i,jul:/^يوليو/i,aug:/^اغسطس/i,sep:/^سبتمبر/i,oct:/^اكتوبر/i,nov:/^نوفمبر/i,dec:/^ديسمبر/i,sun:/^الاحد/i,mon:/^ا(1)?/i,tue:/^الثلاثاء/i,wed:/^الاربعاء/i,thu:/^الخميس/i,fri:/^الجمعة/i,sat:/^السبت/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ar-DZ' => 'Date.CultureInfo={name:"ar-DZ",englishName:"Arabic (Algeria)",nativeName:"العربية (الجزائر)",dayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],abbreviatedDayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],shortestDayNames:["أ","ا","ث","أ","خ","ج","س"],firstLetterDayNames:["أ","ا","ث","أ","خ","ج","س"],monthNames:["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],abbreviatedMonthNames:["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],amDesignator:"ص",pmDesignator:"م",firstDayOfWeek:6,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd-MM-yyyy",longDate:"dd MMMM, yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dd MMMM, yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^جانفييه/i,feb:/^فيفرييه/i,mar:/^مارس/i,apr:/^أفريل/i,may:/^مي/i,jun:/^جوان/i,jul:/^جوييه/i,aug:/^أوت/i,sep:/^سبتمبر/i,oct:/^اكتوبر/i,nov:/^نوفمبر/i,dec:/^ديسمبر/i,sun:/^الاحد/i,mon:/^ا(1)?/i,tue:/^الثلاثاء/i,wed:/^الاربعاء/i,thu:/^الخميس/i,fri:/^الجمعة/i,sat:/^السبت/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ar-EG' => 'Date.CultureInfo={name:"ar-EG",englishName:"Arabic (Egypt)",nativeName:"العربية (مصر)",dayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],abbreviatedDayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],shortestDayNames:["أ","ا","ث","أ","خ","ج","س"],firstLetterDayNames:["أ","ا","ث","أ","خ","ج","س"],monthNames:["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],abbreviatedMonthNames:["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],amDesignator:"ص",pmDesignator:"م",firstDayOfWeek:6,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM, yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM, yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^يناير/i,feb:/^فبراير/i,mar:/^مارس/i,apr:/^ابريل/i,may:/^مايو/i,jun:/^يونيو/i,jul:/^يوليو/i,aug:/^اغسطس/i,sep:/^سبتمبر/i,oct:/^اكتوبر/i,nov:/^نوفمبر/i,dec:/^ديسمبر/i,sun:/^الاحد/i,mon:/^ا(1)?/i,tue:/^الثلاثاء/i,wed:/^الاربعاء/i,thu:/^الخميس/i,fri:/^الجمعة/i,sat:/^السبت/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ar-IQ' => 'Date.CultureInfo={name:"ar-IQ",englishName:"Arabic (Iraq)",nativeName:"العربية (العراق)",dayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],abbreviatedDayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],shortestDayNames:["أ","ا","ث","أ","خ","ج","س"],firstLetterDayNames:["أ","ا","ث","أ","خ","ج","س"],monthNames:["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول"],abbreviatedMonthNames:["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول"],amDesignator:"ص",pmDesignator:"م",firstDayOfWeek:6,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM, yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM, yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^كانون الثاني/i,feb:/^شباط/i,mar:/^آذار/i,apr:/^نيسان/i,may:/^أيار/i,jun:/^حزيران/i,jul:/^تموز/i,aug:/^آب/i,sep:/^أيلول/i,oct:/^تشرين الأول/i,nov:/^تشرين الثاني/i,dec:/^كانون الأول/i,sun:/^الاحد/i,mon:/^ا(1)?/i,tue:/^الثلاثاء/i,wed:/^الاربعاء/i,thu:/^الخميس/i,fri:/^الجمعة/i,sat:/^السبت/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ar-JO' => 'Date.CultureInfo={name:"ar-JO",englishName:"Arabic (Jordan)",nativeName:"العربية (الأردن)",dayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],abbreviatedDayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],shortestDayNames:["أ","ا","ث","أ","خ","ج","س"],firstLetterDayNames:["أ","ا","ث","أ","خ","ج","س"],monthNames:["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول"],abbreviatedMonthNames:["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول"],amDesignator:"ص",pmDesignator:"م",firstDayOfWeek:6,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM, yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM, yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^كانون الثاني/i,feb:/^شباط/i,mar:/^آذار/i,apr:/^نيسان/i,may:/^أيار/i,jun:/^حزيران/i,jul:/^تموز/i,aug:/^آب/i,sep:/^أيلول/i,oct:/^تشرين الأول/i,nov:/^تشرين الثاني/i,dec:/^كانون الأول/i,sun:/^الاحد/i,mon:/^ا(1)?/i,tue:/^الثلاثاء/i,wed:/^الاربعاء/i,thu:/^الخميس/i,fri:/^الجمعة/i,sat:/^السبت/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ar-KW' => 'Date.CultureInfo={name:"ar-KW",englishName:"Arabic (Kuwait)",nativeName:"العربية (الكويت)",dayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],abbreviatedDayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],shortestDayNames:["أ","ا","ث","أ","خ","ج","س"],firstLetterDayNames:["أ","ا","ث","أ","خ","ج","س"],monthNames:["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],abbreviatedMonthNames:["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],amDesignator:"ص",pmDesignator:"م",firstDayOfWeek:6,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM, yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM, yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^يناير/i,feb:/^فبراير/i,mar:/^مارس/i,apr:/^ابريل/i,may:/^مايو/i,jun:/^يونيو/i,jul:/^يوليو/i,aug:/^اغسطس/i,sep:/^سبتمبر/i,oct:/^اكتوبر/i,nov:/^نوفمبر/i,dec:/^ديسمبر/i,sun:/^الاحد/i,mon:/^ا(1)?/i,tue:/^الثلاثاء/i,wed:/^الاربعاء/i,thu:/^الخميس/i,fri:/^الجمعة/i,sat:/^السبت/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ar-LB' => 'Date.CultureInfo={name:"ar-LB",englishName:"Arabic (Lebanon)",nativeName:"العربية (لبنان)",dayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],abbreviatedDayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],shortestDayNames:["أ","ا","ث","أ","خ","ج","س"],firstLetterDayNames:["أ","ا","ث","أ","خ","ج","س"],monthNames:["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول"],abbreviatedMonthNames:["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول"],amDesignator:"ص",pmDesignator:"م",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM, yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM, yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^كانون الثاني/i,feb:/^شباط/i,mar:/^آذار/i,apr:/^نيسان/i,may:/^أيار/i,jun:/^حزيران/i,jul:/^تموز/i,aug:/^آب/i,sep:/^أيلول/i,oct:/^تشرين الأول/i,nov:/^تشرين الثاني/i,dec:/^كانون الأول/i,sun:/^الاحد/i,mon:/^ا(1)?/i,tue:/^الثلاثاء/i,wed:/^الاربعاء/i,thu:/^الخميس/i,fri:/^الجمعة/i,sat:/^السبت/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ar-LY' => 'Date.CultureInfo={name:"ar-LY",englishName:"Arabic (Libya)",nativeName:"العربية (ليبيا)",dayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],abbreviatedDayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],shortestDayNames:["أ","ا","ث","أ","خ","ج","س"],firstLetterDayNames:["أ","ا","ث","أ","خ","ج","س"],monthNames:["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],abbreviatedMonthNames:["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],amDesignator:"ص",pmDesignator:"م",firstDayOfWeek:6,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM, yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM, yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^يناير/i,feb:/^فبراير/i,mar:/^مارس/i,apr:/^ابريل/i,may:/^مايو/i,jun:/^يونيو/i,jul:/^يوليو/i,aug:/^اغسطس/i,sep:/^سبتمبر/i,oct:/^اكتوبر/i,nov:/^نوفمبر/i,dec:/^ديسمبر/i,sun:/^الاحد/i,mon:/^ا(1)?/i,tue:/^الثلاثاء/i,wed:/^الاربعاء/i,thu:/^الخميس/i,fri:/^الجمعة/i,sat:/^السبت/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ar-MA' => 'Date.CultureInfo={name:"ar-MA",englishName:"Arabic (Morocco)",nativeName:"العربية (المملكة المغربية)",dayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],abbreviatedDayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],shortestDayNames:["أ","ا","ث","أ","خ","ج","س"],firstLetterDayNames:["أ","ا","ث","أ","خ","ج","س"],monthNames:["يناير","فبراير","مارس","ابريل","ماي","يونيو","يوليوز","غشت","شتنبر","اكتوبر","نونبر","دجنبر"],abbreviatedMonthNames:["يناير","فبراير","مارس","ابريل","ماي","يونيو","يوليوز","غشت","شتنبر","اكتوبر","نونبر","دجنبر"],amDesignator:"ص",pmDesignator:"م",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd-MM-yyyy",longDate:"dd MMMM, yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dd MMMM, yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^يناير/i,feb:/^فبراير/i,mar:/^مارس/i,apr:/^ابريل/i,may:/^ماي/i,jun:/^يونيو/i,jul:/^يوليوز/i,aug:/^غشت/i,sep:/^شتنبر/i,oct:/^اكتوبر/i,nov:/^نونبر/i,dec:/^دجنبر/i,sun:/^الاحد/i,mon:/^ا(1)?/i,tue:/^الثلاثاء/i,wed:/^الاربعاء/i,thu:/^الخميس/i,fri:/^الجمعة/i,sat:/^السبت/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ar-OM' => 'Date.CultureInfo={name:"ar-OM",englishName:"Arabic (Oman)",nativeName:"العربية (عمان)",dayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],abbreviatedDayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],shortestDayNames:["أ","ا","ث","أ","خ","ج","س"],firstLetterDayNames:["أ","ا","ث","أ","خ","ج","س"],monthNames:["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],abbreviatedMonthNames:["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],amDesignator:"ص",pmDesignator:"م",firstDayOfWeek:6,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM, yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM, yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^يناير/i,feb:/^فبراير/i,mar:/^مارس/i,apr:/^ابريل/i,may:/^مايو/i,jun:/^يونيو/i,jul:/^يوليو/i,aug:/^اغسطس/i,sep:/^سبتمبر/i,oct:/^اكتوبر/i,nov:/^نوفمبر/i,dec:/^ديسمبر/i,sun:/^الاحد/i,mon:/^ا(1)?/i,tue:/^الثلاثاء/i,wed:/^الاربعاء/i,thu:/^الخميس/i,fri:/^الجمعة/i,sat:/^السبت/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ar-QA' => 'Date.CultureInfo={name:"ar-QA",englishName:"Arabic (Qatar)",nativeName:"العربية (قطر)",dayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],abbreviatedDayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],shortestDayNames:["أ","ا","ث","أ","خ","ج","س"],firstLetterDayNames:["أ","ا","ث","أ","خ","ج","س"],monthNames:["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],abbreviatedMonthNames:["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],amDesignator:"ص",pmDesignator:"م",firstDayOfWeek:6,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM, yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM, yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^يناير/i,feb:/^فبراير/i,mar:/^مارس/i,apr:/^ابريل/i,may:/^مايو/i,jun:/^يونيو/i,jul:/^يوليو/i,aug:/^اغسطس/i,sep:/^سبتمبر/i,oct:/^اكتوبر/i,nov:/^نوفمبر/i,dec:/^ديسمبر/i,sun:/^الاحد/i,mon:/^ا(1)?/i,tue:/^الثلاثاء/i,wed:/^الاربعاء/i,thu:/^الخميس/i,fri:/^الجمعة/i,sat:/^السبت/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ar-SA' => 'Date.CultureInfo={name:"ar-SA",englishName:"Arabic (Saudi Arabia)",nativeName:"العربية (المملكة العربية السعودية)",dayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],abbreviatedDayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],shortestDayNames:["أ","ا","ث","أ","خ","ج","س"],firstLetterDayNames:["أ","ا","ث","أ","خ","ج","س"],monthNames:["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة"],abbreviatedMonthNames:["محرم","صفر","ربيع الاول","ربيع الثاني","جمادى الاولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة"],amDesignator:"ص",pmDesignator:"م",firstDayOfWeek:6,twoDigitYearMax:1451,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yy",longDate:"dd/MMMM/yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dd/MMMM/yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^محرم/i,feb:/^صفر/i,mar:/^ربيع الأول/i,apr:/^ربيع الثاني/i,may:/^جمادى الأولى/i,jun:/^جمادى الثانية/i,jul:/^رجب/i,aug:/^شعبان/i,sep:/^رمضان/i,oct:/^شوال/i,nov:/^ذو القعدة/i,dec:/^ذو الحجة/i,sun:/^الاحد/i,mon:/^ا(1)?/i,tue:/^الثلاثاء/i,wed:/^الاربعاء/i,thu:/^الخميس/i,fri:/^الجمعة/i,sat:/^السبت/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ar-SY' => 'Date.CultureInfo={name:"ar-SY",englishName:"Arabic (Syria)",nativeName:"العربية (سوريا)",dayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],abbreviatedDayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],shortestDayNames:["أ","ا","ث","أ","خ","ج","س"],firstLetterDayNames:["أ","ا","ث","أ","خ","ج","س"],monthNames:["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول"],abbreviatedMonthNames:["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول"],amDesignator:"ص",pmDesignator:"م",firstDayOfWeek:6,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM, yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM, yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^كانون الثاني/i,feb:/^شباط/i,mar:/^آذار/i,apr:/^نيسان/i,may:/^أيار/i,jun:/^حزيران/i,jul:/^تموز/i,aug:/^آب/i,sep:/^أيلول/i,oct:/^تشرين الأول/i,nov:/^تشرين الثاني/i,dec:/^كانون الأول/i,sun:/^الاحد/i,mon:/^ا(1)?/i,tue:/^الثلاثاء/i,wed:/^الاربعاء/i,thu:/^الخميس/i,fri:/^الجمعة/i,sat:/^السبت/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ar-TN' => 'Date.CultureInfo={name:"ar-TN",englishName:"Arabic (Tunisia)",nativeName:"العربية (تونس)",dayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],abbreviatedDayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],shortestDayNames:["أ","ا","ث","أ","خ","ج","س"],firstLetterDayNames:["أ","ا","ث","أ","خ","ج","س"],monthNames:["جانفي","فيفري","مارس","افريل","ماي","جوان","جويلية","اوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],abbreviatedMonthNames:["جانفي","فيفري","مارس","افريل","ماي","جوان","جويلية","اوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],amDesignator:"ص",pmDesignator:"م",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd-MM-yyyy",longDate:"dd MMMM, yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dd MMMM, yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^جانفي/i,feb:/^فيفري/i,mar:/^مارس/i,apr:/^افريل/i,may:/^ماي/i,jun:/^جوان/i,jul:/^جويلية/i,aug:/^اوت/i,sep:/^سبتمبر/i,oct:/^اكتوبر/i,nov:/^نوفمبر/i,dec:/^ديسمبر/i,sun:/^الاحد/i,mon:/^ا(1)?/i,tue:/^الثلاثاء/i,wed:/^الاربعاء/i,thu:/^الخميس/i,fri:/^الجمعة/i,sat:/^السبت/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ar-YE' => 'Date.CultureInfo={name:"ar-YE",englishName:"Arabic (Yemen)",nativeName:"العربية (اليمن)",dayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],abbreviatedDayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],shortestDayNames:["أ","ا","ث","أ","خ","ج","س"],firstLetterDayNames:["أ","ا","ث","أ","خ","ج","س"],monthNames:["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],abbreviatedMonthNames:["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر"],amDesignator:"ص",pmDesignator:"م",firstDayOfWeek:6,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM, yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM, yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^يناير/i,feb:/^فبراير/i,mar:/^مارس/i,apr:/^ابريل/i,may:/^مايو/i,jun:/^يونيو/i,jul:/^يوليو/i,aug:/^اغسطس/i,sep:/^سبتمبر/i,oct:/^اكتوبر/i,nov:/^نوفمبر/i,dec:/^ديسمبر/i,sun:/^الاحد/i,mon:/^ا(1)?/i,tue:/^الثلاثاء/i,wed:/^الاربعاء/i,thu:/^الخميس/i,fri:/^الجمعة/i,sat:/^السبت/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'az-Cyrl-AZ' => 'Date.CultureInfo={name:"az-Cyrl-AZ",englishName:"Azeri (Cyrillic, Azerbaijan)",nativeName:"Азәрбајҹан (Азәрбајҹан)",dayNames:["Базар","Базар ертәси","Чәршәнбә ахшамы","Чәршәнбә","Ҹүмә ахшамы","Ҹүмә","Шәнбә"],abbreviatedDayNames:["Б","Бе","Ча","Ч","Ҹа","Ҹ","Ш"],shortestDayNames:["Б","Бе","Ча","Ч","Ҹа","Ҹ","Ш"],firstLetterDayNames:["Б","Б","Ч","Ч","Ҹ","Ҹ","Ш"],monthNames:["Јанвар","Феврал","Март","Апрел","Мај","Ијун","Ијул","Август","Сентјабр","Октјабр","Нојабр","Декабр"],abbreviatedMonthNames:["Јан","Фев","Мар","Апр","Мај","Ијун","Ијул","Авг","Сен","Окт","Ноя","Дек"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"d MMMM yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^јан(вар)?/i,feb:/^фев(рал)?/i,mar:/^мар(т)?/i,apr:/^апр(ел)?/i,may:/^мај/i,jun:/^ијун/i,jul:/^ијул/i,aug:/^авг(уст)?/i,sep:/^сен(тјабр)?/i,oct:/^окт(јабр)?/i,nov:/^нојабр/i,dec:/^дек(абр)?/i,sun:/^базар/i,mon:/^базар ертәси/i,tue:/^чәршәнбә ахшамы/i,wed:/^чәршәнбә/i,thu:/^ҹүмә ахшамы/i,fri:/^ҹүмә/i,sat:/^шәнбә/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'az-Latn-AZ' => 'Date.CultureInfo={name:"az-Latn-AZ",englishName:"Azeri (Latin, Azerbaijan)",nativeName:"Azərbaycan­ılı (Azərbaycanca)",dayNames:["Bazar","Bazar ertəsi","Çərşənbə axşamı","Çərşənbə","Cümə axşamı","Cümə","Şənbə"],abbreviatedDayNames:["B","Be","Ça","Ç","Ca","C","Ş"],shortestDayNames:["B","Be","Ça","Ç","Ca","C","Ş"],firstLetterDayNames:["B","B","Ç","Ç","C","C","Ş"],monthNames:["Yanvar","Fevral","Mart","Aprel","May","İyun","İyul","Avgust","Sentyabr","Oktyabr","Noyabr","Dekabr"],abbreviatedMonthNames:["Yan","Fev","Mar","Apr","May","İyun","İyul","Avg","Sen","Okt","Noy","Dek"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"d MMMM yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^yan(var)?/i,feb:/^fev(ral)?/i,mar:/^mar(t)?/i,apr:/^apr(el)?/i,may:/^may/i,jun:/^iyun/i,jul:/^iyul/i,aug:/^avg(ust)?/i,sep:/^sen(tyabr)?/i,oct:/^okt(yabr)?/i,nov:/^noy(abr)?/i,dec:/^dek(abr)?/i,sun:/^bazar/i,mon:/^bazar ertəsi/i,tue:/^çərşənbə axşamı/i,wed:/^çərşənbə/i,thu:/^cümə axşamı/i,fri:/^cümə/i,sat:/^şənbə/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'be-BY' => 'Date.CultureInfo={name:"be-BY",englishName:"Belarusian (Belarus)",nativeName:"Беларускі (Беларусь)",dayNames:["нядзеля","панядзелак","аўторак","серада","чацвер","пятніца","субота"],abbreviatedDayNames:["нд","пн","аў","ср","чц","пт","сб"],shortestDayNames:["нд","пн","аў","ср","чц","пт","сб"],firstLetterDayNames:["н","п","а","с","ч","п","с"],monthNames:["Студзень","Люты","Сакавік","Красавік","Май","Чэрвень","Ліпень","Жнівень","Верасень","Кастрычнік","Лістапад","Снежань"],abbreviatedMonthNames:["Сту","Лют","Сак","Кра","Май","Чэр","Ліп","Жні","Вер","Кас","Ліс","Сне"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"d MMMM yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^сту(дзень)?/i,feb:/^лют(ы)?/i,mar:/^сак(авік)?/i,apr:/^кра(савік)?/i,may:/^май/i,jun:/^чэр(вень)?/i,jul:/^ліп(ень)?/i,aug:/^жні(вень)?/i,sep:/^вер(асень)?/i,oct:/^кас(трычнік)?/i,nov:/^ліс(тапад)?/i,dec:/^сне(жань)?/i,sun:/^нядзеля/i,mon:/^панядзелак/i,tue:/^аўторак/i,wed:/^серада/i,thu:/^чацвер/i,fri:/^пятніца/i,sat:/^субота/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'bg-BG' => 'Date.CultureInfo={name:"bg-BG",englishName:"Bulgarian (Bulgaria)",nativeName:"български (България)",dayNames:["неделя","понеделник","вторник","сряда","четвъртък","петък","събота"],abbreviatedDayNames:["Нд","Пн","Вт","Ср","Чт","Пт","Сб"],shortestDayNames:["не","по","вт","ср","че","пе","съ"],firstLetterDayNames:["н","п","в","с","ч","п","с"],monthNames:["Януари","Февруари","Март","Април","Май","Юни","Юли","Август","Септември","Октомври","Ноември","Декември"],abbreviatedMonthNames:["Януари","Февруари","Март","Април","Май","Юни","Юли","Август","Септември","Октомври","Ноември","Декември"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.M.yyyy \'г.\'",longDate:"dd MMMM yyyy \'г.\'",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dd MMMM yyyy \'г.\' HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy \'г.\'"},regexPatterns:{jan:/^януари/i,feb:/^февруари/i,mar:/^март/i,apr:/^април/i,may:/^май/i,jun:/^юни/i,jul:/^юли/i,aug:/^август/i,sep:/^септември/i,oct:/^октомври/i,nov:/^ноември/i,dec:/^декември/i,sun:/^не((деля)?)?/i,mon:/^по((неделник)?)?/i,tue:/^вторник/i,wed:/^сряда/i,thu:/^че((твъртък)?)?/i,fri:/^пе((тък)?)?/i,sat:/^съ((бота)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'bs-Latn-BA' => 'Date.CultureInfo={name:"bs-Latn-BA",englishName:"Bosnian (Bosnia and Herzegovina)",nativeName:"bosanski (Bosna i Hercegovina)",dayNames:["nedjelja","ponedjeljak","utorak","srijeda","četvrtak","petak","subota"],abbreviatedDayNames:["ned","pon","uto","sri","čet","pet","sub"],shortestDayNames:["ned","pon","uto","sri","čet","pet","sub"],firstLetterDayNames:["n","p","u","s","č","p","s"],monthNames:["januar","februar","mart","april","maj","jun","jul","avgust","septembar","oktobar","novembar","decembar"],abbreviatedMonthNames:["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d.M.yyyy",longDate:"d. MMMM yyyy",shortTime:"H:mm:ss",longTime:"H:mm:ss",fullDateTime:"d. MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uar)?/i,feb:/^feb(ruar)?/i,mar:/^mar(t)?/i,apr:/^apr(il)?/i,may:/^maj/i,jun:/^jun/i,jul:/^jul/i,aug:/^avg(ust)?/i,sep:/^sep(tembar)?/i,oct:/^okt(obar)?/i,nov:/^nov(embar)?/i,dec:/^dec(embar)?/i,sun:/^nedjelja/i,mon:/^ponedjeljak/i,tue:/^utorak/i,wed:/^srijeda/i,thu:/^četvrtak/i,fri:/^petak/i,sat:/^subota/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ca-ES' => 'Date.CultureInfo={name:"ca-ES",englishName:"Catalan (Catalan)",nativeName:"català (català)",dayNames:["diumenge","dilluns","dimarts","dimecres","dijous","divendres","dissabte"],abbreviatedDayNames:["dg.","dl.","dt.","dc.","dj.","dv.","ds."],shortestDayNames:["dg","dl","dt","dc","dj","dv","ds"],firstLetterDayNames:["d","d","d","d","d","d","d"],monthNames:["gener","febrer","març","abril","maig","juny","juliol","agost","setembre","octubre","novembre","desembre"],abbreviatedMonthNames:["gen","feb","març","abr","maig","juny","jul","ag","set","oct","nov","des"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, d\' / \'MMMM\' / \'yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dddd, d\' / \'MMMM\' / \'yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' / \'yyyy"},regexPatterns:{jan:/^gen(er)?/i,feb:/^feb(rer)?/i,mar:/^març/i,apr:/^abr(il)?/i,may:/^maig/i,jun:/^juny/i,jul:/^jul(iol)?/i,aug:/^ag(ost)?/i,sep:/^set(embre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(embre)?/i,dec:/^des(embre)?/i,sun:/^dg((.(umenge)?)?)?/i,mon:/^dl((.(lluns)?)?)?/i,tue:/^dt((.(marts)?)?)?/i,wed:/^dc((.(mecres)?)?)?/i,thu:/^dj((.(jous)?)?)?/i,fri:/^dv((.(vendres)?)?)?/i,sat:/^ds((.(ssabte)?)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'cs-CZ' => 'Date.CultureInfo={name:"cs-CZ",englishName:"Czech (Czech Republic)",nativeName:"čeština (Česká republika)",dayNames:["neděle","pondělí","úterý","středa","čtvrtek","pátek","sobota"],abbreviatedDayNames:["ne","po","út","st","čt","pá","so"],shortestDayNames:["ne","po","út","st","čt","pá","so"],firstLetterDayNames:["n","p","ú","s","č","p","s"],monthNames:["leden","únor","březen","duben","květen","červen","červenec","srpen","září","říjen","listopad","prosinec"],abbreviatedMonthNames:["I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII"],amDesignator:"dop.",pmDesignator:"odp.",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d.M.yyyy",longDate:"d. MMMM yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d. MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^leden/i,feb:/^únor/i,mar:/^březen/i,apr:/^duben/i,may:/^květen/i,jun:/^červen/i,jul:/^červenec/i,aug:/^srpen/i,sep:/^září/i,oct:/^říjen/i,nov:/^listopad/i,dec:/^prosinec/i,sun:/^neděle/i,mon:/^pondělí/i,tue:/^úterý/i,wed:/^středa/i,thu:/^čtvrtek/i,fri:/^pátek/i,sat:/^sobota/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'cy-GB' => 'Date.CultureInfo={name:"cy-GB",englishName:"Welsh (United Kingdom)",nativeName:"Cymraeg (y Deyrnas Unedig)",dayNames:["Dydd Sul","Dydd Llun","Dydd Mawrth","Dydd Mercher","Dydd Iau","Dydd Gwener","Dydd Sadwrn"],abbreviatedDayNames:["Sul","Llun","Maw","Mer","Iau","Gwe","Sad"],shortestDayNames:["Sul","Llun","Maw","Mer","Iau","Gwe","Sad"],firstLetterDayNames:["S","L","M","M","I","G","S"],monthNames:["Ionawr","Chwefror","Mawrth","Ebrill","Mai","Mehefin","Gorffennaf","Awst","Medi","Hydref","Tachwedd","Rhagfyr"],abbreviatedMonthNames:["Ion","Chwe","Maw","Ebr","Mai","Meh","Gor","Aws","Med","Hyd","Tach","Rhag"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM yyyy",shortTime:"HH:mm:ss",longTime:"HH:mm:ss",fullDateTime:"dd MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^ion(awr)?/i,feb:/^chwe(fror)?/i,mar:/^maw(rth)?/i,apr:/^ebr(ill)?/i,may:/^mai/i,jun:/^meh(efin)?/i,jul:/^gor(ffennaf)?/i,aug:/^aws(t)?/i,sep:/^med(i)?/i,oct:/^hyd(ref)?/i,nov:/^tach(wedd)?/i,dec:/^rhag(fyr)?/i,sun:/^dydd sul/i,mon:/^dydd llun/i,tue:/^dydd mawrth/i,wed:/^dydd mercher/i,thu:/^dydd iau/i,fri:/^dydd gwener/i,sat:/^dydd sadwrn/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'da-DK' => 'Date.CultureInfo={name:"da-DK",englishName:"Danish (Denmark)",nativeName:"dansk (Danmark)",dayNames:["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"],abbreviatedDayNames:["sø","ma","ti","on","to","fr","lø"],shortestDayNames:["sø","ma","ti","on","to","fr","lø"],firstLetterDayNames:["s","m","t","o","t","f","l"],monthNames:["januar","februar","marts","april","maj","juni","juli","august","september","oktober","november","december"],abbreviatedMonthNames:["jan","feb","mar","apr","maj","jun","jul","aug","sep","okt","nov","dec"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd-MM-yyyy",longDate:"d. MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"d. MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d. MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uar)?/i,feb:/^feb(ruar)?/i,mar:/^mar(ts)?/i,apr:/^apr(il)?/i,may:/^maj/i,jun:/^jun(i)?/i,jul:/^jul(i)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^søndag/i,mon:/^mandag/i,tue:/^tirsdag/i,wed:/^onsdag/i,thu:/^torsdag/i,fri:/^fredag/i,sat:/^lørdag/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'de-AT' => 'Date.CultureInfo={name:"de-AT",englishName:"German (Austria)",nativeName:"Deutsch (Österreich)",dayNames:["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"],abbreviatedDayNames:["So","Mo","Di","Mi","Do","Fr","Sa"],shortestDayNames:["So","Mo","Di","Mi","Do","Fr","Sa"],firstLetterDayNames:["S","M","D","M","D","F","S"],monthNames:["Jänner","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"],abbreviatedMonthNames:["Jän","Feb","Mär","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"dddd, dd. MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dddd, dd. MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jän(ner)?/i,feb:/^feb(ruar)?/i,mar:/^mär(z)?/i,apr:/^apr(il)?/i,may:/^mai/i,jun:/^jun(i)?/i,jul:/^jul(i)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nov(ember)?/i,dec:/^dez(ember)?/i,sun:/^sonntag/i,mon:/^montag/i,tue:/^dienstag/i,wed:/^mittwoch/i,thu:/^donnerstag/i,fri:/^freitag/i,sat:/^samstag/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'de-CH' => 'Date.CultureInfo={name:"de-CH",englishName:"German (Switzerland)",nativeName:"Deutsch (Schweiz)",dayNames:["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"],abbreviatedDayNames:["So","Mo","Di","Mi","Do","Fr","Sa"],shortestDayNames:["So","Mo","Di","Mi","Do","Fr","Sa"],firstLetterDayNames:["S","M","D","M","D","F","S"],monthNames:["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"],abbreviatedMonthNames:["Jan","Feb","Mrz","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"dddd, d. MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dddd, d. MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uar)?/i,feb:/^feb(ruar)?/i,mar:/^märz/i,apr:/^apr(il)?/i,may:/^mai/i,jun:/^jun(i)?/i,jul:/^jul(i)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nov(ember)?/i,dec:/^dez(ember)?/i,sun:/^sonntag/i,mon:/^montag/i,tue:/^dienstag/i,wed:/^mittwoch/i,thu:/^donnerstag/i,fri:/^freitag/i,sat:/^samstag/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'de-DE' => 'Date.CultureInfo={name:"de-DE",englishName:"German (Germany)",nativeName:"Deutsch (Deutschland)",dayNames:["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"],abbreviatedDayNames:["So","Mo","Di","Mi","Do","Fr","Sa"],shortestDayNames:["So","Mo","Di","Mi","Do","Fr","Sa"],firstLetterDayNames:["S","M","D","M","D","F","S"],monthNames:["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"],abbreviatedMonthNames:["Jan","Feb","Mrz","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"dddd, d. MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dddd, d. MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uar)?/i,feb:/^feb(ruar)?/i,mar:/^märz/i,apr:/^apr(il)?/i,may:/^mai/i,jun:/^jun(i)?/i,jul:/^jul(i)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nov(ember)?/i,dec:/^dez(ember)?/i,sun:/^sonntag/i,mon:/^montag/i,tue:/^dienstag/i,wed:/^mittwoch/i,thu:/^donnerstag/i,fri:/^freitag/i,sat:/^samstag/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'de-LI' => 'Date.CultureInfo={name:"de-LI",englishName:"German (Liechtenstein)",nativeName:"Deutsch (Liechtenstein)",dayNames:["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"],abbreviatedDayNames:["So","Mo","Di","Mi","Do","Fr","Sa"],shortestDayNames:["So","Mo","Di","Mi","Do","Fr","Sa"],firstLetterDayNames:["S","M","D","M","D","F","S"],monthNames:["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"],abbreviatedMonthNames:["Jan","Feb","Mrz","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"dddd, d. MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dddd, d. MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uar)?/i,feb:/^feb(ruar)?/i,mar:/^märz/i,apr:/^apr(il)?/i,may:/^mai/i,jun:/^jun(i)?/i,jul:/^jul(i)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nov(ember)?/i,dec:/^dez(ember)?/i,sun:/^sonntag/i,mon:/^montag/i,tue:/^dienstag/i,wed:/^mittwoch/i,thu:/^donnerstag/i,fri:/^freitag/i,sat:/^samstag/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'de-LU' => 'Date.CultureInfo={name:"de-LU",englishName:"German (Luxembourg)",nativeName:"Deutsch (Luxemburg)",dayNames:["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"],abbreviatedDayNames:["So","Mo","Di","Mi","Do","Fr","Sa"],shortestDayNames:["So","Mo","Di","Mi","Do","Fr","Sa"],firstLetterDayNames:["S","M","D","M","D","F","S"],monthNames:["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"],abbreviatedMonthNames:["Jan","Feb","Mrz","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"dddd, d. MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dddd, d. MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uar)?/i,feb:/^feb(ruar)?/i,mar:/^märz/i,apr:/^apr(il)?/i,may:/^mai/i,jun:/^jun(i)?/i,jul:/^jul(i)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nov(ember)?/i,dec:/^dez(ember)?/i,sun:/^sonntag/i,mon:/^montag/i,tue:/^dienstag/i,wed:/^mittwoch/i,thu:/^donnerstag/i,fri:/^freitag/i,sat:/^samstag/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'dv-MV' => 'Date.CultureInfo={name:"dv-MV",englishName:"Divehi (Maldives)",nativeName:"ދިވެހިބަސް (ދިވެހި ރާއްޖެ)",dayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],abbreviatedDayNames:["الاحد","الاثنين","الثلاثاء","الاربعاء","الخميس","الجمعة","السبت"],shortestDayNames:["أ","ا","ث","أ","خ","ج","س"],firstLetterDayNames:["أ","ا","ث","أ","خ","ج","س"],monthNames:["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة"],abbreviatedMonthNames:["محرم","صفر","ربيع الاول","ربيع الثاني","جمادى الاولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة"],amDesignator:"މކ",pmDesignator:"މފ",firstDayOfWeek:0,twoDigitYearMax:1451,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yy",longDate:"dd/MMMM/yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dd/MMMM/yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^محرم/i,feb:/^صفر/i,mar:/^ربيع الأول/i,apr:/^ربيع الثاني/i,may:/^جمادى الأولى/i,jun:/^جمادى الثانية/i,jul:/^رجب/i,aug:/^شعبان/i,sep:/^رمضان/i,oct:/^شوال/i,nov:/^ذو القعدة/i,dec:/^ذو الحجة/i,sun:/^الاحد/i,mon:/^ا(1)?/i,tue:/^الثلاثاء/i,wed:/^الاربعاء/i,thu:/^الخميس/i,fri:/^الجمعة/i,sat:/^السبت/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'el-GR' => 'Date.CultureInfo={name:"el-GR",englishName:"Greek (Greece)",nativeName:"ελληνικά (Ελλάδα)",dayNames:["Κυριακή","Δευτέρα","Τρίτη","Τετάρτη","Πέμπτη","Παρασκευή","Σάββατο"],abbreviatedDayNames:["Κυρ","Δευ","Τρι","Τετ","Πεμ","Παρ","Σαβ"],shortestDayNames:["Κυ","Δε","Τρ","Τε","Πε","Πα","Σά"],firstLetterDayNames:["Κ","Δ","Τ","Τ","Π","Π","Σ"],monthNames:["Ιανουάριος","Φεβρουάριος","Μάρτιος","Απρίλιος","Μάιος","Ιούνιος","Ιούλιος","Αύγουστος","Σεπτέμβριος","Οκτώβριος","Νοέμβριος","Δεκέμβριος"],abbreviatedMonthNames:["Ιαν","Φεβ","Μαρ","Απρ","Μαϊ","Ιουν","Ιουλ","Αυγ","Σεπ","Οκτ","Νοε","Δεκ"],amDesignator:"πμ",pmDesignator:"μμ",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d/M/yyyy",longDate:"dddd, d MMMM yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, d MMMM yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^ιαν(ουάριος)?/i,feb:/^φεβ(ρουάριος)?/i,mar:/^μάρτιος/i,apr:/^απρ(ίλιος)?/i,may:/^μάιος/i,jun:/^ιούνιος/i,jul:/^ιούλιος/i,aug:/^αύγουστος/i,sep:/^σεπ(τέμβριος)?/i,oct:/^οκτ(ώβριος)?/i,nov:/^νοέμβριος/i,dec:/^δεκ(έμβριος)?/i,sun:/^κυ(ρ(ιακή)?)?/i,mon:/^δε(υ(τέρα)?)?/i,tue:/^τρ(ι(τη)?)?/i,wed:/^τε(τ(άρτη)?)?/i,thu:/^πε(μ(πτη)?)?/i,fri:/^πα(ρ(ασκευή)?)?/i,sat:/^σά(β(βατο)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'en-029' => 'Date.CultureInfo={name:"en-029",englishName:"English (Caribbean)",nativeName:"English (Caribbean)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"MM/dd/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'en-AU' => 'Date.CultureInfo={name:"en-AU",englishName:"English (Australia)",nativeName:"English (Australia)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d/MM/yyyy",longDate:"dddd, d MMMM yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, d MMMM yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'en-BZ' => 'Date.CultureInfo={name:"en-BZ",englishName:"English (Belize)",nativeName:"English (Belize)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd MMMM yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd MMMM yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'en-CA' => 'Date.CultureInfo={name:"en-CA",englishName:"English (Canada)",nativeName:"English (Canada)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"MMMM d, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"MMMM d, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'en-GB' => 'Date.CultureInfo={name:"en-GB",englishName:"English (United Kingdom)",nativeName:"English (United Kingdom)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dd MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'en-IE' => 'Date.CultureInfo={name:"en-IE",englishName:"English (Ireland)",nativeName:"English (Eire)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dd MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'en-JM' => 'Date.CultureInfo={name:"en-JM",englishName:"English (Jamaica)",nativeName:"English (Jamaica)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'en-NZ' => 'Date.CultureInfo={name:"en-NZ",englishName:"English (New Zealand)",nativeName:"English (New Zealand)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d/MM/yyyy",longDate:"dddd, d MMMM yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, d MMMM yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'en-PH' => 'Date.CultureInfo={name:"en-PH",englishName:"English (Republic of the Philippines)",nativeName:"English (Philippines)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'en-TT' => 'Date.CultureInfo={name:"en-TT",englishName:"English (Trinidad and Tobago)",nativeName:"English (Trinidad y Tobago)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd MMMM yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd MMMM yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'en-US' => 'Date.CultureInfo={name:"en-US",englishName:"English (United States)",nativeName:"English (United States)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'en-ZA' => 'Date.CultureInfo={name:"en-ZA",englishName:"English (South Africa)",nativeName:"English (South Africa)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy/MM/dd",longDate:"dd MMMM yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'en-ZW' => 'Date.CultureInfo={name:"en-ZW",englishName:"English (Zimbabwe)",nativeName:"English (Zimbabwe)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-AR' => 'Date.CultureInfo={name:"es-AR",englishName:"Spanish (Argentina)",nativeName:"Español (Argentina)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-BO' => 'Date.CultureInfo={name:"es-BO",englishName:"Spanish (Bolivia)",nativeName:"Español (Bolivia)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-CL' => 'Date.CultureInfo={name:"es-CL",englishName:"Spanish (Chile)",nativeName:"Español (Chile)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"",pmDesignator:"",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd-MM-yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-CO' => 'Date.CultureInfo={name:"es-CO",englishName:"Spanish (Colombia)",nativeName:"Español (Colombia)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-CR' => 'Date.CultureInfo={name:"es-CR",englishName:"Spanish (Costa Rica)",nativeName:"Español (Costa Rica)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-DO' => 'Date.CultureInfo={name:"es-DO",englishName:"Spanish (Dominican Republic)",nativeName:"Español (República Dominicana)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-EC' => 'Date.CultureInfo={name:"es-EC",englishName:"Spanish (Ecuador)",nativeName:"Español (Ecuador)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"",pmDesignator:"",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-ES' => 'Date.CultureInfo={name:"es-ES",englishName:"Spanish (Spain)",nativeName:"español (España)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-GT' => 'Date.CultureInfo={name:"es-GT",englishName:"Spanish (Guatemala)",nativeName:"Español (Guatemala)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-HN' => 'Date.CultureInfo={name:"es-HN",englishName:"Spanish (Honduras)",nativeName:"Español (Honduras)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-MX' => 'Date.CultureInfo={name:"es-MX",englishName:"Spanish (Mexico)",nativeName:"Español (México)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-NI' => 'Date.CultureInfo={name:"es-NI",englishName:"Spanish (Nicaragua)",nativeName:"Español (Nicaragua)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-PA' => 'Date.CultureInfo={name:"es-PA",englishName:"Spanish (Panama)",nativeName:"Español (Panamá)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"MM/dd/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-PE' => 'Date.CultureInfo={name:"es-PE",englishName:"Spanish (Peru)",nativeName:"Español (Perú)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-PR' => 'Date.CultureInfo={name:"es-PR",englishName:"Spanish (Puerto Rico)",nativeName:"Español (Puerto Rico)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-PY' => 'Date.CultureInfo={name:"es-PY",englishName:"Spanish (Paraguay)",nativeName:"Español (Paraguay)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-SV' => 'Date.CultureInfo={name:"es-SV",englishName:"Spanish (El Salvador)",nativeName:"Español (El Salvador)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-UY' => 'Date.CultureInfo={name:"es-UY",englishName:"Spanish (Uruguay)",nativeName:"Español (Uruguay)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'es-VE' => 'Date.CultureInfo={name:"es-VE",englishName:"Spanish (Venezuela)",nativeName:"Español (Republica Bolivariana de Venezuela)",dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],abbreviatedDayNames:["dom","lun","mar","mié","jue","vie","sáb"],shortestDayNames:["do","lu","ma","mi","ju","vi","sá"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],abbreviatedMonthNames:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^ene(ro)?/i,feb:/^feb(rero)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^may(o)?/i,jun:/^jun(io)?/i,jul:/^jul(io)?/i,aug:/^ago(sto)?/i,sep:/^sep(tiembre)?/i,oct:/^oct(ubre)?/i,nov:/^nov(iembre)?/i,dec:/^dic(iembre)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(n(es)?)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mi(é(rcoles)?)?/i,thu:/^ju(e(ves)?)?/i,fri:/^vi(e(rnes)?)?/i,sat:/^sá(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'et-EE' => 'Date.CultureInfo={name:"et-EE",englishName:"Estonian (Estonia)",nativeName:"eesti (Eesti)",dayNames:["pühapäev","esmaspäev","teisipäev","kolmapäev","neljapäev","reede","laupäev"],abbreviatedDayNames:["P","E","T","K","N","R","L"],shortestDayNames:["P","E","T","K","N","R","L"],firstLetterDayNames:["P","E","T","K","N","R","L"],monthNames:["jaanuar","veebruar","märts","aprill","mai","juuni","juuli","august","september","oktoober","november","detsember"],abbreviatedMonthNames:["jaan","veebr","märts","apr","mai","juuni","juuli","aug","sept","okt","nov","dets"],amDesignator:"EL",pmDesignator:"PL",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d.MM.yyyy",longDate:"d. MMMM yyyy\'. a.\'",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d. MMMM yyyy\'. a.\' H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d. MMMM",yearMonth:"MMMM yyyy\'. a.\'"},regexPatterns:{jan:/^jaan(uar)?/i,feb:/^veebr(uar)?/i,mar:/^märts/i,apr:/^apr(ill)?/i,may:/^mai/i,jun:/^juuni/i,jul:/^juuli/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(oober)?/i,nov:/^nov(ember)?/i,dec:/^dets(ember)?/i,sun:/^pühapäev/i,mon:/^esmaspäev/i,tue:/^teisipäev/i,wed:/^kolmapäev/i,thu:/^neljapäev/i,fri:/^reede/i,sat:/^laupäev/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'eu-ES' => 'Date.CultureInfo={name:"eu-ES",englishName:"Basque (Basque)",nativeName:"euskara (euskara)",dayNames:["igandea","astelehena","asteartea","asteazkena","osteguna","ostirala","larunbata"],abbreviatedDayNames:["ig.","al.","as.","az.","og.","or.","lr."],shortestDayNames:["ig","al","as","az","og","or","lr"],firstLetterDayNames:["i","a","a","a","o","o","l"],monthNames:["urtarrila","otsaila","martxoa","apirila","maiatza","ekaina","uztaila","abuztua","iraila","urria","azaroa","abendua"],abbreviatedMonthNames:["urt.","ots.","mar.","api.","mai.","eka.","uzt.","abu.","ira.","urr.","aza.","abe."],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy/MM/dd",longDate:"dddd, yyyy.\'eko\' MMMM\'k \'d",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dddd, yyyy.\'eko\' MMMM\'k \'d HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"yyyy.\'eko\' MMMM"},regexPatterns:{jan:/^urt(.(arrila)?)?/i,feb:/^ots(.(aila)?)?/i,mar:/^mar(.(txoa)?)?/i,apr:/^api(.(rila)?)?/i,may:/^mai(.(atza)?)?/i,jun:/^eka(.(ina)?)?/i,jul:/^uzt(.(aila)?)?/i,aug:/^abu(.(ztua)?)?/i,sep:/^ira(.(ila)?)?/i,oct:/^urr(.(ia)?)?/i,nov:/^aza(.(roa)?)?/i,dec:/^abe(.(ndua)?)?/i,sun:/^ig((.(andea)?)?)?/i,mon:/^al((.(telehena)?)?)?/i,tue:/^as((.(teartea)?)?)?/i,wed:/^az((.(teazkena)?)?)?/i,thu:/^og((.(teguna)?)?)?/i,fri:/^or((.(tirala)?)?)?/i,sat:/^lr((.(runbata)?)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'fa-IR' => 'Date.CultureInfo={name:"fa-IR",englishName:"Persian (Iran)",nativeName:"فارسى (ايران)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"ق.ظ",pmDesignator:"ب.ظ",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'fi-FI' => 'Date.CultureInfo={name:"fi-FI",englishName:"Finnish (Finland)",nativeName:"suomi (Suomi)",dayNames:["sunnuntai","maanantai","tiistai","keskiviikko","torstai","perjantai","lauantai"],abbreviatedDayNames:["su","ma","ti","ke","to","pe","la"],shortestDayNames:["su","ma","ti","ke","to","pe","la"],firstLetterDayNames:["s","m","t","k","t","p","l"],monthNames:["tammikuu","helmikuu","maaliskuu","huhtikuu","toukokuu","kesäkuu","heinäkuu","elokuu","syyskuu","lokakuu","marraskuu","joulukuu"],abbreviatedMonthNames:["tammi","helmi","maalis","huhti","touko","kesä","heinä","elo","syys","loka","marras","joulu"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d.M.yyyy",longDate:"d. MMMM\'ta \'yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d. MMMM\'ta \'yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d. MMMM\'ta\'",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^tammi(kuu)?/i,feb:/^helmi(kuu)?/i,mar:/^maalis(kuu)?/i,apr:/^huhti(kuu)?/i,may:/^touko(kuu)?/i,jun:/^kesä(kuu)?/i,jul:/^heinä(kuu)?/i,aug:/^elo(kuu)?/i,sep:/^syys(kuu)?/i,oct:/^loka(kuu)?/i,nov:/^marras(kuu)?/i,dec:/^joulu(kuu)?/i,sun:/^sunnuntai/i,mon:/^maanantai/i,tue:/^tiistai/i,wed:/^keskiviikko/i,thu:/^torstai/i,fri:/^perjantai/i,sat:/^lauantai/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'fo-FO' => 'Date.CultureInfo={name:"fo-FO",englishName:"Faroese (Faroe Islands)",nativeName:"føroyskt (Føroyar)",dayNames:["sunnudagur","mánadagur","týsdagur","mikudagur","hósdagur","fríggjadagur","leygardagur"],abbreviatedDayNames:["sun","mán","týs","mik","hós","frí","leyg"],shortestDayNames:["su","má","tý","mi","hó","fr","ley"],firstLetterDayNames:["s","m","t","m","h","f","l"],monthNames:["januar","februar","mars","apríl","mai","juni","juli","august","september","oktober","november","desember"],abbreviatedMonthNames:["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd-MM-yyyy",longDate:"d. MMMM yyyy",shortTime:"HH.mm",longTime:"HH.mm.ss",fullDateTime:"d. MMMM yyyy HH.mm.ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d. MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uar)?/i,feb:/^feb(ruar)?/i,mar:/^mar(s)?/i,apr:/^apr(íl)?/i,may:/^mai/i,jun:/^jun(i)?/i,jul:/^jul(i)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nov(ember)?/i,dec:/^des(ember)?/i,sun:/^su(n(nudagur)?)?/i,mon:/^má(n(adagur)?)?/i,tue:/^tý(s(dagur)?)?/i,wed:/^mi(k(udagur)?)?/i,thu:/^hó(s(dagur)?)?/i,fri:/^fr(í(ggjadagur)?)?/i,sat:/^ley(g(ardagur)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'fr-BE' => 'Date.CultureInfo={name:"fr-BE",englishName:"French (Belgium)",nativeName:"français (Belgique)",dayNames:["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"],abbreviatedDayNames:["dim.","lun.","mar.","mer.","jeu.","ven.","sam."],shortestDayNames:["di","lu","ma","me","je","ve","sa"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"],abbreviatedMonthNames:["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc."],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d/MM/yyyy",longDate:"dddd d MMMM yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dddd d MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^janv(.(ier)?)?/i,feb:/^févr(.(ier)?)?/i,mar:/^mars/i,apr:/^avr(.(il)?)?/i,may:/^mai/i,jun:/^juin/i,jul:/^juil(.(let)?)?/i,aug:/^août/i,sep:/^sept(.(embre)?)?/i,oct:/^oct(.(obre)?)?/i,nov:/^nov(.(embre)?)?/i,dec:/^déc(.(embre)?)?/i,sun:/^di(m(.(anche)?)?)?/i,mon:/^lu(n(.(di)?)?)?/i,tue:/^ma(r(.(di)?)?)?/i,wed:/^me(r(.(credi)?)?)?/i,thu:/^je(u(.(di)?)?)?/i,fri:/^ve(n(.(dredi)?)?)?/i,sat:/^sa(m(.(edi)?)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'fr-CA' => 'Date.CultureInfo={name:"fr-CA",englishName:"French (Canada)",nativeName:"français (Canada)",dayNames:["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"],abbreviatedDayNames:["dim.","lun.","mar.","mer.","jeu.","ven.","sam."],shortestDayNames:["di","lu","ma","me","je","ve","sa"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"],abbreviatedMonthNames:["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc."],amDesignator:"",pmDesignator:"",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy-MM-dd",longDate:"d MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"d MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^janv(.(ier)?)?/i,feb:/^févr(.(ier)?)?/i,mar:/^mars/i,apr:/^avr(.(il)?)?/i,may:/^mai/i,jun:/^juin/i,jul:/^juil(.(let)?)?/i,aug:/^août/i,sep:/^sept(.(embre)?)?/i,oct:/^oct(.(obre)?)?/i,nov:/^nov(.(embre)?)?/i,dec:/^déc(.(embre)?)?/i,sun:/^di(m(.(anche)?)?)?/i,mon:/^lu(n(.(di)?)?)?/i,tue:/^ma(r(.(di)?)?)?/i,wed:/^me(r(.(credi)?)?)?/i,thu:/^je(u(.(di)?)?)?/i,fri:/^ve(n(.(dredi)?)?)?/i,sat:/^sa(m(.(edi)?)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'fr-CH' => 'Date.CultureInfo={name:"fr-CH",englishName:"French (Switzerland)",nativeName:"français (Suisse)",dayNames:["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"],abbreviatedDayNames:["dim.","lun.","mar.","mer.","jeu.","ven.","sam."],shortestDayNames:["di","lu","ma","me","je","ve","sa"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"],abbreviatedMonthNames:["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc."],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"dddd, d. MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dddd, d. MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^janv(.(ier)?)?/i,feb:/^févr(.(ier)?)?/i,mar:/^mars/i,apr:/^avr(.(il)?)?/i,may:/^mai/i,jun:/^juin/i,jul:/^juil(.(let)?)?/i,aug:/^août/i,sep:/^sept(.(embre)?)?/i,oct:/^oct(.(obre)?)?/i,nov:/^nov(.(embre)?)?/i,dec:/^déc(.(embre)?)?/i,sun:/^di(m(.(anche)?)?)?/i,mon:/^lu(n(.(di)?)?)?/i,tue:/^ma(r(.(di)?)?)?/i,wed:/^me(r(.(credi)?)?)?/i,thu:/^je(u(.(di)?)?)?/i,fri:/^ve(n(.(dredi)?)?)?/i,sat:/^sa(m(.(edi)?)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'fr-FR' => 'Date.CultureInfo={name:"fr-FR",englishName:"French (France)",nativeName:"français (France)",dayNames:["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"],abbreviatedDayNames:["dim.","lun.","mar.","mer.","jeu.","ven.","sam."],shortestDayNames:["di","lu","ma","me","je","ve","sa"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"],abbreviatedMonthNames:["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc."],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd d MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dddd d MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^janv(.(ier)?)?/i,feb:/^févr(.(ier)?)?/i,mar:/^mars/i,apr:/^avr(.(il)?)?/i,may:/^mai/i,jun:/^juin/i,jul:/^juil(.(let)?)?/i,aug:/^août/i,sep:/^sept(.(embre)?)?/i,oct:/^oct(.(obre)?)?/i,nov:/^nov(.(embre)?)?/i,dec:/^déc(.(embre)?)?/i,sun:/^di(m(.(anche)?)?)?/i,mon:/^lu(n(.(di)?)?)?/i,tue:/^ma(r(.(di)?)?)?/i,wed:/^me(r(.(credi)?)?)?/i,thu:/^je(u(.(di)?)?)?/i,fri:/^ve(n(.(dredi)?)?)?/i,sat:/^sa(m(.(edi)?)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'fr-LU' => 'Date.CultureInfo={name:"fr-LU",englishName:"French (Luxembourg)",nativeName:"français (Luxembourg)",dayNames:["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"],abbreviatedDayNames:["dim.","lun.","mar.","mer.","jeu.","ven.","sam."],shortestDayNames:["di","lu","ma","me","je","ve","sa"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"],abbreviatedMonthNames:["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc."],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd d MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dddd d MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^janv(.(ier)?)?/i,feb:/^févr(.(ier)?)?/i,mar:/^mars/i,apr:/^avr(.(il)?)?/i,may:/^mai/i,jun:/^juin/i,jul:/^juil(.(let)?)?/i,aug:/^août/i,sep:/^sept(.(embre)?)?/i,oct:/^oct(.(obre)?)?/i,nov:/^nov(.(embre)?)?/i,dec:/^déc(.(embre)?)?/i,sun:/^di(m(.(anche)?)?)?/i,mon:/^lu(n(.(di)?)?)?/i,tue:/^ma(r(.(di)?)?)?/i,wed:/^me(r(.(credi)?)?)?/i,thu:/^je(u(.(di)?)?)?/i,fri:/^ve(n(.(dredi)?)?)?/i,sat:/^sa(m(.(edi)?)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'fr-MC' => 'Date.CultureInfo={name:"fr-MC",englishName:"French (Principality of Monaco)",nativeName:"français (Principauté de Monaco)",dayNames:["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"],abbreviatedDayNames:["dim.","lun.","mar.","mer.","jeu.","ven.","sam."],shortestDayNames:["di","lu","ma","me","je","ve","sa"],firstLetterDayNames:["d","l","m","m","j","v","s"],monthNames:["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"],abbreviatedMonthNames:["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc."],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd d MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dddd d MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^janv(.(ier)?)?/i,feb:/^févr(.(ier)?)?/i,mar:/^mars/i,apr:/^avr(.(il)?)?/i,may:/^mai/i,jun:/^juin/i,jul:/^juil(.(let)?)?/i,aug:/^août/i,sep:/^sept(.(embre)?)?/i,oct:/^oct(.(obre)?)?/i,nov:/^nov(.(embre)?)?/i,dec:/^déc(.(embre)?)?/i,sun:/^di(m(.(anche)?)?)?/i,mon:/^lu(n(.(di)?)?)?/i,tue:/^ma(r(.(di)?)?)?/i,wed:/^me(r(.(credi)?)?)?/i,thu:/^je(u(.(di)?)?)?/i,fri:/^ve(n(.(dredi)?)?)?/i,sat:/^sa(m(.(edi)?)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'gl-ES' => 'Date.CultureInfo={name:"gl-ES",englishName:"Galician (Galician)",nativeName:"galego (galego)",dayNames:["domingo","luns","martes","mércores","xoves","venres","sábado"],abbreviatedDayNames:["dom","luns","mar","mér","xov","ven","sab"],shortestDayNames:["do","lu","ma","mé","xo","ve","sa"],firstLetterDayNames:["d","l","m","m","x","v","s"],monthNames:["xaneiro","febreiro","marzo","abril","maio","xuño","xullo","agosto","setembro","outubro","novembro","decembro"],abbreviatedMonthNames:["xan","feb","mar","abr","maio","xuñ","xull","ago","set","out","nov","dec"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^xan(eiro)?/i,feb:/^feb(reiro)?/i,mar:/^mar(zo)?/i,apr:/^abr(il)?/i,may:/^maio/i,jun:/^xuñ(o)?/i,jul:/^xull(o)?/i,aug:/^ago(sto)?/i,sep:/^set(embro)?/i,oct:/^out(ubro)?/i,nov:/^nov(embro)?/i,dec:/^dec(embro)?/i,sun:/^do(m(ingo)?)?/i,mon:/^lu(1)?/i,tue:/^ma(r(tes)?)?/i,wed:/^mé(r(cores)?)?/i,thu:/^xo(v(es)?)?/i,fri:/^ve(n(res)?)?/i,sat:/^sa(b(ado)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'gu-IN' => 'Date.CultureInfo={name:"gu-IN",englishName:"Gujarati (India)",nativeName:"ગુજરાતી (ભારત)",dayNames:["રવિવાર","સોમવાર","મંગળવાર","બુધવાર","ગુરુવાર","શુક્રવાર","શનિવાર"],abbreviatedDayNames:["રવિ","સોમ","મંગળ","બુધ","ગુરુ","શુક્ર","શનિ"],shortestDayNames:["ર","સ","મ","બ","ગ","શ","શ"],firstLetterDayNames:["ર","સ","મ","બ","ગ","શ","શ"],monthNames:["જાન્યુઆરી","ફેબ્રુઆરી","માર્ચ","એપ્રિલ","મે","જૂન","જુલાઈ","ઑગસ્ટ","સપ્ટેમ્બર","ઑક્ટ્બર","નવેમ્બર","ડિસેમ્બર"],abbreviatedMonthNames:["જાન્યુ","ફેબ્રુ","માર્ચ","એપ્રિલ","મે","જૂન","જુલાઈ","ઑગસ્ટ","સપ્ટે","ઑક્ટો","નવે","ડિસે"],amDesignator:"પૂર્વ મધ્યાહ્ન",pmDesignator:"ઉત્તર મધ્યાહ્ન",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd-MM-yy",longDate:"dd MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dd MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^જાન્યુ(આરી)?/i,feb:/^ફેબ્રુ(આરી)?/i,mar:/^માર્ચ/i,apr:/^એપ્રિલ/i,may:/^મે/i,jun:/^જૂન/i,jul:/^જુલાઈ/i,aug:/^ઑગસ્ટ/i,sep:/^સપ્ટે(મ્બર)?/i,oct:/^ઑક્ટ્બર/i,nov:/^નવે(મ્બર)?/i,dec:/^ડિસે(મ્બર)?/i,sun:/^ર(વિ(વાર)?)?/i,mon:/^સ(ોમ(વાર)?)?/i,tue:/^મ(ંગળ(વાર)?)?/i,wed:/^બ(ુધ(વાર)?)?/i,thu:/^ગ(ુરુ(વાર)?)?/i,fri:/^શ(ુક્ર(વાર)?)?/i,sat:/^શ(નિ(વાર)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'he-IL' => 'Date.CultureInfo={name:"he-IL",englishName:"Hebrew (Israel)",nativeName:"עברית (ישראל)",dayNames:["יום ראשון","יום שני","יום שלישי","יום רביעי","יום חמישי","יום שישי","שבת"],abbreviatedDayNames:["יום א","יום ב","יום ג","יום ד","יום ה","יום ו","שבת"],shortestDayNames:["א","ב","ג","ד","ה","ו","ש"],firstLetterDayNames:["א","ב","ג","ד","ה","ו","ש"],monthNames:["ינואר","פברואר","מרץ","אפריל","מאי","יוני","יולי","אוגוסט","ספטמבר","אוקטובר","נובמבר","דצמבר"],abbreviatedMonthNames:["ינו","פבר","מרץ","אפר","מאי","יונ","יול","אוג","ספט","אוק","נוב","דצמ"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd dd MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dddd dd MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^ינו(אר)?/i,feb:/^פבר(ואר)?/i,mar:/^מרץ/i,apr:/^אפר(יל)?/i,may:/^מאי/i,jun:/^יונ(י)?/i,jul:/^יול(י)?/i,aug:/^אוג(וסט)?/i,sep:/^ספט(מבר)?/i,oct:/^אוק(טובר)?/i,nov:/^נוב(מבר)?/i,dec:/^דצמ(בר)?/i,sun:/^א(ום א(אשון)?)?/i,mon:/^ב(ום ב(ני)?)?/i,tue:/^ג(ום ג(לישי)?)?/i,wed:/^ד(ום ד(ביעי)?)?/i,thu:/^ה(ום ה(מישי)?)?/i,fri:/^ו(ום ו(ישי)?)?/i,sat:/^ש(1)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'hi-IN' => 'Date.CultureInfo={name:"hi-IN",englishName:"Hindi (India)",nativeName:"हिंदी (भारत)",dayNames:["रविवार","सोमवार","मंगलवार","बुधवार","गुरुवार","शुक्रवार","शनिवार"],abbreviatedDayNames:["रवि.","सोम.","मंगल.","बुध.","गुरु.","शुक्र.","शनि."],shortestDayNames:["र","स","म","ब","ग","श","श"],firstLetterDayNames:["र","स","म","ब","ग","श","श"],monthNames:["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर"],abbreviatedMonthNames:["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर"],amDesignator:"पूर्वाह्न",pmDesignator:"अपराह्न",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd-MM-yyyy",longDate:"dd MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dd MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^जनवरी/i,feb:/^फरवरी/i,mar:/^मार्च/i,apr:/^अप्रैल/i,may:/^मई/i,jun:/^जून/i,jul:/^जुलाई/i,aug:/^अगस्त/i,sep:/^सितम्बर/i,oct:/^अक्तूबर/i,nov:/^नवम्बर/i,dec:/^दिसम्बर/i,sun:/^र(वि(.(वार)?)?)?/i,mon:/^स(ोम(.(वार)?)?)?/i,tue:/^म(ंगल(.(वार)?)?)?/i,wed:/^ब(ुध(.(वार)?)?)?/i,thu:/^ग(ुरु(.(वार)?)?)?/i,fri:/^श(ुक्र(.(वार)?)?)?/i,sat:/^श(नि(.(वार)?)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'hr-BA' => 'Date.CultureInfo={name:"hr-BA",englishName:"Croatian (Bosnia and Herzegovina)",nativeName:"hrvatski (Bosna i Hercegovina)",dayNames:["nedjelja","ponedjeljak","utorak","srijeda","četvrtak","petak","subota"],abbreviatedDayNames:["ned","pon","uto","sri","čet","pet","sub"],shortestDayNames:["ned","pon","uto","sri","čet","pet","sub"],firstLetterDayNames:["n","p","u","s","č","p","s"],monthNames:["siječanj","veljača","ožujak","travanj","svibanj","lipanj","srpanj","kolovoz","rujan","listopad","studeni","prosinac"],abbreviatedMonthNames:["sij","vlj","ožu","tra","svi","lip","srp","kol","ruj","lis","stu","pro"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d.M.yyyy",longDate:"d. MMMM yyyy",shortTime:"H:mm:ss",longTime:"H:mm:ss",fullDateTime:"d. MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^sij(ečanj)?/i,feb:/^veljača/i,mar:/^ožu(jak)?/i,apr:/^tra(vanj)?/i,may:/^svi(banj)?/i,jun:/^lip(anj)?/i,jul:/^srp(anj)?/i,aug:/^kol(ovoz)?/i,sep:/^ruj(an)?/i,oct:/^lis(topad)?/i,nov:/^stu(deni)?/i,dec:/^pro(sinac)?/i,sun:/^nedjelja/i,mon:/^ponedjeljak/i,tue:/^utorak/i,wed:/^srijeda/i,thu:/^četvrtak/i,fri:/^petak/i,sat:/^subota/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'hr-HR' => 'Date.CultureInfo={name:"hr-HR",englishName:"Croatian (Croatia)",nativeName:"hrvatski (Hrvatska)",dayNames:["nedjelja","ponedjeljak","utorak","srijeda","četvrtak","petak","subota"],abbreviatedDayNames:["ned","pon","uto","sri","čet","pet","sub"],shortestDayNames:["ne","po","ut","sr","če","pe","su"],firstLetterDayNames:["n","p","u","s","č","p","s"],monthNames:["siječanj","veljača","ožujak","travanj","svibanj","lipanj","srpanj","kolovoz","rujan","listopad","studeni","prosinac"],abbreviatedMonthNames:["sij","vlj","ožu","tra","svi","lip","srp","kol","ruj","lis","stu","pro"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d.M.yyyy",longDate:"d. MMMM yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d. MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d. MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^sij(ečanj)?/i,feb:/^veljača/i,mar:/^ožu(jak)?/i,apr:/^tra(vanj)?/i,may:/^svi(banj)?/i,jun:/^lip(anj)?/i,jul:/^srp(anj)?/i,aug:/^kol(ovoz)?/i,sep:/^ruj(an)?/i,oct:/^lis(topad)?/i,nov:/^stu(deni)?/i,dec:/^pro(sinac)?/i,sun:/^ne(d(jelja)?)?/i,mon:/^po(n(edjeljak)?)?/i,tue:/^ut(o(rak)?)?/i,wed:/^sr(i(jeda)?)?/i,thu:/^če(t(vrtak)?)?/i,fri:/^pe(t(ak)?)?/i,sat:/^su(b(ota)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'hu-HU' => 'Date.CultureInfo={name:"hu-HU",englishName:"Hungarian (Hungary)",nativeName:"magyar (Magyarország)",dayNames:["vasárnap","hétfő","kedd","szerda","csütörtök","péntek","szombat"],abbreviatedDayNames:["V","H","K","Sze","Cs","P","Szo"],shortestDayNames:["V","H","K","Sze","Cs","P","Szo"],firstLetterDayNames:["V","H","K","S","C","P","S"],monthNames:["január","február","március","április","május","június","július","augusztus","szeptember","október","november","december"],abbreviatedMonthNames:["jan.","febr.","márc.","ápr.","máj.","jún.","júl.","aug.","szept.","okt.","nov.","dec."],amDesignator:"de.",pmDesignator:"du.",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy. MM. dd.",longDate:"yyyy. MMMM d.",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"yyyy. MMMM d. H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM d.",yearMonth:"yyyy. MMMM"},regexPatterns:{jan:/^jan(.(uár)?)?/i,feb:/^febr(.(uár)?)?/i,mar:/^márc(.(ius)?)?/i,apr:/^ápr(.(ilis)?)?/i,may:/^máj(.(us)?)?/i,jun:/^jún(.(ius)?)?/i,jul:/^júl(.(ius)?)?/i,aug:/^aug(.(usztus)?)?/i,sep:/^szept(.(ember)?)?/i,oct:/^okt(.(óber)?)?/i,nov:/^nov(.(ember)?)?/i,dec:/^dec(.(ember)?)?/i,sun:/^vasárnap/i,mon:/^hétfő/i,tue:/^kedd/i,wed:/^szerda/i,thu:/^csütörtök/i,fri:/^péntek/i,sat:/^szombat/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'hy-AM' => 'Date.CultureInfo={name:"hy-AM",englishName:"Armenian (Armenia)",nativeName:"Հայերեն (Հայաստան)",dayNames:["Կիրակի","Երկուշաբթի","Երեքշաբթի","Չորեքշաբթի","Հինգշաբթի","ՈՒրբաթ","Շաբաթ"],abbreviatedDayNames:["Կիր","Երկ","Երք","Չրք","Հնգ","ՈՒր","Շբթ"],shortestDayNames:["Կ","Ե","Ե","Չ","Հ","Ո","Շ"],firstLetterDayNames:["Կ","Ե","Ե","Չ","Հ","Ո","Շ"],monthNames:["Հունվար","Փետրվար","Մարտ","Ապրիլ","Մայիս","Հունիս","Հուլիս","Օգոստոս","Սեպտեմբեր","Հոկտեմբեր","Նոյեմբեր","Դեկտեմբեր"],abbreviatedMonthNames:["ՀՆՎ","ՓՏՎ","ՄՐՏ","ԱՊՐ","ՄՅՍ","ՀՆՍ","ՀԼՍ","ՕԳՍ","ՍԵՊ","ՀՈԿ","ՆՈՅ","ԴԵԿ"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"d MMMM, yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d MMMM, yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^հունվար/i,feb:/^փետրվար/i,mar:/^մարտ/i,apr:/^ապր(իլ)?/i,may:/^մայիս/i,jun:/^հունիս/i,jul:/^հուլիս/i,aug:/^օգոստոս/i,sep:/^սեպ(տեմբեր)?/i,oct:/^հոկ(տեմբեր)?/i,nov:/^նոյ(եմբեր)?/i,dec:/^դեկ(տեմբեր)?/i,sun:/^կ(իր(ակի)?)?/i,mon:/^ե(րկ(ուշաբթի)?)?/i,tue:/^ե(րք(քշաբթի)?)?/i,wed:/^չ(րք(եքշաբթի)?)?/i,thu:/^հ(նգ(գշաբթի)?)?/i,fri:/^ո(ւր(բաթ)?)?/i,sat:/^շ(բթ(աթ)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'id-ID' => 'Date.CultureInfo={name:"id-ID",englishName:"Indonesian (Indonesia)",nativeName:"Bahasa Indonesia (Indonesia)",dayNames:["Minggu","Senin","Selasa","Rabu","Kamis","Jumat","Sabtu"],abbreviatedDayNames:["Minggu","Sen","Sel","Rabu","Kamis","Jumat","Sabtu"],shortestDayNames:["M","S","S","R","K","J","S"],firstLetterDayNames:["M","S","S","R","K","J","S"],monthNames:["Januari","Februari","Maret","April","Mei","Juni","Juli","Agustus","September","Oktober","Nopember","Desember"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Agust","Sep","Okt","Nop","Des"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dd MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uari)?/i,feb:/^feb(ruari)?/i,mar:/^mar(et)?/i,apr:/^apr(il)?/i,may:/^mei/i,jun:/^jun(i)?/i,jul:/^jul(i)?/i,aug:/^agust(us)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nop(ember)?/i,dec:/^des(ember)?/i,sun:/^m(1)?/i,mon:/^s(en(in)?)?/i,tue:/^s(el(asa)?)?/i,wed:/^r(1)?/i,thu:/^k(1)?/i,fri:/^j(1)?/i,sat:/^s(1)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'is-IS' => 'Date.CultureInfo={name:"is-IS",englishName:"Icelandic (Iceland)",nativeName:"íslenska (Ísland)",dayNames:["sunnudagur","mánudagur","þriðjudagur","miðvikudagur","fimmtudagur","föstudagur","laugardagur"],abbreviatedDayNames:["sun.","mán.","þri.","mið.","fim.","fös.","lau."],shortestDayNames:["su","má","þr","mi","fi","fö","la"],firstLetterDayNames:["s","m","þ","m","f","f","l"],monthNames:["janúar","febrúar","mars","apríl","maí","júní","júlí","ágúst","september","október","nóvember","desember"],abbreviatedMonthNames:["jan.","feb.","mar.","apr.","maí","jún.","júl.","ágú.","sep.","okt.","nóv.","des."],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d.M.yyyy",longDate:"d. MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"d. MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d. MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(.(úar)?)?/i,feb:/^feb(.(rúar)?)?/i,mar:/^mar(.(s)?)?/i,apr:/^apr(.(íl)?)?/i,may:/^maí/i,jun:/^jún(.(í)?)?/i,jul:/^júl(.(í)?)?/i,aug:/^ágú(.(st)?)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(.(óber)?)?/i,nov:/^nóv(.(ember)?)?/i,dec:/^des(.(ember)?)?/i,sun:/^su(n(.(nudagur)?)?)?/i,mon:/^má(n(.(udagur)?)?)?/i,tue:/^þr(i(.(ðjudagur)?)?)?/i,wed:/^mi(ð(.(vikudagur)?)?)?/i,thu:/^fi(m(.(mtudagur)?)?)?/i,fri:/^fö(s(.(tudagur)?)?)?/i,sat:/^la(u(.(gardagur)?)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'it-CH' => 'Date.CultureInfo={name:"it-CH",englishName:"Italian (Switzerland)",nativeName:"italiano (Svizzera)",dayNames:["domenica","lunedì","martedì","mercoledì","giovedì","venerdì","sabato"],abbreviatedDayNames:["dom","lun","mar","mer","gio","ven","sab"],shortestDayNames:["do","lu","ma","me","gi","ve","sa"],firstLetterDayNames:["d","l","m","m","g","v","s"],monthNames:["gennaio","febbraio","marzo","aprile","maggio","giugno","luglio","agosto","settembre","ottobre","novembre","dicembre"],abbreviatedMonthNames:["gen","feb","mar","apr","mag","gio","lug","ago","set","ott","nov","dic"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"dddd, d. MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dddd, d. MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d. MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^gen(naio)?/i,feb:/^feb(braio)?/i,mar:/^mar(zo)?/i,apr:/^apr(ile)?/i,may:/^mag(gio)?/i,jun:/^giugno/i,jul:/^lug(lio)?/i,aug:/^ago(sto)?/i,sep:/^set(tembre)?/i,oct:/^ott(obre)?/i,nov:/^nov(embre)?/i,dec:/^dic(embre)?/i,sun:/^do(m(enica)?)?/i,mon:/^lu(n(edì)?)?/i,tue:/^ma(r(tedì)?)?/i,wed:/^me(r(coledì)?)?/i,thu:/^gi(o(vedì)?)?/i,fri:/^ve(n(erdì)?)?/i,sat:/^sa(b(ato)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'it-IT' => 'Date.CultureInfo={name:"it-IT",englishName:"Italian (Italy)",nativeName:"italiano (Italia)",dayNames:["domenica","lunedì","martedì","mercoledì","giovedì","venerdì","sabato"],abbreviatedDayNames:["dom","lun","mar","mer","gio","ven","sab"],shortestDayNames:["do","lu","ma","me","gi","ve","sa"],firstLetterDayNames:["d","l","m","m","g","v","s"],monthNames:["gennaio","febbraio","marzo","aprile","maggio","giugno","luglio","agosto","settembre","ottobre","novembre","dicembre"],abbreviatedMonthNames:["gen","feb","mar","apr","mag","giu","lug","ago","set","ott","nov","dic"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd d MMMM yyyy",shortTime:"H.mm",longTime:"H.mm.ss",fullDateTime:"dddd d MMMM yyyy H.mm.ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^gen(naio)?/i,feb:/^feb(braio)?/i,mar:/^mar(zo)?/i,apr:/^apr(ile)?/i,may:/^mag(gio)?/i,jun:/^giu(gno)?/i,jul:/^lug(lio)?/i,aug:/^ago(sto)?/i,sep:/^set(tembre)?/i,oct:/^ott(obre)?/i,nov:/^nov(embre)?/i,dec:/^dic(embre)?/i,sun:/^do(m(enica)?)?/i,mon:/^lu(n(edì)?)?/i,tue:/^ma(r(tedì)?)?/i,wed:/^me(r(coledì)?)?/i,thu:/^gi(o(vedì)?)?/i,fri:/^ve(n(erdì)?)?/i,sat:/^sa(b(ato)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ja-JP' => 'Date.CultureInfo={name:"ja-JP",englishName:"Japanese (Japan)",nativeName:"日本語 (日本)",dayNames:["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"],abbreviatedDayNames:["日","月","火","水","木","金","土"],shortestDayNames:["日","月","火","水","木","金","土"],firstLetterDayNames:["日","月","火","水","木","金","土"],monthNames:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],abbreviatedMonthNames:["1","2","3","4","5","6","7","8","9","10","11","12"],amDesignator:"午前",pmDesignator:"午後",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy/MM/dd",longDate:"yyyy\'年\'M\'月\'d\'日\'",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"yyyy\'年\'M\'月\'d\'日\' H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"M\'月\'d\'日\'",yearMonth:"yyyy\'年\'M\'月\'"},regexPatterns:{jan:/^1(月)?/i,feb:/^2(月)?/i,mar:/^3(月)?/i,apr:/^4(月)?/i,may:/^5(月)?/i,jun:/^6(月)?/i,jul:/^7(月)?/i,aug:/^8(月)?/i,sep:/^9(月)?/i,oct:/^10(月)?/i,nov:/^11(月)?/i,dec:/^12(月)?/i,sun:/^日曜日/i,mon:/^月曜日/i,tue:/^火曜日/i,wed:/^水曜日/i,thu:/^木曜日/i,fri:/^金曜日/i,sat:/^土曜日/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ka-GE' => 'Date.CultureInfo={name:"ka-GE",englishName:"Georgian (Georgia)",nativeName:"ქართული (საქართველო)",dayNames:["კვირა","ორშაბათი","სამშაბათი","ოთხშაბათი","ხუთშაბათი","პარასკევი","შაბათი"],abbreviatedDayNames:["კვირა","ორშაბათი","სამშაბათი","ოთხშაბათი","ხუთშაბათი","პარასკევი","შაბათი"],shortestDayNames:["კ","ო","ს","ო","ხ","პ","შ"],firstLetterDayNames:["კ","ო","ს","ო","ხ","პ","შ"],monthNames:["იანვარი","თებერვალი","მარტი","აპრილი","მაისი","ივნისი","ივლისი","აგვისტო","სექტემბერი","ოქტომბერი","ნოემბერი","დეკემბერი"],abbreviatedMonthNames:["იან","თებ","მარ","აპრ","მაის","ივნ","ივლ","აგვ","სექ","ოქტ","ნოემ","დეკ"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"yyyy \'წლის\' dd MM, dddd",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"yyyy \'წლის\' dd MM, dddd H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^იან(ვარი)?/i,feb:/^თებ(ერვალი)?/i,mar:/^მარ(ტი)?/i,apr:/^აპრ(ილი)?/i,may:/^მაის(ი)?/i,jun:/^ივნ(ისი)?/i,jul:/^ივლ(ისი)?/i,aug:/^აგვ(ისტო)?/i,sep:/^სექ(ტემბერი)?/i,oct:/^ოქტ(ომბერი)?/i,nov:/^ნოემ(ბერი)?/i,dec:/^დეკ(ემბერი)?/i,sun:/^კ(1)?/i,mon:/^ო(1)?/i,tue:/^ს(1)?/i,wed:/^ო(1)?/i,thu:/^ხ(1)?/i,fri:/^პ(1)?/i,sat:/^შ(1)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'kk-KZ' => 'Date.CultureInfo={name:"kk-KZ",englishName:"Kazakh (Kazakhstan)",nativeName:"Қазақ (Қазақстан)",dayNames:["Жексенбі","Дүйсенбі","Сейсенбі","Сәрсенбі","Бейсенбі","Жұма","Сенбі"],abbreviatedDayNames:["Жк","Дс","Сс","Ср","Бс","Жм","Сн"],shortestDayNames:["Жк","Дс","Сс","Ср","Бс","Жм","Сн"],firstLetterDayNames:["Ж","Д","С","С","Б","Ж","С"],monthNames:["қаңтар","ақпан","наурыз","сәуір","мамыр","маусым","шілде","тамыз","қыркүйек","қазан","қараша","желтоқсан"],abbreviatedMonthNames:["Қаң","Ақп","Нау","Сәу","Мам","Мау","Шіл","Там","Қыр","Қаз","Қар","Жел"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"d MMMM yyyy \'ж.\'",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d MMMM yyyy \'ж.\' H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^қаң(тар)?/i,feb:/^ақп(ан)?/i,mar:/^нау(рыз)?/i,apr:/^сәу(ір)?/i,may:/^мам(ыр)?/i,jun:/^мау(сым)?/i,jul:/^шіл(де)?/i,aug:/^там(ыз)?/i,sep:/^қыр(күйек)?/i,oct:/^қаз(ан)?/i,nov:/^қар(аша)?/i,dec:/^жел(тоқсан)?/i,sun:/^жексенбі/i,mon:/^дүйсенбі/i,tue:/^сейсенбі/i,wed:/^сәрсенбі/i,thu:/^бейсенбі/i,fri:/^жұма/i,sat:/^сенбі/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'kn-IN' => 'Date.CultureInfo={name:"kn-IN",englishName:"Kannada (India)",nativeName:"ಕನ್ನಡ (ಭಾರತ)",dayNames:["ಭಾನುವಾರ","ಸೋಮವಾರ","ಮಂಗಳವಾರ","ಬುಧವಾರ","ಗುರುವಾರ","ಶುಕ್ರವಾರ","ಶನಿವಾರ"],abbreviatedDayNames:["ಭಾನು.","ಸೋಮ.","ಮಂಗಳ.","ಬುಧ.","ಗುರು.","ಶುಕ್ರ.","ಶನಿ."],shortestDayNames:["ರ","ಸ","ಮ","ಬ","ಗ","ಶ","ಶ"],firstLetterDayNames:["ರ","ಸ","ಮ","ಬ","ಗ","ಶ","ಶ"],monthNames:["ಜನವರಿ","ಫೆಬ್ರವರಿ","ಮಾರ್ಚ್","ಎಪ್ರಿಲ್","ಮೇ","ಜೂನ್","ಜುಲೈ","ಆಗಸ್ಟ್","ಸೆಪ್ಟಂಬರ್","ಅಕ್ಟೋಬರ್","ನವೆಂಬರ್","ಡಿಸೆಂಬರ್"],abbreviatedMonthNames:["ಜನವರಿ","ಫೆಬ್ರವರಿ","ಮಾರ್ಚ್","ಎಪ್ರಿಲ್","ಮೇ","ಜೂನ್","ಜುಲೈ","ಆಗಸ್ಟ್","ಸೆಪ್ಟಂಬರ್","ಅಕ್ಟೋಬರ್","ನವೆಂಬರ್","ಡಿಸೆಂಬರ್"],amDesignator:"ಪೂರ್ವಾಹ್ನ",pmDesignator:"ಅಪರಾಹ್ನ",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd-MM-yy",longDate:"dd MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dd MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^ಜನವರಿ/i,feb:/^ಫೆಬ್ರವರಿ/i,mar:/^ಮಾರ್ಚ್/i,apr:/^ಎಪ್ರಿಲ್/i,may:/^ಮೇ/i,jun:/^ಜೂನ್/i,jul:/^ಜುಲೈ/i,aug:/^ಆಗಸ್ಟ್/i,sep:/^ಸೆಪ್ಟಂಬರ್/i,oct:/^ಅಕ್ಟೋಬರ್/i,nov:/^ನವೆಂಬರ್/i,dec:/^ಡಿಸೆಂಬರ್/i,sun:/^ರ(ಾನು(.(ವಾರ)?)?)?/i,mon:/^ಸ(ೋಮ(.(ವಾರ)?)?)?/i,tue:/^ಮ(ಂಗಳ(.(ವಾರ)?)?)?/i,wed:/^ಬ(ುಧ(.(ವಾರ)?)?)?/i,thu:/^ಗ(ುರು(.(ವಾರ)?)?)?/i,fri:/^ಶ(ುಕ್ರ(.(ವಾರ)?)?)?/i,sat:/^ಶ(ನಿ(.(ವಾರ)?)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ko-KR' => 'Date.CultureInfo={name:"ko-KR",englishName:"Korean (Korea)",nativeName:"한국어 (대한민국)",dayNames:["일요일","월요일","화요일","수요일","목요일","금요일","토요일"],abbreviatedDayNames:["일","월","화","수","목","금","토"],shortestDayNames:["일","월","화","수","목","금","토"],firstLetterDayNames:["일","월","화","수","목","금","토"],monthNames:["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월"],abbreviatedMonthNames:["1","2","3","4","5","6","7","8","9","10","11","12"],amDesignator:"오전",pmDesignator:"오후",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy-MM-dd",longDate:"yyyy\'년\' M\'월\' d\'일\' dddd",shortTime:"tt h:mm",longTime:"tt h:mm:ss",fullDateTime:"yyyy\'년\' M\'월\' d\'일\' dddd tt h:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"M\'월\' d\'일\'",yearMonth:"yyyy\'년\' M\'월\'"},regexPatterns:{jan:/^1(월)?/i,feb:/^2(월)?/i,mar:/^3(월)?/i,apr:/^4(월)?/i,may:/^5(월)?/i,jun:/^6(월)?/i,jul:/^7(월)?/i,aug:/^8(월)?/i,sep:/^9(월)?/i,oct:/^10(월)?/i,nov:/^11(월)?/i,dec:/^12(월)?/i,sun:/^일요일/i,mon:/^월요일/i,tue:/^화요일/i,wed:/^수요일/i,thu:/^목요일/i,fri:/^금요일/i,sat:/^토요일/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'kok-IN' => 'Date.CultureInfo={name:"kok-IN",englishName:"Konkani (India)",nativeName:"कोंकणी (भारत)",dayNames:["आयतार","सोमार","मंगळार","बुधवार","बिरेस्तार","सुक्रार","शेनवार"],abbreviatedDayNames:["आय.","सोम.","मंगळ.","बुध.","बिरे.","सुक्र.","शेन."],shortestDayNames:["आ","स","म","ब","ब","स","श"],firstLetterDayNames:["आ","स","म","ब","ब","स","श"],monthNames:["जानेवारी","फेब्रुवारी","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टेंबर","ऑक्टोबर","नोवेम्बर","डिसेंबर"],abbreviatedMonthNames:["जानेवारी","फेब्रुवारी","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टेंबर","ऑक्टोबर","नोवेम्बर","डिसेंबर"],amDesignator:"म.पू.",pmDesignator:"म.नं.",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd-MM-yyyy",longDate:"dd MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dd MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^जानेवारी/i,feb:/^फेब्रुवारी/i,mar:/^मार्च/i,apr:/^एप्रिल/i,may:/^मे/i,jun:/^जून/i,jul:/^जुलै/i,aug:/^ऑगस्ट/i,sep:/^सप्टेंबर/i,oct:/^ऑक्टोबर/i,nov:/^नोवेम्बर/i,dec:/^डिसेंबर/i,sun:/^आ(य(.(तार)?)?)?/i,mon:/^स(ोम(.(ार)?)?)?/i,tue:/^म(ंगळ(.(ार)?)?)?/i,wed:/^ब(ुध(.(वार)?)?)?/i,thu:/^ब(िरे(.(स्तार)?)?)?/i,fri:/^स(ुक्र(.(ार)?)?)?/i,sat:/^श(ेन(.(वार)?)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ky-KG' => 'Date.CultureInfo={name:"ky-KG",englishName:"Kyrgyz (Kyrgyzstan)",nativeName:"Кыргыз (Кыргызстан)",dayNames:["Жекшемби","Дүйшөмбү","Шейшемби","Шаршемби","Бейшемби","Жума","Ишемби"],abbreviatedDayNames:["Жш","Дш","Шш","Шр","Бш","Жм","Иш"],shortestDayNames:["Жш","Дш","Шш","Шр","Бш","Жм","Иш"],firstLetterDayNames:["Ж","Д","Ш","Ш","Б","Ж","И"],monthNames:["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"],abbreviatedMonthNames:["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yy",longDate:"d\'-\'MMMM yyyy\'-ж.\'",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d\'-\'MMMM yyyy\'-ж.\' H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM yyyy\'-ж.\'"},regexPatterns:{jan:/^янв(арь)?/i,feb:/^фев(раль)?/i,mar:/^мар(т)?/i,apr:/^апр(ель)?/i,may:/^май/i,jun:/^июн(ь)?/i,jul:/^июл(ь)?/i,aug:/^авг(уст)?/i,sep:/^сен(тябрь)?/i,oct:/^окт(ябрь)?/i,nov:/^ноя(брь)?/i,dec:/^дек(абрь)?/i,sun:/^жекшемби/i,mon:/^дүйшөмбү/i,tue:/^шейшемби/i,wed:/^шаршемби/i,thu:/^бейшемби/i,fri:/^жума/i,sat:/^ишемби/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'lt-LT' => 'Date.CultureInfo={name:"lt-LT",englishName:"Lithuanian (Lithuania)",nativeName:"lietuvių (Lietuva)",dayNames:["sekmadienis","pirmadienis","antradienis","trečiadienis","ketvirtadienis","penktadienis","šeštadienis"],abbreviatedDayNames:["Sk","Pr","An","Tr","Kt","Pn","Št"],shortestDayNames:["S","P","A","T","K","Pn","Š"],firstLetterDayNames:["S","P","A","T","K","P","Š"],monthNames:["sausis","vasaris","kovas","balandis","gegužė","birželis","liepa","rugpjūtis","rugsėjis","spalis","lapkritis","gruodis"],abbreviatedMonthNames:["Sau","Vas","Kov","Bal","Geg","Bir","Lie","Rgp","Rgs","Spl","Lap","Grd"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy.MM.dd",longDate:"yyyy \'m.\' MMMM d \'d.\'",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"yyyy \'m.\' MMMM d \'d.\' HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM d \'d.\'",yearMonth:"yyyy \'m.\' MMMM"},regexPatterns:{jan:/^sau(sis)?/i,feb:/^vas(aris)?/i,mar:/^kov(as)?/i,apr:/^bal(andis)?/i,may:/^geg(užė)?/i,jun:/^bir(želis)?/i,jul:/^lie(pa)?/i,aug:/^rugpjūtis/i,sep:/^rugsėjis/i,oct:/^spalis/i,nov:/^lap(kritis)?/i,dec:/^gruodis/i,sun:/^s(k(kmadienis)?)?/i,mon:/^p(r(rmadienis)?)?/i,tue:/^a(n(tradienis)?)?/i,wed:/^t(r(ečiadienis)?)?/i,thu:/^k(t(tvirtadienis)?)?/i,fri:/^penktadienis/i,sat:/^š(t(štadienis)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'lv-LV' => 'Date.CultureInfo={name:"lv-LV",englishName:"Latvian (Latvia)",nativeName:"latviešu (Latvija)",dayNames:["svētdiena","pirmdiena","otrdiena","trešdiena","ceturtdiena","piektdiena","sestdiena"],abbreviatedDayNames:["Sv","Pr","Ot","Tr","Ce","Pk","Se"],shortestDayNames:["Sv","Pr","Ot","Tr","Ce","Pk","Se"],firstLetterDayNames:["S","P","O","T","C","P","S"],monthNames:["janvāris","februāris","marts","aprīlis","maijs","jūnijs","jūlijs","augusts","septembris","oktobris","novembris","decembris"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","Mai","Jūn","Jūl","Aug","Sep","Okt","Nov","Dec"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy.MM.dd.",longDate:"dddd, yyyy\'. gada \'d. MMMM",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dddd, yyyy\'. gada \'d. MMMM H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d. MMMM",yearMonth:"yyyy. MMMM"},regexPatterns:{jan:/^jan(vāris)?/i,feb:/^feb(ruāris)?/i,mar:/^mar(ts)?/i,apr:/^apr(īlis)?/i,may:/^mai(js)?/i,jun:/^jūn(ijs)?/i,jul:/^jūl(ijs)?/i,aug:/^aug(usts)?/i,sep:/^sep(tembris)?/i,oct:/^okt(obris)?/i,nov:/^nov(embris)?/i,dec:/^dec(embris)?/i,sun:/^svētdiena/i,mon:/^pirmdiena/i,tue:/^otrdiena/i,wed:/^trešdiena/i,thu:/^ceturtdiena/i,fri:/^piektdiena/i,sat:/^sestdiena/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'mi-NZ' => 'Date.CultureInfo={name:"mi-NZ",englishName:"Maori (New Zealand)",nativeName:"Reo Māori (Aotearoa)",dayNames:["Rātapu","Mane","Tūrei","Wenerei","Tāite","Paraire","Hātarei"],abbreviatedDayNames:["Ta","Ma","Tū","We","Tāi","Pa","Hā"],shortestDayNames:["Ta","Ma","Tū","We","Tāi","Pa","Hā"],firstLetterDayNames:["T","M","T","W","T","P","H"],monthNames:["Kohi-tātea","Hui-tanguru","Poutū-te-rangi","Paenga-whāwhā","Haratua","Pipiri","Hōngoingoi","Here-turi-kōkā","Mahuru","Whiringa-ā-nuku","Whiringa-ā-rangi","Hakihea"],abbreviatedMonthNames:["Kohi","Hui","Pou","Pae","Hara","Pipi","Hōngoi","Here","Mahu","Whi-nu","Whi-ra","Haki"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d/MM/yyyy",longDate:"dddd, d MMMM yyyy",shortTime:"h:mm:ss tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, d MMMM yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^kohi(-tātea)?/i,feb:/^hui(-tanguru)?/i,mar:/^pou(tū-te-rangi)?/i,apr:/^pae(nga-whāwhā)?/i,may:/^hara(tua)?/i,jun:/^pipi(ri)?/i,jul:/^hōngoi(ngoi)?/i,aug:/^here(-turi-kōkā)?/i,sep:/^mahu(ru)?/i,oct:/^whiringa-ā-nuku/i,nov:/^whiringa-ā-rangi/i,dec:/^haki(hea)?/i,sun:/^rātapu/i,mon:/^mane/i,tue:/^tūrei/i,wed:/^wenerei/i,thu:/^tāite/i,fri:/^paraire/i,sat:/^hātarei/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'mk-MK' => 'Date.CultureInfo={name:"mk-MK",englishName:"Macedonian",nativeName:"македонски јазик (Македонија)",dayNames:["недела","понеделник","вторник","среда","четврток","петок","сабота"],abbreviatedDayNames:["нед","пон","втр","срд","чет","пет","саб"],shortestDayNames:["не","по","вт","ср","че","пе","са"],firstLetterDayNames:["н","п","в","с","ч","п","с"],monthNames:["јануари","февруари","март","април","мај","јуни","јули","август","септември","октомври","ноември","декември"],abbreviatedMonthNames:["јан","фев","мар","апр","мај","јун","јул","авг","сеп","окт","ное","дек"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"dddd, dd MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dddd, dd MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^јан(уари)?/i,feb:/^фев(руари)?/i,mar:/^мар(т)?/i,apr:/^апр(ил)?/i,may:/^мај/i,jun:/^јун(и)?/i,jul:/^јул(и)?/i,aug:/^авг(уст)?/i,sep:/^сеп(тември)?/i,oct:/^окт(омври)?/i,nov:/^ное(мври)?/i,dec:/^дек(ември)?/i,sun:/^не(д(ела)?)?/i,mon:/^по(н(еделник)?)?/i,tue:/^вт(р(рник)?)?/i,wed:/^ср(д(да)?)?/i,thu:/^че(т(врток)?)?/i,fri:/^пе(т(ок)?)?/i,sat:/^са(б(ота)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'mn-MN' => 'Date.CultureInfo={name:"mn-MN",englishName:"Mongolian (Cyrillic, Mongolia)",nativeName:"Монгол хэл (Монгол улс)",dayNames:["Ням","Даваа","Мягмар","Лхагва","Пүрэв","Баасан","Бямба"],abbreviatedDayNames:["Ня","Да","Мя","Лх","Пү","Ба","Бя"],shortestDayNames:["Ня","Да","Мя","Лх","Пү","Ба","Бя"],firstLetterDayNames:["Н","Д","М","Л","П","Б","Б"],monthNames:["1 дүгээр сар","2 дугаар сар","3 дугаар сар","4 дүгээр сар","5 дугаар сар","6 дугаар сар","7 дугаар сар","8 дугаар сар","9 дүгээр сар","10 дугаар сар","11 дүгээр сар","12 дугаар сар"],abbreviatedMonthNames:["I","II","III","IV","V","VI","VII","VШ","IX","X","XI","XII"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yy.MM.dd",longDate:"yyyy \'оны\' MMMM d",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"yyyy \'оны\' MMMM d H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"yyyy \'он\' MMMM"},regexPatterns:{jan:/^1 дүгээр сар/i,feb:/^2 дугаар сар/i,mar:/^3 дугаар сар/i,apr:/^4 дүгээр сар/i,may:/^5 дугаар сар/i,jun:/^6 дугаар сар/i,jul:/^7 дугаар сар/i,aug:/^8 дугаар сар/i,sep:/^9 дүгээр сар/i,oct:/^10 дугаар сар/i,nov:/^11 дүгээр сар/i,dec:/^12 дугаар сар/i,sun:/^ням/i,mon:/^даваа/i,tue:/^мягмар/i,wed:/^лхагва/i,thu:/^пүрэв/i,fri:/^баасан/i,sat:/^бямба/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'mr-IN' => 'Date.CultureInfo={name:"mr-IN",englishName:"Marathi (India)",nativeName:"मराठी (भारत)",dayNames:["रविवार","सोमवार","मंगळवार","बुधवार","गुरुवार","शुक्रवार","शनिवार"],abbreviatedDayNames:["रवि.","सोम.","मंगळ.","बुध.","गुरु.","शुक्र.","शनि."],shortestDayNames:["र","स","म","ब","ग","श","श"],firstLetterDayNames:["र","स","म","ब","ग","श","श"],monthNames:["जानेवारी","फेब्रुवारी","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टेंबर","ऑक्टोबर","नोव्हेंबर","डिसेंबर"],abbreviatedMonthNames:["जाने.","फेब्रु.","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टें.","ऑक्टो.","नोव्हें.","डिसें."],amDesignator:"म.पू.",pmDesignator:"म.नं.",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd-MM-yyyy",longDate:"dd MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dd MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^जाने(.(वारी)?)?/i,feb:/^फेब्रु(.(वारी)?)?/i,mar:/^मार्च/i,apr:/^एप्रिल/i,may:/^मे/i,jun:/^जून/i,jul:/^जुलै/i,aug:/^ऑगस्ट/i,sep:/^सप्टें(.(बर)?)?/i,oct:/^ऑक्टो(.(बर)?)?/i,nov:/^नोव्हें(.(बर)?)?/i,dec:/^डिसें(.(बर)?)?/i,sun:/^र(वि(.(वार)?)?)?/i,mon:/^स(ोम(.(वार)?)?)?/i,tue:/^म(ंगळ(.(वार)?)?)?/i,wed:/^ब(ुध(.(वार)?)?)?/i,thu:/^ग(ुरु(.(वार)?)?)?/i,fri:/^श(ुक्र(.(वार)?)?)?/i,sat:/^श(नि(.(वार)?)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ms-BN' => 'Date.CultureInfo={name:"ms-BN",englishName:"Malay (Brunei Darussalam)",nativeName:"Bahasa Malaysia (Brunei Darussalam)",dayNames:["Ahad","Isnin","Selasa","Rabu","Khamis","Jumaat","Sabtu"],abbreviatedDayNames:["Ahad","Isnin","Sel","Rabu","Khamis","Jumaat","Sabtu"],shortestDayNames:["A","I","S","R","K","J","S"],firstLetterDayNames:["A","I","S","R","K","J","S"],monthNames:["Januari","Februari","Mac","April","Mei","Jun","Julai","Ogos","September","Oktober","November","Disember"],abbreviatedMonthNames:["Jan","Feb","Mac","Apr","Mei","Jun","Jul","Ogos","Sept","Okt","Nov","Dis"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dd MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uari)?/i,feb:/^feb(ruari)?/i,mar:/^mac/i,apr:/^apr(il)?/i,may:/^mei/i,jun:/^jun/i,jul:/^jul(ai)?/i,aug:/^ogos/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nov(ember)?/i,dec:/^dis(ember)?/i,sun:/^a(1)?/i,mon:/^i(1)?/i,tue:/^s(el(asa)?)?/i,wed:/^r(1)?/i,thu:/^k(1)?/i,fri:/^j(1)?/i,sat:/^s(1)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ms-MY' => 'Date.CultureInfo={name:"ms-MY",englishName:"Malay (Malaysia)",nativeName:"Bahasa Malaysia (Malaysia)",dayNames:["Ahad","Isnin","Selasa","Rabu","Khamis","Jumaat","Sabtu"],abbreviatedDayNames:["Ahad","Isnin","Sel","Rabu","Khamis","Jumaat","Sabtu"],shortestDayNames:["A","I","S","R","K","J","S"],firstLetterDayNames:["A","I","S","R","K","J","S"],monthNames:["Januari","Februari","Mac","April","Mei","Jun","Julai","Ogos","September","Oktober","November","Disember"],abbreviatedMonthNames:["Jan","Feb","Mac","Apr","Mei","Jun","Jul","Ogos","Sept","Okt","Nov","Dis"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dd MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uari)?/i,feb:/^feb(ruari)?/i,mar:/^mac/i,apr:/^apr(il)?/i,may:/^mei/i,jun:/^jun/i,jul:/^jul(ai)?/i,aug:/^ogos/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nov(ember)?/i,dec:/^dis(ember)?/i,sun:/^a(1)?/i,mon:/^i(1)?/i,tue:/^s(el(asa)?)?/i,wed:/^r(1)?/i,thu:/^k(1)?/i,fri:/^j(1)?/i,sat:/^s(1)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'mt-MT' => 'Date.CultureInfo={name:"mt-MT",englishName:"Maltese (Malta)",nativeName:"Malti (Malta)",dayNames:["Il-Ħadd","It-Tnejn","It-Tlieta","L-Erbgħa","Il-Ħamis","Il-Ġimgħa","Is-Sibt"],abbreviatedDayNames:["Ħad","Tne","Tli","Erb","Ħam","Ġim","Sib"],shortestDayNames:["Ħad","Tne","Tli","Erb","Ħam","Ġim","Sib"],firstLetterDayNames:["Ħ","T","T","E","Ħ","Ġ","S"],monthNames:["Jannar","Frar","Marzu","April","Mejju","Ġunju","Lulju","Awissu","Settembru","Ottubru","Novembru","Diċembru"],abbreviatedMonthNames:["Jan","Fra","Mar","Apr","Mej","Ġun","Lul","Awi","Set","Ott","Nov","Diċ"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, d\' ta\\\' \'MMMM yyyy",shortTime:"HH:mm:ss",longTime:"HH:mm:ss",fullDateTime:"dddd, d\' ta\\\' \'MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(nar)?/i,feb:/^fra(r)?/i,mar:/^mar(zu)?/i,apr:/^apr(il)?/i,may:/^mej(ju)?/i,jun:/^ġun(ju)?/i,jul:/^lul(ju)?/i,aug:/^awi(ssu)?/i,sep:/^set(tembru)?/i,oct:/^ott(ubru)?/i,nov:/^nov(embru)?/i,dec:/^diċ(embru)?/i,sun:/^il-ħadd/i,mon:/^it-tnejn/i,tue:/^it-tlieta/i,wed:/^l-erbgħa/i,thu:/^il-ħamis/i,fri:/^il-ġimgħa/i,sat:/^is-sibt/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'nb-NO' => 'Date.CultureInfo={name:"nb-NO",englishName:"Norwegian, Bokmål (Norway)",nativeName:"norsk, bokmål (Norge)",dayNames:["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"],abbreviatedDayNames:["sø","ma","ti","on","to","fr","lø"],shortestDayNames:["sø","ma","ti","on","to","fr","lø"],firstLetterDayNames:["s","m","t","o","t","f","l"],monthNames:["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember"],abbreviatedMonthNames:["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"d. MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"d. MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d. MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uar)?/i,feb:/^feb(ruar)?/i,mar:/^mar(s)?/i,apr:/^apr(il)?/i,may:/^mai/i,jun:/^jun(i)?/i,jul:/^jul(i)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nov(ember)?/i,dec:/^des(ember)?/i,sun:/^søndag/i,mon:/^mandag/i,tue:/^tirsdag/i,wed:/^onsdag/i,thu:/^torsdag/i,fri:/^fredag/i,sat:/^lørdag/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'nl-BE' => 'Date.CultureInfo={name:"nl-BE",englishName:"Dutch (Belgium)",nativeName:"Nederlands (België)",dayNames:["zondag","maandag","dinsdag","woensdag","donderdag","vrijdag","zaterdag"],abbreviatedDayNames:["zo","ma","di","wo","do","vr","za"],shortestDayNames:["zo","ma","di","wo","do","vr","za"],firstLetterDayNames:["z","m","d","w","d","v","z"],monthNames:["januari","februari","maart","april","mei","juni","juli","augustus","september","oktober","november","december"],abbreviatedMonthNames:["jan","feb","mrt","apr","mei","jun","jul","aug","sep","okt","nov","dec"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d/MM/yyyy",longDate:"dddd d MMMM yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dddd d MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uari)?/i,feb:/^feb(ruari)?/i,mar:/^maart/i,apr:/^apr(il)?/i,may:/^mei/i,jun:/^jun(i)?/i,jul:/^jul(i)?/i,aug:/^aug(ustus)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^zondag/i,mon:/^maandag/i,tue:/^dinsdag/i,wed:/^woensdag/i,thu:/^donderdag/i,fri:/^vrijdag/i,sat:/^zaterdag/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'nl-NL' => 'Date.CultureInfo={name:"nl-NL",englishName:"Dutch (Netherlands)",nativeName:"Nederlands (Nederland)",dayNames:["zondag","maandag","dinsdag","woensdag","donderdag","vrijdag","zaterdag"],abbreviatedDayNames:["zo","ma","di","wo","do","vr","za"],shortestDayNames:["zo","ma","di","wo","do","vr","za"],firstLetterDayNames:["z","m","d","w","d","v","z"],monthNames:["januari","februari","maart","april","mei","juni","juli","augustus","september","oktober","november","december"],abbreviatedMonthNames:["jan","feb","mrt","apr","mei","jun","jul","aug","sep","okt","nov","dec"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d-M-yyyy",longDate:"dddd d MMMM yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dddd d MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uari)?/i,feb:/^feb(ruari)?/i,mar:/^maart/i,apr:/^apr(il)?/i,may:/^mei/i,jun:/^jun(i)?/i,jul:/^jul(i)?/i,aug:/^aug(ustus)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^zondag/i,mon:/^maandag/i,tue:/^dinsdag/i,wed:/^woensdag/i,thu:/^donderdag/i,fri:/^vrijdag/i,sat:/^zaterdag/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'nn-NO' => 'Date.CultureInfo={name:"nn-NO",englishName:"Norwegian, Nynorsk (Norway)",nativeName:"norsk, nynorsk (Noreg)",dayNames:["søndag","måndag","tysdag","onsdag","torsdag","fredag","laurdag"],abbreviatedDayNames:["sø","må","ty","on","to","fr","la"],shortestDayNames:["sø","må","ty","on","to","fr","la"],firstLetterDayNames:["s","m","t","o","t","f","l"],monthNames:["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember"],abbreviatedMonthNames:["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"d. MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"d. MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d. MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uar)?/i,feb:/^feb(ruar)?/i,mar:/^mar(s)?/i,apr:/^apr(il)?/i,may:/^mai/i,jun:/^jun(i)?/i,jul:/^jul(i)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nov(ember)?/i,dec:/^des(ember)?/i,sun:/^søndag/i,mon:/^måndag/i,tue:/^tysdag/i,wed:/^onsdag/i,thu:/^torsdag/i,fri:/^fredag/i,sat:/^laurdag/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ns-ZA' => 'Date.CultureInfo={name:"ns-ZA",englishName:"Northern Sotho (South Africa)",nativeName:"Sesotho sa Leboa (Afrika Borwa)",dayNames:["Lamorena","Mošupologo","Labobedi","Laboraro","Labone","Labohlano","Mokibelo"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["Pherekgong","Hlakola","Mopitlo","Moranang","Mosegamanye","Ngoatobošego","Phuphu","Phato","Lewedi","Diphalana","Dibatsela","Manthole"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy/MM/dd",longDate:"dd MMMM yyyy",shortTime:"hh:mm:ss tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^pherekgong/i,feb:/^hlakola/i,mar:/^mopitlo/i,apr:/^moranang/i,may:/^mosegamanye/i,jun:/^ngoatobošego/i,jul:/^phuphu/i,aug:/^phato/i,sep:/^lewedi/i,oct:/^diphalana/i,nov:/^dibatsela/i,dec:/^manthole/i,sun:/^lamorena/i,mon:/^mošupologo/i,tue:/^labobedi/i,wed:/^laboraro/i,thu:/^labone/i,fri:/^labohlano/i,sat:/^mokibelo/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'pa-IN' => 'Date.CultureInfo={name:"pa-IN",englishName:"Punjabi (India)",nativeName:"ਪੰਜਾਬੀ (ਭਾਰਤ)",dayNames:["ਐਤਵਾਰ","ਸੋਮਵਾਰ","ਮੰਗਲਵਾਰ","ਬੁਧਵਾਰ","ਵੀਰਵਾਰ","ਸ਼ੁੱਕਰਵਾਰ","ਸ਼ਨੀਚਰਵਾਰ"],abbreviatedDayNames:["ਐਤ.","ਸੋਮ.","ਮੰਗਲ.","ਬੁਧ.","ਵੀਰ.","ਸ਼ੁਕਰ.","ਸ਼ਨੀ."],shortestDayNames:["ਐ","ਸ","ਮ","ਬ","ਵ","ਸ਼","ਸ਼"],firstLetterDayNames:["ਐ","ਸ","ਮ","ਬ","ਵ","ਸ਼","ਸ਼"],monthNames:["ਜਨਵਰੀ","ਫ਼ਰਵਰੀ","ਮਾਰਚ","ਅਪ੍ਰੈਲ","ਮਈ","ਜੂਨ","ਜੁਲਾਈ","ਅਗਸਤ","ਸਤੰਬਰ","ਅਕਤੂਬਰ","ਨਵੰਬਰ","ਦਸੰਬਰ"],abbreviatedMonthNames:["ਜਨਵਰੀ","ਫ਼ਰਵਰੀ","ਮਾਰਚ","ਅਪ੍ਰੈਲ","ਮਈ","ਜੂਨ","ਜੁਲਾਈ","ਅਗਸਤ","ਸਤੰਬਰ","ਅਕਤੂਬਰ","ਨਵੰਬਰ","ਦਸੰਬਰ"],amDesignator:"ਸਵੇਰੇ",pmDesignator:"ਸ਼ਾਮ",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd-MM-yy",longDate:"dd MMMM yyyy dddd",shortTime:"tt hh:mm",longTime:"tt hh:mm:ss",fullDateTime:"dd MMMM yyyy dddd tt hh:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^ਜਨਵਰੀ/i,feb:/^ਫ਼ਰਵਰੀ/i,mar:/^ਮਾਰਚ/i,apr:/^ਅਪ੍ਰੈਲ/i,may:/^ਮਈ/i,jun:/^ਜੂਨ/i,jul:/^ਜੁਲਾਈ/i,aug:/^ਅਗਸਤ/i,sep:/^ਸਤੰਬਰ/i,oct:/^ਅਕਤੂਬਰ/i,nov:/^ਨਵੰਬਰ/i,dec:/^ਦਸੰਬਰ/i,sun:/^ਐ(ਤ(.(ਵਾਰ)?)?)?/i,mon:/^ਸ(ੋਮ(.(ਵਾਰ)?)?)?/i,tue:/^ਮ(ੰਗਲ(.(ਵਾਰ)?)?)?/i,wed:/^ਬ(ੁਧ(.(ਵਾਰ)?)?)?/i,thu:/^ਵ(ੀਰ(.(ਵਾਰ)?)?)?/i,fri:/^ਸ਼(ੁਕਰ(.(ਰਵਾਰ)?)?)?/i,sat:/^ਸ਼(ਨੀ(.(ਚਰਵਾਰ)?)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'pl-PL' => 'Date.CultureInfo={name:"pl-PL",englishName:"Polish (Poland)",nativeName:"polski (Polska)",dayNames:["niedziela","poniedziałek","wtorek","środa","czwartek","piątek","sobota"],abbreviatedDayNames:["N","Pn","Wt","Śr","Cz","Pt","So"],shortestDayNames:["N","Pn","Wt","Śr","Cz","Pt","So"],firstLetterDayNames:["N","P","W","Ś","C","P","S"],monthNames:["styczeń","luty","marzec","kwiecień","maj","czerwiec","lipiec","sierpień","wrzesień","październik","listopad","grudzień"],abbreviatedMonthNames:["sty","lut","mar","kwi","maj","cze","lip","sie","wrz","paź","lis","gru"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy-MM-dd",longDate:"d MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"d MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^sty(czeń)?/i,feb:/^lut(y)?/i,mar:/^mar(zec)?/i,apr:/^kwi(ecień)?/i,may:/^maj/i,jun:/^cze(rwiec)?/i,jul:/^lip(iec)?/i,aug:/^sie(rpień)?/i,sep:/^wrz(esień)?/i,oct:/^paź(dziernik)?/i,nov:/^lis(topad)?/i,dec:/^gru(dzień)?/i,sun:/^niedziela/i,mon:/^poniedziałek/i,tue:/^wtorek/i,wed:/^środa/i,thu:/^czwartek/i,fri:/^piątek/i,sat:/^sobota/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'pt-BR' => 'Date.CultureInfo={name:"pt-BR",englishName:"Portuguese (Brazil)",nativeName:"Português (Brasil)",dayNames:["domingo","segunda-feira","terça-feira","quarta-feira","quinta-feira","sexta-feira","sábado"],abbreviatedDayNames:["dom","seg","ter","qua","qui","sex","sáb"],shortestDayNames:["dom","seg","ter","qua","qui","sex","sáb"],firstLetterDayNames:["d","s","t","q","q","s","s"],monthNames:["janeiro","fevereiro","março","abril","maio","junho","julho","agosto","setembro","outubro","novembro","dezembro"],abbreviatedMonthNames:["jan","fev","mar","abr","mai","jun","jul","ago","set","out","nov","dez"],amDesignator:"",pmDesignator:"",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d/M/yyyy",longDate:"dddd, d\' de \'MMMM\' de \'yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dddd, d\' de \'MMMM\' de \'yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd\' de \'MMMM",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^jan(eiro)?/i,feb:/^fev(ereiro)?/i,mar:/^mar(ço)?/i,apr:/^abr(il)?/i,may:/^mai(o)?/i,jun:/^jun(ho)?/i,jul:/^jul(ho)?/i,aug:/^ago(sto)?/i,sep:/^set(embro)?/i,oct:/^out(ubro)?/i,nov:/^nov(embro)?/i,dec:/^dez(embro)?/i,sun:/^domingo/i,mon:/^segunda-feira/i,tue:/^terça-feira/i,wed:/^quarta-feira/i,thu:/^quinta-feira/i,fri:/^sexta-feira/i,sat:/^sábado/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'pt-PT' => 'Date.CultureInfo={name:"pt-PT",englishName:"Portuguese (Portugal)",nativeName:"português (Portugal)",dayNames:["domingo","segunda-feira","terça-feira","quarta-feira","quinta-feira","sexta-feira","sábado"],abbreviatedDayNames:["dom","seg","ter","qua","qui","sex","sáb"],shortestDayNames:["dom","seg","ter","qua","qui","sex","sáb"],firstLetterDayNames:["d","s","t","q","q","s","s"],monthNames:["Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"],abbreviatedMonthNames:["Jan","Fev","Mar","Abr","Mai","Jun","Jul","Ago","Set","Out","Nov","Dez"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd-MM-yyyy",longDate:"dddd, d\' de \'MMMM\' de \'yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dddd, d\' de \'MMMM\' de \'yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d/M",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^jan(eiro)?/i,feb:/^fev(ereiro)?/i,mar:/^mar(ço)?/i,apr:/^abr(il)?/i,may:/^mai(o)?/i,jun:/^jun(ho)?/i,jul:/^jul(ho)?/i,aug:/^ago(sto)?/i,sep:/^set(embro)?/i,oct:/^out(ubro)?/i,nov:/^nov(embro)?/i,dec:/^dez(embro)?/i,sun:/^domingo/i,mon:/^segunda-feira/i,tue:/^terça-feira/i,wed:/^quarta-feira/i,thu:/^quinta-feira/i,fri:/^sexta-feira/i,sat:/^sábado/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'quz-BO' => 'Date.CultureInfo={name:"quz-BO",englishName:"Quechua (Bolivia)",nativeName:"runasimi (Bolivia Suyu)",dayNames:["intichaw","killachaw","atipachaw","quyllurchaw","Ch\' askachaw","Illapachaw","k\'uychichaw"],abbreviatedDayNames:["int","kil","ati","quy","Ch’","Ill","k\'u"],shortestDayNames:["int","kil","ati","quy","Ch’","Ill","k\'u"],firstLetterDayNames:["i","k","a","q","C","I","k"],monthNames:["Qulla puquy","Hatun puquy","Pauqar waray","ayriwa","Aymuray","Inti raymi","Anta Sitwa","Qhapaq Sitwa","Uma raymi","Kantaray","Ayamarq\'a","Kapaq Raymi"],abbreviatedMonthNames:["Qul","Hat","Pau","ayr","Aym","Int","Ant","Qha","Uma","Kan","Aya","Kap"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm:ss tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^qul(la puquy)?/i,feb:/^hat(un puquy)?/i,mar:/^pau(qar waray)?/i,apr:/^ayr(iwa)?/i,may:/^aym(uray)?/i,jun:/^int(i raymi)?/i,jul:/^ant(a sitwa)?/i,aug:/^qha(paq sitwa)?/i,sep:/^uma( raymi)?/i,oct:/^kan(taray)?/i,nov:/^aya(marq\'a)?/i,dec:/^kap(aq raymi)?/i,sun:/^intichaw/i,mon:/^killachaw/i,tue:/^atipachaw/i,wed:/^quyllurchaw/i,thu:/^ch\' askachaw/i,fri:/^illapachaw/i,sat:/^k\'uychichaw/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'quz-EC' => 'Date.CultureInfo={name:"quz-EC",englishName:"Quechua (Ecuador)",nativeName:"runasimi (Ecuador Suyu)",dayNames:["intichaw","killachaw","atipachaw","quyllurchaw","Ch\' askachaw","Illapachaw","k\'uychichaw"],abbreviatedDayNames:["int","kil","ati","quy","Ch’","Ill","k\'u"],shortestDayNames:["int","kil","ati","quy","Ch’","Ill","k\'u"],firstLetterDayNames:["i","k","a","q","C","I","k"],monthNames:["Qulla puquy","Hatun puquy","Pauqar waray","ayriwa","Aymuray","Inti raymi","Anta Sitwa","Qhapaq Sitwa","Uma raymi","Kantaray","Ayamarq\'a","Kapaq Raymi"],abbreviatedMonthNames:["Qul","Hat","Pau","ayr","Aym","Int","Ant","Qha","Uma","Kan","Aya","Kap"],amDesignator:"",pmDesignator:"",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"H:mm:ss",longTime:"H:mm:ss",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^qul(la puquy)?/i,feb:/^hat(un puquy)?/i,mar:/^pau(qar waray)?/i,apr:/^ayr(iwa)?/i,may:/^aym(uray)?/i,jun:/^int(i raymi)?/i,jul:/^ant(a sitwa)?/i,aug:/^qha(paq sitwa)?/i,sep:/^uma( raymi)?/i,oct:/^kan(taray)?/i,nov:/^aya(marq\'a)?/i,dec:/^kap(aq raymi)?/i,sun:/^intichaw/i,mon:/^killachaw/i,tue:/^atipachaw/i,wed:/^quyllurchaw/i,thu:/^ch\' askachaw/i,fri:/^illapachaw/i,sat:/^k\'uychichaw/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'quz-PE' => 'Date.CultureInfo={name:"quz-PE",englishName:"Quechua (Peru)",nativeName:"runasimi (Peru Suyu)",dayNames:["intichaw","killachaw","atipachaw","quyllurchaw","Ch\' askachaw","Illapachaw","k\'uychichaw"],abbreviatedDayNames:["int","kil","ati","quy","Ch’","Ill","k\'u"],shortestDayNames:["int","kil","ati","quy","Ch’","Ill","k\'u"],firstLetterDayNames:["i","k","a","q","C","I","k"],monthNames:["Qulla puquy","Hatun puquy","Pauqar waray","ayriwa","Aymuray","Inti raymi","Anta Sitwa","Qhapaq Sitwa","Uma raymi","Kantaray","Ayamarq\'a","Kapaq Raymi"],abbreviatedMonthNames:["Qul","Hat","Pau","ayr","Aym","Int","Ant","Qha","Uma","Kan","Aya","Kap"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dddd, dd\' de \'MMMM\' de \'yyyy",shortTime:"hh:mm:ss tt",longTime:"hh:mm:ss tt",fullDateTime:"dddd, dd\' de \'MMMM\' de \'yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM\' de \'yyyy"},regexPatterns:{jan:/^qul(la puquy)?/i,feb:/^hat(un puquy)?/i,mar:/^pau(qar waray)?/i,apr:/^ayr(iwa)?/i,may:/^aym(uray)?/i,jun:/^int(i raymi)?/i,jul:/^ant(a sitwa)?/i,aug:/^qha(paq sitwa)?/i,sep:/^uma( raymi)?/i,oct:/^kan(taray)?/i,nov:/^aya(marq\'a)?/i,dec:/^kap(aq raymi)?/i,sun:/^intichaw/i,mon:/^killachaw/i,tue:/^atipachaw/i,wed:/^quyllurchaw/i,thu:/^ch\' askachaw/i,fri:/^illapachaw/i,sat:/^k\'uychichaw/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ro-RO' => 'Date.CultureInfo={name:"ro-RO",englishName:"Romanian (Romania)",nativeName:"română (România)",dayNames:["duminică","luni","marţi","miercuri","joi","vineri","sâmbătă"],abbreviatedDayNames:["D","L","Ma","Mi","J","V","S"],shortestDayNames:["D","L","Ma","Mi","J","V","S"],firstLetterDayNames:["D","L","M","M","J","V","S"],monthNames:["ianuarie","februarie","martie","aprilie","mai","iunie","iulie","august","septembrie","octombrie","noiembrie","decembrie"],abbreviatedMonthNames:["ian.","feb.","mar.","apr.","mai.","iun.","iul.","aug.","sep.","oct.","nov.","dec."],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"d MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"d MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^ian(.(uarie)?)?/i,feb:/^feb(.(ruarie)?)?/i,mar:/^mar(.(tie)?)?/i,apr:/^apr(.(ilie)?)?/i,may:/^mai(.()?)?/i,jun:/^iun(.(ie)?)?/i,jul:/^iul(.(ie)?)?/i,aug:/^aug(.(ust)?)?/i,sep:/^sep(.(tembrie)?)?/i,oct:/^oct(.(ombrie)?)?/i,nov:/^noiembrie/i,dec:/^dec(.(embrie)?)?/i,sun:/^duminică/i,mon:/^luni/i,tue:/^marţi/i,wed:/^miercuri/i,thu:/^joi/i,fri:/^vineri/i,sat:/^sâmbătă/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ru-RU' => 'Date.CultureInfo={name:"ru-RU",englishName:"Russian (Russia)",nativeName:"русский (Россия)",dayNames:["воскресенье","понедельник","вторник","среда","четверг","пятница","суббота"],abbreviatedDayNames:["Вс","Пн","Вт","Ср","Чт","Пт","Сб"],shortestDayNames:["Вс","Пн","Вт","Ср","Чт","Пт","Сб"],firstLetterDayNames:["В","П","В","С","Ч","П","С"],monthNames:["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"],abbreviatedMonthNames:["янв","фев","мар","апр","май","июн","июл","авг","сен","окт","ноя","дек"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"d MMMM yyyy \'г.\'",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d MMMM yyyy \'г.\' H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy \'г.\'"},regexPatterns:{jan:/^янв(арь)?/i,feb:/^фев(раль)?/i,mar:/^мар(т)?/i,apr:/^апр(ель)?/i,may:/^май/i,jun:/^июн(ь)?/i,jul:/^июл(ь)?/i,aug:/^авг(уст)?/i,sep:/^сен(тябрь)?/i,oct:/^окт(ябрь)?/i,nov:/^ноя(брь)?/i,dec:/^дек(абрь)?/i,sun:/^воскресенье/i,mon:/^понедельник/i,tue:/^вторник/i,wed:/^среда/i,thu:/^четверг/i,fri:/^пятница/i,sat:/^суббота/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'sa-IN' => 'Date.CultureInfo={name:"sa-IN",englishName:"Sanskrit (India)",nativeName:"संस्कृत (भारतम्)",dayNames:["रविवासरः","सोमवासरः","मङ्गलवासरः","बुधवासरः","गुरुवासरः","शुक्रवासरः","शनिवासरः"],abbreviatedDayNames:["रविवासरः","सोमवासरः","मङ्गलवासरः","बुधवासरः","गुरुवासरः","शुक्रवासरः","शनिवासरः"],shortestDayNames:["र","स","म","ब","ग","श","श"],firstLetterDayNames:["र","स","म","ब","ग","श","श"],monthNames:["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर"],abbreviatedMonthNames:["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर"],amDesignator:"पूर्वाह्न",pmDesignator:"अपराह्न",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd-MM-yyyy",longDate:"dd MMMM yyyy dddd",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dd MMMM yyyy dddd HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^जनवरी/i,feb:/^फरवरी/i,mar:/^मार्च/i,apr:/^अप्रैल/i,may:/^मई/i,jun:/^जून/i,jul:/^जुलाई/i,aug:/^अगस्त/i,sep:/^सितम्बर/i,oct:/^अक्तूबर/i,nov:/^नवम्बर/i,dec:/^दिसम्बर/i,sun:/^र(1)?/i,mon:/^स(1)?/i,tue:/^म(1)?/i,wed:/^ब(1)?/i,thu:/^ग(1)?/i,fri:/^श(1)?/i,sat:/^श(1)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'se-FI' => 'Date.CultureInfo={name:"se-FI",englishName:"Sami (Northern) (Finland)",nativeName:"davvisámegiella (Suopma)",dayNames:["sotnabeaivi","vuossárga","maŋŋebárga","gaskavahkku","duorastat","bearjadat","lávvardat"],abbreviatedDayNames:["sotn","vuos","maŋ","gask","duor","bear","láv"],shortestDayNames:["sotn","vuos","maŋ","gask","duor","bear","láv"],firstLetterDayNames:["s","v","m","g","d","b","l"],monthNames:["ođđajagemánnu","guovvamánnu","njukčamánnu","cuoŋománnu","miessemánnu","geassemánnu","suoidnemánnu","borgemánnu","čakčamánnu","golggotmánnu","skábmamánnu","juovlamánnu"],abbreviatedMonthNames:["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d.M.yyyy",longDate:"MMMM d\'. b. \'yyyy",shortTime:"H:mm:ss",longTime:"H:mm:ss",fullDateTime:"MMMM d\'. b. \'yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^ođđajagemánnu/i,feb:/^guov(vamánnu)?/i,mar:/^njuk(čamánnu)?/i,apr:/^cuo(ŋománnu)?/i,may:/^mies(semánnu)?/i,jun:/^geas(semánnu)?/i,jul:/^suoi(dnemánnu)?/i,aug:/^borg(emánnu)?/i,sep:/^čakč(amánnu)?/i,oct:/^golg(gotmánnu)?/i,nov:/^skáb(mamánnu)?/i,dec:/^juov(lamánnu)?/i,sun:/^sotnabeaivi/i,mon:/^vuossárga/i,tue:/^maŋŋebárga/i,wed:/^gaskavahkku/i,thu:/^duorastat/i,fri:/^bearjadat/i,sat:/^lávvardat/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'se-NO' => 'Date.CultureInfo={name:"se-NO",englishName:"Sami (Northern) (Norway)",nativeName:"davvisámegiella (Norga)",dayNames:["sotnabeaivi","vuossárga","maŋŋebárga","gaskavahkku","duorastat","bearjadat","lávvardat"],abbreviatedDayNames:["sotn","vuos","maŋ","gask","duor","bear","láv"],shortestDayNames:["sotn","vuos","maŋ","gask","duor","bear","láv"],firstLetterDayNames:["s","v","m","g","d","b","l"],monthNames:["ođđajagemánnu","guovvamánnu","njukčamánnu","cuoŋománnu","miessemánnu","geassemánnu","suoidnemánnu","borgemánnu","čakčamánnu","golggotmánnu","skábmamánnu","juovlamánnu"],abbreviatedMonthNames:["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"MMMM d\'. b. \'yyyy",shortTime:"HH:mm:ss",longTime:"HH:mm:ss",fullDateTime:"MMMM d\'. b. \'yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^ođđajagemánnu/i,feb:/^guov(vamánnu)?/i,mar:/^njuk(čamánnu)?/i,apr:/^cuo(ŋománnu)?/i,may:/^mies(semánnu)?/i,jun:/^geas(semánnu)?/i,jul:/^suoi(dnemánnu)?/i,aug:/^borg(emánnu)?/i,sep:/^čakč(amánnu)?/i,oct:/^golg(gotmánnu)?/i,nov:/^skáb(mamánnu)?/i,dec:/^juov(lamánnu)?/i,sun:/^sotnabeaivi/i,mon:/^vuossárga/i,tue:/^maŋŋebárga/i,wed:/^gaskavahkku/i,thu:/^duorastat/i,fri:/^bearjadat/i,sat:/^lávvardat/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'se-SE' => 'Date.CultureInfo={name:"se-SE",englishName:"Sami (Northern) (Sweden)",nativeName:"davvisámegiella (Ruoŧŧa)",dayNames:["sotnabeaivi","mánnodat","disdat","gaskavahkku","duorastat","bearjadat","lávvardat"],abbreviatedDayNames:["sotn","mán","dis","gask","duor","bear","láv"],shortestDayNames:["sotn","mán","dis","gask","duor","bear","láv"],firstLetterDayNames:["s","m","d","g","d","b","l"],monthNames:["ođđajagemánnu","guovvamánnu","njukčamánnu","cuoŋománnu","miessemánnu","geassemánnu","suoidnemánnu","borgemánnu","čakčamánnu","golggotmánnu","skábmamánnu","juovlamánnu"],abbreviatedMonthNames:["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy-MM-dd",longDate:"MMMM d\'. b. \'yyyy",shortTime:"HH:mm:ss",longTime:"HH:mm:ss",fullDateTime:"MMMM d\'. b. \'yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^ođđajagemánnu/i,feb:/^guov(vamánnu)?/i,mar:/^njuk(čamánnu)?/i,apr:/^cuo(ŋománnu)?/i,may:/^mies(semánnu)?/i,jun:/^geas(semánnu)?/i,jul:/^suoi(dnemánnu)?/i,aug:/^borg(emánnu)?/i,sep:/^čakč(amánnu)?/i,oct:/^golg(gotmánnu)?/i,nov:/^skáb(mamánnu)?/i,dec:/^juov(lamánnu)?/i,sun:/^sotnabeaivi/i,mon:/^mánnodat/i,tue:/^disdat/i,wed:/^gaskavahkku/i,thu:/^duorastat/i,fri:/^bearjadat/i,sat:/^lávvardat/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'sk-SK' => 'Date.CultureInfo={name:"sk-SK",englishName:"Slovak (Slovakia)",nativeName:"slovenčina (Slovenská republika)",dayNames:["nedeľa","pondelok","utorok","streda","štvrtok","piatok","sobota"],abbreviatedDayNames:["ne","po","ut","st","št","pi","so"],shortestDayNames:["ne","po","ut","st","št","pi","so"],firstLetterDayNames:["n","p","u","s","š","p","s"],monthNames:["január","február","marec","apríl","máj","jún","júl","august","september","október","november","december"],abbreviatedMonthNames:["I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d. M. yyyy",longDate:"d. MMMM yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d. MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^január/i,feb:/^február/i,mar:/^marec/i,apr:/^apríl/i,may:/^máj/i,jun:/^jún/i,jul:/^júl/i,aug:/^august/i,sep:/^sep(t(ember)?)?/i,oct:/^október/i,nov:/^november/i,dec:/^december/i,sun:/^nedeľa/i,mon:/^pondelok/i,tue:/^utorok/i,wed:/^streda/i,thu:/^štvrtok/i,fri:/^piatok/i,sat:/^sobota/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'sl-SI' => 'Date.CultureInfo={name:"sl-SI",englishName:"Slovenian (Slovenia)",nativeName:"slovenski (Slovenija)",dayNames:["nedelja","ponedeljek","torek","sreda","četrtek","petek","sobota"],abbreviatedDayNames:["ned","pon","tor","sre","čet","pet","sob"],shortestDayNames:["ne","po","to","sr","če","pe","so"],firstLetterDayNames:["n","p","t","s","č","p","s"],monthNames:["januar","februar","marec","april","maj","junij","julij","avgust","september","oktober","november","december"],abbreviatedMonthNames:["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d.M.yyyy",longDate:"d. MMMM yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d. MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d. MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uar)?/i,feb:/^feb(ruar)?/i,mar:/^mar(ec)?/i,apr:/^apr(il)?/i,may:/^maj/i,jun:/^jun(ij)?/i,jul:/^jul(ij)?/i,aug:/^avg(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^ne(d(elja)?)?/i,mon:/^po(n(edeljek)?)?/i,tue:/^to(r(ek)?)?/i,wed:/^sr(e(da)?)?/i,thu:/^če(t(rtek)?)?/i,fri:/^pe(t(ek)?)?/i,sat:/^so(b(ota)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'sma-NO' => 'Date.CultureInfo={name:"sma-NO",englishName:"Sami (Southern) (Norway)",nativeName:"åarjelsaemiengiele (Nöörje)",dayNames:["aejlege","måanta","dæjsta","gaskevåhkoe","duarsta","bearjadahke","laavvardahke"],abbreviatedDayNames:["aej","måa","dæj","gask","duar","bearj","laav"],shortestDayNames:["aej","måa","dæj","gask","duar","bearj","laav"],firstLetterDayNames:["a","m","d","g","d","b","l"],monthNames:["tsïengele","goevte","njoktje","voerhtje","suehpede","ruffie","snjaltje","mïetske","skïerede","golke","rahka","goeve"],abbreviatedMonthNames:["tsïen","goevt","njok","voer","sueh","ruff","snja","mïet","skïer","golk","rahk","goev"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"MMMM d\'. b. \'yyyy",shortTime:"HH:mm:ss",longTime:"HH:mm:ss",fullDateTime:"MMMM d\'. b. \'yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^tsïen(gele)?/i,feb:/^goevt(e)?/i,mar:/^njok(tje)?/i,apr:/^voer(htje)?/i,may:/^sueh(pede)?/i,jun:/^ruff(ie)?/i,jul:/^snja(ltje)?/i,aug:/^mïet(ske)?/i,sep:/^skïer(ede)?/i,oct:/^golk(e)?/i,nov:/^rahk(a)?/i,dec:/^goev(e)?/i,sun:/^aejlege/i,mon:/^måanta/i,tue:/^dæjsta/i,wed:/^gaskevåhkoe/i,thu:/^duarsta/i,fri:/^bearjadahke/i,sat:/^laavvardahke/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'sma-SE' => 'Date.CultureInfo={name:"sma-SE",englishName:"Sami (Southern) (Sweden)",nativeName:"åarjelsaemiengiele (Sveerje)",dayNames:["aejlege","måanta","dæjsta","gaskevåhkoe","duarsta","bearjadahke","laavvardahke"],abbreviatedDayNames:["aej","måa","dæj","gask","duar","bearj","laav"],shortestDayNames:["aej","måa","dæj","gask","duar","bearj","laav"],firstLetterDayNames:["a","m","d","g","d","b","l"],monthNames:["tsïengele","goevte","njoktje","voerhtje","suehpede","ruffie","snjaltje","mïetske","skïerede","golke","rahka","goeve"],abbreviatedMonthNames:["tsïen","goevt","njok","voer","sueh","ruff","snja","mïet","skïer","golk","rahk","goev"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy-MM-dd",longDate:"MMMM d\'. b. \'yyyy",shortTime:"HH:mm:ss",longTime:"HH:mm:ss",fullDateTime:"MMMM d\'. b. \'yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^tsïen(gele)?/i,feb:/^goevt(e)?/i,mar:/^njok(tje)?/i,apr:/^voer(htje)?/i,may:/^sueh(pede)?/i,jun:/^ruff(ie)?/i,jul:/^snja(ltje)?/i,aug:/^mïet(ske)?/i,sep:/^skïer(ede)?/i,oct:/^golk(e)?/i,nov:/^rahk(a)?/i,dec:/^goev(e)?/i,sun:/^aejlege/i,mon:/^måanta/i,tue:/^dæjsta/i,wed:/^gaskevåhkoe/i,thu:/^duarsta/i,fri:/^bearjadahke/i,sat:/^laavvardahke/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'smj-NO' => 'Date.CultureInfo={name:"smj-NO",englishName:"Sami (Lule) (Norway)",nativeName:"julevusámegiella (Vuodna)",dayNames:["sådnåbiejvve","mánnodahka","dijstahka","gasskavahkko","duorastahka","bierjjedahka","lávvodahka"],abbreviatedDayNames:["såd","mán","dis","gas","duor","bier","láv"],shortestDayNames:["såd","mán","dis","gas","duor","bier","láv"],firstLetterDayNames:["s","m","d","g","d","b","l"],monthNames:["ådåjakmánno","guovvamánno","sjnjuktjamánno","vuoratjismánno","moarmesmánno","biehtsemánno","sjnjilltjamánno","bårggemánno","ragátmánno","gålgådismánno","basádismánno","javllamánno"],abbreviatedMonthNames:["ådåj","guov","snju","vuor","moar","bieh","snji","bårg","ragá","gålg","basá","javl"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"MMMM d\'. b. \'yyyy",shortTime:"HH:mm:ss",longTime:"HH:mm:ss",fullDateTime:"MMMM d\'. b. \'yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^ådåj(akmánno)?/i,feb:/^guov(vamánno)?/i,mar:/^sjnjuktjamánno/i,apr:/^vuor(atjismánno)?/i,may:/^moar(mesmánno)?/i,jun:/^bieh(tsemánno)?/i,jul:/^sjnjilltjamánno/i,aug:/^bårg(gemánno)?/i,sep:/^ragá(tmánno)?/i,oct:/^gålg(ådismánno)?/i,nov:/^basá(dismánno)?/i,dec:/^javl(lamánno)?/i,sun:/^sådnåbiejvve/i,mon:/^mánnodahka/i,tue:/^dijstahka/i,wed:/^gasskavahkko/i,thu:/^duorastahka/i,fri:/^bierjjedahka/i,sat:/^lávvodahka/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'smj-SE' => 'Date.CultureInfo={name:"smj-SE",englishName:"Sami (Lule) (Sweden)",nativeName:"julevusámegiella (Svierik)",dayNames:["ájllek","mánnodahka","dijstahka","gasskavahkko","duorastahka","bierjjedahka","lávvodahka"],abbreviatedDayNames:["ájl","mán","dis","gas","duor","bier","láv"],shortestDayNames:["ájl","mán","dis","gas","duor","bier","láv"],firstLetterDayNames:["á","m","d","g","d","b","l"],monthNames:["ådåjakmánno","guovvamánno","sjnjuktjamánno","vuoratjismánno","moarmesmánno","biehtsemánno","sjnjilltjamánno","bårggemánno","ragátmánno","gålgådismánno","basádismánno","javllamánno"],abbreviatedMonthNames:["ådåj","guov","snju","vuor","moar","bieh","snji","bårg","ragá","gålg","basá","javl"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy-MM-dd",longDate:"MMMM d\'. b. \'yyyy",shortTime:"HH:mm:ss",longTime:"HH:mm:ss",fullDateTime:"MMMM d\'. b. \'yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^ådåj(akmánno)?/i,feb:/^guov(vamánno)?/i,mar:/^sjnjuktjamánno/i,apr:/^vuor(atjismánno)?/i,may:/^moar(mesmánno)?/i,jun:/^bieh(tsemánno)?/i,jul:/^sjnjilltjamánno/i,aug:/^bårg(gemánno)?/i,sep:/^ragá(tmánno)?/i,oct:/^gålg(ådismánno)?/i,nov:/^basá(dismánno)?/i,dec:/^javl(lamánno)?/i,sun:/^ájllek/i,mon:/^mánnodahka/i,tue:/^dijstahka/i,wed:/^gasskavahkko/i,thu:/^duorastahka/i,fri:/^bierjjedahka/i,sat:/^lávvodahka/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'smn-FI' => 'Date.CultureInfo={name:"smn-FI",englishName:"Sami (Inari) (Finland)",nativeName:"sämikielâ (Suomâ)",dayNames:["pasepeivi","vuossargâ","majebargâ","koskokko","tuorâstâh","vástuppeivi","lávárdâh"],abbreviatedDayNames:["pa","vu","ma","ko","tu","vá","lá"],shortestDayNames:["pa","vu","ma","ko","tu","vá","lá"],firstLetterDayNames:["p","v","m","k","t","v","l"],monthNames:["uđđâivemáánu","kuovâmáánu","njuhčâmáánu","cuáŋuimáánu","vyesimáánu","kesimáánu","syeinimáánu","porgemáánu","čohčâmáánu","roovvâdmáánu","skammâmáánu","juovlâmáánu"],abbreviatedMonthNames:["uđiv","kuov","njuh","cuoŋ","vyes","kesi","syei","porg","čoh","roov","ska","juov"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d.M.yyyy",longDate:"MMMM d\'. p. \'yyyy",shortTime:"H:mm:ss",longTime:"H:mm:ss",fullDateTime:"MMMM d\'. p. \'yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^uđđâivemáánu/i,feb:/^kuov(âmáánu)?/i,mar:/^njuh(čâmáánu)?/i,apr:/^cuáŋuimáánu/i,may:/^vyes(imáánu)?/i,jun:/^kesi(máánu)?/i,jul:/^syei(nimáánu)?/i,aug:/^porg(emáánu)?/i,sep:/^čoh(čâmáánu)?/i,oct:/^roov(vâdmáánu)?/i,nov:/^ska(mmâmáánu)?/i,dec:/^juov(lâmáánu)?/i,sun:/^pasepeivi/i,mon:/^vuossargâ/i,tue:/^majebargâ/i,wed:/^koskokko/i,thu:/^tuorâstâh/i,fri:/^vástuppeivi/i,sat:/^lávárdâh/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'sms-FI' => 'Date.CultureInfo={name:"sms-FI",englishName:"Sami (Skolt) (Finland)",nativeName:"sääm´ǩiõll (Lää´ddjânnam)",dayNames:["pâ´sspei´vv","vuõssargg","mââibargg","seärad","nelljdpei´vv","piâtnâc","sue´vet"],abbreviatedDayNames:["pâ","vu","mâ","se","ne","pi","su"],shortestDayNames:["pâ","vu","mâ","se","ne","pi","su"],firstLetterDayNames:["p","v","m","s","n","p","s"],monthNames:["ođđee´jjmään","tä´lvvmään","pâ´zzlâšttammään","njuhččmään","vue´ssmään","ǩie´ssmään","suei´nnmään","på´rǧǧmään","čõhččmään","kålggmään","skamm´mään","rosttovmään"],abbreviatedMonthNames:["ođjm","tä´lvv","pâzl","njuh","vue","ǩie","suei","på´r","čõh","kålg","ska","rost"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d.M.yyyy",longDate:"MMMM d\'. p. \'yyyy",shortTime:"H:mm:ss",longTime:"H:mm:ss",fullDateTime:"MMMM d\'. p. \'yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^ođđee´jjmään/i,feb:/^tä´lvv(mään)?/i,mar:/^pâ´zzlâšttammään/i,apr:/^njuh(ččmään)?/i,may:/^vue(´ssmään)?/i,jun:/^ǩie(´ssmään)?/i,jul:/^suei(´nnmään)?/i,aug:/^på´r(ǧǧmään)?/i,sep:/^čõh(ččmään)?/i,oct:/^kålg(gmään)?/i,nov:/^ska(mm´mään)?/i,dec:/^rost(tovmään)?/i,sun:/^pâ´sspei´vv/i,mon:/^vuõssargg/i,tue:/^mââibargg/i,wed:/^seärad/i,thu:/^nelljdpei´vv/i,fri:/^piâtnâc/i,sat:/^sue´vet/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'sq-AL' => 'Date.CultureInfo={name:"sq-AL",englishName:"Albanian (Albania)",nativeName:"shqipe (Shqipëria)",dayNames:["e diel","e hënë","e martë","e mërkurë","e enjte","e premte","e shtunë"],abbreviatedDayNames:["Die","Hën","Mar","Mër","Enj","Pre","Sht"],shortestDayNames:["Di","Hë","Ma","Më","En","Pr","Sh"],firstLetterDayNames:["D","H","M","M","E","P","S"],monthNames:["janar","shkurt","mars","prill","maj","qershor","korrik","gusht","shtator","tetor","nëntor","dhjetor"],abbreviatedMonthNames:["Jan","Shk","Mar","Pri","Maj","Qer","Kor","Gsh","Sht","Tet","Nën","Dhj"],amDesignator:"PD",pmDesignator:"MD",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy-MM-dd",longDate:"yyyy-MM-dd",shortTime:"h:mm.tt",longTime:"h:mm:ss.tt",fullDateTime:"yyyy-MM-dd h:mm:ss.tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"yyyy-MM"},regexPatterns:{jan:/^jan(ar)?/i,feb:/^shk(urt)?/i,mar:/^mar(s)?/i,apr:/^pri(ll)?/i,may:/^maj/i,jun:/^qer(shor)?/i,jul:/^kor(rik)?/i,aug:/^gusht/i,sep:/^sht(ator)?/i,oct:/^tet(or)?/i,nov:/^nën(tor)?/i,dec:/^dhj(etor)?/i,sun:/^di(e(iel)?)?/i,mon:/^hë(n(ënë)?)?/i,tue:/^ma(r(artë)?)?/i,wed:/^më(r(ërkurë)?)?/i,thu:/^en(j(njte)?)?/i,fri:/^pr(e(remte)?)?/i,sat:/^sh(t(htunë)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'sr-Cyrl-BA' => 'Date.CultureInfo={name:"sr-Cyrl-BA",englishName:"Serbian (Cyrillic) (Bosnia and Herzegovina)",nativeName:"српски (Босна и Херцеговина)",dayNames:["недеља","понедељак","уторак","среда","четвртак","петак","субота"],abbreviatedDayNames:["нед","пон","уто","сре","чет","пет","суб"],shortestDayNames:["нед","пон","уто","сре","чет","пет","суб"],firstLetterDayNames:["н","п","у","с","ч","п","с"],monthNames:["јануар","фебруар","март","април","мај","јун","јул","август","септембар","октобар","новембар","децембар"],abbreviatedMonthNames:["јан","феб","мар","апр","мај","јун","јул","авг","сеп","окт","нов","дец"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d.M.yyyy",longDate:"d. MMMM yyyy",shortTime:"H:mm:ss",longTime:"H:mm:ss",fullDateTime:"d. MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^јан(уар)?/i,feb:/^феб(руар)?/i,mar:/^мар(т)?/i,apr:/^апр(ил)?/i,may:/^мај/i,jun:/^јун/i,jul:/^јул/i,aug:/^авг(уст)?/i,sep:/^сеп(тембар)?/i,oct:/^окт(обар)?/i,nov:/^нов(ембар)?/i,dec:/^дец(ембар)?/i,sun:/^недеља/i,mon:/^понедељак/i,tue:/^уторак/i,wed:/^среда/i,thu:/^четвртак/i,fri:/^петак/i,sat:/^субота/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'sr-Cyrl-CS' => 'Date.CultureInfo={name:"sr-Cyrl-CS",englishName:"Serbian (Cyrillic, Serbia)",nativeName:"српски (Србија)",dayNames:["недеља","понедељак","уторак","среда","четвртак","петак","субота"],abbreviatedDayNames:["нед","пон","уто","сре","чет","пет","суб"],shortestDayNames:["не","по","ут","ср","че","пе","су"],firstLetterDayNames:["н","п","у","с","ч","п","с"],monthNames:["јануар","фебруар","март","април","мај","јун","јул","август","септембар","октобар","новембар","децембар"],abbreviatedMonthNames:["јан","феб","мар","апр","мај","јун","јул","авг","сеп","окт","нов","дец"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d.M.yyyy",longDate:"d. MMMM yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d. MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d. MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^јан(уар)?/i,feb:/^феб(руар)?/i,mar:/^мар(т)?/i,apr:/^апр(ил)?/i,may:/^мај/i,jun:/^јун/i,jul:/^јул/i,aug:/^авг(уст)?/i,sep:/^сеп(тембар)?/i,oct:/^окт(обар)?/i,nov:/^нов(ембар)?/i,dec:/^дец(ембар)?/i,sun:/^не(д(еља)?)?/i,mon:/^по(н(едељак)?)?/i,tue:/^ут(о(рак)?)?/i,wed:/^ср(е(да)?)?/i,thu:/^че(т(вртак)?)?/i,fri:/^пе(т(ак)?)?/i,sat:/^су(б(ота)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'sr-Latn-BA' => 'Date.CultureInfo={name:"sr-Latn-BA",englishName:"Serbian (Latin) (Bosnia and Herzegovina)",nativeName:"srpski (Bosna i Hercegovina)",dayNames:["nedelja","ponedeljak","utorak","sreda","četvrtak","petak","subota"],abbreviatedDayNames:["ned","pon","uto","sre","čet","pet","sub"],shortestDayNames:["ned","pon","uto","sre","čet","pet","sub"],firstLetterDayNames:["n","p","u","s","č","p","s"],monthNames:["januar","februar","mart","april","maj","jun","jul","avgust","septembar","oktobar","novembar","decembar"],abbreviatedMonthNames:["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d.M.yyyy",longDate:"d. MMMM yyyy",shortTime:"H:mm:ss",longTime:"H:mm:ss",fullDateTime:"d. MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uar)?/i,feb:/^feb(ruar)?/i,mar:/^mar(t)?/i,apr:/^apr(il)?/i,may:/^maj/i,jun:/^jun/i,jul:/^jul/i,aug:/^avg(ust)?/i,sep:/^sep(tembar)?/i,oct:/^okt(obar)?/i,nov:/^nov(embar)?/i,dec:/^dec(embar)?/i,sun:/^nedelja/i,mon:/^ponedeljak/i,tue:/^utorak/i,wed:/^sreda/i,thu:/^četvrtak/i,fri:/^petak/i,sat:/^subota/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'sr-Latn-CS' => 'Date.CultureInfo={name:"sr-Latn-CS",englishName:"Serbian (Latin, Serbia)",nativeName:"srpski (Srbija)",dayNames:["nedelja","ponedeljak","utorak","sreda","četvrtak","petak","subota"],abbreviatedDayNames:["ned","pon","uto","sre","čet","pet","sub"],shortestDayNames:["ne","po","ut","sr","če","pe","su"],firstLetterDayNames:["n","p","u","s","č","p","s"],monthNames:["januar","februar","mart","april","maj","jun","jul","avgust","septembar","oktobar","novembar","decembar"],abbreviatedMonthNames:["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d.M.yyyy",longDate:"d. MMMM yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d. MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d. MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uar)?/i,feb:/^feb(ruar)?/i,mar:/^mar(t)?/i,apr:/^apr(il)?/i,may:/^maj/i,jun:/^jun/i,jul:/^jul/i,aug:/^avg(ust)?/i,sep:/^sep(tembar)?/i,oct:/^okt(obar)?/i,nov:/^nov(embar)?/i,dec:/^dec(embar)?/i,sun:/^ne(d(elja)?)?/i,mon:/^po(n(edeljak)?)?/i,tue:/^ut(o(rak)?)?/i,wed:/^sr(e(da)?)?/i,thu:/^če(t(vrtak)?)?/i,fri:/^pe(t(ak)?)?/i,sat:/^su(b(ota)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'sv-FI' => 'Date.CultureInfo={name:"sv-FI",englishName:"Swedish (Finland)",nativeName:"svenska (Finland)",dayNames:["söndag","måndag","tisdag","onsdag","torsdag","fredag","lördag"],abbreviatedDayNames:["sö","må","ti","on","to","fr","lö"],shortestDayNames:["sö","må","ti","on","to","fr","lö"],firstLetterDayNames:["s","m","t","o","t","f","l"],monthNames:["januari","februari","mars","april","maj","juni","juli","augusti","september","oktober","november","december"],abbreviatedMonthNames:["jan","feb","mar","apr","maj","jun","jul","aug","sep","okt","nov","dec"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d.M.yyyy",longDate:"\'den \'d MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"\'den \'d MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"\'den \'d MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uari)?/i,feb:/^feb(ruari)?/i,mar:/^mar(s)?/i,apr:/^apr(il)?/i,may:/^maj/i,jun:/^jun(i)?/i,jul:/^jul(i)?/i,aug:/^aug(usti)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^söndag/i,mon:/^måndag/i,tue:/^tisdag/i,wed:/^onsdag/i,thu:/^torsdag/i,fri:/^fredag/i,sat:/^lördag/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'sv-SE' => 'Date.CultureInfo={name:"sv-SE",englishName:"Swedish (Sweden)",nativeName:"svenska (Sverige)",dayNames:["söndag","måndag","tisdag","onsdag","torsdag","fredag","lördag"],abbreviatedDayNames:["sö","må","ti","on","to","fr","lö"],shortestDayNames:["sö","må","ti","on","to","fr","lö"],firstLetterDayNames:["s","m","t","o","t","f","l"],monthNames:["januari","februari","mars","april","maj","juni","juli","augusti","september","oktober","november","december"],abbreviatedMonthNames:["jan","feb","mar","apr","maj","jun","jul","aug","sep","okt","nov","dec"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy-MM-dd",longDate:"\'den \'d MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"\'den \'d MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"\'den \'d MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^jan(uari)?/i,feb:/^feb(ruari)?/i,mar:/^mar(s)?/i,apr:/^apr(il)?/i,may:/^maj/i,jun:/^jun(i)?/i,jul:/^jul(i)?/i,aug:/^aug(usti)?/i,sep:/^sep(t(ember)?)?/i,oct:/^okt(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^söndag/i,mon:/^måndag/i,tue:/^tisdag/i,wed:/^onsdag/i,thu:/^torsdag/i,fri:/^fredag/i,sat:/^lördag/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'sw-KE' => 'Date.CultureInfo={name:"sw-KE",englishName:"Kiswahili (Kenya)",nativeName:"Kiswahili (Kenya)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["S","M","T","W","T","F","S"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^s(un(day)?)?/i,mon:/^m(on(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^w(ed(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^f(ri(day)?)?/i,sat:/^s(at(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'syr-SY' => 'Date.CultureInfo={name:"syr-SY",englishName:"Syriac (Syria)",nativeName:"ܣܘܪܝܝܐ (سوريا)",dayNames:["ܚܕ ܒܫܒܐ","ܬܪܝܢ ܒܫܒܐ","ܬܠܬܐ ܒܫܒܐ","ܐܪܒܥܐ ܒܫܒܐ","ܚܡܫܐ ܒܫܒܐ","ܥܪܘܒܬܐ","ܫܒܬܐ"],abbreviatedDayNames:["܏ܐ ܏ܒܫ","܏ܒ ܏ܒܫ","܏ܓ ܏ܒܫ","܏ܕ ܏ܒܫ","܏ܗ ܏ܒܫ","܏ܥܪܘܒ","܏ܫܒ"],shortestDayNames:["܏","܏","܏","܏","܏","܏","܏"],firstLetterDayNames:["܏","܏","܏","܏","܏","܏","܏"],monthNames:["ܟܢܘܢ ܐܚܪܝ","ܫܒܛ","ܐܕܪ","ܢܝܣܢ","ܐܝܪ","ܚܙܝܪܢ","ܬܡܘܙ","ܐܒ","ܐܝܠܘܠ","ܬܫܪܝ ܩܕܝܡ","ܬܫܪܝ ܐܚܪܝ","ܟܢܘܢ ܩܕܝܡ"],abbreviatedMonthNames:["܏ܟܢ ܏ܒ","ܫܒܛ","ܐܕܪ","ܢܝܣܢ","ܐܝܪ","ܚܙܝܪܢ","ܬܡܘܙ","ܐܒ","ܐܝܠܘܠ","܏ܬܫ ܏ܐ","܏ܬܫ ܏ܒ","܏ܟܢ ܏ܐ"],amDesignator:"ܩ.ܛ",pmDesignator:"ܒ.ܛ",firstDayOfWeek:6,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM, yyyy",shortTime:"hh:mm tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM, yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^ܟܢܘܢ ܐܚܪܝ/i,feb:/^ܫܒܛ/i,mar:/^ܐܕܪ/i,apr:/^ܢܝܣܢ/i,may:/^ܐܝܪ/i,jun:/^ܚܙܝܪܢ/i,jul:/^ܬܡܘܙ/i,aug:/^ܐܒ/i,sep:/^ܐܝܠܘܠ/i,oct:/^ܬܫܪܝ ܩܕܝܡ/i,nov:/^ܬܫܪܝ ܐܚܪܝ/i,dec:/^ܟܢܘܢ ܩܕܝܡ/i,sun:/^܏(ܐ ܏ܒܫ(ܐ)?)?/i,mon:/^܏(ܒ ܏ܒܫ(ܫܒܐ)?)?/i,tue:/^܏(ܓ ܏ܒܫ(ܫܒܐ)?)?/i,wed:/^܏(ܕ ܏ܒܫ(ܒܫܒܐ)?)?/i,thu:/^܏(ܗ ܏ܒܫ(ܫܒܐ)?)?/i,fri:/^܏(ܥܪܘܒ(ܐ)?)?/i,sat:/^܏(ܫܒ(ܐ)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ta-IN' => 'Date.CultureInfo={name:"ta-IN",englishName:"Tamil (India)",nativeName:"தமிழ் (இந்தியா)",dayNames:["ஞாயிறு","திங்கள்","செவ்வாய்","புதன்","வியாழன்","வெள்ளி","சனி"],abbreviatedDayNames:["ஞா","தி","செ","பு","வி","வெ","ச"],shortestDayNames:["ஞ","த","ச","ப","வ","வ","ச"],firstLetterDayNames:["ஞ","த","ச","ப","வ","வ","ச"],monthNames:["ஜனவரி","பெப்ரவரி","மார்ச்","ஏப்ரல்","மே","ஜூன்","ஜூலை","ஆகஸ்ட்","செப்டம்பர்","அக்டோபர்","நவம்பர்","டிசம்பர்"],abbreviatedMonthNames:["ஜன.","பெப்.","மார்.","ஏப்.","மே","ஜூன்","ஜூலை","ஆக.","செப்.","அக்.","நவ.","டிச."],amDesignator:"காலை",pmDesignator:"மாலை",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd-MM-yyyy",longDate:"dd MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dd MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^ஜன(.(வரி)?)?/i,feb:/^பெப்(.(ரவரி)?)?/i,mar:/^மார்(.(ச்)?)?/i,apr:/^ஏப்(.(ரல்)?)?/i,may:/^மே/i,jun:/^ஜூன்/i,jul:/^ஜூலை/i,aug:/^ஆக(.(ஸ்ட்)?)?/i,sep:/^செப்(.(டம்பர்)?)?/i,oct:/^அக்(.(டோபர்)?)?/i,nov:/^நவ(.(ம்பர்)?)?/i,dec:/^டிச(.(ம்பர்)?)?/i,sun:/^ஞ(ா(யிறு)?)?/i,mon:/^த(ி(ங்கள்)?)?/i,tue:/^ச(ெ(வ்வாய்)?)?/i,wed:/^ப(ு(தன்)?)?/i,thu:/^வ(ி(யாழன்)?)?/i,fri:/^வ(ெ(ள்ளி)?)?/i,sat:/^சனி/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'te-IN' => 'Date.CultureInfo={name:"te-IN",englishName:"Telugu (India)",nativeName:"తెలుగు (భారత దేశం)",dayNames:["ఆదివారం","సోమవారం","మంగళవారం","బుధవారం","గురువారం","శుక్రవారం","శనివారం"],abbreviatedDayNames:["ఆది.","సోమ.","మంగళ.","బుధ.","గురు.","శుక్ర.","శని."],shortestDayNames:["ఆ","స","మ","బ","గ","శ","శ"],firstLetterDayNames:["ఆ","స","మ","బ","గ","శ","శ"],monthNames:["జనవరి","ఫిబ్రవరి","మార్చి","ఏప్రిల్","మే","జూన్","జూలై","ఆగస్టు","సెప్టెంబర్","అక్టోబర్","నవంబర్","డిసెంబర్"],abbreviatedMonthNames:["జనవరి","ఫిబ్రవరి","మార్చి","ఏప్రిల్","మే","జూన్","జూలై","ఆగస్టు","సెప్టెంబర్","అక్టోబర్","నవంబర్","డిసెంబర్"],amDesignator:"పూర్వాహ్న",pmDesignator:"అపరాహ్న",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd-MM-yy",longDate:"dd MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dd MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^జనవరి/i,feb:/^ఫిబ్రవరి/i,mar:/^మార్చి/i,apr:/^ఏప్రిల్/i,may:/^మే/i,jun:/^జూన్/i,jul:/^జూలై/i,aug:/^ఆగస్టు/i,sep:/^సెప్టెంబర్/i,oct:/^అక్టోబర్/i,nov:/^నవంబర్/i,dec:/^డిసెంబర్/i,sun:/^ఆ(ది(.(వారం)?)?)?/i,mon:/^స(ోమ(.(వారం)?)?)?/i,tue:/^మ(ంగళ(.(వారం)?)?)?/i,wed:/^బ(ుధ(.(వారం)?)?)?/i,thu:/^గ(ురు(.(వారం)?)?)?/i,fri:/^శ(ుక్ర(.(వారం)?)?)?/i,sat:/^శ(ని(.(వారం)?)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'th-TH' => 'Date.CultureInfo={name:"th-TH",englishName:"Thai (Thailand)",nativeName:"ไทย (ไทย)",dayNames:["อาทิตย์","จันทร์","อังคาร","พุธ","พฤหัสบดี","ศุกร์","เสาร์"],abbreviatedDayNames:["อา.","จ.","อ.","พ.","พฤ.","ศ.","ส."],shortestDayNames:["อ","จ","อ","พ","พ","ศ","ส"],firstLetterDayNames:["อ","จ","อ","พ","พ","ศ","ส"],monthNames:["มกราคม","กุมภาพันธ์","มีนาคม","เมษายน","พฤษภาคม","มิถุนายน","กรกฎาคม","สิงหาคม","กันยายน","ตุลาคม","พฤศจิกายน","ธันวาคม"],abbreviatedMonthNames:["ม.ค.","ก.พ.","มี.ค.","เม.ย.","พ.ค.","มิ.ย.","ก.ค.","ส.ค.","ก.ย.","ต.ค.","พ.ย.","ธ.ค."],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:1,twoDigitYearMax:2572,dateElementOrder:"dmy",formatPatterns:{shortDate:"d/M/yyyy",longDate:"d MMMM yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^ม(.(กราค)?)?/i,feb:/^ก(.(ุมภาพันธ์)?)?/i,mar:/^มี(.(นาคม)?)?/i,apr:/^เม(.(ษายน)?)?/i,may:/^พ(.(ฤษภาคม)?)?/i,jun:/^มิ(.(ถุนายน)?)?/i,jul:/^ก(.(รฎาคม)?)?/i,aug:/^ส(.(ิงหาคม)?)?/i,sep:/^ก(.(ันยายน)?)?/i,oct:/^ต(.(ุลาคม)?)?/i,nov:/^พ(.(ฤศจิกายน)?)?/i,dec:/^ธ(.(ันวาคม)?)?/i,sun:/^อ(า(.(ทิตย์)?)?)?/i,mon:/^จ((.(ันทร์)?)?)?/i,tue:/^อ((.(ังคาร)?)?)?/i,wed:/^พ((.(ุธ)?)?)?/i,thu:/^พ(ฤ(.(หัสบดี)?)?)?/i,fri:/^ศ((.(ุกร์)?)?)?/i,sat:/^ส((.(สาร์)?)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'tn-ZA' => 'Date.CultureInfo={name:"tn-ZA",englishName:"Tswana (South Africa)",nativeName:"Setswana (Aforika Borwa)",dayNames:["Latshipi","Mosupologo","Labobedi","Laboraro","Labone","Labotlhano","Lamatlhatso"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["Ferikgong","Tlhakole","Mopitloe","Moranang","Motsheganong","Seetebosigo","Phukwi","Phatwe","Lwetse","Diphalane","Ngwanatsele","Sedimothole"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy/MM/dd",longDate:"dd MMMM yyyy",shortTime:"hh:mm:ss tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^ferikgong/i,feb:/^tlhakole/i,mar:/^mopitloe/i,apr:/^moranang/i,may:/^motsheganong/i,jun:/^seetebosigo/i,jul:/^phukwi/i,aug:/^phatwe/i,sep:/^lwetse/i,oct:/^diphalane/i,nov:/^ngwanatsele/i,dec:/^sedimothole/i,sun:/^latshipi/i,mon:/^mosupologo/i,tue:/^labobedi/i,wed:/^laboraro/i,thu:/^labone/i,fri:/^labotlhano/i,sat:/^lamatlhatso/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'tr-TR' => 'Date.CultureInfo={name:"tr-TR",englishName:"Turkish (Turkey)",nativeName:"Türkçe (Türkiye)",dayNames:["Pazar","Pazartesi","Salı","Çarşamba","Perşembe","Cuma","Cumartesi"],abbreviatedDayNames:["Paz","Pzt","Sal","Çar","Per","Cum","Cmt"],shortestDayNames:["Pz","Pt","Sa","Ça","Pe","Cu","Ct"],firstLetterDayNames:["P","P","S","Ç","P","C","C"],monthNames:["Ocak","Şubat","Mart","Nisan","Mayıs","Haziran","Temmuz","Ağustos","Eylül","Ekim","Kasım","Aralık"],abbreviatedMonthNames:["Oca","Şub","Mar","Nis","May","Haz","Tem","Ağu","Eyl","Eki","Kas","Ara"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"dd MMMM yyyy dddd",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dd MMMM yyyy dddd HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^oca(k)?/i,feb:/^şub(at)?/i,mar:/^mar(t)?/i,apr:/^nis(an)?/i,may:/^may(ıs)?/i,jun:/^haz(iran)?/i,jul:/^tem(muz)?/i,aug:/^ağu(stos)?/i,sep:/^eyl(ül)?/i,oct:/^eki(m)?/i,nov:/^kas(ım)?/i,dec:/^ara(lık)?/i,sun:/^pz(z(ar)?)?/i,mon:/^pt(t(artesi)?)?/i,tue:/^sa(l(ı)?)?/i,wed:/^ça(r(şamba)?)?/i,thu:/^pe(r(şembe)?)?/i,fri:/^cu(m(a)?)?/i,sat:/^ct(t(artesi)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'tt-RU' => 'Date.CultureInfo={name:"tt-RU",englishName:"Tatar (Russia)",nativeName:"Татар (Россия)",dayNames:["Якшәмбе","Дүшәмбе","Сишәмбе","Чәршәмбе","Пәнҗешәмбе","Җомга","Шимбә"],abbreviatedDayNames:["Якш","Дүш","Сиш","Чәрш","Пәнҗ","Җом","Шим"],shortestDayNames:["Якш","Дүш","Сиш","Чәрш","Пәнҗ","Җом","Шим"],firstLetterDayNames:["Я","Д","С","Ч","П","Җ","Ш"],monthNames:["Гыйнварь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"],abbreviatedMonthNames:["Гыйнв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"d MMMM yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d MMMM yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^гыйнв(арь)?/i,feb:/^фев(раль)?/i,mar:/^мар(т)?/i,apr:/^апр(ель)?/i,may:/^май/i,jun:/^июн(ь)?/i,jul:/^июл(ь)?/i,aug:/^авг(уст)?/i,sep:/^сен(тябрь)?/i,oct:/^окт(ябрь)?/i,nov:/^ноя(брь)?/i,dec:/^дек(абрь)?/i,sun:/^якшәмбе/i,mon:/^дүшәмбе/i,tue:/^сишәмбе/i,wed:/^чәршәмбе/i,thu:/^пәнҗешәмбе/i,fri:/^җомга/i,sat:/^шимбә/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'uk-UA' => 'Date.CultureInfo={name:"uk-UA",englishName:"Ukrainian (Ukraine)",nativeName:"україньска (Україна)",dayNames:["неділя","понеділок","вівторок","середа","четвер","п\'ятниця","субота"],abbreviatedDayNames:["Нд","Пн","Вт","Ср","Чт","Пт","Сб"],shortestDayNames:["Нд","Пн","Вт","Ср","Чт","Пт","Сб"],firstLetterDayNames:["Н","П","В","С","Ч","П","С"],monthNames:["Січень","Лютий","Березень","Квітень","Травень","Червень","Липень","Серпень","Вересень","Жовтень","Листопад","Грудень"],abbreviatedMonthNames:["Січ","Лют","Бер","Кві","Тра","Чер","Лип","Сер","Вер","Жов","Лис","Гру"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"d MMMM yyyy\' р.\'",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"d MMMM yyyy\' р.\' H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM yyyy\' р.\'"},regexPatterns:{jan:/^січ(ень)?/i,feb:/^лют(ий)?/i,mar:/^бер(езень)?/i,apr:/^кві(тень)?/i,may:/^тра(вень)?/i,jun:/^чер(вень)?/i,jul:/^лип(ень)?/i,aug:/^сер(пень)?/i,sep:/^вер(есень)?/i,oct:/^жов(тень)?/i,nov:/^лис(топад)?/i,dec:/^гру(день)?/i,sun:/^неділя/i,mon:/^понеділок/i,tue:/^вівторок/i,wed:/^середа/i,thu:/^четвер/i,fri:/^п\'ятниця/i,sat:/^субота/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'ur-PK' => 'Date.CultureInfo={name:"ur-PK",englishName:"Urdu (Islamic Republic of Pakistan)",nativeName:"اُردو (پاکستان)",dayNames:["اتوار","پير","منگل","بدھ","جمعرات","جمعه","هفته"],abbreviatedDayNames:["اتوار","پير","منگل","بدھ","جمعرات","جمعه","هفته"],shortestDayNames:["ا","پ","م","ب","ج","ج","ه"],firstLetterDayNames:["ا","پ","م","ب","ج","ج","ه"],monthNames:["جنورى","فرورى","مارچ","اپريل","مئ","جون","جولاٸ","اگست","ستمبر","اکتوبر","نومبر","دسمبر"],abbreviatedMonthNames:["جنورى","فرورى","مارچ","اپريل","مئ","جون","جولاٸ","اگست","ستمبر","اکتوبر","نومبر","دسمبر"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dd MMMM, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^جنورى/i,feb:/^فرورى/i,mar:/^مارچ/i,apr:/^اپريل/i,may:/^مئ/i,jun:/^جون/i,jul:/^جولاٸ/i,aug:/^اگست/i,sep:/^ستمبر/i,oct:/^اکتوبر/i,nov:/^نومبر/i,dec:/^دسمبر/i,sun:/^ا(1)?/i,mon:/^پ(1)?/i,tue:/^م(1)?/i,wed:/^ب(1)?/i,thu:/^ج(1)?/i,fri:/^ج(1)?/i,sat:/^ه(1)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'uz-Cyrl-UZ' => 'Date.CultureInfo={name:"uz-Cyrl-UZ",englishName:"Uzbek (Cyrillic, Uzbekistan)",nativeName:"Ўзбек (Ўзбекистон)",dayNames:["якшанба","душанба","сешанба","чоршанба","пайшанба","жума","шанба"],abbreviatedDayNames:["якш","дш","сш","чш","пш","ж","ш"],shortestDayNames:["якш","дш","сш","чш","пш","ж","ш"],firstLetterDayNames:["я","д","с","ч","п","ж","ш"],monthNames:["Январ","Феврал","Март","Апрел","Май","Июн","Июл","Август","Сентябр","Октябр","Ноябр","Декабр"],abbreviatedMonthNames:["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"yyyy \'йил\' d-MMMM",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"yyyy \'йил\' d-MMMM HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d-MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^янв(ар)?/i,feb:/^фев(рал)?/i,mar:/^мар(т)?/i,apr:/^апр(ел)?/i,may:/^май/i,jun:/^июн/i,jul:/^июл/i,aug:/^авг(уст)?/i,sep:/^сен(тябр)?/i,oct:/^окт(ябр)?/i,nov:/^ноя(бр)?/i,dec:/^дек(абр)?/i,sun:/^якшанба/i,mon:/^душанба/i,tue:/^сешанба/i,wed:/^чоршанба/i,thu:/^пайшанба/i,fri:/^жума/i,sat:/^шанба/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'uz-Latn-UZ' => 'Date.CultureInfo={name:"uz-Latn-UZ",englishName:"Uzbek (Latin, Uzbekistan)",nativeName:"U\'zbek (U\'zbekiston Respublikasi)",dayNames:["yakshanba","dushanba","seshanba","chorshanba","payshanba","juma","shanba"],abbreviatedDayNames:["yak.","dsh.","sesh.","chr.","psh.","jm.","sh."],shortestDayNames:["yak","dsh","sesh","chr","psh","jm","sh"],firstLetterDayNames:["y","d","s","c","p","j","s"],monthNames:["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr"],abbreviatedMonthNames:["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM yyyy",longDate:"yyyy \'yil\' d-MMMM",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"yyyy \'yil\' d-MMMM HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d-MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^yanvar/i,feb:/^fevral/i,mar:/^mart/i,apr:/^aprel/i,may:/^may/i,jun:/^iyun/i,jul:/^iyul/i,aug:/^avgust/i,sep:/^sentyabr/i,oct:/^oktyabr/i,nov:/^noyabr/i,dec:/^dekabr/i,sun:/^yak((.(shanba)?)?)?/i,mon:/^dsh((.(hanba)?)?)?/i,tue:/^sesh((.(anba)?)?)?/i,wed:/^chr((.(rshanba)?)?)?/i,thu:/^psh((.(shanba)?)?)?/i,fri:/^jm((.(ma)?)?)?/i,sat:/^sh((.(anba)?)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'vi-VN' => 'Date.CultureInfo={name:"vi-VN",englishName:"Vietnamese (Vietnam)",nativeName:"Tiếng Việt (Việt Nam)",dayNames:["Chủ Nhật","Thứ Hai","Thứ Ba","Thứ Tư","Thứ Năm","Thứ Sáu","Thứ Bảy"],abbreviatedDayNames:["CN","Hai","Ba","Tư","Năm","Sáu","Bảy"],shortestDayNames:["C","H","B","T","N","S","B"],firstLetterDayNames:["C","H","B","T","N","S","B"],monthNames:["Tháng Giêng","Tháng Hai","Tháng Ba","Tháng Tư","Tháng Năm","Tháng Sáu","Tháng Bảy","Tháng Tám","Tháng Chín","Tháng Mười","Tháng Mười Một","Tháng Mười Hai"],abbreviatedMonthNames:["Thg1","Thg2","Thg3","Thg4","Thg5","Thg6","Thg7","Thg8","Thg9","Thg10","Thg11","Thg12"],amDesignator:"SA",pmDesignator:"CH",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd/MM/yyyy",longDate:"dd MMMM yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dd MMMM yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^tháng giêng/i,feb:/^tháng hai/i,mar:/^tháng ba/i,apr:/^tháng tư/i,may:/^tháng năm/i,jun:/^tháng sáu/i,jul:/^tháng bảy/i,aug:/^tháng tám/i,sep:/^tháng chín/i,oct:/^tháng mười/i,nov:/^tháng mười một/i,dec:/^tháng mười hai/i,sun:/^c(n(ủ nhật)?)?/i,mon:/^h(ai(́ hai)?)?/i,tue:/^b(a(ứ ba)?)?/i,wed:/^t(ư(ứ tư)?)?/i,thu:/^n(ăm(́ năm)?)?/i,fri:/^s(áu( sáu)?)?/i,sat:/^b(ảy( bảy)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'xh-ZA' => 'Date.CultureInfo={name:"xh-ZA",englishName:"Xhosa (South Africa)",nativeName:"isiXhosa (uMzantsi Afrika)",dayNames:["iCawa","uMvulo","uLwesibini","uLwesithathu","uLwesine","uLwesihlanu","uMgqibelo"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["eyoMqungu","eyoMdumba","eyoKwindla","Tshazimpuzi","Canzibe","eyeSilimela","eyeKhala","eyeThupha","eyoMsintsi","eyeDwara","eyeNkanga","eyoMnga"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy/MM/dd",longDate:"dd MMMM yyyy",shortTime:"hh:mm:ss tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^eyomqungu/i,feb:/^eyomdumba/i,mar:/^eyokwindla/i,apr:/^tshazimpuzi/i,may:/^canzibe/i,jun:/^eyesilimela/i,jul:/^eyekhala/i,aug:/^eyethupha/i,sep:/^eyomsintsi/i,oct:/^eyedwara/i,nov:/^eyenkanga/i,dec:/^eyomnga/i,sun:/^icawa/i,mon:/^umvulo/i,tue:/^ulwesibini/i,wed:/^ulwesithathu/i,thu:/^ulwesine/i,fri:/^ulwesihlanu/i,sat:/^umgqibelo/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'zh-CN' => 'Date.CultureInfo={name:"zh-CN",englishName:"Chinese (People\'s Republic of China)",nativeName:"中文(中华人民共和国)",dayNames:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],abbreviatedDayNames:["日","一","二","三","四","五","六"],shortestDayNames:["日","一","二","三","四","五","六"],firstLetterDayNames:["日","一","二","三","四","五","六"],monthNames:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],abbreviatedMonthNames:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],amDesignator:"上午",pmDesignator:"下午",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy/M/d",longDate:"yyyy\'年\'M\'月\'d\'日\'",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"yyyy\'年\'M\'月\'d\'日\' H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"M\'月\'d\'日\'",yearMonth:"yyyy\'年\'M\'月\'"},regexPatterns:{jan:/^一月/i,feb:/^二月/i,mar:/^三月/i,apr:/^四月/i,may:/^五月/i,jun:/^六月/i,jul:/^七月/i,aug:/^八月/i,sep:/^九月/i,oct:/^十月/i,nov:/^十一月/i,dec:/^十二月/i,sun:/^星期日/i,mon:/^星期一/i,tue:/^星期二/i,wed:/^星期三/i,thu:/^星期四/i,fri:/^星期五/i,sat:/^星期六/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'zh-HK' => 'Date.CultureInfo={name:"zh-HK",englishName:"Chinese (Hong Kong S.A.R.)",nativeName:"中文(香港特别行政區)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"",pmDesignator:"",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d/M/yyyy",longDate:"dddd, d MMMM, yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dddd, d MMMM, yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'zh-MO' => 'Date.CultureInfo={name:"zh-MO",englishName:"Chinese (Macao S.A.R.)",nativeName:"中文(澳門特别行政區)",dayNames:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],abbreviatedDayNames:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],shortestDayNames:["日","一","二","三","四","五","六"],firstLetterDayNames:["日","一","二","三","四","五","六"],monthNames:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],abbreviatedMonthNames:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],amDesignator:"",pmDesignator:"",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d/M/yyyy",longDate:"dddd, d MMMM, yyyy",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"dddd, d MMMM, yyyy H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^一月/i,feb:/^二月/i,mar:/^三月/i,apr:/^四月/i,may:/^五月/i,jun:/^六月/i,jul:/^七月/i,aug:/^八月/i,sep:/^九月/i,oct:/^十月/i,nov:/^十一月/i,dec:/^十二月/i,sun:/^星期日/i,mon:/^星期一/i,tue:/^星期二/i,wed:/^星期三/i,thu:/^星期四/i,fri:/^星期五/i,sat:/^星期六/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'zh-SG' => 'Date.CultureInfo={name:"zh-SG",englishName:"Chinese (Singapore)",nativeName:"中文(新加坡)",dayNames:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],abbreviatedDayNames:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],shortestDayNames:["日","一","二","三","四","五","六"],firstLetterDayNames:["日","一","二","三","四","五","六"],monthNames:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],abbreviatedMonthNames:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d/M/yyyy",longDate:"dddd, d MMMM, yyyy",shortTime:"tt h:mm",longTime:"tt h:mm:ss",fullDateTime:"dddd, d MMMM, yyyy tt h:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^一月/i,feb:/^二月/i,mar:/^三月/i,apr:/^四月/i,may:/^五月/i,jun:/^六月/i,jul:/^七月/i,aug:/^八月/i,sep:/^九月/i,oct:/^十月/i,nov:/^十一月/i,dec:/^十二月/i,sun:/^星期日/i,mon:/^星期一/i,tue:/^星期二/i,wed:/^星期三/i,thu:/^星期四/i,fri:/^星期五/i,sat:/^星期六/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'zh-TW' => 'Date.CultureInfo={name:"zh-TW",englishName:"Chinese (Taiwan)",nativeName:"中文(台灣)",dayNames:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],abbreviatedDayNames:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],shortestDayNames:["日","一","二","三","四","五","六"],firstLetterDayNames:["日","一","二","三","四","五","六"],monthNames:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],abbreviatedMonthNames:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],amDesignator:"上午",pmDesignator:"下午",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy/M/d",longDate:"yyyy\'年\'M\'月\'d\'日\'",shortTime:"tt hh:mm",longTime:"tt hh:mm:ss",fullDateTime:"yyyy\'年\'M\'月\'d\'日\' tt hh:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"M\'月\'d\'日\'",yearMonth:"yyyy\'年\'M\'月\'"},regexPatterns:{jan:/^一月/i,feb:/^二月/i,mar:/^三月/i,apr:/^四月/i,may:/^五月/i,jun:/^六月/i,jul:/^七月/i,aug:/^八月/i,sep:/^九月/i,oct:/^十月/i,nov:/^十一月/i,dec:/^十二月/i,sun:/^星期日/i,mon:/^星期一/i,tue:/^星期二/i,wed:/^星期三/i,thu:/^星期四/i,fri:/^星期五/i,sat:/^星期六/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
'zu-ZA' => 'Date.CultureInfo={name:"zu-ZA",englishName:"Zulu (South Africa)",nativeName:"isiZulu (iNingizimu Afrika)",dayNames:["iSonto","uMsombuluko","uLwesibili","uLwesithathu","uLwesine","uLwesihlanu","uMgqibelo"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["uJanuwari","uFebuwari","uMashi","uAprhili","uMeyi","uJuni","uJulayi","uAgaste","uSepthemba","uOkthoba","uNovemba","uDisemba"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yyyy/MM/dd",longDate:"dd MMMM yyyy",shortTime:"hh:mm:ss tt",longTime:"hh:mm:ss tt",fullDateTime:"dd MMMM yyyy hh:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^ujanuwari/i,feb:/^ufebuwari/i,mar:/^umashi/i,apr:/^uaprhili/i,may:/^umeyi/i,jun:/^ujuni/i,jul:/^ujulayi/i,aug:/^uagaste/i,sep:/^usepthemba/i,oct:/^uokthoba/i,nov:/^unovemba/i,dec:/^udisemba/i,sun:/^isonto/i,mon:/^umsombuluko/i,tue:/^ulwesibili/i,wed:/^ulwesithathu/i,thu:/^ulwesine/i,fri:/^ulwesihlanu/i,sat:/^umgqibelo/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
',
);
public static function localizationForLanguage($language) {
if (isset(self::$localizations[$language])) {
return self::$localizations[$language];
}
return false;
}
}

View File

@@ -0,0 +1,78 @@
<?php
class wfDeactivationOption {
const RETAIN = 'retain';
const DELETE_MAIN = 'delete-main';
const DELETE_LOGIN_SECURITY = 'delete-wfls';
const DELETE_ALL = 'delete-all';
private static $options = array();
private $key;
private $label;
private $deleteMain, $deleteLoginSecurity;
private function __construct($key, $label, $deleteMain, $deleteLoginSecurity) {
$this->key = $key;
$this->label = $label;
$this->deleteMain = $deleteMain;
$this->deleteLoginSecurity = $deleteLoginSecurity;
}
public function getKey() {
return $this->key;
}
public function getLabel() {
return $this->label;
}
public function deletesMain() {
return $this->deleteMain;
}
public function deletesLoginSecurity() {
return $this->deleteLoginSecurity;
}
public function matchesState($deleteMain, $deleteLoginSecurity) {
return $deleteMain === $this->deleteMain && $deleteLoginSecurity === $this->deleteLoginSecurity;
}
private static function registerOption($option) {
self::$options[$option->getKey()] = $option;
}
private static function initializeOptions() {
if (empty(self::$options)) {
$options = array(
new self(self::RETAIN, __('Keep all Wordfence tables and data', 'wordfence'), false, false),
new self(self::DELETE_MAIN, __('Delete Wordfence tables and data, but keep Login Security tables and 2FA codes', 'wordfence'), true, false),
new self(self::DELETE_LOGIN_SECURITY, __('Delete Login Security tables and 2FA codes, but keep Wordfence tables and data', 'wordfence'), false, true),
new self(self::DELETE_ALL, __('Delete all Wordfence tables and data', 'wordfence'), true, true)
);
foreach ($options as $option)
self::registerOption($option);
}
}
public static function getAll() {
self::initializeOptions();
return self::$options;
}
public static function forKey($key) {
self::initializeOptions();
return array_key_exists($key, self::$options) ? self::$options[$key] : null;
}
public static function forState($deleteMain, $deleteLoginSecurity) {
foreach (self::getAll() as $option) {
if ($option->matchesState($deleteMain, $deleteLoginSecurity))
return $option;
}
return null;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,89 @@
<?php
$dictWords = array(
'password',
'Password',
'passwd',
'admin',
'administrator',
'super',
'superuser',
'supervisor',
'root',
'manager',
'mgr',
'1234567890',
'123456789',
'12345678',
'1234567',
'123456',
'12345',
'1234',
'123',
'12',
'1',
'password',
'abc123',
'qwerty',
'asdf',
'zxcv',
'9876543210',
'876543210',
'76543210',
'6543210',
'543210',
'43210',
'3210',
'210',
'10',
'0',
'1',
'11',
'111',
'1111',
'11111',
'2',
'22',
'222',
'2222',
'22222',
'3',
'33',
'333',
'3333',
'33333',
'4',
'44',
'444',
'4444',
'44444',
'5',
'55',
'555',
'5555',
'55555',
'6',
'66',
'666',
'6666',
'66666',
'7',
'77',
'777',
'7777',
'77777',
'8',
'88',
'888',
'8888',
'88888',
'9',
'99',
'999',
'9999',
'99999',
'0',
'00',
'000',
'0000',
'00000'
);

View File

@@ -0,0 +1,88 @@
<?php
abstract class wfDirectoryIterator {
abstract public function file($file);
/**
* @var string
*/
private $directory;
/**
* @var int
*/
private $directory_limit;
private $directories_entered = array();
private $directories_processed = array();
/**
* @var callback
*/
private $callback;
/**
* @var int
*/
private $max_iterations;
private $iterations;
/**
* @param string $directory
* @param int $max_files_per_directory
* @param int $max_iterations
*/
public function __construct($directory = ABSPATH, $max_files_per_directory = 20000, $max_iterations = 1000000) {
$this->directory = $directory;
$this->directory_limit = $max_files_per_directory;
$this->max_iterations = $max_iterations;
}
public function run() {
$this->iterations = 0;
$this->scan($this->directory);
}
protected function scan($dir) {
$dir = rtrim($dir, DIRECTORY_SEPARATOR);
$handle = opendir($dir);
$file_count = 0;
while ($file = readdir($handle)) {
if ($file == '.' || $file == '..') {
continue;
}
$file_path = $dir . '/' . $file;
$real_path = realpath($file_path);
if (isset($this->directories_processed[$real_path]) || isset($this->directories_entered[$real_path])) { //Already processed or being processed, possibly a recursive symlink
continue;
}
else if (is_dir($file_path)) {
$this->directories_entered[$real_path] = 1;
if ($this->scan($file_path) === false) {
closedir($handle);
return false;
}
$this->directories_processed[$real_path] = 1;
unset($this->directories_entered[$real_path]);
}
else {
if ($this->file($file_path) === false) {
closedir($handle);
return false;
}
}
if (++$file_count >= $this->directory_limit) {
break;
}
if (++$this->iterations >= $this->max_iterations) {
closedir($handle);
return false;
}
}
closedir($handle);
return true;
}
}

View File

@@ -0,0 +1,91 @@
<?php
require_once __DIR__ . "/wfInvalidPathException.php";
require_once __DIR__ . "/wfInaccessibleDirectoryException.php";
class wfFileUtils {
const CURRENT_DIRECTORY = '.';
const PARENT_DIRECTORY = '..';
const DIRECTORY_SEPARATOR = '/';
public static function isCurrentOrParentDirectory($file) {
return $file === self::CURRENT_DIRECTORY || $file === self::PARENT_DIRECTORY;
}
public static function getContents($directory) {
$contents = @scandir($directory);
if ($contents === false)
throw new wfInaccessibleDirectoryException("Unable to read contents", $directory);
return array_filter($contents, function ($file) { return !wfFileUtils::isCurrentOrParentDirectory($file); });
}
public static function trimSeparators($path, $trimLeft = true, $trimRight = true) {
if ($trimLeft)
$path = ltrim($path, self::DIRECTORY_SEPARATOR);
if ($trimRight)
$path = rtrim($path, self::DIRECTORY_SEPARATOR);
return $path;
}
public static function joinPaths() {
$paths = func_get_args();
$count = count($paths);
$filtered = array();
$trailingSeparator = false;
for ($i = 0; $i < $count; $i++) {
$path = self::trimSeparators($paths[$i], !empty($filtered));
if (!empty($path)) {
$filtered[] = $path;
$trailingSeparator = substr($paths[$i], -1) === self::DIRECTORY_SEPARATOR;
}
}
return implode(self::DIRECTORY_SEPARATOR, $filtered) . ($trailingSeparator ? self::DIRECTORY_SEPARATOR : '');
}
public static function splitPath($path, &$count = null) {
$components = array_values(array_filter(explode(self::DIRECTORY_SEPARATOR, $path)));
$count = count($components);
return $components;
}
public static function isReadableFile($file) {
return @is_file($file) && @is_readable($file);
}
public static function belongsTo($child, $parent) {
$childComponents = self::splitPath($child, $childCount);
$parentComponents = self::splitPath($parent, $parentCount);
if ($childCount < $parentCount)
return false;
for ($i = 0; $i < $parentCount; $i++) {
if ($childComponents[$i] !== $parentComponents[$i])
return false;
}
return true;
}
public static function matchPaths($a, $b, $allowChild = false) {
$aComponents = self::splitPath($a, $aCount);
$bComponents = self::splitPath($b, $bCount);
if ($allowChild ? ($bCount < $aCount) : ($aCount !== $bCount))
return false;
for ($i = 0; $i < $aCount; $i++) {
if ($aComponents[$i] !== $bComponents[$i])
return false;
}
return true;
}
public static function realPath($path) {
$realPath = realpath($path);
if ($realPath === false)
throw new wfInvalidPathException("Realpath resolution failed", $path);
return $realPath;
}
public static function isChild($parent, $child) {
return self::matchPaths($parent, $child, true);
}
}

View File

@@ -0,0 +1,78 @@
<?php
class wfHelperBin {
/**
* @param string $bin1
* @param string $bin2
* @return mixed
*/
public static function addbin2bin($bin1, $bin2) {
if (strlen($bin1) % 4 != 0) {
$bin1 = str_repeat("\0", 4 - (strlen($bin1) % 4)) . $bin1;
}
if (strlen($bin2) % 4 != 0) {
$bin2 = str_repeat("\0", 4 - (strlen($bin2) % 4)) . $bin2;
}
$bin1_ints = array_reverse(array_values(unpack('N*', $bin1)));
$bin2_ints = array_reverse(array_values(unpack('N*', $bin2)));
$return = array();
$carries = 0;
for ($i=0; $i < max(count($bin1_ints), count($bin2_ints)); $i++) {
$int1 = array_key_exists($i, $bin1_ints) ? $bin1_ints[$i] : 0;
$int2 = array_key_exists($i, $bin2_ints) ? $bin2_ints[$i] : 0;
$val = $int1 + $int2 + $carries;
if ($carries > 0) {
$carries = 0;
}
if ($val >= 0x100000000) {
$val -= 0x100000000;
$carries++;
}
$return[] = $val;
}
if ($carries) {
$return[] += $carries;
}
$return = array_reverse($return);
array_unshift($return, 'N*');
$return = call_user_func_array('pack', $return);
$return = ltrim($return, "\x00");
return strlen($return) == 0 ? "\x00" : $return;
}
/**
* Convert binary string to the 10101's representation.
*
* @param string $string
* @return string
*/
public static function bin2str($string) {
$return = '';
for ($i = 0; $i < strlen($string); $i++) {
$return .= str_pad(decbin(ord($string[$i])), 8, '0', STR_PAD_LEFT);
}
$return = ltrim($return, '0');
return strlen($return) == 0 ? '0' : $return;
}
/**
* Convert 10101's representation back to the binary data.
*
* @param string $string
* @return string
*/
public static function str2bin($string) {
if (strlen($string) % 32 > 0) {
$string = str_repeat('0', 32 - (strlen($string) % 32)) . $string;
}
$ints = str_split($string, 32);
$return = '';
foreach ($ints as $int) {
$return .= pack('N', bindec($int));
}
$return = ltrim($return, "\0");
return strlen($return) == 0 ? "\0" : $return;
}
}

View File

@@ -0,0 +1,65 @@
<?php
class wfHelperString {
/**
* cycle through arguments
*
* @return mixed
*/
public static function cycle() {
static $counter = 0;
$args = func_get_args();
if (empty($args)) {
$counter = 0;
return null;
}
$return_val = $args[$counter % count($args)];
$counter++;
return $return_val;
}
public static function plainTextTable($table) {
if (count($table) === 0) {
return '';
}
$colLengths = array();
for ($row = 0; $row < count($table); $row++) {
for ($col = 0; $col < count($table[$row]); $col++) {
foreach (explode("\n", $table[$row][$col]) as $colText) {
if (!isset($colLengths[$col])) {
$colLengths[$col] = strlen($colText);
continue;
}
$len = strlen($colText);
if ($len > $colLengths[$col]) {
$colLengths[$col] = $len;
}
}
}
}
$hr = str_repeat('-', array_sum($colLengths) + (count($colLengths) * 3) + 1);
$output = $hr . "\n";
for ($row = 0; $row < count($table); $row++) {
$colHeight = 0;
for ($col = 0; $col < count($table[$row]); $col++) {
$height = substr_count($table[$row][$col], "\n");
if ($height > $colHeight) {
$colHeight = $height;
}
}
for ($colRow = 0; $colRow <= $colHeight; $colRow++) {
for ($col = 0; $col < count($table[$row]); $col++) {
$colRows = explode("\n", $table[$row][$col]);
$output .= '| ' . str_pad(isset($colRows[$colRow]) ? $colRows[$colRow] : '', $colLengths[$col], ' ', STR_PAD_RIGHT) . ' ';
}
$output .= "|\n";
}
if ($row === 0) {
$output .= $hr . "\n";
}
}
return trim($output . (count($table) > 1 ? $hr : ''));
}
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* Addresses should be in human readable format as a single IP (e.g. 1.2.3.4) or CIDR (e.g. 1.2.3.4/32)
*/
$wfIPWhitelist = array(
'private' => array(
//We've modified this and removed some addresses which may be routable on the Net and cause auto-whitelisting.
//'0.0.0.0/8', #Broadcast addr
'10.0.0.0/8', #Private addrs
//'100.64.0.0/10', #carrier-grade-nat for comms between ISP and subscribers
'127.0.0.0/8', #loopback
//'169.254.0.0/16', #link-local when DHCP fails e.g. os x
'172.16.0.0/12', #private addrs
'192.0.0.0/29', #used for NAT with IPv6, so basically a private addr
//'192.0.2.0/24', #Only for use in docs and examples, not for public use
//'192.88.99.0/24', #Used by 6to4 anycast relays
'192.168.0.0/16', #Used for local communications within a private network
//'198.18.0.0/15', #Used for testing of inter-network communications between two separate subnets
//'198.51.100.0/24', #Assigned as "TEST-NET-2" in RFC 5737 for use solely in documentation and example source code and should not be used publicly.
//'203.0.113.0/24', #Assigned as "TEST-NET-3" in RFC 5737 for use solely in documentation and example source code and should not be used publicly.
//'224.0.0.0/4', #Reserved for multicast assignments as specified in RFC 5771
//'240.0.0.0/4', #Reserved for future use, as specified by RFC 6890
//'255.255.255.255/32', #Reserved for the "limited broadcast" destination address, as specified by RFC 6890
),
'wordfence' => array(
'54.68.32.247', // Central @ AWS
'44.235.211.232',
'54.71.203.174'
),
);

View File

@@ -0,0 +1,117 @@
<?php
class wfImportExportController {
/**
* Returns the singleton wfImportExportController.
*
* @return wfImportExportController
*/
public static function shared() {
static $_shared = null;
if ($_shared === null) {
$_shared = new wfImportExportController();
}
return $_shared;
}
public function export() {
$export = array();
//Basic Options
$keys = wfConfig::getExportableOptionsKeys();
foreach ($keys as $key) {
$export[$key] = wfConfig::get($key, '');
}
//Serialized Options
$export['scanSched'] = wfConfig::get_ser('scanSched', array());
//Table-based Options
$export['blocks'] = wfBlock::exportBlocks();
//Make the API call
try {
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
$res = $api->call('export_options', array(), array('export' => json_encode($export)));
if ($res['ok'] && $res['token']) {
return array(
'ok' => 1,
'token' => $res['token'],
);
}
else if ($res['err']) {
return array('err' => __("An error occurred: ", 'wordfence') . $res['err']);
}
else {
throw new Exception(__("Invalid response: ", 'wordfence') . var_export($res, true));
}
}
catch (Exception $e) {
return array('err' => __("An error occurred: ", 'wordfence') . $e->getMessage());
}
}
public function import($token) {
try {
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
$res = $api->call('import_options', array(), array('token' => $token));
if ($res['ok'] && $res['export']) {
$totalSet = 0;
$import = @json_decode($res['export'], true);
if (!is_array($import)) {
return array('err' => __("An error occurred: Invalid options format received.", 'wordfence'));
}
//Basic Options
$keys = wfConfig::getExportableOptionsKeys();
$toSet = array();
foreach ($keys as $key) {
if (isset($import[$key])) {
$toSet[$key] = $import[$key];
}
}
if (count($toSet)) {
$validation = wfConfig::validate($toSet);
$skipped = array();
if ($validation !== true) {
foreach ($validation as $error) {
$skipped[$error['option']] = $error['error'];
unset($toSet[$error['option']]);
}
}
$totalSet += count($toSet);
wfConfig::save(wfConfig::clean($toSet));
}
//Serialized Options
if (isset($import['scanSched']) && is_array($import['scanSched'])) {
wfConfig::set_ser('scanSched', $import['scanSched']);
wfScanner::shared()->scheduleScans();
$totalSet++;
}
//Table-based Options
if (isset($import['blocks']) && is_array($import['blocks'])) {
wfBlock::importBlocks($import['blocks']);
$totalSet += count($import['blocks']);
}
return array(
'ok' => 1,
'totalSet' => $totalSet,
);
}
else if ($res['err']) {
return array('err' => sprintf(/* translators: Error message. */ __("An error occurred: %s", 'wordfence'), $res['err']));
}
else {
throw new Exception(sprintf(/* translators: Error message. */ __("Invalid response: %s", 'wordfence'), var_export($res, true)));
}
}
catch (Exception $e) {
return array('err' => sprintf(/* translators: Error message. */ __("An error occurred: %s", 'wordfence'), $e->getMessage()));
}
}
}

View File

@@ -0,0 +1,16 @@
<?php
class wfInaccessibleDirectoryException extends RuntimeException {
private $directory;
public function __construct($message, $directory) {
parent::__construct("{$message}: {$directory}");
$this->directory = $directory;
}
public function getDirectory() {
return $this->directory;
}
}

View File

@@ -0,0 +1,16 @@
<?php
class wfInvalidPathException extends RuntimeException {
private $path;
public function __construct($message, $path) {
parent::__construct("{$message} for path {$path}");
$this->path = $path;
}
public function getPath() {
return $this->path;
}
}

View File

@@ -0,0 +1,65 @@
<?php
class wfIpLocation {
const LANGUAGE_DEFAULT = 'en';
const LANGUAGE_SEPARATOR = '_';
private $record;
public function __construct($record) {
$this->record = is_array($record) ? $record : array();
}
public function getCountryRecord() {
if (array_key_exists('country', $this->record)) {
$country = $this->record['country'];
if (is_array($country))
return $country;
}
return array();
}
public function getCountryField($field) {
$country = $this->getCountryRecord();
if (array_key_exists($field, $country))
return $country[$field];
return null;
}
public function getCountryCode() {
$isoCode = $this->getCountryField('iso_code');
if (is_string($isoCode) && strlen($isoCode) === 2)
return $isoCode;
return null;
}
private function findBestLanguageMatch($options, $preferredLanguage = self::LANGUAGE_DEFAULT) {
$languages = array();
if (is_string($preferredLanguage))
$languages[] = $preferredLanguage;
if (strpos($preferredLanguage, self::LANGUAGE_SEPARATOR) !== false) {
$components = explode(self::LANGUAGE_SEPARATOR, $preferredLanguage);
$baseLanguage = $components[0];
if ($baseLanguage !== self::LANGUAGE_DEFAULT)
$languages[] = $baseLanguage;
}
if ($preferredLanguage !== self::LANGUAGE_DEFAULT)
$languages[] = self::LANGUAGE_DEFAULT;
foreach ($languages as $language) {
if (array_key_exists($language, $options))
return $options[$language];
}
if (!empty($options))
return reset($options);
return null;
}
public function getCountryName($preferredLanguage = self::LANGUAGE_DEFAULT) {
$names = $this->getCountryField('names');
if (is_array($names) && !empty($names))
return $this->findBestLanguageMatch($names, $preferredLanguage);
return null;
}
}

View File

@@ -0,0 +1,110 @@
<?php
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/wfIpLocation.php';
use Wordfence\MmdbReader\Database;
use Wordfence\MmdbReader\Exception\MmdbThrowable;
class wfIpLocator {
const SOURCE_BUNDLED = 0;
const SOURCE_WFLOGS = 1;
const DATABASE_FILE_NAME = 'GeoLite2-Country.mmdb';
private static $instances = array();
private $database;
private $preferred;
private function __construct($database, $preferred) {
$this->database = $database;
$this->preferred = $preferred;
}
public function isPreferred() {
return $this->preferred;
}
private static function logError($message) {
if (class_exists('wfUtils'))
wfUtils::check_and_log_last_error('ip_locator', 'IP Location Error:', $message, 0);
}
public function locate($ip) {
if ($this->database !== null) {
try {
$record = $this->database->search($ip);
if ($record !== null)
return new wfIpLocation($record);
}
catch (MmdbThrowable $t) {
self::logError('Failed to locate IP address: ' . $t->getMessage());
}
}
return null;
}
public function getCountryCode($ip, $default = '') {
$record = $this->locate($ip);
if ($record !== null)
return $record->getCountryCode();
return $default;
}
public function getDatabaseVersion() {
if ($this->database !== null) {
try {
return $this->database->getMetadata()->getBuildEpoch();
}
catch (MmdbThrowable $t) {
self::logError('Failed to retrieve database version: ' . $t->getMessage());
}
}
return null;
}
private static function getDatabaseDirectory($source) {
switch ($source) {
case self::SOURCE_BUNDLED:
return WFWAF_LOG_PATH;
case self::SOURCE_BUNDLED:
default:
return __DIR__;
}
}
private static function initializeDatabase($preferredSource, &$isPreferred) {
$sources = array();
if ($preferredSource !== self::SOURCE_BUNDLED)
$sources[] = $preferredSource;
$sources[] = self::SOURCE_BUNDLED;
$isPreferred = true;
foreach ($sources as $source) {
$directory = self::getDatabaseDirectory($source);
try {
$path = $directory . '/' . self::DATABASE_FILE_NAME;
if (file_exists($path)) //Preemptive check to prevent warnings
return Database::open($path);
}
catch (MmdbThrowable $t) {
self::logError('Failed to initialize IP location database: ' . $t->getMessage());
}
$preferred = false;
}
return null;
}
public static function getInstance($preferredSource = null) {
if ($preferredSource === null)
$preferredSource = self::SOURCE_WFLOGS;
if (!array_key_exists($preferredSource, self::$instances)) {
$database = self::initializeDatabase($preferredSource, $isPreferred);
self::$instances[$preferredSource] = new wfIpLocator($database, $isPreferred);
}
return self::$instances[$preferredSource];
}
}

View File

@@ -0,0 +1,771 @@
<?php
require_once(dirname(__FILE__) . '/wfUtils.php');
class wfIssues {
//Possible responses from `addIssue`
const ISSUE_ADDED = 'a';
const ISSUE_UPDATED = 'u';
const ISSUE_DUPLICATE = 'd';
const ISSUE_IGNOREP = 'ip';
const ISSUE_IGNOREC = 'ic';
//Possible status message states
const STATUS_NONE = 'n'; //Default state before running
const STATUS_SKIPPED = 's'; //The scan job was skipped because it didn't need to run
const STATUS_IGNORED = 'i'; //The scan job found an issue, but it matched an entry in the ignore list
const STATUS_PROBLEM = 'p'; //The scan job found an issue
const STATUS_SECURE = 'r'; //The scan job found no issues
const STATUS_FAILED = 'f'; //The scan job failed
const STATUS_SUCCESS = 'c'; //The scan job succeeded
const STATUS_PAIDONLY = 'x';
//Possible scan failure types
const SCAN_FAILED_GENERAL = 'general';
const SCAN_FAILED_TIMEOUT = 'timeout';
const SCAN_FAILED_DURATION_REACHED = 'duration';
const SCAN_FAILED_VERSION_CHANGE = 'versionchange';
const SCAN_FAILED_FORK_FAILED = 'forkfailed';
const SCAN_FAILED_CALLBACK_TEST_FAILED = 'callbackfailed';
const SCAN_FAILED_START_TIMEOUT = 'starttimeout';
const SCAN_FAILED_API_SSL_UNAVAILABLE = 'sslunavailable';
const SCAN_FAILED_API_CALL_FAILED = 'apifailed';
const SCAN_FAILED_API_INVALID_RESPONSE = 'apiinvalid';
const SCAN_FAILED_API_ERROR_RESPONSE = 'apierror';
const SEVERITY_NONE = 0;
const SEVERITY_LOW = 25;
const SEVERITY_MEDIUM = 50;
const SEVERITY_HIGH = 75;
const SEVERITY_CRITICAL = 100;
private $db = false;
//Properties that are serialized on sleep:
private $updateCalled = false;
private $issuesTable = '';
private $pendingIssuesTable = '';
private $maxIssues = 0;
private $newIssues = array();
public $totalIssues = 0;
public $totalIgnoredIssues = 0;
private $totalIssuesBySeverity = array();
public static $issueSeverities = array(
'checkGSB' => wfIssues::SEVERITY_CRITICAL,
'checkSpamIP' => wfIssues::SEVERITY_HIGH,
'spamvertizeCheck' => wfIssues::SEVERITY_CRITICAL,
'commentBadURL' => wfIssues::SEVERITY_LOW,
'postBadTitle' => wfIssues::SEVERITY_HIGH,
'postBadURL' => wfIssues::SEVERITY_HIGH,
'file' => wfIssues::SEVERITY_CRITICAL,
'timelimit' => wfIssues::SEVERITY_HIGH,
'checkHowGetIPs' => wfIssues::SEVERITY_HIGH,
'diskSpace' => wfIssues::SEVERITY_HIGH,
'wafStatus' => wfIssues::SEVERITY_CRITICAL,
'configReadable' => wfIssues::SEVERITY_CRITICAL,
'wfPluginVulnerable' => wfIssues::SEVERITY_HIGH,
'coreUnknown' => wfIssues::SEVERITY_HIGH,
'easyPasswordWeak' => wfIssues::SEVERITY_HIGH,
'knownfile' => wfIssues::SEVERITY_HIGH,
'optionBadURL' => wfIssues::SEVERITY_HIGH,
'publiclyAccessible' => wfIssues::SEVERITY_HIGH,
'suspiciousAdminUsers' => wfIssues::SEVERITY_HIGH,
'wfPluginAbandoned' => wfIssues::SEVERITY_MEDIUM,
'wfPluginRemoved' => wfIssues::SEVERITY_CRITICAL,
'wfPluginUpgrade' => wfIssues::SEVERITY_MEDIUM,
'wfThemeUpgrade' => wfIssues::SEVERITY_MEDIUM,
'wfUpgradeError' => wfIssues::SEVERITY_MEDIUM,
'wfUpgrade' => wfIssues::SEVERITY_HIGH,
'wpscan_directoryList' => wfIssues::SEVERITY_HIGH,
'wpscan_fullPathDiscl' => wfIssues::SEVERITY_HIGH,
);
public static function validIssueTypes() {
return array('checkHowGetIPs', 'checkSpamIP', 'commentBadURL', 'configReadable', 'coreUnknown', 'database', 'diskSpace', 'wafStatus', 'easyPassword', 'file', 'geoipSupport', 'knownfile', 'optionBadURL', 'postBadTitle', 'postBadURL', 'publiclyAccessible', 'spamvertizeCheck', 'suspiciousAdminUsers', 'timelimit', 'wfPluginAbandoned', 'wfPluginRemoved', 'wfPluginUpgrade', 'wfPluginVulnerable', 'wfThemeUpgrade', 'wfUpgradeError', 'wfUpgrade', 'wpscan_directoryList', 'wpscan_fullPathDiscl', 'skippedPaths');
}
public static function statusPrep(){
wfConfig::set_ser('wfStatusStartMsgs', array());
wordfence::status(10, 'info', "SUM_PREP:Preparing a new scan.");
wfIssues::updateScanStillRunning();
}
public static function statusStart($message) {
$statusStartMsgs = wfConfig::get_ser('wfStatusStartMsgs', array());
$statusStartMsgs[] = $message;
wfConfig::set_ser('wfStatusStartMsgs', $statusStartMsgs);
wordfence::status(10, 'info', 'SUM_START:' . $message);
wfIssues::updateScanStillRunning();
return count($statusStartMsgs) - 1;
}
public static function statusEnd($index, $state) {
$statusStartMsgs = wfConfig::get_ser('wfStatusStartMsgs', array());
if ($state == self::STATUS_SKIPPED) {
wordfence::status(10, 'info', 'SUM_ENDSKIPPED:' . $statusStartMsgs[$index]);
}
else if ($state == self::STATUS_IGNORED) {
wordfence::status(10, 'info', 'SUM_ENDIGNORED:' . $statusStartMsgs[$index]);
}
else if ($state == self::STATUS_PROBLEM) {
wordfence::status(10, 'info', 'SUM_ENDBAD:' . $statusStartMsgs[$index]);
}
else if ($state == self::STATUS_SECURE) {
wordfence::status(10, 'info', 'SUM_ENDOK:' . $statusStartMsgs[$index]);
}
else if ($state == self::STATUS_FAILED) {
wordfence::status(10, 'info', 'SUM_ENDFAILED:' . $statusStartMsgs[$index]);
}
else if ($state == self::STATUS_SUCCESS) {
wordfence::status(10, 'info', 'SUM_ENDSUCCESS:' . $statusStartMsgs[$index]);
}
wfIssues::updateScanStillRunning();
$statusStartMsgs[$index] = '';
wfConfig::set_ser('wfStatusStartMsgs', $statusStartMsgs);
}
public static function statusEndErr() {
$statusStartMsgs = wfConfig::get_ser('wfStatusStartMsgs', array());
for ($i = 0; $i < count($statusStartMsgs); $i++) {
if (empty($statusStartMsgs[$i]) === false) {
wordfence::status(10, 'info', 'SUM_ENDERR:' . $statusStartMsgs[$i]);
$statusStartMsgs[$i] = '';
}
}
wfIssues::updateScanStillRunning();
}
public static function statusPaidOnly($message) {
wordfence::status(10, 'info', "SUM_PAIDONLY:" . $message);
wfIssues::updateScanStillRunning();
}
public static function statusDisabled($message) {
wordfence::status(10, 'info', "SUM_DISABLED:" . $message);
wfIssues::updateScanStillRunning();
}
public static function updateScanStillRunning($running = true) {
$timestamp = time();
if (!$running) {
$timestamp = 0;
}
wfConfig::set('wf_scanLastStatusTime', $timestamp);
}
/**
* Returns false if the scan has not been detected as failed. If it has, returns a constant corresponding to the reason.
*
* @return bool|string
*/
public static function hasScanFailed() {
$lastStatusUpdate = self::lastScanStatusUpdate();
if ($lastStatusUpdate !== false && wfScanner::shared()->isRunning()) {
$threshold = WORDFENCE_SCAN_FAILURE_THRESHOLD;
if (time() - $lastStatusUpdate > $threshold) {
return self::SCAN_FAILED_TIMEOUT;
}
}
$scanStartAttempt = wfConfig::get('scanStartAttempt', 0);
if ($scanStartAttempt && time() - $scanStartAttempt > WORDFENCE_SCAN_START_FAILURE_THRESHOLD) {
return self::SCAN_FAILED_START_TIMEOUT;
}
$recordedFailure = wfConfig::get('lastScanFailureType');
switch ($recordedFailure) {
case self::SCAN_FAILED_GENERAL:
case self::SCAN_FAILED_DURATION_REACHED:
case self::SCAN_FAILED_VERSION_CHANGE:
case self::SCAN_FAILED_FORK_FAILED:
case self::SCAN_FAILED_CALLBACK_TEST_FAILED:
case self::SCAN_FAILED_API_SSL_UNAVAILABLE:
case self::SCAN_FAILED_API_CALL_FAILED:
case self::SCAN_FAILED_API_INVALID_RESPONSE:
case self::SCAN_FAILED_API_ERROR_RESPONSE:
return $recordedFailure;
}
return false;
}
/**
* Returns false if the scan has not been detected as timed out. If it has, it returns the timestamp of the last status update.
*
* @return bool|int
*/
public static function lastScanStatusUpdate() {
if (wfConfig::get('wf_scanLastStatusTime', 0) === 0) {
return false;
}
$threshold = WORDFENCE_SCAN_FAILURE_THRESHOLD;
return (time() > wfConfig::get('wf_scanLastStatusTime', 0) + $threshold) ? wfConfig::get('wf_scanLastStatusTime', 0) : false;
}
/**
* Returns the singleton wfIssues.
*
* @return wfIssues
*/
public static function shared() {
static $_issues = null;
if ($_issues === null) {
$_issues = new wfIssues();
}
return $_issues;
}
public function __sleep(){ //Same order here as vars above
return array('updateCalled', 'issuesTable', 'pendingIssuesTable', 'maxIssues', 'newIssues', 'totalIssues', 'totalIgnoredIssues', 'totalIssuesBySeverity');
}
public function __construct(){
$this->issuesTable = wfDB::networkTable('wfIssues');
$this->pendingIssuesTable = wfDB::networkTable('wfPendingIssues');
$this->maxIssues = wfConfig::get('scan_maxIssues', 0);
}
public function __wakeup(){
$this->db = new wfDB();
}
public function addIssue($type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData, $alreadyHashed = false) {
return $this->_addIssue('issue', $type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData, $alreadyHashed);
}
public function addPendingIssue($type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData) {
return $this->_addIssue('pending', $type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData);
}
/**
* Create a new issue
*
* @param string $group The issue type (e.g., issue or pending
* @param string $type
* @param int $severity
* @param string $ignoreP string to compare against for permanent ignores
* @param string $ignoreC string to compare against for ignoring until something changes
* @param string $shortMsg
* @param string $longMsg
* @param array $templateData
* @param bool $alreadyHashed If true, don't re-hash $ignoreP and $ignoreC
* @return string One of the ISSUE_ constants
*/
private function _addIssue($group, $type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData, $alreadyHashed = false) {
if ($group == 'pending') {
$table = $this->pendingIssuesTable;
}
else {
$table = $this->issuesTable;
}
if (!$alreadyHashed) {
$ignoreP = md5($ignoreP);
$ignoreC = md5($ignoreC);
}
$results = $this->getDB()->querySelect("SELECT id, status, ignoreP, ignoreC FROM {$table} WHERE (ignoreP = '%s' OR ignoreC = '%s')", $ignoreP, $ignoreC);
foreach ($results as $row) {
if ($row['status'] == 'new' && ($row['ignoreC'] == $ignoreC || $row['ignoreP'] == $ignoreP)) {
if ($type != 'file' && $type != 'database') { //Filter out duplicate new issues except for infected files because we want to see all infections even if file contents are identical
return self::ISSUE_DUPLICATE;
}
}
if ($row['status'] == 'ignoreP' && $row['ignoreP'] == $ignoreP) { $this->totalIgnoredIssues++; return self::ISSUE_IGNOREP; } //Always ignore
else if ($row['status'] == 'ignoreC' && $row['ignoreC'] == $ignoreC) { $this->totalIgnoredIssues++; return self::ISSUE_IGNOREC; } //Unchanged, ignore
else if ($row['status'] == 'ignoreC') {
$updateID = $row['id']; //Re-use the existing issue row
break;
}
}
if ($group != 'pending') {
if (!array_key_exists($severity, $this->totalIssuesBySeverity)) {
$this->totalIssuesBySeverity[$severity] = 0;
}
$this->totalIssuesBySeverity[$severity]++;
$this->totalIssues++;
if (empty($this->maxIssues) || $this->totalIssues <= $this->maxIssues)
{
$this->newIssues[] = array(
'type' => $type,
'severity' => $severity,
'ignoreP' => $ignoreP,
'ignoreC' => $ignoreC,
'shortMsg' => $shortMsg,
'longMsg' => $longMsg,
'tmplData' => $templateData
);
}
}
if (isset($updateID)) {
if ($group !== 'pending' && wfCentral::isConnected()) {
wfCentral::sendIssue(array(
'id' => $updateID,
'lastUpdated' => time(),
'type' => $type,
'severity' => $severity,
'ignoreP' => $ignoreP,
'ignoreC' => $ignoreC,
'shortMsg' => $shortMsg,
'longMsg' => $longMsg,
'data' => $templateData,
));
}
$this->getDB()->queryWrite(
"UPDATE {$table} SET lastUpdated = UNIX_TIMESTAMP(), status = '%s', type = '%s', severity = %d, ignoreP = '%s', ignoreC = '%s', shortMsg = '%s', longMsg = '%s', data = '%s' WHERE id = %d",
'new',
$type,
$severity,
$ignoreP,
$ignoreC,
$shortMsg,
$longMsg,
serialize($templateData),
$updateID);
return self::ISSUE_UPDATED;
}
$this->getDB()->queryWrite("INSERT INTO {$table} (time, lastUpdated, status, type, severity, ignoreP, ignoreC, shortMsg, longMsg, data) VALUES (UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s')",
'new',
$type,
$severity,
$ignoreP,
$ignoreC,
$shortMsg,
$longMsg,
serialize($templateData));
if ($group !== 'pending' && wfCentral::isConnected()) {
global $wpdb;
wfCentral::sendIssue(array(
'id' => $wpdb->insert_id,
'status' => 'new',
'time' => time(),
'lastUpdated' => time(),
'type' => $type,
'severity' => $severity,
'ignoreP' => $ignoreP,
'ignoreC' => $ignoreC,
'shortMsg' => $shortMsg,
'longMsg' => $longMsg,
'data' => $templateData,
));
}
return self::ISSUE_ADDED;
}
public function deleteIgnored(){
if (wfCentral::isConnected()) {
$result = $this->getDB()->querySelect("SELECT id from " . $this->issuesTable . " where status='ignoreP' or status='ignoreC'");
$issues = array();
foreach ($result as $row) {
$issues[] = $row['id'];
}
wfCentral::deleteIssues($issues);
}
$this->getDB()->queryWrite("delete from " . $this->issuesTable . " where status='ignoreP' or status='ignoreC'");
}
public function deleteNew($types = null) {
if (!is_array($types)) {
if (wfCentral::isConnected()) {
wfCentral::deleteNewIssues();
}
$this->getDB()->queryWrite("DELETE FROM {$this->issuesTable} WHERE status = 'new'");
}
else {
if (wfCentral::isConnected()) {
wfCentral::deleteIssueTypes($types, 'new');
}
$query = "DELETE FROM {$this->issuesTable} WHERE status = 'new' AND type IN (" . implode(',', array_fill(0, count($types), "'%s'")) . ")";
array_unshift($types, $query);
call_user_func_array(array($this->getDB(), 'queryWrite'), $types);
}
}
public function ignoreAllNew(){
if (wfCentral::isConnected()) {
$issues = $this->getDB()->querySelect('SELECT * FROM ' . $this->issuesTable . ' WHERE status=\'new\'');
if ($issues) {
wfCentral::sendIssues($issues);
}
}
$this->getDB()->queryWrite("update " . $this->issuesTable . " set status='ignoreC' where status='new'");
}
public function emailNewIssues($timeLimitReached = false, $scanController = false){
$level = wfConfig::getAlertLevel();
$emails = wfConfig::getAlertEmails();
if (!count($emails)) {
return;
}
$shortSiteURL = preg_replace('/^https?:\/\//i', '', site_url());
$subject = "[Wordfence Alert] Problems found on $shortSiteURL";
if(sizeof($emails) < 1){ return; }
if($level < 1){ return; }
$needsToAlert = false;
foreach ($this->totalIssuesBySeverity as $issueSeverity => $totalIssuesBySeverity) {
if ($issueSeverity >= $level && $totalIssuesBySeverity > 0) {
$needsToAlert = true;
break;
}
}
if (!$needsToAlert) {
return;
}
$emailedIssues = wfConfig::get_ser('emailedIssuesList', array());
if(! is_array($emailedIssues)){
$emailedIssues = array();
}
$overflowCount = $this->totalIssues - count($this->newIssues);
$finalIssues = array();
$previousIssues = array();
foreach($this->newIssues as $newIssue){
$alreadyEmailed = false;
foreach($emailedIssues as $emailedIssue){
if($newIssue['ignoreP'] == $emailedIssue['ignoreP'] || $newIssue['ignoreC'] == $emailedIssue['ignoreC']){
$alreadyEmailed = true;
$previousIssues[] = $newIssue;
break;
}
}
if(! $alreadyEmailed){
$finalIssues[] = $newIssue;
}
else {
$overflowCount--;
}
}
if(sizeof($finalIssues) < 1){ return; }
$this->newIssues = array();
$this->totalIssues = 0;
$totals = array();
foreach($finalIssues as $i){
$emailedIssues[] = array( 'ignoreC' => $i['ignoreC'], 'ignoreP' => $i['ignoreP'] );
if (!array_key_exists($i['severity'], $totals)) {
$totals[$i['severity']] = 0;
}
$totals[$i['severity']]++;
}
wfConfig::set_ser('emailedIssuesList', $emailedIssues);
$needsToAlert = false;
foreach ($totals as $issueSeverity => $totalIssuesBySeverity) {
if ($issueSeverity >= $level && $totalIssuesBySeverity > 0) {
$needsToAlert = true;
break;
}
}
if (!$needsToAlert) {
return;
}
$content = wfUtils::tmpl('email_newIssues.php', array(
'isPaid' => wfConfig::get('isPaid'),
'issues' => $finalIssues,
'previousIssues' => $previousIssues,
'totals' => $totals,
'level' => $level,
'issuesNotShown' => $overflowCount,
'adminURL' => get_admin_url(),
'timeLimitReached' => $timeLimitReached,
'scanController' => ($scanController ? $scanController : wfScanner::shared()),
));
foreach ($emails as $email) {
$uniqueContent = str_replace('<!-- ##UNSUBSCRIBE## -->', wp_kses(sprintf(__('No longer an administrator for this site? <a href="%s" target="_blank">Click here</a> to stop receiving security alerts.', 'wordfence'), wfUtils::getSiteBaseURL() . '?_wfsf=removeAlertEmail&jwt=' . wfUtils::generateJWT(array('email' => $email))), array('a'=>array('href'=>array(), 'target'=>array()))), $content);
wp_mail($email, $subject, $uniqueContent, 'Content-type: text/html');
}
}
public function clearEmailedStatus($issues) {
if (empty($issues)) { return; }
$emailed_issues = wfConfig::get_ser('emailedIssuesList', array());
if (!is_array($emailed_issues)) { return; }
$updated = array();
foreach ($emailed_issues as $ei) {
$cleared = false;
foreach ($issues as $issue) {
if ($issue['ignoreP'] == $ei['ignoreP'] || $issue['ignoreC'] == $ei['ignoreC']) {
//Discard this one
$cleared = true;
}
}
if (!$cleared) {
$updated[] = $ei;
}
}
wfConfig::set_ser('emailedIssuesList', $updated);
}
public function deleteIssue($id){
$this->clearEmailedStatus(array($this->getIssueByID($id)));
$this->getDB()->queryWrite("delete from " . $this->issuesTable . " where id=%d", $id);
if (wfCentral::isConnected()) {
wfCentral::deleteIssue($id);
}
}
public function deleteUpdateIssues($type) {
$issues = $this->getDB()->querySelect("SELECT id, status, ignoreP, ignoreC FROM {$this->issuesTable} WHERE status = 'new' AND type = '%s'", $type);
$this->clearEmailedStatus($issues);
$this->getDB()->queryWrite("DELETE FROM {$this->issuesTable} WHERE status = 'new' AND type = '%s'", $type);
if (wfCentral::isConnected()) {
wfCentral::deleteIssueTypes(array($type));
}
}
public function deleteAllUpdateIssues() {
$issues = $this->getDB()->querySelect("SELECT id, status, ignoreP, ignoreC FROM {$this->issuesTable} WHERE status = 'new' AND (type = 'wfUpgrade' OR type = 'wfUpgradeError' OR type = 'wfPluginUpgrade' OR type = 'wfThemeUpgrade')");
$this->clearEmailedStatus($issues);
$this->getDB()->queryWrite("DELETE FROM {$this->issuesTable} WHERE status = 'new' AND (type = 'wfUpgrade' OR type = 'wfUpgradeError' OR type = 'wfPluginUpgrade' OR type = 'wfThemeUpgrade')");
if (wfCentral::isConnected()) {
wfCentral::deleteIssueTypes(array('wfUpgrade', 'wfUpgradeError', 'wfPluginUpgrade', 'wfThemeUpgrade'));
}
}
public function updateIssue($id, $status){ //ignoreC, ignoreP, delete or new
if($status == 'delete'){
if (wfCentral::isConnected()) {
wfCentral::deleteIssue($id);
}
$this->clearEmailedStatus(array($this->getIssueByID($id)));
$this->getDB()->queryWrite("delete from " . $this->issuesTable . " where id=%d", $id);
} else if($status == 'ignoreC' || $status == 'ignoreP' || $status == 'new'){
$this->getDB()->queryWrite("update " . $this->issuesTable . " set status='%s' where id=%d", $status, $id);
if (wfCentral::isConnected()) {
$issue = $this->getDB()->querySelect('SELECT * FROM ' . $this->issuesTable . ' where id=%d', $id);
if ($issue) {
wfCentral::sendIssues($issue);
}
}
}
}
public function getIssueByID($id) {
$rec = $this->getDB()->querySingleRec("select * from " . $this->issuesTable . " where id=%d", $id);
$rec['data'] = unserialize($rec['data']);
return $rec;
}
public function getIssueCounts() {
global $wpdb;
$counts = $wpdb->get_results('SELECT COUNT(*) AS c, status FROM ' . $this->issuesTable . ' WHERE status = "new" OR status = "ignoreP" OR status = "ignoreC" GROUP BY status', ARRAY_A);
$result = array();
foreach ($counts as $row) {
$result[$row['status']] = $row['c'];
}
return $result;
}
public function getIssues($offset = 0, $limit = 100, $ignoredOffset = 0, $ignoredLimit = 100) {
/** @var wpdb $wpdb */
global $wpdb;
$siteCleaningTypes = array('file', 'checkGSB', 'checkSpamIP', 'commentBadURL', 'knownfile', 'optionBadURL', 'postBadTitle', 'postBadURL', 'spamvertizeCheck', 'suspiciousAdminUsers');
$sortTagging = 'CASE';
foreach ($siteCleaningTypes as $index => $t) {
$sortTagging .= ' WHEN type = \'' . esc_sql($t) . '\' THEN ' . ((int) $index);
}
$sortTagging .= ' ELSE 999 END';
$ret = array(
'new' => array(),
'ignored' => array()
);
$userIni = ini_get('user_ini.filename');
$q1 = $this->getDB()->querySelect("SELECT *, {$sortTagging} AS sortTag FROM " . $this->issuesTable . " WHERE status = 'new' ORDER BY severity DESC, sortTag ASC, type ASC, time DESC LIMIT %d,%d", $offset, $limit);
$q2 = $this->getDB()->querySelect("SELECT *, {$sortTagging} AS sortTag FROM " . $this->issuesTable . " WHERE status = 'ignoreP' OR status = 'ignoreC' ORDER BY severity DESC, sortTag ASC, type ASC, time DESC LIMIT %d,%d", $ignoredOffset, $ignoredLimit);
$q = array_merge($q1, $q2);
foreach($q as $i){
$i['data'] = unserialize($i['data']);
$i['timeAgo'] = wfUtils::makeTimeAgo(time() - $i['time']);
$i['displayTime'] = wfUtils::formatLocalTime(get_option('date_format') . ' ' . get_option('time_format'), $i['time']);
$i['longMsg'] = wp_kses($i['longMsg'], 'post');
if($i['status'] == 'new'){
$ret['new'][] = $i;
} else if($i['status'] == 'ignoreP' || $i['status'] == 'ignoreC'){
$ret['ignored'][] = $i;
} else {
error_log("Issue has bad status: " . $i['status']);
continue;
}
}
foreach($ret as $status => &$issueList){
for($i = 0; $i < sizeof($issueList); $i++){
if ($issueList[$i]['type'] == 'file' || $issueList[$i]['type'] == 'knownfile') {
if (array_key_exists('realFile', $issueList[$i]['data'])) {
$localFile = $issueList[$i]['data']['realFile'];
$issueList[$i]['data']['realFileToken'] = self::generateRealFileToken($localFile);
}
else {
$localFile = $issueList[$i]['data']['file'];
if ($localFile != '.htaccess' && $localFile != $userIni) {
$localFile = ABSPATH . '/' . preg_replace('/^[\.\/]+/', '', $localFile);
}
else {
$localFile = ABSPATH . '/' . $localFile;
}
}
if(file_exists($localFile)){
$issueList[$i]['data']['fileExists'] = true;
} else {
$issueList[$i]['data']['fileExists'] = '';
}
}
if ($issueList[$i]['type'] == 'database') {
$issueList[$i]['data']['optionExists'] = false;
if (!empty($issueList[$i]['data']['site_id'])) {
$table_options = wfDB::blogTable('options', $issueList[$i]['data']['site_id']);
$issueList[$i]['data']['optionExists'] = $wpdb->get_var($wpdb->prepare("SELECT count(*) FROM {$table_options} WHERE option_name = %s", $issueList[$i]['data']['option_name'])) > 0;
}
}
$issueList[$i]['issueIDX'] = $i;
if (isset($issueList[$i]['data']['cType'])) {
$issueList[$i]['data']['ucType'] = ucwords($issueList[$i]['data']['cType']);
}
}
}
return $ret; //array of lists of issues by status
}
public function getPendingIssues($offset = 0, $limit = 100){
/** @var wpdb $wpdb */
global $wpdb;
$issues = $this->getDB()->querySelect("SELECT * FROM {$this->pendingIssuesTable} ORDER BY id ASC LIMIT %d,%d", $offset, $limit);
foreach($issues as &$i){
$i['data'] = unserialize($i['data']);
}
return $issues;
}
public function getFixableIssueCount() {
global $wpdb;
$issues = $this->getDB()->querySelect("SELECT * FROM {$this->issuesTable} WHERE data LIKE '%s:6:\"canFix\";b:1;%'");
$count = 0;
foreach ($issues as $i) {
$i['data'] = unserialize($i['data']);
if (isset($i['data']['canFix']) && $i['data']['canFix']) {
$count++;
}
}
return $count;
}
public function getDeleteableIssueCount() {
global $wpdb;
$issues = $this->getDB()->querySelect("SELECT * FROM {$this->issuesTable} WHERE data LIKE '%s:9:\"canDelete\";b:1;%'");
$count = 0;
foreach ($issues as $i) {
$i['data'] = unserialize($i['data']);
if (isset($i['data']['canDelete']) && $i['data']['canDelete']) {
$count++;
}
}
return $count;
}
public function getIssueCount() {
return (int) $this->getDB()->querySingle("select COUNT(*) from " . $this->issuesTable . " WHERE status = 'new'");
}
public function getPendingIssueCount() {
return (int) $this->getDB()->querySingle("select COUNT(*) from " . $this->pendingIssuesTable . " WHERE status = 'new'");
}
public function getLastIssueUpdateTimestamp() {
return (int) $this->getDB()->querySingle("select MAX(lastUpdated) from " . $this->issuesTable);
}
public function reconcileUpgradeIssues($report = null, $useCachedValued = false) {
if ($report === null) {
$report = new wfActivityReport();
}
$updatesNeeded = $report->getUpdatesNeeded($useCachedValued);
if ($updatesNeeded) {
if (!$updatesNeeded['core']) {
$this->deleteUpdateIssues('wfUpgrade');
}
if ($updatesNeeded['plugins']) {
$upgradeNames = array();
foreach ($updatesNeeded['plugins'] as $p) {
$name = $p['Name'];
$upgradeNames[$name] = 1;
}
$upgradeIssues = $this->getDB()->querySelect("SELECT * FROM {$this->issuesTable} WHERE status = 'new' AND type = 'wfPluginUpgrade'");
foreach ($upgradeIssues as $issue) {
$data = unserialize($issue['data']);
$name = $data['Name'];
if (!isset($upgradeNames[$name])) { //Some plugins don't have a slug associated with them, so we anchor on the name
$this->deleteIssue($issue['id']);
}
}
}
else {
$this->deleteUpdateIssues('wfPluginUpgrade');
}
if ($updatesNeeded['themes']) {
$upgradeNames = array();
foreach ($updatesNeeded['themes'] as $t) {
$name = $t['Name'];
$upgradeNames[$name] = 1;
}
$upgradeIssues = $this->getDB()->querySelect("SELECT * FROM {$this->issuesTable} WHERE status = 'new' AND type = 'wfThemeUpgrade'");
foreach ($upgradeIssues as $issue) {
$data = unserialize($issue['data']);
$name = $data['Name'];
if (!isset($upgradeNames[$name])) { //Some themes don't have a slug associated with them, so we anchor on the name
$this->deleteIssue($issue['id']);
}
}
}
else {
$this->deleteUpdateIssues('wfThemeUpgrade');
}
}
else {
$this->deleteAllUpdateIssues();
}
wfScanEngine::refreshScanNotification($this);
}
private function getDB(){
if(! $this->db){
$this->db = new wfDB();
}
return $this->db;
}
/**
* @return string
*/
public function getIssuesTable() {
return $this->issuesTable;
}
private static function getRealFileTokenKey($realFile) {
return 'wf-real-file-' . base64_encode($realFile);
}
private static function generateRealFileToken($realFile) {
$key = self::getRealFileTokenKey($realFile);
return wp_create_nonce($key);
}
public static function verifyRealFileToken($token, $realFile) {
$key = self::getRealFileTokenKey($realFile);
return wp_verify_nonce($token, $key);
}
}

View File

@@ -0,0 +1,237 @@
<?php
class wfJWT {
private $claims;
const JWT_TTL = 600;
const ISSUER = 600;
public static function extractTokenContents($token) {
if (!is_string($token)) {
throw new InvalidArgumentException('Token is not a string. ' . gettype($token) . ' given.');
}
// Verify the token matches the JWT format.
if (!preg_match('/^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?$/', $token)) {
throw new wfJWTException('Invalid token format.');
}
list($header, $body, $signature) = explode('.', $token);
// Test that the token is valid and not expired.
$decodedHeader = base64_decode($header);
if (!(is_string($decodedHeader) && $decodedHeader)) {
throw new wfJWTException('Token header is invalid.');
}
$header = json_decode($decodedHeader, true);
if (!is_array($header)) {
throw new wfJWTException('Token header is invalid.');
}
$decodedBody = base64_decode($body);
if (!(is_string($decodedBody) && $decodedBody)) {
throw new wfJWTException('Token body is invalid.');
}
$body = json_decode($decodedBody, true);
if (!is_array($body)) {
throw new wfJWTException('Token body is invalid.');
}
return array(
'header' => $header,
'body' => $body,
'signature' => $signature,
);
}
/**
* @param mixed $subject
*/
public function __construct($subject = null) {
$this->claims = $this->getClaimDefaults();
$this->claims['sub'] = $subject;
}
/**
* @return string
*/
public function encode() {
$header = $this->encodeString($this->buildHeader());
$body = $this->encodeString($this->buildBody());
return sprintf('%s.%s.%s', $header, $body,
$this->encodeString($this->sign(sprintf('%s.%s', $header, $body))));
}
/**
* @param string $token
* @return array
* @throws wfJWTException|InvalidArgumentException
*/
public function decode($token) {
if (!is_string($token)) {
throw new InvalidArgumentException('Token is not a string. ' . gettype($token) . ' given.');
}
// Verify the token matches the JWT format.
if (!preg_match('/^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?$/', $token)) {
throw new wfJWTException('Invalid token format.');
}
list($header, $body, $signature) = explode('.', $token);
// Verify signature matches the supplied payload.
if (!$this->verifySignature($this->decodeString($signature), sprintf('%s.%s', $header, $body))) {
throw new wfJWTException('Invalid signature.');
}
// Test that the token is valid and not expired.
$decodedHeader = base64_decode($header);
if (!(is_string($decodedHeader) && $decodedHeader)) {
throw new wfJWTException('Token header is invalid.');
}
$header = json_decode($decodedHeader, true);
if (!(
is_array($header) &&
array_key_exists('alg', $header) &&
$header['alg'] === 'HS256' &&
$header['typ'] === 'JWT'
)) {
throw new wfJWTException('Token header is invalid.');
}
$decodedBody = base64_decode($body);
if (!(is_string($decodedBody) && $decodedBody)) {
throw new wfJWTException('Token body is invalid.');
}
$body = json_decode($decodedBody, true);
if (!(
is_array($body) &&
// Check the token not before now timestamp.
array_key_exists('nbf', $body) &&
is_numeric($body['nbf']) &&
$body['nbf'] <= time() &&
// Check the token is not expired.
array_key_exists('exp', $body) &&
is_numeric($body['exp']) &&
$body['exp'] >= time() &&
// Check the issuer and audience is ours.
$body['iss'] === 'Wordfence ' . WORDFENCE_VERSION &&
$body['aud'] === 'Wordfence Central'
)) {
throw new wfJWTException('Token is invalid or expired.');
}
return array(
'header' => $header,
'body' => $body,
);
}
/**
* @param string $string
* @return string
*/
public function sign($string) {
$salt = wp_salt('auth');
return hash_hmac('sha256', $string, $salt, true);
}
/**
* @param string $signature
* @param string $message
* @return bool
*/
public function verifySignature($signature, $message) {
return hash_equals($this->sign($message), $signature);
}
/**
* @return string
*/
public function __toString() {
return $this->encode();
}
/**
* @param string $data
* @return string
*/
public function encodeString($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
/**
* @param string $data
* @return bool|string
*/
public function decodeString($data) {
return base64_decode(strtr($data, '-_', '+/'));
}
/**
* @return mixed|string
*/
protected function buildHeader() {
return '{"alg":"HS256","typ":"JWT"}';
}
/**
* @return mixed|string
*/
protected function buildBody() {
return json_encode($this->getClaims());
}
/**
* @return array
*/
protected function getClaimDefaults() {
$now = time();
return array(
'iss' => 'Wordfence ' . WORDFENCE_VERSION,
'aud' => 'Wordfence Central',
'nbf' => $now,
'iat' => $now,
'exp' => $now + self::JWT_TTL,
);
}
/**
* @param array $claims
*/
public function addClaims($claims) {
if (!is_array($claims)) {
throw new InvalidArgumentException(__METHOD__ . ' expects argument 1 to be array.');
}
$this->setClaims(array_merge($this->getClaims(), $claims));
}
/**
* @return array
*/
public function getClaims() {
return $this->claims;
}
/**
* @param array $claims
*/
public function setClaims($claims) {
$this->claims = $claims;
}
}
class wfJWTException extends Exception {
}

View File

@@ -0,0 +1,394 @@
<?php
require_once __DIR__ . '/wfWebsite.php';
class wfLicense {
const TYPE_FREE = 'free';
const TYPE_PREMIUM = 'premium';
const TYPE_CARE = 'care';
const TYPE_RESPONSE = 'response';
const KEY_TYPE_FREE = 'free';
const KEY_TYPE_PAID_CURRENT = 'paid-current';
const KEY_TYPE_PAID_EXPIRED = 'paid-expired';
const KEY_TYPE_PAID_DELETED = 'paid-deleted';
const CONFIG_API_KEY = 'apiKey';
const CONFIG_REMAINING_DAYS = 'keyExpDays';
const CONFIG_PAID = 'isPaid';
const CONFIG_KEY_TYPE = 'keyType';
const CONFIG_HAS_KEY_CONFLICT = 'hasKeyConflict';
const CONFIG_TYPE = 'licenseType';
const REGISTRATION_PAYLOAD_VERSION = 1;
private static $TYPES = array(
self::TYPE_FREE,
self::TYPE_PREMIUM,
self::TYPE_CARE,
self::TYPE_RESPONSE
);
private static $reflectionClass = null;
private static $current = null;
private $apiKey;
private $paid;
private $type;
private $remainingDays;
private $conflicting;
private $deleted;
private $keyType;
/**
* @param string $apiKey
* @param bool $paid whether or not this is a paid license
* @param ?string $type the license type (@see self::$TYPES)
* @param int $remainingDays the number of days remaining before the license expires
* (may be negative if already expired)
* @param bool $conflicting whether or not there is a conflict with this license
* @param bool $deleted whether or not the key was deleted
*/
private function __construct($apiKey = null, $paid = null, $type = null, $remainingDays = null, $conflicting = false, $deleted = false, $keyType = null) {
$this->apiKey = $apiKey;
$this->paid = $paid;
$this->setType($type);
$this->remainingDays = $remainingDays;
$this->conflicting = $conflicting;
$this->deleted = $deleted;
$this->keyType = $keyType;
}
public function setApiKey($apiKey) {
$this->apiKey = $apiKey;
return $this;
}
public function getApiKey() {
return $this->apiKey;
}
public function setPaid($paid) {
$this->paid = $paid;
return $this;
}
public function isPaid() {
return $this->paid;
}
public function setType($type) {
$this->type = $type !== null && self::isValidType($type) ? (string) $type : ($this->isPaid() ? self::TYPE_PREMIUM : self::TYPE_FREE);
return $this;
}
public function getType() {
return $this->type === null ? self::TYPE_FREE : $this->type;
}
public function is($type, $orGreater = false) {
return $this->type === $type || ($orGreater && $this->isAtLeast($type));
}
public function setRemainingDays($days) {
$this->remainingDays = (int) $days;
return $this;
}
public function getRemainingDays() {
return $this->remainingDays;
}
public function setConflicting($conflicting = true) {
$this->conflicting = $conflicting;
return $this;
}
public function hasConflict() {
return $this->conflicting;
}
public function setDeleted($deleted = true) {
$this->deleted = $deleted;
return $this;
}
public function isExpired() {
return $this->getKeyType() === self::KEY_TYPE_PAID_EXPIRED;
}
public function isValid() {
return !$this->isExpired();
}
public function isPaidAndCurrent() {
return $this->getKeyType() === self::KEY_TYPE_PAID_CURRENT;
}
private function resolveKeyType() {
if ($this->deleted)
return self::KEY_TYPE_PAID_DELETED;
if ($this->paid) {
if ($this->remainingDays >= 0)
return self::KEY_TYPE_PAID_CURRENT;
else
return self::KEY_TYPE_PAID_EXPIRED;
}
return self::KEY_TYPE_FREE;
}
public function getKeyType() {
if (!$this->keyType)
$this->keyType = $this->resolveKeyType();
return $this->keyType;
}
private function clearCache() {
$this->keyType = null;
}
private function compareTiers($a, $b, $inclusive = true) {
if ($a === $b)
return $inclusive;
foreach (self::$TYPES as $tier) {
if ($tier === $a)
return true;
if ($tier === $b)
return false;
}
return false;
}
/**
* Check if the license type is at or above the given tier
*/
public function isAtLeast($type) {
if ($type !== self::TYPE_FREE && !$this->isValid())
return false;
return $this->compareTiers($type, $this->getType());
}
public function isBelow($type) {
if ($type !== self::TYPE_FREE && !$this->isValid())
return true;
return $this->compareTiers($this->getType(), $type, false);
}
public function isPremium($orGreater = false) {
return $this->is(self::TYPE_PREMIUM, $orGreater);
}
public function isAtLeastPremium() {
return $this->isPremium(true);
}
public function isBelowPremium() {
return $this->isBelow(self::TYPE_PREMIUM);
}
public function isCare($orGreater = false) {
return $this->is(self::TYPE_CARE, $orGreater);
}
public function isAtLeastCare() {
return $this->isCare(true);
}
public function isBelowCare() {
return $this->isBelow(self::TYPE_CARE);
}
public function isResponse($orGreater = false) {
return $this->is(self::TYPE_RESPONSE, $orGreater);
}
public function isAtLeastResponse() {
return $this->isResponse(true);
}
public function isBelowResponse() {
return $this->isBelow(self::TYPE_RESPONSE);
}
public function getShieldLogo() {
$type = $this->getType();
return wfUtils::getBaseURL() . "images/logos/shield-{$type}.svg";
}
public function getStylesheet($global = false) {
$type = $this->getType();
$suffix = $global ? '-global' : '';
return wfUtils::getBaseURL() . wfUtils::versionedAsset("css/license/{$type}{$suffix}.css", '', WORDFENCE_VERSION);
}
public function getGlobalStylesheet() {
return $this->getStylesheet(true);
}
public function getTypeLabel($requireCurrent = true, $includePrefix = null) {
$paidKeyTypes = array(self::KEY_TYPE_PAID_CURRENT);
if (!$requireCurrent) {
$paidKeyTypes[] = self::KEY_TYPE_PAID_EXPIRED;
$paidKeyTypes[] = self::KEY_TYPE_PAID_DELETED;
}
if (in_array($this->getKeyType(), $paidKeyTypes)) {
switch ($this->type) {
case self::TYPE_CARE:
return $includePrefix || $includePrefix === null ? __('Wordfence Care', 'wordfence') : __('Care', 'wordfence');
case self::TYPE_RESPONSE:
return $includePrefix || $includePrefix === null ? __('Wordfence Response', 'wordfence') : __('Response', 'wordfence');
case self::TYPE_PREMIUM:
default:
return $includePrefix ? __('Wordfence Premium', 'wordfence') : __('Premium', 'wordfence');
}
}
return $includePrefix ? __('Wordfence Free', 'wordfence') : __('Free', 'wordfence');
}
public function getPrefixedTypeLabel($requireCurrent = true) {
return $this->getTypeLabel($requireCurrent, true);
}
private function generateLicenseUrl($path, $query = array(), $campaign = null) {
if ($campaign !== null)
$campaign = "gnl1{$campaign}";
$url = implode(
'/',
array_filter(array(
'https://www.wordfence.com',
$campaign,
$path
))
);
return $url . (empty($query) ? '' : ('?' . http_build_query($query)));
}
public function getSupportUrl($campaign = null) {
return $this->generateLicenseUrl(
'get-help',
array(
'license' => $this->apiKey
),
$campaign
);
}
public function getUpgradeUrl($campaign = null) {
if ($this->isAtLeastPremium()) {
return $this->generateLicenseUrl(
'licenses',
array(
'upgrade' => $this->apiKey
),
$campaign
);
}
else {
return $this->generateLicenseUrl(
'products/pricing/',
array(),
$campaign
);
}
}
private function writeConfig($hasError = false) {
$this->clearCache();
$keyType = $this->getKeyType();
wfConfig::set(self::CONFIG_API_KEY, $this->apiKey);
wfConfig::set(self::CONFIG_TYPE, $this->type);
wfConfig::set(self::CONFIG_REMAINING_DAYS, $this->remainingDays);
wfConfig::set(self::CONFIG_PAID, $keyType === self::KEY_TYPE_PAID_CURRENT);
wfConfig::setOrRemove(self::CONFIG_HAS_KEY_CONFLICT, $this->conflicting ? 1 : null);
if (!$hasError) { //Only save a limited subset of the config if an API error occurred
wfConfig::set(self::CONFIG_KEY_TYPE, $keyType);
}
}
/**
* @param bool $hasError whether or not an error occurred while retrieving the current license data
*/
public function save($hasError = false) {
$this->writeConfig($hasError);
}
public function downgradeToFree($apiKey) {
$this->apiKey = $apiKey;
$this->type = self::TYPE_FREE;
$this->paid = false;
$this->keyType = self::KEY_TYPE_FREE;
$this->conflicting = false;
$this->deleted = false;
$this->remainingDays = -1;
return $this;
}
public static function isValidType($type) {
return in_array($type, self::$TYPES);
}
private static function fromConfig() {
$remainingDays = wfConfig::get(self::CONFIG_REMAINING_DAYS, null);
if ($remainingDays !== null)
$remainingDays = (int) $remainingDays;
$keyType = wfConfig::get(self::CONFIG_KEY_TYPE, null);
return new self(
(string) wfConfig::get(self::CONFIG_API_KEY),
(bool) wfConfig::get(self::CONFIG_PAID),
(string) wfConfig::get(self::CONFIG_TYPE, self::TYPE_FREE),
$remainingDays,
(bool) wfConfig::get(self::CONFIG_HAS_KEY_CONFLICT, false),
$keyType === self::KEY_TYPE_PAID_DELETED,
$keyType
);
}
public static function current() {
if (self::$current === null) {
self::$current = self::fromConfig();
}
return self::$current;
}
const REGISTRATION_TOKEN_TTL = 86400; //24 hours
const REGISTRATION_TOKEN_KEY = 'wfRegistrationToken';
const REGISTRATION_TOKEN_LENGTH = 32;
public static function getRegistrationToken($refreshTtl = false) {
$token = get_transient(self::REGISTRATION_TOKEN_KEY);
if ($token === false) {
$token = openssl_random_pseudo_bytes(self::REGISTRATION_TOKEN_LENGTH);
if ($token === false)
throw new Exception('Unable to generate registration token');
$token = wfUtils::base64url_encode($token);
$refreshTtl = true;
}
if ($refreshTtl)
set_transient(self::REGISTRATION_TOKEN_KEY, $token, self::REGISTRATION_TOKEN_TTL);
return $token;
}
public static function validateRegistrationToken($token) {
$expected = self::getRegistrationToken();
//Note that the length of $expected is publicly known since it's in the plugin source, so differening lengths immediately triggering a false return is not a cause for concern
return hash_equals($expected, $token);
}
public static function generateRegistrationLink() {
$wfWebsite = wfWebsite::getInstance();
$stats = wfAPI::generateSiteStats();
$token = self::getRegistrationToken(true);
$returnUrl = network_admin_url('admin.php?page=WordfenceInstall');
$payload = array(
self::REGISTRATION_PAYLOAD_VERSION,
$stats,
$token,
$returnUrl,
);
$payload = implode(';', $payload);
$payload = wfUtils::base64url_encode($payload);
return $wfWebsite->getUrl("plugin/registration/{$payload}");
}
}

View File

@@ -0,0 +1,404 @@
<?php
if (!defined('WORDFENCE_VERSION')) { exit; }
wfUtils::doNotCache();
header('HTTP/1.1 503 Service Temporarily Unavailable');
header('Status: 503 Service Temporarily Unavailable');
?>
<!DOCTYPE html>
<html>
<head>
<title><?php esc_html_e('You are temporarily locked out', 'wordfence'); ?></title>
<style>
html {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 0.875rem;
line-height: 1.42857143;
color: #333;
background-color: #fff;
padding: 0;
margin: 0;
}
body {
padding: 0;
margin: 0;
}
a {
color:#00709e;
}
h1, h2, h3, h4, h5, h6 {
font-weight: 200;
line-height: 1.1;
}
h1, .h1 { font-size: 3rem; }
h2, .h2 { font-size: 2.5rem; }
h3, .h3 { font-size: 1.5rem; }
h4, .h4 { font-size: 1rem; }
h5, .h5 { font-size: 0.875rem; }
h6, .h6 { font-size: 0.75rem; }
h1, h2, h3 {
margin-top: 20px;
margin-bottom: 10px;
}
h4, h5, h6 {
margin-top: 10px;
margin-bottom: 10px;
}
.wf-btn {
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
text-transform: uppercase;
padding: .4rem 1rem;
font-size: .875rem;
line-height: 1.3125rem;
border-radius: 4px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none
}
@media (min-width: 768px) {
.wf-btn {
padding: .5rem 1.25rem;
font-size: .875rem;
line-height: 1.3125rem;
border-radius: 4px
}
}
.wf-btn:focus,
.wf-btn.wf-focus,
.wf-btn:active:focus,
.wf-btn:active.wf-focus,
.wf-btn.wf-active:focus,
.wf-btn.wf-active.wf-focus {
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px
}
.wf-btn:hover,
.wf-btn:focus,
.wf-btn.wf-focus {
color: #00709e;
text-decoration: none
}
.wf-btn:active,
.wf-btn.wf-active {
outline: 0;
background-image: none;
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125)
}
.wf-btn.wf-disabled,
.wf-btn[disabled],
.wf-btn[readonly],
fieldset[disabled] .wf-btn {
cursor: not-allowed;
-webkit-box-shadow: none;
box-shadow: none
}
a.wf-btn {
text-decoration: none
}
a.wf-btn.wf-disabled,
fieldset[disabled] a.wf-btn {
cursor: not-allowed;
pointer-events: none
}
.wf-btn-default {
color: #00709e;
background-color: #fff;
border-color: #00709e
}
.wf-btn-default:focus,
.wf-btn-default.focus {
color: #00709e;
background-color: #e6e6e6;
border-color: #00161f
}
.wf-btn-default:hover {
color: #00709e;
background-color: #e6e6e6;
border-color: #004561
}
.wf-btn-default:active,
.wf-btn-default.active {
color: #00709e;
background-color: #e6e6e6;
border-color: #004561
}
.wf-btn-default:active:hover,
.wf-btn-default:active:focus,
.wf-btn-default:active.focus,
.wf-btn-default.active:hover,
.wf-btn-default.active:focus,
.wf-btn-default.active.focus {
color: #00709e;
background-color: #d4d4d4;
border-color: #00161f
}
.wf-btn-default:active,
.wf-btn-default.wf-active {
background-image: none
}
.wf-btn-default.wf-disabled,
.wf-btn-default[disabled],
.wf-btn-default[readonly],
fieldset[disabled] .wf-btn-default {
color: #777;
background-color: #fff;
border-color: #e2e2e2;
cursor: not-allowed
}
.wf-btn-default.wf-disabled:hover,
.wf-btn-default.wf-disabled:focus,
.wf-btn-default.wf-disabled.wf-focus,
.wf-btn-default[disabled]:hover,
.wf-btn-default[disabled]:focus,
.wf-btn-default[disabled].wf-focus,
.wf-btn-default[readonly]:hover,
.wf-btn-default[readonly]:focus,
.wf-btn-default[readonly].wf-focus,
fieldset[disabled] .wf-btn-default:hover,
fieldset[disabled] .wf-btn-default:focus,
fieldset[disabled] .wf-btn-default.wf-focus {
background-color: #fff;
border-color: #00709e
}
input[type="text"], input.wf-input-text {
text-align: left;
max-width: 200px;
height: 30px;
border-radius: 0;
border: 0;
background-color: #ffffff;
box-shadow: 0px 0px 0px 1px rgba(215,215,215,0.65);
padding: 0.25rem;
}
hr {
margin-top: 1rem;
margin-bottom: 1rem;
border: 0;
border-top: 4px solid #eee
}
p {
font-size: 1.4rem;
font-weight: 300;
}
p.medium, div.medium p {
font-size: 1.1rem;
}
p.small, div.small p {
font-size: 1rem;
}
.container {
max-width: 900px;
padding: 0 1rem;
margin: 0 auto;
}
.top-accent {
height: 25px;
background-color: #00709e;
}
.block-data {
width: 100%;
border-top: 6px solid #00709e;
}
.block-data tr:nth-child(odd) th, .block-data tr:nth-child(odd) td {
background-color: #eeeeee;
}
.block-data th, .block-data td {
text-align: left;
padding: 1rem;
font-size: 1.1rem;
}
.block-data th.reason, .block-data td.reason {
color: #930000;
}
.block-data th {
font-weight: 300;
}
.block-data td {
font-weight: 500;
}
.about {
margin-top: 2rem;
display: flex;
flex-direction: row;
align-items: stretch;
}
.about .badge {
flex-basis: 116px;
flex-grow: 0;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: flex-start;
}
.about svg {
width: 100px;
height: 100px;
}
.about-text {
background-color: #00709e;
color: #ffffff;
padding: 1rem;
}
.about-text .h4 {
font-weight: 500;
margin-top: 0;
margin-bottom: 0.25rem;
font-size: 0.875rem;
}
.about-text p {
font-size: 0.875rem;
font-weight: 200;
margin-top: 0.3rem;
margin-bottom: 0.3rem;
}
.about-text p:first-of-type {
margin-top: 0;
}
.about-text p:last-of-type {
margin-bottom: 0;
}
.st0{fill:#00709e;}
.st1{fill:#FFFFFF;}
.generated {
color: #999999;
margin-top: 2rem;
}
/* Text meant only for screen readers. */
.screen-reader-text {
border: 0;
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
word-wrap: normal !important;
}
.screen-reader-text:focus {
background-color: #eee;
clip: auto !important;
clip-path: none;
color: #444;
display: block;
font-size: 1em;
height: auto;
left: 5px;
line-height: normal;
padding: 15px 23px 14px;
text-decoration: none;
top: 5px;
width: auto;
z-index: 100000; /* Above WP toolbar. */
}
</style>
</head>
<body>
<div class="top-accent"></div>
<div class="container">
<h1><?php esc_html_e('Your access to this site has been temporarily limited by the site owner', 'wordfence'); ?></h1>
<p><?php esc_html_e('Your access to this service has been temporarily limited. Please try again in a few minutes. (HTTP response code 503)', 'wordfence'); ?></p>
<p><?php esc_html_e('If you think you have been blocked in error, contact the owner of this site for assistance.', 'wordfence'); ?></p>
<?php if (!empty($customText)): ?>
<hr>
<div class="medium"><?php echo $customText; ?></div>
<?php endif; ?>
<hr>
<ul>
<li><a href="<?php echo esc_url(site_url()); ?>"><?php esc_html_e('Return to the site home page', 'wordfence'); ?></a></li>
<li><a href="<?php echo esc_url(admin_url()); ?>"><?php esc_html_e('Attempt to return to the admin login page (you may still be locked out)', 'wordfence'); ?></a></li>
</ul>
<?php require(dirname(__FILE__) . '/wfUnlockMsg.php'); ?>
<h2 class="h3"><?php esc_html_e('Block Technical Data', 'wordfence'); ?></h2>
<table border="0" cellspacing="0" cellpadding="0" class="block-data">
<tr>
<th class="reason"><?php esc_html_e('Block Reason:', 'wordfence'); ?></th>
<td class="reason"><?php esc_html_e('You have been temporarily locked out of this system. This means that you will not be able to log in for a while.', 'wordfence'); ?></td>
</tr>
<tr>
<th class="time"><?php esc_html_e('Time:', 'wordfence'); ?></th>
<td class="time"><?php echo htmlspecialchars(gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime())); ?></td>
</tr>
</table>
<div class="about">
<div class="badge">
<?php
$contents = file_get_contents(WORDFENCE_PATH . '/images/wf-error-badge.svg');
$contents = preg_replace('/^<\?xml.+?\?>\s*/i', '', $contents);
$contents = preg_replace('/^<!DOCTYPE.+?>\s*/i', '', $contents);
$contents = preg_replace('/<svg\s+xmlns="[^"]*"/i', '<svg', $contents);
echo $contents;
?>
</div>
<div class="about-text">
<h3 class="h4"><?php esc_html_e('About Wordfence', 'wordfence'); ?></h3>
<p><?php esc_html_e('Wordfence is a security plugin installed on over 4 million WordPress sites. The owner of this site is using Wordfence to manage access to their site.', 'wordfence'); ?></p>
<p><?php esc_html_e('You can also read the documentation to learn about Wordfence\'s blocking tools, or visit wordfence.com to learn more about Wordfence.', 'wordfence'); ?></p>
</div>
</div>
<p class="documentation small"><?php echo wp_kses(sprintf(__('Click here to learn more: <a href="%s" target="_blank" rel="noopener noreferrer">Documentation<span class="screen-reader-text"> (opens in new tab)</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_LOCKED_OUT)), array('a'=>array('href'=>array(), 'target'=>array(), 'rel'=>array()), 'span'=>array('class'=>array()))); ?></p>
<p class="generated small"><em><?php esc_html(printf(__('Generated by Wordfence at %s', 'wordfence'), gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime()))); ?>.<br><?php esc_html_e('Your computer\'s time:', 'wordfence'); ?> <script type="application/javascript">document.write(new Date().toUTCString());</script>.</em></p>
</div>
</body>
</html>
<?php exit(); ?>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,133 @@
<?php
/*
Copyright (c) 2012, Da Xue
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY DA XUE ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL DA XUE BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* https://github.com/dsx724/php-bloom-filter */
// Modified for PHP 5.2 compatibility and to support serialization.
class wfMD5BloomFilter {
private static function merge($bf1,$bf2,$bfout,$union = false){
if ($bf1->m != $bf2->m) throw new Exception('Unable to merge due to vector difference.');
if ($bf1->k != $bf2->k) throw new Exception('Unable to merge due to hash count difference.');
$length = strlen($bfout->bit_array);
if ($union){
$bfout->bit_array = $bf1->bit_array | $bf2->bit_array;
$bfout->n = $bf1->n + $bf2->n;
} else {
$bfout->bit_array = $bf1->bit_array & $bf2->bit_array;
$bfout->n = abs($bf1->n - $bf2->n);
}
}
public static function createFromProbability($n, $p){
if ($p <= 0 || $p >= 1) throw new Exception('Invalid false positive rate requested.');
if ($n <= 0) throw new Exception('Invalid capacity requested.');
$k = floor(log(1/$p,2));
$m = pow(2,ceil(log(-$n*log($p)/pow(log(2),2),2))); //approximate estimator method
return new self($m,$k);
}
public static function getUnion($bf1,$bf2){
$bf = new self($bf1->m,$bf1->k,$bf1->hash);
self::merge($bf1,$bf2,$bf,true);
return $bf;
}
public static function getIntersection($bf1,$bf2){
$bf = new self($bf1->m,$bf1->k,$bf1->hash);
self::merge($bf1,$bf2,$bf,false);
return $bf;
}
private $n = 0; // # of entries
private $m; // # of bits in array
private $k; // # of hash functions
private $k2;
private $mask;
private $bit_array; // data structure
public function __construct($m, $k){
if ($m < 8) throw new Exception('The bit array length must be at least 8 bits.');
if (($m & ($m - 1)) !== 0) throw new Exception('The bit array length must be power of 2.');
if ($m > 65536) throw new Exception('The maximum data structure size is 8KB.');
if ($k > 8) throw new Exception('The maximum bits to set is 8.');
$this->m = $m;
$this->k = $k;
$this->k2 = $k * 2;
$address_bits = (int)log($m,2);
$this->mask = (1 << $address_bits) - 8;
$this->bit_array = (binary)(str_repeat("\0",$this->getArraySize(true)));
}
public function __sleep() {
return array('n', 'm', 'k', 'k2', 'mask', 'bit_array');
}
public function calculateProbability($n = 0){
return pow(1-pow(1-1/$this->m,$this->k*($n ? $n : $this->n)),$this->k);
}
public function calculateCapacity($p){
return floor($this->m*log(2)/log($p,1-pow(1-1/$this->m,$this->m*log(2))));
}
public function getElementCount(){
return $this->n;
}
public function getArraySize($bytes = false){
return $this->m >> ($bytes ? 3 : 0);
}
public function getHashCount(){
return $this->k;
}
public function getInfo($p = null){
$units = array('','K','M','G','T','P','E','Z','Y');
$M = $this->getArraySize(true);
$magnitude = intval(floor(log($M,1024)));
$unit = $units[$magnitude];
$M /= pow(1024,$magnitude);
return 'Allocated '.$this->getArraySize().' bits ('.$M.' '.$unit.'Bytes)'.PHP_EOL.
'Using '.$this->getHashCount(). ' (16b) hashes'.PHP_EOL.
'Contains '.$this->getElementCount().' elements'.PHP_EOL.
(isset($p) ? 'Capacity of '.number_format($this->calculateCapacity($p)).' (p='.$p.')'.PHP_EOL : '');
}
public function add($key){
$hash = md5($key,true);
for ($index = 0; $index < $this->k2; $index++){
$hash_sub = (ord($hash[$index++]) << 8) | ord($hash[$index]);
$word = ($hash_sub & $this->mask) >> 3;
$this->bit_array[$word] = $this->bit_array[$word] | chr(1 << ($hash_sub & 7));
}
$this->n++;
}
public function contains($key){
$hash = md5($key,true);
for ($index = 0; $index < $this->k2; $index++){
$hash_sub = (ord($hash[$index++]) << 8) | ord($hash[$index]);
if ((ord($this->bit_array[($hash_sub & $this->mask) >> 3]) & (1 << ($hash_sub & 7))) === 0) return false;
}
return true;
}
public function unionWith($bf){
self::merge($this,$bf,$this,true);
}
public function intersectWith($bf){
self::merge($this,$bf,$this,false);
}
}

View File

@@ -0,0 +1,38 @@
<?php
class wfModuleController {
private $_optionIndexes;
private $_optionBlocks;
public static function shared() {
static $_shared = false;
if ($_shared === false) {
$_shared = new wfModuleController();
}
return $_shared;
}
public function __construct() {
$this->_optionIndexes = array();
$this->_optionBlocks = array();
}
public function __get($key) {
switch ($key) {
case 'optionIndexes':
return $this->_optionIndexes;
case 'optionBlocks':
return $this->_optionBlocks;
}
throw new OutOfBoundsException('Invalid key');
}
public function addOptionIndex($target, $text) {
$this->_optionIndexes[$target] = $text;
}
public function addOptionBlock($html) {
$this->_optionBlocks[] = $html;
}
}

View File

@@ -0,0 +1,162 @@
<?php
class wfNotification {
const PRIORITY_LOW = 1500;
const PRIORITY_DEFAULT = 1000;
const PRIORITY_HIGH = 500;
const PRIORITY_HIGH_CRITICAL = 501;
const PRIORITY_HIGH_WARNING = 502;
protected $_id;
protected $_category;
protected $_priority;
protected $_ctime;
protected $_html;
protected $_links;
public static function notifications($since = 0) {
global $wpdb;
$table_wfNotifications = wfDB::networkTable('wfNotifications');
$rawNotifications = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$table_wfNotifications} WHERE `new` = 1 AND `ctime` > %d ORDER BY `priority` ASC, `ctime` DESC", $since), ARRAY_A);
$notifications = array();
foreach ($rawNotifications as $raw) {
$notifications[] = new wfNotification($raw['id'], $raw['priority'], $raw['html'], $raw['category'], $raw['ctime'], json_decode($raw['links'], true), true);
}
return $notifications;
}
public static function getNotificationForID($id) {
global $wpdb;
$table_wfNotifications = wfDB::networkTable('wfNotifications');
$rawNotifications = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$table_wfNotifications} WHERE `id` = %s ORDER BY `priority` ASC, `ctime` DESC", $id), ARRAY_A);
if (count($rawNotifications) == 1) {
$raw = $rawNotifications[0];
return new wfNotification($raw['id'], $raw['priority'], $raw['html'], $raw['category'], $raw['ctime'], json_decode($raw['links'], true), true);
}
return null;
}
public static function getNotificationForCategory($category, $requireNew = true) {
global $wpdb;
$table_wfNotifications = wfDB::networkTable('wfNotifications');
$rawNotifications = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$table_wfNotifications} WHERE " . ($requireNew ? '`new` = 1 AND ' : '') . "`category` = %s ORDER BY `priority` ASC, `ctime` DESC LIMIT 1", $category), ARRAY_A);
if (count($rawNotifications) == 1) {
$raw = $rawNotifications[0];
return new wfNotification($raw['id'], $raw['priority'], $raw['html'], $raw['category'], $raw['ctime'], json_decode($raw['links'], true), true);
}
return null;
}
public static function reconcileNotificationsWithOptions() {
$notification_updatesNeeded = wfConfig::get('notification_updatesNeeded');
$notification_securityAlerts = wfConfig::get('notification_securityAlerts') || !wfConfig::p();
$notification_promotions = wfConfig::get('notification_promotions') || !wfConfig::p();
$notification_blogHighlights = wfConfig::get('notification_blogHighlights') || !wfConfig::p();
$notification_productUpdates = wfConfig::get('notification_productUpdates') || !wfConfig::p();
$notification_scanStatus = wfConfig::get('notification_scanStatus');
$notifications = self::notifications();
foreach ($notifications as $n) {
$category = $n->category;
if (preg_match('/^release/i', $category) && !$notification_productUpdates) { $n->markAsRead(); }
if (preg_match('/^digest/i', $category) && !$notification_blogHighlights) { $n->markAsRead(); }
if (preg_match('/^alert/i', $category) && !$notification_securityAlerts) { $n->markAsRead(); }
if (preg_match('/^promo/i', $category) && !$notification_promotions) { $n->markAsRead(); }
switch ($category) {
case 'wfplugin_scan':
if (!$notification_scanStatus) { $n->markAsRead(); }
break;
case 'wfplugin_updates':
if (!$notification_updatesNeeded) { $n->markAsRead(); }
break;
case 'wfplugin_keyconflict':
default:
//Allow it
break;
}
}
}
public function __construct($id, $priority, $html, $category = null, $ctime = null, $links = null, $memoryOnly = false) {
if ($id === null) {
$id = 'site-' . wfUtils::base32_encode(pack('I', wfConfig::atomicInc('lastNotificationID')));
}
if ($category === null) {
$category = '';
}
if ($ctime === null) {
$ctime = time();
}
if (!is_array($links)) {
$links = array();
}
$this->_id = $id;
$this->_category = $category;
$this->_priority = $priority;
$this->_ctime = $ctime;
$this->_html = $html;
$this->_links = $links;
global $wpdb;
if (!$memoryOnly) {
$linksJSON = json_encode($links);
$notification_updatesNeeded = wfConfig::get('notification_updatesNeeded');
$notification_securityAlerts = wfConfig::get('notification_securityAlerts') || !wfConfig::p();
$notification_promotions = wfConfig::get('notification_promotions') || !wfConfig::p();
$notification_blogHighlights = wfConfig::get('notification_blogHighlights') || !wfConfig::p();
$notification_productUpdates = wfConfig::get('notification_productUpdates') || !wfConfig::p();
$notification_scanStatus = wfConfig::get('notification_scanStatus');
if (preg_match('/^release/i', $category) && !$notification_productUpdates) { return; }
if (preg_match('/^digest/i', $category) && !$notification_blogHighlights) { return; }
if (preg_match('/^alert/i', $category) && !$notification_securityAlerts) { return; }
if (preg_match('/^promo/i', $category) && !$notification_promotions) { return; }
switch ($category) {
case 'wfplugin_scan':
if (!$notification_scanStatus) { return; }
break;
case 'wfplugin_updates':
if (!$notification_updatesNeeded) { return; }
break;
case 'wfplugin_keyconflict':
default:
//Allow it
break;
}
$table_wfNotifications = wfDB::networkTable('wfNotifications');
if (!empty($category)) {
$existing = self::getNotificationForCategory($category);
if ($existing) {
$wpdb->query($wpdb->prepare("UPDATE {$table_wfNotifications} SET priority = %d, ctime = %d, html = %s, links = %s WHERE id = %s", $priority, $ctime, $html, $linksJSON, $existing->id));
return;
}
}
$wpdb->query($wpdb->prepare("INSERT IGNORE INTO {$table_wfNotifications} (id, category, priority, ctime, html, links) VALUES (%s, %s, %d, %d, %s, %s)", $id, $category, $priority, $ctime, $html, $linksJSON));
}
}
public function __get($key){
if ($key == 'id') { return $this->_id; }
else if ($key == 'category') { return $this->_category; }
else if ($key == 'priority') { return $this->_priority; }
else if ($key == 'ctime') { return $this->_ctime; }
else if ($key == 'html') { return $this->_html; }
else if ($key == 'links') { return $this->_links; }
throw new InvalidArgumentException();
}
public function markAsRead() {
global $wpdb;
$table_wfNotifications = wfDB::networkTable('wfNotifications');
$wpdb->query($wpdb->prepare("UPDATE {$table_wfNotifications} SET `new` = 0 WHERE `id` = %s", $this->_id));
}
}

View File

@@ -0,0 +1,199 @@
<?php
class wfOnboardingController {
const ONBOARDING_EMAILS = 'emails'; //New install, part 1 completed
const ONBOARDING_LICENSE = 'license'; //New install, part 2 completed
const ONBOARDING_SKIPPED = 'skipped'; //New install, onboarding attempt was skipped
const TOUR_DASHBOARD = 'dashboard';
const TOUR_FIREWALL = 'firewall';
const TOUR_SCAN = 'scan';
const TOUR_BLOCKING = 'blocking';
const TOUR_LIVE_TRAFFIC = 'livetraffic';
const TOUR_LOGIN_SECURITY = 'loginsecurity';
/**
* Sets the appropriate initial settings for an existing install so it's not forced through onboarding.
*/
public static function migrateOnboarding() {
$alertEmails = wfConfig::getAlertEmails();
$onboardingAttempt1 = wfConfig::get('onboardingAttempt1');
if (!empty($alertEmails) && empty($onboardingAttempt1)) {
wfConfig::set('onboardingAttempt1', self::ONBOARDING_LICENSE); //Mark onboarding as done
$keys = array(self::TOUR_DASHBOARD, self::TOUR_FIREWALL, self::TOUR_SCAN, self::TOUR_BLOCKING, self::TOUR_LIVE_TRAFFIC);
foreach ($keys as $k) {
wfConfig::set('needsNewTour_' . $k, 0);
wfConfig::set('needsUpgradeTour_' . $k, 1);
}
}
}
/**
* Initializes the onboarding hooks.
*
* Only called if (is_admin() && wfUtils::isAdmin()) is true.
*/
public static function initialize() {
$willShowAnyTour = (self::shouldShowNewTour(self::TOUR_DASHBOARD) || self::shouldShowUpgradeTour(self::TOUR_DASHBOARD) ||
self::shouldShowNewTour(self::TOUR_FIREWALL) || self::shouldShowUpgradeTour(self::TOUR_FIREWALL) ||
self::shouldShowNewTour(self::TOUR_SCAN) || self::shouldShowUpgradeTour(self::TOUR_SCAN) ||
self::shouldShowNewTour(self::TOUR_BLOCKING) || self::shouldShowUpgradeTour(self::TOUR_BLOCKING) ||
self::shouldShowNewTour(self::TOUR_LIVE_TRAFFIC) || self::shouldShowUpgradeTour(self::TOUR_LIVE_TRAFFIC) ||
self::shouldShowNewTour(self::TOUR_LOGIN_SECURITY) || self::shouldShowUpgradeTour(self::TOUR_LOGIN_SECURITY));
if (!self::shouldShowAnyAttempt() && !$willShowAnyTour) {
return;
}
add_action('in_admin_header', 'wfOnboardingController::_admin_header'); //Called immediately after <div id="wpcontent">
add_action('pre_current_active_plugins', 'wfOnboardingController::_pre_plugins'); //Called immediately after <hr class="wp-header-end">
add_action('admin_enqueue_scripts', 'wfOnboardingController::_enqueue_scripts');
}
/**
* Enqueues the scripts and styles we need globally on the backend for onboarding.
*/
public static function _enqueue_scripts() {
$willShowAnyPluginOnboarding = (self::shouldShowAttempt1() || self::shouldShowAttempt2());
$willShowAnyTour = (self::shouldShowNewTour(self::TOUR_DASHBOARD) || self::shouldShowUpgradeTour(self::TOUR_DASHBOARD) ||
self::shouldShowNewTour(self::TOUR_FIREWALL) || self::shouldShowUpgradeTour(self::TOUR_FIREWALL) ||
self::shouldShowNewTour(self::TOUR_SCAN) || self::shouldShowUpgradeTour(self::TOUR_SCAN) ||
self::shouldShowNewTour(self::TOUR_BLOCKING) || self::shouldShowUpgradeTour(self::TOUR_BLOCKING) ||
self::shouldShowNewTour(self::TOUR_LIVE_TRAFFIC) || self::shouldShowUpgradeTour(self::TOUR_LIVE_TRAFFIC) ||
self::shouldShowNewTour(self::TOUR_LOGIN_SECURITY) || self::shouldShowUpgradeTour(self::TOUR_LOGIN_SECURITY));
if (wfUtils::isAdmin() &&
(($willShowAnyPluginOnboarding && preg_match('~(?:^|/)wp-admin(?:/network)?/plugins\.php~i', $_SERVER['REQUEST_URI'])) ||
(isset($_GET['page']) &&
(preg_match('/^Wordfence/', @$_GET['page']) || preg_match('/^WFLS/', @$_GET['page']))
)
)
) {
self::enqueue_assets();
}
}
public static function enqueue_assets() {
wp_enqueue_style('wordfence-font', wfUtils::getBaseURL() . wfUtils::versionedAsset('css/wf-roboto-font.css'), '', WORDFENCE_VERSION);
wp_enqueue_style('wordfence-ionicons-style', wfUtils::getBaseURL() . wfUtils::versionedAsset('css/wf-ionicons.css'), '', WORDFENCE_VERSION);
wp_enqueue_style('wordfenceOnboardingCSS', wfUtils::getBaseURL() . wfUtils::versionedAsset('css/wf-onboarding.css'), '', WORDFENCE_VERSION);
wp_enqueue_style('wordfence-colorbox-style', wfUtils::getBaseURL() . wfUtils::versionedAsset('css/wf-colorbox.css'), '', WORDFENCE_VERSION);
wp_enqueue_script('jquery.wfcolorbox', wfUtils::getBaseURL() . wfUtils::versionedAsset('js/jquery.colorbox-min.js'), array('jquery'), WORDFENCE_VERSION);
}
/**
* Outputs the onboarding overlay if it needs to be shown on the plugins page.
*/
public static function _admin_header() {
$willShowAnyTour = (self::shouldShowNewTour(self::TOUR_DASHBOARD) || self::shouldShowUpgradeTour(self::TOUR_DASHBOARD) ||
self::shouldShowNewTour(self::TOUR_FIREWALL) || self::shouldShowUpgradeTour(self::TOUR_FIREWALL) ||
self::shouldShowNewTour(self::TOUR_SCAN) || self::shouldShowUpgradeTour(self::TOUR_SCAN) ||
self::shouldShowNewTour(self::TOUR_BLOCKING) || self::shouldShowUpgradeTour(self::TOUR_BLOCKING) ||
self::shouldShowNewTour(self::TOUR_LIVE_TRAFFIC) || self::shouldShowUpgradeTour(self::TOUR_LIVE_TRAFFIC) ||
self::shouldShowNewTour(self::TOUR_LOGIN_SECURITY) || self::shouldShowUpgradeTour(self::TOUR_LOGIN_SECURITY));
$screen = get_current_screen();
if ($screen->base == 'plugins' && self::shouldShowAttempt1()) {
register_shutdown_function('wfOnboardingController::_markAttempt1Shown');
$freshInstall = wfView::create('onboarding/fresh-install')->render();
echo wfView::create('onboarding/overlay', array(
'contentHTML' => $freshInstall,
))->render();
}
else if (preg_match('/wordfence/i', $screen->base) && $willShowAnyTour) {
echo wfView::create('onboarding/tour-overlay')->render();
}
}
public static function _markAttempt1Shown() {
wfConfig::set('onboardingAttempt1', self::ONBOARDING_SKIPPED); //Only show it once, default to skipped after outputting the first time
}
public static function shouldShowAttempt1() { //Overlay on plugin page
if (wfConfig::get('onboardingAttempt3') == self::ONBOARDING_LICENSE) {
return false;
}
switch (wfConfig::get('onboardingAttempt1')) {
case self::ONBOARDING_LICENSE:
case self::ONBOARDING_SKIPPED:
return false;
}
return true;
}
public static function _pre_plugins() {
if (self::shouldShowAttempt2()) {
echo wfView::create('onboarding/plugin-header')->render();
}
}
private static function needsApiKey() {
$key = wfConfig::get('apiKey');
return empty($key);
}
public static function shouldShowAttempt2() { //Header on plugin page
if (wfConfig::get('onboardingAttempt3') == self::ONBOARDING_LICENSE) {
return false;
}
return !wfConfig::get('onboardingAttempt2') && self::needsApiKey();
}
public static function shouldShowAttempt3($dismissable = false) {
if (self::needsApiKey()) {
if (!$dismissable)
return true;
$delayedAt = (int) wfConfig::get('onboardingDelayedAt', 0);
if (time() - $delayedAt > 43200 /*12 hours in seconds*/)
return true;
}
return false;
}
/**
* Whether or not to pop up attempt 3 at page load or wait for user interaction.
*
* @return bool
*/
public static function shouldShowAttempt3Automatically() {
static $_shouldShowAttempt3Automatically = null;
if ($_shouldShowAttempt3Automatically !== null) { //We cache this so the answer remains the same for the whole request
return $_shouldShowAttempt3Automatically;
}
if (!self::shouldShowAttempt3()) {
$_shouldShowAttempt3Automatically = false;
return false;
}
return $_shouldShowAttempt3Automatically = self::shouldShowAttempt3();
}
public static function willShowNewTour($page) {
$key = 'needsNewTour_' . $page;
return wfConfig::get($key);
}
public static function shouldShowNewTour($page) {
$key = 'needsNewTour_' . $page;
return (!self::shouldShowAttempt3Automatically() && !wfConfig::get('touppPromptNeeded') && wfConfig::get($key));
}
public static function willShowUpgradeTour($page) {
$key = 'needsUpgradeTour_' . $page;
return wfConfig::get($key);
}
public static function shouldShowUpgradeTour($page) {
$key = 'needsUpgradeTour_' . $page;
return (!self::shouldShowAttempt3Automatically() && !wfConfig::get('touppPromptNeeded') && wfConfig::get($key));
}
public static function shouldShowAnyAttempt() {
return self::shouldShowAttempt1() || self::shouldShowAttempt2() || self::shouldShowAttempt3();
}
}

View File

@@ -0,0 +1,40 @@
<?php
class wfPersistenceController {
private $_disclosureStates;
public static function shared() {
static $_shared = false;
if ($_shared === false) {
$_shared = new wfPersistenceController();
}
return $_shared;
}
public function __construct() {
$this->_disclosureStates = wfConfig::get_ser('disclosureStates', array());
}
/**
* Returns whether the options block is in an active state.
*
* @param $key
* @return bool
*/
public function isActive($key) {
if (!isset($this->_disclosureStates[$key])) {
return false;
}
return !!$this->_disclosureStates[$key];
}
/**
* Returns whether the options block has been set.
*
* @param $key
* @return bool
*/
public function isConfigured($key) {
return isset($this->_disclosureStates[$key]);
}
}

View File

@@ -0,0 +1,14 @@
<?php
if (defined('ABSPATH')) {
class wfWP_REST_Users_Controller extends WP_REST_Users_Controller
{
public static function wfGetURLBase() {
$controller = new wfWP_REST_Users_Controller();
return rtrim($controller->namespace . '/' . $controller->rest_base, '/');
}
public function _wfGetURLBase() {
return rtrim($this->namespace, '/' . $this->rest_base, '/');
}
}
}

View File

@@ -0,0 +1,362 @@
<?php
class wfScan {
public static $debugMode = false;
public static $errorHandlingOn = true;
public static $peakMemAtStart = 0;
/**
* Returns the stored cronkey or false if not set. If $expired is provided, will set to <timestamp>/false based
* on whether or not the cronkey is expired.
*
* @param null $expired
* @return bool|string
*/
private static function storedCronKey(&$expired = null) {
$currentCronKey = wfConfig::get('currentCronKey', false);
if (empty($currentCronKey))
{
if ($expired !== null) {
$expired = false;
}
return false;
}
$savedKey = explode(',',$currentCronKey);
if (time() - $savedKey[0] > 86400) {
if ($expired !== null) {
$expired = $savedKey[0];
}
return $savedKey[1];
}
if ($expired !== null) {
$expired = false;
}
return $savedKey[1];
}
public static function wfScanMain(){
self::$peakMemAtStart = memory_get_peak_usage(true);
$db = new wfDB();
if($db->errorMsg){
self::errorExit(sprintf(/* translators: Error message. */ __("Could not connect to database to start scan: %s", 'wordfence'), $db->errorMsg));
}
if(! wordfence::wfSchemaExists()){
self::errorExit(__("Looks like the Wordfence database tables have been deleted. You can fix this by de-activating and re-activating the Wordfence plugin from your Plugins menu.", 'wordfence'));
}
if( isset( $_GET['test'] ) && $_GET['test'] == '1'){
echo "WFCRONTESTOK:" . wfConfig::get('cronTestID');
self::status(4, 'info', __("Cron test received and message printed", 'wordfence'));
exit();
}
self::status(4, 'info', __("Scan engine received request.", 'wordfence'));
/* ----------Starting signature check -------- */
self::status(4, 'info', __("Verifying start request signature.", 'wordfence'));
if (!isset($_GET['signature']) || !wfScanEngine::verifyStartSignature($_GET['signature'], isset($_GET['isFork']) ? wfUtils::truthyToBoolean($_GET['isFork']) : false, isset($_GET['scanMode']) ? $_GET['scanMode'] : '', isset($_GET['cronKey']) ? $_GET['cronKey'] : '', isset($_GET['remote']) ? wfUtils::truthyToBoolean($_GET['remote']) : false)) {
self::errorExit(__('The signature on the request to start a scan is invalid. Please try again.', 'wordfence'));
}
/* ----------Starting cronkey check -------- */
self::status(4, 'info', __("Fetching stored cronkey for comparison.", 'wordfence'));
$expired = false;
$storedCronKey = self::storedCronKey($expired);
$displayCronKey_received = (isset($_GET['cronKey']) ? (preg_match('/^[a-f0-9]+$/i', $_GET['cronKey']) && strlen($_GET['cronKey']) == 32 ? $_GET['cronKey'] : __('[invalid]', 'wordfence')) : __('[none]', 'wordfence'));
$displayCronKey_stored = (!empty($storedCronKey) && !$expired ? $storedCronKey : __('[none]', 'wordfence'));
self::status(4, 'info', sprintf(/* translators: 1. WordPress nonce. 2. WordPress nonce. */ __('Checking cronkey: %1$s (expecting %2$s)', 'wordfence'), $displayCronKey_received, $displayCronKey_stored));
if (empty($_GET['cronKey'])) {
self::status(4, 'error', __("Wordfence scan script accessed directly, or WF did not receive a cronkey.", 'wordfence'));
echo "If you see this message it means Wordfence is working correctly. You should not access this URL directly. It is part of the Wordfence security plugin and is designed for internal use only.";
exit();
}
if ($expired) {
self::errorExit(sprintf(
/* translators: 1. Unix timestamp. 2. WordPress nonce. 3. Unix timestamp. */
__('The key used to start a scan expired. The value is: %1$s and split is: %2$s and time is: %3$d', 'wordfence'), $expired, $storedCronKey, time()));
} //keys only last 60 seconds and are used within milliseconds of creation
if (!$storedCronKey) {
wordfence::status(4, 'error', __("Wordfence could not find a saved cron key to start the scan so assuming it started and exiting.", 'wordfence'));
exit();
}
self::status(4, 'info', __("Checking saved cronkey against cronkey param", 'wordfence'));
if (!hash_equals($storedCronKey, $_GET['cronKey'])) {
self::errorExit(
sprintf(
/* translators: 1. WordPress nonce (used for debugging). 2. WordPress nonce (used for debugging). 3. WordPress nonce (used for debugging). */
__('Wordfence could not start a scan because the cron key does not match the saved key. Saved: %1$s Sent: %2$s Current unexploded: %3$s', 'wordfence'),
$storedCronKey,
$_GET['cronKey'],
wfConfig::get('currentCronKey', false)
)
);
}
wfConfig::set('currentCronKey', '');
/* --------- end cronkey check ---------- */
wfScanMonitor::logLastSuccess();
$scanMode = wfScanner::SCAN_TYPE_STANDARD;
if (isset($_GET['scanMode']) && wfScanner::isValidScanType($_GET['scanMode'])) {
$scanMode = $_GET['scanMode'];
}
$scanController = new wfScanner($scanMode);
wfConfig::remove('scanStartAttempt');
$isFork = ($_GET['isFork'] == '1' ? true : false);
wfScanMonitor::handleStageStart($isFork);
if(! $isFork){
self::status(4, 'info', __("Checking if scan is already running", 'wordfence'));
if(! wfUtils::getScanLock()){
self::errorExit(__("There is already a scan running.", 'wordfence'));
}
wfIssues::updateScanStillRunning();
wfConfig::set('wfPeakMemory', 0, wfConfig::DONT_AUTOLOAD);
wfConfig::set('wfScanStartVersion', wfUtils::getWPVersion());
wfConfig::set('lowResourceScanWaitStep', false);
if ($scanController->useLowResourceScanning()) {
self::status(1, 'info', __("Using low resource scanning", 'wordfence'));
}
}
self::status(4, 'info', __("Requesting max memory", 'wordfence'));
wfUtils::requestMaxMemory();
self::status(4, 'info', __("Setting up error handling environment", 'wordfence'));
set_error_handler('wfScan::error_handler', E_ALL);
register_shutdown_function('wfScan::shutdown');
if(! self::$debugMode){
ob_start('wfScan::obHandler');
}
@error_reporting(E_ALL);
wfUtils::iniSet('display_errors','On');
self::status(4, 'info', __("Setting up scanRunning and starting scan", 'wordfence'));
try {
if ($isFork) {
$scan = wfConfig::get_ser('wfsd_engine', false, false);
if ($scan) {
self::status(4, 'info', sprintf(/* translators: Error message (used for debugging). */ __("Got a true deserialized value back from 'wfsd_engine' with type: %s", 'wordfence'), gettype($scan)));
wfConfig::set('wfsd_engine', '', wfConfig::DONT_AUTOLOAD);
}
else {
self::status(2, 'error', sprintf(/* translators: Error message (used for debugging). */ __("Scan can't continue - stored data not found after a fork. Got type: %s", 'wordfence'), gettype($scan)));
wfConfig::set('wfsd_engine', '', wfConfig::DONT_AUTOLOAD);
wfConfig::set('lastScanCompleted', __('Scan can\'t continue - stored data not found after a fork.', 'wordfence'));
wfConfig::set('lastScanFailureType', wfIssues::SCAN_FAILED_FORK_FAILED);
wfUtils::clearScanLock();
self::status(2, 'error', "Scan terminated with error: " . __('Scan can\'t continue - stored data not found after a fork.', 'wordfence'));
self::status(10, 'info', "SUM_KILLED:" . __('Previous scan terminated with an error. See below.', 'wordfence'));
exit();
}
}
else {
$delay = -1;
$isScheduled = false;
$originalScanStart = wfConfig::get('originalScheduledScanStart', 0);
$lastScanStart = wfConfig::get('lastScheduledScanStart', 0);
$minimumFrequency = ($scanController->schedulingMode() == wfScanner::SCAN_SCHEDULING_MODE_MANUAL ? 1800 : 43200);
if ($lastScanStart && (time() - $lastScanStart) < $minimumFrequency) {
$isScheduled = true;
if ($originalScanStart > 0) {
$delay = max($lastScanStart - $originalScanStart, 0);
}
}
wfIssues::statusPrep(); //Re-initializes all status counters
$scanController->resetStages();
$scanController->resetSummaryItems();
if ($scanMode != wfScanner::SCAN_TYPE_QUICK) {
wordfence::status(1, 'info', __("Contacting Wordfence to initiate scan", 'wordfence'));
$wp_version = wfUtils::getWPVersion();
$apiKey = wfConfig::get('apiKey');
$api = new wfAPI($apiKey, $wp_version);
$response = $api->call('log_scan', array(), array('delay' => $delay, 'scheduled' => (int) $isScheduled, 'mode' => wfConfig::get('schedMode')/*, 'forcedefer' => 1*/));
if ($scanController->schedulingMode() == wfScanner::SCAN_SCHEDULING_MODE_AUTOMATIC && $isScheduled) {
if (isset($response['defer'])) {
$defer = (int) $response['defer'];
wordfence::status(2, 'info', sprintf(/* translators: Time until. */ __("Deferring scheduled scan by %s", 'wordfence'), wfUtils::makeDuration($defer)));
wfConfig::set('lastScheduledScanStart', 0);
wfConfig::set('lastScanCompleted', 'ok');
wfConfig::set('lastScanFailureType', false);
wfConfig::set_ser('wfStatusStartMsgs', array());
$scanController->recordLastScanTime();
$i = new wfIssues();
wfScanEngine::refreshScanNotification($i);
wfScanner::shared()->scheduleSingleScan(time() + $defer, $originalScanStart);
wfUtils::clearScanLock();
exit();
}
}
$malwarePrefixesHash = (isset($response['malwarePrefixes']) ? $response['malwarePrefixes'] : '');
$coreHashesHash = (isset($response['coreHashes']) ? $response['coreHashes'] : '');
$scan = new wfScanEngine($malwarePrefixesHash, $coreHashesHash, $scanMode);
$scan->deleteNewIssues();
}
else {
wordfence::status(1, 'info', __("Initiating quick scan", 'wordfence'));
$scan = new wfScanEngine('', '', $scanMode);
}
}
$scan->go();
}
catch (wfScanEngineDurationLimitException $e) { //User error set in wfScanEngine
wfUtils::clearScanLock();
$peakMemory = self::logPeakMemory();
self::status(2, 'info', sprintf(
__('Wordfence used %1$s of memory for scan. Server peak memory usage was: %2$s', 'wordfence'),
wfUtils::formatBytes($peakMemory - self::$peakMemAtStart),
wfUtils::formatBytes($peakMemory)
));
self::status(2, 'error', sprintf(__("Scan terminated with error: %s", 'wordfence'), $e->getMessage()));
exit();
}
catch (wfScanEngineCoreVersionChangeException $e) { //User error set in wfScanEngine
wfUtils::clearScanLock();
$peakMemory = self::logPeakMemory();
self::status(2, 'info', sprintf(
/* translators: 1. Bytes of memory. 2. Bytes of memory. */
__('Wordfence used %1$s of memory for scan. Server peak memory usage was: %2$s', 'wordfence'),
wfUtils::formatBytes($peakMemory - self::$peakMemAtStart),
wfUtils::formatBytes($peakMemory)
));
self::status(2, 'error', sprintf(/* translators: Error message. */ __("Scan terminated with error: %s", 'wordfence'), $e->getMessage()));
$nextScheduledScan = wordfence::getNextScanStartTimestamp();
if ($nextScheduledScan !== false && $nextScheduledScan - time() > 21600 /* 6 hours */) {
$nextScheduledScan = time() + 3600;
wfScanner::shared()->scheduleSingleScan($nextScheduledScan);
}
self::status(2, 'error', wordfence::getNextScanStartTime($nextScheduledScan));
exit();
}
catch (wfAPICallSSLUnavailableException $e) {
wfConfig::set('lastScanCompleted', $e->getMessage());
wfConfig::set('lastScanFailureType', wfIssues::SCAN_FAILED_API_SSL_UNAVAILABLE);
wfUtils::clearScanLock();
$peakMemory = self::logPeakMemory();
self::status(2, 'info', sprintf(
/* translators: 1. Bytes of memory. 2. Bytes of memory. */
__('Wordfence used %1$s of memory for scan. Server peak memory usage was: %2$s', 'wordfence'),
wfUtils::formatBytes($peakMemory - self::$peakMemAtStart),
wfUtils::formatBytes($peakMemory)
));
self::status(2, 'error', sprintf(/* translators: Error message. */__("Scan terminated with error: %s", 'wordfence'), $e->getMessage()));
exit();
}
catch (wfAPICallFailedException $e) {
wfConfig::set('lastScanCompleted', $e->getMessage());
wfConfig::set('lastScanFailureType', wfIssues::SCAN_FAILED_API_CALL_FAILED);
wfUtils::clearScanLock();
$peakMemory = self::logPeakMemory();
self::status(2, 'info', sprintf(
/* translators: 1. Bytes of memory. 2. Bytes of memory. */
__('Wordfence used %1$s of memory for scan. Server peak memory usage was: %2$s', 'wordfence'),
wfUtils::formatBytes($peakMemory - self::$peakMemAtStart),
wfUtils::formatBytes($peakMemory)
));
self::status(2, 'error', sprintf(/* translators: Error message. */ __("Scan terminated with error: %s", 'wordfence'), $e->getMessage()));
exit();
}
catch (wfAPICallInvalidResponseException $e) {
wfConfig::set('lastScanCompleted', $e->getMessage());
wfConfig::set('lastScanFailureType', wfIssues::SCAN_FAILED_API_INVALID_RESPONSE);
wfUtils::clearScanLock();
$peakMemory = self::logPeakMemory();
self::status(2, 'info', sprintf(
/* translators: 1. Bytes of memory. 2. Bytes of memory. */
__('Wordfence used %1$s of memory for scan. Server peak memory usage was: %2$s', 'wordfence'),
wfUtils::formatBytes($peakMemory - self::$peakMemAtStart),
wfUtils::formatBytes($peakMemory)
));
self::status(2, 'error', sprintf(/* translators: Error message. */ __("Scan terminated with error: %s", 'wordfence'), $e->getMessage()));
exit();
}
catch (wfAPICallErrorResponseException $e) {
wfConfig::set('lastScanCompleted', $e->getMessage());
wfConfig::set('lastScanFailureType', wfIssues::SCAN_FAILED_API_ERROR_RESPONSE);
wfUtils::clearScanLock();
$peakMemory = self::logPeakMemory();
self::status(2, 'info', sprintf(
/* translators: 1. Bytes of memory. 2. Bytes of memory. */
__('Wordfence used %1$s of memory for scan. Server peak memory usage was: %2$s', 'wordfence'),
wfUtils::formatBytes($peakMemory - self::$peakMemAtStart),
wfUtils::formatBytes($peakMemory)
));
self::status(2, 'error', sprintf(/* translators: Error message. */ __("Scan terminated with error: %s", 'wordfence'), $e->getMessage()));
if (preg_match('/The Wordfence API key you\'re using is already being used by: (\S*?) /', $e->getMessage(), $matches)) {
wordfence::alert(__('Wordfence scan failed because of license site URL conflict', 'wordfence'), sprintf(
/* translators: Site URL. */
__(<<<MSG
The Wordfence scan has failed because the Wordfence API key you're using is already being used by: %s
If you have changed your blog URL, please sign-in to Wordfence, purchase a new key or reset an existing key, and then enter that key on this site's Wordfence Options page.
MSG
, 'wordfence'), $matches[1]), false);
}
exit();
}
catch (Exception $e) {
wfUtils::clearScanLock();
self::status(2, 'error', sprintf(/* translators: Error message. */ __("Scan terminated with error: %s", 'wordfence'), $e->getMessage()));
self::status(10, 'info', "SUM_KILLED:" . __('Previous scan terminated with an error. See below.', 'wordfence'));
exit();
}
wfUtils::clearScanLock();
}
public static function logPeakMemory(){
$oldPeak = wfConfig::get('wfPeakMemory', 0, false);
$peak = memory_get_peak_usage(true);
if ($peak > $oldPeak) {
wfConfig::set('wfPeakMemory', $peak, wfConfig::DONT_AUTOLOAD);
return $peak;
}
return $oldPeak;
}
public static function obHandler($buf){
if(strlen($buf) > 1000){
$buf = substr($buf, 0, 255);
}
if(empty($buf) === false && preg_match('/[a-zA-Z0-9]+/', $buf)){
self::status(1, 'error', $buf);
}
}
public static function error_handler($errno, $errstr, $errfile, $errline){
if(self::$errorHandlingOn && error_reporting() > 0){
if(preg_match('/wordfence\//', $errfile)){
$level = 1; //It's one of our files, so level 1
} else {
$level = 4; //It's someone elses plugin so only show if debug is enabled
}
self::status($level, 'error', "$errstr ($errno) File: $errfile Line: $errline");
}
return false;
}
public static function shutdown(){
self::logPeakMemory();
}
private static function errorExit($msg){
wordfence::status(1, 'error', sprintf(/* translators: Error message. */ __('Scan Engine Error: %s', 'wordfence'), $msg));
exit();
}
private static function status($level, $type, $msg){
wordfence::status($level, $type, $msg);
}
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More