+ * capitalize($string);
+ * // Top-O-The-Morning To All_of_you!
+ *
+ * echo $inflector->capitalize($string, '-_ ');
+ * // Top-O-The-Morning To All_Of_You!
+ * ?>
+ *
+ *
+ * @param string $string The string to operate on.
+ * @param string $delimiters A list of word separators.
+ *
+ * @return string The string with all delimiter-separated words capitalized.
+ */
+ public function capitalize(string $string, string $delimiters = " \n\t\r\0\x0B-"): string
+ {
+ return ucwords($string, $delimiters);
+ }
+
+ /**
+ * Checks if the given string seems like it has utf8 characters in it.
+ *
+ * @param string $string The string to check for utf8 characters in.
+ */
+ public function seemsUtf8(string $string): bool
+ {
+ for ($i = 0; $i < strlen($string); $i++) {
+ if (ord($string[$i]) < 0x80) {
+ continue; // 0bbbbbbb
+ }
+
+ if ((ord($string[$i]) & 0xE0) === 0xC0) {
+ $n = 1; // 110bbbbb
+ } elseif ((ord($string[$i]) & 0xF0) === 0xE0) {
+ $n = 2; // 1110bbbb
+ } elseif ((ord($string[$i]) & 0xF8) === 0xF0) {
+ $n = 3; // 11110bbb
+ } elseif ((ord($string[$i]) & 0xFC) === 0xF8) {
+ $n = 4; // 111110bb
+ } elseif ((ord($string[$i]) & 0xFE) === 0xFC) {
+ $n = 5; // 1111110b
+ } else {
+ return false; // Does not match any model
+ }
+
+ for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ?
+ if (++$i === strlen($string) || ((ord($string[$i]) & 0xC0) !== 0x80)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Remove any illegal characters, accents, etc.
+ *
+ * @param string $string String to unaccent
+ *
+ * @return string Unaccented string
+ */
+ public function unaccent(string $string): string
+ {
+ if (preg_match('/[\x80-\xff]/', $string) === false) {
+ return $string;
+ }
+
+ if ($this->seemsUtf8($string)) {
+ $string = strtr($string, self::ACCENTED_CHARACTERS);
+ } else {
+ $characters = [];
+
+ // Assume ISO-8859-1 if not UTF-8
+ $characters['in'] =
+ chr(128)
+ . chr(131)
+ . chr(138)
+ . chr(142)
+ . chr(154)
+ . chr(158)
+ . chr(159)
+ . chr(162)
+ . chr(165)
+ . chr(181)
+ . chr(192)
+ . chr(193)
+ . chr(194)
+ . chr(195)
+ . chr(196)
+ . chr(197)
+ . chr(199)
+ . chr(200)
+ . chr(201)
+ . chr(202)
+ . chr(203)
+ . chr(204)
+ . chr(205)
+ . chr(206)
+ . chr(207)
+ . chr(209)
+ . chr(210)
+ . chr(211)
+ . chr(212)
+ . chr(213)
+ . chr(214)
+ . chr(216)
+ . chr(217)
+ . chr(218)
+ . chr(219)
+ . chr(220)
+ . chr(221)
+ . chr(224)
+ . chr(225)
+ . chr(226)
+ . chr(227)
+ . chr(228)
+ . chr(229)
+ . chr(231)
+ . chr(232)
+ . chr(233)
+ . chr(234)
+ . chr(235)
+ . chr(236)
+ . chr(237)
+ . chr(238)
+ . chr(239)
+ . chr(241)
+ . chr(242)
+ . chr(243)
+ . chr(244)
+ . chr(245)
+ . chr(246)
+ . chr(248)
+ . chr(249)
+ . chr(250)
+ . chr(251)
+ . chr(252)
+ . chr(253)
+ . chr(255);
+
+ $characters['out'] = 'EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy';
+
+ $string = strtr($string, $characters['in'], $characters['out']);
+
+ $doubleChars = [];
+
+ $doubleChars['in'] = [
+ chr(140),
+ chr(156),
+ chr(198),
+ chr(208),
+ chr(222),
+ chr(223),
+ chr(230),
+ chr(240),
+ chr(254),
+ ];
+
+ $doubleChars['out'] = ['OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th'];
+
+ $string = str_replace($doubleChars['in'], $doubleChars['out'], $string);
+ }
+
+ return $string;
+ }
+
+ /**
+ * Convert any passed string to a url friendly string.
+ * Converts 'My first blog post' to 'my-first-blog-post'
+ *
+ * @param string $string String to urlize.
+ *
+ * @return string Urlized string.
+ */
+ public function urlize(string $string): string
+ {
+ // Remove all non url friendly characters with the unaccent function
+ $unaccented = $this->unaccent($string);
+
+ if (function_exists('mb_strtolower')) {
+ $lowered = mb_strtolower($unaccented);
+ } else {
+ $lowered = strtolower($unaccented);
+ }
+
+ $replacements = [
+ '/\W/' => ' ',
+ '/([A-Z]+)([A-Z][a-z])/' => '\1_\2',
+ '/([a-z\d])([A-Z])/' => '\1_\2',
+ '/[^A-Z^a-z^0-9^\/]+/' => '-',
+ ];
+
+ $urlized = $lowered;
+
+ foreach ($replacements as $pattern => $replacement) {
+ $replaced = preg_replace($pattern, $replacement, $urlized);
+
+ if ($replaced === null) {
+ throw new RuntimeException(sprintf(
+ 'preg_replace returned null for value "%s"',
+ $urlized
+ ));
+ }
+
+ $urlized = $replaced;
+ }
+
+ return trim($urlized, '-');
+ }
+
+ /**
+ * Returns a word in singular form.
+ *
+ * @param string $word The word in plural form.
+ *
+ * @return string The word in singular form.
+ */
+ public function singularize(string $word): string
+ {
+ return $this->singularizer->inflect($word);
+ }
+
+ /**
+ * Returns a word in plural form.
+ *
+ * @param string $word The word in singular form.
+ *
+ * @return string The word in plural form.
+ */
+ public function pluralize(string $word): string
+ {
+ return $this->pluralizer->inflect($word);
+ }
+}
diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/InflectorFactory.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/InflectorFactory.php
new file mode 100755
index 00000000..a0740a74
--- /dev/null
+++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/InflectorFactory.php
@@ -0,0 +1,52 @@
+getFlippedSubstitutions()
+ );
+ }
+
+ public static function getPluralRuleset(): Ruleset
+ {
+ return new Ruleset(
+ new Transformations(...Inflectible::getPlural()),
+ new Patterns(...Uninflected::getPlural()),
+ new Substitutions(...Inflectible::getIrregular())
+ );
+ }
+}
diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Uninflected.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Uninflected.php
new file mode 100755
index 00000000..02257de1
--- /dev/null
+++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Uninflected.php
@@ -0,0 +1,189 @@
+getFlippedSubstitutions()
+ );
+ }
+
+ public static function getPluralRuleset(): Ruleset
+ {
+ return new Ruleset(
+ new Transformations(...Inflectible::getPlural()),
+ new Patterns(...Uninflected::getPlural()),
+ new Substitutions(...Inflectible::getIrregular())
+ );
+ }
+}
diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Uninflected.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Uninflected.php
new file mode 100755
index 00000000..9747f919
--- /dev/null
+++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Uninflected.php
@@ -0,0 +1,28 @@
+getFlippedSubstitutions()
+ );
+ }
+
+ public static function getPluralRuleset(): Ruleset
+ {
+ return new Ruleset(
+ new Transformations(...Inflectible::getPlural()),
+ new Patterns(...Uninflected::getPlural()),
+ new Substitutions(...Inflectible::getIrregular())
+ );
+ }
+}
diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Uninflected.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Uninflected.php
new file mode 100755
index 00000000..5d8d3b3a
--- /dev/null
+++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Uninflected.php
@@ -0,0 +1,30 @@
+pattern = $pattern;
+
+ if (isset($this->pattern[0]) && $this->pattern[0] === '/') {
+ $this->regex = $this->pattern;
+ } else {
+ $this->regex = '/' . $this->pattern . '/i';
+ }
+ }
+
+ public function getPattern(): string
+ {
+ return $this->pattern;
+ }
+
+ public function getRegex(): string
+ {
+ return $this->regex;
+ }
+
+ public function matches(string $word): bool
+ {
+ return preg_match($this->getRegex(), $word) === 1;
+ }
+}
diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Patterns.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Patterns.php
new file mode 100755
index 00000000..e8d45cb7
--- /dev/null
+++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Patterns.php
@@ -0,0 +1,34 @@
+patterns = $patterns;
+
+ $patterns = array_map(static function (Pattern $pattern): string {
+ return $pattern->getPattern();
+ }, $this->patterns);
+
+ $this->regex = '/^(?:' . implode('|', $patterns) . ')$/i';
+ }
+
+ public function matches(string $word): bool
+ {
+ return preg_match($this->regex, $word, $regs) === 1;
+ }
+}
diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Inflectible.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Inflectible.php
new file mode 100755
index 00000000..0d41fe7e
--- /dev/null
+++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Inflectible.php
@@ -0,0 +1,98 @@
+getFlippedSubstitutions()
+ );
+ }
+
+ public static function getPluralRuleset(): Ruleset
+ {
+ return new Ruleset(
+ new Transformations(...Inflectible::getPlural()),
+ new Patterns(...Uninflected::getPlural()),
+ new Substitutions(...Inflectible::getIrregular())
+ );
+ }
+}
diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Uninflected.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Uninflected.php
new file mode 100755
index 00000000..b8e988f8
--- /dev/null
+++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Uninflected.php
@@ -0,0 +1,32 @@
+regular = $regular;
+ $this->uninflected = $uninflected;
+ $this->irregular = $irregular;
+ }
+
+ public function getRegular(): Transformations
+ {
+ return $this->regular;
+ }
+
+ public function getUninflected(): Patterns
+ {
+ return $this->uninflected;
+ }
+
+ public function getIrregular(): Substitutions
+ {
+ return $this->irregular;
+ }
+}
diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Inflectible.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Inflectible.php
new file mode 100755
index 00000000..91294609
--- /dev/null
+++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Inflectible.php
@@ -0,0 +1,47 @@
+getFlippedSubstitutions()
+ );
+ }
+
+ public static function getPluralRuleset(): Ruleset
+ {
+ return new Ruleset(
+ new Transformations(...Inflectible::getPlural()),
+ new Patterns(...Uninflected::getPlural()),
+ new Substitutions(...Inflectible::getIrregular())
+ );
+ }
+}
diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Uninflected.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Uninflected.php
new file mode 100755
index 00000000..c26ebe9c
--- /dev/null
+++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Uninflected.php
@@ -0,0 +1,30 @@
+from = $from;
+ $this->to = $to;
+ }
+
+ public function getFrom(): Word
+ {
+ return $this->from;
+ }
+
+ public function getTo(): Word
+ {
+ return $this->to;
+ }
+}
diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Substitutions.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Substitutions.php
new file mode 100755
index 00000000..17ee2961
--- /dev/null
+++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Substitutions.php
@@ -0,0 +1,57 @@
+substitutions[$substitution->getFrom()->getWord()] = $substitution;
+ }
+ }
+
+ public function getFlippedSubstitutions(): Substitutions
+ {
+ $substitutions = [];
+
+ foreach ($this->substitutions as $substitution) {
+ $substitutions[] = new Substitution(
+ $substitution->getTo(),
+ $substitution->getFrom()
+ );
+ }
+
+ return new Substitutions(...$substitutions);
+ }
+
+ public function inflect(string $word): string
+ {
+ $lowerWord = strtolower($word);
+
+ if (isset($this->substitutions[$lowerWord])) {
+ $firstLetterUppercase = $lowerWord[0] !== $word[0];
+
+ $toWord = $this->substitutions[$lowerWord]->getTo()->getWord();
+
+ if ($firstLetterUppercase) {
+ return strtoupper($toWord[0]) . substr($toWord, 1);
+ }
+
+ return $toWord;
+ }
+
+ return $word;
+ }
+}
diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformation.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformation.php
new file mode 100755
index 00000000..30dcd594
--- /dev/null
+++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformation.php
@@ -0,0 +1,39 @@
+pattern = $pattern;
+ $this->replacement = $replacement;
+ }
+
+ public function getPattern(): Pattern
+ {
+ return $this->pattern;
+ }
+
+ public function getReplacement(): string
+ {
+ return $this->replacement;
+ }
+
+ public function inflect(string $word): string
+ {
+ return (string) preg_replace($this->pattern->getRegex(), $this->replacement, $word);
+ }
+}
diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformations.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformations.php
new file mode 100755
index 00000000..b6a48fa8
--- /dev/null
+++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformations.php
@@ -0,0 +1,29 @@
+transformations = $transformations;
+ }
+
+ public function inflect(string $word): string
+ {
+ foreach ($this->transformations as $transformation) {
+ if ($transformation->getPattern()->matches($word)) {
+ return $transformation->inflect($word);
+ }
+ }
+
+ return $word;
+ }
+}
diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Inflectible.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Inflectible.php
new file mode 100755
index 00000000..a2bda0d9
--- /dev/null
+++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Inflectible.php
@@ -0,0 +1,34 @@
+getFlippedSubstitutions()
+ );
+ }
+
+ public static function getPluralRuleset(): Ruleset
+ {
+ return new Ruleset(
+ new Transformations(...Inflectible::getPlural()),
+ new Patterns(...Uninflected::getPlural()),
+ new Substitutions(...Inflectible::getIrregular())
+ );
+ }
+}
diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Uninflected.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Uninflected.php
new file mode 100755
index 00000000..ec1c37dd
--- /dev/null
+++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Uninflected.php
@@ -0,0 +1,30 @@
+word = $word;
+ }
+
+ public function getWord(): string
+ {
+ return $this->word;
+ }
+}
diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/RulesetInflector.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/RulesetInflector.php
new file mode 100755
index 00000000..12b2ed5b
--- /dev/null
+++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/RulesetInflector.php
@@ -0,0 +1,56 @@
+rulesets = array_merge([$ruleset], $rulesets);
+ }
+
+ public function inflect(string $word): string
+ {
+ if ($word === '') {
+ return '';
+ }
+
+ foreach ($this->rulesets as $ruleset) {
+ if ($ruleset->getUninflected()->matches($word)) {
+ return $word;
+ }
+
+ $inflected = $ruleset->getIrregular()->inflect($word);
+
+ if ($inflected !== $word) {
+ return $inflected;
+ }
+
+ $inflected = $ruleset->getRegular()->inflect($word);
+
+ if ($inflected !== $word) {
+ return $inflected;
+ }
+ }
+
+ return $word;
+ }
+}
diff --git a/vendor/doctrine/inflector/lib/Doctrine/Inflector/WordInflector.php b/vendor/doctrine/inflector/lib/Doctrine/Inflector/WordInflector.php
new file mode 100755
index 00000000..b88b1d69
--- /dev/null
+++ b/vendor/doctrine/inflector/lib/Doctrine/Inflector/WordInflector.php
@@ -0,0 +1,10 @@
+>
+ */
+ private array $tokens = [];
+
+ /**
+ * Current lexer position in input string.
+ */
+ private int $position = 0;
+
+ /**
+ * Current peek of current lexer position.
+ */
+ private int $peek = 0;
+
+ /**
+ * The next token in the input.
+ *
+ * @var mixed[]|null
+ * @psalm-var Tokento
+ foreach ($definition->info[$token->name]->attr_transform_pre as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) { + $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + } + + // create alias to this element's attribute definition array, see + // also $d_defs (global attribute definition array) + // DEFINITION CALL + $defs = $definition->info[$token->name]->attr; + + $attr_key = false; + $context->register('CurrentAttr', $attr_key); + + // iterate through all the attribute keypairs + // Watch out for name collisions: $key has previously been used + foreach ($attr as $attr_key => $value) { + + // call the definition + if (isset($defs[$attr_key])) { + // there is a local definition defined + if ($defs[$attr_key] === false) { + // We've explicitly been told not to allow this element. + // This is usually when there's a global definition + // that must be overridden. + // Theoretically speaking, we could have a + // AttrDef_DenyAll, but this is faster! + $result = false; + } else { + // validate according to the element's definition + $result = $defs[$attr_key]->validate( + $value, + $config, + $context + ); + } + } elseif (isset($d_defs[$attr_key])) { + // there is a global definition defined, validate according + // to the global definition + $result = $d_defs[$attr_key]->validate( + $value, + $config, + $context + ); + } else { + // system never heard of the attribute? DELETE! + $result = false; + } + + // put the results into effect + if ($result === false || $result === null) { + // this is a generic error message that should replaced + // with more specific ones when possible + if ($e) { + $e->send(E_ERROR, 'AttrValidator: Attribute removed'); + } + + // remove the attribute + unset($attr[$attr_key]); + } elseif (is_string($result)) { + // generally, if a substitution is happening, there + // was some sort of implicit correction going on. We'll + // delegate it to the attribute classes to say exactly what. + + // simple substitution + $attr[$attr_key] = $result; + } else { + // nothing happens + } + + // we'd also want slightly more complicated substitution + // involving an array as the return value, + // although we're not sure how colliding attributes would + // resolve (certain ones would be completely overriden, + // others would prepend themselves). + } + + $context->destroy('CurrentAttr'); + + // post transforms + + // global (error reporting untested) + foreach ($definition->info_attr_transform_post as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) { + $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + } + + // local (error reporting untested) + foreach ($definition->info[$token->name]->attr_transform_post as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) { + $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + } + + $token->attr = $attr; + + // destroy CurrentToken if we made it ourselves + if (!$current_token) { + $context->destroy('CurrentToken'); + } + + } + + +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php new file mode 100755 index 00000000..707122bb --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php @@ -0,0 +1,124 @@ + +if (!defined('PHP_EOL')) { + switch (strtoupper(substr(PHP_OS, 0, 3))) { + case 'WIN': + define('PHP_EOL', "\r\n"); + break; + case 'DAR': + define('PHP_EOL', "\r"); + break; + default: + define('PHP_EOL', "\n"); + } +} + +/** + * Bootstrap class that contains meta-functionality for HTML Purifier such as + * the autoload function. + * + * @note + * This class may be used without any other files from HTML Purifier. + */ +class HTMLPurifier_Bootstrap +{ + + /** + * Autoload function for HTML Purifier + * @param string $class Class to load + * @return bool + */ + public static function autoload($class) + { + $file = HTMLPurifier_Bootstrap::getPath($class); + if (!$file) { + return false; + } + // Technically speaking, it should be ok and more efficient to + // just do 'require', but Antonio Parraga reports that with + // Zend extensions such as Zend debugger and APC, this invariant + // may be broken. Since we have efficient alternatives, pay + // the cost here and avoid the bug. + require_once HTMLPURIFIER_PREFIX . '/' . $file; + return true; + } + + /** + * Returns the path for a specific class. + * @param string $class Class path to get + * @return string + */ + public static function getPath($class) + { + if (strncmp('HTMLPurifier', $class, 12) !== 0) { + return false; + } + // Custom implementations + if (strncmp('HTMLPurifier_Language_', $class, 22) === 0) { + $code = str_replace('_', '-', substr($class, 22)); + $file = 'HTMLPurifier/Language/classes/' . $code . '.php'; + } else { + $file = str_replace('_', '/', $class) . '.php'; + } + if (!file_exists(HTMLPURIFIER_PREFIX . '/' . $file)) { + return false; + } + return $file; + } + + /** + * "Pre-registers" our autoloader on the SPL stack. + */ + public static function registerAutoload() + { + $autoload = array('HTMLPurifier_Bootstrap', 'autoload'); + if (($funcs = spl_autoload_functions()) === false) { + spl_autoload_register($autoload); + } elseif (function_exists('spl_autoload_unregister')) { + if (version_compare(PHP_VERSION, '5.3.0', '>=')) { + // prepend flag exists, no need for shenanigans + spl_autoload_register($autoload, true, true); + } else { + $buggy = version_compare(PHP_VERSION, '5.2.11', '<'); + $compat = version_compare(PHP_VERSION, '5.1.2', '<=') && + version_compare(PHP_VERSION, '5.1.0', '>='); + foreach ($funcs as $func) { + if ($buggy && is_array($func)) { + // :TRICKY: There are some compatibility issues and some + // places where we need to error out + $reflector = new ReflectionMethod($func[0], $func[1]); + if (!$reflector->isStatic()) { + throw new Exception( + 'HTML Purifier autoloader registrar is not compatible + with non-static object methods due to PHP Bug #44144; + Please do not use HTMLPurifier.autoload.php (or any + file that includes this file); instead, place the code: + spl_autoload_register(array(\'HTMLPurifier_Bootstrap\', \'autoload\')) + after your own autoloaders.' + ); + } + // Suprisingly, spl_autoload_register supports the + // Class::staticMethod callback format, although call_user_func doesn't + if ($compat) { + $func = implode('::', $func); + } + } + spl_autoload_unregister($func); + } + spl_autoload_register($autoload); + foreach ($funcs as $func) { + spl_autoload_register($func); + } + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php new file mode 100755 index 00000000..3f08b81c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php @@ -0,0 +1,549 @@ +info['text-align'] = new HTMLPurifier_AttrDef_Enum( + array('left', 'right', 'center', 'justify'), + false + ); + + $border_style = + $this->info['border-bottom-style'] = + $this->info['border-right-style'] = + $this->info['border-left-style'] = + $this->info['border-top-style'] = new HTMLPurifier_AttrDef_Enum( + array( + 'none', + 'hidden', + 'dotted', + 'dashed', + 'solid', + 'double', + 'groove', + 'ridge', + 'inset', + 'outset' + ), + false + ); + + $this->info['border-style'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_style); + + $this->info['clear'] = new HTMLPurifier_AttrDef_Enum( + array('none', 'left', 'right', 'both'), + false + ); + $this->info['float'] = new HTMLPurifier_AttrDef_Enum( + array('none', 'left', 'right'), + false + ); + $this->info['font-style'] = new HTMLPurifier_AttrDef_Enum( + array('normal', 'italic', 'oblique'), + false + ); + $this->info['font-variant'] = new HTMLPurifier_AttrDef_Enum( + array('normal', 'small-caps'), + false + ); + + $uri_or_none = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum(array('none')), + new HTMLPurifier_AttrDef_CSS_URI() + ) + ); + + $this->info['list-style-position'] = new HTMLPurifier_AttrDef_Enum( + array('inside', 'outside'), + false + ); + $this->info['list-style-type'] = new HTMLPurifier_AttrDef_Enum( + array( + 'disc', + 'circle', + 'square', + 'decimal', + 'lower-roman', + 'upper-roman', + 'lower-alpha', + 'upper-alpha', + 'none' + ), + false + ); + $this->info['list-style-image'] = $uri_or_none; + + $this->info['list-style'] = new HTMLPurifier_AttrDef_CSS_ListStyle($config); + + $this->info['text-transform'] = new HTMLPurifier_AttrDef_Enum( + array('capitalize', 'uppercase', 'lowercase', 'none'), + false + ); + $this->info['color'] = new HTMLPurifier_AttrDef_CSS_Color(); + + $this->info['background-image'] = $uri_or_none; + $this->info['background-repeat'] = new HTMLPurifier_AttrDef_Enum( + array('repeat', 'repeat-x', 'repeat-y', 'no-repeat') + ); + $this->info['background-attachment'] = new HTMLPurifier_AttrDef_Enum( + array('scroll', 'fixed') + ); + $this->info['background-position'] = new HTMLPurifier_AttrDef_CSS_BackgroundPosition(); + + $this->info['background-size'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum( + array( + 'auto', + 'cover', + 'contain', + 'initial', + 'inherit', + ) + ), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_CSS_Length() + ) + ); + + $border_color = + $this->info['border-top-color'] = + $this->info['border-bottom-color'] = + $this->info['border-left-color'] = + $this->info['border-right-color'] = + $this->info['background-color'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum(array('transparent')), + new HTMLPurifier_AttrDef_CSS_Color() + ) + ); + + $this->info['background'] = new HTMLPurifier_AttrDef_CSS_Background($config); + + $this->info['border-color'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_color); + + $border_width = + $this->info['border-top-width'] = + $this->info['border-bottom-width'] = + $this->info['border-left-width'] = + $this->info['border-right-width'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum(array('thin', 'medium', 'thick')), + new HTMLPurifier_AttrDef_CSS_Length('0') //disallow negative + ) + ); + + $this->info['border-width'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_width); + + $this->info['letter-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum(array('normal')), + new HTMLPurifier_AttrDef_CSS_Length() + ) + ); + + $this->info['word-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum(array('normal')), + new HTMLPurifier_AttrDef_CSS_Length() + ) + ); + + $this->info['font-size'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum( + array( + 'xx-small', + 'x-small', + 'small', + 'medium', + 'large', + 'x-large', + 'xx-large', + 'larger', + 'smaller' + ) + ), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_CSS_Length() + ) + ); + + $this->info['line-height'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum(array('normal')), + new HTMLPurifier_AttrDef_CSS_Number(true), // no negatives + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true) + ) + ); + + $margin = + $this->info['margin-top'] = + $this->info['margin-bottom'] = + $this->info['margin-left'] = + $this->info['margin-right'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_Enum(array('auto')) + ) + ); + + $this->info['margin'] = new HTMLPurifier_AttrDef_CSS_Multiple($margin); + + // non-negative + $padding = + $this->info['padding-top'] = + $this->info['padding-bottom'] = + $this->info['padding-left'] = + $this->info['padding-right'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true) + ) + ); + + $this->info['padding'] = new HTMLPurifier_AttrDef_CSS_Multiple($padding); + + $this->info['text-indent'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage() + ) + ); + + $trusted_wh = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true), + new HTMLPurifier_AttrDef_Enum(array('auto', 'initial', 'inherit')) + ) + ); + $trusted_min_wh = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true), + new HTMLPurifier_AttrDef_Enum(array('initial', 'inherit')) + ) + ); + $trusted_max_wh = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true), + new HTMLPurifier_AttrDef_Enum(array('none', 'initial', 'inherit')) + ) + ); + $max = $config->get('CSS.MaxImgLength'); + + $this->info['width'] = + $this->info['height'] = + $max === null ? + $trusted_wh : + new HTMLPurifier_AttrDef_Switch( + 'img', + // For img tags: + new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length('0', $max), + new HTMLPurifier_AttrDef_Enum(array('auto')) + ) + ), + // For everyone else: + $trusted_wh + ); + $this->info['min-width'] = + $this->info['min-height'] = + $max === null ? + $trusted_min_wh : + new HTMLPurifier_AttrDef_Switch( + 'img', + // For img tags: + new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length('0', $max), + new HTMLPurifier_AttrDef_Enum(array('initial', 'inherit')) + ) + ), + // For everyone else: + $trusted_min_wh + ); + $this->info['max-width'] = + $this->info['max-height'] = + $max === null ? + $trusted_max_wh : + new HTMLPurifier_AttrDef_Switch( + 'img', + // For img tags: + new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length('0', $max), + new HTMLPurifier_AttrDef_Enum(array('none', 'initial', 'inherit')) + ) + ), + // For everyone else: + $trusted_max_wh + ); + + $this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration(); + + $this->info['font-family'] = new HTMLPurifier_AttrDef_CSS_FontFamily(); + + // this could use specialized code + $this->info['font-weight'] = new HTMLPurifier_AttrDef_Enum( + array( + 'normal', + 'bold', + 'bolder', + 'lighter', + '100', + '200', + '300', + '400', + '500', + '600', + '700', + '800', + '900' + ), + false + ); + + // MUST be called after other font properties, as it references + // a CSSDefinition object + $this->info['font'] = new HTMLPurifier_AttrDef_CSS_Font($config); + + // same here + $this->info['border'] = + $this->info['border-bottom'] = + $this->info['border-top'] = + $this->info['border-left'] = + $this->info['border-right'] = new HTMLPurifier_AttrDef_CSS_Border($config); + + $this->info['border-collapse'] = new HTMLPurifier_AttrDef_Enum( + array('collapse', 'separate') + ); + + $this->info['caption-side'] = new HTMLPurifier_AttrDef_Enum( + array('top', 'bottom') + ); + + $this->info['table-layout'] = new HTMLPurifier_AttrDef_Enum( + array('auto', 'fixed') + ); + + $this->info['vertical-align'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum( + array( + 'baseline', + 'sub', + 'super', + 'top', + 'text-top', + 'middle', + 'bottom', + 'text-bottom' + ) + ), + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage() + ) + ); + + $this->info['border-spacing'] = new HTMLPurifier_AttrDef_CSS_Multiple(new HTMLPurifier_AttrDef_CSS_Length(), 2); + + // These CSS properties don't work on many browsers, but we live + // in THE FUTURE! + $this->info['white-space'] = new HTMLPurifier_AttrDef_Enum( + array('nowrap', 'normal', 'pre', 'pre-wrap', 'pre-line') + ); + + if ($config->get('CSS.Proprietary')) { + $this->doSetupProprietary($config); + } + + if ($config->get('CSS.AllowTricky')) { + $this->doSetupTricky($config); + } + + if ($config->get('CSS.Trusted')) { + $this->doSetupTrusted($config); + } + + $allow_important = $config->get('CSS.AllowImportant'); + // wrap all attr-defs with decorator that handles !important + foreach ($this->info as $k => $v) { + $this->info[$k] = new HTMLPurifier_AttrDef_CSS_ImportantDecorator($v, $allow_important); + } + + $this->setupConfigStuff($config); + } + + /** + * @param HTMLPurifier_Config $config + */ + protected function doSetupProprietary($config) + { + // Internet Explorer only scrollbar colors + $this->info['scrollbar-arrow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-base-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-darkshadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-face-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-highlight-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-shadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + + // vendor specific prefixes of opacity + $this->info['-moz-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + $this->info['-khtml-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + + // only opacity, for now + $this->info['filter'] = new HTMLPurifier_AttrDef_CSS_Filter(); + + // more CSS3 + $this->info['page-break-after'] = + $this->info['page-break-before'] = new HTMLPurifier_AttrDef_Enum( + array( + 'auto', + 'always', + 'avoid', + 'left', + 'right' + ) + ); + $this->info['page-break-inside'] = new HTMLPurifier_AttrDef_Enum(array('auto', 'avoid')); + + $border_radius = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Percentage(true), // disallow negative + new HTMLPurifier_AttrDef_CSS_Length('0') // disallow negative + )); + + $this->info['border-top-left-radius'] = + $this->info['border-top-right-radius'] = + $this->info['border-bottom-right-radius'] = + $this->info['border-bottom-left-radius'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_radius, 2); + // TODO: support SLASH syntax + $this->info['border-radius'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_radius, 4); + + } + + /** + * @param HTMLPurifier_Config $config + */ + protected function doSetupTricky($config) + { + $this->info['display'] = new HTMLPurifier_AttrDef_Enum( + array( + 'inline', + 'block', + 'list-item', + 'run-in', + 'compact', + 'marker', + 'table', + 'inline-block', + 'inline-table', + 'table-row-group', + 'table-header-group', + 'table-footer-group', + 'table-row', + 'table-column-group', + 'table-column', + 'table-cell', + 'table-caption', + 'none' + ) + ); + $this->info['visibility'] = new HTMLPurifier_AttrDef_Enum( + array('visible', 'hidden', 'collapse') + ); + $this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(array('visible', 'hidden', 'auto', 'scroll')); + $this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + } + + /** + * @param HTMLPurifier_Config $config + */ + protected function doSetupTrusted($config) + { + $this->info['position'] = new HTMLPurifier_AttrDef_Enum( + array('static', 'relative', 'absolute', 'fixed') + ); + $this->info['top'] = + $this->info['left'] = + $this->info['right'] = + $this->info['bottom'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_Enum(array('auto')), + ) + ); + $this->info['z-index'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Integer(), + new HTMLPurifier_AttrDef_Enum(array('auto')), + ) + ); + } + + /** + * Performs extra config-based processing. Based off of + * HTMLPurifier_HTMLDefinition. + * @param HTMLPurifier_Config $config + * @todo Refactor duplicate elements into common class (probably using + * composition, not inheritance). + */ + protected function setupConfigStuff($config) + { + // setup allowed elements + $support = "(for information on implementing this, see the " . + "support forums) "; + $allowed_properties = $config->get('CSS.AllowedProperties'); + if ($allowed_properties !== null) { + foreach ($this->info as $name => $d) { + if (!isset($allowed_properties[$name])) { + unset($this->info[$name]); + } + unset($allowed_properties[$name]); + } + // emit errors + foreach ($allowed_properties as $name => $d) { + // :TODO: Is this htmlspecialchars() call really necessary? + $name = htmlspecialchars($name); + trigger_error("Style attribute '$name' is not supported $support", E_USER_WARNING); + } + } + + $forbidden_properties = $config->get('CSS.ForbiddenProperties'); + if ($forbidden_properties !== null) { + foreach ($this->info as $name => $d) { + if (isset($forbidden_properties[$name])) { + unset($this->info[$name]); + } + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php new file mode 100755 index 00000000..8eb17b82 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php @@ -0,0 +1,52 @@ +elements; + } + + /** + * Validates nodes according to definition and returns modification. + * + * @param HTMLPurifier_Node[] $children Array of HTMLPurifier_Node + * @param HTMLPurifier_Config $config HTMLPurifier_Config object + * @param HTMLPurifier_Context $context HTMLPurifier_Context object + * @return bool|array true to leave nodes as is, false to remove parent node, array of replacement children + */ + abstract public function validateChildren($children, $config, $context); +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php new file mode 100755 index 00000000..7439be26 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php @@ -0,0 +1,67 @@ +inline = new HTMLPurifier_ChildDef_Optional($inline); + $this->block = new HTMLPurifier_ChildDef_Optional($block); + $this->elements = $this->block->elements; + } + + /** + * @param HTMLPurifier_Node[] $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function validateChildren($children, $config, $context) + { + if ($context->get('IsInline') === false) { + return $this->block->validateChildren( + $children, + $config, + $context + ); + } else { + return $this->inline->validateChildren( + $children, + $config, + $context + ); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php new file mode 100755 index 00000000..f515888a --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php @@ -0,0 +1,102 @@ +dtd_regex = $dtd_regex; + $this->_compileRegex(); + } + + /** + * Compiles the PCRE regex from a DTD regex ($dtd_regex to $_pcre_regex) + */ + protected function _compileRegex() + { + $raw = str_replace(' ', '', $this->dtd_regex); + if ($raw[0] != '(') { + $raw = "($raw)"; + } + $el = '[#a-zA-Z0-9_.-]+'; + $reg = $raw; + + // COMPLICATED! AND MIGHT BE BUGGY! I HAVE NO CLUE WHAT I'M + // DOING! Seriously: if there's problems, please report them. + + // collect all elements into the $elements array + preg_match_all("/$el/", $reg, $matches); + foreach ($matches[0] as $match) { + $this->elements[$match] = true; + } + + // setup all elements as parentheticals with leading commas + $reg = preg_replace("/$el/", '(,\\0)', $reg); + + // remove commas when they were not solicited + $reg = preg_replace("/([^,(|]\(+),/", '\\1', $reg); + + // remove all non-paranthetical commas: they are handled by first regex + $reg = preg_replace("/,\(/", '(', $reg); + + $this->_pcre_regex = $reg; + } + + /** + * @param HTMLPurifier_Node[] $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function validateChildren($children, $config, $context) + { + $list_of_children = ''; + $nesting = 0; // depth into the nest + foreach ($children as $node) { + if (!empty($node->is_whitespace)) { + continue; + } + $list_of_children .= $node->name . ','; + } + // add leading comma to deal with stray comma declarations + $list_of_children = ',' . rtrim($list_of_children, ','); + $okay = + preg_match( + '/^,?' . $this->_pcre_regex . '$/', + $list_of_children + ); + return (bool)$okay; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php new file mode 100755 index 00000000..a8a6cbdd --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php @@ -0,0 +1,38 @@ + true, 'ul' => true, 'ol' => true); + + public $whitespace; + + /** + * @param array $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function validateChildren($children, $config, $context) + { + // Flag for subclasses + $this->whitespace = false; + + // if there are no tokens, delete parent node + if (empty($children)) { + return false; + } + + // if li is not allowed, delete parent node + if (!isset($config->getHTMLDefinition()->info['li'])) { + trigger_error("Cannot allow ul/ol without allowing li", E_USER_WARNING); + return false; + } + + // the new set of children + $result = array(); + + // a little sanity check to make sure it's not ALL whitespace + $all_whitespace = true; + + $current_li = null; + + foreach ($children as $node) { + if (!empty($node->is_whitespace)) { + $result[] = $node; + continue; + } + $all_whitespace = false; // phew, we're not talking about whitespace + + if ($node->name === 'li') { + // good + $current_li = $node; + $result[] = $node; + } else { + // we want to tuck this into the previous li + // Invariant: we expect the node to be ol/ul + // ToDo: Make this more robust in the case of not ol/ul + // by distinguishing between existing li and li created + // to handle non-list elements; non-list elements should + // not be appended to an existing li; only li created + // for non-list. This distinction is not currently made. + if ($current_li === null) { + $current_li = new HTMLPurifier_Node_Element('li'); + $result[] = $current_li; + } + $current_li->children[] = $node; + $current_li->empty = false; // XXX fascinating! Check for this error elsewhere ToDo + } + } + if (empty($result)) { + return false; + } + if ($all_whitespace) { + return false; + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php new file mode 100755 index 00000000..b9468063 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php @@ -0,0 +1,45 @@ +whitespace) { + return $children; + } else { + return array(); + } + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php new file mode 100755 index 00000000..0d1c8f5f --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php @@ -0,0 +1,118 @@ + $x) { + $elements[$i] = true; + if (empty($i)) { + unset($elements[$i]); + } // remove blank + } + } + $this->elements = $elements; + } + + /** + * @type bool + */ + public $allow_empty = false; + + /** + * @type string + */ + public $type = 'required'; + + /** + * @param array $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function validateChildren($children, $config, $context) + { + // Flag for subclasses + $this->whitespace = false; + + // if there are no tokens, delete parent node + if (empty($children)) { + return false; + } + + // the new set of children + $result = array(); + + // whether or not parsed character data is allowed + // this controls whether or not we silently drop a tag + // or generate escaped HTML from it + $pcdata_allowed = isset($this->elements['#PCDATA']); + + // a little sanity check to make sure it's not ALL whitespace + $all_whitespace = true; + + $stack = array_reverse($children); + while (!empty($stack)) { + $node = array_pop($stack); + if (!empty($node->is_whitespace)) { + $result[] = $node; + continue; + } + $all_whitespace = false; // phew, we're not talking about whitespace + + if (!isset($this->elements[$node->name])) { + // special case text + // XXX One of these ought to be redundant or something + if ($pcdata_allowed && $node instanceof HTMLPurifier_Node_Text) { + $result[] = $node; + continue; + } + // spill the child contents in + // ToDo: Make configurable + if ($node instanceof HTMLPurifier_Node_Element) { + for ($i = count($node->children) - 1; $i >= 0; $i--) { + $stack[] = $node->children[$i]; + } + continue; + } + continue; + } + $result[] = $node; + } + if (empty($result)) { + return false; + } + if ($all_whitespace) { + $this->whitespace = true; + return false; + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php new file mode 100755 index 00000000..3270a46e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php @@ -0,0 +1,110 @@ +init($config); + return $this->fake_elements; + } + + /** + * @param array $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function validateChildren($children, $config, $context) + { + $this->init($config); + + // trick the parent class into thinking it allows more + $this->elements = $this->fake_elements; + $result = parent::validateChildren($children, $config, $context); + $this->elements = $this->real_elements; + + if ($result === false) { + return array(); + } + if ($result === true) { + $result = $children; + } + + $def = $config->getHTMLDefinition(); + $block_wrap_name = $def->info_block_wrapper; + $block_wrap = false; + $ret = array(); + + foreach ($result as $node) { + if ($block_wrap === false) { + if (($node instanceof HTMLPurifier_Node_Text && !$node->is_whitespace) || + ($node instanceof HTMLPurifier_Node_Element && !isset($this->elements[$node->name]))) { + $block_wrap = new HTMLPurifier_Node_Element($def->info_block_wrapper); + $ret[] = $block_wrap; + } + } else { + if ($node instanceof HTMLPurifier_Node_Element && isset($this->elements[$node->name])) { + $block_wrap = false; + + } + } + if ($block_wrap) { + $block_wrap->children[] = $node; + } else { + $ret[] = $node; + } + } + return $ret; + } + + /** + * @param HTMLPurifier_Config $config + */ + private function init($config) + { + if (!$this->init) { + $def = $config->getHTMLDefinition(); + // allow all inline elements + $this->real_elements = $this->elements; + $this->fake_elements = $def->info_content_sets['Flow']; + $this->fake_elements['#PCDATA'] = true; + $this->init = true; + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php new file mode 100755 index 00000000..67c7e953 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php @@ -0,0 +1,224 @@ + true, + 'tbody' => true, + 'thead' => true, + 'tfoot' => true, + 'caption' => true, + 'colgroup' => true, + 'col' => true + ); + + public function __construct() + { + } + + /** + * @param array $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function validateChildren($children, $config, $context) + { + if (empty($children)) { + return false; + } + + // only one of these elements is allowed in a table + $caption = false; + $thead = false; + $tfoot = false; + + // whitespace + $initial_ws = array(); + $after_caption_ws = array(); + $after_thead_ws = array(); + $after_tfoot_ws = array(); + + // as many of these as you want + $cols = array(); + $content = array(); + + $tbody_mode = false; // if true, then we need to wrap any stray + //
+ This directive turns on auto-paragraphing, where double newlines are + converted in to paragraphs whenever possible. Auto-paragraphing: +
+
+ p tags must be allowed for this directive to take effect.
+ We do not use br tags for paragraphing, as that is
+ semantically incorrect.
+
+ To prevent auto-paragraphing as a content-producer, refrain from using
+ double-newlines except to specify a new paragraph or in contexts where
+ it has special meaning (whitespace usually has no meaning except in
+ tags like pre, so this should not be difficult.) To prevent
+ the paragraphing of inline text adjacent to block elements, wrap them
+ in div tags (the behavior is slightly different outside of
+ the root node.)
+
+ This directive can be used to add custom auto-format injectors. + Specify an array of injector names (class name minus the prefix) + or concrete implementations. Injector class must exist. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt new file mode 100755 index 00000000..663064a3 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt @@ -0,0 +1,11 @@ +AutoFormat.DisplayLinkURI +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- ++ This directive turns on the in-text display of URIs in <a> tags, and disables + those links. For example, example becomes + example (http://example.com). +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt new file mode 100755 index 00000000..3a48ba96 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt @@ -0,0 +1,12 @@ +AutoFormat.Linkify +TYPE: bool +VERSION: 2.0.1 +DEFAULT: false +--DESCRIPTION-- + +
+ This directive turns on linkification, auto-linking http, ftp and
+ https URLs. a tags with the href attribute
+ must be allowed.
+
+ Location of configuration documentation to link to, let %s substitute + into the configuration's namespace and directive names sans the percent + sign. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt new file mode 100755 index 00000000..7996488b --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt @@ -0,0 +1,12 @@ +AutoFormat.PurifierLinkify +TYPE: bool +VERSION: 2.0.1 +DEFAULT: false +--DESCRIPTION-- + +
+ Internal auto-formatter that converts configuration directives in
+ syntax %Namespace.Directive to links. a tags
+ with the href attribute must be allowed.
+
+ Given that an element has no contents, it will be removed by default, unless
+ this predicate dictates otherwise. The predicate can either be an associative
+ map from tag name to list of attributes that must be present for the element
+ to be considered preserved: thus, the default always preserves colgroup,
+ th and td, and also iframe if it
+ has a src.
+
+ When %AutoFormat.RemoveEmpty and %AutoFormat.RemoveEmpty.RemoveNbsp + are enabled, this directive defines what HTML elements should not be + removede if they have only a non-breaking space in them. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt new file mode 100755 index 00000000..9228dee2 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt @@ -0,0 +1,15 @@ +AutoFormat.RemoveEmpty.RemoveNbsp +TYPE: bool +VERSION: 4.0.0 +DEFAULT: false +--DESCRIPTION-- ++ When enabled, HTML Purifier will treat any elements that contain only + non-breaking spaces as well as regular whitespace as empty, and remove + them when %AutoFormat.RemoveEmpty is enabled. +
++ See %AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions for a list of elements + that don't have this behavior applied to them. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt new file mode 100755 index 00000000..34657ba4 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt @@ -0,0 +1,46 @@ +AutoFormat.RemoveEmpty +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- ++ When enabled, HTML Purifier will attempt to remove empty elements that + contribute no semantic information to the document. The following types + of nodes will be removed: +
+<a></a> but not
+ <br />), and
+ colgroup element, orid or name attribute,
+ when those attributes are permitted on those elements.
+ + Please be very careful when using this functionality; while it may not + seem that empty elements contain useful information, they can alter the + layout of a document given appropriate styling. This directive is most + useful when you are processing machine-generated HTML, please avoid using + it on regular user HTML. +
++ Elements that contain only whitespace will be treated as empty. Non-breaking + spaces, however, do not count as whitespace. See + %AutoFormat.RemoveEmpty.RemoveNbsp for alternate behavior. +
++ This algorithm is not perfect; you may still notice some empty tags, + particularly if a node had elements, but those elements were later removed + because they were not permitted in that context, or tags that, after + being auto-closed by another tag, where empty. This is for safety reasons + to prevent clever code from breaking validation. The general rule of thumb: + if a tag looked empty on the way in, it will get removed; if HTML Purifier + made it empty, it will stay. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt new file mode 100755 index 00000000..dde990ab --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt @@ -0,0 +1,11 @@ +AutoFormat.RemoveSpansWithoutAttributes +TYPE: bool +VERSION: 4.0.1 +DEFAULT: false +--DESCRIPTION-- +
+ This directive causes span tags without any attributes
+ to be removed. It will also remove spans that had all attributes
+ removed during processing.
+
+ By default, HTML Purifier removes duplicate CSS properties,
+ like color:red; color:blue. If this is set to
+ true, duplicate properties are allowed.
+
display:none; is considered a tricky property that
+will only be allowed if this directive is set to true.
+--# vim: et sw=4 sts=4
diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt
new file mode 100755
index 00000000..3fd46540
--- /dev/null
+++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt
@@ -0,0 +1,12 @@
+CSS.AllowedFonts
+TYPE: lookup/null
+VERSION: 4.3.0
+DEFAULT: NULL
+--DESCRIPTION--
+
+ Allows you to manually specify a set of allowed fonts. If
+ NULL, all fonts are allowed. This directive
+ affects generic names (serif, sans-serif, monospace, cursive,
+ fantasy) as well as specific font families.
+
+ If HTML Purifier's style attributes set is unsatisfactory for your needs, + you can overload it with your own list of tags to allow. Note that this + method is subtractive: it does its job by taking away from HTML Purifier + usual feature set, so you cannot add an attribute that HTML Purifier never + supported in the first place. +
++ Warning: If another directive conflicts with the + elements here, that directive will win and override. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt new file mode 100755 index 00000000..5cb7dda3 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt @@ -0,0 +1,11 @@ +CSS.DefinitionRev +TYPE: int +VERSION: 2.0.0 +DEFAULT: 1 +--DESCRIPTION-- + ++ Revision identifier for your custom definition. See + %HTML.DefinitionRev for details. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt new file mode 100755 index 00000000..f1f5c5f1 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt @@ -0,0 +1,13 @@ +CSS.ForbiddenProperties +TYPE: lookup +VERSION: 4.2.0 +DEFAULT: array() +--DESCRIPTION-- ++ This is the logical inverse of %CSS.AllowedProperties, and it will + override that directive or any other directive. If possible, + %CSS.AllowedProperties is recommended over this directive, + because it can sometimes be difficult to tell whether or not you've + forbidden all of the CSS properties you truly would like to disallow. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt new file mode 100755 index 00000000..7a329147 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt @@ -0,0 +1,16 @@ +CSS.MaxImgLength +TYPE: string/null +DEFAULT: '1200px' +VERSION: 3.1.1 +--DESCRIPTION-- +
+ This parameter sets the maximum allowed length on img tags,
+ effectively the width and height properties.
+ Only absolute units of measurement (in, pt, pc, mm, cm) and pixels (px) are allowed. This is
+ in place to prevent imagecrash attacks, disable with null at your own risk.
+ This directive is similar to %HTML.MaxImgLength, and both should be
+ concurrently edited, although there are
+ subtle differences in the input format (the CSS max is a number with
+ a unit).
+
+ Whether or not to allow safe, proprietary CSS values. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt new file mode 100755 index 00000000..e733a61e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt @@ -0,0 +1,9 @@ +CSS.Trusted +TYPE: bool +VERSION: 4.2.1 +DEFAULT: false +--DESCRIPTION-- +Indicates whether or not the user's CSS input is trusted or not. If the +input is trusted, a more expansive set of allowed properties. See +also %HTML.Trusted. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt new file mode 100755 index 00000000..c486724c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt @@ -0,0 +1,14 @@ +Cache.DefinitionImpl +TYPE: string/null +VERSION: 2.0.0 +DEFAULT: 'Serializer' +--DESCRIPTION-- + +This directive defines which method to use when caching definitions, +the complex data-type that makes HTML Purifier tick. Set to null +to disable caching (not recommended, as you will see a definite +performance degradation). + +--ALIASES-- +Core.DefinitionCache +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt new file mode 100755 index 00000000..54036507 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt @@ -0,0 +1,13 @@ +Cache.SerializerPath +TYPE: string/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + ++ Absolute path with no trailing slash to store serialized definitions in. + Default is within the + HTML Purifier library inside DefinitionCache/Serializer. This + path must be writable by the webserver. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt new file mode 100755 index 00000000..2e0cc810 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt @@ -0,0 +1,16 @@ +Cache.SerializerPermissions +TYPE: int/null +VERSION: 4.3.0 +DEFAULT: 0755 +--DESCRIPTION-- + ++ Directory permissions of the files and directories created inside + the DefinitionCache/Serializer or other custom serializer path. +
+
+ In HTML Purifier 4.8.0, this also supports NULL,
+ which means that no chmod'ing or directory creation shall
+ occur.
+
+ This directive enables aggressive pre-filter fixes HTML Purifier can + perform in order to ensure that open angled-brackets do not get killed + during parsing stage. Enabling this will result in two preg_replace_callback + calls and at least two preg_replace calls for every HTML document parsed; + if your users make very well-formed HTML, you can set this directive false. + This has no effect when DirectLex is used. +
++ Notice: This directive's default turned from false to true + in HTML Purifier 3.2.0. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyRemoveScript.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyRemoveScript.txt new file mode 100755 index 00000000..b2b6ab14 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyRemoveScript.txt @@ -0,0 +1,16 @@ +Core.AggressivelyRemoveScript +TYPE: bool +VERSION: 4.9.0 +DEFAULT: true +--DESCRIPTION-- ++ This directive enables aggressive pre-filter removal of + script tags. This is not necessary for security, + but it can help work around a bug in libxml where embedded + HTML elements inside script sections cause the parser to + choke. To revert to pre-4.9.0 behavior, set this to false. + This directive has no effect if %Core.Trusted is true, + %Core.RemoveScriptContents is false, or %Core.HiddenElements + does not contain script. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt new file mode 100755 index 00000000..2c910cc7 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt @@ -0,0 +1,16 @@ +Core.AllowHostnameUnderscore +TYPE: bool +VERSION: 4.6.0 +DEFAULT: false +--DESCRIPTION-- ++ By RFC 1123, underscores are not permitted in host names. + (This is in contrast to the specification for DNS, RFC + 2181, which allows underscores.) + However, most browsers do the right thing when faced with + an underscore in the host name, and so some poorly written + websites are written with the expectation this should work. + Setting this parameter to true relaxes our allowed character + check so that underscores are permitted. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowParseManyTags.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowParseManyTags.txt new file mode 100755 index 00000000..06278f82 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowParseManyTags.txt @@ -0,0 +1,12 @@ +Core.AllowParseManyTags +TYPE: bool +DEFAULT: false +VERSION: 4.10.1 +--DESCRIPTION-- ++ This directive allows parsing of many nested tags. + If you set true, relaxes any hardcoded limit from the parser. + However, in that case it may cause a Dos attack. + Be careful when enabling it. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt new file mode 100755 index 00000000..d7317911 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt @@ -0,0 +1,12 @@ +Core.CollectErrors +TYPE: bool +VERSION: 2.0.0 +DEFAULT: false +--DESCRIPTION-- + +Whether or not to collect errors found while filtering the document. This +is a useful way to give feedback to your users. Warning: +Currently this feature is very patchy and experimental, with lots of +possible error messages not yet implemented. It will not cause any +problems, but it may not help your users either. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt new file mode 100755 index 00000000..a75844cd --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt @@ -0,0 +1,160 @@ +Core.ColorKeywords +TYPE: hash +VERSION: 2.0.0 +--DEFAULT-- +array ( + 'aliceblue' => '#F0F8FF', + 'antiquewhite' => '#FAEBD7', + 'aqua' => '#00FFFF', + 'aquamarine' => '#7FFFD4', + 'azure' => '#F0FFFF', + 'beige' => '#F5F5DC', + 'bisque' => '#FFE4C4', + 'black' => '#000000', + 'blanchedalmond' => '#FFEBCD', + 'blue' => '#0000FF', + 'blueviolet' => '#8A2BE2', + 'brown' => '#A52A2A', + 'burlywood' => '#DEB887', + 'cadetblue' => '#5F9EA0', + 'chartreuse' => '#7FFF00', + 'chocolate' => '#D2691E', + 'coral' => '#FF7F50', + 'cornflowerblue' => '#6495ED', + 'cornsilk' => '#FFF8DC', + 'crimson' => '#DC143C', + 'cyan' => '#00FFFF', + 'darkblue' => '#00008B', + 'darkcyan' => '#008B8B', + 'darkgoldenrod' => '#B8860B', + 'darkgray' => '#A9A9A9', + 'darkgrey' => '#A9A9A9', + 'darkgreen' => '#006400', + 'darkkhaki' => '#BDB76B', + 'darkmagenta' => '#8B008B', + 'darkolivegreen' => '#556B2F', + 'darkorange' => '#FF8C00', + 'darkorchid' => '#9932CC', + 'darkred' => '#8B0000', + 'darksalmon' => '#E9967A', + 'darkseagreen' => '#8FBC8F', + 'darkslateblue' => '#483D8B', + 'darkslategray' => '#2F4F4F', + 'darkslategrey' => '#2F4F4F', + 'darkturquoise' => '#00CED1', + 'darkviolet' => '#9400D3', + 'deeppink' => '#FF1493', + 'deepskyblue' => '#00BFFF', + 'dimgray' => '#696969', + 'dimgrey' => '#696969', + 'dodgerblue' => '#1E90FF', + 'firebrick' => '#B22222', + 'floralwhite' => '#FFFAF0', + 'forestgreen' => '#228B22', + 'fuchsia' => '#FF00FF', + 'gainsboro' => '#DCDCDC', + 'ghostwhite' => '#F8F8FF', + 'gold' => '#FFD700', + 'goldenrod' => '#DAA520', + 'gray' => '#808080', + 'grey' => '#808080', + 'green' => '#008000', + 'greenyellow' => '#ADFF2F', + 'honeydew' => '#F0FFF0', + 'hotpink' => '#FF69B4', + 'indianred' => '#CD5C5C', + 'indigo' => '#4B0082', + 'ivory' => '#FFFFF0', + 'khaki' => '#F0E68C', + 'lavender' => '#E6E6FA', + 'lavenderblush' => '#FFF0F5', + 'lawngreen' => '#7CFC00', + 'lemonchiffon' => '#FFFACD', + 'lightblue' => '#ADD8E6', + 'lightcoral' => '#F08080', + 'lightcyan' => '#E0FFFF', + 'lightgoldenrodyellow' => '#FAFAD2', + 'lightgray' => '#D3D3D3', + 'lightgrey' => '#D3D3D3', + 'lightgreen' => '#90EE90', + 'lightpink' => '#FFB6C1', + 'lightsalmon' => '#FFA07A', + 'lightseagreen' => '#20B2AA', + 'lightskyblue' => '#87CEFA', + 'lightslategray' => '#778899', + 'lightslategrey' => '#778899', + 'lightsteelblue' => '#B0C4DE', + 'lightyellow' => '#FFFFE0', + 'lime' => '#00FF00', + 'limegreen' => '#32CD32', + 'linen' => '#FAF0E6', + 'magenta' => '#FF00FF', + 'maroon' => '#800000', + 'mediumaquamarine' => '#66CDAA', + 'mediumblue' => '#0000CD', + 'mediumorchid' => '#BA55D3', + 'mediumpurple' => '#9370DB', + 'mediumseagreen' => '#3CB371', + 'mediumslateblue' => '#7B68EE', + 'mediumspringgreen' => '#00FA9A', + 'mediumturquoise' => '#48D1CC', + 'mediumvioletred' => '#C71585', + 'midnightblue' => '#191970', + 'mintcream' => '#F5FFFA', + 'mistyrose' => '#FFE4E1', + 'moccasin' => '#FFE4B5', + 'navajowhite' => '#FFDEAD', + 'navy' => '#000080', + 'oldlace' => '#FDF5E6', + 'olive' => '#808000', + 'olivedrab' => '#6B8E23', + 'orange' => '#FFA500', + 'orangered' => '#FF4500', + 'orchid' => '#DA70D6', + 'palegoldenrod' => '#EEE8AA', + 'palegreen' => '#98FB98', + 'paleturquoise' => '#AFEEEE', + 'palevioletred' => '#DB7093', + 'papayawhip' => '#FFEFD5', + 'peachpuff' => '#FFDAB9', + 'peru' => '#CD853F', + 'pink' => '#FFC0CB', + 'plum' => '#DDA0DD', + 'powderblue' => '#B0E0E6', + 'purple' => '#800080', + 'rebeccapurple' => '#663399', + 'red' => '#FF0000', + 'rosybrown' => '#BC8F8F', + 'royalblue' => '#4169E1', + 'saddlebrown' => '#8B4513', + 'salmon' => '#FA8072', + 'sandybrown' => '#F4A460', + 'seagreen' => '#2E8B57', + 'seashell' => '#FFF5EE', + 'sienna' => '#A0522D', + 'silver' => '#C0C0C0', + 'skyblue' => '#87CEEB', + 'slateblue' => '#6A5ACD', + 'slategray' => '#708090', + 'slategrey' => '#708090', + 'snow' => '#FFFAFA', + 'springgreen' => '#00FF7F', + 'steelblue' => '#4682B4', + 'tan' => '#D2B48C', + 'teal' => '#008080', + 'thistle' => '#D8BFD8', + 'tomato' => '#FF6347', + 'turquoise' => '#40E0D0', + 'violet' => '#EE82EE', + 'wheat' => '#F5DEB3', + 'white' => '#FFFFFF', + 'whitesmoke' => '#F5F5F5', + 'yellow' => '#FFFF00', + 'yellowgreen' => '#9ACD32' +) +--DESCRIPTION-- + +Lookup array of color names to six digit hexadecimal number corresponding +to color, with preceding hash mark. Used when parsing colors. The lookup +is done in a case-insensitive manner. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt new file mode 100755 index 00000000..64b114fc --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt @@ -0,0 +1,14 @@ +Core.ConvertDocumentToFragment +TYPE: bool +DEFAULT: true +--DESCRIPTION-- + +This parameter determines whether or not the filter should convert +input that is a full document with html and body tags to a fragment +of just the contents of a body tag. This parameter is simply something +HTML Purifier can do during an edge-case: for most inputs, this +processing is not necessary. + +--ALIASES-- +Core.AcceptFullDocuments +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt new file mode 100755 index 00000000..36f16e07 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt @@ -0,0 +1,17 @@ +Core.DirectLexLineNumberSyncInterval +TYPE: int +VERSION: 2.0.0 +DEFAULT: 0 +--DESCRIPTION-- + ++ Specifies the number of tokens the DirectLex line number tracking + implementations should process before attempting to resyncronize the + current line count by manually counting all previous new-lines. When + at 0, this functionality is disabled. Lower values will decrease + performance, and this is only strictly necessary if the counting + algorithm is buggy (in which case you should report it as a bug). + This has no effect when %Core.MaintainLineNumbers is disabled or DirectLex is + not being used. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt new file mode 100755 index 00000000..1cd4c2c9 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt @@ -0,0 +1,14 @@ +Core.DisableExcludes +TYPE: bool +DEFAULT: false +VERSION: 4.5.0 +--DESCRIPTION-- +
+ This directive disables SGML-style exclusions, e.g. the exclusion of
+ <object> in any descendant of a
+ <pre> tag. Disabling excludes will allow some
+ invalid documents to pass through HTML Purifier, but HTML Purifier
+ will also be less likely to accidentally remove large documents during
+ processing.
+
Warning: this configuration option is no longer does anything as of 4.6.0.
+ +When true, a child is found that is not allowed in the context of the +parent element will be transformed into text as if it were ASCII. When +false, that element and all internal tags will be dropped, though text will +be preserved. There is no option for dropping the element but preserving +child nodes.
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt new file mode 100755 index 00000000..a7a5b249 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt @@ -0,0 +1,7 @@ +Core.EscapeInvalidTags +TYPE: bool +DEFAULT: false +--DESCRIPTION-- +When true, invalid tags will be written back to the document as plain text. +Otherwise, they are silently dropped. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt new file mode 100755 index 00000000..abb49994 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt @@ -0,0 +1,13 @@ +Core.EscapeNonASCIICharacters +TYPE: bool +VERSION: 1.4.0 +DEFAULT: false +--DESCRIPTION-- +This directive overcomes a deficiency in %Core.Encoding by blindly +converting all non-ASCII characters into decimal numeric entities before +converting it to its native encoding. This means that even characters that +can be expressed in the non-UTF-8 encoding will be entity-ized, which can +be a real downer for encodings like Big5. It also assumes that the ASCII +repetoire is available, although this is the case for almost all encodings. +Anyway, use UTF-8! +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt new file mode 100755 index 00000000..915391ed --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt @@ -0,0 +1,19 @@ +Core.HiddenElements +TYPE: lookup +--DEFAULT-- +array ( + 'script' => true, + 'style' => true, +) +--DESCRIPTION-- + +
+ This directive is a lookup array of elements which should have their
+ contents removed when they are not allowed by the HTML definition.
+ For example, the contents of a script tag are not
+ normally shown in a document, so if script tags are to be removed,
+ their contents should be removed to. This is opposed to a b
+ tag, which defines some presentational changes but does not hide its
+ contents.
+
+ Prior to HTML Purifier 4.9.0, entities were decoded by performing + a global search replace for all entities whose decoded versions + did not have special meanings under HTML, and replaced them with + their decoded versions. We would match all entities, even if they did + not have a trailing semicolon, but only if there weren't any trailing + alphanumeric characters. +
+| Original | Text | Attribute |
|---|---|---|
| ¥ | ¥ | ¥ |
| ¥ | ¥ | ¥ |
| ¥a | ¥a | ¥a |
| ¥= | ¥= | ¥= |
+ In HTML Purifier 4.9.0, we changed the behavior of entity parsing + to match entities that had missing trailing semicolons in less + cases, to more closely match HTML5 parsing behavior: +
+| Original | Text | Attribute |
|---|---|---|
| ¥ | ¥ | ¥ |
| ¥ | ¥ | ¥ |
| ¥a | ¥a | ¥a |
| ¥= | ¥= | ¥= |
+ This flag reverts back to pre-HTML Purifier 4.9.0 behavior. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt new file mode 100755 index 00000000..8983e2cc --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt @@ -0,0 +1,34 @@ +Core.LexerImpl +TYPE: mixed/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + ++ This parameter determines what lexer implementation can be used. The + valid values are: +
+HTMLPurifier_Lexer.
+ I may remove this option simply because I don't expect anyone
+ to use it.
+ + If true, HTML Purifier will add line number information to all tokens. + This is useful when error reporting is turned on, but can result in + significant performance degradation and should not be used when + unnecessary. This directive must be used with the DirectLex lexer, + as the DOMLex lexer does not (yet) support this functionality. + If the value is null, an appropriate value will be selected based + on other configuration. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt new file mode 100755 index 00000000..d77f5360 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt @@ -0,0 +1,11 @@ +Core.NormalizeNewlines +TYPE: bool +VERSION: 4.2.0 +DEFAULT: true +--DESCRIPTION-- +
+ Whether or not to normalize newlines to the operating
+ system default. When false, HTML Purifier
+ will attempt to preserve mixed newline files.
+
+ This directive enables pre-emptive URI checking in img
+ tags, as the attribute validation strategy is not authorized to
+ remove elements from the document. Revert to pre-1.3.0 behavior by setting to false.
+
<? ...
+?>, remove it out-right. This may be useful if the HTML
+you are validating contains XML processing instruction gunk, however,
+it can also be user-unfriendly for people attempting to post PHP
+snippets.
+--# vim: et sw=4 sts=4
diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt
new file mode 100755
index 00000000..a4cd966d
--- /dev/null
+++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt
@@ -0,0 +1,12 @@
+Core.RemoveScriptContents
+TYPE: bool/null
+DEFAULT: NULL
+VERSION: 2.0.0
+DEPRECATED-VERSION: 2.1.0
+DEPRECATED-USE: Core.HiddenElements
+--DESCRIPTION--
++ This directive enables HTML Purifier to remove not only script tags + but all of their contents. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt new file mode 100755 index 00000000..3db50ef2 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt @@ -0,0 +1,11 @@ +Filter.Custom +TYPE: list +VERSION: 3.1.0 +DEFAULT: array() +--DESCRIPTION-- +
+ This directive can be used to add custom filters; it is nearly the
+ equivalent of the now deprecated HTMLPurifier->addFilter()
+ method. Specify an array of concrete implementations.
+
+ Whether or not to escape the dangerous characters <, > and & + as \3C, \3E and \26, respectively. This is can be safely set to false + if the contents of StyleBlocks will be placed in an external stylesheet, + where there is no risk of it being interpreted as HTML. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt new file mode 100755 index 00000000..7f95f54d --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt @@ -0,0 +1,29 @@ +Filter.ExtractStyleBlocks.Scope +TYPE: string/null +VERSION: 3.0.0 +DEFAULT: NULL +ALIASES: Filter.ExtractStyleBlocksScope, FilterParam.ExtractStyleBlocksScope +--DESCRIPTION-- + +
+ If you would like users to be able to define external stylesheets, but
+ only allow them to specify CSS declarations for a specific node and
+ prevent them from fiddling with other elements, use this directive.
+ It accepts any valid CSS selector, and will prepend this to any
+ CSS declaration extracted from the document. For example, if this
+ directive is set to #user-content and a user uses the
+ selector a:hover, the final selector will be
+ #user-content a:hover.
+
+ The comma shorthand may be used; consider the above example, with
+ #user-content, #user-content2, the final selector will
+ be #user-content a:hover, #user-content2 a:hover.
+
+ Warning: It is possible for users to bypass this measure + using a naughty + selector. This is a bug in CSS Tidy 1.3, not HTML + Purifier, and I am working to get it fixed. Until then, HTML Purifier + performs a basic check to prevent this. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt new file mode 100755 index 00000000..6c231b2d --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt @@ -0,0 +1,16 @@ +Filter.ExtractStyleBlocks.TidyImpl +TYPE: mixed/null +VERSION: 3.1.0 +DEFAULT: NULL +ALIASES: FilterParam.ExtractStyleBlocksTidyImpl +--DESCRIPTION-- +
+ If left NULL, HTML Purifier will attempt to instantiate a csstidy
+ class to use for internal cleaning. This will usually be good enough.
+
+ However, for trusted user input, you can set this to false to
+ disable cleaning. In addition, you can supply your own concrete implementation
+ of Tidy's interface to use, although I don't know why you'd want to do that.
+
+ This directive turns on the style block extraction filter, which removes
+ style blocks from input HTML, cleans them up with CSSTidy,
+ and places them in the StyleBlocks context variable, for further
+ use by you, usually to be placed in an external stylesheet, or a
+ style block in the head of your document.
+
+ Sample usage: +
+'; +?> + + + ++Filter.ExtractStyleBlocks +body {color:#F00;} Some text'; + + $config = HTMLPurifier_Config::createDefault(); + $config->set('Filter', 'ExtractStyleBlocks', true); + $purifier = new HTMLPurifier($config); + + $html = $purifier->purify($dirty); + + // This implementation writes the stylesheets to the styles/ directory. + // You can also echo the styles inside the document, but it's a bit + // more difficult to make sure they get interpreted properly by + // browsers; try the usual CSS armoring techniques. + $styles = $purifier->context->get('StyleBlocks'); + $dir = 'styles/'; + if (!is_dir($dir)) mkdir($dir); + $hash = sha1($_GET['html']); + foreach ($styles as $i => $style) { + file_put_contents($name = $dir . $hash . "_$i"); + echo ''; + } +?> + + ++ ++ + +]]>
+ Warning: It is possible for a user to mount an + imagecrash attack using this CSS. Counter-measures are difficult; + it is not simply enough to limit the range of CSS lengths (using + relative lengths with many nesting levels allows for large values + to be attained without actually specifying them in the stylesheet), + and the flexible nature of selectors makes it difficult to selectively + disable lengths on image tags (HTML Purifier, however, does disable + CSS width and height in inline styling). There are probably two effective + counter measures: an explicit width and height set to auto in all + images in your document (unlikely) or the disabling of width and + height (somewhat reasonable). Whether or not these measures should be + used is left to the reader. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt new file mode 100755 index 00000000..321eaa2d --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt @@ -0,0 +1,16 @@ +Filter.YouTube +TYPE: bool +VERSION: 3.1.0 +DEFAULT: false +--DESCRIPTION-- ++ Warning: Deprecated in favor of %HTML.SafeObject and + %Output.FlashCompat (turn both on to allow YouTube videos and other + Flash content). +
++ This directive enables YouTube video embedding in HTML Purifier. Check + this document + on embedding videos for more information on what this filter does. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt new file mode 100755 index 00000000..0b2c106d --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt @@ -0,0 +1,25 @@ +HTML.Allowed +TYPE: itext/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +
+ This is a preferred convenience directive that combines
+ %HTML.AllowedElements and %HTML.AllowedAttributes.
+ Specify elements and attributes that are allowed using:
+ element1[attr1|attr2],element2.... For example,
+ if you would like to only allow paragraphs and links, specify
+ a[href],p. You can specify attributes that apply
+ to all elements using an asterisk, e.g. *[lang].
+ You can also use newlines instead of commas to separate elements.
+
+ Warning:
+ All of the constraints on the component directives are still enforced.
+ The syntax is a subset of TinyMCE's valid_elements
+ whitelist: directly copy-pasting it here will probably result in
+ broken whitelists. If %HTML.AllowedElements or %HTML.AllowedAttributes
+ are set, this directive has no effect.
+
+ If HTML Purifier's attribute set is unsatisfactory, overload it! + The syntax is "tag.attr" or "*.attr" for the global attributes + (style, id, class, dir, lang, xml:lang). +
++ Warning: If another directive conflicts with the + elements here, that directive will win and override. For + example, %HTML.EnableAttrID will take precedence over *.id in this + directive. You must set that directive to true before you can use + IDs at all. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt new file mode 100755 index 00000000..140e2142 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt @@ -0,0 +1,10 @@ +HTML.AllowedComments +TYPE: lookup +VERSION: 4.4.0 +DEFAULT: array() +--DESCRIPTION-- +A whitelist which indicates what explicit comment bodies should be +allowed, modulo leading and trailing whitespace. See also %HTML.AllowedCommentsRegexp +(these directives are union'ed together, so a comment is considered +valid if any directive deems it valid.) +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt new file mode 100755 index 00000000..f22e977d --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt @@ -0,0 +1,15 @@ +HTML.AllowedCommentsRegexp +TYPE: string/null +VERSION: 4.4.0 +DEFAULT: NULL +--DESCRIPTION-- +A regexp, which if it matches the body of a comment, indicates that +it should be allowed. Trailing and leading spaces are removed prior +to running this regular expression. +Warning: Make sure you specify +correct anchor metacharacters^regex$, otherwise you may accept
+comments that you did not mean to! In particular, the regex /foo|bar/
+is probably not sufficiently strict, since it also allows foobar.
+See also %HTML.AllowedComments (these directives are union'ed together,
+so a comment is considered valid if any directive deems it valid.)
+--# vim: et sw=4 sts=4
diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt
new file mode 100755
index 00000000..1d3fa790
--- /dev/null
+++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt
@@ -0,0 +1,23 @@
+HTML.AllowedElements
+TYPE: lookup/null
+VERSION: 1.3.0
+DEFAULT: NULL
+--DESCRIPTION--
++ If HTML Purifier's tag set is unsatisfactory for your needs, you can + overload it with your own list of tags to allow. If you change + this, you probably also want to change %HTML.AllowedAttributes; see + also %HTML.Allowed which lets you set allowed elements and + attributes at the same time. +
++ If you attempt to allow an element that HTML Purifier does not know + about, HTML Purifier will raise an error. You will need to manually + tell HTML Purifier about this element by using the + advanced customization features. +
++ Warning: If another directive conflicts with the + elements here, that directive will win and override. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt new file mode 100755 index 00000000..5a59a55c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt @@ -0,0 +1,20 @@ +HTML.AllowedModules +TYPE: lookup/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + ++ A doctype comes with a set of usual modules to use. Without having + to mucking about with the doctypes, you can quickly activate or + disable these modules by specifying which modules you wish to allow + with this directive. This is most useful for unit testing specific + modules, although end users may find it useful for their own ends. +
++ If you specify a module that does not exist, the manager will silently + fail to use it, so be careful! User-defined modules are not affected + by this directive. Modules defined in %HTML.CoreModules are not + affected by this directive. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt new file mode 100755 index 00000000..151fb7b8 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt @@ -0,0 +1,11 @@ +HTML.Attr.Name.UseCDATA +TYPE: bool +DEFAULT: false +VERSION: 4.0.0 +--DESCRIPTION-- +The W3C specification DTD defines the name attribute to be CDATA, not ID, due +to limitations of DTD. In certain documents, this relaxed behavior is desired, +whether it is to specify duplicate names, or to specify names that would be +illegal IDs (for example, names that begin with a digit.) Set this configuration +directive to true to use the relaxed parsing rules. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt new file mode 100755 index 00000000..45ae469e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt @@ -0,0 +1,18 @@ +HTML.BlockWrapper +TYPE: string +VERSION: 1.3.0 +DEFAULT: 'p' +--DESCRIPTION-- + ++ String name of element to wrap inline elements that are inside a block + context. This only occurs in the children of blockquote in strict mode. +
+
+ Example: by default value,
+ <blockquote>Foo</blockquote> would become
+ <blockquote><p>Foo</p></blockquote>.
+ The <p> tags can be replaced with whatever you desire,
+ as long as it is a block level element.
+
+ Certain modularized doctypes (XHTML, namely), have certain modules + that must be included for the doctype to be an conforming document + type: put those modules here. By default, XHTML's core modules + are used. You can set this to a blank array to disable core module + protection, but this is not recommended. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt new file mode 100755 index 00000000..6ed70b59 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt @@ -0,0 +1,9 @@ +HTML.CustomDoctype +TYPE: string/null +VERSION: 2.0.1 +DEFAULT: NULL +--DESCRIPTION-- + +A custom doctype for power-users who defined their own document +type. This directive only applies when %HTML.Doctype is blank. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt new file mode 100755 index 00000000..103db754 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt @@ -0,0 +1,33 @@ +HTML.DefinitionID +TYPE: string/null +DEFAULT: NULL +VERSION: 2.0.0 +--DESCRIPTION-- + ++ Unique identifier for a custom-built HTML definition. If you edit + the raw version of the HTMLDefinition, introducing changes that the + configuration object does not reflect, you must specify this variable. + If you change your custom edits, you should change this directive, or + clear your cache. Example: +
+
+$config = HTMLPurifier_Config::createDefault();
+$config->set('HTML', 'DefinitionID', '1');
+$def = $config->getHTMLDefinition();
+$def->addAttribute('a', 'tabindex', 'Number');
+
++ In the above example, the configuration is still at the defaults, but + using the advanced API, an extra attribute has been added. The + configuration object normally has no way of knowing that this change + has taken place, so it needs an extra directive: %HTML.DefinitionID. + If someone else attempts to use the default configuration, these two + pieces of code will not clobber each other in the cache, since one has + an extra directive attached to it. +
++ You must specify a value to this directive to use the + advanced API features. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt new file mode 100755 index 00000000..229ae026 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt @@ -0,0 +1,16 @@ +HTML.DefinitionRev +TYPE: int +VERSION: 2.0.0 +DEFAULT: 1 +--DESCRIPTION-- + ++ Revision identifier for your custom definition specified in + %HTML.DefinitionID. This serves the same purpose: uniquely identifying + your custom definition, but this one does so in a chronological + context: revision 3 is more up-to-date then revision 2. Thus, when + this gets incremented, the cache handling is smart enough to clean + up any older revisions of your definition as well as flush the + cache. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt new file mode 100755 index 00000000..9dab497f --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt @@ -0,0 +1,11 @@ +HTML.Doctype +TYPE: string/null +DEFAULT: NULL +--DESCRIPTION-- +Doctype to use during filtering. Technically speaking this is not actually +a doctype (as it does not identify a corresponding DTD), but we are using +this name for sake of simplicity. When non-blank, this will override any +older directives like %HTML.XHTML or %HTML.Strict. +--ALLOWED-- +'HTML 4.01 Transitional', 'HTML 4.01 Strict', 'XHTML 1.0 Transitional', 'XHTML 1.0 Strict', 'XHTML 1.1' +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt new file mode 100755 index 00000000..7878dc0b --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt @@ -0,0 +1,11 @@ +HTML.FlashAllowFullScreen +TYPE: bool +VERSION: 4.2.0 +DEFAULT: false +--DESCRIPTION-- +
+ Whether or not to permit embedded Flash content from
+ %HTML.SafeObject to expand to the full screen. Corresponds to
+ the allowFullScreen parameter.
+
+ While this directive is similar to %HTML.AllowedAttributes, for
+ forwards-compatibility with XML, this attribute has a different syntax. Instead of
+ tag.attr, use tag@attr. To disallow href
+ attributes in a tags, set this directive to
+ a@href. You can also disallow an attribute globally with
+ attr or *@attr (either syntax is fine; the latter
+ is provided for consistency with %HTML.AllowedAttributes).
+
+ Warning: This directive complements %HTML.ForbiddenElements, + accordingly, check + out that directive for a discussion of why you + should think twice before using this directive. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt new file mode 100755 index 00000000..93a53e14 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt @@ -0,0 +1,20 @@ +HTML.ForbiddenElements +TYPE: lookup +VERSION: 3.1.0 +DEFAULT: array() +--DESCRIPTION-- ++ This was, perhaps, the most requested feature ever in HTML + Purifier. Please don't abuse it! This is the logical inverse of + %HTML.AllowedElements, and it will override that directive, or any + other directive. +
+
+ If possible, %HTML.Allowed is recommended over this directive, because it
+ can sometimes be difficult to tell whether or not you've forbidden all of
+ the behavior you would like to disallow. If you forbid img
+ with the expectation of preventing images on your site, you'll be in for
+ a nasty surprise when people start using the background-image
+ CSS property.
+
+ Whether or not to permit form elements in the user input, regardless of + %HTML.Trusted value. Please be very careful when using this functionality, as + enabling forms in untrusted documents may allow for phishing attacks. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt new file mode 100755 index 00000000..e424c386 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt @@ -0,0 +1,14 @@ +HTML.MaxImgLength +TYPE: int/null +DEFAULT: 1200 +VERSION: 3.1.1 +--DESCRIPTION-- +
+ This directive controls the maximum number of pixels in the width and
+ height attributes in img tags. This is
+ in place to prevent imagecrash attacks, disable with null at your own risk.
+ This directive is similar to %CSS.MaxImgLength, and both should be
+ concurrently edited, although there are
+ subtle differences in the input format (the HTML max is an integer).
+
+ String name of element that HTML fragment passed to library will be + inserted in. An interesting variation would be using span as the + parent element, meaning that only inline tags would be allowed. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt new file mode 100755 index 00000000..dfb72049 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt @@ -0,0 +1,12 @@ +HTML.Proprietary +TYPE: bool +VERSION: 3.1.0 +DEFAULT: false +--DESCRIPTION-- +
+ Whether or not to allow proprietary elements and attributes in your
+ documents, as per HTMLPurifier_HTMLModule_Proprietary.
+ Warning: This can cause your documents to stop
+ validating!
+
+ Whether or not to permit embed tags in documents, with a number of extra + security features added to prevent script execution. This is similar to + what websites like MySpace do to embed tags. Embed is a proprietary + element and will cause your website to stop validating; you should + see if you can use %Output.FlashCompat with %HTML.SafeObject instead + first.
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt new file mode 100755 index 00000000..5eb6ec2b --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt @@ -0,0 +1,13 @@ +HTML.SafeIframe +TYPE: bool +VERSION: 4.4.0 +DEFAULT: false +--DESCRIPTION-- ++ Whether or not to permit iframe tags in untrusted documents. This + directive must be accompanied by a whitelist of permitted iframes, + such as %URI.SafeIframeRegexp, otherwise it will fatally error. + This directive has no effect on strict doctypes, as iframes are not + valid. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt new file mode 100755 index 00000000..ceb342e2 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt @@ -0,0 +1,13 @@ +HTML.SafeObject +TYPE: bool +VERSION: 3.1.1 +DEFAULT: false +--DESCRIPTION-- ++ Whether or not to permit object tags in documents, with a number of extra + security features added to prevent script execution. This is similar to + what websites like MySpace do to object tags. You should also enable + %Output.FlashCompat in order to generate Internet Explorer + compatibility code for your object tags. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt new file mode 100755 index 00000000..5ebc7a19 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt @@ -0,0 +1,10 @@ +HTML.SafeScripting +TYPE: lookup +VERSION: 4.5.0 +DEFAULT: array() +--DESCRIPTION-- ++ Whether or not to permit script tags to external scripts in documents. + Inline scripting is not allowed, and the script must match an explicit whitelist. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt new file mode 100755 index 00000000..a8b1de56 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt @@ -0,0 +1,9 @@ +HTML.Strict +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +DEPRECATED-VERSION: 1.7.0 +DEPRECATED-USE: HTML.Doctype +--DESCRIPTION-- +Determines whether or not to use Transitional (loose) or Strict rulesets. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt new file mode 100755 index 00000000..587a1677 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt @@ -0,0 +1,8 @@ +HTML.TargetBlank +TYPE: bool +VERSION: 4.4.0 +DEFAULT: FALSE +--DESCRIPTION-- +If enabled,target=blank attributes are added to all outgoing links.
+(This includes links from an HTTPS version of a page to an HTTP version.)
+--# vim: et sw=4 sts=4
diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoopener.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoopener.txt
new file mode 100755
index 00000000..dd514c0d
--- /dev/null
+++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoopener.txt
@@ -0,0 +1,10 @@
+--# vim: et sw=4 sts=4
+HTML.TargetNoopener
+TYPE: bool
+VERSION: 4.8.0
+DEFAULT: TRUE
+--DESCRIPTION--
+If enabled, noopener rel attributes are added to links which have
+a target attribute associated with them. This prevents malicious
+destinations from overwriting the original window.
+--# vim: et sw=4 sts=4
diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoreferrer.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoreferrer.txt
new file mode 100755
index 00000000..cb5a0b0e
--- /dev/null
+++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoreferrer.txt
@@ -0,0 +1,9 @@
+HTML.TargetNoreferrer
+TYPE: bool
+VERSION: 4.8.0
+DEFAULT: TRUE
+--DESCRIPTION--
+If enabled, noreferrer rel attributes are added to links which have
+a target attribute associated with them. This prevents malicious
+destinations from overwriting the original window.
+--# vim: et sw=4 sts=4
diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt
new file mode 100755
index 00000000..b4c271b7
--- /dev/null
+++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt
@@ -0,0 +1,8 @@
+HTML.TidyAdd
+TYPE: lookup
+VERSION: 2.0.0
+DEFAULT: array()
+--DESCRIPTION--
+
+Fixes to add to the default set of Tidy fixes as per your level.
+--# vim: et sw=4 sts=4
diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt
new file mode 100755
index 00000000..4186ccd0
--- /dev/null
+++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt
@@ -0,0 +1,24 @@
+HTML.TidyLevel
+TYPE: string
+VERSION: 2.0.0
+DEFAULT: 'medium'
+--DESCRIPTION--
+
+General level of cleanliness the Tidy module should enforce. +There are four allowed values:
+
+ If true, HTML Purifier will protect against Internet Explorer's
+ mishandling of the innerHTML attribute by appending
+ a space to any attribute that does not contain angled brackets, spaces
+ or quotes, but contains a backtick. This slightly changes the
+ semantics of any given attribute, so if this is unacceptable and
+ you do not use innerHTML on any of your pages, you can
+ turn this directive off.
+
+ If true, HTML Purifier will generate Internet Explorer compatibility + code for all object code. This is highly recommended if you enable + %HTML.SafeObject. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt new file mode 100755 index 00000000..79f8ad82 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt @@ -0,0 +1,13 @@ +Output.Newline +TYPE: string/null +VERSION: 2.0.1 +DEFAULT: NULL +--DESCRIPTION-- + ++ Newline string to format final output with. If left null, HTML Purifier + will auto-detect the default newline type of the system and use that; + you can manually override it here. Remember, \r\n is Windows, \r + is Mac, and \n is Unix. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt new file mode 100755 index 00000000..232b0236 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt @@ -0,0 +1,14 @@ +Output.SortAttr +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- +
+ If true, HTML Purifier will sort attributes by name before writing them back
+ to the document, converting a tag like: <el b="" a="" c="" />
+ to <el a="" b="" c="" />. This is a workaround for
+ a bug in FCKeditor which causes it to swap attributes order, adding noise
+ to text diffs. If you're not seeing this bug, chances are, you don't need
+ this directive.
+
+ Determines whether or not to run Tidy on the final output for pretty + formatting reasons, such as indentation and wrap. +
++ This can greatly improve readability for editors who are hand-editing + the HTML, but is by no means necessary as HTML Purifier has already + fixed all major errors the HTML may have had. Tidy is a non-default + extension, and this directive will silently fail if Tidy is not + available. +
++ If you are looking to make the overall look of your page's source + better, I recommend running Tidy on the entire page rather than just + user-content (after all, the indentation relative to the containing + blocks will be incorrect). +
+--ALIASES-- +Core.TidyFormat +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt new file mode 100755 index 00000000..071bc029 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt @@ -0,0 +1,7 @@ +Test.ForceNoIconv +TYPE: bool +DEFAULT: false +--DESCRIPTION-- +When set to true, HTMLPurifier_Encoder will act as if iconv does not exist +and use only pure PHP implementations. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt new file mode 100755 index 00000000..eb97307e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt @@ -0,0 +1,18 @@ +URI.AllowedSchemes +TYPE: lookup +--DEFAULT-- +array ( + 'http' => true, + 'https' => true, + 'mailto' => true, + 'ftp' => true, + 'nntp' => true, + 'news' => true, + 'tel' => true, +) +--DESCRIPTION-- +Whitelist that defines the schemes that a URI is allowed to have. This +prevents XSS attacks from using pseudo-schemes like javascript or mocha. +There is also support for thedata and file
+URI schemes, but they are not enabled by default.
+--# vim: et sw=4 sts=4
diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Base.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Base.txt
new file mode 100755
index 00000000..876f0680
--- /dev/null
+++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Base.txt
@@ -0,0 +1,17 @@
+URI.Base
+TYPE: string/null
+VERSION: 2.1.0
+DEFAULT: NULL
+--DESCRIPTION--
+
++ The base URI is the URI of the document this purified HTML will be + inserted into. This information is important if HTML Purifier needs + to calculate absolute URIs from relative URIs, such as when %URI.MakeAbsolute + is on. You may use a non-absolute URI for this value, but behavior + may vary (%URI.MakeAbsolute deals nicely with both absolute and + relative paths, but forwards-compatibility is not guaranteed). + Warning: If set, the scheme on this URI + overrides the one specified by %URI.DefaultScheme. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt new file mode 100755 index 00000000..834bc08c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt @@ -0,0 +1,15 @@ +URI.DefaultScheme +TYPE: string/null +DEFAULT: 'http' +--DESCRIPTION-- + ++ Defines through what scheme the output will be served, in order to + select the proper object validator when no scheme information is present. +
+ ++ Starting with HTML Purifier 4.9.0, the default scheme can be null, in + which case we reject all URIs which do not have explicit schemes. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt new file mode 100755 index 00000000..f05312ba --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt @@ -0,0 +1,11 @@ +URI.DefinitionID +TYPE: string/null +VERSION: 2.1.0 +DEFAULT: NULL +--DESCRIPTION-- + ++ Unique identifier for a custom-built URI definition. If you want + to add custom URIFilters, you must specify this value. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt new file mode 100755 index 00000000..80cfea93 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt @@ -0,0 +1,11 @@ +URI.DefinitionRev +TYPE: int +VERSION: 2.1.0 +DEFAULT: 1 +--DESCRIPTION-- + ++ Revision identifier for your custom definition. See + %HTML.DefinitionRev for details. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt new file mode 100755 index 00000000..71ce025a --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt @@ -0,0 +1,14 @@ +URI.Disable +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +--DESCRIPTION-- + ++ Disables all URIs in all forms. Not sure why you'd want to do that + (after all, the Internet's founded on the notion of a hyperlink). +
+ +--ALIASES-- +Attr.DisableURI +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt new file mode 100755 index 00000000..13c122c8 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt @@ -0,0 +1,11 @@ +URI.DisableExternal +TYPE: bool +VERSION: 1.2.0 +DEFAULT: false +--DESCRIPTION-- +Disables links to external websites. This is a highly effective anti-spam +and anti-pagerank-leech measure, but comes at a hefty price: nolinks or +images outside of your domain will be allowed. Non-linkified URIs will +still be preserved. If you want to be able to link to subdomains or use +absolute URIs, specify %URI.Host for your website. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt new file mode 100755 index 00000000..abcc1efd --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt @@ -0,0 +1,13 @@ +URI.DisableExternalResources +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +--DESCRIPTION-- +Disables the embedding of external resources, preventing users from +embedding things like images from other hosts. This prevents access +tracking (good for email viewers), bandwidth leeching, cross-site request +forging, goatse.cx posting, and other nasties, but also results in a loss +of end-user functionality (they can't directly post a pic they posted from +Flickr anymore). Use it if you don't have a robust user-content moderation +team. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt new file mode 100755 index 00000000..f891de49 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt @@ -0,0 +1,15 @@ +URI.DisableResources +TYPE: bool +VERSION: 4.2.0 +DEFAULT: false +--DESCRIPTION-- ++ Disables embedding resources, essentially meaning no pictures. You can + still link to them though. See %URI.DisableExternalResources for why + this might be a good idea. +
++ Note: While this directive has been available since 1.3.0, + it didn't actually start doing anything until 4.2.0. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Host.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Host.txt new file mode 100755 index 00000000..ee83b121 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Host.txt @@ -0,0 +1,19 @@ +URI.Host +TYPE: string/null +VERSION: 1.2.0 +DEFAULT: NULL +--DESCRIPTION-- + ++ Defines the domain name of the server, so we can determine whether or + an absolute URI is from your website or not. Not strictly necessary, + as users should be using relative URIs to reference resources on your + website. It will, however, let you use absolute URIs to link to + subdomains of the domain you post here: i.e. example.com will allow + sub.example.com. However, higher up domains will still be excluded: + if you set %URI.Host to sub.example.com, example.com will be blocked. + Note: This directive overrides %URI.Base because + a given page may be on a sub-domain, but you wish HTML Purifier to be + more relaxed and allow some of the parent domains too. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt new file mode 100755 index 00000000..0b6df762 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt @@ -0,0 +1,9 @@ +URI.HostBlacklist +TYPE: list +VERSION: 1.3.0 +DEFAULT: array() +--DESCRIPTION-- +List of strings that are forbidden in the host of any URI. Use it to kill +domain names of spam, etc. Note that it will catch anything in the domain, +so moo.com will catch moo.com.example.com. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt new file mode 100755 index 00000000..4214900a --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt @@ -0,0 +1,13 @@ +URI.MakeAbsolute +TYPE: bool +VERSION: 2.1.0 +DEFAULT: false +--DESCRIPTION-- + ++ Converts all URIs into absolute forms. This is useful when the HTML + being filtered assumes a specific base path, but will actually be + viewed in a different context (and setting an alternate base URI is + not possible). %URI.Base must be set for this directive to work. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt new file mode 100755 index 00000000..58c81dcc --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt @@ -0,0 +1,83 @@ +URI.Munge +TYPE: string/null +VERSION: 1.3.0 +DEFAULT: NULL +--DESCRIPTION-- + +
+ Munges all browsable (usually http, https and ftp)
+ absolute URIs into another URI, usually a URI redirection service.
+ This directive accepts a URI, formatted with a %s where
+ the url-encoded original URI should be inserted (sample:
+ http://www.google.com/url?q=%s).
+
+ Uses for this directive: +
+
+ Prior to HTML Purifier 3.1.1, this directive also enabled the munging
+ of browsable external resources, which could break things if your redirection
+ script was a splash page or used meta tags. To revert to
+ previous behavior, please use %URI.MungeResources.
+
+ You may want to also use %URI.MungeSecretKey along with this directive + in order to enforce what URIs your redirector script allows. Open + redirector scripts can be a security risk and negatively affect the + reputation of your domain name. +
++ Starting with HTML Purifier 3.1.1, there is also these substitutions: +
+| Key | +Description | +Example <a href=""> |
+
|---|---|---|
| %r | +1 - The URI embeds a resource (blank) - The URI is merely a link |
+ + |
| %n | +The name of the tag this URI came from | +a | +
| %m | +The name of the attribute this URI came from | +href | +
| %p | +The name of the CSS property this URI came from, or blank if irrelevant | ++ |
+ Admittedly, these letters are somewhat arbitrary; the only stipulation + was that they couldn't be a through f. r is for resource (I would have preferred + e, but you take what you can get), n is for name, m + was picked because it came after n (and I couldn't use a), p is for + property. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt new file mode 100755 index 00000000..6fce0fdc --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt @@ -0,0 +1,17 @@ +URI.MungeResources +TYPE: bool +VERSION: 3.1.1 +DEFAULT: false +--DESCRIPTION-- +
+ If true, any URI munging directives like %URI.Munge
+ will also apply to embedded resources, such as <img src="">.
+ Be careful enabling this directive if you have a redirector script
+ that does not use the Location HTTP header; all of your images
+ and other embedded resources will break.
+
+ Warning: It is strongly advised you use this in conjunction + %URI.MungeSecretKey to mitigate the security risk of an open redirector. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt new file mode 100755 index 00000000..1e17c1d4 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt @@ -0,0 +1,30 @@ +URI.MungeSecretKey +TYPE: string/null +VERSION: 3.1.1 +DEFAULT: NULL +--DESCRIPTION-- ++ This directive enables secure checksum generation along with %URI.Munge. + It should be set to a secure key that is not shared with anyone else. + The checksum can be placed in the URI using %t. Use of this checksum + affords an additional level of protection by allowing a redirector + to check if a URI has passed through HTML Purifier with this line: +
+ +$checksum === hash_hmac("sha256", $url, $secret_key)
+
++ If the output is TRUE, the redirector script should accept the URI. +
+ ++ Please note that it would still be possible for an attacker to procure + secure hashes en-mass by abusing your website's Preview feature or the + like, but this service affords an additional level of protection + that should be combined with website blacklisting. +
+ ++ Remember this has no effect if %URI.Munge is not on. +
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt new file mode 100755 index 00000000..23331a4e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt @@ -0,0 +1,9 @@ +URI.OverrideAllowedSchemes +TYPE: bool +DEFAULT: true +--DESCRIPTION-- +If this is set to true (which it is by default), you can override +%URI.AllowedSchemes by simply registering a HTMLPurifier_URIScheme to the +registry. If false, you will also have to update that directive in order +to add more schemes. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt new file mode 100755 index 00000000..79084832 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt @@ -0,0 +1,22 @@ +URI.SafeIframeRegexp +TYPE: string/null +VERSION: 4.4.0 +DEFAULT: NULL +--DESCRIPTION-- ++ A PCRE regular expression that will be matched against an iframe URI. This is + a relatively inflexible scheme, but works well enough for the most common + use-case of iframes: embedded video. This directive only has an effect if + %HTML.SafeIframe is enabled. Here are some example values: +
+%^http://www.youtube.com/embed/% - Allow YouTube videos%^http://player.vimeo.com/video/% - Allow Vimeo videos%^http://(www.youtube.com/embed/|player.vimeo.com/video/)% - Allow both
+ Note that this directive does not give you enough granularity to, say, disable
+ all autoplay videos. Pipe up on the HTML Purifier forums if this
+ is a capability you want.
+
' . $this->locale->getMessage('ErrorCollector: No errors') . '
'; + } else { + return ''; + //$string .= ''; + //$string .= ''; + $ret[] = $string; + } + foreach ($current->children as $array) { + $context[] = $current; + $stack = array_merge($stack, array_reverse($array, true)); + for ($i = count($array); $i > 0; $i--) { + $context_stack[] = $context; + } + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php new file mode 100755 index 00000000..cf869d32 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php @@ -0,0 +1,74 @@ +children[$type][$id])) { + $this->children[$type][$id] = new HTMLPurifier_ErrorStruct(); + $this->children[$type][$id]->type = $type; + } + return $this->children[$type][$id]; + } + + /** + * @param int $severity + * @param string $message + */ + public function addError($severity, $message) + { + $this->errors[] = array($severity, $message); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php new file mode 100755 index 00000000..be85b4c5 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php @@ -0,0 +1,12 @@ +preFilter, + * 2->preFilter, 3->preFilter, purify, 3->postFilter, 2->postFilter, + * 1->postFilter. + * + * @note Methods are not declared abstract as it is perfectly legitimate + * for an implementation not to want anything to happen on a step + */ + +class HTMLPurifier_Filter +{ + + /** + * Name of the filter for identification purposes. + * @type string + */ + public $name; + + /** + * Pre-processor function, handles HTML before HTML Purifier + * @param string $html + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public function preFilter($html, $config, $context) + { + return $html; + } + + /** + * Post-processor function, handles HTML after HTML Purifier + * @param string $html + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public function postFilter($html, $config, $context) + { + return $html; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php new file mode 100755 index 00000000..66f70b0f --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php @@ -0,0 +1,341 @@ + blocks from input HTML, cleans them up + * using CSSTidy, and then places them in $purifier->context->get('StyleBlocks') + * so they can be used elsewhere in the document. + * + * @note + * See tests/HTMLPurifier/Filter/ExtractStyleBlocksTest.php for + * sample usage. + * + * @note + * This filter can also be used on stylesheets not included in the + * document--something purists would probably prefer. Just directly + * call HTMLPurifier_Filter_ExtractStyleBlocks->cleanCSS() + */ +class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter +{ + /** + * @type string + */ + public $name = 'ExtractStyleBlocks'; + + /** + * @type array + */ + private $_styleMatches = array(); + + /** + * @type csstidy + */ + private $_tidy; + + /** + * @type HTMLPurifier_AttrDef_HTML_ID + */ + private $_id_attrdef; + + /** + * @type HTMLPurifier_AttrDef_CSS_Ident + */ + private $_class_attrdef; + + /** + * @type HTMLPurifier_AttrDef_Enum + */ + private $_enum_attrdef; + + public function __construct() + { + $this->_tidy = new csstidy(); + $this->_tidy->set_cfg('lowercase_s', false); + $this->_id_attrdef = new HTMLPurifier_AttrDef_HTML_ID(true); + $this->_class_attrdef = new HTMLPurifier_AttrDef_CSS_Ident(); + $this->_enum_attrdef = new HTMLPurifier_AttrDef_Enum( + array( + 'first-child', + 'link', + 'visited', + 'active', + 'hover', + 'focus' + ) + ); + } + + /** + * Save the contents of CSS blocks to style matches + * @param array $matches preg_replace style $matches array + */ + protected function styleCallback($matches) + { + $this->_styleMatches[] = $matches[1]; + } + + /** + * Removes inline + // we must not grab foo in a font-family prop). + if ($config->get('Filter.ExtractStyleBlocks.Escaping')) { + $css = str_replace( + array('<', '>', '&'), + array('\3C ', '\3E ', '\26 '), + $css + ); + } + return $css; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php new file mode 100755 index 00000000..276d8362 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php @@ -0,0 +1,65 @@ +]+>.+?' . + '(?:http:)?//www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?#s'; + $pre_replace = ''; + return preg_replace($pre_regex, $pre_replace, $html); + } + + /** + * @param string $html + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public function postFilter($html, $config, $context) + { + $post_regex = '##'; + return preg_replace_callback($post_regex, array($this, 'postFilterCallback'), $html); + } + + /** + * @param $url + * @return string + */ + protected function armorUrl($url) + { + return str_replace('--', '--', $url); + } + + /** + * @param array $matches + * @return string + */ + protected function postFilterCallback($matches) + { + $url = $this->armorUrl($matches[1]); + return ''; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php new file mode 100755 index 00000000..eb56e2df --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php @@ -0,0 +1,286 @@ + tags. + * @type bool + */ + private $_scriptFix = false; + + /** + * Cache of HTMLDefinition during HTML output to determine whether or + * not attributes should be minimized. + * @type HTMLPurifier_HTMLDefinition + */ + private $_def; + + /** + * Cache of %Output.SortAttr. + * @type bool + */ + private $_sortAttr; + + /** + * Cache of %Output.FlashCompat. + * @type bool + */ + private $_flashCompat; + + /** + * Cache of %Output.FixInnerHTML. + * @type bool + */ + private $_innerHTMLFix; + + /** + * Stack for keeping track of object information when outputting IE + * compatibility code. + * @type array + */ + private $_flashStack = array(); + + /** + * Configuration for the generator + * @type HTMLPurifier_Config + */ + protected $config; + + /** + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + */ + public function __construct($config, $context) + { + $this->config = $config; + $this->_scriptFix = $config->get('Output.CommentScriptContents'); + $this->_innerHTMLFix = $config->get('Output.FixInnerHTML'); + $this->_sortAttr = $config->get('Output.SortAttr'); + $this->_flashCompat = $config->get('Output.FlashCompat'); + $this->_def = $config->getHTMLDefinition(); + $this->_xhtml = $this->_def->doctype->xml; + } + + /** + * Generates HTML from an array of tokens. + * @param HTMLPurifier_Token[] $tokens Array of HTMLPurifier_Token + * @return string Generated HTML + */ + public function generateFromTokens($tokens) + { + if (!$tokens) { + return ''; + } + + // Basic algorithm + $html = ''; + for ($i = 0, $size = count($tokens); $i < $size; $i++) { + if ($this->_scriptFix && $tokens[$i]->name === 'script' + && $i + 2 < $size && $tokens[$i+2] instanceof HTMLPurifier_Token_End) { + // script special case + // the contents of the script block must be ONE token + // for this to work. + $html .= $this->generateFromToken($tokens[$i++]); + $html .= $this->generateScriptFromToken($tokens[$i++]); + } + $html .= $this->generateFromToken($tokens[$i]); + } + + // Tidy cleanup + if (extension_loaded('tidy') && $this->config->get('Output.TidyFormat')) { + $tidy = new Tidy; + $tidy->parseString( + $html, + array( + 'indent'=> true, + 'output-xhtml' => $this->_xhtml, + 'show-body-only' => true, + 'indent-spaces' => 2, + 'wrap' => 68, + ), + 'utf8' + ); + $tidy->cleanRepair(); + $html = (string) $tidy; // explicit cast necessary + } + + // Normalize newlines to system defined value + if ($this->config->get('Core.NormalizeNewlines')) { + $nl = $this->config->get('Output.Newline'); + if ($nl === null) { + $nl = PHP_EOL; + } + if ($nl !== "\n") { + $html = str_replace("\n", $nl, $html); + } + } + return $html; + } + + /** + * Generates HTML from a single token. + * @param HTMLPurifier_Token $token HTMLPurifier_Token object. + * @return string Generated HTML + */ + public function generateFromToken($token) + { + if (!$token instanceof HTMLPurifier_Token) { + trigger_error('Cannot generate HTML from non-HTMLPurifier_Token object', E_USER_WARNING); + return ''; + + } elseif ($token instanceof HTMLPurifier_Token_Start) { + $attr = $this->generateAttributes($token->attr, $token->name); + if ($this->_flashCompat) { + if ($token->name == "object") { + $flash = new stdClass(); + $flash->attr = $token->attr; + $flash->param = array(); + $this->_flashStack[] = $flash; + } + } + return '<' . $token->name . ($attr ? ' ' : '') . $attr . '>'; + + } elseif ($token instanceof HTMLPurifier_Token_End) { + $_extra = ''; + if ($this->_flashCompat) { + if ($token->name == "object" && !empty($this->_flashStack)) { + // doesn't do anything for now + } + } + return $_extra . '' . $token->name . '>'; + + } elseif ($token instanceof HTMLPurifier_Token_Empty) { + if ($this->_flashCompat && $token->name == "param" && !empty($this->_flashStack)) { + $this->_flashStack[count($this->_flashStack)-1]->param[$token->attr['name']] = $token->attr['value']; + } + $attr = $this->generateAttributes($token->attr, $token->name); + return '<' . $token->name . ($attr ? ' ' : '') . $attr . + ( $this->_xhtml ? ' /': '' ) //
tags? + if ($this->allowsElement('p')) { + if (empty($this->currentNesting) || strpos($text, "\n\n") !== false) { + // Note that we have differing behavior when dealing with text + // in the anonymous root node, or a node inside the document. + // If the text as a double-newline, the treatment is the same; + // if it doesn't, see the next if-block if you're in the document. + + $i = $nesting = null; + if (!$this->forwardUntilEndToken($i, $current, $nesting) && $token->is_whitespace) { + // State 1.1: ... ^ (whitespace, then document end) + // ---- + // This is a degenerate case + } else { + if (!$token->is_whitespace || $this->_isInline($current)) { + // State 1.2: PAR1 + // ---- + + // State 1.3: PAR1\n\nPAR2 + // ------------ + + // State 1.4:
tag? + } elseif (!empty($this->currentNesting) && + $this->currentNesting[count($this->currentNesting) - 1]->name == 'p') { + // State 3.1: ...
PAR1 + // ---- + + // State 3.2: ...
PAR1\n\nPAR2 + // ------------ + $token = array(); + $this->_splitText($text, $token); + // Abort! + } else { + // State 4.1: ...PAR1 + // ---- + + // State 4.2: ...PAR1\n\nPAR2 + // ------------ + } + } + + /** + * @param HTMLPurifier_Token $token + */ + public function handleElement(&$token) + { + // We don't have to check if we're already in a
tag for block + // tokens, because the tag would have been autoclosed by MakeWellFormed. + if ($this->allowsElement('p')) { + if (!empty($this->currentNesting)) { + if ($this->_isInline($token)) { + // State 1:
PAR1
\n\n + // --- + // Quite frankly, this should be handled by splitText + $token = array($this->_pStart(), $token); + } else { + // State 1.1.1:PAR1
+ // --- + // State 1.1.2:is needed. + if ($this->_pLookAhead()) { + // State 1.3.1:
tags. + } + } + } + } else { + // State 2.2:
+ // --- + } + } + + /** + * Splits up a text in paragraph tokens and appends them + * to the result stream that will replace the original + * @param string $data String text data that will be processed + * into paragraphs + * @param HTMLPurifier_Token[] $result Reference to array of tokens that the + * tags will be appended onto + */ + private function _splitText($data, &$result) + { + $raw_paragraphs = explode("\n\n", $data); + $paragraphs = array(); // without empty paragraphs + $needs_start = false; + $needs_end = false; + + $c = count($raw_paragraphs); + if ($c == 1) { + // There were no double-newlines, abort quickly. In theory this + // should never happen. + $result[] = new HTMLPurifier_Token_Text($data); + return; + } + for ($i = 0; $i < $c; $i++) { + $par = $raw_paragraphs[$i]; + if (trim($par) !== '') { + $paragraphs[] = $par; + } else { + if ($i == 0) { + // Double newline at the front + if (empty($result)) { + // The empty result indicates that the AutoParagraph + // injector did not add any start paragraph tokens. + // This means that we have been in a paragraph for + // a while, and the newline means we should start a new one. + $result[] = new HTMLPurifier_Token_End('p'); + $result[] = new HTMLPurifier_Token_Text("\n\n"); + // However, the start token should only be added if + // there is more processing to be done (i.e. there are + // real paragraphs in here). If there are none, the + // next start paragraph tag will be handled by the + // next call to the injector + $needs_start = true; + } else { + // We just started a new paragraph! + // Reinstate a double-newline for presentation's sake, since + // it was in the source code. + array_unshift($result, new HTMLPurifier_Token_Text("\n\n")); + } + } elseif ($i + 1 == $c) { + // Double newline at the end + // There should be a trailing
when we're finally done. + $needs_end = true; + } + } + } + + // Check if this was just a giant blob of whitespace. Move this earlier, + // perhaps? + if (empty($paragraphs)) { + return; + } + + // Add the start tag indicated by \n\n at the beginning of $data + if ($needs_start) { + $result[] = $this->_pStart(); + } + + // Append the paragraphs onto the result + foreach ($paragraphs as $par) { + $result[] = new HTMLPurifier_Token_Text($par); + $result[] = new HTMLPurifier_Token_End('p'); + $result[] = new HTMLPurifier_Token_Text("\n\n"); + $result[] = $this->_pStart(); + } + + // Remove trailing start token; Injector will handle this later if + // it was indeed needed. This prevents from needing to do a lookahead, + // at the cost of a lookbehind later. + array_pop($result); + + // If there is no need for an end tag, remove all of it and let + // MakeWellFormed close it later. + if (!$needs_end) { + array_pop($result); // removes \n\n + array_pop($result); // removes + } + } + + /** + * Returns true if passed token is inline (and, ergo, allowed in + * paragraph tags) + * @param HTMLPurifier_Token $token + * @return bool + */ + private function _isInline($token) + { + return isset($this->htmlDefinition->info['p']->child->elements[$token->name]); + } + + /** + * Looks ahead in the token list and determines whether or not we need + * to insert atag. + * @return bool + */ + private function _pLookAhead() + { + if ($this->currentToken instanceof HTMLPurifier_Token_Start) { + $nesting = 1; + } else { + $nesting = 0; + } + $ok = false; + $i = null; + while ($this->forwardUntilEndToken($i, $current, $nesting)) { + $result = $this->_checkNeedsP($current); + if ($result !== null) { + $ok = $result; + break; + } + } + return $ok; + } + + /** + * Determines if a particular token requires an earlier inline token + * to get a paragraph. This should be used with _forwardUntilEndToken + * @param HTMLPurifier_Token $current + * @return bool + */ + private function _checkNeedsP($current) + { + if ($current instanceof HTMLPurifier_Token_Start) { + if (!$this->_isInline($current)) { + //
n"; + //echo "$n\nsigfigs = $sigfigs\nnew_log = $new_log\nlog = $log\nrp = $rp\n\n"; + + $n = $this->round($n, $sigfigs); + if (strpos($n, '.') !== false) { + $n = rtrim($n, '0'); + } + $n = rtrim($n, '.'); + + return new HTMLPurifier_Length($n, $unit); + } + + /** + * Returns the number of significant figures in a string number. + * @param string $n Decimal number + * @return int number of sigfigs + */ + public function getSigFigs($n) + { + $n = ltrim($n, '0+-'); + $dp = strpos($n, '.'); // decimal position + if ($dp === false) { + $sigfigs = strlen(rtrim($n, '0')); + } else { + $sigfigs = strlen(ltrim($n, '0.')); // eliminate extra decimal character + if ($dp !== 0) { + $sigfigs--; + } + } + return $sigfigs; + } + + /** + * Adds two numbers, using arbitrary precision when available. + * @param string $s1 + * @param string $s2 + * @param int $scale + * @return string + */ + private function add($s1, $s2, $scale) + { + if ($this->bcmath) { + return bcadd($s1, $s2, $scale); + } else { + return $this->scale((float)$s1 + (float)$s2, $scale); + } + } + + /** + * Multiples two numbers, using arbitrary precision when available. + * @param string $s1 + * @param string $s2 + * @param int $scale + * @return string + */ + private function mul($s1, $s2, $scale) + { + if ($this->bcmath) { + return bcmul($s1, $s2, $scale); + } else { + return $this->scale((float)$s1 * (float)$s2, $scale); + } + } + + /** + * Divides two numbers, using arbitrary precision when available. + * @param string $s1 + * @param string $s2 + * @param int $scale + * @return string + */ + private function div($s1, $s2, $scale) + { + if ($this->bcmath) { + return bcdiv($s1, $s2, $scale); + } else { + return $this->scale((float)$s1 / (float)$s2, $scale); + } + } + + /** + * Rounds a number according to the number of sigfigs it should have, + * using arbitrary precision when available. + * @param float $n + * @param int $sigfigs + * @return string + */ + private function round($n, $sigfigs) + { + $new_log = (int)floor(log(abs($n), 10)); // Number of digits left of decimal - 1 + $rp = $sigfigs - $new_log - 1; // Number of decimal places needed + $neg = $n < 0 ? '-' : ''; // Negative sign + if ($this->bcmath) { + if ($rp >= 0) { + $n = bcadd($n, $neg . '0.' . str_repeat('0', $rp) . '5', $rp + 1); + $n = bcdiv($n, '1', $rp); + } else { + // This algorithm partially depends on the standardized + // form of numbers that comes out of bcmath. + $n = bcadd($n, $neg . '5' . str_repeat('0', $new_log - $sigfigs), 0); + $n = substr($n, 0, $sigfigs + strlen($neg)) . str_repeat('0', $new_log - $sigfigs + 1); + } + return $n; + } else { + return $this->scale(round($n, $sigfigs - $new_log - 1), $rp + 1); + } + } + + /** + * Scales a float to $scale digits right of decimal point, like BCMath. + * @param float $r + * @param int $scale + * @return string + */ + private function scale($r, $scale) + { + if ($scale < 0) { + // The f sprintf type doesn't support negative numbers, so we + // need to cludge things manually. First get the string. + $r = sprintf('%.0f', (float)$r); + // Due to floating point precision loss, $r will more than likely + // look something like 4652999999999.9234. We grab one more digit + // than we need to precise from $r and then use that to round + // appropriately. + $precise = (string)round(substr($r, 0, strlen($r) + $scale), -1); + // Now we return it, truncating the zero that was rounded off. + return substr($precise, 0, -1) . str_repeat('0', -$scale + 1); + } + return sprintf('%.' . $scale . 'f', (float)$r); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser.php new file mode 100755 index 00000000..0c97c828 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser.php @@ -0,0 +1,198 @@ + self::C_STRING, + 'istring' => self::ISTRING, + 'text' => self::TEXT, + 'itext' => self::ITEXT, + 'int' => self::C_INT, + 'float' => self::C_FLOAT, + 'bool' => self::C_BOOL, + 'lookup' => self::LOOKUP, + 'list' => self::ALIST, + 'hash' => self::HASH, + 'mixed' => self::C_MIXED + ); + + /** + * Lookup table of types that are string, and can have aliases or + * allowed value lists. + */ + public static $stringTypes = array( + self::C_STRING => true, + self::ISTRING => true, + self::TEXT => true, + self::ITEXT => true, + ); + + /** + * Validate a variable according to type. + * It may return NULL as a valid type if $allow_null is true. + * + * @param mixed $var Variable to validate + * @param int $type Type of variable, see HTMLPurifier_VarParser->types + * @param bool $allow_null Whether or not to permit null as a value + * @return string Validated and type-coerced variable + * @throws HTMLPurifier_VarParserException + */ + final public function parse($var, $type, $allow_null = false) + { + if (is_string($type)) { + if (!isset(HTMLPurifier_VarParser::$types[$type])) { + throw new HTMLPurifier_VarParserException("Invalid type '$type'"); + } else { + $type = HTMLPurifier_VarParser::$types[$type]; + } + } + $var = $this->parseImplementation($var, $type, $allow_null); + if ($allow_null && $var === null) { + return null; + } + // These are basic checks, to make sure nothing horribly wrong + // happened in our implementations. + switch ($type) { + case (self::C_STRING): + case (self::ISTRING): + case (self::TEXT): + case (self::ITEXT): + if (!is_string($var)) { + break; + } + if ($type == self::ISTRING || $type == self::ITEXT) { + $var = strtolower($var); + } + return $var; + case (self::C_INT): + if (!is_int($var)) { + break; + } + return $var; + case (self::C_FLOAT): + if (!is_float($var)) { + break; + } + return $var; + case (self::C_BOOL): + if (!is_bool($var)) { + break; + } + return $var; + case (self::LOOKUP): + case (self::ALIST): + case (self::HASH): + if (!is_array($var)) { + break; + } + if ($type === self::LOOKUP) { + foreach ($var as $k) { + if ($k !== true) { + $this->error('Lookup table contains value other than true'); + } + } + } elseif ($type === self::ALIST) { + $keys = array_keys($var); + if (array_keys($keys) !== $keys) { + $this->error('Indices for list are not uniform'); + } + } + return $var; + case (self::C_MIXED): + return $var; + default: + $this->errorInconsistent(get_class($this), $type); + } + $this->errorGeneric($var, $type); + } + + /** + * Actually implements the parsing. Base implementation does not + * do anything to $var. Subclasses should overload this! + * @param mixed $var + * @param int $type + * @param bool $allow_null + * @return string + */ + protected function parseImplementation($var, $type, $allow_null) + { + return $var; + } + + /** + * Throws an exception. + * @throws HTMLPurifier_VarParserException + */ + protected function error($msg) + { + throw new HTMLPurifier_VarParserException($msg); + } + + /** + * Throws an inconsistency exception. + * @note This should not ever be called. It would be called if we + * extend the allowed values of HTMLPurifier_VarParser without + * updating subclasses. + * @param string $class + * @param int $type + * @throws HTMLPurifier_Exception + */ + protected function errorInconsistent($class, $type) + { + throw new HTMLPurifier_Exception( + "Inconsistency in $class: " . HTMLPurifier_VarParser::getTypeName($type) . + " not implemented" + ); + } + + /** + * Generic error for if a type didn't work. + * @param mixed $var + * @param int $type + */ + protected function errorGeneric($var, $type) + { + $vtype = gettype($var); + $this->error("Expected type " . HTMLPurifier_VarParser::getTypeName($type) . ", got $vtype"); + } + + /** + * @param int $type + * @return string + */ + public static function getTypeName($type) + { + static $lookup; + if (!$lookup) { + // Lazy load the alternative lookup table + $lookup = array_flip(HTMLPurifier_VarParser::$types); + } + if (!isset($lookup[$type])) { + return 'unknown'; + } + return $lookup[$type]; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php new file mode 100755 index 00000000..3bfbe838 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php @@ -0,0 +1,130 @@ + $j) { + $var[$i] = trim($j); + } + if ($type === self::HASH) { + // key:value,key2:value2 + $nvar = array(); + foreach ($var as $keypair) { + $c = explode(':', $keypair, 2); + if (!isset($c[1])) { + continue; + } + $nvar[trim($c[0])] = trim($c[1]); + } + $var = $nvar; + } + } + if (!is_array($var)) { + break; + } + $keys = array_keys($var); + if ($keys === array_keys($keys)) { + if ($type == self::ALIST) { + return $var; + } elseif ($type == self::LOOKUP) { + $new = array(); + foreach ($var as $key) { + $new[$key] = true; + } + return $new; + } else { + break; + } + } + if ($type === self::ALIST) { + trigger_error("Array list did not have consecutive integer indexes", E_USER_WARNING); + return array_values($var); + } + if ($type === self::LOOKUP) { + foreach ($var as $key => $value) { + if ($value !== true) { + trigger_error( + "Lookup array has non-true value at key '$key'; " . + "maybe your input array was not indexed numerically", + E_USER_WARNING + ); + } + $var[$key] = true; + } + } + return $var; + default: + $this->errorInconsistent(__CLASS__, $type); + } + $this->errorGeneric($var, $type); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php new file mode 100755 index 00000000..f11c318e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php @@ -0,0 +1,38 @@ +evalExpression($var); + } + + /** + * @param string $expr + * @return mixed + * @throws HTMLPurifier_VarParserException + */ + protected function evalExpression($expr) + { + $var = null; + $result = eval("\$var = $expr;"); + if ($result === false) { + throw new HTMLPurifier_VarParserException("Fatal error in evaluated code"); + } + return $var; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParserException.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParserException.php new file mode 100755 index 00000000..5df34149 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParserException.php @@ -0,0 +1,11 @@ +front = $front; + $this->back = $back; + } + + /** + * Creates a zipper from an array, with a hole in the + * 0-index position. + * @param Array to zipper-ify. + * @return Tuple of zipper and element of first position. + */ + static public function fromArray($array) { + $z = new self(array(), array_reverse($array)); + $t = $z->delete(); // delete the "dummy hole" + return array($z, $t); + } + + /** + * Convert zipper back into a normal array, optionally filling in + * the hole with a value. (Usually you should supply a $t, unless you + * are at the end of the array.) + */ + public function toArray($t = NULL) { + $a = $this->front; + if ($t !== NULL) $a[] = $t; + for ($i = count($this->back)-1; $i >= 0; $i--) { + $a[] = $this->back[$i]; + } + return $a; + } + + /** + * Move hole to the next element. + * @param $t Element to fill hole with + * @return Original contents of new hole. + */ + public function next($t) { + if ($t !== NULL) array_push($this->front, $t); + return empty($this->back) ? NULL : array_pop($this->back); + } + + /** + * Iterated hole advancement. + * @param $t Element to fill hole with + * @param $i How many forward to advance hole + * @return Original contents of new hole, i away + */ + public function advance($t, $n) { + for ($i = 0; $i < $n; $i++) { + $t = $this->next($t); + } + return $t; + } + + /** + * Move hole to the previous element + * @param $t Element to fill hole with + * @return Original contents of new hole. + */ + public function prev($t) { + if ($t !== NULL) array_push($this->back, $t); + return empty($this->front) ? NULL : array_pop($this->front); + } + + /** + * Delete contents of current hole, shifting hole to + * next element. + * @return Original contents of new hole. + */ + public function delete() { + return empty($this->back) ? NULL : array_pop($this->back); + } + + /** + * Returns true if we are at the end of the list. + * @return bool + */ + public function done() { + return empty($this->back); + } + + /** + * Insert element before hole. + * @param Element to insert + */ + public function insertBefore($t) { + if ($t !== NULL) array_push($this->front, $t); + } + + /** + * Insert element after hole. + * @param Element to insert + */ + public function insertAfter($t) { + if ($t !== NULL) array_push($this->back, $t); + } + + /** + * Splice in multiple elements at hole. Functional specification + * in terms of array_splice: + * + * $arr1 = $arr; + * $old1 = array_splice($arr1, $i, $delete, $replacement); + * + * list($z, $t) = HTMLPurifier_Zipper::fromArray($arr); + * $t = $z->advance($t, $i); + * list($old2, $t) = $z->splice($t, $delete, $replacement); + * $arr2 = $z->toArray($t); + * + * assert($old1 === $old2); + * assert($arr1 === $arr2); + * + * NB: the absolute index location after this operation is + * *unchanged!* + * + * @param Current contents of hole. + */ + public function splice($t, $delete, $replacement) { + // delete + $old = array(); + $r = $t; + for ($i = $delete; $i > 0; $i--) { + $old[] = $r; + $r = $this->delete(); + } + // insert + for ($i = count($replacement)-1; $i >= 0; $i--) { + $this->insertAfter($r); + $r = $replacement[$i]; + } + return array($old, $r); + } +} diff --git a/vendor/fakerphp/faker/CHANGELOG.md b/vendor/fakerphp/faker/CHANGELOG.md new file mode 100755 index 00000000..566ad322 --- /dev/null +++ b/vendor/fakerphp/faker/CHANGELOG.md @@ -0,0 +1,181 @@ +# CHANGELOG + +## [Unreleased](https://github.com/FakerPHP/Faker/compare/v1.20.0...main) + +## [2022-12-13, v1.21.0](https://github.com/FakerPHP/Faker/compare/v1.20.0..v1.21.0) + +- Dropped support for PHP 7.1, 7.2, and 7.3 (#543) +- Added support for PHP 8.2 (#528) + +## [2022-07-20, v1.20.0](https://github.com/FakerPHP/Faker/compare/v1.19.0..v1.20.0) + +- Fixed typo in French phone number (#452) +- Fixed some Hungarian naming bugs (#451) +- Fixed bug where the NL-BE VAT generation was incorrect (#455) +- Improve Turkish phone numbers for E164 and added landline support (#460) +- Add Microsoft Edge User Agent (#464) +- Added option to set image formats on Faker\Provider\Image (#473) +- Added support for French color translations (#466) +- Support filtering timezones by country code (#480) +- Fixed typo in some greek names (#490) +- Marked the Faker\Provider\Image as deprecated + +## [2022-02-02, v1.19.0](https://github.com/FakerPHP/Faker/compare/v1.18.0..v1.19.0) + +- Added color extension to core (#442) +- Added conflict with `doctrine/persistence` below version `1.4` +- Fix for support on different Doctrine ORM versions (#414) +- Fix usage of `Doctrine\Persistence` dependency +- Fix CZ Person birthNumber docblock return type (#437) +- Fix is_IS Person docbock types (#439) +- Fix is_IS Address docbock type (#438) +- Fix regexify escape backslash in character class (#434) +- Removed UUID from Generator to be able to extend it (#441) + +## [2022-01-23, v1.18.0](https://github.com/FakerPHP/Faker/compare/v1.17.0..v1.18.0) + +- Deprecated UUID, use uuid3 to specify version (#427) +- Reset formatters when adding a new provider (#366) +- Helper methods to use our custom generators (#155) +- Set allow-plugins for Composer 2.2 (#405) +- Fix kk_KZ\Person::individualIdentificationNumber generation (#411) +- Allow for -> syntax to be used in parsing (#423) +- Person->name was missing string return type (#424) +- Generate a valid BE TAX number (#415) +- Added the UUID extension to Core (#427) + +## [2021-12-05, v1.17.0](https://github.com/FakerPHP/Faker/compare/v1.16.0..v1.17.0) + +- Partial PHP 8.1 compatibility (#373) +- Add payment provider for `ne_NP` locale (#375) +- Add Egyptian Arabic `ar_EG` locale (#377) +- Updated list of South African TLDs (#383) +- Fixed formatting of E.164 numbers (#380) +- Allow `symfony/deprecation-contracts` `^3.0` (#397) + +## [2021-09-06, v1.16.0](https://github.com/FakerPHP/Faker/compare/v1.15.0..v1.16.0) + +- Add Company extension +- Add Address extension +- Add Person extension +- Add PhoneNumber extension +- Add VersionExtension (#350) +- Stricter types in Extension\Container and Extension\GeneratorAwareExtension (#345) +- Fix deprecated property access in `nl_NL` (#348) +- Add support for `psr/container` >= 2.0 (#354) +- Add missing union types in Faker\Generator (#352) + +## [2021-07-06, v1.15.0](https://github.com/FakerPHP/Faker/compare/v1.14.1..v1.15.0) + +- Updated the generator phpdoc to help identify magic methods (#307) +- Prevent direct access and triggered deprecation warning for "word" (#302) +- Updated length on all global e164 numbers (#301) +- Updated last names from different source (#312) +- Don't generate birth number of '000' for Swedish personal identity (#306) +- Add job list for localization id_ID (#339) + +## [2021-03-30, v1.14.1](https://github.com/FakerPHP/Faker/compare/v1.14.0..v1.14.1) + +- Fix where randomNumber and randomFloat would return a 0 value (#291 / #292) + +## [2021-03-29, v1.14.0](https://github.com/FakerPHP/Faker/compare/v1.13.0..v1.14.0) + +- Fix for realText to ensure the text keeps closer to its boundaries (#152) +- Fix where regexify produces a random character instead of a literal dot (#135 +- Deprecate zh_TW methods that only call base methods (#122) +- Add used extensions to composer.json as suggestion (#120) +- Moved TCNo and INN from calculator to localized providers (#108) +- Fix regex dot/backslash issue where a dot is replaced with a backslash as escape character (#206) +- Deprecate direct property access (#164) +- Added test to assert unique() behaviour (#233) +- Added RUC for the es_PE locale (#244) +- Test IBAN formats for Latin America (AR/PE/VE) (#260) +- Added VAT number for en_GB (#255) +- Added new districts for the ne_NP locale (#258) +- Fix for U.S. Area Code Generation (#261) +- Fix in numerify where a better random numeric value is guaranteed (#256) +- Fix e164PhoneNumber to only generate valid phone numbers with valid country codes (#264) +- Extract fixtures into separate classes (#234) +- Remove french domains that no longer exists (#277) +- Fix error that occurs when getting a polish title (#279) +- Use valid area codes for North America E164 phone numbers (#280) + +- Adding support for extensions and PSR-11 (#154) +- Adding trait for GeneratorAwareExtension (#165) +- Added helper class for extension (#162) +- Added blood extension to core (#232) +- Added barcode extension to core (#252) +- Added number extension (#257) + +- Various code style updates +- Added a note about our breaking change promise (#273) + +## [2020-12-18, v1.13.0](https://github.com/FakerPHP/Faker/compare/v1.12.1..v1.13.0) + +Several fixes and new additions in this release. A lot of cleanup has been done +on the codebase on both tests and consistency. + +- Feature/pl pl license plate (#62) +- Fix greek phone numbers (#16) +- Move AT payment provider logic to de_AT (#72) +- Fix wiktionary links (#73) +- Fix AT person links (#74) +- Fix AT cities (#75) +- Deprecate at_AT providers (#78) +- Add Austrian `ssn()` to `Person` provider (#79) +- Fix typos in id_ID Address (#83) +- Austrian post codes (#86) +- Updated Polish data (#70) +- Improve Austrian social security number generation (#88) +- Move US phone numbers with extension to own method (#91) +- Add UK National Insurance number generator (#89) +- Fix en_SG phone number generator (#100) +- Remove usage of mt_rand (#87) +- Remove whitespace from beginning of el_GR phone numbers (#105) +- Building numbers can not be 0, 00, 000 (#107) +- Add 172.16/12 local IPv4 block (#121) +- Add JCB credit card type (#124) +- Remove json_decode from emoji generation (#123) +- Remove ro street address (#146) + +## [2020-12-11, v1.12.1](https://github.com/FakerPHP/Faker/compare/v1.12.0..v1.12.1) + +This is a security release that prevents a hacker to execute code on the server. + +## [2020-11-23, v1.12.0](https://github.com/FakerPHP/Faker/compare/v1.11.0..v1.12.0) + +- Fix ro_RO first and last day of year calculation offset (#65) +- Fix en_NG locale test namespaces that did not match PSR-4 (#57) +- Added Singapore NRIC/FIN provider (#56) +- Added provider for Lithuanian municipalities (#58) +- Added blood types provider (#61) + +## [2020-11-15, v1.11.0](https://github.com/FakerPHP/Faker/compare/v1.10.1..v1.11.0) + +- Added Provider for Swedish Municipalities +- Updates to person names in pt_BR +- Many code style changes + +## [2020-10-28, v1.10.1](https://github.com/FakerPHP/Faker/compare/v1.10.0..v1.10.1) + +- Updates the Danish addresses in dk_DK +- Removed offense company names in nl_NL +- Clarify changelog with original fork +- Standin replacement for LoremPixel to Placeholder.com (#11) + +## [2020-10-27, v1.10.0](https://github.com/FakerPHP/Faker/compare/v1.9.1..v1.10.0) + +- Support PHP 7.1-8.0 +- Fix typo in de_DE Company Provider +- Fix dateTimeThisYear method +- Fix typo in de_DE jobTitleFormat +- Fix IBAN generation for CR +- Fix typos in greek first names +- Fix US job title typo +- Do not clear entity manager for doctrine orm populator +- Remove persian rude words +- Corrections to RU names + +## 2020-10-27, v1.9.1 + +- Initial version. Same as `fzaninotto/Faker:v1.9.1`. diff --git a/vendor/fakerphp/faker/LICENSE b/vendor/fakerphp/faker/LICENSE new file mode 100755 index 00000000..99ed0075 --- /dev/null +++ b/vendor/fakerphp/faker/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2011 François Zaninotto +Portions Copyright (c) 2008 Caius Durling +Portions Copyright (c) 2008 Adam Royle +Portions Copyright (c) 2008 Fiona Burrows + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/fakerphp/faker/README.md b/vendor/fakerphp/faker/README.md new file mode 100755 index 00000000..c3c199d5 --- /dev/null +++ b/vendor/fakerphp/faker/README.md @@ -0,0 +1,107 @@ +

0
+ string
+ $this->uniqueGenerator
+ new ChanceGenerator($this, $weight, $default)
+ new ValidGenerator($this, $validator, $maxRetries)
+ self
+ self
+ self
+ TableRegistry
+ $this->class
+ \Doctrine\ODM\MongoDB\Mapping\ClassMetadata
+ \Doctrine\ODM\MongoDB\Mapping\ClassMetadata
+ \Doctrine\ODM\MongoDB\Mapping\ClassMetadata
+ \Doctrine\ORM\Mapping\ClassMetadata
+ \Doctrine\ORM\Mapping\ClassMetadata
+ createQueryBuilder
+ getAssociationMappings
+ newInstance
+ Mandango
+ Mandango
+ $this->mandango
+ Mandango
+ \ColumnMap
+ $columnMap
+ $columnMap
+ $columnMap
+ $columnMap
+ $columnMap
+ $columnMap
+ $columnMap
+ $columnMap
+ \ColumnMap
+ \Propel
+ PropelPDO
+ ColumnMap
+ $columnMap
+ $columnMap
+ $columnMap
+ $columnMap
+ $columnMap
+ $columnMap
+ $columnMap
+ $columnMap
+ ColumnMap
+ Propel
+ PropelPDO
+ $this->mapper
+ string
+ $relation
+ $relation
+ BelongsTo
+ Locator
+ Mapper
+ $locator
+ $this->mapper
+ $this->mapper
+ $this->mapper
+ $this->mapper
+ $this->mapper
+ Locator
+ Mapper
+ $this->locator
+ Locator
+ Locator
+ [static::class, 'randomDigit']
+ $array
+ Closure
+ false
+ $element->ownerDocument
+ $element->ownerDocument
+ $element->ownerDocument
+ $element->ownerDocument
+ $element->ownerDocument
+ $element->ownerDocument
+ $element->ownerDocument
+ $element->ownerDocument
+ $element->ownerDocument
+ $element->ownerDocument
+ $element->ownerDocument
+ $root->ownerDocument
+ $imei
+ int
+ static::$cityPrefix
+ static::birthNumber(static::GENDER_FEMALE)
+ static::birthNumber(static::GENDER_MALE)
+ $weights[$i]
+ $ref[$i]
+ static::split($text)
+ $multipliers[$i - 1]
+ $weights[$i]
+ $weights[$i]
+ $weights[$i]
+ $high[$i]
+ $low[$i]
+ $result[$i]
+ $weights[$i + 3]
+ $weights[$i]
+ $weights[$i]
+ DateTime
+ $multipliers[$i]
+ static::lastName()
+ static::lastName()
+
+ * // will never return twice the same value
+ * $faker->unique()->randomElement(array(1, 2, 3));
+ *
+ *
+ * @param bool $reset If set to true, resets the list of existing values
+ * @param int $maxRetries Maximum number of retries to find a unique value,
+ * After which an OverflowException is thrown.
+ *
+ * @throws \OverflowException When no unique value can be found by iterating $maxRetries times
+ *
+ * @return self A proxy class returning only non-existing values
+ */
+ public function unique($reset = false, $maxRetries = 10000)
+ {
+ if ($reset || $this->uniqueGenerator === null) {
+ $this->uniqueGenerator = new UniqueGenerator($this, $maxRetries);
+ }
+
+ return $this->uniqueGenerator;
+ }
+
+ /**
+ * Get a value only some percentage of the time.
+ *
+ * @param float $weight A probability between 0 and 1, 0 means that we always get the default value.
+ *
+ * @return self
+ */
+ public function optional(float $weight = 0.5, $default = null)
+ {
+ if ($weight > 1) {
+ trigger_deprecation('fakerphp/faker', '1.16', 'First argument ($weight) to method "optional()" must be between 0 and 1. You passed %f, we assume you meant %f.', $weight, $weight / 100);
+ $weight = $weight / 100;
+ }
+
+ return new ChanceGenerator($this, $weight, $default);
+ }
+
+ /**
+ * To make sure the value meet some criteria, pass a callable that verifies the
+ * output. If the validator fails, the generator will try again.
+ *
+ * The value validity is determined by a function passed as first argument.
+ *
+ *
+ * $values = array();
+ * $evenValidator = function ($digit) {
+ * return $digit % 2 === 0;
+ * };
+ * for ($i=0; $i < 10; $i++) {
+ * $values []= $faker->valid($evenValidator)->randomDigit;
+ * }
+ * print_r($values); // [0, 4, 8, 4, 2, 6, 0, 8, 8, 6]
+ *
+ *
+ * @param ?\Closure $validator A function returning true for valid values
+ * @param int $maxRetries Maximum number of retries to find a valid value,
+ * After which an OverflowException is thrown.
+ *
+ * @throws \OverflowException When no valid value can be found by iterating $maxRetries times
+ *
+ * @return self A proxy class returning only valid values
+ */
+ public function valid(?\Closure $validator = null, int $maxRetries = 10000)
+ {
+ return new ValidGenerator($this, $validator, $maxRetries);
+ }
+
+ public function seed($seed = null)
+ {
+ if ($seed === null) {
+ mt_srand();
+ } else {
+ mt_srand((int) $seed, MT_RAND_PHP);
+ }
+ }
+
+ public function format($format, $arguments = [])
+ {
+ return call_user_func_array($this->getFormatter($format), $arguments);
+ }
+
+ /**
+ * @param string $format
+ *
+ * @return callable
+ */
+ public function getFormatter($format)
+ {
+ if (isset($this->formatters[$format])) {
+ return $this->formatters[$format];
+ }
+
+ if (method_exists($this, $format)) {
+ $this->formatters[$format] = [$this, $format];
+
+ return $this->formatters[$format];
+ }
+
+ // "Faker\Core\Barcode->ean13"
+ if (preg_match('|^([a-zA-Z0-9\\\]+)->([a-zA-Z0-9]+)$|', $format, $matches)) {
+ $this->formatters[$format] = [$this->ext($matches[1]), $matches[2]];
+
+ return $this->formatters[$format];
+ }
+
+ foreach ($this->providers as $provider) {
+ if (method_exists($provider, $format)) {
+ $this->formatters[$format] = [$provider, $format];
+
+ return $this->formatters[$format];
+ }
+ }
+
+ throw new \InvalidArgumentException(sprintf('Unknown format "%s"', $format));
+ }
+
+ /**
+ * Replaces tokens ('{{ tokenName }}') with the result from the token method call
+ *
+ * @param string $string String that needs to bet parsed
+ *
+ * @return string
+ */
+ public function parse($string)
+ {
+ $callback = function ($matches) {
+ return $this->format($matches[1]);
+ };
+
+ return preg_replace_callback('/{{\s?(\w+|[\w\\\]+->\w+?)\s?}}/u', $callback, $string);
+ }
+
+ /**
+ * Get a random MIME type
+ *
+ * @example 'video/avi'
+ */
+ public function mimeType()
+ {
+ return $this->ext(Extension\FileExtension::class)->mimeType();
+ }
+
+ /**
+ * Get a random file extension (without a dot)
+ *
+ * @example avi
+ */
+ public function fileExtension()
+ {
+ return $this->ext(Extension\FileExtension::class)->extension();
+ }
+
+ /**
+ * Get a full path to a new real file on the system.
+ */
+ public function filePath()
+ {
+ return $this->ext(Extension\FileExtension::class)->filePath();
+ }
+
+ /**
+ * Get an actual blood type
+ *
+ * @example 'AB'
+ */
+ public function bloodType(): string
+ {
+ return $this->ext(Extension\BloodExtension::class)->bloodType();
+ }
+
+ /**
+ * Get a random resis value
+ *
+ * @example '+'
+ */
+ public function bloodRh(): string
+ {
+ return $this->ext(Extension\BloodExtension::class)->bloodRh();
+ }
+
+ /**
+ * Get a full blood group
+ *
+ * @example 'AB+'
+ */
+ public function bloodGroup(): string
+ {
+ return $this->ext(Extension\BloodExtension::class)->bloodGroup();
+ }
+
+ /**
+ * Get a random EAN13 barcode.
+ *
+ * @example '4006381333931'
+ */
+ public function ean13(): string
+ {
+ return $this->ext(Extension\BarcodeExtension::class)->ean13();
+ }
+
+ /**
+ * Get a random EAN8 barcode.
+ *
+ * @example '73513537'
+ */
+ public function ean8(): string
+ {
+ return $this->ext(Extension\BarcodeExtension::class)->ean8();
+ }
+
+ /**
+ * Get a random ISBN-10 code
+ *
+ * @see http://en.wikipedia.org/wiki/International_Standard_Book_Number
+ *
+ * @example '4881416324'
+ */
+ public function isbn10(): string
+ {
+ return $this->ext(Extension\BarcodeExtension::class)->isbn10();
+ }
+
+ /**
+ * Get a random ISBN-13 code
+ *
+ * @see http://en.wikipedia.org/wiki/International_Standard_Book_Number
+ *
+ * @example '9790404436093'
+ */
+ public function isbn13(): string
+ {
+ return $this->ext(Extension\BarcodeExtension::class)->isbn13();
+ }
+
+ /**
+ * Returns a random number between $int1 and $int2 (any order)
+ *
+ * @example 79907610
+ */
+ public function numberBetween($int1 = 0, $int2 = 2147483647): int
+ {
+ return $this->ext(Extension\NumberExtension::class)->numberBetween((int) $int1, (int) $int2);
+ }
+
+ /**
+ * Returns a random number between 0 and 9
+ */
+ public function randomDigit(): int
+ {
+ return $this->ext(Extension\NumberExtension::class)->randomDigit();
+ }
+
+ /**
+ * Generates a random digit, which cannot be $except
+ */
+ public function randomDigitNot($except): int
+ {
+ return $this->ext(Extension\NumberExtension::class)->randomDigitNot((int) $except);
+ }
+
+ /**
+ * Returns a random number between 1 and 9
+ */
+ public function randomDigitNotZero(): int
+ {
+ return $this->ext(Extension\NumberExtension::class)->randomDigitNotZero();
+ }
+
+ /**
+ * Return a random float number
+ *
+ * @example 48.8932
+ */
+ public function randomFloat($nbMaxDecimals = null, $min = 0, $max = null): float
+ {
+ return $this->ext(Extension\NumberExtension::class)->randomFloat(
+ $nbMaxDecimals !== null ? (int) $nbMaxDecimals : null,
+ (float) $min,
+ $max !== null ? (float) $max : null,
+ );
+ }
+
+ /**
+ * Returns a random integer with 0 to $nbDigits digits.
+ *
+ * The maximum value returned is mt_getrandmax()
+ *
+ * @param int|null $nbDigits Defaults to a random number between 1 and 9
+ * @param bool $strict Whether the returned number should have exactly $nbDigits
+ *
+ * @example 79907610
+ */
+ public function randomNumber($nbDigits = null, $strict = false): int
+ {
+ return $this->ext(Extension\NumberExtension::class)->randomNumber(
+ $nbDigits !== null ? (int) $nbDigits : null,
+ (bool) $strict,
+ );
+ }
+
+ /**
+ * Get a version number in semantic versioning syntax 2.0.0. (https://semver.org/spec/v2.0.0.html)
+ *
+ * @param bool $preRelease Pre release parts may be randomly included
+ * @param bool $build Build parts may be randomly included
+ *
+ * @example 1.0.0
+ * @example 1.0.0-alpha.1
+ * @example 1.0.0-alpha.1+b71f04d
+ */
+ public function semver(bool $preRelease = false, bool $build = false): string
+ {
+ return $this->ext(Extension\VersionExtension::class)->semver($preRelease, $build);
+ }
+
+ /**
+ * @deprecated
+ */
+ protected function callFormatWithMatches($matches)
+ {
+ trigger_deprecation('fakerphp/faker', '1.14', 'Protected method "callFormatWithMatches()" is deprecated and will be removed.');
+
+ return $this->format($matches[1]);
+ }
+
+ /**
+ * @param string $attribute
+ *
+ * @deprecated Use a method instead.
+ */
+ public function __get($attribute)
+ {
+ trigger_deprecation('fakerphp/faker', '1.14', 'Accessing property "%s" is deprecated, use "%s()" instead.', $attribute, $attribute);
+
+ return $this->format($attribute);
+ }
+
+ /**
+ * @param string $method
+ * @param array $attributes
+ */
+ public function __call($method, $attributes)
+ {
+ return $this->format($method, $attributes);
+ }
+
+ public function __destruct()
+ {
+ $this->seed();
+ }
+
+ public function __wakeup()
+ {
+ $this->formatters = [];
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Guesser/Name.php b/vendor/fakerphp/faker/src/Faker/Guesser/Name.php
new file mode 100755
index 00000000..ddb048bc
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Guesser/Name.php
@@ -0,0 +1,180 @@
+generator = $generator;
+ }
+
+ /**
+ * @param string $name
+ * @param int|null $size Length of field, if known
+ *
+ * @return callable|null
+ */
+ public function guessFormat($name, $size = null)
+ {
+ $name = Base::toLower($name);
+ $generator = $this->generator;
+
+ if (preg_match('/^is[_A-Z]/', $name)) {
+ return static function () use ($generator) {
+ return $generator->boolean;
+ };
+ }
+
+ if (preg_match('/(_a|A)t$/', $name)) {
+ return static function () use ($generator) {
+ return $generator->dateTime;
+ };
+ }
+
+ switch (str_replace('_', '', $name)) {
+ case 'firstname':
+ return static function () use ($generator) {
+ return $generator->firstName;
+ };
+
+ case 'lastname':
+ return static function () use ($generator) {
+ return $generator->lastName;
+ };
+
+ case 'username':
+ case 'login':
+ return static function () use ($generator) {
+ return $generator->userName;
+ };
+
+ case 'email':
+ case 'emailaddress':
+ return static function () use ($generator) {
+ return $generator->email;
+ };
+
+ case 'phonenumber':
+ case 'phone':
+ case 'telephone':
+ case 'telnumber':
+ return static function () use ($generator) {
+ return $generator->phoneNumber;
+ };
+
+ case 'address':
+ return static function () use ($generator) {
+ return $generator->address;
+ };
+
+ case 'city':
+ case 'town':
+ return static function () use ($generator) {
+ return $generator->city;
+ };
+
+ case 'streetaddress':
+ return static function () use ($generator) {
+ return $generator->streetAddress;
+ };
+
+ case 'postcode':
+ case 'zipcode':
+ return static function () use ($generator) {
+ return $generator->postcode;
+ };
+
+ case 'state':
+ return static function () use ($generator) {
+ return $generator->state;
+ };
+
+ case 'county':
+ if ($this->generator->locale == 'en_US') {
+ return static function () use ($generator) {
+ return sprintf('%s County', $generator->city);
+ };
+ }
+
+ return static function () use ($generator) {
+ return $generator->state;
+ };
+
+ case 'country':
+ switch ($size) {
+ case 2:
+ return static function () use ($generator) {
+ return $generator->countryCode;
+ };
+
+ case 3:
+ return static function () use ($generator) {
+ return $generator->countryISOAlpha3;
+ };
+
+ case 5:
+ case 6:
+ return static function () use ($generator) {
+ return $generator->locale;
+ };
+
+ default:
+ return static function () use ($generator) {
+ return $generator->country;
+ };
+ }
+
+ break;
+
+ case 'locale':
+ return static function () use ($generator) {
+ return $generator->locale;
+ };
+
+ case 'currency':
+ case 'currencycode':
+ return static function () use ($generator) {
+ return $generator->currencyCode;
+ };
+
+ case 'url':
+ case 'website':
+ return static function () use ($generator) {
+ return $generator->url;
+ };
+
+ case 'company':
+ case 'companyname':
+ case 'employer':
+ return static function () use ($generator) {
+ return $generator->company;
+ };
+
+ case 'title':
+ if ($size !== null && $size <= 10) {
+ return static function () use ($generator) {
+ return $generator->title;
+ };
+ }
+
+ return static function () use ($generator) {
+ return $generator->sentence;
+ };
+
+ case 'body':
+ case 'summary':
+ case 'article':
+ case 'description':
+ return static function () use ($generator) {
+ return $generator->text;
+ };
+ }
+
+ return null;
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/CakePHP/ColumnTypeGuesser.php b/vendor/fakerphp/faker/src/Faker/ORM/CakePHP/ColumnTypeGuesser.php
new file mode 100755
index 00000000..c2a30e67
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/CakePHP/ColumnTypeGuesser.php
@@ -0,0 +1,79 @@
+generator = $generator;
+ }
+
+ /**
+ * @return \Closure|null
+ */
+ public function guessFormat($column, $table)
+ {
+ $generator = $this->generator;
+ $schema = $table->schema();
+
+ switch ($schema->columnType($column)) {
+ case 'boolean':
+ return static function () use ($generator) {
+ return $generator->boolean;
+ };
+
+ case 'integer':
+ return static function () use ($generator) {
+ return $generator->numberBetween(0, 2147483647);
+ };
+
+ case 'biginteger':
+ return static function () use ($generator) {
+ return $generator->numberBetween(0, PHP_INT_MAX);
+ };
+
+ case 'decimal':
+ case 'float':
+ return static function () use ($generator) {
+ return $generator->randomFloat();
+ };
+
+ case 'uuid':
+ return static function () use ($generator) {
+ return $generator->uuid();
+ };
+
+ case 'string':
+ if (method_exists($schema, 'getColumn')) {
+ $columnData = $schema->getColumn($column);
+ } else {
+ $columnData = $schema->column($column);
+ }
+ $length = $columnData['length'];
+
+ return static function () use ($generator, $length) {
+ return $generator->text($length);
+ };
+
+ case 'text':
+ return static function () use ($generator) {
+ return $generator->text();
+ };
+
+ case 'date':
+ case 'datetime':
+ case 'timestamp':
+ case 'time':
+ return static function () use ($generator) {
+ return $generator->datetime();
+ };
+
+ case 'binary':
+ default:
+ return null;
+ }
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/CakePHP/EntityPopulator.php b/vendor/fakerphp/faker/src/Faker/ORM/CakePHP/EntityPopulator.php
new file mode 100755
index 00000000..cd9890bd
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/CakePHP/EntityPopulator.php
@@ -0,0 +1,173 @@
+class = $class;
+ }
+
+ /**
+ * @param string $name
+ */
+ public function __get($name)
+ {
+ return $this->{$name};
+ }
+
+ /**
+ * @param string $name
+ */
+ public function __set($name, $value)
+ {
+ $this->{$name} = $value;
+ }
+
+ public function mergeColumnFormattersWith($columnFormatters)
+ {
+ $this->columnFormatters = array_merge($this->columnFormatters, $columnFormatters);
+ }
+
+ public function mergeModifiersWith($modifiers)
+ {
+ $this->modifiers = array_merge($this->modifiers, $modifiers);
+ }
+
+ /**
+ * @return array
+ */
+ public function guessColumnFormatters($populator)
+ {
+ $formatters = [];
+ $class = $this->class;
+ $table = $this->getTable($class);
+ $schema = $table->schema();
+ $pk = $schema->primaryKey();
+ $guessers = $populator->getGuessers() + ['ColumnTypeGuesser' => new ColumnTypeGuesser($populator->getGenerator())];
+ $isForeignKey = static function ($column) use ($table) {
+ foreach ($table->associations()->type('BelongsTo') as $assoc) {
+ if ($column == $assoc->foreignKey()) {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ foreach ($schema->columns() as $column) {
+ if ($column == $pk[0] || $isForeignKey($column)) {
+ continue;
+ }
+
+ foreach ($guessers as $guesser) {
+ if ($formatter = $guesser->guessFormat($column, $table)) {
+ $formatters[$column] = $formatter;
+
+ break;
+ }
+ }
+ }
+
+ return $formatters;
+ }
+
+ /**
+ * @return array
+ */
+ public function guessModifiers()
+ {
+ $modifiers = [];
+ $table = $this->getTable($this->class);
+
+ $belongsTo = $table->associations()->type('BelongsTo');
+
+ foreach ($belongsTo as $assoc) {
+ $modifiers['belongsTo' . $assoc->name()] = function ($data, $insertedEntities) use ($assoc) {
+ $table = $assoc->target();
+ $foreignModel = $table->alias();
+
+ $foreignKeys = [];
+
+ if (!empty($insertedEntities[$foreignModel])) {
+ $foreignKeys = $insertedEntities[$foreignModel];
+ } else {
+ $foreignKeys = $table->find('all')
+ ->select(['id'])
+ ->map(static function ($row) {
+ return $row->id;
+ })
+ ->toArray();
+ }
+
+ if (empty($foreignKeys)) {
+ throw new \Exception(sprintf('%s belongsTo %s, which seems empty at this point.', $this->getTable($this->class)->table(), $assoc->table()));
+ }
+
+ $foreignKey = $foreignKeys[array_rand($foreignKeys)];
+ $data[$assoc->foreignKey()] = $foreignKey;
+
+ return $data;
+ };
+ }
+
+ // TODO check if TreeBehavior attached to modify lft/rgt cols
+
+ return $modifiers;
+ }
+
+ /**
+ * @param array $options
+ */
+ public function execute($class, $insertedEntities, $options = [])
+ {
+ $table = $this->getTable($class);
+ $entity = $table->newEntity();
+
+ foreach ($this->columnFormatters as $column => $format) {
+ if (null !== $format) {
+ $entity->{$column} = is_callable($format) ? $format($insertedEntities, $table) : $format;
+ }
+ }
+
+ foreach ($this->modifiers as $modifier) {
+ $entity = $modifier($entity, $insertedEntities);
+ }
+
+ if (!$entity = $table->save($entity, $options)) {
+ throw new \RuntimeException("Failed saving $class record");
+ }
+
+ $pk = $table->primaryKey();
+
+ if (is_string($pk)) {
+ return $entity->{$pk};
+ }
+
+ return $entity->{$pk[0]};
+ }
+
+ public function setConnection($name)
+ {
+ $this->connectionName = $name;
+ }
+
+ protected function getTable($class)
+ {
+ $options = [];
+
+ if (!empty($this->connectionName)) {
+ $options['connection'] = $this->connectionName;
+ }
+
+ return TableRegistry::get($class, $options);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/CakePHP/Populator.php b/vendor/fakerphp/faker/src/Faker/ORM/CakePHP/Populator.php
new file mode 100755
index 00000000..ac195fbd
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/CakePHP/Populator.php
@@ -0,0 +1,113 @@
+generator = $generator;
+ }
+
+ /**
+ * @return \Faker\Generator
+ */
+ public function getGenerator()
+ {
+ return $this->generator;
+ }
+
+ /**
+ * @return array
+ */
+ public function getGuessers()
+ {
+ return $this->guessers;
+ }
+
+ /**
+ * @return $this
+ */
+ public function removeGuesser($name)
+ {
+ if ($this->guessers[$name]) {
+ unset($this->guessers[$name]);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @throws \Exception
+ *
+ * @return $this
+ */
+ public function addGuesser($class)
+ {
+ if (!is_object($class)) {
+ $class = new $class($this->generator);
+ }
+
+ if (!method_exists($class, 'guessFormat')) {
+ throw new \Exception('Missing required custom guesser method: ' . get_class($class) . '::guessFormat()');
+ }
+
+ $this->guessers[get_class($class)] = $class;
+
+ return $this;
+ }
+
+ /**
+ * @param array $customColumnFormatters
+ * @param array $customModifiers
+ *
+ * @return $this
+ */
+ public function addEntity($entity, $number, $customColumnFormatters = [], $customModifiers = [])
+ {
+ if (!$entity instanceof EntityPopulator) {
+ $entity = new EntityPopulator($entity);
+ }
+
+ $entity->columnFormatters = $entity->guessColumnFormatters($this);
+
+ if ($customColumnFormatters) {
+ $entity->mergeColumnFormattersWith($customColumnFormatters);
+ }
+
+ $entity->modifiers = $entity->guessModifiers($this);
+
+ if ($customModifiers) {
+ $entity->mergeModifiersWith($customModifiers);
+ }
+
+ $class = $entity->class;
+ $this->entities[$class] = $entity;
+ $this->quantities[$class] = $number;
+
+ return $this;
+ }
+
+ /**
+ * @param array $options
+ *
+ * @return array
+ */
+ public function execute($options = [])
+ {
+ $insertedEntities = [];
+
+ foreach ($this->quantities as $class => $number) {
+ for ($i = 0; $i < $number; ++$i) {
+ $insertedEntities[$class][] = $this->entities[$class]->execute($class, $insertedEntities, $options);
+ }
+ }
+
+ return $insertedEntities;
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/Doctrine/ColumnTypeGuesser.php b/vendor/fakerphp/faker/src/Faker/ORM/Doctrine/ColumnTypeGuesser.php
new file mode 100755
index 00000000..3267fe46
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/Doctrine/ColumnTypeGuesser.php
@@ -0,0 +1,91 @@
+generator = $generator;
+ }
+
+ /**
+ * @return \Closure|null
+ */
+ public function guessFormat($fieldName, ClassMetadata $class)
+ {
+ $generator = $this->generator;
+ $type = $class->getTypeOfField($fieldName);
+
+ switch ($type) {
+ case 'boolean':
+ return static function () use ($generator) {
+ return $generator->boolean;
+ };
+
+ case 'decimal':
+ $size = $class->fieldMappings[$fieldName]['precision'] ?? 2;
+
+ return static function () use ($generator, $size) {
+ return $generator->randomNumber($size + 2) / 100;
+ };
+
+ case 'smallint':
+ return static function () use ($generator) {
+ return $generator->numberBetween(0, 65535);
+ };
+
+ case 'integer':
+ return static function () use ($generator) {
+ return $generator->numberBetween(0, 2147483647);
+ };
+
+ case 'bigint':
+ return static function () use ($generator) {
+ return $generator->numberBetween(0, PHP_INT_MAX);
+ };
+
+ case 'float':
+ return static function () use ($generator) {
+ return $generator->randomFloat();
+ };
+
+ case 'string':
+ $size = $class->fieldMappings[$fieldName]['length'] ?? 255;
+
+ return static function () use ($generator, $size) {
+ return $generator->text($size);
+ };
+
+ case 'text':
+ return static function () use ($generator) {
+ return $generator->text;
+ };
+
+ case 'datetime':
+ case 'date':
+ case 'time':
+ return static function () use ($generator) {
+ return $generator->datetime;
+ };
+
+ case 'datetime_immutable':
+ case 'date_immutable':
+ case 'time_immutable':
+ return static function () use ($generator) {
+ return \DateTimeImmutable::createFromMutable($generator->datetime);
+ };
+
+ default:
+ // no smart way to guess what the user expects here
+ return null;
+ }
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/Doctrine/EntityPopulator.php b/vendor/fakerphp/faker/src/Faker/ORM/Doctrine/EntityPopulator.php
new file mode 100755
index 00000000..47923999
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/Doctrine/EntityPopulator.php
@@ -0,0 +1,248 @@
+class = $class;
+ }
+
+ /**
+ * @return string
+ */
+ public function getClass()
+ {
+ return $this->class->getName();
+ }
+
+ public function setColumnFormatters($columnFormatters)
+ {
+ $this->columnFormatters = $columnFormatters;
+ }
+
+ /**
+ * @return array
+ */
+ public function getColumnFormatters()
+ {
+ return $this->columnFormatters;
+ }
+
+ public function mergeColumnFormattersWith($columnFormatters)
+ {
+ $this->columnFormatters = array_merge($this->columnFormatters, $columnFormatters);
+ }
+
+ public function setModifiers(array $modifiers)
+ {
+ $this->modifiers = $modifiers;
+ }
+
+ /**
+ * @return array
+ */
+ public function getModifiers()
+ {
+ return $this->modifiers;
+ }
+
+ public function mergeModifiersWith(array $modifiers)
+ {
+ $this->modifiers = array_merge($this->modifiers, $modifiers);
+ }
+
+ /**
+ * @return array
+ */
+ public function guessColumnFormatters(\Faker\Generator $generator)
+ {
+ $formatters = [];
+ $nameGuesser = new \Faker\Guesser\Name($generator);
+ $columnTypeGuesser = new ColumnTypeGuesser($generator);
+
+ foreach ($this->class->getFieldNames() as $fieldName) {
+ if ($this->class->isIdentifier($fieldName) || !$this->class->hasField($fieldName)) {
+ continue;
+ }
+
+ $size = $this->class->fieldMappings[$fieldName]['length'] ?? null;
+
+ if ($formatter = $nameGuesser->guessFormat($fieldName, $size)) {
+ $formatters[$fieldName] = $formatter;
+
+ continue;
+ }
+
+ if ($formatter = $columnTypeGuesser->guessFormat($fieldName, $this->class)) {
+ $formatters[$fieldName] = $formatter;
+
+ continue;
+ }
+ }
+
+ foreach ($this->class->getAssociationNames() as $assocName) {
+ if ($this->class->isCollectionValuedAssociation($assocName)) {
+ continue;
+ }
+
+ $relatedClass = $this->class->getAssociationTargetClass($assocName);
+
+ $unique = $optional = false;
+
+ if ($this->class instanceof \Doctrine\ORM\Mapping\ClassMetadata) {
+ $mappings = $this->class->getAssociationMappings();
+
+ foreach ($mappings as $mapping) {
+ if ($mapping['targetEntity'] == $relatedClass) {
+ if ($mapping['type'] == \Doctrine\ORM\Mapping\ClassMetadata::ONE_TO_ONE) {
+ $unique = true;
+ $optional = $mapping['joinColumns'][0]['nullable'] ?? false;
+
+ break;
+ }
+ }
+ }
+ } elseif ($this->class instanceof \Doctrine\ODM\MongoDB\Mapping\ClassMetadata) {
+ $mappings = $this->class->associationMappings;
+
+ foreach ($mappings as $mapping) {
+ if ($mapping['targetDocument'] == $relatedClass) {
+ if ($mapping['type'] == \Doctrine\ODM\MongoDB\Mapping\ClassMetadata::ONE && $mapping['association'] == \Doctrine\ODM\MongoDB\Mapping\ClassMetadata::REFERENCE_ONE) {
+ $unique = true;
+ $optional = $mapping['nullable'] ?? false;
+
+ break;
+ }
+ }
+ }
+ }
+
+ $index = 0;
+ $formatters[$assocName] = static function ($inserted) use ($relatedClass, &$index, $unique, $optional, $generator) {
+ if (isset($inserted[$relatedClass])) {
+ if ($unique) {
+ $related = null;
+
+ if (isset($inserted[$relatedClass][$index]) || !$optional) {
+ $related = $inserted[$relatedClass][$index];
+ }
+
+ ++$index;
+
+ return $related;
+ }
+
+ return $generator->randomElement($inserted[$relatedClass]);
+ }
+
+ return null;
+ };
+ }
+
+ return $formatters;
+ }
+
+ /**
+ * Insert one new record using the Entity class.
+ *
+ * @param bool $generateId
+ *
+ * @return EntityPopulator
+ */
+ public function execute(ObjectManager $manager, $insertedEntities, $generateId = false)
+ {
+ $obj = $this->class->newInstance();
+
+ $this->fillColumns($obj, $insertedEntities);
+ $this->callMethods($obj, $insertedEntities);
+
+ if ($generateId) {
+ $idsName = $this->class->getIdentifier();
+
+ foreach ($idsName as $idName) {
+ $id = $this->generateId($obj, $idName, $manager);
+ $this->class->reflFields[$idName]->setValue($obj, $id);
+ }
+ }
+
+ $manager->persist($obj);
+
+ return $obj;
+ }
+
+ private function fillColumns($obj, $insertedEntities): void
+ {
+ foreach ($this->columnFormatters as $field => $format) {
+ if (null !== $format) {
+ // Add some extended debugging information to any errors thrown by the formatter
+ try {
+ $value = is_callable($format) ? $format($insertedEntities, $obj) : $format;
+ } catch (\InvalidArgumentException $ex) {
+ throw new \InvalidArgumentException(sprintf(
+ 'Failed to generate a value for %s::%s: %s',
+ get_class($obj),
+ $field,
+ $ex->getMessage(),
+ ));
+ }
+ // Try a standard setter if it's available, otherwise fall back on reflection
+ $setter = sprintf('set%s', ucfirst($field));
+
+ if (is_callable([$obj, $setter])) {
+ $obj->$setter($value);
+ } else {
+ $this->class->reflFields[$field]->setValue($obj, $value);
+ }
+ }
+ }
+ }
+
+ private function callMethods($obj, $insertedEntities): void
+ {
+ foreach ($this->getModifiers() as $modifier) {
+ $modifier($obj, $insertedEntities);
+ }
+ }
+
+ /**
+ * @return int
+ */
+ private function generateId($obj, $column, ObjectManager $manager)
+ {
+ $repository = $manager->getRepository(get_class($obj));
+ $result = $repository->createQueryBuilder('e')
+ ->select(sprintf('e.%s', $column))
+ ->getQuery()
+ ->execute();
+ $ids = array_map('current', $result->toArray());
+
+ do {
+ $id = mt_rand();
+ } while (in_array($id, $ids, false));
+
+ return $id;
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/Doctrine/Populator.php b/vendor/fakerphp/faker/src/Faker/ORM/Doctrine/Populator.php
new file mode 100755
index 00000000..1bce6ab4
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/Doctrine/Populator.php
@@ -0,0 +1,126 @@
+generator = $generator;
+ $this->manager = $manager;
+ $this->batchSize = $batchSize;
+ }
+
+ /**
+ * Add an order for the generation of $number records for $entity.
+ *
+ * @param mixed $entity A Doctrine classname, or a \Faker\ORM\Doctrine\EntityPopulator instance
+ * @param int $number The number of entities to populate
+ */
+ public function addEntity($entity, $number, $customColumnFormatters = [], $customModifiers = [], $generateId = false)
+ {
+ if (!$entity instanceof \Faker\ORM\Doctrine\EntityPopulator) {
+ if (null === $this->manager) {
+ throw new \InvalidArgumentException('No entity manager passed to Doctrine Populator.');
+ }
+ $entity = new \Faker\ORM\Doctrine\EntityPopulator($this->manager->getClassMetadata($entity));
+ }
+ $entity->setColumnFormatters($entity->guessColumnFormatters($this->generator));
+
+ if ($customColumnFormatters) {
+ $entity->mergeColumnFormattersWith($customColumnFormatters);
+ }
+ $entity->mergeModifiersWith($customModifiers);
+ $this->generateId[$entity->getClass()] = $generateId;
+
+ $class = $entity->getClass();
+ $this->entities[$class] = $entity;
+ $this->quantities[$class] = $number;
+ }
+
+ /**
+ * Populate the database using all the Entity classes previously added.
+ *
+ * Please note that large amounts of data will result in more memory usage since the the Populator will return
+ * all newly created primary keys after executing.
+ *
+ * @param ObjectManager|null $entityManager A Doctrine connection object
+ *
+ * @return array A list of the inserted PKs
+ */
+ public function execute($entityManager = null)
+ {
+ if (null === $entityManager) {
+ $entityManager = $this->manager;
+ }
+
+ if (null === $entityManager) {
+ throw new \InvalidArgumentException('No entity manager passed to Doctrine Populator.');
+ }
+
+ $insertedEntities = [];
+
+ foreach ($this->quantities as $class => $number) {
+ $generateId = $this->generateId[$class];
+
+ for ($i = 0; $i < $number; ++$i) {
+ $insertedEntities[$class][] = $this->entities[$class]->execute(
+ $entityManager,
+ $insertedEntities,
+ $generateId,
+ );
+
+ if (count($insertedEntities) % $this->batchSize === 0) {
+ $entityManager->flush();
+ }
+ }
+ $entityManager->flush();
+ }
+
+ return $insertedEntities;
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/Doctrine/backward-compatibility.php b/vendor/fakerphp/faker/src/Faker/ORM/Doctrine/backward-compatibility.php
new file mode 100755
index 00000000..6f545f87
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/Doctrine/backward-compatibility.php
@@ -0,0 +1,11 @@
+generator = $generator;
+ }
+
+ /**
+ * @return \Closure|null
+ */
+ public function guessFormat($field)
+ {
+ $generator = $this->generator;
+
+ switch ($field['type']) {
+ case 'boolean':
+ return static function () use ($generator) {
+ return $generator->boolean;
+ };
+
+ case 'integer':
+ return static function () use ($generator) {
+ return $generator->numberBetween(0, 4294967295);
+ };
+
+ case 'float':
+ return static function () use ($generator) {
+ return $generator->randomFloat();
+ };
+
+ case 'string':
+ return static function () use ($generator) {
+ return $generator->text(255);
+ };
+
+ case 'date':
+ return static function () use ($generator) {
+ return $generator->dateTime;
+ };
+
+ default:
+ // no smart way to guess what the user expects here
+ return null;
+ }
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/Mandango/EntityPopulator.php b/vendor/fakerphp/faker/src/Faker/ORM/Mandango/EntityPopulator.php
new file mode 100755
index 00000000..515ab7b6
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/Mandango/EntityPopulator.php
@@ -0,0 +1,123 @@
+class = $class;
+ }
+
+ /**
+ * @return string
+ */
+ public function getClass()
+ {
+ return $this->class;
+ }
+
+ public function setColumnFormatters($columnFormatters)
+ {
+ $this->columnFormatters = $columnFormatters;
+ }
+
+ /**
+ * @return array
+ */
+ public function getColumnFormatters()
+ {
+ return $this->columnFormatters;
+ }
+
+ public function mergeColumnFormattersWith($columnFormatters)
+ {
+ $this->columnFormatters = array_merge($this->columnFormatters, $columnFormatters);
+ }
+
+ /**
+ * @return array
+ */
+ public function guessColumnFormatters(\Faker\Generator $generator, Mandango $mandango)
+ {
+ $formatters = [];
+ $nameGuesser = new \Faker\Guesser\Name($generator);
+ $columnTypeGuesser = new \Faker\ORM\Mandango\ColumnTypeGuesser($generator);
+
+ $metadata = $mandango->getMetadata($this->class);
+
+ // fields
+ foreach ($metadata['fields'] as $fieldName => $field) {
+ if ($formatter = $nameGuesser->guessFormat($fieldName)) {
+ $formatters[$fieldName] = $formatter;
+
+ continue;
+ }
+
+ if ($formatter = $columnTypeGuesser->guessFormat($field)) {
+ $formatters[$fieldName] = $formatter;
+
+ continue;
+ }
+ }
+
+ // references
+ foreach (array_merge($metadata['referencesOne'], $metadata['referencesMany']) as $referenceName => $reference) {
+ if (!isset($reference['class'])) {
+ continue;
+ }
+ $referenceClass = $reference['class'];
+
+ $formatters[$referenceName] = static function ($insertedEntities) use ($referenceClass) {
+ if (isset($insertedEntities[$referenceClass])) {
+ return Base::randomElement($insertedEntities[$referenceClass]);
+ }
+
+ return null;
+ };
+ }
+
+ return $formatters;
+ }
+
+ /**
+ * Insert one new record using the Entity class.
+ */
+ public function execute(Mandango $mandango, $insertedEntities)
+ {
+ $metadata = $mandango->getMetadata($this->class);
+
+ $obj = $mandango->create($this->class);
+
+ foreach ($this->columnFormatters as $column => $format) {
+ if (null !== $format) {
+ $value = is_callable($format) ? $format($insertedEntities, $obj) : $format;
+
+ if (isset($metadata['fields'][$column])
+ || isset($metadata['referencesOne'][$column])) {
+ $obj->set($column, $value);
+ }
+
+ if (isset($metadata['referencesMany'][$column])) {
+ $adder = 'add' . ucfirst($column);
+ $obj->$adder($value);
+ }
+ }
+ }
+ $mandango->persist($obj);
+
+ return $obj;
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/Mandango/Populator.php b/vendor/fakerphp/faker/src/Faker/ORM/Mandango/Populator.php
new file mode 100755
index 00000000..de6c3b81
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/Mandango/Populator.php
@@ -0,0 +1,63 @@
+generator = $generator;
+ $this->mandango = $mandango;
+ }
+
+ /**
+ * Add an order for the generation of $number records for $entity.
+ *
+ * @param mixed $entity A Propel ActiveRecord classname, or a \Faker\ORM\Propel\EntityPopulator instance
+ * @param int $number The number of entities to populate
+ */
+ public function addEntity($entity, $number, $customColumnFormatters = [])
+ {
+ if (!$entity instanceof \Faker\ORM\Mandango\EntityPopulator) {
+ $entity = new \Faker\ORM\Mandango\EntityPopulator($entity);
+ }
+ $entity->setColumnFormatters($entity->guessColumnFormatters($this->generator, $this->mandango));
+
+ if ($customColumnFormatters) {
+ $entity->mergeColumnFormattersWith($customColumnFormatters);
+ }
+ $class = $entity->getClass();
+ $this->entities[$class] = $entity;
+ $this->quantities[$class] = $number;
+ }
+
+ /**
+ * Populate the database using all the Entity classes previously added.
+ *
+ * @return array A list of the inserted entities.
+ */
+ public function execute()
+ {
+ $insertedEntities = [];
+
+ foreach ($this->quantities as $class => $number) {
+ for ($i = 0; $i < $number; ++$i) {
+ $insertedEntities[$class][] = $this->entities[$class]->execute($this->mandango, $insertedEntities);
+ }
+ }
+ $this->mandango->flush();
+
+ return $insertedEntities;
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/Propel/ColumnTypeGuesser.php b/vendor/fakerphp/faker/src/Faker/ORM/Propel/ColumnTypeGuesser.php
new file mode 100755
index 00000000..3d8a9a11
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/Propel/ColumnTypeGuesser.php
@@ -0,0 +1,109 @@
+generator = $generator;
+ }
+
+ /**
+ * @return \Closure|null
+ */
+ public function guessFormat(\ColumnMap $column)
+ {
+ $generator = $this->generator;
+
+ if ($column->isTemporal()) {
+ if ($column->isEpochTemporal()) {
+ return static function () use ($generator) {
+ return $generator->dateTime;
+ };
+ }
+
+ return static function () use ($generator) {
+ return $generator->dateTimeAD;
+ };
+ }
+ $type = $column->getType();
+
+ switch ($type) {
+ case \PropelColumnTypes::BOOLEAN:
+ case \PropelColumnTypes::BOOLEAN_EMU:
+ return static function () use ($generator) {
+ return $generator->boolean;
+ };
+
+ case \PropelColumnTypes::NUMERIC:
+ case \PropelColumnTypes::DECIMAL:
+ $size = $column->getSize();
+
+ return static function () use ($generator, $size) {
+ return $generator->randomNumber($size + 2) / 100;
+ };
+
+ case \PropelColumnTypes::TINYINT:
+ return static function () use ($generator) {
+ return $generator->numberBetween(0, 127);
+ };
+
+ case \PropelColumnTypes::SMALLINT:
+ return static function () use ($generator) {
+ return $generator->numberBetween(0, 32767);
+ };
+
+ case \PropelColumnTypes::INTEGER:
+ return static function () use ($generator) {
+ return $generator->numberBetween(0, 2147483647);
+ };
+
+ case \PropelColumnTypes::BIGINT:
+ return static function () use ($generator) {
+ return $generator->numberBetween(0, PHP_INT_MAX);
+ };
+
+ case \PropelColumnTypes::FLOAT:
+ case \PropelColumnTypes::DOUBLE:
+ case \PropelColumnTypes::REAL:
+ return static function () use ($generator) {
+ return $generator->randomFloat();
+ };
+
+ case \PropelColumnTypes::CHAR:
+ case \PropelColumnTypes::VARCHAR:
+ case \PropelColumnTypes::BINARY:
+ case \PropelColumnTypes::VARBINARY:
+ $size = $column->getSize();
+
+ return static function () use ($generator, $size) {
+ return $generator->text($size);
+ };
+
+ case \PropelColumnTypes::LONGVARCHAR:
+ case \PropelColumnTypes::LONGVARBINARY:
+ case \PropelColumnTypes::CLOB:
+ case \PropelColumnTypes::CLOB_EMU:
+ case \PropelColumnTypes::BLOB:
+ return static function () use ($generator) {
+ return $generator->text;
+ };
+
+ case \PropelColumnTypes::ENUM:
+ $valueSet = $column->getValueSet();
+
+ return static function () use ($generator, $valueSet) {
+ return $generator->randomElement($valueSet);
+ };
+
+ case \PropelColumnTypes::OBJECT:
+ case \PropelColumnTypes::PHP_ARRAY:
+ default:
+ // no smart way to guess what the user expects here
+ return null;
+ }
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/Propel/EntityPopulator.php b/vendor/fakerphp/faker/src/Faker/ORM/Propel/EntityPopulator.php
new file mode 100755
index 00000000..f5af75c9
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/Propel/EntityPopulator.php
@@ -0,0 +1,204 @@
+class = $class;
+ }
+
+ /**
+ * @return string
+ */
+ public function getClass()
+ {
+ return $this->class;
+ }
+
+ public function setColumnFormatters($columnFormatters)
+ {
+ $this->columnFormatters = $columnFormatters;
+ }
+
+ /**
+ * @return array
+ */
+ public function getColumnFormatters()
+ {
+ return $this->columnFormatters;
+ }
+
+ public function mergeColumnFormattersWith($columnFormatters)
+ {
+ $this->columnFormatters = array_merge($this->columnFormatters, $columnFormatters);
+ }
+
+ /**
+ * @return array
+ */
+ public function guessColumnFormatters(\Faker\Generator $generator)
+ {
+ $formatters = [];
+ $class = $this->class;
+ $peerClass = $class::PEER;
+ $tableMap = $peerClass::getTableMap();
+ $nameGuesser = new \Faker\Guesser\Name($generator);
+ $columnTypeGuesser = new \Faker\ORM\Propel\ColumnTypeGuesser($generator);
+
+ foreach ($tableMap->getColumns() as $columnMap) {
+ // skip behavior columns, handled by modifiers
+ if ($this->isColumnBehavior($columnMap)) {
+ continue;
+ }
+
+ if ($columnMap->isForeignKey()) {
+ $relatedClass = $columnMap->getRelation()->getForeignTable()->getClassname();
+ $formatters[$columnMap->getPhpName()] = static function ($inserted) use ($relatedClass, $generator) {
+ return isset($inserted[$relatedClass]) ? $generator->randomElement($inserted[$relatedClass]) : null;
+ };
+
+ continue;
+ }
+
+ if ($columnMap->isPrimaryKey()) {
+ continue;
+ }
+
+ if ($formatter = $nameGuesser->guessFormat($columnMap->getPhpName(), $columnMap->getSize())) {
+ $formatters[$columnMap->getPhpName()] = $formatter;
+
+ continue;
+ }
+
+ if ($formatter = $columnTypeGuesser->guessFormat($columnMap)) {
+ $formatters[$columnMap->getPhpName()] = $formatter;
+
+ continue;
+ }
+ }
+
+ return $formatters;
+ }
+
+ /**
+ * @return bool
+ */
+ protected function isColumnBehavior(\ColumnMap $columnMap)
+ {
+ foreach ($columnMap->getTable()->getBehaviors() as $name => $params) {
+ $columnName = Base::toLower($columnMap->getName());
+
+ switch ($name) {
+ case 'nested_set':
+ $columnNames = [$params['left_column'], $params['right_column'], $params['level_column']];
+
+ if (in_array($columnName, $columnNames, false)) {
+ return true;
+ }
+
+ break;
+
+ case 'timestampable':
+ $columnNames = [$params['create_column'], $params['update_column']];
+
+ if (in_array($columnName, $columnNames, false)) {
+ return true;
+ }
+
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ public function setModifiers($modifiers)
+ {
+ $this->modifiers = $modifiers;
+ }
+
+ /**
+ * @return array
+ */
+ public function getModifiers()
+ {
+ return $this->modifiers;
+ }
+
+ public function mergeModifiersWith($modifiers)
+ {
+ $this->modifiers = array_merge($this->modifiers, $modifiers);
+ }
+
+ /**
+ * @return array
+ */
+ public function guessModifiers(\Faker\Generator $generator)
+ {
+ $modifiers = [];
+ $class = $this->class;
+ $peerClass = $class::PEER;
+ $tableMap = $peerClass::getTableMap();
+
+ foreach ($tableMap->getBehaviors() as $name => $params) {
+ switch ($name) {
+ case 'nested_set':
+ $modifiers['nested_set'] = static function ($obj, $inserted) use ($class, $generator): void {
+ if (isset($inserted[$class])) {
+ $queryClass = $class . 'Query';
+ $parent = $queryClass::create()->findPk($generator->randomElement($inserted[$class]));
+ $obj->insertAsLastChildOf($parent);
+ } else {
+ $obj->makeRoot();
+ }
+ };
+
+ break;
+
+ case 'sortable':
+ $modifiers['sortable'] = static function ($obj, $inserted) use ($class, $generator): void {
+ $obj->insertAtRank($generator->numberBetween(1, count($inserted[$class] ?? []) + 1));
+ };
+
+ break;
+ }
+ }
+
+ return $modifiers;
+ }
+
+ /**
+ * Insert one new record using the Entity class.
+ */
+ public function execute($con, $insertedEntities)
+ {
+ $obj = new $this->class();
+
+ foreach ($this->getColumnFormatters() as $column => $format) {
+ if (null !== $format) {
+ $obj->setByName($column, is_callable($format) ? $format($insertedEntities, $obj) : $format);
+ }
+ }
+
+ foreach ($this->getModifiers() as $modifier) {
+ $modifier($obj, $insertedEntities);
+ }
+ $obj->save($con);
+
+ return $obj->getPrimaryKey();
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/Propel/Populator.php b/vendor/fakerphp/faker/src/Faker/ORM/Propel/Populator.php
new file mode 100755
index 00000000..e3d42981
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/Propel/Populator.php
@@ -0,0 +1,90 @@
+generator = $generator;
+ }
+
+ /**
+ * Add an order for the generation of $number records for $entity.
+ *
+ * @param mixed $entity A Propel ActiveRecord classname, or a \Faker\ORM\Propel\EntityPopulator instance
+ * @param int $number The number of entities to populate
+ */
+ public function addEntity($entity, $number, $customColumnFormatters = [], $customModifiers = [])
+ {
+ if (!$entity instanceof \Faker\ORM\Propel\EntityPopulator) {
+ $entity = new \Faker\ORM\Propel\EntityPopulator($entity);
+ }
+ $entity->setColumnFormatters($entity->guessColumnFormatters($this->generator));
+
+ if ($customColumnFormatters) {
+ $entity->mergeColumnFormattersWith($customColumnFormatters);
+ }
+ $entity->setModifiers($entity->guessModifiers($this->generator));
+
+ if ($customModifiers) {
+ $entity->mergeModifiersWith($customModifiers);
+ }
+ $class = $entity->getClass();
+ $this->entities[$class] = $entity;
+ $this->quantities[$class] = $number;
+ }
+
+ /**
+ * Populate the database using all the Entity classes previously added.
+ *
+ * @param PropelPDO $con A Propel connection object
+ *
+ * @return array A list of the inserted PKs
+ */
+ public function execute($con = null)
+ {
+ if (null === $con) {
+ $con = $this->getConnection();
+ }
+ $isInstancePoolingEnabled = \Propel::isInstancePoolingEnabled();
+ \Propel::disableInstancePooling();
+ $insertedEntities = [];
+ $con->beginTransaction();
+
+ foreach ($this->quantities as $class => $number) {
+ for ($i = 0; $i < $number; ++$i) {
+ $insertedEntities[$class][] = $this->entities[$class]->execute($con, $insertedEntities);
+ }
+ }
+ $con->commit();
+
+ if ($isInstancePoolingEnabled) {
+ \Propel::enableInstancePooling();
+ }
+
+ return $insertedEntities;
+ }
+
+ protected function getConnection()
+ {
+ // use the first connection available
+ $class = key($this->entities);
+
+ if (!$class) {
+ throw new \RuntimeException('No class found from entities. Did you add entities to the Populator ?');
+ }
+
+ $peer = $class::PEER;
+
+ return \Propel::getConnection($peer::DATABASE_NAME, \Propel::CONNECTION_WRITE);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/Propel2/ColumnTypeGuesser.php b/vendor/fakerphp/faker/src/Faker/ORM/Propel2/ColumnTypeGuesser.php
new file mode 100755
index 00000000..4c08e0ad
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/Propel2/ColumnTypeGuesser.php
@@ -0,0 +1,112 @@
+generator = $generator;
+ }
+
+ /**
+ * @return \Closure|null
+ */
+ public function guessFormat(ColumnMap $column)
+ {
+ $generator = $this->generator;
+
+ if ($column->isTemporal()) {
+ if ($column->getType() == PropelTypes::BU_DATE || $column->getType() == PropelTypes::BU_TIMESTAMP) {
+ return static function () use ($generator) {
+ return $generator->dateTime;
+ };
+ }
+
+ return static function () use ($generator) {
+ return $generator->dateTimeAD;
+ };
+ }
+ $type = $column->getType();
+
+ switch ($type) {
+ case PropelTypes::BOOLEAN:
+ case PropelTypes::BOOLEAN_EMU:
+ return static function () use ($generator) {
+ return $generator->boolean;
+ };
+
+ case PropelTypes::NUMERIC:
+ case PropelTypes::DECIMAL:
+ $size = $column->getSize();
+
+ return static function () use ($generator, $size) {
+ return $generator->randomNumber($size + 2) / 100;
+ };
+
+ case PropelTypes::TINYINT:
+ return static function () use ($generator) {
+ return $generator->numberBetween(0, 127);
+ };
+
+ case PropelTypes::SMALLINT:
+ return static function () use ($generator) {
+ return $generator->numberBetween(0, 32767);
+ };
+
+ case PropelTypes::INTEGER:
+ return static function () use ($generator) {
+ return $generator->numberBetween(0, 2147483647);
+ };
+
+ case PropelTypes::BIGINT:
+ return static function () use ($generator) {
+ return $generator->numberBetween(0, PHP_INT_MAX);
+ };
+
+ case PropelTypes::FLOAT:
+ case PropelTypes::DOUBLE:
+ case PropelTypes::REAL:
+ return static function () use ($generator) {
+ return $generator->randomFloat();
+ };
+
+ case PropelTypes::CHAR:
+ case PropelTypes::VARCHAR:
+ case PropelTypes::BINARY:
+ case PropelTypes::VARBINARY:
+ $size = $column->getSize();
+
+ return static function () use ($generator, $size) {
+ return $generator->text($size);
+ };
+
+ case PropelTypes::LONGVARCHAR:
+ case PropelTypes::LONGVARBINARY:
+ case PropelTypes::CLOB:
+ case PropelTypes::CLOB_EMU:
+ case PropelTypes::BLOB:
+ return static function () use ($generator) {
+ return $generator->text;
+ };
+
+ case PropelTypes::ENUM:
+ $valueSet = $column->getValueSet();
+
+ return static function () use ($generator, $valueSet) {
+ return $generator->randomElement($valueSet);
+ };
+
+ case PropelTypes::OBJECT:
+ case PropelTypes::PHP_ARRAY:
+ default:
+ // no smart way to guess what the user expects here
+ return null;
+ }
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/Propel2/EntityPopulator.php b/vendor/fakerphp/faker/src/Faker/ORM/Propel2/EntityPopulator.php
new file mode 100755
index 00000000..44804e37
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/Propel2/EntityPopulator.php
@@ -0,0 +1,207 @@
+class = $class;
+ }
+
+ /**
+ * @return string
+ */
+ public function getClass()
+ {
+ return $this->class;
+ }
+
+ public function setColumnFormatters($columnFormatters)
+ {
+ $this->columnFormatters = $columnFormatters;
+ }
+
+ /**
+ * @return array
+ */
+ public function getColumnFormatters()
+ {
+ return $this->columnFormatters;
+ }
+
+ public function mergeColumnFormattersWith($columnFormatters)
+ {
+ $this->columnFormatters = array_merge($this->columnFormatters, $columnFormatters);
+ }
+
+ /**
+ * @return array
+ */
+ public function guessColumnFormatters(\Faker\Generator $generator)
+ {
+ $formatters = [];
+ $class = $this->class;
+ $peerClass = $class::TABLE_MAP;
+ $tableMap = $peerClass::getTableMap();
+ $nameGuesser = new \Faker\Guesser\Name($generator);
+ $columnTypeGuesser = new \Faker\ORM\Propel2\ColumnTypeGuesser($generator);
+
+ foreach ($tableMap->getColumns() as $columnMap) {
+ // skip behavior columns, handled by modifiers
+ if ($this->isColumnBehavior($columnMap)) {
+ continue;
+ }
+
+ if ($columnMap->isForeignKey()) {
+ $relatedClass = $columnMap->getRelation()->getForeignTable()->getClassname();
+ $formatters[$columnMap->getPhpName()] = static function ($inserted) use ($relatedClass, $generator) {
+ $relatedClass = trim($relatedClass, '\\');
+
+ return isset($inserted[$relatedClass]) ? $generator->randomElement($inserted[$relatedClass]) : null;
+ };
+
+ continue;
+ }
+
+ if ($columnMap->isPrimaryKey()) {
+ continue;
+ }
+
+ if ($formatter = $nameGuesser->guessFormat($columnMap->getPhpName(), $columnMap->getSize())) {
+ $formatters[$columnMap->getPhpName()] = $formatter;
+
+ continue;
+ }
+
+ if ($formatter = $columnTypeGuesser->guessFormat($columnMap)) {
+ $formatters[$columnMap->getPhpName()] = $formatter;
+
+ continue;
+ }
+ }
+
+ return $formatters;
+ }
+
+ /**
+ * @return bool
+ */
+ protected function isColumnBehavior(ColumnMap $columnMap)
+ {
+ foreach ($columnMap->getTable()->getBehaviors() as $name => $params) {
+ $columnName = Base::toLower($columnMap->getName());
+
+ switch ($name) {
+ case 'nested_set':
+ $columnNames = [$params['left_column'], $params['right_column'], $params['level_column']];
+
+ if (in_array($columnName, $columnNames, false)) {
+ return true;
+ }
+
+ break;
+
+ case 'timestampable':
+ $columnNames = [$params['create_column'], $params['update_column']];
+
+ if (in_array($columnName, $columnNames, false)) {
+ return true;
+ }
+
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ public function setModifiers($modifiers)
+ {
+ $this->modifiers = $modifiers;
+ }
+
+ /**
+ * @return array
+ */
+ public function getModifiers()
+ {
+ return $this->modifiers;
+ }
+
+ public function mergeModifiersWith($modifiers)
+ {
+ $this->modifiers = array_merge($this->modifiers, $modifiers);
+ }
+
+ /**
+ * @return array
+ */
+ public function guessModifiers(\Faker\Generator $generator)
+ {
+ $modifiers = [];
+ $class = $this->class;
+ $peerClass = $class::TABLE_MAP;
+ $tableMap = $peerClass::getTableMap();
+
+ foreach ($tableMap->getBehaviors() as $name => $params) {
+ switch ($name) {
+ case 'nested_set':
+ $modifiers['nested_set'] = static function ($obj, $inserted) use ($class, $generator): void {
+ if (isset($inserted[$class])) {
+ $queryClass = $class . 'Query';
+ $parent = $queryClass::create()->findPk($generator->randomElement($inserted[$class]));
+ $obj->insertAsLastChildOf($parent);
+ } else {
+ $obj->makeRoot();
+ }
+ };
+
+ break;
+
+ case 'sortable':
+ $modifiers['sortable'] = static function ($obj, $inserted) use ($class, $generator): void {
+ $obj->insertAtRank($generator->numberBetween(1, count($inserted[$class] ?? []) + 1));
+ };
+
+ break;
+ }
+ }
+
+ return $modifiers;
+ }
+
+ /**
+ * Insert one new record using the Entity class.
+ */
+ public function execute($con, $insertedEntities)
+ {
+ $obj = new $this->class();
+
+ foreach ($this->getColumnFormatters() as $column => $format) {
+ if (null !== $format) {
+ $obj->setByName($column, is_callable($format) ? $format($insertedEntities, $obj) : $format);
+ }
+ }
+
+ foreach ($this->getModifiers() as $modifier) {
+ $modifier($obj, $insertedEntities);
+ }
+ $obj->save($con);
+
+ return $obj->getPrimaryKey();
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/Propel2/Populator.php b/vendor/fakerphp/faker/src/Faker/ORM/Propel2/Populator.php
new file mode 100755
index 00000000..7698f80e
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/Propel2/Populator.php
@@ -0,0 +1,93 @@
+generator = $generator;
+ }
+
+ /**
+ * Add an order for the generation of $number records for $entity.
+ *
+ * @param mixed $entity A Propel ActiveRecord classname, or a \Faker\ORM\Propel2\EntityPopulator instance
+ * @param int $number The number of entities to populate
+ */
+ public function addEntity($entity, $number, $customColumnFormatters = [], $customModifiers = [])
+ {
+ if (!$entity instanceof \Faker\ORM\Propel2\EntityPopulator) {
+ $entity = new \Faker\ORM\Propel2\EntityPopulator($entity);
+ }
+ $entity->setColumnFormatters($entity->guessColumnFormatters($this->generator));
+
+ if ($customColumnFormatters) {
+ $entity->mergeColumnFormattersWith($customColumnFormatters);
+ }
+ $entity->setModifiers($entity->guessModifiers($this->generator));
+
+ if ($customModifiers) {
+ $entity->mergeModifiersWith($customModifiers);
+ }
+ $class = $entity->getClass();
+ $this->entities[$class] = $entity;
+ $this->quantities[$class] = $number;
+ }
+
+ /**
+ * Populate the database using all the Entity classes previously added.
+ *
+ * @param PropelPDO $con A Propel connection object
+ *
+ * @return array A list of the inserted PKs
+ */
+ public function execute($con = null)
+ {
+ if (null === $con) {
+ $con = $this->getConnection();
+ }
+ $isInstancePoolingEnabled = Propel::isInstancePoolingEnabled();
+ Propel::disableInstancePooling();
+ $insertedEntities = [];
+ $con->beginTransaction();
+
+ foreach ($this->quantities as $class => $number) {
+ for ($i = 0; $i < $number; ++$i) {
+ $insertedEntities[$class][] = $this->entities[$class]->execute($con, $insertedEntities);
+ }
+ }
+ $con->commit();
+
+ if ($isInstancePoolingEnabled) {
+ Propel::enableInstancePooling();
+ }
+
+ return $insertedEntities;
+ }
+
+ protected function getConnection()
+ {
+ // use the first connection available
+ $class = key($this->entities);
+
+ if (!$class) {
+ throw new \RuntimeException('No class found from entities. Did you add entities to the Populator ?');
+ }
+
+ $peer = $class::TABLE_MAP;
+
+ return Propel::getConnection($peer::DATABASE_NAME, ServiceContainerInterface::CONNECTION_WRITE);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/Spot/ColumnTypeGuesser.php b/vendor/fakerphp/faker/src/Faker/ORM/Spot/ColumnTypeGuesser.php
new file mode 100755
index 00000000..f06ba048
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/Spot/ColumnTypeGuesser.php
@@ -0,0 +1,84 @@
+generator = $generator;
+ }
+
+ /**
+ * @return \Closure|null
+ */
+ public function guessFormat(array $field)
+ {
+ $generator = $this->generator;
+ $type = $field['type'];
+
+ switch ($type) {
+ case 'boolean':
+ return static function () use ($generator) {
+ return $generator->boolean;
+ };
+
+ case 'decimal':
+ $size = $field['precision'] ?? 2;
+
+ return static function () use ($generator, $size) {
+ return $generator->randomNumber($size + 2) / 100;
+ };
+
+ case 'smallint':
+ return static function () use ($generator) {
+ return $generator->numberBetween(0, 65535);
+ };
+
+ case 'integer':
+ return static function () use ($generator) {
+ return $generator->numberBetween(0, 2147483647);
+ };
+
+ case 'bigint':
+ return static function () use ($generator) {
+ return $generator->numberBetween(0, PHP_INT_MAX);
+ };
+
+ case 'float':
+ return static function () use ($generator) {
+ return $generator->randomFloat(null, 0, 4294967295);
+ };
+
+ case 'string':
+ $size = $field['length'] ?? 255;
+
+ return static function () use ($generator, $size) {
+ return $generator->text($size);
+ };
+
+ case 'text':
+ return static function () use ($generator) {
+ return $generator->text;
+ };
+
+ case 'datetime':
+ case 'date':
+ case 'time':
+ return static function () use ($generator) {
+ return $generator->datetime;
+ };
+
+ default:
+ // no smart way to guess what the user expects here
+ return null;
+ }
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/Spot/EntityPopulator.php b/vendor/fakerphp/faker/src/Faker/ORM/Spot/EntityPopulator.php
new file mode 100755
index 00000000..b67ae253
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/Spot/EntityPopulator.php
@@ -0,0 +1,199 @@
+mapper = $mapper;
+ $this->locator = $locator;
+ $this->useExistingData = $useExistingData;
+ }
+
+ /**
+ * @return string
+ */
+ public function getMapper()
+ {
+ return $this->mapper;
+ }
+
+ public function setColumnFormatters($columnFormatters)
+ {
+ $this->columnFormatters = $columnFormatters;
+ }
+
+ /**
+ * @return array
+ */
+ public function getColumnFormatters()
+ {
+ return $this->columnFormatters;
+ }
+
+ public function mergeColumnFormattersWith($columnFormatters)
+ {
+ $this->columnFormatters = array_merge($this->columnFormatters, $columnFormatters);
+ }
+
+ public function setModifiers(array $modifiers)
+ {
+ $this->modifiers = $modifiers;
+ }
+
+ /**
+ * @return array
+ */
+ public function getModifiers()
+ {
+ return $this->modifiers;
+ }
+
+ public function mergeModifiersWith(array $modifiers)
+ {
+ $this->modifiers = array_merge($this->modifiers, $modifiers);
+ }
+
+ /**
+ * @return array
+ */
+ public function guessColumnFormatters(Generator $generator)
+ {
+ $formatters = [];
+ $nameGuesser = new Name($generator);
+ $columnTypeGuesser = new ColumnTypeGuesser($generator);
+ $fields = $this->mapper->fields();
+
+ foreach ($fields as $fieldName => $field) {
+ if ($field['primary'] === true) {
+ continue;
+ }
+
+ if ($formatter = $nameGuesser->guessFormat($fieldName)) {
+ $formatters[$fieldName] = $formatter;
+
+ continue;
+ }
+
+ if ($formatter = $columnTypeGuesser->guessFormat($field)) {
+ $formatters[$fieldName] = $formatter;
+
+ continue;
+ }
+ }
+ $entityName = $this->mapper->entity();
+ $entity = $this->mapper->build([]);
+ $relations = $entityName::relations($this->mapper, $entity);
+
+ foreach ($relations as $relation) {
+ // We don't need any other relation here.
+ if ($relation instanceof BelongsTo) {
+ $fieldName = $relation->localKey();
+ $entityName = $relation->entityName();
+ $field = $fields[$fieldName];
+ $required = $field['required'];
+
+ $locator = $this->locator;
+
+ $formatters[$fieldName] = function ($inserted) use ($required, $entityName, $locator, $generator) {
+ if (!empty($inserted[$entityName])) {
+ return $generator->randomElement($inserted[$entityName])->get('id');
+ }
+
+ if ($required && $this->useExistingData) {
+ // We did not add anything like this, but it's required,
+ // So let's find something existing in DB.
+ $mapper = $locator->mapper($entityName);
+ $records = $mapper->all()->limit(self::RELATED_FETCH_COUNT)->toArray();
+
+ if (empty($records)) {
+ return null;
+ }
+
+ return $generator->randomElement($records)['id'];
+ }
+
+ return null;
+ };
+ }
+ }
+
+ return $formatters;
+ }
+
+ /**
+ * Insert one new record using the Entity class.
+ *
+ * @return string
+ */
+ public function execute($insertedEntities)
+ {
+ $obj = $this->mapper->build([]);
+
+ $this->fillColumns($obj, $insertedEntities);
+ $this->callMethods($obj, $insertedEntities);
+
+ $this->mapper->insert($obj);
+
+ return $obj;
+ }
+
+ private function fillColumns($obj, $insertedEntities): void
+ {
+ foreach ($this->columnFormatters as $field => $format) {
+ if (null !== $format) {
+ $value = is_callable($format) ? $format($insertedEntities, $obj) : $format;
+ $obj->set($field, $value);
+ }
+ }
+ }
+
+ private function callMethods($obj, $insertedEntities): void
+ {
+ foreach ($this->getModifiers() as $modifier) {
+ $modifier($obj, $insertedEntities);
+ }
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/ORM/Spot/Populator.php b/vendor/fakerphp/faker/src/Faker/ORM/Spot/Populator.php
new file mode 100755
index 00000000..b321f5c5
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/ORM/Spot/Populator.php
@@ -0,0 +1,89 @@
+generator = $generator;
+ $this->locator = $locator;
+ }
+
+ /**
+ * Add an order for the generation of $number records for $entity.
+ *
+ * @param string $entityName Name of Entity object to generate
+ * @param int $number The number of entities to populate
+ * @param array $customColumnFormatters
+ * @param array $customModifiers
+ * @param bool $useExistingData Should we use existing rows (e.g. roles) to populate relations?
+ */
+ public function addEntity(
+ $entityName,
+ $number,
+ $customColumnFormatters = [],
+ $customModifiers = [],
+ $useExistingData = false
+ ) {
+ $mapper = $this->locator->mapper($entityName);
+
+ if (null === $mapper) {
+ throw new \InvalidArgumentException('No mapper can be found for entity ' . $entityName);
+ }
+ $entity = new EntityPopulator($mapper, $this->locator, $useExistingData);
+
+ $entity->setColumnFormatters($entity->guessColumnFormatters($this->generator));
+
+ if ($customColumnFormatters) {
+ $entity->mergeColumnFormattersWith($customColumnFormatters);
+ }
+ $entity->mergeModifiersWith($customModifiers);
+
+ $this->entities[$entityName] = $entity;
+ $this->quantities[$entityName] = $number;
+ }
+
+ /**
+ * Populate the database using all the Entity classes previously added.
+ *
+ * @param Locator $locator A Spot locator
+ *
+ * @return array A list of the inserted PKs
+ */
+ public function execute($locator = null)
+ {
+ if (null === $locator) {
+ $locator = $this->locator;
+ }
+
+ if (null === $locator) {
+ throw new \InvalidArgumentException('No entity manager passed to Spot Populator.');
+ }
+
+ $insertedEntities = [];
+
+ foreach ($this->quantities as $entityName => $number) {
+ for ($i = 0; $i < $number; ++$i) {
+ $insertedEntities[$entityName][] = $this->entities[$entityName]->execute(
+ $insertedEntities,
+ );
+ }
+ }
+
+ return $insertedEntities;
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/Address.php b/vendor/fakerphp/faker/src/Faker/Provider/Address.php
new file mode 100755
index 00000000..9727497b
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/Address.php
@@ -0,0 +1,166 @@
+generator->parse($format);
+ }
+
+ /**
+ * @example 'Crist Parks'
+ *
+ * @return string
+ */
+ public function streetName()
+ {
+ $format = static::randomElement(static::$streetNameFormats);
+
+ return $this->generator->parse($format);
+ }
+
+ /**
+ * @example '791 Crist Parks'
+ *
+ * @return string
+ */
+ public function streetAddress()
+ {
+ $format = static::randomElement(static::$streetAddressFormats);
+
+ return $this->generator->parse($format);
+ }
+
+ /**
+ * @example 86039-9874
+ *
+ * @return string
+ */
+ public static function postcode()
+ {
+ return static::toUpper(static::bothify(static::randomElement(static::$postcode)));
+ }
+
+ /**
+ * @example '791 Crist Parks, Sashabury, IL 86039-9874'
+ *
+ * @return string
+ */
+ public function address()
+ {
+ $format = static::randomElement(static::$addressFormats);
+
+ return $this->generator->parse($format);
+ }
+
+ /**
+ * @example 'Japan'
+ *
+ * @return string
+ */
+ public static function country()
+ {
+ return static::randomElement(static::$country);
+ }
+
+ /**
+ * Uses signed degrees format (returns a float number between -90 and 90)
+ *
+ * @example '77.147489'
+ *
+ * @param float|int $min
+ * @param float|int $max
+ *
+ * @return float
+ */
+ public static function latitude($min = -90, $max = 90)
+ {
+ return static::randomFloat(6, $min, $max);
+ }
+
+ /**
+ * Uses signed degrees format (returns a float number between -180 and 180)
+ *
+ * @example '86.211205'
+ *
+ * @param float|int $min
+ * @param float|int $max
+ *
+ * @return float
+ */
+ public static function longitude($min = -180, $max = 180)
+ {
+ return static::randomFloat(6, $min, $max);
+ }
+
+ /**
+ * @example array('77.147489', '86.211205')
+ *
+ * @return float[]
+ */
+ public static function localCoordinates()
+ {
+ return [
+ 'latitude' => static::latitude(),
+ 'longitude' => static::longitude(),
+ ];
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/Barcode.php b/vendor/fakerphp/faker/src/Faker/Provider/Barcode.php
new file mode 100755
index 00000000..0d39a61e
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/Barcode.php
@@ -0,0 +1,107 @@
+ean(13);
+ }
+
+ /**
+ * Get a random EAN8 barcode.
+ *
+ * @return string
+ *
+ * @example '73513537'
+ */
+ public function ean8()
+ {
+ return $this->ean(8);
+ }
+
+ /**
+ * Get a random ISBN-10 code
+ *
+ * @see http://en.wikipedia.org/wiki/International_Standard_Book_Number
+ *
+ * @return string
+ *
+ * @example '4881416324'
+ */
+ public function isbn10()
+ {
+ $code = static::numerify(str_repeat('#', 9));
+
+ return $code . Isbn::checksum($code);
+ }
+
+ /**
+ * Get a random ISBN-13 code
+ *
+ * @see http://en.wikipedia.org/wiki/International_Standard_Book_Number
+ *
+ * @return string
+ *
+ * @example '9790404436093'
+ */
+ public function isbn13()
+ {
+ $code = '97' . self::numberBetween(8, 9) . static::numerify(str_repeat('#', 9));
+
+ return $code . Ean::checksum($code);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/Base.php b/vendor/fakerphp/faker/src/Faker/Provider/Base.php
new file mode 100755
index 00000000..e3713ce0
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/Base.php
@@ -0,0 +1,661 @@
+generator = $generator;
+ }
+
+ /**
+ * Returns a random number between 0 and 9
+ *
+ * @return int
+ */
+ public static function randomDigit()
+ {
+ return mt_rand(0, 9);
+ }
+
+ /**
+ * Returns a random number between 1 and 9
+ *
+ * @return int
+ */
+ public static function randomDigitNotNull()
+ {
+ return mt_rand(1, 9);
+ }
+
+ /**
+ * Generates a random digit, which cannot be $except
+ *
+ * @param int $except
+ *
+ * @return int
+ */
+ public static function randomDigitNot($except)
+ {
+ $result = self::numberBetween(0, 8);
+
+ if ($result >= $except) {
+ ++$result;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns a random integer with 0 to $nbDigits digits.
+ *
+ * The maximum value returned is mt_getrandmax()
+ *
+ * @param int $nbDigits Defaults to a random number between 1 and 9
+ * @param bool $strict Whether the returned number should have exactly $nbDigits
+ *
+ * @example 79907610
+ *
+ * @return int
+ */
+ public static function randomNumber($nbDigits = null, $strict = false)
+ {
+ if (!is_bool($strict)) {
+ throw new \InvalidArgumentException('randomNumber() generates numbers of fixed width. To generate numbers between two boundaries, use numberBetween() instead.');
+ }
+
+ if (null === $nbDigits) {
+ $nbDigits = static::randomDigitNotNull();
+ }
+ $max = 10 ** $nbDigits - 1;
+
+ if ($max > mt_getrandmax()) {
+ throw new \InvalidArgumentException('randomNumber() can only generate numbers up to mt_getrandmax()');
+ }
+
+ if ($strict) {
+ return mt_rand(10 ** ($nbDigits - 1), $max);
+ }
+
+ return mt_rand(0, $max);
+ }
+
+ /**
+ * Return a random float number
+ *
+ * @param int $nbMaxDecimals
+ * @param float|int $min
+ * @param float|int $max
+ *
+ * @example 48.8932
+ *
+ * @return float
+ */
+ public static function randomFloat($nbMaxDecimals = null, $min = 0, $max = null)
+ {
+ if (null === $nbMaxDecimals) {
+ $nbMaxDecimals = static::randomDigit();
+ }
+
+ if (null === $max) {
+ $max = static::randomNumber();
+
+ if ($min > $max) {
+ $max = $min;
+ }
+ }
+
+ if ($min > $max) {
+ $tmp = $min;
+ $min = $max;
+ $max = $tmp;
+ }
+
+ return round($min + mt_rand() / mt_getrandmax() * ($max - $min), $nbMaxDecimals);
+ }
+
+ /**
+ * Returns a random number between $int1 and $int2 (any order)
+ *
+ * @param int $int1 default to 0
+ * @param int $int2 defaults to 32 bit max integer, ie 2147483647
+ *
+ * @example 79907610
+ *
+ * @return int
+ */
+ public static function numberBetween($int1 = 0, $int2 = 2147483647)
+ {
+ $min = $int1 < $int2 ? $int1 : $int2;
+ $max = $int1 < $int2 ? $int2 : $int1;
+
+ return mt_rand($min, $max);
+ }
+
+ /**
+ * Returns the passed value
+ */
+ public static function passthrough($value)
+ {
+ return $value;
+ }
+
+ /**
+ * Returns a random letter from a to z
+ *
+ * @return string
+ */
+ public static function randomLetter()
+ {
+ return chr(mt_rand(97, 122));
+ }
+
+ /**
+ * Returns a random ASCII character (excluding accents and special chars)
+ *
+ * @return string
+ */
+ public static function randomAscii()
+ {
+ return chr(mt_rand(33, 126));
+ }
+
+ /**
+ * Returns randomly ordered subsequence of $count elements from a provided array
+ *
+ * @param array $array Array to take elements from. Defaults to a-c
+ * @param int $count Number of elements to take.
+ * @param bool $allowDuplicates Allow elements to be picked several times. Defaults to false
+ *
+ * @throws \LengthException When requesting more elements than provided
+ *
+ * @return array New array with $count elements from $array
+ */
+ public static function randomElements($array = ['a', 'b', 'c'], $count = 1, $allowDuplicates = false)
+ {
+ $traversables = [];
+
+ if ($array instanceof \Traversable) {
+ foreach ($array as $element) {
+ $traversables[] = $element;
+ }
+ }
+
+ $arr = count($traversables) ? $traversables : $array;
+
+ $allKeys = array_keys($arr);
+ $numKeys = count($allKeys);
+
+ if (!$allowDuplicates && $numKeys < $count) {
+ throw new \LengthException(sprintf('Cannot get %d elements, only %d in array', $count, $numKeys));
+ }
+
+ $highKey = $numKeys - 1;
+ $keys = $elements = [];
+ $numElements = 0;
+
+ while ($numElements < $count) {
+ $num = mt_rand(0, $highKey);
+
+ if (!$allowDuplicates) {
+ if (isset($keys[$num])) {
+ continue;
+ }
+ $keys[$num] = true;
+ }
+
+ $elements[] = $arr[$allKeys[$num]];
+ ++$numElements;
+ }
+
+ return $elements;
+ }
+
+ /**
+ * Returns a random element from a passed array
+ *
+ * @param array $array
+ */
+ public static function randomElement($array = ['a', 'b', 'c'])
+ {
+ if (!$array || ($array instanceof \Traversable && !count($array))) {
+ return null;
+ }
+ $elements = static::randomElements($array, 1);
+
+ return $elements[0];
+ }
+
+ /**
+ * Returns a random key from a passed associative array
+ *
+ * @param array $array
+ *
+ * @return int|string|null
+ */
+ public static function randomKey($array = [])
+ {
+ if (!$array) {
+ return null;
+ }
+ $keys = array_keys($array);
+
+ return $keys[mt_rand(0, count($keys) - 1)];
+ }
+
+ /**
+ * Returns a shuffled version of the argument.
+ *
+ * This function accepts either an array, or a string.
+ *
+ * @example $faker->shuffle([1, 2, 3]); // [2, 1, 3]
+ * @example $faker->shuffle('hello, world'); // 'rlo,h eold!lw'
+ *
+ * @see shuffleArray()
+ * @see shuffleString()
+ *
+ * @param array|string $arg The set to shuffle
+ *
+ * @return array|string The shuffled set
+ */
+ public static function shuffle($arg = '')
+ {
+ if (is_array($arg)) {
+ return static::shuffleArray($arg);
+ }
+
+ if (is_string($arg)) {
+ return static::shuffleString($arg);
+ }
+
+ throw new \InvalidArgumentException('shuffle() only supports strings or arrays');
+ }
+
+ /**
+ * Returns a shuffled version of the array.
+ *
+ * This function does not mutate the original array. It uses the
+ * Fisher–Yates algorithm, which is unbiased, together with a Mersenne
+ * twister random generator. This function is therefore more random than
+ * PHP's shuffle() function, and it is seedable.
+ *
+ * @see http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
+ *
+ * @example $faker->shuffleArray([1, 2, 3]); // [2, 1, 3]
+ *
+ * @param array $array The set to shuffle
+ *
+ * @return array The shuffled set
+ */
+ public static function shuffleArray($array = [])
+ {
+ $shuffledArray = [];
+ $i = 0;
+ reset($array);
+
+ foreach ($array as $key => $value) {
+ if ($i == 0) {
+ $j = 0;
+ } else {
+ $j = mt_rand(0, $i);
+ }
+
+ if ($j == $i) {
+ $shuffledArray[] = $value;
+ } else {
+ $shuffledArray[] = $shuffledArray[$j];
+ $shuffledArray[$j] = $value;
+ }
+ ++$i;
+ }
+
+ return $shuffledArray;
+ }
+
+ /**
+ * Returns a shuffled version of the string.
+ *
+ * This function does not mutate the original string. It uses the
+ * Fisher–Yates algorithm, which is unbiased, together with a Mersenne
+ * twister random generator. This function is therefore more random than
+ * PHP's shuffle() function, and it is seedable. Additionally, it is
+ * UTF8 safe if the mb extension is available.
+ *
+ * @see http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
+ *
+ * @example $faker->shuffleString('hello, world'); // 'rlo,h eold!lw'
+ *
+ * @param string $string The set to shuffle
+ * @param string $encoding The string encoding (defaults to UTF-8)
+ *
+ * @return string The shuffled set
+ */
+ public static function shuffleString($string = '', $encoding = 'UTF-8')
+ {
+ if (function_exists('mb_strlen')) {
+ // UTF8-safe str_split()
+ $array = [];
+ $strlen = mb_strlen($string, $encoding);
+
+ for ($i = 0; $i < $strlen; ++$i) {
+ $array[] = mb_substr($string, $i, 1, $encoding);
+ }
+ } else {
+ $array = str_split($string, 1);
+ }
+
+ return implode('', static::shuffleArray($array));
+ }
+
+ private static function replaceWildcard($string, $wildcard, $callback)
+ {
+ if (($pos = strpos($string, $wildcard)) === false) {
+ return $string;
+ }
+
+ for ($i = $pos, $last = strrpos($string, $wildcard, $pos) + 1; $i < $last; ++$i) {
+ if ($string[$i] === $wildcard) {
+ $string[$i] = call_user_func($callback);
+ }
+ }
+
+ return $string;
+ }
+
+ /**
+ * Replaces all hash sign ('#') occurrences with a random number
+ * Replaces all percentage sign ('%') occurrences with a not null number
+ *
+ * @param string $string String that needs to bet parsed
+ *
+ * @return string
+ */
+ public static function numerify($string = '###')
+ {
+ // instead of using randomDigit() several times, which is slow,
+ // count the number of hashes and generate once a large number
+ $toReplace = [];
+
+ if (($pos = strpos($string, '#')) !== false) {
+ for ($i = $pos, $last = strrpos($string, '#', $pos) + 1; $i < $last; ++$i) {
+ if ($string[$i] === '#') {
+ $toReplace[] = $i;
+ }
+ }
+ }
+
+ if ($nbReplacements = count($toReplace)) {
+ $maxAtOnce = strlen((string) mt_getrandmax()) - 1;
+ $numbers = '';
+ $i = 0;
+
+ while ($i < $nbReplacements) {
+ $size = min($nbReplacements - $i, $maxAtOnce);
+ $numbers .= str_pad(static::randomNumber($size), $size, '0', STR_PAD_LEFT);
+ $i += $size;
+ }
+
+ for ($i = 0; $i < $nbReplacements; ++$i) {
+ $string[$toReplace[$i]] = $numbers[$i];
+ }
+ }
+ $string = self::replaceWildcard($string, '%', [static::class, 'randomDigitNotNull']);
+
+ return $string;
+ }
+
+ /**
+ * Replaces all question mark ('?') occurrences with a random letter
+ *
+ * @param string $string String that needs to bet parsed
+ *
+ * @return string
+ */
+ public static function lexify($string = '????')
+ {
+ return self::replaceWildcard($string, '?', [static::class, 'randomLetter']);
+ }
+
+ /**
+ * Replaces hash signs ('#') and question marks ('?') with random numbers and letters
+ * An asterisk ('*') is replaced with either a random number or a random letter
+ *
+ * @param string $string String that needs to be parsed
+ *
+ * @return string
+ */
+ public static function bothify($string = '## ??')
+ {
+ $string = self::replaceWildcard($string, '*', static function () {
+ return mt_rand(0, 1) ? '#' : '?';
+ });
+
+ return static::lexify(static::numerify($string));
+ }
+
+ /**
+ * Replaces * signs with random numbers and letters and special characters
+ *
+ * @example $faker->asciify(''********'); // "s5'G!uC3"
+ *
+ * @param string $string String that needs to bet parsed
+ *
+ * @return string
+ */
+ public static function asciify($string = '****')
+ {
+ return preg_replace_callback('/\*/u', [static::class, 'randomAscii'], $string);
+ }
+
+ /**
+ * Transforms a basic regular expression into a random string satisfying the expression.
+ *
+ * @example $faker->regexify('[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}'); // sm0@y8k96a.ej
+ *
+ * Regex delimiters '/.../' and begin/end markers '^...$' are ignored.
+ *
+ * Only supports a small subset of the regex syntax. For instance,
+ * unicode, negated classes, unbounded ranges, subpatterns, back references,
+ * assertions, recursive patterns, and comments are not supported. Escaping
+ * support is extremely fragile.
+ *
+ * This method is also VERY slow. Use it only when no other formatter
+ * can generate the fake data you want. For instance, prefer calling
+ * `$faker->email` rather than `regexify` with the previous regular
+ * expression.
+ *
+ * Also note than `bothify` can probably do most of what this method does,
+ * but much faster. For instance, for a dummy email generation, try
+ * `$faker->bothify('?????????@???.???')`.
+ *
+ * @see https://github.com/icomefromthenet/ReverseRegex for a more robust implementation
+ *
+ * @param string $regex A regular expression (delimiters are optional)
+ *
+ * @return string
+ */
+ public static function regexify($regex = '')
+ {
+ // ditch the anchors
+ $regex = preg_replace('/^\/?\^?/', '', $regex);
+ $regex = preg_replace('/\$?\/?$/', '', $regex);
+ // All {2} become {2,2}
+ $regex = preg_replace('/\{(\d+)\}/', '{\1,\1}', $regex);
+ // Single-letter quantifiers (?, *, +) become bracket quantifiers ({0,1}, {0,rand}, {1, rand})
+ $regex = preg_replace('/(? 0 && $weight < 1 && mt_rand() / mt_getrandmax() <= $weight) {
+ return $this->generator;
+ }
+
+ // new system with percentage
+ if (is_int($weight) && mt_rand(1, 100) <= $weight) {
+ return $this->generator;
+ }
+
+ return new DefaultGenerator($default);
+ }
+
+ /**
+ * Chainable method for making any formatter unique.
+ *
+ *
+ * // will never return twice the same value
+ * $faker->unique()->randomElement(array(1, 2, 3));
+ *
+ *
+ * @param bool $reset If set to true, resets the list of existing values
+ * @param int $maxRetries Maximum number of retries to find a unique value,
+ * After which an OverflowException is thrown.
+ *
+ * @throws \OverflowException When no unique value can be found by iterating $maxRetries times
+ *
+ * @return UniqueGenerator A proxy class returning only non-existing values
+ */
+ public function unique($reset = false, $maxRetries = 10000)
+ {
+ if ($reset || !$this->unique) {
+ $this->unique = new UniqueGenerator($this->generator, $maxRetries);
+ }
+
+ return $this->unique;
+ }
+
+ /**
+ * Chainable method for forcing any formatter to return only valid values.
+ *
+ * The value validity is determined by a function passed as first argument.
+ *
+ *
+ * $values = array();
+ * $evenValidator = function ($digit) {
+ * return $digit % 2 === 0;
+ * };
+ * for ($i=0; $i < 10; $i++) {
+ * $values []= $faker->valid($evenValidator)->randomDigit;
+ * }
+ * print_r($values); // [0, 4, 8, 4, 2, 6, 0, 8, 8, 6]
+ *
+ *
+ * @param Closure $validator A function returning true for valid values
+ * @param int $maxRetries Maximum number of retries to find a unique value,
+ * After which an OverflowException is thrown.
+ *
+ * @throws \OverflowException When no valid value can be found by iterating $maxRetries times
+ *
+ * @return ValidGenerator A proxy class returning only valid values
+ */
+ public function valid($validator = null, $maxRetries = 10000)
+ {
+ return new ValidGenerator($this->generator, $validator, $maxRetries);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/Biased.php b/vendor/fakerphp/faker/src/Faker/Provider/Biased.php
new file mode 100755
index 00000000..42c70bcc
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/Biased.php
@@ -0,0 +1,65 @@
+generator->parse($format);
+ }
+
+ /**
+ * @example 'Ltd'
+ *
+ * @return string
+ */
+ public static function companySuffix()
+ {
+ return static::randomElement(static::$companySuffix);
+ }
+
+ /**
+ * @example 'Job'
+ *
+ * @return string
+ */
+ public function jobTitle()
+ {
+ $format = static::randomElement(static::$jobTitleFormat);
+
+ return $this->generator->parse($format);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/DateTime.php b/vendor/fakerphp/faker/src/Faker/Provider/DateTime.php
new file mode 100755
index 00000000..46c3c90f
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/DateTime.php
@@ -0,0 +1,383 @@
+getTimestamp();
+ }
+
+ return strtotime(empty($max) ? 'now' : $max);
+ }
+
+ /**
+ * Get a timestamp between January 1, 1970, and now
+ *
+ * @param \DateTime|int|string $max maximum timestamp used as random end limit, default to "now"
+ *
+ * @return int
+ *
+ * @example 1061306726
+ */
+ public static function unixTime($max = 'now')
+ {
+ return self::numberBetween(0, static::getMaxTimestamp($max));
+ }
+
+ /**
+ * Get a datetime object for a date between January 1, 1970 and now
+ *
+ * @param \DateTime|int|string $max maximum timestamp used as random end limit, default to "now"
+ * @param string $timezone time zone in which the date time should be set, default to DateTime::$defaultTimezone, if set, otherwise the result of `date_default_timezone_get`
+ *
+ * @return \DateTime
+ *
+ * @see http://php.net/manual/en/timezones.php
+ * @see http://php.net/manual/en/function.date-default-timezone-get.php
+ *
+ * @example DateTime('2005-08-16 20:39:21')
+ */
+ public static function dateTime($max = 'now', $timezone = null)
+ {
+ return static::setTimezone(
+ new \DateTime('@' . static::unixTime($max)),
+ $timezone,
+ );
+ }
+
+ /**
+ * Get a datetime object for a date between January 1, 001 and now
+ *
+ * @param \DateTime|int|string $max maximum timestamp used as random end limit, default to "now"
+ * @param string|null $timezone time zone in which the date time should be set, default to DateTime::$defaultTimezone, if set, otherwise the result of `date_default_timezone_get`
+ *
+ * @return \DateTime
+ *
+ * @see http://php.net/manual/en/timezones.php
+ * @see http://php.net/manual/en/function.date-default-timezone-get.php
+ *
+ * @example DateTime('1265-03-22 21:15:52')
+ */
+ public static function dateTimeAD($max = 'now', $timezone = null)
+ {
+ $min = (PHP_INT_SIZE > 4 ? -62135597361 : -PHP_INT_MAX);
+
+ return static::setTimezone(
+ new \DateTime('@' . self::numberBetween($min, static::getMaxTimestamp($max))),
+ $timezone,
+ );
+ }
+
+ /**
+ * get a date string formatted with ISO8601
+ *
+ * @param \DateTime|int|string $max maximum timestamp used as random end limit, default to "now"
+ *
+ * @return string
+ *
+ * @example '2003-10-21T16:05:52+0000'
+ */
+ public static function iso8601($max = 'now')
+ {
+ return static::date(\DateTime::ISO8601, $max);
+ }
+
+ /**
+ * Get a date string between January 1, 1970 and now
+ *
+ * @param string $format
+ * @param \DateTime|int|string $max maximum timestamp used as random end limit, default to "now"
+ *
+ * @return string
+ *
+ * @example '2008-11-27'
+ */
+ public static function date($format = 'Y-m-d', $max = 'now')
+ {
+ return static::dateTime($max)->format($format);
+ }
+
+ /**
+ * Get a time string (24h format by default)
+ *
+ * @param string $format
+ * @param \DateTime|int|string $max maximum timestamp used as random end limit, default to "now"
+ *
+ * @return string
+ *
+ * @example '15:02:34'
+ */
+ public static function time($format = 'H:i:s', $max = 'now')
+ {
+ return static::dateTime($max)->format($format);
+ }
+
+ /**
+ * Get a DateTime object based on a random date between two given dates.
+ * Accepts date strings that can be recognized by strtotime().
+ *
+ * @param \DateTime|string $startDate Defaults to 30 years ago
+ * @param \DateTime|string $endDate Defaults to "now"
+ * @param string|null $timezone time zone in which the date time should be set, default to DateTime::$defaultTimezone, if set, otherwise the result of `date_default_timezone_get`
+ *
+ * @return \DateTime
+ *
+ * @see http://php.net/manual/en/timezones.php
+ * @see http://php.net/manual/en/function.date-default-timezone-get.php
+ *
+ * @example DateTime('1999-02-02 11:42:52')
+ */
+ public static function dateTimeBetween($startDate = '-30 years', $endDate = 'now', $timezone = null)
+ {
+ $startTimestamp = $startDate instanceof \DateTime ? $startDate->getTimestamp() : strtotime($startDate);
+ $endTimestamp = static::getMaxTimestamp($endDate);
+
+ if ($startTimestamp > $endTimestamp) {
+ throw new \InvalidArgumentException('Start date must be anterior to end date.');
+ }
+
+ $timestamp = self::numberBetween($startTimestamp, $endTimestamp);
+
+ return static::setTimezone(
+ new \DateTime('@' . $timestamp),
+ $timezone,
+ );
+ }
+
+ /**
+ * Get a DateTime object based on a random date between one given date and
+ * an interval
+ * Accepts date string that can be recognized by strtotime().
+ *
+ * @param \DateTime|string $date Defaults to 30 years ago
+ * @param string $interval Defaults to 5 days after
+ * @param string|null $timezone time zone in which the date time should be set, default to DateTime::$defaultTimezone, if set, otherwise the result of `date_default_timezone_get`
+ *
+ * @return \DateTime
+ *
+ * @example dateTimeInInterval('1999-02-02 11:42:52', '+ 5 days')
+ *
+ * @see http://php.net/manual/en/timezones.php
+ * @see http://php.net/manual/en/function.date-default-timezone-get.php
+ */
+ public static function dateTimeInInterval($date = '-30 years', $interval = '+5 days', $timezone = null)
+ {
+ $intervalObject = \DateInterval::createFromDateString($interval);
+ $datetime = $date instanceof \DateTime ? $date : new \DateTime($date);
+ $otherDatetime = clone $datetime;
+ $otherDatetime->add($intervalObject);
+
+ $begin = min($datetime, $otherDatetime);
+ $end = $datetime === $begin ? $otherDatetime : $datetime;
+
+ return static::dateTimeBetween(
+ $begin,
+ $end,
+ $timezone,
+ );
+ }
+
+ /**
+ * Get a date time object somewhere within a century.
+ *
+ * @param \DateTime|int|string $max maximum timestamp used as random end limit, default to "now"
+ * @param string|null $timezone time zone in which the date time should be set, default to DateTime::$defaultTimezone, if set, otherwise the result of `date_default_timezone_get`
+ *
+ * @return \DateTime
+ */
+ public static function dateTimeThisCentury($max = 'now', $timezone = null)
+ {
+ return static::dateTimeBetween('-100 year', $max, $timezone);
+ }
+
+ /**
+ * Get a date time object somewhere within a decade.
+ *
+ * @param \DateTime|int|string $max maximum timestamp used as random end limit, default to "now"
+ * @param string|null $timezone time zone in which the date time should be set, default to DateTime::$defaultTimezone, if set, otherwise the result of `date_default_timezone_get`
+ *
+ * @return \DateTime
+ */
+ public static function dateTimeThisDecade($max = 'now', $timezone = null)
+ {
+ return static::dateTimeBetween('-10 year', $max, $timezone);
+ }
+
+ /**
+ * Get a date time object somewhere inside the current year.
+ *
+ * @param \DateTime|int|string $max maximum timestamp used as random end limit, default to "now"
+ * @param string|null $timezone time zone in which the date time should be set, default to DateTime::$defaultTimezone, if set, otherwise the result of `date_default_timezone_get`
+ *
+ * @return \DateTime
+ */
+ public static function dateTimeThisYear($max = 'now', $timezone = null)
+ {
+ return static::dateTimeBetween('first day of january this year', $max, $timezone);
+ }
+
+ /**
+ * Get a date time object somewhere within a month.
+ *
+ * @param \DateTime|int|string $max maximum timestamp used as random end limit, default to "now"
+ * @param string|null $timezone time zone in which the date time should be set, default to DateTime::$defaultTimezone, if set, otherwise the result of `date_default_timezone_get`
+ *
+ * @return \DateTime
+ */
+ public static function dateTimeThisMonth($max = 'now', $timezone = null)
+ {
+ return static::dateTimeBetween('-1 month', $max, $timezone);
+ }
+
+ /**
+ * Get a string containing either "am" or "pm".
+ *
+ * @param \DateTime|int|string $max maximum timestamp used as random end limit, default to "now"
+ *
+ * @return string
+ *
+ * @example 'am'
+ */
+ public static function amPm($max = 'now')
+ {
+ return static::dateTime($max)->format('a');
+ }
+
+ /**
+ * @param \DateTime|int|string $max maximum timestamp used as random end limit, default to "now"
+ *
+ * @return string
+ *
+ * @example '22'
+ */
+ public static function dayOfMonth($max = 'now')
+ {
+ return static::dateTime($max)->format('d');
+ }
+
+ /**
+ * @param \DateTime|int|string $max maximum timestamp used as random end limit, default to "now"
+ *
+ * @return string
+ *
+ * @example 'Tuesday'
+ */
+ public static function dayOfWeek($max = 'now')
+ {
+ return static::dateTime($max)->format('l');
+ }
+
+ /**
+ * @param \DateTime|int|string $max maximum timestamp used as random end limit, default to "now"
+ *
+ * @return string
+ *
+ * @example '7'
+ */
+ public static function month($max = 'now')
+ {
+ return static::dateTime($max)->format('m');
+ }
+
+ /**
+ * @param \DateTime|int|string $max maximum timestamp used as random end limit, default to "now"
+ *
+ * @return string
+ *
+ * @example 'September'
+ */
+ public static function monthName($max = 'now')
+ {
+ return static::dateTime($max)->format('F');
+ }
+
+ /**
+ * @param \DateTime|int|string $max maximum timestamp used as random end limit, default to "now"
+ *
+ * @return string
+ *
+ * @example '1987'
+ */
+ public static function year($max = 'now')
+ {
+ return static::dateTime($max)->format('Y');
+ }
+
+ /**
+ * @return string
+ *
+ * @example 'XVII'
+ */
+ public static function century()
+ {
+ return static::randomElement(static::$century);
+ }
+
+ /**
+ * @return string
+ *
+ * @example 'Europe/Paris'
+ */
+ public static function timezone()
+ {
+ return static::randomElement(\DateTimeZone::listIdentifiers());
+ }
+
+ /**
+ * Internal method to set the time zone on a DateTime.
+ *
+ * @param string|null $timezone
+ *
+ * @return \DateTime
+ */
+ private static function setTimezone(\DateTime $dt, $timezone)
+ {
+ return $dt->setTimezone(new \DateTimeZone(static::resolveTimezone($timezone)));
+ }
+
+ /**
+ * Sets default time zone.
+ *
+ * @param string $timezone
+ */
+ public static function setDefaultTimezone($timezone = null)
+ {
+ static::$defaultTimezone = $timezone;
+ }
+
+ /**
+ * Gets default time zone.
+ *
+ * @return string|null
+ */
+ public static function getDefaultTimezone()
+ {
+ return static::$defaultTimezone;
+ }
+
+ /**
+ * @param string|null $timezone
+ *
+ * @return string|null
+ */
+ private static function resolveTimezone($timezone)
+ {
+ return (null === $timezone) ? ((null === static::$defaultTimezone) ? date_default_timezone_get() : static::$defaultTimezone) : $timezone;
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/File.php b/vendor/fakerphp/faker/src/Faker/Provider/File.php
new file mode 100755
index 00000000..3cf3db9f
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/File.php
@@ -0,0 +1,610 @@
+ file extension(s)
+ *
+ * @see http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
+ */
+ protected static $mimeTypes = [
+ 'application/atom+xml' => 'atom',
+ 'application/ecmascript' => 'ecma',
+ 'application/emma+xml' => 'emma',
+ 'application/epub+zip' => 'epub',
+ 'application/java-archive' => 'jar',
+ 'application/java-vm' => 'class',
+ 'application/javascript' => 'js',
+ 'application/json' => 'json',
+ 'application/jsonml+json' => 'jsonml',
+ 'application/lost+xml' => 'lostxml',
+ 'application/mathml+xml' => 'mathml',
+ 'application/mets+xml' => 'mets',
+ 'application/mods+xml' => 'mods',
+ 'application/mp4' => 'mp4s',
+ 'application/msword' => ['doc', 'dot'],
+ 'application/octet-stream' => [
+ 'bin',
+ 'dms',
+ 'lrf',
+ 'mar',
+ 'so',
+ 'dist',
+ 'distz',
+ 'pkg',
+ 'bpk',
+ 'dump',
+ 'elc',
+ 'deploy',
+ ],
+ 'application/ogg' => 'ogx',
+ 'application/omdoc+xml' => 'omdoc',
+ 'application/pdf' => 'pdf',
+ 'application/pgp-encrypted' => 'pgp',
+ 'application/pgp-signature' => ['asc', 'sig'],
+ 'application/pkix-pkipath' => 'pkipath',
+ 'application/pkixcmp' => 'pki',
+ 'application/pls+xml' => 'pls',
+ 'application/postscript' => ['ai', 'eps', 'ps'],
+ 'application/pskc+xml' => 'pskcxml',
+ 'application/rdf+xml' => 'rdf',
+ 'application/reginfo+xml' => 'rif',
+ 'application/rss+xml' => 'rss',
+ 'application/rtf' => 'rtf',
+ 'application/sbml+xml' => 'sbml',
+ 'application/vnd.adobe.air-application-installer-package+zip' => 'air',
+ 'application/vnd.adobe.xdp+xml' => 'xdp',
+ 'application/vnd.adobe.xfdf' => 'xfdf',
+ 'application/vnd.ahead.space' => 'ahead',
+ 'application/vnd.dart' => 'dart',
+ 'application/vnd.data-vision.rdz' => 'rdz',
+ 'application/vnd.dece.data' => ['uvf', 'uvvf', 'uvd', 'uvvd'],
+ 'application/vnd.dece.ttml+xml' => ['uvt', 'uvvt'],
+ 'application/vnd.dece.unspecified' => ['uvx', 'uvvx'],
+ 'application/vnd.dece.zip' => ['uvz', 'uvvz'],
+ 'application/vnd.denovo.fcselayout-link' => 'fe_launch',
+ 'application/vnd.dna' => 'dna',
+ 'application/vnd.dolby.mlp' => 'mlp',
+ 'application/vnd.dpgraph' => 'dpg',
+ 'application/vnd.dreamfactory' => 'dfac',
+ 'application/vnd.ds-keypoint' => 'kpxx',
+ 'application/vnd.dvb.ait' => 'ait',
+ 'application/vnd.dvb.service' => 'svc',
+ 'application/vnd.dynageo' => 'geo',
+ 'application/vnd.ecowin.chart' => 'mag',
+ 'application/vnd.enliven' => 'nml',
+ 'application/vnd.epson.esf' => 'esf',
+ 'application/vnd.epson.msf' => 'msf',
+ 'application/vnd.epson.quickanime' => 'qam',
+ 'application/vnd.epson.salt' => 'slt',
+ 'application/vnd.epson.ssf' => 'ssf',
+ 'application/vnd.ezpix-album' => 'ez2',
+ 'application/vnd.ezpix-package' => 'ez3',
+ 'application/vnd.fdf' => 'fdf',
+ 'application/vnd.fdsn.mseed' => 'mseed',
+ 'application/vnd.fdsn.seed' => ['seed', 'dataless'],
+ 'application/vnd.flographit' => 'gph',
+ 'application/vnd.fluxtime.clip' => 'ftc',
+ 'application/vnd.hal+xml' => 'hal',
+ 'application/vnd.hydrostatix.sof-data' => 'sfd-hdstx',
+ 'application/vnd.ibm.minipay' => 'mpy',
+ 'application/vnd.ibm.secure-container' => 'sc',
+ 'application/vnd.iccprofile' => ['icc', 'icm'],
+ 'application/vnd.igloader' => 'igl',
+ 'application/vnd.immervision-ivp' => 'ivp',
+ 'application/vnd.kde.karbon' => 'karbon',
+ 'application/vnd.kde.kchart' => 'chrt',
+ 'application/vnd.kde.kformula' => 'kfo',
+ 'application/vnd.kde.kivio' => 'flw',
+ 'application/vnd.kde.kontour' => 'kon',
+ 'application/vnd.kde.kpresenter' => ['kpr', 'kpt'],
+ 'application/vnd.kde.kspread' => 'ksp',
+ 'application/vnd.kde.kword' => ['kwd', 'kwt'],
+ 'application/vnd.kenameaapp' => 'htke',
+ 'application/vnd.kidspiration' => 'kia',
+ 'application/vnd.kinar' => ['kne', 'knp'],
+ 'application/vnd.koan' => ['skp', 'skd', 'skt', 'skm'],
+ 'application/vnd.kodak-descriptor' => 'sse',
+ 'application/vnd.las.las+xml' => 'lasxml',
+ 'application/vnd.llamagraphics.life-balance.desktop' => 'lbd',
+ 'application/vnd.llamagraphics.life-balance.exchange+xml' => 'lbe',
+ 'application/vnd.lotus-1-2-3' => '123',
+ 'application/vnd.lotus-approach' => 'apr',
+ 'application/vnd.lotus-freelance' => 'pre',
+ 'application/vnd.lotus-notes' => 'nsf',
+ 'application/vnd.lotus-organizer' => 'org',
+ 'application/vnd.lotus-screencam' => 'scm',
+ 'application/vnd.mozilla.xul+xml' => 'xul',
+ 'application/vnd.ms-artgalry' => 'cil',
+ 'application/vnd.ms-cab-compressed' => 'cab',
+ 'application/vnd.ms-excel' => [
+ 'xls',
+ 'xlm',
+ 'xla',
+ 'xlc',
+ 'xlt',
+ 'xlw',
+ ],
+ 'application/vnd.ms-excel.addin.macroenabled.12' => 'xlam',
+ 'application/vnd.ms-excel.sheet.binary.macroenabled.12' => 'xlsb',
+ 'application/vnd.ms-excel.sheet.macroenabled.12' => 'xlsm',
+ 'application/vnd.ms-excel.template.macroenabled.12' => 'xltm',
+ 'application/vnd.ms-fontobject' => 'eot',
+ 'application/vnd.ms-htmlhelp' => 'chm',
+ 'application/vnd.ms-ims' => 'ims',
+ 'application/vnd.ms-lrm' => 'lrm',
+ 'application/vnd.ms-officetheme' => 'thmx',
+ 'application/vnd.ms-pki.seccat' => 'cat',
+ 'application/vnd.ms-pki.stl' => 'stl',
+ 'application/vnd.ms-powerpoint' => ['ppt', 'pps', 'pot'],
+ 'application/vnd.ms-powerpoint.addin.macroenabled.12' => 'ppam',
+ 'application/vnd.ms-powerpoint.presentation.macroenabled.12' => 'pptm',
+ 'application/vnd.ms-powerpoint.slide.macroenabled.12' => 'sldm',
+ 'application/vnd.ms-powerpoint.slideshow.macroenabled.12' => 'ppsm',
+ 'application/vnd.ms-powerpoint.template.macroenabled.12' => 'potm',
+ 'application/vnd.ms-project' => ['mpp', 'mpt'],
+ 'application/vnd.ms-word.document.macroenabled.12' => 'docm',
+ 'application/vnd.ms-word.template.macroenabled.12' => 'dotm',
+ 'application/vnd.ms-works' => ['wps', 'wks', 'wcm', 'wdb'],
+ 'application/vnd.ms-wpl' => 'wpl',
+ 'application/vnd.ms-xpsdocument' => 'xps',
+ 'application/vnd.mseq' => 'mseq',
+ 'application/vnd.musician' => 'mus',
+ 'application/vnd.oasis.opendocument.chart' => 'odc',
+ 'application/vnd.oasis.opendocument.chart-template' => 'otc',
+ 'application/vnd.oasis.opendocument.database' => 'odb',
+ 'application/vnd.oasis.opendocument.formula' => 'odf',
+ 'application/vnd.oasis.opendocument.formula-template' => 'odft',
+ 'application/vnd.oasis.opendocument.graphics' => 'odg',
+ 'application/vnd.oasis.opendocument.graphics-template' => 'otg',
+ 'application/vnd.oasis.opendocument.image' => 'odi',
+ 'application/vnd.oasis.opendocument.image-template' => 'oti',
+ 'application/vnd.oasis.opendocument.presentation' => 'odp',
+ 'application/vnd.oasis.opendocument.presentation-template' => 'otp',
+ 'application/vnd.oasis.opendocument.spreadsheet' => 'ods',
+ 'application/vnd.oasis.opendocument.spreadsheet-template' => 'ots',
+ 'application/vnd.oasis.opendocument.text' => 'odt',
+ 'application/vnd.oasis.opendocument.text-master' => 'odm',
+ 'application/vnd.oasis.opendocument.text-template' => 'ott',
+ 'application/vnd.oasis.opendocument.text-web' => 'oth',
+ 'application/vnd.olpc-sugar' => 'xo',
+ 'application/vnd.oma.dd2+xml' => 'dd2',
+ 'application/vnd.openofficeorg.extension' => 'oxt',
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'pptx',
+ 'application/vnd.openxmlformats-officedocument.presentationml.slide' => 'sldx',
+ 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => 'ppsx',
+ 'application/vnd.openxmlformats-officedocument.presentationml.template' => 'potx',
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'xlsx',
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => 'xltx',
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'docx',
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => 'dotx',
+ 'application/vnd.pvi.ptid1' => 'ptid',
+ 'application/vnd.quark.quarkxpress' => [
+ 'qxd',
+ 'qxt',
+ 'qwd',
+ 'qwt',
+ 'qxl',
+ 'qxb',
+ ],
+ 'application/vnd.realvnc.bed' => 'bed',
+ 'application/vnd.recordare.musicxml' => 'mxl',
+ 'application/vnd.recordare.musicxml+xml' => 'musicxml',
+ 'application/vnd.rig.cryptonote' => 'cryptonote',
+ 'application/vnd.rim.cod' => 'cod',
+ 'application/vnd.rn-realmedia' => 'rm',
+ 'application/vnd.rn-realmedia-vbr' => 'rmvb',
+ 'application/vnd.route66.link66+xml' => 'link66',
+ 'application/vnd.sailingtracker.track' => 'st',
+ 'application/vnd.seemail' => 'see',
+ 'application/vnd.sema' => 'sema',
+ 'application/vnd.semd' => 'semd',
+ 'application/vnd.semf' => 'semf',
+ 'application/vnd.shana.informed.formdata' => 'ifm',
+ 'application/vnd.shana.informed.formtemplate' => 'itp',
+ 'application/vnd.shana.informed.interchange' => 'iif',
+ 'application/vnd.shana.informed.package' => 'ipk',
+ 'application/vnd.simtech-mindmapper' => ['twd', 'twds'],
+ 'application/vnd.smaf' => 'mmf',
+ 'application/vnd.stepmania.stepchart' => 'sm',
+ 'application/vnd.sun.xml.calc' => 'sxc',
+ 'application/vnd.sun.xml.calc.template' => 'stc',
+ 'application/vnd.sun.xml.draw' => 'sxd',
+ 'application/vnd.sun.xml.draw.template' => 'std',
+ 'application/vnd.sun.xml.impress' => 'sxi',
+ 'application/vnd.sun.xml.impress.template' => 'sti',
+ 'application/vnd.sun.xml.math' => 'sxm',
+ 'application/vnd.sun.xml.writer' => 'sxw',
+ 'application/vnd.sun.xml.writer.global' => 'sxg',
+ 'application/vnd.sun.xml.writer.template' => 'stw',
+ 'application/vnd.sus-calendar' => ['sus', 'susp'],
+ 'application/vnd.svd' => 'svd',
+ 'application/vnd.symbian.install' => ['sis', 'sisx'],
+ 'application/vnd.syncml+xml' => 'xsm',
+ 'application/vnd.syncml.dm+wbxml' => 'bdm',
+ 'application/vnd.syncml.dm+xml' => 'xdm',
+ 'application/vnd.tao.intent-module-archive' => 'tao',
+ 'application/vnd.tcpdump.pcap' => ['pcap', 'cap', 'dmp'],
+ 'application/vnd.tmobile-livetv' => 'tmo',
+ 'application/vnd.trid.tpt' => 'tpt',
+ 'application/vnd.triscape.mxs' => 'mxs',
+ 'application/vnd.trueapp' => 'tra',
+ 'application/vnd.ufdl' => ['ufd', 'ufdl'],
+ 'application/vnd.uiq.theme' => 'utz',
+ 'application/vnd.umajin' => 'umj',
+ 'application/vnd.unity' => 'unityweb',
+ 'application/vnd.uoml+xml' => 'uoml',
+ 'application/vnd.vcx' => 'vcx',
+ 'application/vnd.visio' => ['vsd', 'vst', 'vss', 'vsw'],
+ 'application/vnd.visionary' => 'vis',
+ 'application/vnd.vsf' => 'vsf',
+ 'application/vnd.wap.wbxml' => 'wbxml',
+ 'application/vnd.wap.wmlc' => 'wmlc',
+ 'application/vnd.wap.wmlscriptc' => 'wmlsc',
+ 'application/vnd.webturbo' => 'wtb',
+ 'application/vnd.wolfram.player' => 'nbp',
+ 'application/vnd.wordperfect' => 'wpd',
+ 'application/vnd.wqd' => 'wqd',
+ 'application/vnd.wt.stf' => 'stf',
+ 'application/vnd.xara' => 'xar',
+ 'application/vnd.xfdl' => 'xfdl',
+ 'application/voicexml+xml' => 'vxml',
+ 'application/widget' => 'wgt',
+ 'application/winhlp' => 'hlp',
+ 'application/wsdl+xml' => 'wsdl',
+ 'application/wspolicy+xml' => 'wspolicy',
+ 'application/x-7z-compressed' => '7z',
+ 'application/x-bittorrent' => 'torrent',
+ 'application/x-blorb' => ['blb', 'blorb'],
+ 'application/x-bzip' => 'bz',
+ 'application/x-cdlink' => 'vcd',
+ 'application/x-cfs-compressed' => 'cfs',
+ 'application/x-chat' => 'chat',
+ 'application/x-chess-pgn' => 'pgn',
+ 'application/x-conference' => 'nsc',
+ 'application/x-cpio' => 'cpio',
+ 'application/x-csh' => 'csh',
+ 'application/x-debian-package' => ['deb', 'udeb'],
+ 'application/x-dgc-compressed' => 'dgc',
+ 'application/x-director' => [
+ 'dir',
+ 'dcr',
+ 'dxr',
+ 'cst',
+ 'cct',
+ 'cxt',
+ 'w3d',
+ 'fgd',
+ 'swa',
+ ],
+ 'application/x-font-ttf' => ['ttf', 'ttc'],
+ 'application/x-font-type1' => ['pfa', 'pfb', 'pfm', 'afm'],
+ 'application/x-font-woff' => 'woff',
+ 'application/x-freearc' => 'arc',
+ 'application/x-futuresplash' => 'spl',
+ 'application/x-gca-compressed' => 'gca',
+ 'application/x-glulx' => 'ulx',
+ 'application/x-gnumeric' => 'gnumeric',
+ 'application/x-gramps-xml' => 'gramps',
+ 'application/x-gtar' => 'gtar',
+ 'application/x-hdf' => 'hdf',
+ 'application/x-install-instructions' => 'install',
+ 'application/x-iso9660-image' => 'iso',
+ 'application/x-java-jnlp-file' => 'jnlp',
+ 'application/x-latex' => 'latex',
+ 'application/x-lzh-compressed' => ['lzh', 'lha'],
+ 'application/x-mie' => 'mie',
+ 'application/x-mobipocket-ebook' => ['prc', 'mobi'],
+ 'application/x-ms-application' => 'application',
+ 'application/x-ms-shortcut' => 'lnk',
+ 'application/x-ms-wmd' => 'wmd',
+ 'application/x-ms-wmz' => 'wmz',
+ 'application/x-ms-xbap' => 'xbap',
+ 'application/x-msaccess' => 'mdb',
+ 'application/x-msbinder' => 'obd',
+ 'application/x-mscardfile' => 'crd',
+ 'application/x-msclip' => 'clp',
+ 'application/x-msdownload' => ['exe', 'dll', 'com', 'bat', 'msi'],
+ 'application/x-msmediaview' => [
+ 'mvb',
+ 'm13',
+ 'm14',
+ ],
+ 'application/x-msmetafile' => ['wmf', 'wmz', 'emf', 'emz'],
+ 'application/x-rar-compressed' => 'rar',
+ 'application/x-research-info-systems' => 'ris',
+ 'application/x-sh' => 'sh',
+ 'application/x-shar' => 'shar',
+ 'application/x-shockwave-flash' => 'swf',
+ 'application/x-silverlight-app' => 'xap',
+ 'application/x-sql' => 'sql',
+ 'application/x-stuffit' => 'sit',
+ 'application/x-stuffitx' => 'sitx',
+ 'application/x-subrip' => 'srt',
+ 'application/x-sv4cpio' => 'sv4cpio',
+ 'application/x-sv4crc' => 'sv4crc',
+ 'application/x-t3vm-image' => 't3',
+ 'application/x-tads' => 'gam',
+ 'application/x-tar' => 'tar',
+ 'application/x-tcl' => 'tcl',
+ 'application/x-tex' => 'tex',
+ 'application/x-tex-tfm' => 'tfm',
+ 'application/x-texinfo' => ['texinfo', 'texi'],
+ 'application/x-tgif' => 'obj',
+ 'application/x-ustar' => 'ustar',
+ 'application/x-wais-source' => 'src',
+ 'application/x-x509-ca-cert' => ['der', 'crt'],
+ 'application/x-xfig' => 'fig',
+ 'application/x-xliff+xml' => 'xlf',
+ 'application/x-xpinstall' => 'xpi',
+ 'application/x-xz' => 'xz',
+ 'application/x-zmachine' => 'z1',
+ 'application/xaml+xml' => 'xaml',
+ 'application/xcap-diff+xml' => 'xdf',
+ 'application/xenc+xml' => 'xenc',
+ 'application/xhtml+xml' => ['xhtml', 'xht'],
+ 'application/xml' => ['xml', 'xsl'],
+ 'application/xml-dtd' => 'dtd',
+ 'application/xop+xml' => 'xop',
+ 'application/xproc+xml' => 'xpl',
+ 'application/xslt+xml' => 'xslt',
+ 'application/xspf+xml' => 'xspf',
+ 'application/xv+xml' => ['mxml', 'xhvml', 'xvml', 'xvm'],
+ 'application/yang' => 'yang',
+ 'application/yin+xml' => 'yin',
+ 'application/zip' => 'zip',
+ 'audio/adpcm' => 'adp',
+ 'audio/basic' => ['au', 'snd'],
+ 'audio/midi' => ['mid', 'midi', 'kar', 'rmi'],
+ 'audio/mp4' => 'mp4a',
+ 'audio/mpeg' => [
+ 'mpga',
+ 'mp2',
+ 'mp2a',
+ 'mp3',
+ 'm2a',
+ 'm3a',
+ ],
+ 'audio/ogg' => ['oga', 'ogg', 'spx'],
+ 'audio/vnd.dece.audio' => ['uva', 'uvva'],
+ 'audio/vnd.rip' => 'rip',
+ 'audio/webm' => 'weba',
+ 'audio/x-aac' => 'aac',
+ 'audio/x-aiff' => ['aif', 'aiff', 'aifc'],
+ 'audio/x-caf' => 'caf',
+ 'audio/x-flac' => 'flac',
+ 'audio/x-matroska' => 'mka',
+ 'audio/x-mpegurl' => 'm3u',
+ 'audio/x-ms-wax' => 'wax',
+ 'audio/x-ms-wma' => 'wma',
+ 'audio/x-pn-realaudio' => ['ram', 'ra'],
+ 'audio/x-pn-realaudio-plugin' => 'rmp',
+ 'audio/x-wav' => 'wav',
+ 'audio/xm' => 'xm',
+ 'image/bmp' => 'bmp',
+ 'image/cgm' => 'cgm',
+ 'image/g3fax' => 'g3',
+ 'image/gif' => 'gif',
+ 'image/ief' => 'ief',
+ 'image/jpeg' => ['jpeg', 'jpg', 'jpe'],
+ 'image/ktx' => 'ktx',
+ 'image/png' => 'png',
+ 'image/prs.btif' => 'btif',
+ 'image/sgi' => 'sgi',
+ 'image/svg+xml' => ['svg', 'svgz'],
+ 'image/tiff' => ['tiff', 'tif'],
+ 'image/vnd.adobe.photoshop' => 'psd',
+ 'image/vnd.dece.graphic' => ['uvi', 'uvvi', 'uvg', 'uvvg'],
+ 'image/vnd.dvb.subtitle' => 'sub',
+ 'image/vnd.djvu' => ['djvu', 'djv'],
+ 'image/vnd.dwg' => 'dwg',
+ 'image/vnd.dxf' => 'dxf',
+ 'image/vnd.fastbidsheet' => 'fbs',
+ 'image/vnd.fpx' => 'fpx',
+ 'image/vnd.fst' => 'fst',
+ 'image/vnd.fujixerox.edmics-mmr' => 'mmr',
+ 'image/vnd.fujixerox.edmics-rlc' => 'rlc',
+ 'image/vnd.ms-modi' => 'mdi',
+ 'image/vnd.ms-photo' => 'wdp',
+ 'image/vnd.net-fpx' => 'npx',
+ 'image/vnd.wap.wbmp' => 'wbmp',
+ 'image/vnd.xiff' => 'xif',
+ 'image/webp' => 'webp',
+ 'image/x-3ds' => '3ds',
+ 'image/x-cmu-raster' => 'ras',
+ 'image/x-cmx' => 'cmx',
+ 'image/x-freehand' => ['fh', 'fhc', 'fh4', 'fh5', 'fh7'],
+ 'image/x-icon' => 'ico',
+ 'image/x-mrsid-image' => 'sid',
+ 'image/x-pcx' => 'pcx',
+ 'image/x-pict' => ['pic', 'pct'],
+ 'image/x-portable-anymap' => 'pnm',
+ 'image/x-portable-bitmap' => 'pbm',
+ 'image/x-portable-graymap' => 'pgm',
+ 'image/x-portable-pixmap' => 'ppm',
+ 'image/x-rgb' => 'rgb',
+ 'image/x-tga' => 'tga',
+ 'image/x-xbitmap' => 'xbm',
+ 'image/x-xpixmap' => 'xpm',
+ 'image/x-xwindowdump' => 'xwd',
+ 'message/rfc822' => ['eml', 'mime'],
+ 'model/iges' => ['igs', 'iges'],
+ 'model/mesh' => ['msh', 'mesh', 'silo'],
+ 'model/vnd.collada+xml' => 'dae',
+ 'model/vnd.dwf' => 'dwf',
+ 'model/vnd.gdl' => 'gdl',
+ 'model/vnd.gtw' => 'gtw',
+ 'model/vnd.mts' => 'mts',
+ 'model/vnd.vtu' => 'vtu',
+ 'model/vrml' => ['wrl', 'vrml'],
+ 'model/x3d+binary' => 'x3db',
+ 'model/x3d+vrml' => 'x3dv',
+ 'model/x3d+xml' => 'x3d',
+ 'text/cache-manifest' => 'appcache',
+ 'text/calendar' => ['ics', 'ifb'],
+ 'text/css' => 'css',
+ 'text/csv' => 'csv',
+ 'text/html' => ['html', 'htm'],
+ 'text/n3' => 'n3',
+ 'text/plain' => [
+ 'txt',
+ 'text',
+ 'conf',
+ 'def',
+ 'list',
+ 'log',
+ 'in',
+ ],
+ 'text/prs.lines.tag' => 'dsc',
+ 'text/richtext' => 'rtx',
+ 'text/sgml' => ['sgml', 'sgm'],
+ 'text/tab-separated-values' => 'tsv',
+ 'text/troff' => [
+ 't',
+ 'tr',
+ 'roff',
+ 'man',
+ 'me',
+ 'ms',
+ ],
+ 'text/turtle' => 'ttl',
+ 'text/uri-list' => ['uri', 'uris', 'urls'],
+ 'text/vcard' => 'vcard',
+ 'text/vnd.curl' => 'curl',
+ 'text/vnd.curl.dcurl' => 'dcurl',
+ 'text/vnd.curl.scurl' => 'scurl',
+ 'text/vnd.curl.mcurl' => 'mcurl',
+ 'text/vnd.dvb.subtitle' => 'sub',
+ 'text/vnd.fly' => 'fly',
+ 'text/vnd.fmi.flexstor' => 'flx',
+ 'text/vnd.graphviz' => 'gv',
+ 'text/vnd.in3d.3dml' => '3dml',
+ 'text/vnd.in3d.spot' => 'spot',
+ 'text/vnd.sun.j2me.app-descriptor' => 'jad',
+ 'text/vnd.wap.wml' => 'wml',
+ 'text/vnd.wap.wmlscript' => 'wmls',
+ 'text/x-asm' => ['s', 'asm'],
+ 'text/x-fortran' => ['f', 'for', 'f77', 'f90'],
+ 'text/x-java-source' => 'java',
+ 'text/x-opml' => 'opml',
+ 'text/x-pascal' => ['p', 'pas'],
+ 'text/x-nfo' => 'nfo',
+ 'text/x-setext' => 'etx',
+ 'text/x-sfv' => 'sfv',
+ 'text/x-uuencode' => 'uu',
+ 'text/x-vcalendar' => 'vcs',
+ 'text/x-vcard' => 'vcf',
+ 'video/3gpp' => '3gp',
+ 'video/3gpp2' => '3g2',
+ 'video/h261' => 'h261',
+ 'video/h263' => 'h263',
+ 'video/h264' => 'h264',
+ 'video/jpeg' => 'jpgv',
+ 'video/jpm' => ['jpm', 'jpgm'],
+ 'video/mj2' => 'mj2',
+ 'video/mp4' => 'mp4',
+ 'video/mpeg' => ['mpeg', 'mpg', 'mpe', 'm1v', 'm2v'],
+ 'video/ogg' => 'ogv',
+ 'video/quicktime' => ['qt', 'mov'],
+ 'video/vnd.dece.hd' => ['uvh', 'uvvh'],
+ 'video/vnd.dece.mobile' => ['uvm', 'uvvm'],
+ 'video/vnd.dece.pd' => ['uvp', 'uvvp'],
+ 'video/vnd.dece.sd' => ['uvs', 'uvvs'],
+ 'video/vnd.dece.video' => ['uvv', 'uvvv'],
+ 'video/vnd.dvb.file' => 'dvb',
+ 'video/vnd.fvt' => 'fvt',
+ 'video/vnd.mpegurl' => ['mxu', 'm4u'],
+ 'video/vnd.ms-playready.media.pyv' => 'pyv',
+ 'video/vnd.uvvu.mp4' => ['uvu', 'uvvu'],
+ 'video/vnd.vivo' => 'viv',
+ 'video/webm' => 'webm',
+ 'video/x-f4v' => 'f4v',
+ 'video/x-fli' => 'fli',
+ 'video/x-flv' => 'flv',
+ 'video/x-m4v' => 'm4v',
+ 'video/x-matroska' => ['mkv', 'mk3d', 'mks'],
+ 'video/x-mng' => 'mng',
+ 'video/x-ms-asf' => ['asf', 'asx'],
+ 'video/x-ms-vob' => 'vob',
+ 'video/x-ms-wm' => 'wm',
+ 'video/x-ms-wmv' => 'wmv',
+ 'video/x-ms-wmx' => 'wmx',
+ 'video/x-ms-wvx' => 'wvx',
+ 'video/x-msvideo' => 'avi',
+ 'video/x-sgi-movie' => 'movie',
+ ];
+
+ /**
+ * Get a random MIME type
+ *
+ * @return string
+ *
+ * @example 'video/avi'
+ */
+ public static function mimeType()
+ {
+ return static::randomElement(array_keys(static::$mimeTypes));
+ }
+
+ /**
+ * Get a random file extension (without a dot)
+ *
+ * @example avi
+ *
+ * @return string
+ */
+ public static function fileExtension()
+ {
+ $random_extension = static::randomElement(array_values(static::$mimeTypes));
+
+ return is_array($random_extension) ? static::randomElement($random_extension) : $random_extension;
+ }
+
+ /**
+ * Copy a random file from the source directory to the target directory and returns the filename/fullpath
+ *
+ * @param string $sourceDirectory The directory to look for random file taking
+ * @param string $targetDirectory
+ * @param bool $fullPath Whether to have the full path or just the filename
+ *
+ * @return string
+ */
+ public static function file($sourceDirectory = '/tmp', $targetDirectory = '/tmp', $fullPath = true)
+ {
+ if (!is_dir($sourceDirectory)) {
+ throw new \InvalidArgumentException(sprintf('Source directory %s does not exist or is not a directory.', $sourceDirectory));
+ }
+
+ if (!is_dir($targetDirectory)) {
+ throw new \InvalidArgumentException(sprintf('Target directory %s does not exist or is not a directory.', $targetDirectory));
+ }
+
+ if ($sourceDirectory == $targetDirectory) {
+ throw new \InvalidArgumentException('Source and target directories must differ.');
+ }
+
+ // Drop . and .. and reset array keys
+ $files = array_filter(array_values(array_diff(scandir($sourceDirectory), ['.', '..'])), static function ($file) use ($sourceDirectory) {
+ return is_file($sourceDirectory . DIRECTORY_SEPARATOR . $file) && is_readable($sourceDirectory . DIRECTORY_SEPARATOR . $file);
+ });
+
+ if (empty($files)) {
+ throw new \InvalidArgumentException(sprintf('Source directory %s is empty.', $sourceDirectory));
+ }
+
+ $sourceFullPath = $sourceDirectory . DIRECTORY_SEPARATOR . static::randomElement($files);
+
+ $destinationFile = Uuid::uuid() . '.' . pathinfo($sourceFullPath, PATHINFO_EXTENSION);
+ $destinationFullPath = $targetDirectory . DIRECTORY_SEPARATOR . $destinationFile;
+
+ if (false === copy($sourceFullPath, $destinationFullPath)) {
+ return false;
+ }
+
+ return $fullPath ? $destinationFullPath : $destinationFile;
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/HtmlLorem.php b/vendor/fakerphp/faker/src/Faker/Provider/HtmlLorem.php
new file mode 100755
index 00000000..a8434108
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/HtmlLorem.php
@@ -0,0 +1,307 @@
+addProvider(new Lorem($generator));
+ $generator->addProvider(new Internet($generator));
+ }
+
+ /**
+ * @param int $maxDepth
+ * @param int $maxWidth
+ *
+ * @return string
+ */
+ public function randomHtml($maxDepth = 4, $maxWidth = 4)
+ {
+ if (!class_exists(\DOMDocument::class, false)) {
+ throw new \RuntimeException('ext-dom is required to use randomHtml.');
+ }
+
+ $document = new \DOMDocument();
+ $this->idGenerator = new UniqueGenerator($this->generator);
+
+ $head = $document->createElement('head');
+ $this->addRandomTitle($head);
+
+ $body = $document->createElement('body');
+ $this->addLoginForm($body);
+ $this->addRandomSubTree($body, $maxDepth, $maxWidth);
+
+ $html = $document->createElement('html');
+ $html->appendChild($head);
+ $html->appendChild($body);
+
+ $document->appendChild($html);
+
+ return $document->saveHTML();
+ }
+
+ private function addRandomSubTree(\DOMElement $root, $maxDepth, $maxWidth)
+ {
+ --$maxDepth;
+
+ if ($maxDepth <= 0) {
+ return $root;
+ }
+
+ $siblings = self::numberBetween(1, $maxWidth);
+
+ for ($i = 0; $i < $siblings; ++$i) {
+ if ($maxDepth == 1) {
+ $this->addRandomLeaf($root);
+ } else {
+ $sibling = $root->ownerDocument->createElement('div');
+ $root->appendChild($sibling);
+ $this->addRandomAttribute($sibling);
+ $this->addRandomSubTree($sibling, self::numberBetween(0, $maxDepth), $maxWidth);
+ }
+ }
+
+ return $root;
+ }
+
+ private function addRandomLeaf(\DOMElement $node): void
+ {
+ $rand = self::numberBetween(1, 10);
+
+ switch ($rand) {
+ case 1:
+ $this->addRandomP($node);
+
+ break;
+
+ case 2:
+ $this->addRandomA($node);
+
+ break;
+
+ case 3:
+ $this->addRandomSpan($node);
+
+ break;
+
+ case 4:
+ $this->addRandomUL($node);
+
+ break;
+
+ case 5:
+ $this->addRandomH($node);
+
+ break;
+
+ case 6:
+ $this->addRandomB($node);
+
+ break;
+
+ case 7:
+ $this->addRandomI($node);
+
+ break;
+
+ case 8:
+ $this->addRandomTable($node);
+
+ break;
+
+ default:
+ $this->addRandomText($node);
+
+ break;
+ }
+ }
+
+ private function addRandomAttribute(\DOMElement $node): void
+ {
+ $rand = self::numberBetween(1, 2);
+
+ switch ($rand) {
+ case 1:
+ $node->setAttribute('class', $this->generator->word());
+
+ break;
+
+ case 2:
+ $node->setAttribute('id', (string) $this->idGenerator->randomNumber(5));
+
+ break;
+ }
+ }
+
+ private function addRandomP(\DOMElement $element, $maxLength = 10): void
+ {
+ $node = $element->ownerDocument->createElement(static::P_TAG);
+ $node->textContent = $this->generator->sentence(self::numberBetween(1, $maxLength));
+ $element->appendChild($node);
+ }
+
+ private function addRandomText(\DOMElement $element, $maxLength = 10): void
+ {
+ $text = $element->ownerDocument->createTextNode($this->generator->sentence(self::numberBetween(1, $maxLength)));
+ $element->appendChild($text);
+ }
+
+ private function addRandomA(\DOMElement $element, $maxLength = 10): void
+ {
+ $text = $element->ownerDocument->createTextNode($this->generator->sentence(self::numberBetween(1, $maxLength)));
+ $node = $element->ownerDocument->createElement(static::A_TAG);
+ $node->setAttribute('href', $this->generator->safeEmailDomain());
+ $node->appendChild($text);
+ $element->appendChild($node);
+ }
+
+ private function addRandomTitle(\DOMElement $element, $maxLength = 10): void
+ {
+ $text = $element->ownerDocument->createTextNode($this->generator->sentence(self::numberBetween(1, $maxLength)));
+ $node = $element->ownerDocument->createElement(static::TITLE_TAG);
+ $node->appendChild($text);
+ $element->appendChild($node);
+ }
+
+ private function addRandomH(\DOMElement $element, $maxLength = 10): void
+ {
+ $h = static::H_TAG . (string) self::numberBetween(1, 3);
+ $text = $element->ownerDocument->createTextNode($this->generator->sentence(self::numberBetween(1, $maxLength)));
+ $node = $element->ownerDocument->createElement($h);
+ $node->appendChild($text);
+ $element->appendChild($node);
+ }
+
+ private function addRandomB(\DOMElement $element, $maxLength = 10): void
+ {
+ $text = $element->ownerDocument->createTextNode($this->generator->sentence(self::numberBetween(1, $maxLength)));
+ $node = $element->ownerDocument->createElement(static::B_TAG);
+ $node->appendChild($text);
+ $element->appendChild($node);
+ }
+
+ private function addRandomI(\DOMElement $element, $maxLength = 10): void
+ {
+ $text = $element->ownerDocument->createTextNode($this->generator->sentence(self::numberBetween(1, $maxLength)));
+ $node = $element->ownerDocument->createElement(static::I_TAG);
+ $node->appendChild($text);
+ $element->appendChild($node);
+ }
+
+ private function addRandomSpan(\DOMElement $element, $maxLength = 10): void
+ {
+ $text = $element->ownerDocument->createTextNode($this->generator->sentence(self::numberBetween(1, $maxLength)));
+ $node = $element->ownerDocument->createElement(static::SPAN_TAG);
+ $node->appendChild($text);
+ $element->appendChild($node);
+ }
+
+ private function addLoginForm(\DOMElement $element): void
+ {
+ $textInput = $element->ownerDocument->createElement(static::INPUT_TAG);
+ $textInput->setAttribute('type', 'text');
+ $textInput->setAttribute('id', 'username');
+
+ $textLabel = $element->ownerDocument->createElement(static::LABEL_TAG);
+ $textLabel->setAttribute('for', 'username');
+ $textLabel->textContent = $this->generator->word();
+
+ $passwordInput = $element->ownerDocument->createElement(static::INPUT_TAG);
+ $passwordInput->setAttribute('type', 'password');
+ $passwordInput->setAttribute('id', 'password');
+
+ $passwordLabel = $element->ownerDocument->createElement(static::LABEL_TAG);
+ $passwordLabel->setAttribute('for', 'password');
+ $passwordLabel->textContent = $this->generator->word();
+
+ $submit = $element->ownerDocument->createElement(static::INPUT_TAG);
+ $submit->setAttribute('type', 'submit');
+ $submit->setAttribute('value', $this->generator->word());
+
+ $submit = $element->ownerDocument->createElement(static::FORM_TAG);
+ $submit->setAttribute('action', $this->generator->safeEmailDomain());
+ $submit->setAttribute('method', 'POST');
+ $submit->appendChild($textLabel);
+ $submit->appendChild($textInput);
+ $submit->appendChild($passwordLabel);
+ $submit->appendChild($passwordInput);
+ $element->appendChild($submit);
+ }
+
+ private function addRandomTable(\DOMElement $element, $maxRows = 10, $maxCols = 6, $maxTitle = 4, $maxLength = 10): void
+ {
+ $rows = self::numberBetween(1, $maxRows);
+ $cols = self::numberBetween(1, $maxCols);
+
+ $table = $element->ownerDocument->createElement(static::TABLE_TAG);
+ $thead = $element->ownerDocument->createElement(static::THEAD_TAG);
+ $tbody = $element->ownerDocument->createElement(static::TBODY_TAG);
+
+ $table->appendChild($thead);
+ $table->appendChild($tbody);
+
+ $tr = $element->ownerDocument->createElement(static::TR_TAG);
+ $thead->appendChild($tr);
+
+ for ($i = 0; $i < $cols; ++$i) {
+ $th = $element->ownerDocument->createElement(static::TH_TAG);
+ $th->textContent = $this->generator->sentence(self::numberBetween(1, $maxTitle));
+ $tr->appendChild($th);
+ }
+
+ for ($i = 0; $i < $rows; ++$i) {
+ $tr = $element->ownerDocument->createElement(static::TR_TAG);
+ $tbody->appendChild($tr);
+
+ for ($j = 0; $j < $cols; ++$j) {
+ $th = $element->ownerDocument->createElement(static::TD_TAG);
+ $th->textContent = $this->generator->sentence(self::numberBetween(1, $maxLength));
+ $tr->appendChild($th);
+ }
+ }
+ $element->appendChild($table);
+ }
+
+ private function addRandomUL(\DOMElement $element, $maxItems = 11, $maxLength = 4): void
+ {
+ $num = self::numberBetween(1, $maxItems);
+ $ul = $element->ownerDocument->createElement(static::UL_TAG);
+
+ for ($i = 0; $i < $num; ++$i) {
+ $li = $element->ownerDocument->createElement(static::LI_TAG);
+ $li->textContent = $this->generator->sentence(self::numberBetween(1, $maxLength));
+ $ul->appendChild($li);
+ }
+ $element->appendChild($ul);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/Image.php b/vendor/fakerphp/faker/src/Faker/Provider/Image.php
new file mode 100755
index 00000000..53f28dfc
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/Image.php
@@ -0,0 +1,195 @@
+ 0 ? '?text=' . urlencode(implode(' ', $imageParts)) : '',
+ );
+ }
+
+ /**
+ * Download a remote random image to disk and return its location
+ *
+ * Requires curl, or allow_url_fopen to be on in php.ini.
+ *
+ * @example '/path/to/dir/13b73edae8443990be1aa8f1a483bc27.png'
+ *
+ * @return bool|string
+ */
+ public static function image(
+ $dir = null,
+ $width = 640,
+ $height = 480,
+ $category = null,
+ $fullPath = true,
+ $randomize = true,
+ $word = null,
+ $gray = false,
+ $format = 'png'
+ ) {
+ trigger_deprecation(
+ 'fakerphp/faker',
+ '1.20',
+ 'Provider is deprecated and will no longer be available in Faker 2. Please use a custom provider instead',
+ );
+
+ $dir = null === $dir ? sys_get_temp_dir() : $dir; // GNU/Linux / OS X / Windows compatible
+ // Validate directory path
+ if (!is_dir($dir) || !is_writable($dir)) {
+ throw new \InvalidArgumentException(sprintf('Cannot write to directory "%s"', $dir));
+ }
+
+ // Generate a random filename. Use the server address so that a file
+ // generated at the same time on a different server won't have a collision.
+ $name = md5(uniqid(empty($_SERVER['SERVER_ADDR']) ? '' : $_SERVER['SERVER_ADDR'], true));
+ $filename = sprintf('%s.%s', $name, $format);
+ $filepath = $dir . DIRECTORY_SEPARATOR . $filename;
+
+ $url = static::imageUrl($width, $height, $category, $randomize, $word, $gray, $format);
+
+ // save file
+ if (function_exists('curl_exec')) {
+ // use cURL
+ $fp = fopen($filepath, 'w');
+ $ch = curl_init($url);
+ curl_setopt($ch, CURLOPT_FILE, $fp);
+ $success = curl_exec($ch) && curl_getinfo($ch, CURLINFO_HTTP_CODE) === 200;
+ fclose($fp);
+ curl_close($ch);
+
+ if (!$success) {
+ unlink($filepath);
+
+ // could not contact the distant URL or HTTP error - fail silently.
+ return false;
+ }
+ } elseif (ini_get('allow_url_fopen')) {
+ // use remote fopen() via copy()
+ $success = copy($url, $filepath);
+
+ if (!$success) {
+ // could not contact the distant URL or HTTP error - fail silently.
+ return false;
+ }
+ } else {
+ return new \RuntimeException('The image formatter downloads an image from a remote HTTP server. Therefore, it requires that PHP can request remote hosts, either via cURL or fopen()');
+ }
+
+ return $fullPath ? $filepath : $filename;
+ }
+
+ public static function getFormats(): array
+ {
+ trigger_deprecation(
+ 'fakerphp/faker',
+ '1.20',
+ 'Provider is deprecated and will no longer be available in Faker 2. Please use a custom provider instead',
+ );
+
+ return array_keys(static::getFormatConstants());
+ }
+
+ public static function getFormatConstants(): array
+ {
+ trigger_deprecation(
+ 'fakerphp/faker',
+ '1.20',
+ 'Provider is deprecated and will no longer be available in Faker 2. Please use a custom provider instead',
+ );
+
+ return [
+ static::FORMAT_JPG => constant('IMAGETYPE_JPEG'),
+ static::FORMAT_JPEG => constant('IMAGETYPE_JPEG'),
+ static::FORMAT_PNG => constant('IMAGETYPE_PNG'),
+ ];
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/Internet.php b/vendor/fakerphp/faker/src/Faker/Provider/Internet.php
new file mode 100755
index 00000000..122d9c0c
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/Internet.php
@@ -0,0 +1,407 @@
+generator->parse($format);
+ }
+
+ /**
+ * @example 'jdoe@example.com'
+ *
+ * @return string
+ */
+ final public function safeEmail()
+ {
+ return preg_replace('/\s/u', '', $this->userName() . '@' . static::safeEmailDomain());
+ }
+
+ /**
+ * @example 'jdoe@gmail.com'
+ *
+ * @return string
+ */
+ public function freeEmail()
+ {
+ return preg_replace('/\s/u', '', $this->userName() . '@' . static::freeEmailDomain());
+ }
+
+ /**
+ * @example 'jdoe@dawson.com'
+ *
+ * @return string
+ */
+ public function companyEmail()
+ {
+ return preg_replace('/\s/u', '', $this->userName() . '@' . $this->domainName());
+ }
+
+ /**
+ * @example 'gmail.com'
+ *
+ * @return string
+ */
+ public static function freeEmailDomain()
+ {
+ return static::randomElement(static::$freeEmailDomain);
+ }
+
+ /**
+ * @example 'example.org'
+ *
+ * @return string
+ */
+ final public static function safeEmailDomain()
+ {
+ $domains = [
+ 'example.com',
+ 'example.org',
+ 'example.net',
+ ];
+
+ return static::randomElement($domains);
+ }
+
+ /**
+ * @example 'jdoe'
+ *
+ * @return string
+ */
+ public function userName()
+ {
+ $format = static::randomElement(static::$userNameFormats);
+ $username = static::bothify($this->generator->parse($format));
+
+ $username = strtolower(static::transliterate($username));
+
+ // check if transliterate() didn't support the language and removed all letters
+ if (trim($username, '._') === '') {
+ throw new \Exception('userName failed with the selected locale. Try a different locale or activate the "intl" PHP extension.');
+ }
+
+ // clean possible trailing dots from first/last names
+ $username = str_replace('..', '.', $username);
+ $username = rtrim($username, '.');
+
+ return $username;
+ }
+
+ /**
+ * @example 'fY4èHdZv68'
+ *
+ * @return string
+ */
+ public function password($minLength = 6, $maxLength = 20)
+ {
+ $pattern = str_repeat('*', $this->numberBetween($minLength, $maxLength));
+
+ return $this->asciify($pattern);
+ }
+
+ /**
+ * @example 'tiramisu.com'
+ *
+ * @return string
+ */
+ public function domainName()
+ {
+ return $this->domainWord() . '.' . $this->tld();
+ }
+
+ /**
+ * @example 'faber'
+ *
+ * @return string
+ */
+ public function domainWord()
+ {
+ $lastName = $this->generator->format('lastName');
+
+ $lastName = strtolower(static::transliterate($lastName));
+
+ // check if transliterate() didn't support the language and removed all letters
+ if (trim($lastName, '._') === '') {
+ throw new \Exception('domainWord failed with the selected locale. Try a different locale or activate the "intl" PHP extension.');
+ }
+
+ // clean possible trailing dot from last name
+ $lastName = rtrim($lastName, '.');
+
+ return $lastName;
+ }
+
+ /**
+ * @example 'com'
+ *
+ * @return string
+ */
+ public function tld()
+ {
+ return static::randomElement(static::$tld);
+ }
+
+ /**
+ * @example 'http://www.runolfsdottir.com/'
+ *
+ * @return string
+ */
+ public function url()
+ {
+ $format = static::randomElement(static::$urlFormats);
+
+ return $this->generator->parse($format);
+ }
+
+ /**
+ * @example 'aut-repellat-commodi-vel-itaque-nihil-id-saepe-nostrum'
+ *
+ * @return string
+ */
+ public function slug($nbWords = 6, $variableNbWords = true)
+ {
+ if ($nbWords <= 0) {
+ return '';
+ }
+
+ if ($variableNbWords) {
+ $nbWords = (int) ($nbWords * self::numberBetween(60, 140) / 100) + 1;
+ }
+ $words = $this->generator->words($nbWords);
+
+ return implode('-', $words);
+ }
+
+ /**
+ * @example '237.149.115.38'
+ *
+ * @return string
+ */
+ public function ipv4()
+ {
+ return long2ip(Miscellaneous::boolean() ? self::numberBetween(-2147483648, -2) : self::numberBetween(16777216, 2147483647));
+ }
+
+ /**
+ * @example '35cd:186d:3e23:2986:ef9f:5b41:42a4:e6f1'
+ *
+ * @return string
+ */
+ public function ipv6()
+ {
+ $res = [];
+
+ for ($i = 0; $i < 8; ++$i) {
+ $res[] = dechex(self::numberBetween(0, 65535));
+ }
+
+ return implode(':', $res);
+ }
+
+ /**
+ * @example '10.1.1.17'
+ *
+ * @return string
+ */
+ public static function localIpv4()
+ {
+ $ipBlock = self::randomElement(static::$localIpBlocks);
+
+ return long2ip(static::numberBetween(ip2long($ipBlock[0]), ip2long($ipBlock[1])));
+ }
+
+ /**
+ * @example '32:F1:39:2F:D6:18'
+ *
+ * @return string
+ */
+ public static function macAddress()
+ {
+ $mac = [];
+
+ for ($i = 0; $i < 6; ++$i) {
+ $mac[] = sprintf('%02X', self::numberBetween(0, 0xff));
+ }
+
+ return implode(':', $mac);
+ }
+
+ protected static function transliterate($string)
+ {
+ if (0 === preg_match('/[^A-Za-z0-9_.]/', $string)) {
+ return $string;
+ }
+
+ $transId = 'Any-Latin; Latin-ASCII; NFD; [:Nonspacing Mark:] Remove; NFC;';
+
+ if (class_exists(\Transliterator::class, false) && $transliterator = \Transliterator::create($transId)) {
+ $transString = $transliterator->transliterate($string);
+ } else {
+ $transString = static::toAscii($string);
+ }
+
+ return preg_replace('/[^A-Za-z0-9_.]/u', '', $transString);
+ }
+
+ protected static function toAscii($string)
+ {
+ static $arrayFrom, $arrayTo;
+
+ if (empty($arrayFrom)) {
+ $transliterationTable = [
+ 'IJ' => 'I', 'Ö' => 'O', 'Œ' => 'O', 'Ü' => 'U', 'ä' => 'a', 'æ' => 'a',
+ 'ij' => 'i', 'ö' => 'o', 'œ' => 'o', 'ü' => 'u', 'ß' => 's', 'ſ' => 's',
+ 'À' => 'A', 'Á' => 'A', 'Â' => 'A', 'Ã' => 'A', 'Ä' => 'A', 'Å' => 'A',
+ 'Æ' => 'A', 'Ā' => 'A', 'Ą' => 'A', 'Ă' => 'A', 'Ç' => 'C', 'Ć' => 'C',
+ 'Č' => 'C', 'Ĉ' => 'C', 'Ċ' => 'C', 'Ď' => 'D', 'Đ' => 'D', 'È' => 'E',
+ 'É' => 'E', 'Ê' => 'E', 'Ë' => 'E', 'Ē' => 'E', 'Ę' => 'E', 'Ě' => 'E',
+ 'Ĕ' => 'E', 'Ė' => 'E', 'Ĝ' => 'G', 'Ğ' => 'G', 'Ġ' => 'G', 'Ģ' => 'G',
+ 'Ĥ' => 'H', 'Ħ' => 'H', 'Ì' => 'I', 'Í' => 'I', 'Î' => 'I', 'Ï' => 'I',
+ 'Ī' => 'I', 'Ĩ' => 'I', 'Ĭ' => 'I', 'Į' => 'I', 'İ' => 'I', 'Ĵ' => 'J',
+ 'Ķ' => 'K', 'Ľ' => 'K', 'Ĺ' => 'K', 'Ļ' => 'K', 'Ŀ' => 'K', 'Ł' => 'L',
+ 'Ñ' => 'N', 'Ń' => 'N', 'Ň' => 'N', 'Ņ' => 'N', 'Ŋ' => 'N', 'Ò' => 'O',
+ 'Ó' => 'O', 'Ô' => 'O', 'Õ' => 'O', 'Ø' => 'O', 'Ō' => 'O', 'Ő' => 'O',
+ 'Ŏ' => 'O', 'Ŕ' => 'R', 'Ř' => 'R', 'Ŗ' => 'R', 'Ś' => 'S', 'Ş' => 'S',
+ 'Ŝ' => 'S', 'Ș' => 'S', 'Š' => 'S', 'Ť' => 'T', 'Ţ' => 'T', 'Ŧ' => 'T',
+ 'Ț' => 'T', 'Ù' => 'U', 'Ú' => 'U', 'Û' => 'U', 'Ū' => 'U', 'Ů' => 'U',
+ 'Ű' => 'U', 'Ŭ' => 'U', 'Ũ' => 'U', 'Ų' => 'U', 'Ŵ' => 'W', 'Ŷ' => 'Y',
+ 'Ÿ' => 'Y', 'Ý' => 'Y', 'Ź' => 'Z', 'Ż' => 'Z', 'Ž' => 'Z', 'à' => 'a',
+ 'á' => 'a', 'â' => 'a', 'ã' => 'a', 'ā' => 'a', 'ą' => 'a', 'ă' => 'a',
+ 'å' => 'a', 'ç' => 'c', 'ć' => 'c', 'č' => 'c', 'ĉ' => 'c', 'ċ' => 'c',
+ 'ď' => 'd', 'đ' => 'd', 'è' => 'e', 'é' => 'e', 'ê' => 'e', 'ë' => 'e',
+ 'ē' => 'e', 'ę' => 'e', 'ě' => 'e', 'ĕ' => 'e', 'ė' => 'e', 'ƒ' => 'f',
+ 'ĝ' => 'g', 'ğ' => 'g', 'ġ' => 'g', 'ģ' => 'g', 'ĥ' => 'h', 'ħ' => 'h',
+ 'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i', 'ī' => 'i', 'ĩ' => 'i',
+ 'ĭ' => 'i', 'į' => 'i', 'ı' => 'i', 'ĵ' => 'j', 'ķ' => 'k', 'ĸ' => 'k',
+ 'ł' => 'l', 'ľ' => 'l', 'ĺ' => 'l', 'ļ' => 'l', 'ŀ' => 'l', 'ñ' => 'n',
+ 'ń' => 'n', 'ň' => 'n', 'ņ' => 'n', 'ʼn' => 'n', 'ŋ' => 'n', 'ò' => 'o',
+ 'ó' => 'o', 'ô' => 'o', 'õ' => 'o', 'ø' => 'o', 'ō' => 'o', 'ő' => 'o',
+ 'ŏ' => 'o', 'ŕ' => 'r', 'ř' => 'r', 'ŗ' => 'r', 'ś' => 's', 'š' => 's',
+ 'ť' => 't', 'ù' => 'u', 'ú' => 'u', 'û' => 'u', 'ū' => 'u', 'ů' => 'u',
+ 'ű' => 'u', 'ŭ' => 'u', 'ũ' => 'u', 'ų' => 'u', 'ŵ' => 'w', 'ÿ' => 'y',
+ 'ý' => 'y', 'ŷ' => 'y', 'ż' => 'z', 'ź' => 'z', 'ž' => 'z', 'Α' => 'A',
+ 'Ά' => 'A', 'Ἀ' => 'A', 'Ἁ' => 'A', 'Ἂ' => 'A', 'Ἃ' => 'A', 'Ἄ' => 'A',
+ 'Ἅ' => 'A', 'Ἆ' => 'A', 'Ἇ' => 'A', 'ᾈ' => 'A', 'ᾉ' => 'A', 'ᾊ' => 'A',
+ 'ᾋ' => 'A', 'ᾌ' => 'A', 'ᾍ' => 'A', 'ᾎ' => 'A', 'ᾏ' => 'A', 'Ᾰ' => 'A',
+ 'Ᾱ' => 'A', 'Ὰ' => 'A', 'ᾼ' => 'A', 'Β' => 'B', 'Γ' => 'G', 'Δ' => 'D',
+ 'Ε' => 'E', 'Έ' => 'E', 'Ἐ' => 'E', 'Ἑ' => 'E', 'Ἒ' => 'E', 'Ἓ' => 'E',
+ 'Ἔ' => 'E', 'Ἕ' => 'E', 'Ὲ' => 'E', 'Ζ' => 'Z', 'Η' => 'I', 'Ή' => 'I',
+ 'Ἠ' => 'I', 'Ἡ' => 'I', 'Ἢ' => 'I', 'Ἣ' => 'I', 'Ἤ' => 'I', 'Ἥ' => 'I',
+ 'Ἦ' => 'I', 'Ἧ' => 'I', 'ᾘ' => 'I', 'ᾙ' => 'I', 'ᾚ' => 'I', 'ᾛ' => 'I',
+ 'ᾜ' => 'I', 'ᾝ' => 'I', 'ᾞ' => 'I', 'ᾟ' => 'I', 'Ὴ' => 'I', 'ῌ' => 'I',
+ 'Θ' => 'T', 'Ι' => 'I', 'Ί' => 'I', 'Ϊ' => 'I', 'Ἰ' => 'I', 'Ἱ' => 'I',
+ 'Ἲ' => 'I', 'Ἳ' => 'I', 'Ἴ' => 'I', 'Ἵ' => 'I', 'Ἶ' => 'I', 'Ἷ' => 'I',
+ 'Ῐ' => 'I', 'Ῑ' => 'I', 'Ὶ' => 'I', 'Κ' => 'K', 'Λ' => 'L', 'Μ' => 'M',
+ 'Ν' => 'N', 'Ξ' => 'K', 'Ο' => 'O', 'Ό' => 'O', 'Ὀ' => 'O', 'Ὁ' => 'O',
+ 'Ὂ' => 'O', 'Ὃ' => 'O', 'Ὄ' => 'O', 'Ὅ' => 'O', 'Ὸ' => 'O', 'Π' => 'P',
+ 'Ρ' => 'R', 'Ῥ' => 'R', 'Σ' => 'S', 'Τ' => 'T', 'Υ' => 'Y', 'Ύ' => 'Y',
+ 'Ϋ' => 'Y', 'Ὑ' => 'Y', 'Ὓ' => 'Y', 'Ὕ' => 'Y', 'Ὗ' => 'Y', 'Ῠ' => 'Y',
+ 'Ῡ' => 'Y', 'Ὺ' => 'Y', 'Φ' => 'F', 'Χ' => 'X', 'Ψ' => 'P', 'Ω' => 'O',
+ 'Ώ' => 'O', 'Ὠ' => 'O', 'Ὡ' => 'O', 'Ὢ' => 'O', 'Ὣ' => 'O', 'Ὤ' => 'O',
+ 'Ὥ' => 'O', 'Ὦ' => 'O', 'Ὧ' => 'O', 'ᾨ' => 'O', 'ᾩ' => 'O', 'ᾪ' => 'O',
+ 'ᾫ' => 'O', 'ᾬ' => 'O', 'ᾭ' => 'O', 'ᾮ' => 'O', 'ᾯ' => 'O', 'Ὼ' => 'O',
+ 'ῼ' => 'O', 'α' => 'a', 'ά' => 'a', 'ἀ' => 'a', 'ἁ' => 'a', 'ἂ' => 'a',
+ 'ἃ' => 'a', 'ἄ' => 'a', 'ἅ' => 'a', 'ἆ' => 'a', 'ἇ' => 'a', 'ᾀ' => 'a',
+ 'ᾁ' => 'a', 'ᾂ' => 'a', 'ᾃ' => 'a', 'ᾄ' => 'a', 'ᾅ' => 'a', 'ᾆ' => 'a',
+ 'ᾇ' => 'a', 'ὰ' => 'a', 'ᾰ' => 'a', 'ᾱ' => 'a', 'ᾲ' => 'a', 'ᾳ' => 'a',
+ 'ᾴ' => 'a', 'ᾶ' => 'a', 'ᾷ' => 'a', 'β' => 'b', 'γ' => 'g', 'δ' => 'd',
+ 'ε' => 'e', 'έ' => 'e', 'ἐ' => 'e', 'ἑ' => 'e', 'ἒ' => 'e', 'ἓ' => 'e',
+ 'ἔ' => 'e', 'ἕ' => 'e', 'ὲ' => 'e', 'ζ' => 'z', 'η' => 'i', 'ή' => 'i',
+ 'ἠ' => 'i', 'ἡ' => 'i', 'ἢ' => 'i', 'ἣ' => 'i', 'ἤ' => 'i', 'ἥ' => 'i',
+ 'ἦ' => 'i', 'ἧ' => 'i', 'ᾐ' => 'i', 'ᾑ' => 'i', 'ᾒ' => 'i', 'ᾓ' => 'i',
+ 'ᾔ' => 'i', 'ᾕ' => 'i', 'ᾖ' => 'i', 'ᾗ' => 'i', 'ὴ' => 'i', 'ῂ' => 'i',
+ 'ῃ' => 'i', 'ῄ' => 'i', 'ῆ' => 'i', 'ῇ' => 'i', 'θ' => 't', 'ι' => 'i',
+ 'ί' => 'i', 'ϊ' => 'i', 'ΐ' => 'i', 'ἰ' => 'i', 'ἱ' => 'i', 'ἲ' => 'i',
+ 'ἳ' => 'i', 'ἴ' => 'i', 'ἵ' => 'i', 'ἶ' => 'i', 'ἷ' => 'i', 'ὶ' => 'i',
+ 'ῐ' => 'i', 'ῑ' => 'i', 'ῒ' => 'i', 'ῖ' => 'i', 'ῗ' => 'i', 'κ' => 'k',
+ 'λ' => 'l', 'μ' => 'm', 'ν' => 'n', 'ξ' => 'k', 'ο' => 'o', 'ό' => 'o',
+ 'ὀ' => 'o', 'ὁ' => 'o', 'ὂ' => 'o', 'ὃ' => 'o', 'ὄ' => 'o', 'ὅ' => 'o',
+ 'ὸ' => 'o', 'π' => 'p', 'ρ' => 'r', 'ῤ' => 'r', 'ῥ' => 'r', 'σ' => 's',
+ 'ς' => 's', 'τ' => 't', 'υ' => 'y', 'ύ' => 'y', 'ϋ' => 'y', 'ΰ' => 'y',
+ 'ὐ' => 'y', 'ὑ' => 'y', 'ὒ' => 'y', 'ὓ' => 'y', 'ὔ' => 'y', 'ὕ' => 'y',
+ 'ὖ' => 'y', 'ὗ' => 'y', 'ὺ' => 'y', 'ῠ' => 'y', 'ῡ' => 'y', 'ῢ' => 'y',
+ 'ῦ' => 'y', 'ῧ' => 'y', 'φ' => 'f', 'χ' => 'x', 'ψ' => 'p', 'ω' => 'o',
+ 'ώ' => 'o', 'ὠ' => 'o', 'ὡ' => 'o', 'ὢ' => 'o', 'ὣ' => 'o', 'ὤ' => 'o',
+ 'ὥ' => 'o', 'ὦ' => 'o', 'ὧ' => 'o', 'ᾠ' => 'o', 'ᾡ' => 'o', 'ᾢ' => 'o',
+ 'ᾣ' => 'o', 'ᾤ' => 'o', 'ᾥ' => 'o', 'ᾦ' => 'o', 'ᾧ' => 'o', 'ὼ' => 'o',
+ 'ῲ' => 'o', 'ῳ' => 'o', 'ῴ' => 'o', 'ῶ' => 'o', 'ῷ' => 'o', 'А' => 'A',
+ 'Б' => 'B', 'В' => 'V', 'Г' => 'G', 'Д' => 'D', 'Е' => 'E', 'Ё' => 'E',
+ 'Ж' => 'Z', 'З' => 'Z', 'И' => 'I', 'Й' => 'I', 'К' => 'K', 'Л' => 'L',
+ 'М' => 'M', 'Н' => 'N', 'О' => 'O', 'П' => 'P', 'Р' => 'R', 'С' => 'S',
+ 'Т' => 'T', 'У' => 'U', 'Ф' => 'F', 'Х' => 'K', 'Ц' => 'T', 'Ч' => 'C',
+ 'Ш' => 'S', 'Щ' => 'S', 'Ы' => 'Y', 'Э' => 'E', 'Ю' => 'Y', 'Я' => 'Y',
+ 'а' => 'A', 'б' => 'B', 'в' => 'V', 'г' => 'G', 'д' => 'D', 'е' => 'E',
+ 'ё' => 'E', 'ж' => 'Z', 'з' => 'Z', 'и' => 'I', 'й' => 'I', 'к' => 'K',
+ 'л' => 'L', 'м' => 'M', 'н' => 'N', 'о' => 'O', 'п' => 'P', 'р' => 'R',
+ 'с' => 'S', 'т' => 'T', 'у' => 'U', 'ф' => 'F', 'х' => 'K', 'ц' => 'T',
+ 'ч' => 'C', 'ш' => 'S', 'щ' => 'S', 'ы' => 'Y', 'э' => 'E', 'ю' => 'Y',
+ 'я' => 'Y', 'ð' => 'd', 'Ð' => 'D', 'þ' => 't', 'Þ' => 'T', 'ა' => 'a',
+ 'ბ' => 'b', 'გ' => 'g', 'დ' => 'd', 'ე' => 'e', 'ვ' => 'v', 'ზ' => 'z',
+ 'თ' => 't', 'ი' => 'i', 'კ' => 'k', 'ლ' => 'l', 'მ' => 'm', 'ნ' => 'n',
+ 'ო' => 'o', 'პ' => 'p', 'ჟ' => 'z', 'რ' => 'r', 'ს' => 's', 'ტ' => 't',
+ 'უ' => 'u', 'ფ' => 'p', 'ქ' => 'k', 'ღ' => 'g', 'ყ' => 'q', 'შ' => 's',
+ 'ჩ' => 'c', 'ც' => 't', 'ძ' => 'd', 'წ' => 't', 'ჭ' => 'c', 'ხ' => 'k',
+ 'ჯ' => 'j', 'ჰ' => 'h', 'ţ' => 't', 'ʼ' => "'", '̧' => '', 'ḩ' => 'h',
+ '‘' => "'", '’' => "'", 'ừ' => 'u', '/' => '', 'ế' => 'e', 'ả' => 'a',
+ 'ị' => 'i', 'ậ' => 'a', 'ệ' => 'e', 'ỉ' => 'i', 'ồ' => 'o', 'ề' => 'e',
+ 'ơ' => 'o', 'ạ' => 'a', 'ẵ' => 'a', 'ư' => 'u', 'ằ' => 'a', 'ầ' => 'a',
+ 'ḑ' => 'd', 'Ḩ' => 'H', 'Ḑ' => 'D', 'ș' => 's', 'ț' => 't', 'ộ' => 'o',
+ 'ắ' => 'a', 'ş' => 's', "'" => '', 'ու' => 'u', 'ա' => 'a', 'բ' => 'b',
+ 'գ' => 'g', 'դ' => 'd', 'ե' => 'e', 'զ' => 'z', 'է' => 'e', 'ը' => 'y',
+ 'թ' => 't', 'ժ' => 'zh', 'ի' => 'i', 'լ' => 'l', 'խ' => 'kh', 'ծ' => 'ts',
+ 'կ' => 'k', 'հ' => 'h', 'ձ' => 'dz', 'ղ' => 'gh', 'ճ' => 'ch', 'մ' => 'm',
+ 'յ' => 'y', 'ն' => 'n', 'շ' => 'sh', 'ո' => 'o', 'չ' => 'ch', 'պ' => 'p',
+ 'ջ' => 'j', 'ռ' => 'r', 'ս' => 's', 'վ' => 'v', 'տ' => 't', 'ր' => 'r',
+ 'ց' => 'ts', 'փ' => 'p', 'ք' => 'q', 'և' => 'ev', 'օ' => 'o', 'ֆ' => 'f',
+ ];
+ $arrayFrom = array_keys($transliterationTable);
+ $arrayTo = array_values($transliterationTable);
+ }
+
+ return str_replace($arrayFrom, $arrayTo, $string);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/Lorem.php b/vendor/fakerphp/faker/src/Faker/Provider/Lorem.php
new file mode 100755
index 00000000..a55144a5
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/Lorem.php
@@ -0,0 +1,220 @@
+generator->parse('{{bloodType}}{{bloodRh}}');
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/Miscellaneous.php b/vendor/fakerphp/faker/src/Faker/Provider/Miscellaneous.php
new file mode 100755
index 00000000..91d992ec
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/Miscellaneous.php
@@ -0,0 +1,341 @@
+ [
+ '4539###########',
+ '4556###########',
+ '4916###########',
+ '4532###########',
+ '4929###########',
+ '40240071#######',
+ '4485###########',
+ '4716###########',
+ '4##############',
+ ],
+ 'Visa Retired' => [
+ '4539########',
+ '4556########',
+ '4916########',
+ '4532########',
+ '4929########',
+ '40240071####',
+ '4485########',
+ '4716########',
+ '4###########',
+ ],
+ 'MasterCard' => [
+ '2221###########',
+ '23#############',
+ '24#############',
+ '25#############',
+ '26#############',
+ '2720###########',
+ '51#############',
+ '52#############',
+ '53#############',
+ '54#############',
+ '55#############',
+ ],
+ 'American Express' => [
+ '34############',
+ '37############',
+ ],
+ 'Discover Card' => [
+ '6011###########',
+ ],
+ 'JCB' => [
+ '3528###########',
+ '3589###########',
+ ],
+ ];
+
+ /**
+ * @var array list of IBAN formats, source: @see https://www.swift.com/standards/data-standards/iban
+ */
+ protected static $ibanFormats = [
+ 'AD' => [['n', 4], ['n', 4], ['c', 12]],
+ 'AE' => [['n', 3], ['n', 16]],
+ 'AL' => [['n', 8], ['c', 16]],
+ 'AT' => [['n', 5], ['n', 11]],
+ 'AZ' => [['a', 4], ['c', 20]],
+ 'BA' => [['n', 3], ['n', 3], ['n', 8], ['n', 2]],
+ 'BE' => [['n', 3], ['n', 7], ['n', 2]],
+ 'BG' => [['a', 4], ['n', 4], ['n', 2], ['c', 8]],
+ 'BH' => [['a', 4], ['c', 14]],
+ 'BR' => [['n', 8], ['n', 5], ['n', 10], ['a', 1], ['c', 1]],
+ 'CH' => [['n', 5], ['c', 12]],
+ 'CR' => [['n', 4], ['n', 14]],
+ 'CY' => [['n', 3], ['n', 5], ['c', 16]],
+ 'CZ' => [['n', 4], ['n', 6], ['n', 10]],
+ 'DE' => [['n', 8], ['n', 10]],
+ 'DK' => [['n', 4], ['n', 9], ['n', 1]],
+ 'DO' => [['c', 4], ['n', 20]],
+ 'EE' => [['n', 2], ['n', 2], ['n', 11], ['n', 1]],
+ 'EG' => [['n', 4], ['n', 4], ['n', 17]],
+ 'ES' => [['n', 4], ['n', 4], ['n', 1], ['n', 1], ['n', 10]],
+ 'FI' => [['n', 6], ['n', 7], ['n', 1]],
+ 'FR' => [['n', 5], ['n', 5], ['c', 11], ['n', 2]],
+ 'GB' => [['a', 4], ['n', 6], ['n', 8]],
+ 'GE' => [['a', 2], ['n', 16]],
+ 'GI' => [['a', 4], ['c', 15]],
+ 'GR' => [['n', 3], ['n', 4], ['c', 16]],
+ 'GT' => [['c', 4], ['c', 20]],
+ 'HR' => [['n', 7], ['n', 10]],
+ 'HU' => [['n', 3], ['n', 4], ['n', 1], ['n', 15], ['n', 1]],
+ 'IE' => [['a', 4], ['n', 6], ['n', 8]],
+ 'IL' => [['n', 3], ['n', 3], ['n', 13]],
+ 'IS' => [['n', 4], ['n', 2], ['n', 6], ['n', 10]],
+ 'IT' => [['a', 1], ['n', 5], ['n', 5], ['c', 12]],
+ 'KW' => [['a', 4], ['n', 22]],
+ 'KZ' => [['n', 3], ['c', 13]],
+ 'LB' => [['n', 4], ['c', 20]],
+ 'LI' => [['n', 5], ['c', 12]],
+ 'LT' => [['n', 5], ['n', 11]],
+ 'LU' => [['n', 3], ['c', 13]],
+ 'LV' => [['a', 4], ['c', 13]],
+ 'MC' => [['n', 5], ['n', 5], ['c', 11], ['n', 2]],
+ 'MD' => [['c', 2], ['c', 18]],
+ 'ME' => [['n', 3], ['n', 13], ['n', 2]],
+ 'MK' => [['n', 3], ['c', 10], ['n', 2]],
+ 'MR' => [['n', 5], ['n', 5], ['n', 11], ['n', 2]],
+ 'MT' => [['a', 4], ['n', 5], ['c', 18]],
+ 'MU' => [['a', 4], ['n', 2], ['n', 2], ['n', 12], ['n', 3], ['a', 3]],
+ 'NL' => [['a', 4], ['n', 10]],
+ 'NO' => [['n', 4], ['n', 6], ['n', 1]],
+ 'PK' => [['a', 4], ['c', 16]],
+ 'PL' => [['n', 8], ['n', 16]],
+ 'PS' => [['a', 4], ['c', 21]],
+ 'PT' => [['n', 4], ['n', 4], ['n', 11], ['n', 2]],
+ 'RO' => [['a', 4], ['c', 16]],
+ 'RS' => [['n', 3], ['n', 13], ['n', 2]],
+ 'SA' => [['n', 2], ['c', 18]],
+ 'SE' => [['n', 3], ['n', 16], ['n', 1]],
+ 'SI' => [['n', 5], ['n', 8], ['n', 2]],
+ 'SK' => [['n', 4], ['n', 6], ['n', 10]],
+ 'SM' => [['a', 1], ['n', 5], ['n', 5], ['c', 12]],
+ 'TN' => [['n', 2], ['n', 3], ['n', 13], ['n', 2]],
+ 'TR' => [['n', 5], ['n', 1], ['c', 16]],
+ 'VG' => [['a', 4], ['n', 16]],
+ ];
+
+ /**
+ * @return string Returns a credit card vendor name
+ *
+ * @example 'MasterCard'
+ */
+ public static function creditCardType()
+ {
+ return static::randomElement(static::$cardVendors);
+ }
+
+ /**
+ * Returns the String of a credit card number.
+ *
+ * @param string $type Supporting any of 'Visa', 'MasterCard', 'American Express', 'Discover' and 'JCB'
+ * @param bool $formatted Set to true if the output string should contain one separator every 4 digits
+ * @param string $separator Separator string for formatting card number. Defaults to dash (-).
+ *
+ * @return string
+ *
+ * @example '4485480221084675'
+ */
+ public static function creditCardNumber($type = null, $formatted = false, $separator = '-')
+ {
+ if (null === $type) {
+ $type = static::creditCardType();
+ }
+ $mask = static::randomElement(static::$cardParams[$type]);
+
+ $number = static::numerify($mask);
+ $number .= Luhn::computeCheckDigit($number);
+
+ if ($formatted) {
+ $p1 = substr($number, 0, 4);
+ $p2 = substr($number, 4, 4);
+ $p3 = substr($number, 8, 4);
+ $p4 = substr($number, 12);
+ $number = $p1 . $separator . $p2 . $separator . $p3 . $separator . $p4;
+ }
+
+ return $number;
+ }
+
+ /**
+ * @param bool $valid True (by default) to get a valid expiration date, false to get a maybe valid date
+ *
+ * @return \DateTime
+ *
+ * @example 04/13
+ */
+ public function creditCardExpirationDate($valid = true)
+ {
+ if ($valid) {
+ return $this->generator->dateTimeBetween('now', '36 months');
+ }
+
+ return $this->generator->dateTimeBetween('-36 months', '36 months');
+ }
+
+ /**
+ * @param bool $valid True (by default) to get a valid expiration date, false to get a maybe valid date
+ * @param string $expirationDateFormat
+ *
+ * @return string
+ *
+ * @example '04/13'
+ */
+ public function creditCardExpirationDateString($valid = true, $expirationDateFormat = null)
+ {
+ return $this->creditCardExpirationDate($valid)->format(null === $expirationDateFormat ? static::$expirationDateFormat : $expirationDateFormat);
+ }
+
+ /**
+ * @param bool $valid True (by default) to get a valid expiration date, false to get a maybe valid date
+ *
+ * @return array
+ */
+ public function creditCardDetails($valid = true)
+ {
+ $type = static::creditCardType();
+
+ return [
+ 'type' => $type,
+ 'number' => static::creditCardNumber($type),
+ 'name' => $this->generator->name(),
+ 'expirationDate' => $this->creditCardExpirationDateString($valid),
+ ];
+ }
+
+ /**
+ * International Bank Account Number (IBAN)
+ *
+ * @see http://en.wikipedia.org/wiki/International_Bank_Account_Number
+ *
+ * @param string $countryCode ISO 3166-1 alpha-2 country code
+ * @param string $prefix for generating bank account number of a specific bank
+ * @param int $length total length without country code and 2 check digits
+ *
+ * @return string
+ */
+ public static function iban($countryCode = null, $prefix = '', $length = null)
+ {
+ $countryCode = null === $countryCode ? self::randomKey(self::$ibanFormats) : strtoupper($countryCode);
+
+ $format = !isset(static::$ibanFormats[$countryCode]) ? null : static::$ibanFormats[$countryCode];
+
+ if ($length === null) {
+ if ($format === null) {
+ $length = 24;
+ } else {
+ $length = 0;
+
+ foreach ($format as $part) {
+ [$class, $groupCount] = $part;
+ $length += $groupCount;
+ }
+ }
+ }
+
+ if ($format === null) {
+ $format = [['n', $length]];
+ }
+
+ $expandedFormat = '';
+
+ foreach ($format as $item) {
+ [$class, $length] = $item;
+ $expandedFormat .= str_repeat($class, $length);
+ }
+
+ $result = $prefix;
+ $expandedFormat = substr($expandedFormat, strlen($result));
+
+ foreach (str_split($expandedFormat) as $class) {
+ switch ($class) {
+ default:
+ case 'c':
+ $result .= Miscellaneous::boolean() ? static::randomDigit() : strtoupper(static::randomLetter());
+
+ break;
+
+ case 'a':
+ $result .= strtoupper(static::randomLetter());
+
+ break;
+
+ case 'n':
+ $result .= static::randomDigit();
+
+ break;
+ }
+ }
+
+ $checksum = Iban::checksum($countryCode . '00' . $result);
+
+ return $countryCode . $checksum . $result;
+ }
+
+ /**
+ * Return the String of a SWIFT/BIC number
+ *
+ * @example 'RZTIAT22263'
+ *
+ * @see http://en.wikipedia.org/wiki/ISO_9362
+ *
+ * @return string Swift/Bic number
+ */
+ public static function swiftBicNumber()
+ {
+ return self::regexify('^([A-Z]){4}([A-Z]){2}([0-9A-Z]){2}([0-9A-Z]{3})?$');
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/Person.php b/vendor/fakerphp/faker/src/Faker/Provider/Person.php
new file mode 100755
index 00000000..c11a72bd
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/Person.php
@@ -0,0 +1,147 @@
+generator->parse($format);
+ }
+
+ /**
+ * @param string|null $gender 'male', 'female' or null for any
+ *
+ * @return string
+ *
+ * @example 'John'
+ */
+ public function firstName($gender = null)
+ {
+ if ($gender === static::GENDER_MALE) {
+ return static::firstNameMale();
+ }
+
+ if ($gender === static::GENDER_FEMALE) {
+ return static::firstNameFemale();
+ }
+
+ return $this->generator->parse(static::randomElement(static::$firstNameFormat));
+ }
+
+ /**
+ * @return string
+ */
+ public static function firstNameMale()
+ {
+ return static::randomElement(static::$firstNameMale);
+ }
+
+ /**
+ * @return string
+ */
+ public static function firstNameFemale()
+ {
+ return static::randomElement(static::$firstNameFemale);
+ }
+
+ /**
+ * @example 'Doe'
+ *
+ * @return string
+ */
+ public function lastName()
+ {
+ return static::randomElement(static::$lastName);
+ }
+
+ /**
+ * @example 'Mrs.'
+ *
+ * @param string|null $gender 'male', 'female' or null for any
+ *
+ * @return string
+ */
+ public function title($gender = null)
+ {
+ if ($gender === static::GENDER_MALE) {
+ return static::titleMale();
+ }
+
+ if ($gender === static::GENDER_FEMALE) {
+ return static::titleFemale();
+ }
+
+ return $this->generator->parse(static::randomElement(static::$titleFormat));
+ }
+
+ /**
+ * @example 'Mr.'
+ *
+ * @return string
+ */
+ public static function titleMale()
+ {
+ return static::randomElement(static::$titleMale);
+ }
+
+ /**
+ * @example 'Mrs.'
+ *
+ * @return string
+ */
+ public static function titleFemale()
+ {
+ return static::randomElement(static::$titleFemale);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/PhoneNumber.php b/vendor/fakerphp/faker/src/Faker/Provider/PhoneNumber.php
new file mode 100755
index 00000000..515ef57e
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/PhoneNumber.php
@@ -0,0 +1,270 @@
+generator->parse(static::randomElement(static::$formats)));
+ }
+
+ /**
+ * @example +11134567890
+ *
+ * @return string
+ */
+ public function e164PhoneNumber()
+ {
+ return static::numerify($this->generator->parse(static::randomElement(static::$e164Formats)));
+ }
+
+ /**
+ * International Mobile Equipment Identity (IMEI)
+ *
+ * @see http://en.wikipedia.org/wiki/International_Mobile_Station_Equipment_Identity
+ * @see http://imei-number.com/imei-validation-check/
+ *
+ * @example '720084494799532'
+ *
+ * @return int $imei
+ */
+ public function imei()
+ {
+ $imei = (string) static::numerify('##############');
+ $imei .= Luhn::computeCheckDigit($imei);
+
+ return $imei;
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/Text.php b/vendor/fakerphp/faker/src/Faker/Provider/Text.php
new file mode 100755
index 00000000..585d5b5a
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/Text.php
@@ -0,0 +1,202 @@
+realTextBetween((int) round($maxNbChars * 0.8), $maxNbChars, $indexSize);
+ }
+
+ /**
+ * Generate a text string by the Markov chain algorithm.
+ *
+ * Depending on the $maxNbChars, returns a random valid looking text. The algorithm
+ * generates a weighted table with the specified number of words as the index and the
+ * possible following words as the value.
+ *
+ * @example 'Alice, swallowing down her flamingo, and began by taking the little golden key'
+ *
+ * @param int $minNbChars Minimum number of characters the text should contain (maximum: 8)
+ * @param int $maxNbChars Maximum number of characters the text should contain (minimum: 10)
+ * @param int $indexSize Determines how many words are considered for the generation of the next word.
+ * The minimum is 1, and it produces a higher level of randomness, although the
+ * generated text usually doesn't make sense. Higher index sizes (up to 5)
+ * produce more correct text, at the price of less randomness.
+ *
+ * @return string
+ */
+ public function realTextBetween($minNbChars = 160, $maxNbChars = 200, $indexSize = 2)
+ {
+ if ($minNbChars < 1) {
+ throw new \InvalidArgumentException('minNbChars must be at least 1');
+ }
+
+ if ($maxNbChars < 10) {
+ throw new \InvalidArgumentException('maxNbChars must be at least 10');
+ }
+
+ if ($indexSize < 1) {
+ throw new \InvalidArgumentException('indexSize must be at least 1');
+ }
+
+ if ($indexSize > 5) {
+ throw new \InvalidArgumentException('indexSize must be at most 5');
+ }
+
+ if ($minNbChars >= $maxNbChars) {
+ throw new \InvalidArgumentException('minNbChars must be smaller than maxNbChars');
+ }
+
+ $words = $this->getConsecutiveWords($indexSize);
+ $iterations = 0;
+
+ do {
+ ++$iterations;
+
+ if ($iterations >= 100) {
+ throw new \OverflowException(sprintf('Maximum retries of %d reached without finding a valid real text', $iterations));
+ }
+
+ $result = $this->generateText($maxNbChars, $words);
+ } while (static::strlen($result) <= $minNbChars);
+
+ return $result;
+ }
+
+ /**
+ * @param int $maxNbChars
+ * @param array $words
+ *
+ * @return string
+ */
+ protected function generateText($maxNbChars, $words)
+ {
+ $result = [];
+ $resultLength = 0;
+ // take a random starting point
+ $next = static::randomKey($words);
+
+ while ($resultLength < $maxNbChars && isset($words[$next])) {
+ // fetch a random word to append
+ $word = static::randomElement($words[$next]);
+
+ // calculate next index
+ $currentWords = static::explode($next);
+ $currentWords[] = $word;
+ array_shift($currentWords);
+ $next = static::implode($currentWords);
+
+ // ensure text starts with an uppercase letter
+ if ($resultLength == 0 && !static::validStart($word)) {
+ continue;
+ }
+
+ // append the element
+ $result[] = $word;
+ $resultLength += static::strlen($word) + static::$separatorLen;
+ }
+
+ // remove the element that caused the text to overflow
+ array_pop($result);
+
+ // build result
+ $result = static::implode($result);
+
+ return static::appendEnd($result);
+ }
+
+ protected function getConsecutiveWords($indexSize)
+ {
+ if (!isset($this->consecutiveWords[$indexSize])) {
+ $parts = $this->getExplodedText();
+ $words = [];
+ $index = [];
+
+ for ($i = 0; $i < $indexSize; ++$i) {
+ $index[] = array_shift($parts);
+ }
+
+ for ($i = 0, $count = count($parts); $i < $count; ++$i) {
+ $stringIndex = static::implode($index);
+
+ if (!isset($words[$stringIndex])) {
+ $words[$stringIndex] = [];
+ }
+ $word = $parts[$i];
+ $words[$stringIndex][] = $word;
+ array_shift($index);
+ $index[] = $word;
+ }
+ // cache look up words for performance
+ $this->consecutiveWords[$indexSize] = $words;
+ }
+
+ return $this->consecutiveWords[$indexSize];
+ }
+
+ protected function getExplodedText()
+ {
+ if ($this->explodedText === null) {
+ $this->explodedText = static::explode(preg_replace('/\s+/u', ' ', static::$baseText));
+ }
+
+ return $this->explodedText;
+ }
+
+ protected static function explode($text)
+ {
+ return explode(static::$separator, $text);
+ }
+
+ protected static function implode($words)
+ {
+ return implode(static::$separator, $words);
+ }
+
+ protected static function strlen($text)
+ {
+ return function_exists('mb_strlen') ? mb_strlen($text, 'UTF-8') : strlen($text);
+ }
+
+ protected static function validStart($word)
+ {
+ $isValid = true;
+
+ if (static::$textStartsWithUppercase) {
+ $isValid = preg_match('/^\p{Lu}/u', $word);
+ }
+
+ return $isValid;
+ }
+
+ protected static function appendEnd($text)
+ {
+ return preg_replace("/([ ,-:;\x{2013}\x{2014}]+$)/us", '', $text) . '.';
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/UserAgent.php b/vendor/fakerphp/faker/src/Faker/Provider/UserAgent.php
new file mode 100755
index 00000000..752df4d3
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/UserAgent.php
@@ -0,0 +1,219 @@
+> 8) | (($tLo & 0xff000000) >> 24);
+ $tMi = (($tMi & 0x00ff) << 8) | (($tMi & 0xff00) >> 8);
+ $tHi = (($tHi & 0x00ff) << 8) | (($tHi & 0xff00) >> 8);
+ }
+
+ // apply version number
+ $tHi &= 0x0fff;
+ $tHi |= (3 << 12);
+
+ // cast to string
+ return sprintf(
+ '%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x',
+ $tLo,
+ $tMi,
+ $tHi,
+ $csHi,
+ $csLo,
+ $byte[10],
+ $byte[11],
+ $byte[12],
+ $byte[13],
+ $byte[14],
+ $byte[15],
+ );
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/ar_EG/Address.php b/vendor/fakerphp/faker/src/Faker/Provider/ar_EG/Address.php
new file mode 100755
index 00000000..8fe73f50
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/ar_EG/Address.php
@@ -0,0 +1,207 @@
+generator->parse($format));
+ }
+
+ /**
+ * @example 'wewebit.jo'
+ */
+ public function domainName()
+ {
+ return static::randomElement(static::$lastNameAscii) . '.' . $this->tld();
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/ar_EG/Payment.php b/vendor/fakerphp/faker/src/Faker/Provider/ar_EG/Payment.php
new file mode 100755
index 00000000..1e2eaaf0
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/ar_EG/Payment.php
@@ -0,0 +1,16 @@
+generator->parse($format));
+ }
+
+ /**
+ * @example 'wewebit.jo'
+ */
+ public function domainName()
+ {
+ return static::randomElement(static::$lastNameAscii) . '.' . $this->tld();
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/ar_JO/Person.php b/vendor/fakerphp/faker/src/Faker/Provider/ar_JO/Person.php
new file mode 100755
index 00000000..27db4e54
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/ar_JO/Person.php
@@ -0,0 +1,108 @@
+generator->parse($format));
+ }
+
+ /**
+ * @example 'wewebit.jo'
+ */
+ public function domainName()
+ {
+ return static::randomElement(static::$lastNameAscii) . '.' . $this->tld();
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/ar_SA/Payment.php b/vendor/fakerphp/faker/src/Faker/Provider/ar_SA/Payment.php
new file mode 100755
index 00000000..a09a281d
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/ar_SA/Payment.php
@@ -0,0 +1,22 @@
+generator->parse(static::randomElement(static::$lastNameFormat));
+ }
+
+ public static function lastNameMale()
+ {
+ return static::randomElement(static::$lastNameMale);
+ }
+
+ public static function lastNameFemale()
+ {
+ return static::randomElement(static::$lastNameFemale);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/bg_BG/PhoneNumber.php b/vendor/fakerphp/faker/src/Faker/Provider/bg_BG/PhoneNumber.php
new file mode 100755
index 00000000..22051df4
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/bg_BG/PhoneNumber.php
@@ -0,0 +1,20 @@
+generator->parse($format));
+ }
+
+ /**
+ * Generates valid czech IČO
+ *
+ * @see http://phpfashion.com/jak-overit-platne-ic-a-rodne-cislo
+ *
+ * @return string
+ */
+ public function ico()
+ {
+ $ico = static::numerify('#######');
+ $split = str_split($ico);
+ $prod = 0;
+
+ foreach ([8, 7, 6, 5, 4, 3, 2] as $i => $p) {
+ $prod += $p * $split[$i];
+ }
+ $mod = $prod % 11;
+
+ if ($mod === 0 || $mod === 10) {
+ return "{$ico}1";
+ }
+
+ if ($mod === 1) {
+ return "{$ico}0";
+ }
+
+ return $ico . (11 - $mod);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/cs_CZ/DateTime.php b/vendor/fakerphp/faker/src/Faker/Provider/cs_CZ/DateTime.php
new file mode 100755
index 00000000..e136e651
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/cs_CZ/DateTime.php
@@ -0,0 +1,65 @@
+format('w')];
+ }
+
+ /**
+ * @param \DateTime|int|string $max maximum timestamp used as random end limit, default to "now"
+ *
+ * @return string
+ *
+ * @example '2'
+ */
+ public static function dayOfMonth($max = 'now')
+ {
+ return static::dateTime($max)->format('j');
+ }
+
+ /**
+ * Full date with inflected month
+ *
+ * @return string
+ *
+ * @example '16. listopadu 2003'
+ */
+ public function formattedDate()
+ {
+ $format = static::randomElement(static::$formattedDateFormat);
+
+ return $this->generator->parse($format);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/cs_CZ/Internet.php b/vendor/fakerphp/faker/src/Faker/Provider/cs_CZ/Internet.php
new file mode 100755
index 00000000..ce5b2661
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/cs_CZ/Internet.php
@@ -0,0 +1,9 @@
+generator->boolean() ? static::GENDER_MALE : static::GENDER_FEMALE;
+ }
+
+ $startTimestamp = strtotime("-${maxAge} year");
+ $endTimestamp = strtotime("-${minAge} year");
+ $randTimestamp = self::numberBetween($startTimestamp, $endTimestamp);
+
+ $year = (int) (date('Y', $randTimestamp));
+ $month = (int) (date('n', $randTimestamp));
+ $day = (int) (date('j', $randTimestamp));
+ $suffix = self::numberBetween(0, 999);
+
+ // women has +50 to month
+ if ($gender == static::GENDER_FEMALE) {
+ $month += 50;
+ }
+ // from year 2004 everyone has +20 to month when birth numbers in one day are exhausted
+ if ($year >= 2004 && $this->generator->boolean(10)) {
+ $month += 20;
+ }
+
+ $birthNumber = sprintf('%02d%02d%02d%03d', $year % 100, $month, $day, $suffix);
+
+ // from year 1954 birth number includes CRC
+ if ($year >= 1954) {
+ $crc = intval($birthNumber, 10) % 11;
+
+ if ($crc == 10) {
+ $crc = 0;
+ }
+ $birthNumber .= sprintf('%d', $crc);
+ }
+
+ // add slash
+ if ($this->generator->boolean($slashProbability)) {
+ $birthNumber = substr($birthNumber, 0, 6) . '/' . substr($birthNumber, 6);
+ }
+
+ return $birthNumber;
+ }
+
+ public static function birthNumberMale()
+ {
+ return static::birthNumber(static::GENDER_MALE);
+ }
+
+ public static function birthNumberFemale()
+ {
+ return static::birthNumber(static::GENDER_FEMALE);
+ }
+
+ public function title($gender = null)
+ {
+ return static::titleMale();
+ }
+
+ /**
+ * replaced by specific unisex Czech title
+ */
+ public static function titleMale()
+ {
+ return static::randomElement(static::$title);
+ }
+
+ /**
+ * replaced by specific unisex Czech title
+ */
+ public static function titleFemale()
+ {
+ return static::titleMale();
+ }
+
+ /**
+ * @param string|null $gender 'male', 'female' or null for any
+ *
+ * @example 'Albrecht'
+ */
+ public function lastName($gender = null)
+ {
+ if ($gender === static::GENDER_MALE) {
+ return static::lastNameMale();
+ }
+
+ if ($gender === static::GENDER_FEMALE) {
+ return static::lastNameFemale();
+ }
+
+ return $this->generator->parse(static::randomElement(static::$lastNameFormat));
+ }
+
+ public static function lastNameMale()
+ {
+ return static::randomElement(static::$lastNameMale);
+ }
+
+ public static function lastNameFemale()
+ {
+ return static::randomElement(static::$lastNameFemale);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/cs_CZ/PhoneNumber.php b/vendor/fakerphp/faker/src/Faker/Provider/cs_CZ/PhoneNumber.php
new file mode 100755
index 00000000..a527a254
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/cs_CZ/PhoneNumber.php
@@ -0,0 +1,14 @@
+format('dmy'), static::numerify('%###'));
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/da_DK/PhoneNumber.php b/vendor/fakerphp/faker/src/Faker/Provider/da_DK/PhoneNumber.php
new file mode 100755
index 00000000..6e8c28da
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/da_DK/PhoneNumber.php
@@ -0,0 +1,18 @@
+format('dmy');
+
+ do {
+ $consecutiveNumber = (string) self::numberBetween(100, 999);
+
+ $verificationNumber = (
+ (int) $consecutiveNumber[0] * 3
+ + (int) $consecutiveNumber[1] * 7
+ + (int) $consecutiveNumber[2] * 9
+ + (int) $birthDateString[0] * 5
+ + (int) $birthDateString[1] * 8
+ + (int) $birthDateString[2] * 4
+ + (int) $birthDateString[3] * 2
+ + (int) $birthDateString[4] * 1
+ + (int) $birthDateString[5] * 6
+ ) % 11;
+ } while ($verificationNumber == 10);
+
+ return sprintf('%s%s%s', $consecutiveNumber, $verificationNumber, $birthDateString);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/de_AT/PhoneNumber.php b/vendor/fakerphp/faker/src/Faker/Provider/de_AT/PhoneNumber.php
new file mode 100755
index 00000000..00fbe676
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/de_AT/PhoneNumber.php
@@ -0,0 +1,23 @@
+ 'Aargau'],
+ ['AI' => 'Appenzell Innerrhoden'],
+ ['AR' => 'Appenzell Ausserrhoden'],
+ ['BE' => 'Bern'],
+ ['BL' => 'Basel-Landschaft'],
+ ['BS' => 'Basel-Stadt'],
+ ['FR' => 'Freiburg'],
+ ['GE' => 'Genf'],
+ ['GL' => 'Glarus'],
+ ['GR' => 'Graubünden'],
+ ['JU' => 'Jura'],
+ ['LU' => 'Luzern'],
+ ['NE' => 'Neuenburg'],
+ ['NW' => 'Nidwalden'],
+ ['OW' => 'Obwalden'],
+ ['SG' => 'St. Gallen'],
+ ['SH' => 'Schaffhausen'],
+ ['SO' => 'Solothurn'],
+ ['SZ' => 'Schwyz'],
+ ['TG' => 'Thurgau'],
+ ['TI' => 'Tessin'],
+ ['UR' => 'Uri'],
+ ['VD' => 'Waadt'],
+ ['VS' => 'Wallis'],
+ ['ZG' => 'Zug'],
+ ['ZH' => 'Zürich'],
+ ];
+
+ protected static $country = [
+ 'Afghanistan', 'Alandinseln', 'Albanien', 'Algerien', 'Amerikanisch-Ozeanien', 'Amerikanisch-Samoa', 'Amerikanische Jungferninseln', 'Andorra', 'Angola', 'Anguilla', 'Antarktis', 'Antigua und Barbuda', 'Argentinien', 'Armenien', 'Aruba', 'Aserbaidschan', 'Australien', 'Ägypten', 'Äquatorialguinea', 'Äthiopien', 'Äusseres Ozeanien',
+ 'Bahamas', 'Bahrain', 'Bangladesch', 'Barbados', 'Belarus', 'Belgien', 'Belize', 'Benin', 'Bermuda', 'Bhutan', 'Bolivien', 'Bosnien und Herzegowina', 'Botsuana', 'Bouvetinsel', 'Brasilien', 'Britische Jungferninseln', 'Britisches Territorium im Indischen Ozean', 'Brunei Darussalam', 'Bulgarien', 'Burkina Faso', 'Burundi',
+ 'Chile', 'China', 'Cookinseln', 'Costa Rica', 'Côte d’Ivoire',
+ 'Demokratische Republik Kongo', 'Demokratische Volksrepublik Korea', 'Deutschland', 'Dominica', 'Dominikanische Republik', 'Dschibuti', 'Dänemark',
+ 'Ecuador', 'El Salvador', 'Eritrea', 'Estland', 'Europäische Union',
+ 'Falklandinseln', 'Fidschi', 'Finnland', 'Frankreich', 'Französisch-Guayana', 'Französisch-Polynesien', 'Französische Süd- und Antarktisgebiete', 'Färöer',
+ 'Gabun', 'Gambia', 'Georgien', 'Ghana', 'Gibraltar', 'Grenada', 'Griechenland', 'Grönland', 'Guadeloupe', 'Guam', 'Guatemala', 'Guernsey', 'Guinea', 'Guinea-Bissau', 'Guyana',
+ 'Haiti', 'Heard- und McDonald-Inseln', 'Honduras',
+ 'Indien', 'Indonesien', 'Irak', 'Iran', 'Irland', 'Island', 'Isle of Man', 'Israel', 'Italien',
+ 'Jamaika', 'Japan', 'Jemen', 'Jersey', 'Jordanien',
+ 'Kaimaninseln', 'Kambodscha', 'Kamerun', 'Kanada', 'Kap Verde', 'Kasachstan', 'Katar', 'Kenia', 'Kirgisistan', 'Kiribati', 'Kokosinseln', 'Kolumbien', 'Komoren', 'Kongo', 'Kroatien', 'Kuba', 'Kuwait',
+ 'Laos', 'Lesotho', 'Lettland', 'Libanon', 'Liberia', 'Libyen', 'Liechtenstein', 'Litauen', 'Luxemburg',
+ 'Madagaskar', 'Malawi', 'Malaysia', 'Malediven', 'Mali', 'Malta', 'Marokko', 'Marshallinseln', 'Martinique', 'Mauretanien', 'Mauritius', 'Mayotte', 'Mazedonien', 'Mexiko', 'Mikronesien', 'Monaco', 'Mongolei', 'Montenegro', 'Montserrat', 'Mosambik', 'Myanmar',
+ 'Namibia', 'Nauru', 'Nepal', 'Neukaledonien', 'Neuseeland', 'Nicaragua', 'Niederlande', 'Niederländische Antillen', 'Niger', 'Nigeria', 'Niue', 'Norfolkinsel', 'Norwegen', 'Nördliche Marianen',
+ 'Oman', 'Osttimor', 'Österreich',
+ 'Pakistan', 'Palau', 'Palästinensische Gebiete', 'Panama', 'Papua-Neuguinea', 'Paraguay', 'Peru', 'Philippinen', 'Pitcairn', 'Polen', 'Portugal', 'Puerto Rico',
+ 'Republik Korea', 'Republik Moldau', 'Ruanda', 'Rumänien', 'Russische Föderation', 'Réunion',
+ 'Salomonen', 'Sambia', 'Samoa', 'San Marino', 'Saudi-Arabien', 'Schweden', 'Schweiz', 'Senegal', 'Serbien', 'Serbien und Montenegro', 'Seychellen', 'Sierra Leone', 'Simbabwe', 'Singapur', 'Slowakei', 'Slowenien', 'Somalia', 'Sonderverwaltungszone Hongkong', 'Sonderverwaltungszone Macao', 'Spanien', 'Sri Lanka', 'St. Barthélemy', 'St. Helena', 'St. Kitts und Nevis', 'St. Lucia', 'St. Martin', 'St. Pierre und Miquelon', 'St. Vincent und die Grenadinen', 'Sudan', 'Suriname', 'Svalbard und Jan Mayen', 'Swasiland', 'Syrien', 'São Tomé und Príncipe', 'Südafrika', 'Südgeorgien und die Südlichen Sandwichinseln',
+ 'Tadschikistan', 'Taiwan', 'Tansania', 'Thailand', 'Togo', 'Tokelau', 'Tonga', 'Trinidad und Tobago', 'Tschad', 'Tschechische Republik', 'Tunesien', 'Turkmenistan', 'Turks- und Caicosinseln', 'Tuvalu', 'Türkei',
+ 'Uganda', 'Ukraine', 'Unbekannte oder ungültige Region', 'Ungarn', 'Uruguay', 'Usbekistan',
+ 'Vanuatu', 'Vatikanstadt', 'Venezuela', 'Vereinigte Arabische Emirate', 'Vereinigte Staaten', 'Vereinigtes Königreich', 'Vietnam',
+ 'Wallis und Futuna', 'Weihnachtsinsel', 'Westsahara',
+ 'Zentralafrikanische Republik', 'Zypern',
+ ];
+
+ protected static $cityFormats = [
+ '{{cityName}}',
+ ];
+
+ protected static $streetNameFormats = [
+ '{{lastName}}{{streetSuffixShort}}',
+ '{{cityName}}{{streetSuffixShort}}',
+ '{{firstName}}-{{lastName}}-{{streetSuffixLong}}',
+ ];
+
+ protected static $streetAddressFormats = [
+ '{{streetName}} {{buildingNumber}}',
+ ];
+ protected static $addressFormats = [
+ "{{streetAddress}}\n{{postcode}} {{city}}",
+ ];
+
+ /**
+ * Returns a random city name.
+ *
+ * @example Luzern
+ *
+ * @return string
+ */
+ public function cityName()
+ {
+ return static::randomElement(static::$cityNames);
+ }
+
+ /**
+ * Returns a random street suffix.
+ *
+ * @example str.
+ *
+ * @return string
+ */
+ public function streetSuffixShort()
+ {
+ return static::randomElement(static::$streetSuffixShort);
+ }
+
+ /**
+ * Returns a random street suffix.
+ *
+ * @example Strasse
+ *
+ * @return string
+ */
+ public function streetSuffixLong()
+ {
+ return static::randomElement(static::$streetSuffixLong);
+ }
+
+ /**
+ * Returns a canton
+ *
+ * @example array('BE' => 'Bern')
+ *
+ * @return array
+ */
+ public static function canton()
+ {
+ return static::randomElement(static::$canton);
+ }
+
+ /**
+ * Returns the abbreviation of a canton.
+ *
+ * @return string
+ */
+ public static function cantonShort()
+ {
+ $canton = static::canton();
+
+ return key($canton);
+ }
+
+ /**
+ * Returns the name of canton.
+ *
+ * @return string
+ */
+ public static function cantonName()
+ {
+ $canton = static::canton();
+
+ return current($canton);
+ }
+
+ public static function buildingNumber()
+ {
+ return static::regexify(self::numerify(static::randomElement(static::$buildingNumber)));
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/de_CH/Company.php b/vendor/fakerphp/faker/src/Faker/Provider/de_CH/Company.php
new file mode 100755
index 00000000..ead2781e
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/de_CH/Company.php
@@ -0,0 +1,15 @@
+
+ */
+ protected static $areaCodeRegexes = [
+ 2 => '(0[0-389]|0[4-6][1-68]|1[124]|1[0-9][0-9]|2[18]|2[0-9][1-9]|3[14]|3[0-35-9][0-9]|4[1]|4[02-8][0-9]|5[1]|5[02-9][0-9]|6[1]|6[02-9][0-9]|7[1]|7[2-7][0-9]|8[1]|8[02-7][0-9]|9[1]|9[02-9][0-9])',
+ 3 => '(0|3[15]|3[02-46-9][1-9]|3[02-46-9][02-9][0-9]|4[015]|4[2-4679][1-8]|4[2-4679][02-9][0-9]|5[15]|5[02-46-9][1-9]|5[02-46-9][02-9][0-9]|6[15]|6[02-46-9][1-9]|6[02-46-9][02-9][0-9]|7[15]|7[2-467][1-7]|7[2-467][02-689][0-9]|8[15]|8[2-46-8][013-9]|8[2-46-8][02-9][0-9]|9[15]|9[02-46-9][1-9]|9[02-46-9][02-9][0-9])',
+ 4 => '(0|1[02-9][0-9]|2[1]|2[02-9][0-9]|3[1]|3[02-9][0-9]|4[1]|4[0-9][0-9]|5[1]|5[02-6][0-9]|6[1]|6[02-8][0-9]|7[1]|7[02-79][0-9]|8[1]|8[02-9][0-9]|9[1]|9[02-7][0-9])',
+ 5 => '(0[2-8][0-9]|1[1]|1[02-9][0-9]|2[1]|2[02-9][1-9]|3[1]|3[02-8][0-9]|4[1]|4[02-9][1-9]|5[1]|5[02-9][0-9]|6[1]|6[02-9][0-9]|7[1]|7[02-7][1-9]|8[1]|8[02-8][0-9]|9[1]|9[0-7][1-9])',
+ 6 => '(0[02-9][0-9]|1[1]|1[02-9][0-9]|2[1]|2[02-9][0-9]|3[1]|3[02-9][0-9]|4[1]|4[0-8][0-9]|5[1]|5[02-9][0-9]|6[1]|6[2-9][0-9]|7[1]|7[02-8][1-9]|8[1]|8[02-9][1-9]|9)',
+ 7 => '(0[2-8][1-6]|1[1]|1[2-9][0-9]|2[1]|2[0-7][0-9]|3[1]|3[02-9][0-9]|4[1]|4[0-8][0-9]|5[1]|5[02-8][0-9]|6[1]|6[02-8][0-9]|7[1]|7[02-7][0-9]|8[1]|8[02-5][1-9]|9[1]|9[03-7][0-9])',
+ 8 => '(0[2-9][0-9]|1[1]|1[02-79][0-9]|2[1]|2[02-9][0-9]|3[1]|3[02-9][0-9]|4[1]|4[02-6][0-9]|5[1]|5[02-9][0-9]|6[1]|6[2-8][0-9]|7[1]|7[02-8][1-9]|8[1]|8[02-6][0-9]|9)',
+ 9 => '(0[6]|0[07-9][0-9]|1[1]|1[02-9][0-9]|2[1]|2[02-9][0-9]|3[1]|3[02-9][0-9]|4[1]|4[02-9][0-9]|5[1]|5[02-7][0-9]|6[1]|6[02-8][1-9]|7[1]|7[02-467][0-9]|8[1]|8[02-7][0-9]|9[1]|9[02-7][0-9])',
+ ];
+
+ /**
+ * @see https://en.wikipedia.org/wiki/National_conventions_for_writing_telephone_numbers#Germany
+ * @see https://www.itu.int/oth/T0202000051/en
+ * @see https://en.wikipedia.org/wiki/Telephone_numbers_in_Germany
+ */
+ protected static $formats = [
+ // International format
+ '+49 {{areaCode}} #######',
+ '+49 {{areaCode}} ### ####',
+ '+49 (0{{areaCode}}) #######',
+ '+49 (0{{areaCode}}) ### ####',
+ '+49{{areaCode}}#######',
+ '+49{{areaCode}}### ####',
+
+ // Standard formats
+ '0{{areaCode}} ### ####',
+ '0{{areaCode}} #######',
+ '(0{{areaCode}}) ### ####',
+ '(0{{areaCode}}) #######',
+ ];
+
+ protected static $e164Formats = [
+ '+49{{areaCode}}#######',
+ ];
+
+ /**
+ * @see https://en.wikipedia.org/wiki/Toll-free_telephone_number
+ */
+ protected static $tollFreeAreaCodes = [
+ 800,
+ ];
+
+ protected static $tollFreeFormats = [
+ // Standard formats
+ '0{{tollFreeAreaCode}} ### ####',
+ '(0{{tollFreeAreaCode}}) ### ####',
+ '+49{{tollFreeAreaCode}} ### ####',
+ ];
+
+ public function tollFreeAreaCode()
+ {
+ return self::randomElement(static::$tollFreeAreaCodes);
+ }
+
+ public function tollFreePhoneNumber()
+ {
+ $format = self::randomElement(static::$tollFreeFormats);
+
+ return self::numerify($this->generator->parse($format));
+ }
+
+ protected static $mobileCodes = [
+ 1511, 1512, 1514, 1515, 1516, 1517,
+ 1520, 1521, 1522, 1523, 1525, 1526, 1529,
+ 1570, 1573, 1575, 1577, 1578, 1579,
+ 1590,
+ ];
+
+ protected static $mobileFormats = [
+ '+49{{mobileCode}}#######',
+ '+49 {{mobileCode}} ### ####',
+ '0{{mobileCode}}#######',
+ '0{{mobileCode}} ### ####',
+ '0 {{mobileCode}} ### ####',
+ ];
+
+ /**
+ * @see https://en.wikipedia.org/wiki/List_of_dialling_codes_in_Germany
+ *
+ * @return string
+ */
+ public static function areaCode()
+ {
+ $firstDigit = self::numberBetween(2, 9);
+
+ return $firstDigit . self::regexify(self::$areaCodeRegexes[$firstDigit]);
+ }
+
+ /**
+ * Generate a code for a mobile number.
+ *
+ * @internal Used to generate mobile numbers.
+ *
+ * @return string
+ */
+ public static function mobileCode()
+ {
+ return static::randomElement(static::$mobileCodes);
+ }
+
+ /**
+ * Generate a mobile number.
+ *
+ * @example A mobile number: '015111234567'
+ * @example A mobile number with spaces: '01511 123 4567'
+ * @example A mobile number with international code prefix: '+4915111234567'
+ * @example A mobile number with international code prefix and spaces: '+49 1511 123 4567'
+ *
+ * @return string
+ */
+ public function mobileNumber()
+ {
+ return ltrim(static::numerify($this->generator->parse(
+ static::randomElement(static::$mobileFormats),
+ )));
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/de_DE/Text.php b/vendor/fakerphp/faker/src/Faker/Provider/de_DE/Text.php
new file mode 100755
index 00000000..55ed5a55
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/de_DE/Text.php
@@ -0,0 +1,2038 @@
+generator->parse(static::randomElement(static::$lastNameFormat));
+ }
+
+ /**
+ * @example 'Θεοδωρόπουλος'
+ */
+ public static function lastNameMale()
+ {
+ return static::randomElement(static::$lastNameMale);
+ }
+
+ /**
+ * @example 'Κοκκίνου'
+ */
+ public static function lastNameFemale()
+ {
+ return static::randomElement(static::$lastNameFemale);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/el_GR/PhoneNumber.php b/vendor/fakerphp/faker/src/Faker/Provider/el_GR/PhoneNumber.php
new file mode 100755
index 00000000..53032487
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/el_GR/PhoneNumber.php
@@ -0,0 +1,324 @@
+generator->parse(
+ static::randomElement(static::$fixedLineFormats),
+ )));
+ }
+
+ /**
+ * Generate a code for a mobile number.
+ *
+ * @internal Used to generate mobile numbers.
+ *
+ * @return string
+ */
+ public static function mobileCode()
+ {
+ return static::randomElement(static::$mobileCodes);
+ }
+
+ /**
+ * Generate a mobile number.
+ *
+ * @example A mobile number: '6901234567'
+ * @example A mobile number with spaces: '690 123 4567'
+ * @example A mobile number with international code prefix: '+306901234567'
+ * @example A mobile number with international code prefix and spaces: '+30 690 123 4567'
+ *
+ * @return string
+ */
+ public function mobileNumber()
+ {
+ return ltrim(static::numerify($this->generator->parse(
+ static::randomElement(static::$mobileFormats),
+ )));
+ }
+
+ /**
+ * @deprecated Use PhoneNumber::mobileNumber() instead.
+ */
+ public static function mobilePhoneNumber()
+ {
+ return static::numerify(
+ strtr(static::randomElement(static::$mobileFormats), [
+ '{{internationalCodePrefix}}' => static::internationalCodePrefix(),
+ '{{mobileCode}}' => static::mobileCode(),
+ ]),
+ );
+ }
+
+ /**
+ * Generate a personal number.
+ *
+ * @example A personal number: '7012345678'
+ * @example A personal number with spaces: '70 1234 5678'
+ * @example A personal number with international code prefix: '+307012345678'
+ * @example A personal number with international code prefix and spaces: '+30 70 1234 5678'
+ *
+ * @return string
+ */
+ public function personalNumber()
+ {
+ return ltrim(static::numerify($this->generator->parse(
+ static::randomElement(static::$personalFormats),
+ )));
+ }
+
+ /**
+ * Generate a toll-free number.
+ *
+ * @example A toll-free number: '8001234567'
+ * @example A toll-free number with spaces: '800 123 4567'
+ * @example A toll-free number with international code prefix: '+308001234567'
+ * @example A toll-free number with international code prefix and spaces: '+30 800 123 4567'
+ *
+ * @return string
+ */
+ public static function tollFreeNumber()
+ {
+ return ltrim(static::numerify(
+ strtr(static::randomElement(static::$tollFreeFormats), [
+ '{{internationalCodePrefix}}' => static::internationalCodePrefix(),
+ ]),
+ ));
+ }
+
+ /**
+ * Generate a code for a shared-cost number.
+ *
+ * @internal Used to generate shared-cost numbers.
+ *
+ * @return string
+ */
+ public static function sharedCostCode()
+ {
+ return static::randomElement(static::$sharedCostCodes);
+ }
+
+ /**
+ * Generate a shared-cost number.
+ *
+ * @example A shared-cost number: '8011234567'
+ * @example A shared-cost number with spaces: '801 123 4567'
+ * @example A shared-cost number with international code prefix: '+308011234567'
+ * @example A shared-cost number with international code prefix and spaces: '+30 801 123 4567'
+ *
+ * @return string
+ */
+ public function sharedCostNumber()
+ {
+ return ltrim(static::numerify($this->generator->parse(
+ static::randomElement(static::$sharedCostFormats),
+ )));
+ }
+
+ /**
+ * Generate a code for a premium-rate number.
+ *
+ * @internal Used to generate premium-rate numbers.
+ *
+ * @return string
+ */
+ public static function premiumRateCode()
+ {
+ return static::randomElement(static::$premiumRateCodes);
+ }
+
+ /**
+ * Generate a premium-rate number.
+ *
+ * @example A premium-rate number: '9011234567'
+ * @example A premium-rate number with spaces: '901 123 4567'
+ * @example A premium-rate number with international code prefix: '+309011234567'
+ * @example A premium-rate number with international code prefix and spaces: '+30 901 123 4567'
+ *
+ * @return string
+ */
+ public function premiumRateNumber()
+ {
+ return ltrim(static::numerify($this->generator->parse(
+ static::randomElement(static::$premiumRateFormats),
+ )));
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/el_GR/Text.php b/vendor/fakerphp/faker/src/Faker/Provider/el_GR/Text.php
new file mode 100755
index 00000000..f4be7606
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/el_GR/Text.php
@@ -0,0 +1,2582 @@
+ 0) {
+ $sum -= 97;
+ }
+ $sum = $sum * -1;
+
+ return str_pad((string) $sum, 2, '0', STR_PAD_LEFT);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/en_GB/Internet.php b/vendor/fakerphp/faker/src/Faker/Provider/en_GB/Internet.php
new file mode 100755
index 00000000..ef5934ab
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/en_GB/Internet.php
@@ -0,0 +1,9 @@
+generator->parse(static::randomElement(static::$towns));
+ }
+
+ public function syllable()
+ {
+ return static::randomElement(static::$syllables);
+ }
+
+ public function direction()
+ {
+ return static::randomElement(static::$directions);
+ }
+
+ public function englishStreetName()
+ {
+ return static::randomElement(static::$englishStreetNames);
+ }
+
+ public function villageSuffix()
+ {
+ return static::randomElement(static::$villageSuffixes);
+ }
+
+ public function estateSuffix()
+ {
+ return static::randomElement(static::$estateSuffixes);
+ }
+
+ public function village()
+ {
+ return $this->generator->parse(static::randomElement(static::$villageNameFormats));
+ }
+
+ public function estate()
+ {
+ return $this->generator->parse(static::randomElement(static::$estateNameFormats));
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/en_HK/Internet.php b/vendor/fakerphp/faker/src/Faker/Provider/en_HK/Internet.php
new file mode 100755
index 00000000..2de48a53
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/en_HK/Internet.php
@@ -0,0 +1,14 @@
+generator->parse(static::randomElement(static::$societyNameFormat));
+ }
+
+ /**
+ * @example Mumbai
+ */
+ public function city()
+ {
+ return static::randomElement(static::$city);
+ }
+
+ /**
+ * @example Vaishali Nagar
+ */
+ public function locality()
+ {
+ return $this->generator->parse(static::randomElement(static::$localityFormats));
+ }
+
+ /**
+ * @example Kharadi
+ */
+ public function localityName()
+ {
+ return $this->generator->parse(static::randomElement(static::$localityName));
+ }
+
+ /**
+ * @example Nagar
+ */
+ public function areaSuffix()
+ {
+ return static::randomElement(static::$areaSuffix);
+ }
+
+ /**
+ * @example 'Delhi'
+ */
+ public static function state()
+ {
+ return static::randomElement(static::$state);
+ }
+
+ /**
+ * @example 'DL'
+ */
+ public static function stateAbbr()
+ {
+ return static::randomElement(static::$stateAbbr);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/en_IN/Internet.php b/vendor/fakerphp/faker/src/Faker/Provider/en_IN/Internet.php
new file mode 100755
index 00000000..a5435352
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/en_IN/Internet.php
@@ -0,0 +1,9 @@
+format('y');
+ $checksumArr = ['J', 'Z', 'I', 'H', 'G', 'F', 'E', 'D', 'C', 'B', 'A'];
+ }
+
+ $length = count($weights);
+
+ for ($i = strlen($result); $i < $length; ++$i) {
+ $result .= static::randomDigit();
+ }
+
+ $checksum = in_array($prefix, ['G', 'T'], true) ? 4 : 0;
+
+ for ($i = 0; $i < $length; ++$i) {
+ $checksum += (int) $result[$i] * $weights[$i];
+ }
+
+ return $prefix . $result . $checksumArr[$checksum % 11];
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/en_SG/PhoneNumber.php b/vendor/fakerphp/faker/src/Faker/Provider/en_SG/PhoneNumber.php
new file mode 100755
index 00000000..f5e3ca6b
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/en_SG/PhoneNumber.php
@@ -0,0 +1,105 @@
+generator->parse($format));
+ }
+
+ public function fixedLineNumber()
+ {
+ $format = static::randomElement(static::$fixedLineNumberFormats);
+
+ return static::numerify($this->generator->parse($format));
+ }
+
+ public function voipNumber()
+ {
+ $format = static::randomElement(static::$voipNumber);
+
+ return static::numerify($this->generator->parse($format));
+ }
+
+ public function internationalCodePrefix()
+ {
+ return static::randomElement(static::$internationalCodePrefix);
+ }
+
+ public function zeroToEight()
+ {
+ return static::randomElement(static::$zeroToEight);
+ }
+
+ public function oneToEight()
+ {
+ return static::randomElement(static::$oneToEight);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/en_UG/Address.php b/vendor/fakerphp/faker/src/Faker/Provider/en_UG/Address.php
new file mode 100755
index 00000000..9024b8b7
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/en_UG/Address.php
@@ -0,0 +1,101 @@
+
+ */
+ protected static $areaCodeRegexes = [
+ 2 => '(0[1-35-9]|1[02-9]|2[03-589]|3[149]|4[08]|5[1-46]|6[0279]|7[0269]|8[13])',
+ 3 => '(0[1-57-9]|1[02-9]|2[0135]|3[0-24679]|4[167]|5[12]|6[014]|8[056])',
+ 4 => '(0[124-9]|1[02-579]|2[3-5]|3[0245]|4[0235]|58|6[39]|7[0589]|8[04])',
+ 5 => '(0[1-57-9]|1[0235-8]|20|3[0149]|4[01]|5[19]|6[1-47]|7[013-5]|8[056])',
+ 6 => '(0[1-35-9]|1[024-9]|2[03689]|[34][016]|5[017]|6[0-279]|78|8[0-29])',
+ 7 => '(0[1-46-8]|1[2-9]|2[04-7]|3[1247]|4[037]|5[47]|6[02359]|7[02-59]|8[156])',
+ 8 => '(0[1-68]|1[02-8]|2[08]|3[0-28]|4[3578]|5[046-9]|6[02-5]|7[028])',
+ 9 => '(0[1346-9]|1[02-9]|2[0589]|3[0146-8]|4[0179]|5[12469]|7[0-389]|8[04-69])',
+ ];
+
+ /**
+ * @see https://en.wikipedia.org/wiki/National_conventions_for_writing_telephone_numbers#United_States.2C_Canada.2C_and_other_NANP_countries
+ */
+ protected static $formats = [
+ // International format
+ '+1-{{areaCode}}-{{exchangeCode}}-####',
+ '+1 ({{areaCode}}) {{exchangeCode}}-####',
+ '+1-{{areaCode}}-{{exchangeCode}}-####',
+ '+1.{{areaCode}}.{{exchangeCode}}.####',
+ '+1{{areaCode}}{{exchangeCode}}####',
+
+ // Standard formats
+ '{{areaCode}}-{{exchangeCode}}-####',
+ '({{areaCode}}) {{exchangeCode}}-####',
+ '1-{{areaCode}}-{{exchangeCode}}-####',
+ '{{areaCode}}.{{exchangeCode}}.####',
+
+ '{{areaCode}}-{{exchangeCode}}-####',
+ '({{areaCode}}) {{exchangeCode}}-####',
+ '1-{{areaCode}}-{{exchangeCode}}-####',
+ '{{areaCode}}.{{exchangeCode}}.####',
+ ];
+
+ protected static $formatsWithExtension = [
+ '{{areaCode}}-{{exchangeCode}}-#### x###',
+ '({{areaCode}}) {{exchangeCode}}-#### x###',
+ '1-{{areaCode}}-{{exchangeCode}}-#### x###',
+ '{{areaCode}}.{{exchangeCode}}.#### x###',
+
+ '{{areaCode}}-{{exchangeCode}}-#### x####',
+ '({{areaCode}}) {{exchangeCode}}-#### x####',
+ '1-{{areaCode}}-{{exchangeCode}}-#### x####',
+ '{{areaCode}}.{{exchangeCode}}.#### x####',
+
+ '{{areaCode}}-{{exchangeCode}}-#### x#####',
+ '({{areaCode}}) {{exchangeCode}}-#### x#####',
+ '1-{{areaCode}}-{{exchangeCode}}-#### x#####',
+ '{{areaCode}}.{{exchangeCode}}.#### x#####',
+ ];
+
+ protected static $e164Formats = [
+ '+1{{areaCode}}{{exchangeCode}}####',
+ ];
+
+ /**
+ * @see https://en.wikipedia.org/wiki/Toll-free_telephone_number#United_States
+ */
+ protected static $tollFreeAreaCodes = [
+ 800, 844, 855, 866, 877, 888,
+ ];
+ protected static $tollFreeFormats = [
+ // Standard formats
+ '{{tollFreeAreaCode}}-{{exchangeCode}}-####',
+ '({{tollFreeAreaCode}}) {{exchangeCode}}-####',
+ '1-{{tollFreeAreaCode}}-{{exchangeCode}}-####',
+ '{{tollFreeAreaCode}}.{{exchangeCode}}.####',
+ ];
+
+ public function tollFreeAreaCode()
+ {
+ return self::randomElement(static::$tollFreeAreaCodes);
+ }
+
+ public function tollFreePhoneNumber()
+ {
+ $format = self::randomElement(static::$tollFreeFormats);
+
+ return self::numerify($this->generator->parse($format));
+ }
+
+ /**
+ * @return string
+ *
+ * @example '555-123-546 x123'
+ */
+ public function phoneNumberWithExtension()
+ {
+ return static::numerify($this->generator->parse(static::randomElement(static::$formatsWithExtension)));
+ }
+
+ /**
+ * NPA-format area code
+ *
+ * @see https://en.wikipedia.org/wiki/North_American_Numbering_Plan#Numbering_system
+ *
+ * @return string
+ */
+ public static function areaCode()
+ {
+ $firstDigit = self::numberBetween(2, 9);
+
+ return $firstDigit . self::regexify(self::$areaCodeRegexes[$firstDigit]);
+ }
+
+ /**
+ * NXX-format central office exchange code
+ *
+ * @see https://en.wikipedia.org/wiki/North_American_Numbering_Plan#Numbering_system
+ *
+ * @return string
+ */
+ public static function exchangeCode()
+ {
+ $digits[] = self::numberBetween(2, 9);
+ $digits[] = self::randomDigit();
+
+ if ($digits[1] === 1) {
+ $digits[] = self::randomDigitNot(1);
+ } else {
+ $digits[] = self::randomDigit();
+ }
+
+ return implode('', $digits);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/en_US/Text.php b/vendor/fakerphp/faker/src/Faker/Provider/en_US/Text.php
new file mode 100755
index 00000000..c15d89d9
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/en_US/Text.php
@@ -0,0 +1,3721 @@
+format('Y'),
+ static::randomNumber(6, true),
+ static::randomElement(static::$legalEntities),
+ );
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/en_ZA/Internet.php b/vendor/fakerphp/faker/src/Faker/Provider/en_ZA/Internet.php
new file mode 100755
index 00000000..c2222276
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/en_ZA/Internet.php
@@ -0,0 +1,23 @@
+generator->dateTimeThisCentury();
+ }
+ $birthDateString = $birthdate->format('ymd');
+
+ switch (strtolower($gender ?: '')) {
+ case static::GENDER_FEMALE:
+ $genderDigit = self::numberBetween(0, 4);
+
+ break;
+
+ case static::GENDER_MALE:
+ $genderDigit = self::numberBetween(5, 9);
+
+ break;
+
+ default:
+ $genderDigit = self::numberBetween(0, 9);
+ }
+ $sequenceDigits = str_pad(self::randomNumber(3), 3, 0, STR_PAD_BOTH);
+ $citizenDigit = ($citizen === true) ? '0' : '1';
+ $raceDigit = self::numberBetween(8, 9);
+
+ $partialIdNumber = $birthDateString . $genderDigit . $sequenceDigits . $citizenDigit . $raceDigit;
+
+ return $partialIdNumber . Luhn::computeCheckDigit($partialIdNumber);
+ }
+
+ /**
+ * @see https://en.wikipedia.org/wiki/Driving_licence_in_South_Africa
+ *
+ * @return string
+ */
+ public function licenceCode()
+ {
+ return static::randomElement(static::$licenceCodes);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/en_ZA/PhoneNumber.php b/vendor/fakerphp/faker/src/Faker/Provider/en_ZA/PhoneNumber.php
new file mode 100755
index 00000000..567631a0
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/en_ZA/PhoneNumber.php
@@ -0,0 +1,116 @@
+generator->parse($format));
+ }
+
+ public function tollFreeNumber()
+ {
+ $format = static::randomElement(static::$specialFormats);
+
+ return self::numerify($this->generator->parse($format));
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/es_AR/Address.php b/vendor/fakerphp/faker/src/Faker/Provider/es_AR/Address.php
new file mode 100755
index 00000000..457f8caf
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/es_AR/Address.php
@@ -0,0 +1,68 @@
+numberBetween(10000, 100000000);
+ }
+
+ return $id . $separator . $this->numberBetween(80000000, 100000000);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/es_VE/PhoneNumber.php b/vendor/fakerphp/faker/src/Faker/Provider/es_VE/PhoneNumber.php
new file mode 100755
index 00000000..cfe6438f
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/es_VE/PhoneNumber.php
@@ -0,0 +1,29 @@
+generator->parse($format);
+ }
+
+ /**
+ * @example 'کد پستی'
+ */
+ public static function postcodePrefix()
+ {
+ return static::randomElement(static::$postcodePrefix);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/fa_IR/Company.php b/vendor/fakerphp/faker/src/Faker/Provider/fa_IR/Company.php
new file mode 100755
index 00000000..15da3c5a
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/fa_IR/Company.php
@@ -0,0 +1,60 @@
+generator->parse($format));
+ }
+
+ /**
+ * @example 'ahmad.ir'
+ */
+ public function domainName()
+ {
+ return static::randomElement(static::$lastNameAscii) . '.' . $this->tld();
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/fa_IR/Person.php b/vendor/fakerphp/faker/src/Faker/Provider/fa_IR/Person.php
new file mode 100755
index 00000000..546e2a3f
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/fa_IR/Person.php
@@ -0,0 +1,210 @@
+ 1; --$i) {
+ $sum += $subNationalCodeString[$count] * ($i);
+ ++$count;
+ }
+
+ if (($sum % 11) < 2) {
+ return $sum % 11;
+ }
+
+ return 11 - ($sum % 11);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/fa_IR/PhoneNumber.php b/vendor/fakerphp/faker/src/Faker/Provider/fa_IR/PhoneNumber.php
new file mode 100755
index 00000000..a9606d02
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/fa_IR/PhoneNumber.php
@@ -0,0 +1,76 @@
+ 5) {
+ throw new \InvalidArgumentException('indexSize must be at most 5');
+ }
+
+ $words = $this->getConsecutiveWords($indexSize);
+ $result = [];
+ $resultLength = 0;
+ // take a random starting point
+ $next = static::randomKey($words);
+
+ while ($resultLength < $maxNbChars && isset($words[$next])) {
+ // fetch a random word to append
+ $word = static::randomElement($words[$next]);
+
+ // calculate next index
+ $currentWords = explode(' ', $next);
+
+ $currentWords[] = $word;
+ array_shift($currentWords);
+ $next = implode(' ', $currentWords);
+
+ if ($resultLength == 0 && !preg_match('/^[\x{0600}-\x{06FF}]/u', $word)) {
+ continue;
+ }
+ // append the element
+ $result[] = $word;
+ $resultLength += strlen($word) + 1;
+ }
+
+ // remove the element that caused the text to overflow
+ array_pop($result);
+
+ // build result
+ $result = implode(' ', $result);
+
+ return $result . '.';
+ }
+
+ /**
+ * License: Creative Commons Attribution-ShareAlike License
+ *
+ * Title: مدیر مدرسه
+ * Author: جلال آلاحمد
+ * Language: Persian
+ *
+ * @see http://fa.wikisource.org/wiki/%D9%85%D8%AF%DB%8C%D8%B1_%D9%85%D8%AF%D8%B1%D8%B3%D9%87
+ *
+ * @var string
+ */
+ protected static $baseText = <<<'EOT'
+از در که وارد شدم سیگارم دستم بود. زورم آمد سلام کنم. همین طوری دنگم گرفته بود قد باشم. رئیس فرهنگ که اجازهی نشستن داد، نگاهش لحظهای روی دستم مکث کرد و بعد چیزی را که مینوشت، تمام کرد و میخواست متوجه من بشود که رونویس حکم را روی میزش گذاشته بودم. حرفی نزدیم. رونویس را با کاغذهای ضمیمهاش زیر و رو کرد و بعد غبغب انداخت و آرام و مثلاً خالی از عصبانیت گفت:
+
+- جا نداریم آقا. این که نمیشه! هر روز یه حکم میدند دست یکی میفرستنش سراغ من... دیروز به آقای مدیر کل...
+
+حوصلهی این اباطیل را نداشتم. حرفش را بریدم که:
+
+- ممکنه خواهش کنم زیر همین ورقه مرقوم بفرمایید؟
+
+و سیگارم را توی زیرسیگاری براق روی میزش تکاندم. روی میز، پاک و مرتب بود. درست مثل اتاق همان مهمانخانهی تازهعروسها. هر چیز به جای خود و نه یک ذره گرد. فقط خاکستر سیگار من زیادی بود. مثل تفی در صورت تازه تراشیدهای.... قلم را برداشت و زیر حکم چیزی نوشت و امضا کرد و من از در آمده بودم بیرون. خلاص. تحمل این یکی را نداشتم. با اداهایش. پیدا بود که تازه رئیس شده. زورکی غبغب میانداخت و حرفش را آهسته توی چشم آدم میزد. انگار برای شنیدنش گوش لازم نیست. صد و پنجاه تومان در کارگزینی کل مایه گذاشته بودم تا این حکم را به امضا رسانده بودم. توصیه هم برده بودم و تازه دو ماه هم دویده بودم. مو، لای درزش نمیرفت. میدانستم که چه او بپذیرد، چه نپذیرد، کار تمام است. خودش هم میدانست. حتماً هم دستگیرش شد که با این نک و نالی که میکرد، خودش را کنف کرده. ولی کاری بود و شده بود. در کارگزینی کل، سفارش کرده بودند که برای خالی نبودن عریضه رونویس را به رؤیت رئیس فرهنگ هم برسانم تازه این طور شد. و گر نه بالی حکم کارگزینی کل چه کسی میتوانست حرفی بزند؟ یک وزارت خانه بود و یک کارگزینی! شوخی که نبود. ته دلم قرصتر از اینها بود که محتاج به این استدلالها باشم. اما به نظرم همهی این تقصیرها از این سیگار لعنتی بود که به خیال خودم خواسته بودم خرجش را از محل اضافه حقوق شغل جدیدم در بیاورم. البته از معلمی، هم اُقم نشسته بود. ده سال «الف.ب.» درس دادن و قیافههای بهتزدهی بچههای مردم برای مزخرفترین چرندی که میگویی... و استغناء با غین و استقراء با قاف و خراسانی و هندی و قدیمیترین شعر دری و صنعت ارسال مثل و ردالعجز... و از این مزخرفات! دیدم دارم خر میشوم. گفتم مدیر بشوم. مدیر دبستان! دیگر نه درس خواهم داد و نه مجبور خواهم بود برای فرار از اتلاف وقت، در امتحان تجدیدی به هر احمق بیشعوری هفت بدهم تا ایام آخر تابستانم را که لذیذترین تکهی تعطیلات است، نجات داده باشم. این بود که راه افتادم. رفتم و از اهلش پرسیدم. از یک کار چاق کن. دستم را توی دست کارگزینی گذاشت و قول و قرار و طرفین خوش و خرم و یک روز هم نشانی مدرسه را دستم دادند که بروم وارسی، که باب میلم هست یا نه.
+
+و رفتم. مدرسه دو طبقه بود و نوساز بود و در دامنهی کوه تنها افتاده بود و آفتابرو بود. یک فرهنگدوست خرپول، عمارتش را وسط زمین خودش ساخته بود و بیست و پنج سال هم در اختیار فرهنگ گذاشته بود که مدرسهاش کنند و رفت و آمد بشود و جادهها کوبیده بشود و این قدر ازین بشودها بشود، تا دل ننه باباها بسوزد و برای اینکه راه بچههاشان را کوتاه بکنند، بیایند همان اطراف مدرسه را بخرند و خانه بسازند و زمین یارو از متری یک عباسی بشود صد تومان. یارو اسمش را هم روی دیوار مدرسه کاشیکاری کرده بود. هنوز در و همسایه پیدا نکرده بودند که حرفشان بشود و لنگ و پاچهی سعدی و باباطاهر را بکشند میان و یک ورق دیگر از تاریخالشعرا را بکوبند روی نبش دیوار کوچهشان. تابلوی مدرسه هم حسابی و بزرگ و خوانا. از صد متری داد میزد که توانا بود هر.... هر چه دلتان بخواهد! با شیر و خورشیدش که آن بالا سر، سه پا ایستاده بود و زورکی تعادل خودش را حفظ میکرد و خورشید خانم روی کولش با ابروهای پیوسته و قمچیلی که به دست داشت و تا سه تیر پرتاب، اطراف مدرسه بیابان بود. درندشت و بی آب و آبادانی و آن ته رو به شمال، ردیف کاجهای درهم فرو رفتهای که از سر دیوار گلی یک باغ پیدا بود روی آسمان لکهی دراز و تیرهای زده بود. حتماً تا بیست و پنج سال دیگر همهی این اطراف پر میشد و بوق ماشین و ونگ ونگ بچهها و فریاد لبویی و زنگ روزنامهفروشی و عربدهی گل به سر دارم خیار! نان یارو توی روغن بود.
+
+- راستی شاید متری ده دوازده شاهی بیشتر نخریده باشد؟ شاید هم زمینها را همین جوری به ثبت داده باشد؟ هان؟
+
+- احمق به توچه؟!...
+
+بله این فکرها را همان روزی کردم که ناشناس به مدرسه سر زدم و آخر سر هم به این نتیجه رسیدم که مردم حق دارند جایی بخوابند که آب زیرشان نرود.
+
+- تو اگر مردی، عرضه داشته باش مدیر همین مدرسه هم بشو.
+
+و رفته بودم و دنبال کار را گرفته بودم تا رسیده بودم به اینجا. همان روز وارسی فهمیده بودم که مدیر قبلی مدرسه زندانی است. لابد کلهاش بوی قرمهسبزی میداده و باز لابد حالا دارد کفارهی گناهانی را میدهد که یا خودش نکرده یا آهنگری در بلخ کرده. جزو پر قیچیهای رئیس فرهنگ هم کسی نبود که با مدیرشان، اضافه حقوقی نصیبش بشود و ناچار سر و دستی برای این کار بشکند. خارج از مرکز هم نداشت. این معلومات را توی کارگزینی به دست آورده بودم. هنوز «گه خوردم نامهنویسی» هم مد نشده بود که بگویم یارو به این زودیها از سولدونی در خواهد آمد. فکر نمیکردم که دیگری هم برای این وسط بیابان دلش لک زده باشد با زمستان سختش و با رفت و آمد دشوارش.
+
+این بود که خیالم راحت بود. از همهی اینها گذشته کارگزینی کل موافقت کرده بود! دست است که پیش از بلند شدن بوی اسکناس، آن جا هم دو سه تا عیب شرعی و عرفی گرفته بودند و مثلاً گفته بودن لابد کاسهای زیر نیم کاسه است که فلانی یعنی من، با ده سال سابقهی تدریس، میخواهد مدیر دبستان بشود! غرضشان این بود که لابد خل شدم که از شغل مهم و محترم دبیری دست میشویم. ماهی صد و پنجاه تومان حق مقام در آن روزها پولی نبود که بتوانم نادیده بگیرم. و تازه اگر ندیده میگرفتم چه؟ باز باید بر میگشتم به این کلاسها و این جور حماقتها. این بود که پیش رئیس فرهنگ، صاف برگشتم به کارگزینی کل، سراغ آن که بفهمی نفهمی، دلال کارم بود. و رونویس حکم را گذاشتم و گفتم که چه طور شد و آمدم بیرون.
+
+دو روز بعد رفتم سراغش. معلوم شد که حدسم درست بوده است و رئیس فرهنگ گفته بوده: «من از این لیسانسههای پر افاده نمیخواهم که سیگار به دست توی هر اتاقی سر میکنند.»
+
+و یارو برایش گفته بود که اصلاً وابدا..! فلانی همچین و همچون است و مثقالی هفت صنار با دیگران فرق دارد و این هندوانهها و خیال من راحت باشد و پنجشنبه یک هفتهی دیگر خودم بروم پهلوی او... و این کار را کردم. این بار رئیس فرهنگ جلوی پایم بلند شد که: «ای آقا... چرا اول نفرمودید؟!...» و از کارمندهایش گله کرد و به قول خودش، مرا «در جریان موقعیت محل» گذاشت و بعد با ماشین خودش مرا به مدرسه رساند و گفت زنگ را زودتر از موعد زدند و در حضور معلمها و ناظم، نطق غرایی در خصائل مدیر جدید – که من باشم – کرد و بعد هم مرا گذاشت و رفت با یک مدرسهی شش کلاسهی «نوبنیاد» و یک ناظم و هفت تا معلم و دویست و سی و پنج تا شاگرد. دیگر حسابی مدیر مدرسه شده بودم!
+
+ناظم، جوان رشیدی بود که بلند حرف میزد و به راحتی امر و نهی میکرد و بیا و برویی داشت و با شاگردهای درشت، روی هم ریخته بود که خودشان ترتیب کارها را میدادند و پیدا بود که به سر خر احتیاجی ندارد و بیمدیر هم میتواند گلیم مدرسه را از آب بکشد. معلم کلاس چهار خیلی گنده بود. دو تای یک آدم حسابی. توی دفتر، اولین چیزی که به چشم میآمد. از آنهایی که اگر توی کوچه ببینی، خیال میکنی مدیر کل است. لفظ قلم حرف میزد و شاید به همین دلیل بود که وقتی رئیس فرهنگ رفت و تشریفات را با خودش برد، از طرف همکارانش تبریک ورود گفت و اشاره کرد به اینکه «انشاءالله زیر سایهی سرکار، سال دیگر کلاسهای دبیرستان را هم خواهیم داشت.» پیدا بود که این هیکل کمکم دارد از سر دبستان زیادی میکند! وقتی حرف میزد همهاش درین فکر بودم که با نان آقا معلمی چه طور میشد چنین هیکلی به هم زد و چنین سر و تیپی داشت؟ و راستش تصمیم گرفتم که از فردا صبح به صبح ریشم را بتراشم و یخهام تمیز باشد و اتوی شلوارم تیز.
+
+معلم کلاس اول باریکهای بود، سیاه سوخته. با ته ریشی و سر ماشین کردهای و یخهی بسته. بیکراوات. شبیه میرزابنویسهای دم پستخانه. حتی نوکر باب مینمود. و من آن روز نتوانستم بفهمم وقتی حرف میزند کجا را نگاه میکند. با هر جیغ کوتاهی که میزد هرهر میخندید. با این قضیه نمیشد کاری کرد. معلم کلاس سه، یک جوان ترکهای بود؛ بلند و با صورت استخوانی و ریش از ته تراشیده و یخهی بلند آهاردار. مثل فرفره میجنبید. چشمهایش برق عجیبی میزد که فقط از هوش نبود، چیزی از ناسلامتی در برق چشمهایش بود که مرا واداشت از ناظم بپرسم مبادا مسلول باشد. البته مسلول نبود، تنها بود و در دانشگاه درس میخواند. کلاسهای پنجم و ششم را دو نفر با هم اداره میکردند. یکی فارسی و شرعیات و تاریخ، جغرافی و کاردستی و این جور سرگرمیها را میگفت، که جوانکی بود بریانتین زده، با شلوار پاچه تنگ و پوشت و کراوات زرد و پهنی که نعش یک لنگر بزرگ آن را روی سینهاش نگه داشته بود و دائماً دستش حمایل موهای سرش بود و دم به دم توی شیشهها نگاه میکرد. و آن دیگری که حساب و مرابحه و چیزهای دیگر میگفت، جوانی بود موقر و سنگین مازندرانی به نظر میآمد و به خودش اطمینان داشت. غیر از اینها، یک معلم ورزش هم داشتیم که دو هفته بعد دیدمش و اصفهانی بود و از آن قاچاقها.
+
+رئیس فرهنگ که رفت، گرم و نرم از همهشان حال و احوال پرسیدم. بعد به همه سیگار تعارف کردم. سراپا همکاری و همدردی بود. از کار و بار هر کدامشان پرسیدم. فقط همان معلم کلاس سه، دانشگاه میرفت. آن که لنگر به سینه انداخته بود، شبها انگلیسی میخواند که برود آمریکا. چای و بساطی در کار نبود و ربع ساعتهای تفریح، فقط توی دفتر جمع میشدند و دوباره از نو. و این نمیشد. باید همهی سنن را رعایت کرد. دست کردم و یک پنج تومانی روی میز گذاشتم و قرار شد قبل و منقلی تهیه کنند و خودشان چای را راه بیندازند.
+
+بعد از زنگ قرار شد من سر صف نطقی بکنم. ناظم قضیه را در دو سه کلمه برای بچهها گفت که من رسیدم و همه دست زدند. چیزی نداشتم برایشان بگویم. فقط یادم است اشارهای به این کردم که مدیر خیلی دلش میخواست یکی از شما را به جای فرزند داشته باشد و حالا نمیداند با این همه فرزند چه بکند؟! که بیصدا خندیدند و در میان صفهای عقب یکی پکی زد به خنده. واهمه برم داشت که «نه بابا. کار سادهای هم نیست!» قبلاً فکر کرده بودم که میروم و فارغ از دردسر ادارهی کلاس، در اتاق را روی خودم میبندم و کار خودم را میکنم. اما حالا میدیدم به این سادگیها هم نیست. اگر فردا یکیشان زد سر اون یکی را شکست، اگر یکی زیر ماشین رفت؛ اگر یکی از ایوان افتاد؛ چه خاکی به سرم خواهم ریخت؟
+
+حالا من مانده بودم و ناظم که چیزی از لای در آهسته خزید تو. کسی بود؛ فراش مدرسه با قیافهای دهاتی و ریش نتراشیده و قدی کوتاه و گشاد گشاد راه میرفت و دستهایش را دور از بدن نگه میداشت. آمد و همان کنار در ایستاد. صاف توی چشمم نگاه میکرد. حال او را هم پرسیدم. هر چه بود او هم میتوانست یک گوشهی این بار را بگیرد. در یک دقیقه همهی درد دلهایش را کرد و التماس دعاهایش که تمام شد، فرستادمش برایم چای درست کند و بیاورد. بعد از آن من به ناظم پرداختم. سال پیش، از دانشسرای مقدماتی در آمده بود. یک سال گرمسار و کرج کار کرده بود و امسال آمده بود اینجا. پدرش دو تا زن داشته. از اولی دو تا پسر که هر دو تا چاقوکش از آب در آمدهاند و از دومی فقط او مانده بود که درسخوان شده و سرشناس و نان مادرش را میدهد که مریض است و از پدر سالهاست که خبری نیست و... یک اتاق گرفتهاند به پنجاه تومان و صد و پنجاه تومان حقوق به جایی نمیرسد و تازه زور که بزند سه سال دیگر میتواند از حق فنی نظامت مدرسه استفاده کند
+
+... بعد بلند شدیم که به کلاسها سرکشی کنیم. بعد با ناظم به تک تک کلاسها سر زدیم در این میان من به یاد دوران دبستان خودم افتادم. در کلاس ششم را باز کردیم «... ت بی پدرو مادر» جوانک بریانتین زده خورد توی صورتمان. یکی از بچهها صورتش مثل چغندر قرمز بود. لابد بزک فحش هنوز باقی بود. قرائت فارسی داشتند. معلم دستهایش توی جیبش بود و سینهاش را پیش داده بود و زبان به شکایت باز کرد:
+
+- آقای مدیر! اصلاً دوستی سرشون نمیشه. تو سَری میخوان. ملاحظه کنید بنده با چه صمیمیتی...
+
+حرفش را در تشدید «ایت» بریدم که:
+
+- صحیح میفرمایید. این بار به من ببخشید.
+
+و از در آمدیم بیرون. بعد از آن به اطاقی که در آینده مال من بود سر زدیم. بهتر از این نمیشد. بی سر و صدا، آفتابرو، دور افتاده.
+
+وسط حیاط، یک حوض بزرگ بود و کمعمق. تنها قسمت ساختمان بود که رعایت حال بچههای قد و نیم قد در آن شده بود. دور حیاط دیوار بلندی بود درست مثل دیوار چین. سد مرتفعی در مقابل فرار احتمالی فرهنگ و ته حیاط مستراح و اتاق فراش بغلش و انبار زغال و بعد هم یک کلاس. به مستراح هم سر کشیدیم. همه بی در و سقف و تیغهای میان آنها. نگاهی به ناظم کردم که پا به پایم میآمد. گفت:
+
+- دردسر عجیبی شده آقا. تا حالا صد تا کاغذ به ادارفردا صبح رفتم مدرسه. بچهها با صفهاشان به طرف کلاسها میرفتند و ناظم چوب به دست توی ایوان ایستاده بود و توی دفتر دو تا از معلمها بودند. معلوم شد کار هر روزهشان است. ناظم را هم فرستادم سر یک کلاس دیگر و خودم آمدم دم در مدرسه به قدم زدن؛ فکر کردم از هر طرف که بیایند مرا این ته، دم در مدرسه خواهند دید و تمام طول راه در این خجالت خواهند ماند و دیگر دیر نخواهند آمد. یک سیاهی از ته جادهی جنوبی پیداشد. جوانک بریانتین زده بود. مسلماً او هم مرا میدید، ولی آهستهتر از آن میآمد که یک معلم تأخیر کرده جلوی مدیرش میآمد. جلوتر که آمد حتی شنیدم که سوت میزد. اما بیانصاف چنان سلانه سلانه میآمد که دیدم هیچ جای گذشت نیست. اصلاً محل سگ به من نمیگذاشت. داشتم از کوره در میرفتم که یک مرتبه احساس کردم تغییری در رفتار خود داد و تند کرد.
+
+به خیر گذشت و گرنه خدا عالم است چه اتفاقی میافتاد. سلام که کرد مثل این که میخواست چیزی بگوید که پیش دستی کردم:
+
+- بفرمایید آقا. بفرمایید، بچهها منتظرند.
+
+واقعاً به خیر گذشت. شاید اتوبوسش دیر کرده. شاید راهبندان بوده؛ جاده قرق بوده و باز یک گردنکلفتی از اقصای عالم میآمده که ازین سفرهی مرتضی علی بینصیب نماند. به هر صورت در دل بخشیدمش. چه خوب شد که بد و بیراهی نگفتی! که از دور علم افراشتهی هیکل معلم کلاس چهارم نمایان شد. از همان ته مرا دیده بود. تقریباً میدوید. تحمل این یکی را نداشتم. «بدکاری میکنی. اول بسمالله و مته به خشخاش!» رفتم و توی دفتر نشستم و خودم را به کاری مشغول کردم که هن هن کنان رسید. چنان عرق از پیشانیاش میریخت که راستی خجالت کشیدم. یک لیوان آب از کوه به دستش دادم و مسخشدهی خندهاش را با آب به خوردش دادم و بلند که شد برود، گفتم:
+
+- عوضش دو کیلو لاغر شدید.
+
+برگشت نگاهی کرد و خندهای و رفت. ناگهان ناظم از در وارد شد و از را ه نرسیده گفت:
+
+- دیدید آقا! این جوری میآند مدرسه. اون قرتی که عین خیالش هم نبود آقا! اما این یکی...
+
+از او پرسیدم:
+
+- انگار هنوز دو تا از کلاسها ولند؟
+
+- بله آقا. کلاس سه ورزش دارند. گفتم بنشینند دیکته بنویسند آقا. معلم حساب پنج و شش هم که نیومده آقا.
+
+در همین حین یکی از عکسهای بزرگ دخمههای هخامنشی را که به دیوار کوبیده بود پس زد و:
+
+- نگاه کنید آقا...
+
+روی گچ دیوار با مداد قرمز و نه چندان درشت، به عجله و ناشیانه علامت داس کشیده بودند. همچنین دنبال کرد:
+
+- از آثار دورهی اوناست آقا. کارشون همین چیزها بود. روزنومه بفروشند. تبلیغات کنند و داس چکش بکشند آقا. رئیسشون رو که گرفتند چه جونی کندم آقا تا حالیشون کنم که دست ور دارند آقا. و از روی میز پرید پایین.
+
+- گفتم مگه باز هم هستند؟
+
+- آره آقا، پس چی! یکی همین آقازاده که هنوز نیومده آقا. هر روز نیم ساعت تأخیر داره آقا. یکی هم مثل کلاس سه.
+
+- خوب چرا تا حالا پاکش نکردی؟
+
+- به! آخه آدم درد دلشو واسهی کی بگه؟ آخه آقا در میان تو روی آدم میگند جاسوس، مأمور! باهاش حرفم شده آقا. کتک و کتککاری!
+
+و بعد یک سخنرانی که چه طور مدرسه را خراب کردهاند و اعتماد اهل محله را چه طور از بین بردهاند که نه انجمنی، نه کمکی به بیبضاعتها؛ و از این حرف ها.
+
+بعد از سخنرانی آقای ناظم دستمالم را دادم که آن عکسها را پاک کند و بعد هم راه افتادم که بروم سراغ اتاق خودم. در اتاقم را که باز کردم، داشتم دماغم با بوی خاک نم کشیدهاش اخت میکرد که آخرین معلم هم آمد. آمدم توی ایوان و با صدای بلند، جوری که در تمام مدرسه بشنوند، ناظم را صدا زدم و گفتم با قلم قرمز برای آقا یک ساعت تأخیر بگذارند.هی ساختمان نوشتیم آقا. میگند نمیشه پول دولت رو تو ملک دیگرون خرج کرد.
+
+- گفتم راست میگند.
+
+دیگه کافی بود. آمدیم بیرون. همان توی حیاط تا نفسی تازه کنیم وضع مالی و بودجه و ازین حرفهای مدرسه را پرسیدم. هر اتاق ماهی پانزده ریال حق نظافت داشت. لوازمالتحریر و دفترها را هم ادارهی فرهنگ میداد. ماهی بیست و پنج تومان هم برای آب خوردن داشتند که هنوز وصول نشده بود. برای نصب هر بخاری سالی سه تومان. ماهی سی تومان هم تنخواهگردان مدرسه بود که مثل پول آب سوخت شده بود و حالا هم ماه دوم سال بود. اواخر آبان. حالیش کردم که حوصلهی این کارها را ندارم و غرضم را از مدیر شدن برایش خلاصه کردم و گفتم حاضرم همهی اختیارات را به او بدهم. «اصلاً انگار که هنوز مدیر نیامده.» مهر مدرسه هم پهلوی خودش باشد. البته او را هنوز نمیشناختم. شنیده بودم که مدیرها قبلاً ناظم خودشان را انتخاب میکنند، اما من نه کسی را سراغ داشتم و نه حوصلهاش را. حکم خودم را هم به زور گرفته بودم. سنگهامان را وا کندیم و به دفتر رفتیم و چایی را که فراش از بساط خانهاش درست کرده بود، خوردیم تا زنگ را زدند و باز هم زدند و من نگاهی به پروندههای شاگردها کردم که هر کدام عبارت بود از دو برگ کاغذ. از همین دو سه برگ کاغذ دانستم که اولیای بچهها اغلب زارع و باغبان و اویارند و قبل از اینکه زنگ آخر را بزنند و مدرسه تعطیل بشود بیرون آمدم. برای روز اول خیلی زیاد بود.
+
+فردا صبح رفتم مدرسه. بچهها با صفهاشان به طرف کلاسها میرفتند و ناظم چوب به دست توی ایوان ایستاده بود و توی دفتر دو تا از معلمها بودند. معلوم شد کار هر روزهشان است. ناظم را هم فرستادم سر یک کلاس دیگر و خودم آمدم دم در مدرسه به قدم زدن؛ فکر کردم از هر طرف که بیایند مرا این ته، دم در مدرسه خواهند دید و تمام طول راه در این خجالت خواهند ماند و دیگر دیر نخواهند آمد. یک سیاهی از ته جادهی جنوبی پیداشد. جوانک بریانتین زده بود. مسلماً او هم مرا میدید، ولی آهستهتر از آن میآمد که یک معلم تأخیر کرده جلوی مدیرش میآمد. جلوتر که آمد حتی شنیدم که سوت میزد. اما بیانصاف چنان سلانه سلانه میآمد که دیدم هیچ جای گذشت نیست. اصلاً محل سگ به من نمیگذاشت. داشتم از کوره در میرفتم که یک مرتبه احساس کردم تغییری در رفتار خود داد و تند کرد.
+
+به خیر گذشت و گرنه خدا عالم است چه اتفاقی میافتاد. سلام که کرد مثل این که میخواست چیزی بگوید که پیش دستی کردم:
+
+- بفرمایید آقا. بفرمایید، بچهها منتظرند.
+
+واقعاً به خیر گذشت. شاید اتوبوسش دیر کرده. شاید راهبندان بوده؛ جاده قرق بوده و باز یک گردنکلفتی از اقصای عالم میآمده که ازین سفرهی مرتضی علی بینصیب نماند. به هر صورت در دل بخشیدمش. چه خوب شد که بد و بیراهی نگفتی! که از دور علم افراشتهی هیکل معلم کلاس چهارم نمایان شد. از همان ته مرا دیده بود. تقریباً میدوید. تحمل این یکی را نداشتم. «بدکاری میکنی. اول بسمالله و مته به خشخاش!» رفتم و توی دفتر نشستم و خودم را به کاری مشغول کردم که هن هن کنان رسید. چنان عرق از پیشانیاش میریخت که راستی خجالت کشیدم. یک لیوان آب از کوه به دستش دادم و مسخشدهی خندهاش را با آب به خوردش دادم و بلند که شد برود، گفتم:
+
+- عوضش دو کیلو لاغر شدید.
+
+برگشت نگاهی کرد و خندهای و رفت. ناگهان ناظم از در وارد شد و از را ه نرسیده گفت:
+
+- دیدید آقا! این جوری میآند مدرسه. اون قرتی که عین خیالش هم نبود آقا! اما این یکی...
+
+از او پرسیدم:
+
+- انگار هنوز دو تا از کلاسها ولند؟
+
+- بله آقا. کلاس سه ورزش دارند. گفتم بنشینند دیکته بنویسند آقا. معلم حساب پنج و شش هم که نیومده آقا.
+
+در همین حین یکی از عکسهای بزرگ دخمههای هخامنشی را که به دیوار کوبیده بود پس زد و:
+
+- نگاه کنید آقا...
+
+روی گچ دیوار با مداد قرمز و نه چندان درشت، به عجله و ناشیانه علامت داس کشیده بودند. همچنین دنبال کرد:
+
+- از آثار دورهی اوناست آقا. کارشون همین چیزها بود. روزنومه بفروشند. تبلیغات کنند و داس چکش بکشند آقا. رئیسشون رو که گرفتند چه جونی کندم آقا تا حالیشون کنم که دست ور دارند آقا. و از روی میز پرید پایین.
+
+- گفتم مگه باز هم هستند؟
+
+- آره آقا، پس چی! یکی همین آقازاده که هنوز نیومده آقا. هر روز نیم ساعت تأخیر داره آقا. یکی هم مثل کلاس سه.
+
+- خوب چرا تا حالا پاکش نکردی؟
+
+- به! آخه آدم درد دلشو واسهی کی بگه؟ آخه آقا در میان تو روی آدم میگند جاسوس، مأمور! باهاش حرفم شده آقا. کتک و کتککاری!
+
+و بعد یک سخنرانی که چه طور مدرسه را خراب کردهاند و اعتماد اهل محله را چه طور از بین بردهاند که نه انجمنی، نه کمکی به بیبضاعتها؛ و از این حرف ها.
+
+بعد از سخنرانی آقای ناظم دستمالم را دادم که آن عکسها را پاک کند و بعد هم راه افتادم که بروم سراغ اتاق خودم. در اتاقم را که باز کردم، داشتم دماغم با بوی خاک نم کشیدهاش اخت میکرد که آخرین معلم هم آمد. آمدم توی ایوان و با صدای بلند، جوری که در تمام مدرسه بشنوند، ناظم را صدا زدم و گفتم با قلم قرمز برای آقا یک ساعت تأخیر بگذارند.
+
+روز سوم باز اول وقت مدرسه بودم. هنوز از پشت دیوار نپیچیده بودم که صدای سوز و بریز بچهها به پیشبازم آمد. تند کردم. پنج تا از بچهها توی ایوان به خودشان میپیچیدند و ناظم ترکهای به دست داشت و به نوبت به کف دستشان میزد. بچهها التماس میکردند؛ گریه میکردند؛ اما دستشان را هم دراز میکردند. نزدیک بود داد بزنم یا با لگد بزنم و ناظم را پرت کنم آن طرف. پشتش به من بود و من را نمیدید. ناگهان زمزمهای توی صفها افتاد که یک مرتبه مرا به صرافت انداخت که در مقام مدیریت مدرسه، به سختی میشود ناظم را کتک زد. این بود که خشمم را فرو خوردم و آرام از پلهها رفتم بالا. ناظم، تازه متوجه من شده بود در همین حین دخالتم را کردم و خواهش کردم این بار همهشان را به من ببخشند.
+
+نمیدانم چه کار خطایی از آنها سر زده بود که ناظم را تا این حد عصبانی کرده بود. بچهها سکسکهکنان رفتند توی صفها و بعد زنگ را زدند و صفها رفتند به کلاسها و دنبالشان هم معلمها که همه سر وقت حاضر بودند. نگاهی به ناظم انداختم که تازه حالش سر جا آمده بود و گفتم در آن حالی که داشت، ممکن بود گردن یک کدامشان را بشکند. که مرتبه براق شد:
+
+- اگه یک روز جلوشونو نگیرید سوارتون میشند آقا. نمیدونید چه قاطرهای چموشی شدهاند آقا.
+
+مثل بچه مدرسهایها آقا آقا میکرد. موضوع را برگرداندم و احوال مادرش را پرسیدم. خنده، صورتش را از هم باز کرد و صدا زد فراش برایش آب بیاورد. یادم هست آن روز نیم ساعتی برای آقای ناظم صحبت کردم. پیرانه. و او جوان بود و زود میشد رامش کرد. بعد ازش خواستم که ترکهها را بشکند و آن وقت من رفتم سراغ اتاق خودم.
+
+در همان هفتهی اول به کارها وارد شدم. فردای زمستان و نه تا بخاری زغال سنگی و روزی چهار بار آب آوردن و آب و جاروی اتاقها با یک فراش جور در نمیآید. یک فراش دیگر از اداره ی فرهنگ خواستم که هر روز منتظر ورودش بودیم. بعد از ظهرها را نمیرفتم. روزهای اول با دست و دل لرزان، ولی سه چهار روزه جرأت پیدا کردم. احساس میکردم که مدرسه زیاد هم محض خاطر من نمیگردد. کلاس اول هم یکسره بود و به خاطر بچههای جغله دلهرهای نداشتم. در بیابانهای اطراف مدرسه هم ماشینی آمد و رفت نداشت و گرچه پست و بلند بود اما به هر صورت از حیاط مدرسه که بزرگتر بود. معلم ها هم، هر بعد از ظهری دو تاشان به نوبت میرفتند یک جوری باهم کنار آمده بودند. و ترسی هم از این نبود که بچهها از علم و فرهنگ ثقل سرد بکنند. یک روز هم بازرس آمد و نیم ساعتی پیزر لای پالان هم گذاشتیم و چای و احترامات متقابل! و در دفتر بازرسی تصدیق کرد که مدرسه «با وجود عدم وسایل» بسیار خوب اداره میشود.
+
+بچهها مدام در مدرسه زمین میخوردند، بازی میکردند، زمین میخوردند. مثل اینکه تاتوله خورده بودند. سادهترین شکل بازیهایشان در ربع ساعتهای تفریح، دعوا بود. فکر میکردم علت این همه زمین خوردن شاید این باشد که بیشترشان کفش حسابی ندارند. آنها هم که داشتند، بچهننه بودند و بلد نبودند بدوند و حتی راه بروند. این بود که روزی دو سه بار، دست و پایی خراش بر میداشت. پروندهی برق و تلفن مدرسه را از بایگانی بسیار محقر مدرسه بیرون کشیده بودم و خوانده بودم. اگر یک خرده میدویدی تا دو سه سال دیگر هم برق مدرسه درست میشد و هم تلفنش. دوباره سری به اداره ساختمان زدم و موضوع را تازه کردم و به رفقایی که دورادور در ادارهی برق و تلفن داشتم، یکی دو بار رو انداختم که اول خیال میکردند کار خودم را میخواهم به اسم مدرسه راه بیندازم و ناچار رها کردم. این قدر بود که ادای وظیفهای میکرد. مدرسه آب نداشت. نه آب خوراکی و نه آب جاری. با هرزاب بهاره، آب انبار زیر حوض را میانباشتند که تلمبهای سرش بود و حوض را با همان پر میکردند و خود بچهها. اما برای آب خوردن دو تا منبع صد لیتری داشتیم از آهن سفید که مثل امامزادهای یا سقاخانهای دو قلو، روی چهار پایه کنار حیاط بود و روزی دو بار پر و خالی میشد. این آب را از همان باغی میآوردیم که ردیف کاجهایش روی آسمان، لکهی دراز سیاه انداخته بود. البته فراش میآورد. با یک سطل بزرگ و یک آبپاش که سوراخ بود و تا به مدرسه میرسید، نصف شده بود. هر دو را از جیب خودم دادم تعمیر کردند.
+
+یک روز هم مالک مدرسه آمد. پیرمردی موقر و سنگین که خیال میکرد برای سرکشی به خانهی مستأجرنشینش آمده. از در وارد نشده فریادش بلند شد و فحش را کشید به فراش و به فرهنگ که چرا بچهها دیوار مدرسه را با زغال سیاه کردهاند واز همین توپ و تشرش شناختمش. کلی با او صحبت کردیم البته او دو برابر سن من را داشت. برایش چای هم آوردیم و با معلمها آشنا شد و قولها داد و رفت. کنهای بود. درست یک پیرمرد. یک ساعت و نیم درست نشست. ماهی یک بار هم این برنامه را داشتند که بایست پیهاش را به تن میمالیدم.
+
+اما معلمها. هر کدام یک ابلاغ بیست و چهار ساعته در دست داشتند، ولی در برنامه به هر کدامشان بیست ساعت درس بیشتر نرسیده بود. کم کم قرار شد که یک معلم از فرهنگ بخواهیم و به هر کدامشان هجده ساعت درس بدهیم، به شرط آنکه هیچ بعد از ظهری مدرسه تعطیل نباشد. حتی آن که دانشگاه میرفت میتوانست با هفتهای هجده ساعت درس بسازد. و دشوارترین کار همین بود که با کدخدامنشی حل شد و من یک معلم دیگر از فرهنگ خواستم.
+
+اواخر هفتهی دوم، فراش جدید آمد. مرد پنجاه سالهای باریک و زبر و زرنگ که شبکلاه میگذاشت و لباس آبی میپوشید و تسبیح میگرداند و از هر کاری سر رشته داشت. آب خوردن را نوبتی میآوردند. مدرسه تر و تمیز شد و رونقی گرفت. فراش جدید سرش توی حساب بود. هر دو مستخدم با هم تمام بخاریها را راه انداختند و یک کارگر هم برای کمک به آنها آمد. فراش قدیمی را چهار روز پشت سر هم، سر ظهر میفرستادیم ادارهی فرهنگ و هر آن منتظر زغال بودیم. هنوز یک هفته از آمدن فراش جدید نگذشته بود که صدای همهی معلمها در آمده بود. نه به هیچ کدامشان سلام میکرد و نه به دنبال خرده فرمایشهایشان میرفت. درست است که به من سلام میکرد، اما معلمها هم، لابد هر کدام در حدود من صاحب فضایل و عنوان و معلومات بودند که از یک فراش مدرسه توقع سلام داشته باشند. اما انگار نه انگار.
+
+بدتر از همه این که سر خر معلمها بود. من که از همان اول، خرجم را سوا کرده بودم و آنها را آزاد گذاشته بودم که در مواقع بیکاری در دفتر را روی خودشان ببندند و هر چه میخواهند بگویند و هر کاری میخواهند بکنند. اما او در فاصلهی ساعات درس، همچه که معلمها میآمدند، میآمد توی دفتر و همین طوری گوشهی اتاق میایستاد و معلمها کلافه میشدند. نه میتوانستند شلکلکهای معلمیشان را در حضور او کنار بگذارند و نه جرأت میکردند به او چیزی بگویند. بدزبان بود و از عهدهی همهشان بر میآمد. یکی دوبار دنبال نخود سیاه فرستاده بودندش. اما زرنگ بود و فوری کار را انجام میداد و بر میگشت. حسابی موی دماغ شده بود. ده سال تجربه این حداقل را به من آموخته بود که اگر معلمها در ربع ساعتهای تفریح نتوانند بخندند، سر کلاس، بچههای مردم را کتک خواهند زد. این بود که دخالت کردم. یک روز فراش جدید را صدا زدم. اول حال و احوالپرسی و بعد چند سال سابقه دارد و چند تا بچه و چه قدر میگیرد... که قضیه حل شد. سی صد و خردهای حقوق میگرفت. با بیست و پنج سال سابقه. کار از همین جا خراب بود. پیدا بود که معلمها حق دارند او را غریبه بدانند. نه دیپلمی، نه کاغذپارهای، هر چه باشد یک فراش که بیشتر نبود! و تازه قلدر هم بود و حق هم داشت. اول به اشاره و کنایه و بعد با صراحت بهش فهماندم که گر چه معلم جماعت اجر دنیایی ندارد، اما از او که آدم متدین و فهمیدهای است بعید است و از این حرفها... که یک مرتبه پرید توی حرفم که:
+
+- ای آقا! چه میفرمایید؟ شما نه خودتون این کارهاید و نه اینارو میشناسید. امروز میخواند سیگار براشون بخرم، فردا میفرستنم سراغ عرق. من اینها رو میشناسم.
+
+راست میگفت. زودتر از همه، او دندانهای مرا شمرده بود. فهمیده بود که در مدرسه هیچکارهام. میخواستم کوتاه بیایم، ولی مدیر مدرسه بودن و در مقابل یک فراش پررو ساکت ماندن!... که خر خر کامیون زغال به دادم رسید. ترمز که کرد و صدا خوابید گفتم:
+
+- این حرفها قباحت داره. معلم جماعت کجا پولش به عرق میرسه؟ حالا بدو زغال آوردهاند.
+
+و همین طور که داشت بیرون میرفت، افزودم:
+
+- دو روز دیگه که محتاجت شدند و ازت قرض خواستند با هم رفیق میشید.
+
+و آمدم توی ایوان. در بزرگ آهنی مدرسه را باز کرده بودند و کامیون آمده بود تو و داشتند بارش را جلوی انبار ته حیاط خالی میکردند و راننده، کاغذی به دست ناظم داد که نگاهی به آن انداخت و مرا نشان داد که در ایوان بالا ایستاده بودم و فرستادش بالا. کاغذش را با سلام به دستم داد. بیجک زغال بود. رسید رسمی ادارهی فرهنگ بود در سه نسخه و روی آن ورقهی ماشین شدهی «باسکول» که میگفت کامیون و محتویاتش جمعاً دوازده خروار است. اما رسیدهای رسمی اداری فرهنگ ساکت بودند. جای مقدار زغالی که تحویل مدرسه داده شده بود، در هر سه نسخه خالی بود. پیدا بود که تحویل گیرنده باید پرشان کند. همین کار را کردم. اوراق را بردم توی اتاق و با خودنویسم عدد را روی هر سه ورق نوشتم و امضا کردم و به دست راننده دادم که راه افتاد و از همان بالا به ناظم گفتم:
+
+- اگر مهر هم بایست زد، خودت بزن بابا.
+
+و رفتم سراغ کارم که ناگهان در باز شد و ناظم آمد تو؛ بیجک زغال دستش بود و:
+
+- مگه نفهمیدین آقا؟ مخصوصاً جاش رو خالی گذاشته بودند آقا...
+
+نفهمیده بودم. اما اگر هم فهمیده بودم، فرقی نمیکرد و به هر صورت از چنین کودنی نا به هنگام از جا در رفتم و به شدت گفتم:
+
+- خوب؟
+
+- هیچ چی آقا.... رسمشون همینه آقا. اگه باهاشون کنار نیایید کارمونو لنگ میگذارند آقا...
+
+که از جا در رفتم. به چنین صراحتی مرا که مدیر مدرسه بودم در معامله شرکت میداد. و فریاد زدم:
+
+- عجب! حالا سرکار برای من تکلیف هم معین میکنید؟... خاک بر سر این فرهنگ با مدیرش که من باشم! برو ورقه رو بده دستشون، گورشون رو گم کنند. پدر سوختهها...
+
+چنان فریاد زده بودم که هیچ کس در مدرسه انتظار نداشت. مدیر سر به زیر و پا به راهی بودم که از همه خواهش میکردم و حالا ناظم مدرسه، داشت به من یاد میداد که به جای نه خروار زغال مثلا هجده خروار تحویل بگیرم و بعد با ادارهی فرهنگ کنار بیایم. هی هی!.... تا ظهر هیچ کاری نتوانستم بکنم، جز اینکه چند بار متن استعفانامهام را بنویسم و پاره کنم... قدم اول را این جور جلوی پای آدم میگذارند.
+
+بارندگی که شروع شد دستور دادم بخاریها را از هفت صبح بسوزانند. بچهها همیشه زود میآمدند. حتی روزهای بارانی. مثل اینکه اول آفتاب از خانه بیرونشان میکنند. یا ناهارنخورده. خیلی سعی کردم یک روز زودتر از بچهها مدرسه باشم. اما عاقبت نشد که مدرسه را خالی از نفسِ به علمآلودهی بچهها استنشاق کنم. از راه که میرسیدند دور بخاری جمع میشدند و گیوههاشان را خشک میکردند. و خیلی زود فهمیدم که ظهر در مدرسه ماندن هم مسأله کفش بود. هر که داشت نمیماند.این قاعده در مورد معلمها هم صدق میکرد اقلاً یک پول واکس جلو بودند. وقتی که باران میبارید تمام کوهپایه و بدتر از آن تمام حیاط مدرسه گل میشد. بازی و دویدن متوقف شده بود. مدرسه سوت و کور بود. این جا هم مسأله کفش بود. چشم اغلبشان هم قرمز بود. پیدا بود باز آن روز صبح یک فصل گریه کردهاند و در خانهشان علم صراطی بوده است.
+
+مدرسه داشت تخته میشد. عدهی غایبهای صبح ده برابر شده بود و ساعت اول هیچ معلمی نمیتوانست درس بدهد. دستهای ورمکرده و سرمازده کار نمیکرد. حتی معلم کلاس اولمان هم میدانست که فرهنگ و معلومات مدارس ما صرفاً تابع تمرین است. مشق و تمرین. ده بار بیست بار. دست یخکرده بیل و رنده را هم نمیتواند به کار بگیرد که خیلی هم زمختاند و دست پر کن. این بود که به فکر افتادیم. فراش جدید واردتر از همهی ما بود. یک روز در اتاق دفتر، شورامانندی داشتیم که البته او هم بود. خودش را کمکم تحمیل کرده بود. گفت حاضر است یکی از دُمکلفتهای همسایهی مدرسه را وادارد که شن برایمان بفرستد به شرط آن که ما هم برویم و از انجمن محلی برای بچهها کفش و لباس بخواهیم. قرار شد خودش قضیه را دنبال کند که هفتهی آینده جلسهشان کجاست و حتی بخواهد که دعوتمانندی از ما بکنند. دو روز بعد سه تا کامیون شن آمد. دوتایش را توی حیاط مدرسه، خالی کردیم و سومی را دم در مدرسه، و خود بچهها نیم ساعته پهنش کردند. با پا و بیل و هر چه که به دست میرسید.
+
+عصر همان روز ما را به انجمن دعوت کردند. خود من و ناظم باید میرفتیم. معلم کلاس چهارم را هم با خودمان بردیم. خانهای که محل جلسهی آن شب انجمن بود، درست مثل مدرسه، دور افتاده و تنها بود. قالیها و کنارهها را به فرهنگ میآلودیم و میرفتیم. مثل اینکه سه تا سه تا روی هم انداخته بودند. اولی که کثیف شد دومی. به بالا که رسیدیم یک حاجی آقا در حال نماز خواندن بود. و صاحبخانه با لهجهی غلیظ یزدی به استقبالمان آمد. همراهانم را معرفی کردم و لابد خودش فهمید مدیر کیست. برای ما چای آوردند. سیگارم را چاق کردم و با صاحبخانه از قالیهایش حرف زدیم. ناظم به بچههایی میماند که در مجلس بزرگترها خوابشان میگیرد و دلشان هم نمیخواست دست به سر شوند. سر اعضای انجمن باز شده بود. حاجی آقا صندوقدار بود. من و ناظم عین دو طفلان مسلم بودیم و معلم کلاس چهارم عین خولی وسطمان نشسته. اغلب اعضای انجمن به زبان محلی صحبت میکردند و رفتار ناشی داشتند. حتی یک کدامشان نمیدانستند که دست و پاهای خود را چه جور ضبط و ربط کنند. بلند بلند حرف میزدند. درست مثل اینکه وزارتخانهی دواب سه تا حیوان تازه برای باغ وحش محلهشان وارد کرده. جلسه که رسمی شد، صاحبخانه معرفیمان کرد و شروع کردند. مدام از خودشان صحبت میکردند از اینکه دزد دیشب فلان جا را گرفته و باید درخواست پاسبان شبانه کنیم و...
+
+همین طور یک ساعت حرف زدند و به مهام امور رسیدگی کردند و من و معلم کلاس چهارم سیگار کشیدیم. انگار نه انگار که ما هم بودیم. نوکرشان که آمد استکانها را جمع کند، چیزی روی جلد اشنو نوشتم و برای صاحبخانه فرستادم که یک مرتبه به صرافت ما افتاد و اجازه خواست و:
+
+- آقایان عرضی دارند. بهتر است کارهای خودمان را بگذاریم برای بعد.
+
+مثلاً میخواست بفهماند که نباید همهی حرفها را در حضور ما زده باشند. و اجازه دادند معلم کلاس چهار شروع کرد به نطق و او هم شروع کرد که هر چه باشد ما زیر سایهی آقایانیم و خوشآیند نیست که بچههایی باشند که نه لباس داشته باشند و نه کفش درست و حسابی و از این حرفها و مدام حرف میزد. ناظم هم از چُرت در آمد چیزهایی را که از حفظ کرده بود گفت و التماس دعا و کار را خراب کرد.تشری به ناظم زدم که گدابازی را بگذارد کنار و حالیشان کردم که صحبت از تقاضا نیست و گدایی. بلکه مدرسه دور افتاده است و مستراح بی در و پیکر و از این اباطیل... چه خوب شد که عصبانی نشدم. و قرار شد که پنج نفرشان فردا عصر بیایند که مدرسه را وارسی کنند و تشکر و اظهار خوشحالی و در آمدیم.
+
+در تاریکی بیابان هفت تا سواری پشت در خانه ردیف بودند و رانندهها توی یکی از آنها جمع شده بودند و اسرار اربابهاشان را به هم میگفتند. در این حین من مدام به خودم میگفتم من چرا رفتم؟ به من چه؟ مگر من در بی کفش و کلاهیشان مقصر بودم؟ میبینی احمق؟ مدیر مدرسه هم که باشی باید شخصیت و غرورت را لای زرورق بپیچی و طاق کلاهت بگذاری که اقلاً نپوسد. حتی اگر بخواهی یک معلم کوفتی باشی، نه چرا دور میزنی؟ حتی اگر یک فراش ماهی نود تومانی باشی، باید تا خرخره توی لجن فرو بروی.در همین حین که من در فکر بودم ناظم گفت:
+
+- دیدید آقا چه طور باهامون رفتار کردند؟ با یکی از قالیهاشون آقا تمام مدرسه رو میخرید.
+
+گفتم:
+
+- تا سر و کارت با الف.ب است بهپا قیاس نکنی. خودخوری میآره.
+
+و معلم کلاس چهار گفت:
+
+- اگه فحشمون هم میدادند من باز هم راضی بودم، باید واقعبین بود. خدا کنه پشیمون نشند.
+
+بعد هم مدتی درد دل کردیم و تا اتوبوس برسد و سوار بشیم، معلوم شد که معلم کلاس چهار با زنش متارکه کرده و مادر ناظم را سرطانی تشخیص دادند. و بعد هم شب بخیر...
+
+دو روز تمام مدرسه نرفتم. خجالت میکشیدم توی صورت یک کدامشان نگاه کنم. و در همین دو روز حاجی آقا با دو نفر آمده بودند، مدرسه را وارسی و صورتبرداری و ناظم میگفت که حتی بچههایی هم که کفش و کلاهی داشتند پاره و پوره آمده بودند. و برای بچهها کفش و لباس خریدند. روزهای بعد احساس کردم زنهایی که سر راهم لب جوی آب ظرف میشستند، سلام میکنند و یک بار هم دعای خیر یکیشان را از عقب سر شنیدم.اما چنان از خودم بدم آمده بود که رغبتم نمیشد به کفش و لباسهاشان نگاه کنم. قربان همان گیوههای پاره! بله، نان گدایی فرهنگ را نو نوار کرده بود.
+
+تازه از دردسرهای اول کار مدرسه فارغ شده بودم که شنیدم که یک روز صبح، یکی از اولیای اطفال آمد. بعد از سلام و احوالپرسی دست کرد توی جیبش و شش تا عکس در آورد، گذاشت روی میزم. شش تا عکس زن . و هر کدام به یک حالت. یعنی چه؟ نگاه تندی به او کردم. آدم مرتبی بود. اداری مانند. کسر شأن خودم میدانستم که این گوشهی از زندگی را طبق دستور عکاسباشی فلان خانهی بندری ببینم. اما حالا یک مرد اتو کشیدهی مرتب آمده بود و شش تا از همین عکسها را روی میزم پهن کرده بود و به انتظار آن که وقاحت عکسها چشمهایم را پر کند داشت سیگار چاق میکرد.
+
+حسابی غافلگیر شده بودم... حتماً تا هر شش تای عکسها را ببینم، بیش از یک دقیقه طول کشید. همه از یک نفر بود. به این فکر گریختم که الان هزار ها یا میلیون ها نسخهی آن، توی جیب چه جور آدمهایی است و در کجاها و چه قدر خوب بود که همهی این آدمها را میشناختم یا میدیدم. بیش ازین نمیشد گریخت. یارو به تمام وزنه وقاحتش، جلوی رویم نشسته بود. سیگاری آتش زدم و چشم به او دوختم. کلافه بود و پیدا بود برای کتککاری هم آماده باشد. سرخ شده بود و داشت در دود سیگارش تکیهگاهی برای جسارتی که میخواست به خرج بدهد میجست. عکسها را با یک ورقه از اباطیلی که همان روز سیاه کرده بودم، پوشاندم و بعد با لحنی که دعوا را با آن شروع میکنند؛ پرسیدم:
+
+- خوب، غرض؟
+
+و صدایم توی اتاق پیچید. حرکتی از روی بیچارگی به خودش داد و همهی جسارتها را با دستش توی جیبش کرد و آرامتر از آن چیزی که با خودش تو آورده بود، گفت:
+
+- چه عرض کنم؟... از معلم کلاس پنج تون بپرسید.
+
+که راحت شدم و او شروع کرد به این که «این چه فرهنگی است؟ خراب بشود. پس بچههای مردم با چه اطمینانی به مدرسه بیایند؟
+
+و از این حرفها...
+
+خلاصه این آقا معلم کاردستی کلاس پنجم، این عکسها را داده به پسر آقا تا آنها را روی تخته سه لایی بچسباند و دورش را سمباده بکشد و بیاورد. به هر صورت معلم کلاس پنج بیگدار به آب زده. و حالا من چه بکنم؟ به او چه جوابی بدهم؟ بگویم معلم را اخراج میکنم؟ که نه میتوانم و نه لزومی دارد. او چه بکند؟ حتماً در این شهر کسی را ندارد که به این عکسها دلخوش کرده. ولی آخر چرا این جور؟ یعنی این قدر احمق است که حتی شاگردهایش را نمیشناسد؟... پاشدم ناظم را صدا بزنم که خودش آمده بود بالا، توی ایوان منتظر ایستاده بود. من آخرین کسی بودم که از هر اتفاقی در مدرسه خبردار میشدم. حضور این ولی طفل گیجم کرده بود که چنین عکسهایی را از توی جیب پسرش، و لابد به همین وقاحتی که آنها را روی میز من ریخت، در آورده بوده. وقتی فهمید هر دو در ماندهایم سوار بر اسب شد که اله میکنم و بله میکنم، در مدرسه را میبندم، و از این جفنگیات....
+
+حتماً نمیدانست که اگر در هر مدرسه بسته بشود، در یک اداره بسته شده است. اما من تا او بود نمیتوانستم فکرم را جمع کنم. میخواست پسرش را بخواهیم تا شهادت بدهد و چه جانی کندیم تا حالیش کنیم که پسرش هر چه خفت کشیده، بس است و وعدهها دادیم که معلمش را دم خورشید کباب کنیم و از نان خوردن بیندازیم. یعنی اول ناظم شروع کرد که از دست او دل پری داشت و من هم دنبالش را گرفتم. برای دک کردن او چارهای جز این نبود. و بعد رفت، ما دو نفری ماندیم با شش تا عکس زن . حواسم که جمع شد به ناظم سپردم صدایش را در نیاورد و یک هفتهی تمام مطلب را با عکسها، توی کشوی میزم قفل کردم و بعد پسرک را صدا زدم. نه عزیزدُردانه مینمود و نه هیچ جور دیگر. داد میزد که از خانوادهی عیالواری است. کمخونی و فقر. دیدم معلمش زیاد هم بد تشخیص نداده. یعنی زیاد بیگدار به آب نزده. گفتم:
+
+- خواهر برادر هم داری؟
+
+- آ... آ...آقا داریم آقا.
+
+- چند تا؟
+
+- آ... آقا چهار تا آقا.
+
+- عکسها رو خودت به بابات نشون دادی؟
+
+- نه به خدا آقا... به خدا قسم...
+
+- پس چه طور شد؟
+
+و دیدم از ترس دارد قالب تهی میکند. گرچه چوبهای ناظم شکسته بود، اما ترس او از من که مدیر باشم و از ناظم و از مدرسه و از تنبیه سالم مانده بود.
+
+- نترس بابا. کاریت نداریم. تقصیر آقا معلمه که عکسها رو داده... تو کار بدی نکردی بابا جان. فهمیدی؟ اما میخواهم ببینم چه طور شد که عکسها دست بابات افتاد.
+
+- آ.. آ... آخه آقا... آخه...
+
+میدانستم که باید کمکش کنم تا به حرف بیاید.
+
+گفتم:
+
+- میدونی بابا؟ عکسهام چیز بدی نبود. تو خودت فهمیدی چی بود؟
+
+- آخه آقا...نه آقا.... خواهرم آقا... خواهرم میگفت...
+
+- خواهرت؟ از تو کوچکتره؟
+
+- نه آقا. بزرگتره. میگفتش که آقا... میگفتش که آقا... هیچ چی سر عکسها دعوامون شد.
+
+دیگر تمام بود. عکسها را به خواهرش نشان داده بود که لای دفترچه پر بوده از عکس آرتیستها. به او پز داده بوده. اما حاضر نبوده، حتی یکی از آنها را به خواهرش بدهد. آدم مورد اعتماد معلم باشد و چنین خبطی بکند؟ و تازه جواب معلم را چه بدهد؟ ناچار خواهر او را لو داده بوده. بعد از او معلم را احضار کردم. علت احضار را میدانست. و داد میزد که چیزی ندارد بگوید. پس از یک هفته مهلت، هنوز از وقاحتی که من پیدا کرده بودم، تا از آدم خلع سلاحشدهای مثل او، دست بر ندارم، در تعجب بود. به او سیگار تعارف کردم و این قصه را برایش تعریف کردم که در اوایل تأسیس وزارت معارف، یک روز به وزیر خبر میدهند که فلان معلم با فلان بچه روابطی دارد. وزیر فوراً او را میخواهد و حال و احوال او را میپرسد و اینکه چرا تا به حال زن نگرفته و ناچار تقصیر گردن بیپولی میافتد و دستور که فلان قدر به او کمک کنند تا عروسی راه بیندازد و خود او هم دعوت بشود و قضیه به همین سادگی تمام میشود. و بعد گفتم که خیلی جوانها هستند که نمیتوانند زن بگیرند و وزرای فرهنگ هم این روزها گرفتار مصاحبههای روزنامهای و رادیویی هستند. اما در نجیبخانهها که باز است و ازین مزخرفات... و همدردی و نگذاشتم یک کلمه حرف بزند. بعد هم عکس را که توی پاکت گذاشته بودم، به دستش دادم و وقاحت را با این جمله به حد اعلا رساندم که:
+
+- اگر به تخته نچسبونید، ضررشون کمتره.
+
+تا حقوقم به لیست ادارهی فرهنگ برسه، سه ماه طول کشید. فرهنگیهای گداگشنه و خزانهی خالی و دستهای از پا درازتر! اما خوبیش این بود که در مدرسهی ما فراش جدیدمان پولدار بود و به همهشان قرض داد. کم کم بانک مدرسه شده بود. از سیصد و خردهای تومان که میگرفت، پنجاه تومان را هم خرج نمیکرد. نه سیگار میکشید و نه اهل سینما بود و نه برج دیگری داشت. از این گذشته، باغبان یکی از دمکلفتهای همان اطراف بود و باغی و دستگاهی و سور و ساتی و لابد آشپزخانهی مرتبی. خیلی زود معلمها فهمیدند که یک فراش پولدار خیلی بیشتر به درد میخورد تا یک مدیر بیبو و خاصیت.
+
+این از معلمها. حقوق مرا هم هنوز از مرکز میدادند. با حقوق ماه بعد هم اسم مرا هم به لیست اداره منتقل کردند. درین مدت خودم برای خودم ورقه انجام کار مینوشتم و امضا میکردم و میرفتم از مدرسهای که قبلاً در آن درس میدادم، حقوقم را میگرفتم. سر و صدای حقوق که بلند میشد معلمها مرتب میشدند و کلاس ماهی سه چهار روز کاملاً دایر بود. تا ورقهی انجام کار به دستشان بدهم. غیر از همان یک بار - در اوایل کار- که برای معلم حساب پنج و شش قرمز توی دفتر گذاشتیم، دیگر با مداد قرمز کاری نداشتیم و خیال همهشان راحت بود. وقتی برای گرفتن حقوقم به اداره رفتم، چنان شلوغی بود که به خودم گفتم کاش اصلاً حقوقم را منتقل نکرده بودم. نه میتوانستم سر صف بایستم و نه میتوانستم از حقوقم بگذرم. تازه مگر مواجببگیر دولت چیزی جز یک انبان گشادهی پای صندوق است؟..... و اگر هم میماندی با آن شلوغی باید تا دو بعداز ظهر سر پا بایستی. همهی جیرهخوارهای اداره بو برده بودند که مدیرم. و لابد آنقدر ساده لوح بودند که فکر کنند روزی گذارشان به مدرسهی ما بیفتد. دنبال سفتهها میگشتند، به حسابدار قبلی فحش میدادند، التماس میکردند که این ماه را ندیده بگیرید و همهی حق و حسابدان شده بودند و یکی که زودتر از نوبت پولش را میگرفت صدای همه در میآمد. در لیست مدرسه، بزرگترین رقم مال من بود. درست مثل بزرگترین گناه در نامهی عمل. دو برابر فراش جدیدمان حقوق میگرفتم. از دیدن رقمهای مردنی حقوق دیگران چنان خجالت کشیدم که انگار مال آنها را دزدیدهام. و تازه خلوت که شد و ده پانزده تا امضا که کردم، صندوقدار چشمش به من افتاد و با یک معذرت، شش صد تومان پول دزدی را گذاشت کف دستم... مرده شور!
+
+هنوز برف اول نباریده بود که یک روز عصر، معلم کلاس چهار رفت زیر ماشین. زیر یک سواری. مثل همهی عصرها من مدرسه نبودم. دم غروب بود که فراش قدیمی مدرسه دم در خونهمون، خبرش را آورد. که دویدم به طرف لباسم و تا حاضر بشوم، میشنیدم که دارد قضیه را برای زنم تعریف میکند. ماشین برای یکی از آمریکاییها بوده. باقیش را از خانه که در آمدیم برایم تعریف کرد. گویا یارو خودش پشت فرمون بوده و بعد هم هول شده و در رفته. بچهها خبر را به مدرسه برگرداندهاند و تا فراش و زنش برسند، جمعیت و پاسبانها سوارش کرده بودند و فرستاده بودهاند مریضخانه. به اتوبوس که رسیدم، دیدم لاک پشت است. فراش را مرخص کردم و پریدم توی تاکسی. اول رفتم سراغ پاسگاه جدید کلانتری. تعاریف تکه و پارهای از پرونده مطلع بود. اما پرونده تصریحی نداشت که راننده که بوده. اما هیچ کس نمیدانست عاقبت چه بلایی بر سر معلم کلاس چهار ما آمده است. کشیک پاسگاه همین قدر مطلع بود که درین جور موارد «طبق جریان اداری» اول میروند سرکلانتری، بعد دایرهی تصادفات و بعد بیمارستان. اگر آشنا در نمیآمدیم، کشیک پاسگاه مسلماً نمیگذاشت به پرونده نگاه چپ بکنم. احساس کردم میان اهل محل کمکم دارم سرشناس میشوم. و از این احساس خندهام گرفت.
+
+ساعت ۸ دم در بیمارستان بودم، اگر سالم هم بود حتماً یه چیزیش شده بود. همان طور که من یه چیزیم میشد. روی در بیمارستان نوشته شده بود: «از ساعت ۷ به بعد ورود ممنوع». در زدم. از پشت در کسی همین آیه را صادر کرد. دیدم فایده ندارد و باید از یک چیزی کمک بگیرم. از قدرتی، از مقامی، از هیکلی، از یک چیزی. صدایم را کلفت کردم و گفتم:« من...» میخواستم بگویم من مدیر مدرسهام. ولی فوراً پشیمان شدم. یارو لابد میگفت مدیر مدرسه کدام سگی است؟ این بود با کمی مکث و طمطراق فراوان جملهام را این طور تمام کردم:
+
+- ...بازرس وزارت فرهنگم.
+
+که کلون صدایی کرد و لای در باز شد. یارو با چشمهایش سلام کرد. رفتم تو و با همان صدا پرسیدم:
+
+- این معلمه مدرسه که تصادف کرده...
+
+تا آخرش را خواند. یکی را صدا زد و دنبالم فرستاد که طبقهی فلان، اتاق فلان. از حیاط به راهرو و باز به حیاط دیگر که نصفش را برف پوشانده بود و من چنان میدویدم که یارو از عقب سرم هن هن میکرد. طبقهی اول و دوم و چهارم. چهار تا پله یکی. راهرو تاریک بود و پر از بوهای مخصوص بود. هن هن کنان دری را نشان داد که هل دادم و رفتم تو. بو تندتر بود و تاریکی بیشتر. تالاری بود پر از تخت و جیرجیر کفش و خرخر یک نفر. دور یک تخت چهار نفر ایستاده بودند. حتماً خودش بود. پای تخت که رسیدم، احساس کردم همهی آنچه از خشونت و تظاهر و ابهت به کمک خواسته بودم آب شد و بر سر و صورتم راه افتاد. و این معلم کلاس چهارم مدرسهام بود. سنگین و با شکم بر آمده دراز کشیده بود. خیلی کوتاهتر از زمانی که سر پا بود به نظرم آمد. صورت و سینهاش از روپوش چرکمُرد بیرون بود. صورتش را که شسته بودند کبود کبود بود، درست به رنگ جای سیلی روی صورت بچهها. مرا که دید، لبخند و چه لبخندی! شاید میخواست بگوید مدرسهای که مدیرش عصرها سر کار نباشد، باید همین جورها هم باشد. خنده توی صورت او همین طور لرزید و لرزید تا یخ زد.
+
+«آخر چرا تصادف کردی؟...»
+
+مثل این که سوال را ازو کردم. اما وقتی که دیدم نمیتواند حرف بزند و به جای هر جوابی همان خندهی یخبسته را روی صورت دارد، خودم را به عنوان او دم چک گرفتم. «آخه چرا؟ چرا این هیکل مدیر کلی را با خودت این قد این ور و آن ور میبری تا بزنندت؟ تا زیرت کنند؟ مگر نمیدانستی که معلم حق ندارد این قدر خوشهیکل باشد؟ آخر چرا تصادف کردی؟» به چنان عتاب و خطابی اینها را میگفتم که هیچ مطمئن نیستم بلند بلند به خودش نگفته باشم. و یک مرتبه به کلهام زد که «مبادا خودت چشمش زده باشی؟» و بعد: «احمق خاک بر سر! بعد از سی و چند سال عمر، تازه خرافاتی شدی!» و چنان از خودم بیزاریم گرفت که میخواستم به یکی فحش بدهم، کسی را بزنم. که چشمم به دکتر کشیک افتاد.
+
+- مرده شور این مملکتو ببره. ساعت چهار تا حالا از تن این مرد خون میره. حیفتون نیومد؟...
+
+دستی روی شانهام نشست و فریادم را خواباند. برگشتم پدرش بود. او هم میخندید. دو نفر دیگر هم با او بودند. همه دهاتیوار؛ همه خوش قد و قواره. حظ کردم! آن دو تا پسرهایش بودند یا برادرزادههایش یا کسان دیگرش. تازه داشت گل از گلم میشکفت که شنیدم:
+
+- آقا کی باشند؟
+
+این راهم دکتر کشیک گفت که من باز سوار شدم:
+
+- مرا میگید آقا؟ من هیشکی. یک آقا مدیر کوفتی. این هم معلمم.
+
+که یک مرتبه عقل هی زد و «پسر خفه شو» و خفه شدم. بغض توی گلویم بود. دلم میخواست یک کلمه دیگر بگوید. یک کنایه بزند... نسبت به مهارت هیچ دکتری تا کنون نتوانستهام قسم بخورم. دستش را دراز کرد که به اکراه فشار دادم و بعد شیشهی بزرگی را نشانم داد که وارونه بالای تخت آویزان بود و خرفهمم کرد که این جوری غذا به او میرسانند و عکس هم گرفتهاند و تا فردا صبح اگر زخمها چرک نکند، جا خواهند انداخت و گچ خواهند کرد. که یکی دیگر از راه رسید. گوشی به دست و سفید پوش و معطر. با حرکاتی مثل آرتیست سینما. سلامم کرد. صدایش در ته ذهنم چیزی را مختصر تکانی داد. اما احتیاجی به کنجکاوی نبود. یکی از شاگردهای نمیدانم چند سال پیشم بود. خودش خودش را معرفی کرد. آقای دکتر...! عجب روزگاری! هر تکه از وجودت را با مزخرفی از انبان مزخرفاتت، مثل ذرهای روزی در خاکی ریختهای که حالا سبز کرده. چشم داری احمق. این تویی که روی تخت دراز کشیدهای. ده سال آزگار از پلکان ساعات و دقایق عمرت هر لحظه یکی بالا رفته و تو فقط خستگی این بار را هنوز در تن داری. این جوجهفکلی و جوجههای دیگر که نمیشناسیشان، همه از تخمی سر در آوردهاند که روزی حصار جوانی تو بوده و حالا شکسته و خالی مانده. دستش را گرفتم و کشیدمش کناری و در گوشش هر چه بد و بیراه میدانستم، به او و همکارش و شغلش دادم. مثلاً میخواستم سفارش معلم کلاس چهار مدرسهام را کرده باشم. بعد هم سری برای پدر تکان دادم و گریختم. از در که بیرون آمدم، حیاط بود و هوای بارانی. از در بزرگ که بیرون آمدم به این فکر میکردم که «اصلا به تو چه؟ اصلاً چرا آمدی؟ میخواستی کنجکاویات را سیرکنی؟» و دست آخر به این نتیجه رسیدم که «طعمهای برای میزنشینهای شهربانی و دادگستری به دست آمده و تو نه میتوانی این طعمه را از دستشان بیرون بیاوری و نه هیچ کار دیگری میتوانی بکنی...»
+
+و داشتم سوار تاکسی میشدم تا برگردم خانه که یک دفعه به صرافت افتادم که اقلاً چرا نپرسیدی چه بلایی به سرش آمده؟» خواستم عقبگرد کنم، اما هیکل کبود معلم کلاس چهارم روی تخت بود و دیدم نمیتوانم. خجالت میکشیدم و یا میترسیدم. آن شب تا ساعت دو بیدار بودم و فردا یک گزارش مفصل به امضای مدیر مدرسه و شهادت همهی معلمها برای ادارهی فرهنگ و کلانتری محل و بعد هم دوندگی در ادارهی بیمه و قرار بر این که روزی نه تومان بودجه برای خرج بیمارستان او بدهند و عصر پس از مدتی رفتم مدرسه و کلاسها را تعطیل کردم و معلمها و بچههای ششم را فرستادم عیادتش و دسته گل و ازین بازیها... و یک ساعتی در مدرسه تنها ماندم و فارغ از همه چیز برای خودم خیال بافتم.... و فردا صبح پدرش آمد سلام و احوالپرسی و گفت یک دست و یک پایش شکسته و کمی خونریزی داخل مغز و از طرف یارو آمریکاییه آمدهاند عیادتش و وعده و وعید که وقتی خوب شد، در اصل چهار استخدامش کنند و با زبان بیزبانی حالیم کرد که گزارش را بیخود دادهام و حالا هم دادهام، دنبالش نکنم و رضایت طرفین و کاسهی از آش داغتر و از این حرفها... خاک بر سر مملکت.
+
+اوایل امر توجهی به بچهها نداشتم. خیال میکردم اختلاف سِنی میانمان آن قدر هست که کاری به کار همدیگر نداشته باشیم. همیشه سرم به کار خودم بود. در دفتر را میبستم و در گرمای بخاری دولت قلم صد تا یک غاز میزدم. اما این کار مرتب سه چهار هفته بیشتر دوام نکرد. خسته شدم. ناچار به مدرسه بیشتر میرسیدم. یاد روزهای قدیمی با دوستان قدیمی به خیر چه آدمهای پاک و بیآلایشی بودند، چه شخصیتهای بینام و نشانی و هر کدام با چه زبانی و با چه ادا و اطوارهای مخصوص به خودشان و این جوانهای چلفتهای. چه مقلدهای بیدردسری برای فرهنگیمابی! نه خبری از دیروزشان داشتند و نه از املاک تازهای که با هفتاد واسطه به دستشان داده بودند، چیزی سرشان میشد. بدتر از همه بیدست و پاییشان بود. آرام و مرتب درست مثل واگن شاه عبدالعظیم میآمدند و میرفتند. فقط بلد بودند روزی ده دقیقه دیرتر بیایند و همین. و از این هم بدتر تنگنظریشان بود.
+
+سه بار شاهد دعواهایی بودم که سر یک گلدان میخک یا شمعدانی بود. بچهباغبانها زیاد بودند و هر کدامشان حداقل ماهی یک گلدان میخک یا شمعدانی میآوردند که در آن برف و سرما نعمتی بود. اول تصمیم گرفتم، مدرسه را با آنها زینت دهم. ولی چه فایده؟ نه کسی آبشان میداد و نه مواظبتی. و باز بدتر از همهی اینها، بیشخصیتی معلمها بود که درماندهام کرده بود. دو کلمه نمیتوانستند حرف بزنند. عجب هیچکارههایی بودند! احساس کردم که روز به روز در کلاسها معلمها به جای دانشآموزان جاافتادهتر میشوند. در نتیجه گفتم بیشتر متوجه بچهها باشم.
+
+آنها که تنها با ناظم سر و کار داشتند و مثل این بود که به من فقط یک سلام نیمهجویده بدهکارند. با این همه نومیدکننده نبودند. توی کوچه مواظبشان بودم. میخواستم حرف و سخنها و درد دلها و افکارشان را از یک فحش نیمهکاره یا از یک ادای نیمهتمام حدس بزنم، که سلامنکرده در میرفتند. خیلی کم تنها به مدرسه میآمدند. پیدا بود که سر راه همدیگر میایستند یا در خانهی یکدیگر میروند. سه چهار نفرشان هم با اسکورت میآمدند. از بیست سی نفری که ناهار میماندند، فقط دو نفرشان چلو خورش میآوردند؛ فراش اولی مدرسه برایم خبر میآورد. بقیه گوشتکوبیده، پنیر گردوئی، دم پختکی و از این جور چیزها. دو نفرشان هم بودند که نان سنگک خالی میآوردند. برادر بودند. پنجم و سوم. صبح که میآمدند، جیبهاشان باد کرده بود. سنگک را نصف میکردند و توی جیبهاشان میتپاندند و ظهر میشد، مثل آنهایی که ناهارشان را در خانه میخورند، میرفتند بیرون. من فقط بیرون رفتنشان را میدیدم. اما حتی همینها هر کدام روزی، یکی دو قران از فراش مدرسه خرت و خورت میخریدند. از همان فراش قدیمی مدرسه که ماهی پنج تومان سرایداریش را وصول کرده بودم. هر روز که وارد اتاقم میشدم پشت سر من میآمد بارانیام را بر میداشت و شروع میکرد به گزارش دادن، که دیروز باز دو نفر از معلمها سر یک گلدان دعوا کردهاند یا مأمور فرماندار نظامی آمده یا دفتردار عوض شده و از این اباطیل... پیدا بود که فراش جدید هم در مطالبی که او میگفت، سهمی دارد.
+
+یک روز در حین گزارش دادن، اشارهای کرد به این مطلب که دیروز عصر یکی از بچههای کلاس چهار دو تا کله قند به او فروخته است. درست مثل اینکه سر کلاف را به دستم داده باشد پرسیدم:
+
+- چند؟
+
+- دو تومنش دادم آقا.
+
+- زحمت کشیدی. نگفتی از کجا آورده؟
+
+- من که ضامن بهشت و جهنمش نبودم آقا.
+
+بعد پرسیدم:
+
+- چرا به آقای ناظم خبر ندادی؟
+
+میدانستم که هم او و هم فراش جدید، ناظم را هووی خودشان میدانند و خیلی چیزهاشان از او مخفی بود. این بود که میان من و ناظم خاصهخرجی میکردند. در جوابم همین طور مردد مانده بود که در باز شد و فراش جدید آمد تو. که:
+
+- اگه خبرش میکرد آقا بایست سهمش رو میداد...
+
+اخمم را درهم کشیدم و گفتم:
+
+- تو باز رفتی تو کوک مردم! اونم این جوری سر نزده که نمیآیند تو اتاق کسی، پیرمرد!
+
+و بعد اسم پسرک را ازشان پرسیدم و حالیشان کردم که چندان مهم نیست و فرستادمشان برایم چای بیاورند. بعد کارم را زودتر تمام کردم و رفتم به اتاق دفتر احوالی از مادر ناظم پرسیدم و به هوای ورق زدن پروندهها فهمیدم که پسرک شاگرد دوساله است و پدرش تاجر بازار. بعد برگشتم به اتاقم. یادداشتی برای پدر نوشتم که پس فردا صبح، بیاید مدرسه و دادم دست فراش جدید که خودش برساند و رسیدش را بیاورد.
+
+و پس فردا صبح یارو آمد. باید مدیر مدرسه بود تا دانست که اولیای اطفال چه راحت تن به کوچکترین خردهفرمایشهای مدرسه میدهند. حتم دارم که اگر از اجرای ثبت هم دنبالشان بفرستی به این زودیها آفتابی نشوند. چهل و پنج ساله مردی بود با یخهی بسته بیکراوات و پالتویی که بیشتر به قبا میماند. و خجالتی مینمود. هنوز ننشسته، پرسیدم:
+
+- شما دو تا زن دارید آقا؟
+
+دربارهی پسرش برای خودم پیشگوییهایی کرده بودم و گفتم این طوری به او رودست میزنم. پیدا بود که از سؤالم زیاد یکه نخورده است. گفتم برایش چای آوردند و سیگاری تعارفش کردم که ناشیانه دود کرد از ترس این که مبادا جلویم در بیاید که - به شما چه مربوط است و از این اعتراضها - امانش ندادم و سؤالم را این جور دنبال کردم:
+
+- البته میبخشید. چون لابد به همین علت بچه شما دو سال در یک کلاس مانده.
+
+شروع کرده بودم برایش یک میتینگ بدهم که پرید وسط حرفم:
+
+- به سر شما قسم، روزی چهار زار پول تو جیبی داره آقا. پدرسوختهی نمک به حروم...!
+
+حالیش کردم که علت، پول تو جیبی نیست و خواستم که عصبانی نشود و قول گرفتم که اصلاً به روی پسرش هم نیاورد و آن وقت میتینگم را برایش دادم که لابد پسر در خانه مهر و محبتی نمیبیند و غیبگوییهای دیگر... تا عاقبت یارو خجالتش ریخت و سرِ درد دلش باز شد که عفریته زن اولش همچه بوده و همچون بوده و پسرش هم به خودش برده و کی طلاقش داده و از زن دومش چند تا بچه دارد و این نرهخر حالا باید برای خودش نانآور شده باشد و زنش حق دارد که با دو تا بچهی خردهپا به او نرسد... من هم کلی برایش صحبت کردم. چایی دومش را هم سر کشید و قولهایش را که داد و رفت، من به این فکر افتادم که «نکند علمای تعلیم و تربیت هم، همین جورها تخم دوزرده میکنند!»
+
+یک روز صبح که رسیدم، ناظم هنوز نیامده بود. از این اتفاقها کم میافتاد. ده دقیقهای از زنگ میگذشت و معلمها در دفتر سرگرم اختلاط بودند. خودم هم وقتی معلم بودم به این مرض دچار بودم. اما وقتی مدیر شدم تازه فهمیدم که معلمها چه لذتی میبرند. حق هم داشتند. آدم وقتی مجبور باشد شکلکی را به صورت بگذارد که نه دیگران از آن میخندند و نه خود آدم لذتی میبرد، پیداست که رفع تکلیف میکند. زنگ را گفتم زدند و بچهها سر کلاس رفتند. دو تا از کلاسها بیمعلم بود. یکی از ششمیها را فرستادم سر کلاس سوم که برایشان دیکته بگوید و خودم رفتم سر کلاس چهار. مدیر هم که باشی، باز باید تمرین کنی که مبادا فوت و فن معلمی از یادت برود. در حال صحبت با بچهها بودم که فراش خبر آورد که خانمی توی دفتر منتظرم است. خیال کردم لابد همان زنکهی بیکارهای است که هفتهای یک بار به هوای سرکشی، به وضع درس و مشق بچهاش سری میزند. زن سفیدرویی بود با چشمهای درشت محزون و موی بور. بیست و پنج ساله هم نمینمود. اما بچهاش کلاس سوم بود. روز اول که دیدمش لباس نارنجی به تن داشت و تن بزک کرده بود. از زیارت من خیلی خوشحال شد و از مراتب فضل و ادبم خبر داشت.
+
+خیلی ساده آمده بود تا با دو تا مرد حرفی زده باشد. آن طور که ناظم خبر میداد، یک سالی طلاق گرفته بود و روی هم رفته آمد و رفتنش به مدرسه باعث دردسر بود. وسط بیابان و مدرسهای پر از معلمهای عزب و بیدست و پا و یک زن زیبا... ناچار جور در نمیآمد. این بود که دفعات بعد دست به سرش میکردم، اما از رو نمیرفت. سراغ ناظم و اتاق دفتر را میگرفت و صبر میکرد تا زنگ را بزنند و معلمها جمع بشوند و لابد حرف و سخنی و خندهای و بعد از معلم کلاس سوم سراغ کار و بار و بچهاش را میگرفت و زنگ بعد را که میزدند، خداحافظی میکرد و میرفت. آزاری نداشت. با چشمهایش نفس معلمها را میبرید. و حالا باز هم همان زن بود و آمده بود و من تا از پلکان پایین بروم در ذهنم جملات زنندهای ردیف میکردم، تا پایش را از مدرسه ببرد که در را باز کردم و سلام...
+
+عجب! او نبود. دخترک یکی دو سالهای بود با دهان گشاد و موهای زبرش را به زحمت عقب سرش گلوله کرده بود و بفهمی نفهمی دستی توی صورتش برده بود. روی هم رفته زشت نبود. اما داد میزد که معلم است. گفتم که مدیر مدرسهام و حکمش را داد دستم که دانشسرا دیده بود و تازه استخدام شده بود. برایمان معلم فرستاده بودند. خواستم بگویم «مگر رئیس فرهنگ نمیداند که این جا بیش از حد مرد است» ولی دیدم لزومی ندارد و فکر کردم این هم خودش تنوعی است.
+
+به هر صورت زنی بود و میتوانست محیط خشن مدرسه را که به طرز ناشیانهای پسرانه بود، لطافتی بدهد و خوشآمد گفتم و چای آوردند که نخورد و بردمش کلاسهای سوم و چهارم را نشانش دادم که هر کدام را مایل است، قبول کند و صحبت از هجده ساعت درس که در انتظار او بود و برگشتیم به دفتر .پرسید غیر از او هم، معلم زن داریم. گفتم:
+
+- متأسفانه راه مدرسهی ما را برای پاشنهی کفش خانمها نساختهاند.
+
+که خندید و احساس کردم زورکی میخندد. بعد کمی این دست و آن دست کرد و عاقبت:
+
+- آخه من شنیده بودم شما با معلماتون خیلی خوب تا میکنید.
+
+صدای جذابی داشت. فکر کردم حیف که این صدا را پای تخته سیاه خراب خواهد کرد. و گفتم:
+
+- اما نه این قدر که مدرسه تعطیل بشود خانم! و لابد به عرضتون رسیده که همکارهای شما، خودشون نشستهاند و تصمیم گرفتهاند که هجده ساعت درس بدهند. بنده هیچکارهام.
+
+- اختیار دارید.
+
+و نفهمیدم با این «اختیار دارید» چه میخواست بگوید. اما پیدا بود که بحث سر ساعات درس نیست. آناً تصمیم گرفتم، امتحانی بکنم:
+
+- این را هم اطلاع داشته باشید که فقط دو تا از معلمهای ما متأهلاند.
+
+که قرمز شد و برای این که کار دیگری نکرده باشد، برخاست و حکمش را از روی میز برداشت. پا به پا میشد که دیدم باید به دادش برسم. ساعت را از او پرسیدم. وقت زنگ بود. فراش را صدا کردم که زنگ را بزند و بعد به او گفتم، بهتر است مشورت دیگری هم با رئیس فرهنگ بکند و ما به هر صورت خوشحال خواهیم شد که افتخار همکاری با خانمی مثل ایشان را داشته باشیم و خداحافظ شما. از در دفتر که بیرون رفت، صدای زنگ برخاست و معلمها انگار موشان را آتش زدهاند، به عجله رسیدند و هر کدام از پشت سر، آن قدر او را پاییدند تا از در بزرگ آهنی مدرسه بیرون رفت.
+
+فردا صبح معلوم شد که ناظم، دنبال کار مادرش بوده است که قرار بود بستری شود، تا جای سرطان گرفته را یک دوره برق بگذارند. کل کار بیمارستان را من به کمک دوستانم انجام دادم و موقع آن رسیده بود که مادرش برود بیمارستان اما وحشتش گرفته بود و حاضر نبود به بیمارستان برود. و ناظم میخواست رسماً دخالت کنم و با هم برویم خانهشان و با زبان چرب و نرمی که به قول ناظم داشتم مادرش را راضی کنم. چارهای نبود. مدرسه را به معلمها سپردیم و راه افتادیم. بالاخره به خانهی آنها رسیدیم. خانهای بسیار کوچک و اجارهای. مادر با چشمهای گود نشسته و انگار زغال به صورت مالیده! سیاه نبود اما رنگش چنان تیره بود که وحشتم گرفت. اصلاً صورت نبود. زخم سیاه شدهای بود که انگار از جای چشمها و دهان سر باز کرده است. کلی با مادرش صحبت کردم. از پسرش و کلی دروغ و دونگ، و چادرش را روی چارقدش انداختیم و علی... و خلاصه در بیمارستان بستری شدند.
+
+فردا که به مدرسه آمدم، ناظم سرحال بود و پیدا بود که از شر چیزی خلاص شده است و خبر داد که معلم کلاس سه را گرفتهاند. یک ماه و خردهای میشد که مخفی بود و ما ورقهی انجام کارش را به جانشین غیر رسمیاش داده بودیم و حقوقش لنگ نشده بود و تا خبر رسمی بشنود و در روزنامهای بیابد و قضیه به ادارهی فرهنگ و لیست حقوق بکشد، باز هم میدادیم. اما خبر که رسمی شد، جانشین واجد شرایط هم نمیتوانست بفرستد و باید طبق مقررات رفتار میکردیم و بدیش همین بود. کم کم احساس کردم که مدرسه خلوت شده است و کلاسها اغلب اوقات بیکارند. جانشین معلم کلاس چهار هنوز سر و صورتی به کارش نداده بود و حالا یک کلاس دیگر هم بیمعلم شد. این بود که باز هم به سراغ رئیس فرهنگ رفتم. معلوم شد آن دخترک ترسیده و «نرسیده متلک پیچش کردهاید» رئیس فرهنگ این طور میگفت. و ترجیح داده بود همان زیر نظر خودش دفترداری کند. و بعد قول و قرار و فردا و پس فردا و عاقبت چهار روز دوندگی تا دو تا معلم گرفتم. یکی جوانکی رشتی که گذاشتیمش کلاس چهار و دیگری باز یکی ازین آقاپسرهای بریانتینزده که هر روز کراوات عوض میکرد، با نقشها و طرحهای عجیب. عجب فرهنگ را با قرتیها در آمیخته بودند! باداباد. او را هم گذاشتیم سر کلاس سه. اواخر بهمن، یک روز ناظم آمد اتاقم که بودجهی مدرسه را زنده کرده است. گفتم:
+
+- مبارکه، چه قدر گرفتی؟
+
+- هنوز هیچ چی آقا. قراره فردا سر ظهر بیاند این جا آقا و همین جا قالش رو بکنند.
+
+و فردا اصلاً مدرسه نرفتم. حتماً میخواست من هم باشم و در بده بستان ماهی پانزده قران، حق نظافت هر اتاق نظارت کنم و از مدیریتم مایه بگذارم تا تنخواهگردان مدرسه و حق آب و دیگر پولهای عقبافتاده وصول بشود... فردا سه نفری آمده بودند مدرسه. ناهار هم به خرج ناظم خورده بودند. و قرار دیگری برای یک سور حسابی گذاشته بودند و رفته بودند و ناظم با زبان بیزبانی حالیم کرد که این بار حتماً باید باشم و آن طور که میگفت، جای شکرش باقی بود که مراعات کرده بودند و حق بوقی نخواسته بودند. اولین باری بود که چنین اهمیتی پیدا میکردم. این هم یک مزیت دیگر مدیری مدرسه بود! سی صد تومان از بودجهی دولت بسته به این بود که به فلان مجلس بروی یا نروی. تا سه روز دیگر موعد سور بود، اصلاً یادم نیست چه کردم. اما همهاش در این فکر بودم که بروم یا نروم؟ یک بار دیگر استعفانامهام را توی جیبم گذاشتم و بی این که صدایش را در بیاورم، روز سور هم نرفتم.
+
+بعد دیدم این طور که نمیشود. گفتم بروم قضایا را برای رئیس فرهنگ بگویم. و رفتم. سلام و احوالپرسی نشستم. اما چه بگویم؟ بگویم چون نمیخواستم در خوردن سور شرکت کنم، استعفا میدهم؟... دیدم چیزی ندارم که بگویم. و از این گذشته خفتآور نبود که به خاطر سیصد تومان جا بزنم و استعفا بدهم؟ و «خداحافظ؛ فقط آمده بودم سلام عرض کنم.» و از این دروغها و استعفانامهام را توی جوی آب انداختم. اما ناظم؛ یک هفتهای مثل سگ بود. عصبانی، پر سر و صدا و شارت و شورت! حتی نرفتم احوال مادرش را بپرسم. یک هفتهی تمام میرفتم و در اتاقم را میبستم و سوراخهای گوشم را میگرفتم و تا اِز و چِزّ بچهها بخوابد، از این سر تا آن سر اتاق را میکوبیدم. ده روز تمام، قلب من و بچهها با هم و به یک اندازه از ترس و وحشت تپید. تا عاقبت پولها وصول شد. منتها به جای سیصد و خردهای، فقط صد و پنجاه تومان. علت هم این بود که در تنظیم صورت حسابها اشتباهاتی رخ داده بود که ناچار اصلاحش کرده بودند!
+
+غیر از آن زنی که هفتهای یک بار به مدرسه سری میزد، از اولیای اطفال دو سه نفر دیگر هم بودند که مرتب بودند. یکی همان پاسبانی که با کمربند، پاهای پسرش را بست و فلک کرد. یکی هم کارمند پست و تلگرافی بود که ده روزی یک بار میآمد و پدر همان بچهی شیطان. و یک استاد نجار که پسرش کلاس اول بود و خودش سواد داشت و به آن میبالید و کارآمد مینمود. یک مقنی هم بود درشت استخوان و بلندقد که بچهاش کلاس سوم بود و هفتهای یک بار میآمد و همان توی حیاط، ده پانزده دقیقهای با فراشها اختلاط میکرد و بی سر و صدا میرفت. نه کاری داشت، نه چیزی از آدم میخواست و همان طور که آمده بود چند دقیقهای را با فراش صحبت میکرد و بعد می رفت. فقط یک روز نمیدانم چرا رفته بود بالای دیوار مدرسه. البته اول فکر کردم مأمور اداره برق است ولی بعد متوجه شدم که همان مرد مقنی است. بچهها جیغ و فریاد میکردند و من همهاش درین فکر بودم که چه طور به سر دیوار رفته است؟ ماحصل داد و فریادش این بود که چرا اسم پسر او را برای گرفتن کفش و لباس به انجمن ندادیم. وقتی به او رسیدم نگاهی به او انداختم و بعد تشری به ناظم و معلم ها زدم که ولش کردند و بچهها رفتند سر کلاس و بعد بی این که نگاهی به او بکنم، گفتم:
+
+- خسته نباشی اوستا.
+
+و همان طور که به طرف دفتر میرفتم رو به ناظم و معلمها افزودم:
+
+- لابد جواب درست و حسابی نشنیده که رفته سر دیوار.
+
+که پشت سرم گرپ صدایی آمد و از در دفتر که رفتم تو، او و ناظم با هم وارد شدند. گفتم نشست. و به جای اینکه حرفی بزند به گریه افتاد. هرگز گمان نمیکردم از چنان قد و قامتی صدای گریه در بیاید. این بود که از اتاق بیرون آمدم و فراش را صدا زدم که آب برایش بیاورد و حالش که جا آمد، بیاوردش پهلوی من. اما دیگر از او خبری نشد که نشد. نه آن روز و نه هیچ روز دیگر. آن روز چند دقیقهای بعد از شیشهی اتاق خودم دیدمش که دمش را لای پایش گذاشته بود از در مدرسه بیرون میرفت و فراش جدید آمد که بله میگفتند از پسرش پنج تومان خواسته بودند تا اسمش را برای کفش و لباس به انجمن بدهند. پیدا بود باز توی کوک ناظم رفته است. مرخصش کردم و ناظم را خواستم. معلوم شد میخواسته ناظم را بزند. همین جوری و بیمقدمه.
+
+اواخر بهمن بود که یکی از روزهای برفی با یکی دیگر از اولیای اطفال آشنا شدم. یارو مرد بسیار کوتاهی بود؛ فرنگ مآب و بزک کرده و اتو کشیده که ننشسته از تحصیلاتش و از سفرهای فرنگش حرف زد. میخواست پسرش را آن وقت سال از مدرسهی دیگر به آن جا بیاورد. پسرش از آن بچههایی بود که شیر و مربای صبحانهاش را با قربان صدقه توی حلقشان میتپانند. کلاس دوم بود و ثلث اول دو تا تجدید آورده بود. میگفت در باغ ییلاقیاش که نزدیک مدرسه است، باغبانی دارند که پسرش شاگرد ماست و درسخوان است و پیدا است که بچهها زیر سایه شما خوب پیشرفت میکنند. و از این پیزرها. و حال به خاطر همین بچه، توی این برف و سرما، آمدهاند ساکن باغ ییلاقی شدهاند. بلند شدم ناظم را صدا کردم و دست او و بچهاش را توی دست ناظم گذاشتم و خداحافظ شما... و نیم ساعت بعد ناظم برگشت که یارو خانهی شهرش را به یک دبیرستان اجاره داده، به ماهی سه هزار و دویست تومان، و التماس دعا داشته، یعنی معلم سرخانه میخواسته و حتی بدش نمیآمده است که خود مدیر زحمت بکشند و ازین گندهگوزیها... احساس کردم که ناظم دهانش آب افتاده است. و من به ناظم حالی کردم خودش برود بهتر است و فقط کاری بکند که نه صدای معلمها در بیاید و نه آخر سال، برای یک معدل ده احتیاجی به من بمیرم و تو بمیری پیدا کند. همان روز عصر ناظم رفته بود و قرار و مدار برای هر روز عصر یک ساعت به ماهی صد و پنجاه تومان.
+
+دیگر دنیا به کام ناظم بود. حال مادرش هم بهتر بود و از بیمارستان مرخصش کرده بودند و به فکر زن گرفتن افتاده بود. و هر روز هم برای یک نفر نقشه میکشید حتی برای من هم. یک روز در آمد که چرا ما خودمان «انجمن خانه و مدرسه» نداشته باشیم؟ نشسته بود و حسابش را کرده بود دیده بود که پنجاه شصت نفری از اولیای مدرسه دستشان به دهانشان میرسد و از آن هم که به پسرش درس خصوصی میداد قول مساعد گرفته بود. حالیش کردم که مواظب حرف و سخن ادارهای باشد و هر کار دلش میخواهد بکند. کاغذ دعوت را هم برایش نوشتم با آب و تاب و خودش برای ادارهی فرهنگ، داد ماشین کردند و به وسیلهی خود بچهها فرستاد. و جلسه با حضور بیست و چند نفری از اولیای بچهها رسمی شد. خوبیش این بود که پاسبان کشیک پاسگاه هم آمده بود و دم در برای همه، پاشنههایش را به هم میکوبید و معلمها گوش تا گوش نشسته بودند و مجلس ابهتی داشت و ناظم، چای و شیرینی تهیه کرده بود و چراغ زنبوری کرایه کرده بود و باران هم گذاشت پشتش و سالون برای اولین بار در عمرش به نوایی رسید.
+
+یک سرهنگ بود که رئیسش کردیم و آن زن را که هفتهای یک بار میآمد نایب رئیس. آن که ناظم به پسرش درس خصوصی میداد نیامده بود. اما پاکت سربستهای به اسم مدیر فرستاده بود که فیالمجلس بازش کردیم. عذرخواهی از اینکه نتوانسته بود بیاید و وجه ناقابلی جوف پاکت. صد و پنجاه تومان. و پول را روی میز صندوقدار گذاشتیم که ضبط و ربط کند. نائب رئیس بزک کرده و معطر شیرینی تعارف میکرد و معلمها با هر بار که شیرینی بر میداشتند، یک بار تا بناگوش سرخ میشدند و فراشها دست به دست چای میآوردند.
+
+در فکر بودم که یک مرتبه احساس کردم، سیصد چهارصد تومان پول نقد، روی میز است و هشت صد تومان هم تعهد کرده بودند. پیرزن صندوقدار که کیف پولش را همراهش نیاورده بود ناچار حضار تصویب کردند که پولها فعلاً پیش ناظم باشد. و صورت مجلس مرتب شد و امضاها ردیف پای آن و فردا فهمیدم که ناظم همان شب روی خشت نشسته بوده و به معلمها سور داده بوده است. اولین کاری که کردم رونوشت مجلس آن شب را برای ادارهی فرهنگ فرستادم. و بعد همان استاد نجار را صدا کردم و دستور دادم برای مستراحها دو روزه در بسازد که ناظم خیلی به سختی پولش را داد. و بعد در کوچهی مدرسه درخت کاشتیم. تور والیبال را تعویض و تعدادی توپ در اختیار بچهها گذاشتیم برای تمرین در بعد از ظهرها و آمادگی برای مسابقه با دیگر مدارس و در همین حین سر و کلهی بازرس تربیت بدنی هم پیدا شد و هر روز سرکشی و بیا و برو. تا یک روز که به مدرسه رسیدم شنیدم که از سالون سر و صدا میآید. صدای هالتر بود. ناظم سر خود رفته بود و سرخود دویست سیصد تومان داده بود و هالتر خریده بود و بچههای لاغر زیر بار آن گردن خود را خرد میکردند. من در این میان حرفی نزدم. میتوانستم حرفی بزنم؟ من چیکاره بودم؟ اصلاً به من چه ربطی داشت؟ هر کار که دلشان میخواهد بکنند. مهم این بود که سالون مدرسه رونقی گرفته بود. ناظم هم راضی بود و معلمها هم. چون نه خبر از حسادتی بود و نه حرف و سخنی پیش آمد. فقط میبایست به ناظم سفارش می کردم که فکر فراشها هم باشد.
+
+کم کم خودمان را برای امتحانهای ثلث دوم آماده میکردیم. این بود که اوایل اسفند، یک روز معلمها را صدا زدم و در شورا مانندی که کردیم بیمقدمه برایشان داستان یکی از همکاران سابقم را گفتم که هر وقت بیست میداد تا دو روز تب داشت. البته معلمها خندیدند. ناچار تشویق شدم و داستان آخوندی را گفتم که در بچگی معلم شرعیاتمان بود و زیر عبایش نمره میداد و دستش چنان میلرزید که عبا تکان میخورد و درست ده دقیقه طول میکشید. و تازه چند؟ بهترین شاگردها دوازده. و البته باز هم خندیدند. که این بار کلافهام کرد. و بعد حالیشان کردم که بد نیست در طرح سؤالها مشورت کنیم و از این حرفها...
+
+و از شنبهی بعد، امتحانات شروع شد. درست از نیمهی دوم اسفند. سؤالها را سه نفری میدیدیم. خودم با معلم هر کلاس و ناظم. در سالون میزها را چیده بودیم البته از وقتی هالتردار شده بود خیلی زیباتر شده بود. در سالون کاردستیهای بچهها در همه جا به چشم میخورد. هر کسی هر چیزی را به عنوان کاردستی درست کرده بودند و آورده بودند. که برای این کاردستیها چه پولها که خرج نشده بود و چه دستها که نبریده بود و چه دعواها که نشده بود و چه عرقها که ریخته نشده بود. پیش از هر امتحان که میشد، خودم یک میتینگ برای بچهها میدادم که ترس از معلم و امتحان بیجا است و باید اعتماد به نفس داشت و ازین مزخرفات....ولی مگر حرف به گوش کسی میرفت؟ از در که وارد میشدند، چنان هجومی میبردند که نگو! به جاهای دور از نظر. یک بار چنان بود که احساس کردم مثل اینکه از ترس، لذت میبرند. اگر معلم نبودی یا مدیر، به راحتی میتوانستی حدس بزنی که کیها با هم قرار و مداری دارند و کدام یک پهلو دست کدام یک خواهد نشست. یکی دو بار کوشیدم بالای دست یکیشان بایستم و ببینم چه مینویسد. ولی چنان مضطرب میشدند و دستشان به لرزه میافتاد که از نوشتن باز میماندند. میدیدم که این مردان آینده، درین کلاسها و امتحانها آن قدر خواهند ترسید که وقتی دیپلمه بشوند یا لیسانسه، اصلاً آدم نوع جدیدی خواهند شد. آدمی انباشته از وحشت، انبانی از ترس و دلهره. به این ترتیب یک روز بیشتر دوام نیاوردم. چون دیدم نمیتوانم قلب بچگانهای داشته باشم تا با آن ترس و وحشت بچهها را درک کنم و همدردی نشان بدهم.این جور بود که میدیدم که معلم مدرسه هم نمیتوانم باشم.
+
+دو روز قبل از عید کارنامهها آماده بود و منتظر امضای مدیر. دویست و سی و شش تا امضا اقلاً تا ظهر طول میکشید. پیش از آن هم تا میتوانستم از امضای دفترهای حضور و غیاب میگریختم. خیلی از جیرهخورهای دولت در ادارات دیگر یا در میان همکارانم دیده بودم که در مواقع بیکاری تمرین امضا میکنند. پیش از آن نمیتوانستم بفهمم چه طور از مدیری یک مدرسه یا کارمندی ساده یک اداره میشود به وزارت رسید. یا اصلاً آرزویش را داشت. نیمقراضه امضای آماده و هر کدام معرف یک شخصیت، بعد نیمذرع زبان چرب و نرم که با آن، مار را از سوراخ بیرون بکشی، یا همه جا را بلیسی و یک دست هم قیافه. نه یک جور. دوازده جور.
+
+در این فکرها بودم که ناگهان در میان کارنامهها چشمم به یک اسم آشنا افتاد. به اسم پسران جناب سرهنگ که رئیس انجمن بود. رفتم توی نخ نمراتش. همه متوسط بود و جای ایرادی نبود. و یک مرتبه به صرافت افتادم که از اول سال تا به حال بچههای مدرسه را فقط به اعتبار وضع مالی پدرشان قضاوت کردهام. درست مثل این پسر سرهنگ که به اعتبار کیابیای پدرش درس نمیخواند. دیدم هر کدام که پدرشان فقیرتر است به نظر من باهوشتر میآمدهاند. البته ناظم با این حرفها کاری نداشت. مر قانونی را عمل میکرد. از یکی چشم میپوشید به دیگری سخت میگرفت.
+
+اما من مثل این که قضاوتم را دربارهی بچهها از پیش کرده باشم و چه خوب بود که نمرهها در اختیار من نبود و آن یکی هم «انظباط» مال آخر سال بود. مسخرهترین کارها آن است که کسی به اصلاح وضعی دست بزند، اما در قلمروی که تا سر دماغش بیشتر نیست. و تازه مدرسهی من، این قلمروی فعالیت من، تا سر دماغم هم نبود. به همان توی ذهنم ختم میشد. وضعی را که دیگران ترتیب داده بودند. به این ترتیب بعد از پنج شش ماه، میفهمیدم که حسابم یک حساب عقلایی نبوده است. احساساتی بوده است. ضعفهای احساساتی مرا خشونتهای عملی ناظم جبران میکرد و این بود که جمعاً نمیتوانستم ازو بگذرم. مرد عمل بود. کار را میبرید و پیش میرفت. در زندگی و در هر کاری، هر قدمی بر میداشت، برایش هدف بود. و چشم از وجوه دیگر قضیه میپوشید. این بود که برش داشت. و من نمیتوانستم. چرا که اصلاً مدیر نبودم. خلاص...
+
+و کارنامهی پسر سرهنگ را که زیر دستم عرق کرده بود، به دقت و احتیاج خشک کردم و امضایی زیر آن گذاشتم به قدری بد خط و مسخره بود که به یاد امضای فراش جدیدمان افتادم. حتماً جناب سرهنگ کلافه میشد که چرا چنین آدم بیسوادی را با این خط و ربط امضا مدیر مدرسه کردهاند. آخر یک جناب سرهنگ هم میداند که امضای آدم معرف شخصیت آدم است.
+
+اواخر تعطیلات نوروز رفتم به ملاقات معلم ترکهای کلاس سوم. ناظم که با او میانهی خوشی نداشت. ناچار با معلم حساب کلاس پنج و شش قرار و مداری گذاشته بودم که مختصری علاقهای هم به آن حرف و سخنها داشت. هم به وسیلهی او بود که میدانستم نشانیاش کجا است و توی کدام زندان است. در راه قبل از هر چیز خبر داد که رئیس فرهنگ عوض شده و این طور که شایع است یکی از هم دورهایهای من، جایش آمده. گفتم:
+
+- عجب! چرا؟ مگه رئیس قبلی چپش کم بود؟
+
+- چه عرض کنم. میگند پا تو کفش یکی از نمایندهها کرده. شما خبر ندارید؟
+
+- چه طور؟ از کجا خبر داشته باشم؟
+
+- هیچ چی... می گند دو تا از کارچاقکنهای انتخاباتی یارو از صندوق فرهنگ حقوق میگرفتهاند؛ شب عیدی رئیس فرهنگ حقوقشون رو زده.
+
+- عجب! پس اونم میخواسته اصلاحات کنه! بیچاره.
+
+و بعد از این حرف زدیم که الحمدالله مدرسه مرتب است و آرام و معلمها همکاری میکنند و ناظم بیش از اندازه همهکاره شده است. و من فهمیدم که باز لابد مشتری خصوصی تازهای پیدا شده است که سر و صدای همه همکارها بلند شده. دم در زندان شلوغ بود. کلاه مخملیها، عمقزی گلبتهها، خاله خانباجیها و... اسم نوشتیم و نوبت گرفتیم و به جای پاها، دستهامان زیر بار کوچکی که داشتیم، خسته شد و خواب رفت تا نوبتمان شد. از این اتاق به آن اتاق و عاقبت نردههای آهنی و پشت آن معلم کلاس سه و... عجب چاق شده بود!درست مثل یک آدم حسابی شده بود. خوشحال شدیم و احوالپرسی و تشکر؛ و دیگر چه بگویم؟ بگویم چرا خودت را به دردسر انداختی؟ پیدا بود از مدرسه و کلاس به او خوشتر میگذرد. ایمانی بود و او آن را داشت و خوشبخت بود و دردسری نمیدید و زندان حداقل برایش کلاس درس بود. عاقبت پرسیدم:
+
+- پروندهای هم برات درست کردند یا هنوز بلاتکلیفی؟
+
+- امتحانمو دادم آقا مدیر، بد از آب در نیومد.
+
+- یعنی چه؟
+
+- یعنی بیتکلیف نیستم. چون اسمم تو لیست جیرهی زندون رفته. خیالم راحته. چون سختیهاش گذشته.
+
+دیگر چه بگویم. دیدم چیزی ندارم خداحافظی کردم و او را با معلم حساب تنها گذاشتم و آمدم بیرون و تا مدت ملاقات تمام بشود، دم در زندان قدم زدم و به زندانی فکر کردم که برای خودم ساخته بودم. یعنی آن خرپول فرهنگدوست ساخته بود. و من به میل و رغبت خودم را در آن زندانی کرده بودم. این یکی را به ضرب دگنک این جا آورده بودند. ناچار حق داشت که خیالش راحت باشد. اما من به میل و رغبت رفته بودم و چه بکنم؟ ناظم چه طور؟ راستی اگر رئیس فرهنگ از هم دورهایهای خودم باشد؛ چه طور است بروم و ازو بخواهم که ناظم را جای من بگذارد، یا همین معلم حساب را؟... که معلم حساب در آمد و راه افتادیم. با او هم دیگر حرفی نداشتم. سر پیچ خداحافظ شما و تاکسی گرفتم و یک سر به ادارهی فرهنگ زدم. گرچه دهم عید بود، اما هنوز رفت و آمد سال نو تمام نشده بود. برو و بیا و شیرینی و چای دو جانبه. رفتم تو. سلام و تبریک و همین تعارفات را پراندم.
+
+بله خودش بود. یکی از پخمههای کلاس. که آخر سال سوم کشتیارش شدم دو بیت شعر را حفظ کند، نتوانست که نتوانست. و حالا او رئیس بود و من آقا مدیر. راستی حیف از من، که حتی وزیر چنین رئیس فرهنگهایی باشم! میز همان طور پاک بود و رفته. اما زیرسیگاری انباشته از خاکستر و ته سیگار. بلند شد و چلپ و چولوپ روبوسی کردیم و پهلوی خودش جا باز کرد و گوش تا گوش جیرهخورهای فرهنگ تبریکات صمیمانه و بدگویی از ماسبق و هندوانه و پیزرها! و دو نفر که قد و قوارهشان به درد گود زورخانه میخورد یا پای صندوق انتخابات شیرینی به مردم میدادند. نزدیک بود شیرینی را توی ظرفش بیندازم که دیدم بسیار احمقانه است. سیگارم که تمام شد قضیهی رئیس فرهنگ قبلی و آن دو نفر را در گوشی ازش پرسیدم، حرفی نزد. فقط نگاهی میکرد که شبیه التماس بود و من فرصت جستم تا وضع معلم کلاس سوم را برایش روشن کنم و از او بخواهم تا آن جا که میتواند جلوی حقوقش را نگیرد. و از در که آمدم بیرون، تازه یادم آمد که برای کار دیگری پیش رئیس فرهنگ بودم.
+
+باز دیروز افتضاحی به پا شد. معقول یک ماههی فروردین راحت بودیم. اول اردیبهشت ماه جلالی و کوس رسوایی سر دیوار مدرسه. نزدیک آخر وقت یک جفت پدر و مادر، بچهشان در میان، وارد اتاق شدند. یکی بر افروخته و دیگری رنگ و رو باخته و بچهشان عیناً مثل این عروسکهای کوکی. سلام و علیک و نشستند. خدایا دیگر چه اتفاقی افتاده است؟
+
+- چه خبر شده که با خانوم سرافرازمون کردید؟
+
+مرد اشارهای به زنش کرد که بلند شد و دست بچه را گرفت و رفت بیرون و من ماندم و پدر. اما حرف نمیزد. به خودش فرصت میداد تا عصبانیتش بپزد. سیگارم را در آوردم و تعارفش کردم. مثل این که مگس مزاحمی را از روی دماغش بپراند، سیگار را رد کرد و من که سیگارم را آتش میزدم، فکر کردم لابد دردی دارد که چنین دست و پا بسته و چنین متکی به خانواده به مدرسه آمده. باز پرسیدم:
+
+- خوب، حالا چه فرمایش داشتید؟
+
+که یک مرتبه ترکید:
+
+- اگه من مدیر مدرسه بودم و همچه اتفاقی میافتاد، شیکم خودمو پاره میکردم. خجالت بکش مرد! برو استعفا بده. تا اهل محل نریختن تیکه تیکهات کنند، دو تا گوشتو وردار و دررو. بچههای مردم میآن این جا درس بخونن و حسن اخلاق. نمیآن که...
+
+- این مزخرفات کدومه آقا! حرف حساب سرکار چیه؟
+
+و حرکتی کردم که او را از در بیندازم بیرون. اما آخر باید میفهمیدم چه مرگش است. «ولی آخر با من چه کار دارد؟»
+
+- آبروی من رفته. آبروی صد سالهی خونوادهام رفته. اگه در مدرسهی تو رو تخته نکنم، تخم بابام نیستم. آخه من دیگه با این بچه چی کار کنم؟ تو این مدرسه ناموس مردم در خطره. کلانتری فهمیده؛ پزشک قانونی فهمیده؛ یک پرونده درست شده پنجاه ورق؛ تازه میگی حرف حسابم چیه؟ حرف حسابم اینه که صندلی و این مقام از سر تو زیاده. حرف حسابم اینه که میدم محاکمهات کنند و از نون خوردن بندازنت...
+
+او میگفت و من گوش میکردم و مثل دو تا سگ هار به جان هم افتاده بودیم که در باز شد و ناظم آمد تو. به دادم رسید. در همان حال که من و پدر بچه در حال دعوا بودیم زن و بچه همان آقا رفته بودند و قضایا را برای ناظم تعریف کرده بودند و او فرستاده بوده فاعل را از کلاس کشیده بودند بیرون... و گفت چه طور است زنگ بزنیم و جلوی بچهها ادبش کنیم و کردیم. یعنی این بار خود من رفتم میدان. پسرک نرهخری بود از پنجمیها با لباس مرتب و صورت سرخ و سفید و سالکی به گونه. جلوی روی بچهها کشیدمش زیر مشت و لگد و بعد سه تا از ترکهها را که فراش جدید فوری از باغ همسایه آورده بود، به سر و صورتش خرد کردم. چنان وحشی شده بودم که اگر ترکهها نمیرسید، پسرک را کشته بودم. این هم بود که ناظم به دادش رسید و وساطت کرد و لاشهاش را توی دفتر بردند و بچهها را مرخص کردند و من به اتاقم برگشتم و با حالی زار روی صندلی افتادم، نه از پدر خبری بود و نه از مادر و نه از عروسکهای کوکیشان که ناموسش دست کاری شده بود. و تازه احساس کردم که این کتککاری را باید به او میزدم. خیس عرق بودم و دهانم تلخ بود. تمام فحشهایی که میبایست به آن مردکهی دبنگ میدادم و نداده بودم، در دهانم رسوب کرده بود و مثل دم مار تلخ شده بود. اصلاً چرا زدمش؟ چرا نگذاشتم مثل همیشه ناظم میدانداری کند که هم کارکشتهتر بود و هم خونسردتر. لابد پسرک با دخترعمهاش هم نمیتواند بازی کند. لابد توی خانوادهشان، دخترها سر ده دوازده سالگی باید از پسرهای هم سن رو بگیرند. نکند عیبی کرده باشد؟ و یک مرتبه به صرافت افتادم که بروم ببینم چه بلایی به سرش آوردهام. بلند شدم و یکی از فراشها را صدا کردم که فهمیدم روانهاش کردهاند. آبی آورد که روی دستم میریخت و صورتم را میشستم و میکوشیدم که لرزش دستهایم را نبیند. و در گوشم آهسته گفت که پسر مدیر شرکت اتوبوسرانی است و بدجوری کتک خورده و آنها خیلی سعی کردهاند که تر و تمیزش کنند...
+
+احمق مثلا داشت توی دل مرا خالی میکرد. نمیدانست که من اول تصمیم را گرفتم، بعد مثل سگ هار شدم. و تازه میفهمیدم کسی را زدهام که لیاقتش را داشته. حتماً از این اتفاقها جای دیگر هم میافتد. آدم بردارد پایین تنه بچهی خودش را، یا به قول خودش ناموسش را بگذارد سر گذر که کلانتر محل و پزشک معاینه کنند! تا پرونده درست کنند؟ با این پدرو مادرها بچهها حق دارند که قرتی و دزد و دروغگو از آب در بیایند. این مدرسهها را اول برای پدر و مادرها باز کنند...
+
+با این افکار به خانه رسیدم. زنم در را که باز کرد؛ چشمهایش گرد شد. همیشه وقتی میترسد این طور میشود. برای اینکه خیال نکند آدم کشتهام، زود قضایا را برایش گفتم. و دیدم که در ماند. یعنی ساکت ماند. آب سرد، عرق بیدمشک، سیگار پشت سیگار فایده نداشت، لقمه از گلویم پایین نمیرفت و دستها هنوز میلرزید. هر کدام به اندازهی یک ماه فعالیت کرده بودند. با سیگار چهارم شروع کردم:
+
+- میدانی زن؟ بابای یارو پولداره. مسلماً کار به دادگستری و این جور خنسها میکشه. مدیریت که الفاتحه. اما خیلی دلم میخواد قضیه به دادگاه برسه. یک سال آزگار رو دل کشیدهام و دیگه خسته شدهام. دلم میخواد یکی بپرسه چرا بچهی مردم رو این طوری زدی، چرا تنبیه بدنی کردی! آخه یک مدیر مدرسه هم حرفهایی داره که باید یک جایی بزنه...
+
+که بلند شد و رفت سراغ تلفن. دو سه تا از دوستانم را که در دادگستری کارهای بودند، گرفت و خودم قضیه را برایشان گفتم که مواظب باشند. فردا پسرک فاعل به مدرسه نیامده بود. و ناظم برایم گفت که قضیه ازین قرار بوده است که دوتایی به هوای دیدن مجموعه تمبرهای فاعل با هم به خانهای میروند و قضایا همان جا اتفاق میافتد و داد و هوار و دخالت پدر و مادرهای طرفین و خط و نشان و شبانه کلانتری؛ و تمام اهل محل خبر دارند. او هم نظرش این بود که کار به دادگستری خواهد کشید.
+
+و من یک هفتهی تمام به انتظار اخطاریهی دادگستری صبح و عصر به مدرسه رفتم و مثل بختالنصر پشت پنجره ایستادم. اما در تمام این مدت نه از فاعل خبری شد، نه از مفعول و نه از پدر و مادر ناموسپرست و نه از مدیر شرکت اتوبوسرانی. انگار نه انگار که اتفاقی افتاده. بچهها میآمدند و میرفتند؛ برای آب خوردن عجله میکردند؛ به جای بازی کتککاری میکردند و همه چیز مثل قبل بود. فقط من ماندم و یک دنیا حرف و انتظار. تا عاقبت رسید.... احضاریهای با تعیین وقت قبلی برای دو روز بعد، در فلان شعبه و پیش فلان بازپرس دادگستری. آخر کسی پیدا شده بود که به حرفم گوش کند.
+
+تا دو روز بعد که موعد احضار بود، اصلاً از خانه در نیامدم. نشستم و ماحصل حرفهایم را روی کاغذ آوردم. حرفهایی که با همهی چرندی هر وزیر فرهنگی میتوانست با آن یک برنامهی هفت ساله برای کارش بریزد. و سر ساعت معین رفتم دادگستری. اتاق معین و بازپرس معین. در را باز کردم و سلام، و تا آمدم خودم را معرفی کنم و احضاریه را در بیاورم، یارو پیشدستی کرد و صندلی آورد و چای سفارش داد و «احتیاجی به این حرفها نیست و قضیهی کوچک بود و حل شد و راضی به زحمت شما نبودیم...»
+
+که عرق سرد بر بدن من نشست. چاییام را که خوردم، روی همان کاغذ نشاندار دادگستری استعفانامهام را نوشتم و به نام همکلاسی پخمهام که تازه رئیس شده بود، دم در پست کردم.
+EOT;
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/fi_FI/Address.php b/vendor/fakerphp/faker/src/Faker/Provider/fi_FI/Address.php
new file mode 100755
index 00000000..d72951be
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/fi_FI/Address.php
@@ -0,0 +1,85 @@
+format('dmy');
+
+ switch ((int) ($birthdate->format('Y') / 100)) {
+ case 18:
+ $centurySign = '+';
+
+ break;
+
+ case 19:
+ $centurySign = '-';
+
+ break;
+
+ case 20:
+ $centurySign = 'A';
+
+ break;
+
+ default:
+ throw new \InvalidArgumentException('Year must be between 1800 and 2099 inclusive.');
+ }
+
+ $randomDigits = self::numberBetween(0, 89);
+
+ if ($gender && $gender == static::GENDER_MALE) {
+ if ($randomDigits === 0) {
+ $randomDigits .= static::randomElement([3, 5, 7, 9]);
+ } else {
+ $randomDigits .= static::randomElement([1, 3, 5, 7, 9]);
+ }
+ } elseif ($gender && $gender == static::GENDER_FEMALE) {
+ if ($randomDigits === 0) {
+ $randomDigits .= static::randomElement([2, 4, 6, 8]);
+ } else {
+ $randomDigits .= static::randomElement([0, 2, 4, 6, 8]);
+ }
+ } else {
+ if ($randomDigits === 0) {
+ $randomDigits .= self::numberBetween(2, 9);
+ } else {
+ $randomDigits .= (string) static::numerify('#');
+ }
+ }
+ $randomDigits = str_pad($randomDigits, 3, '0', STR_PAD_LEFT);
+
+ $checksum = $checksumCharacters[(int) ($datePart . $randomDigits) % strlen($checksumCharacters)];
+
+ return $datePart . $centurySign . $randomDigits . $checksum;
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/fi_FI/PhoneNumber.php b/vendor/fakerphp/faker/src/Faker/Provider/fi_FI/PhoneNumber.php
new file mode 100755
index 00000000..db06ce26
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/fi_FI/PhoneNumber.php
@@ -0,0 +1,101 @@
+ 'Argovie'],
+ ['AI' => 'Appenzell Rhodes-Intérieures'],
+ ['AR' => 'Appenzell Rhodes-Extérieures'],
+ ['BE' => 'Berne'],
+ ['BL' => 'Bâle-Campagne'],
+ ['BS' => 'Bâle-Ville'],
+ ['FR' => 'Fribourg'],
+ ['GE' => 'Genève'],
+ ['GL' => 'Glaris'],
+ ['GR' => 'Grisons'],
+ ['JU' => 'Jura'],
+ ['LU' => 'Lucerne'],
+ ['NE' => 'Neuchâtel'],
+ ['NW' => 'Nidwald'],
+ ['OW' => 'Obwald'],
+ ['SG' => 'Saint-Gall'],
+ ['SH' => 'Schaffhouse'],
+ ['SO' => 'Soleure'],
+ ['SZ' => 'Schwytz'],
+ ['TG' => 'Thurgovie'],
+ ['TI' => 'Tessin'],
+ ['UR' => 'Uri'],
+ ['VD' => 'Vaud'],
+ ['VS' => 'Valais'],
+ ['ZG' => 'Zoug'],
+ ['ZH' => 'Zurich'],
+ ];
+
+ protected static $cityFormats = [
+ '{{cityName}}',
+ ];
+
+ protected static $streetNameFormats = [
+ '{{streetPrefix}} {{lastName}}',
+ '{{streetPrefix}} de {{cityName}}',
+ '{{streetPrefix}} de {{lastName}}',
+ ];
+
+ protected static $streetAddressFormats = [
+ '{{streetName}} {{buildingNumber}}',
+ ];
+ protected static $addressFormats = [
+ "{{streetAddress}}\n{{postcode}} {{city}}",
+ ];
+
+ /**
+ * Returns a random street prefix
+ *
+ * @example Rue
+ *
+ * @return string
+ */
+ public static function streetPrefix()
+ {
+ return static::randomElement(static::$streetPrefix);
+ }
+
+ /**
+ * Returns a random city name.
+ *
+ * @example Luzern
+ *
+ * @return string
+ */
+ public function cityName()
+ {
+ return static::randomElement(static::$cityNames);
+ }
+
+ /**
+ * Returns a canton
+ *
+ * @example array('BE' => 'Bern')
+ *
+ * @return array
+ */
+ public static function canton()
+ {
+ return static::randomElement(static::$canton);
+ }
+
+ /**
+ * Returns the abbreviation of a canton.
+ *
+ * @return string
+ */
+ public static function cantonShort()
+ {
+ $canton = static::canton();
+
+ return key($canton);
+ }
+
+ /**
+ * Returns the name of canton.
+ *
+ * @return string
+ */
+ public static function cantonName()
+ {
+ $canton = static::canton();
+
+ return current($canton);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/fr_CH/Color.php b/vendor/fakerphp/faker/src/Faker/Provider/fr_CH/Color.php
new file mode 100755
index 00000000..6deb9f83
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/fr_CH/Color.php
@@ -0,0 +1,7 @@
+ 'Ain'], ['02' => 'Aisne'], ['03' => 'Allier'], ['04' => 'Alpes-de-Haute-Provence'], ['05' => 'Hautes-Alpes'],
+ ['06' => 'Alpes-Maritimes'], ['07' => 'Ardèche'], ['08' => 'Ardennes'], ['09' => 'Ariège'], ['10' => 'Aube'],
+ ['11' => 'Aude'], ['12' => 'Aveyron'], ['13' => 'Bouches-du-Rhône'], ['14' => 'Calvados'], ['15' => 'Cantal'],
+ ['16' => 'Charente'], ['17' => 'Charente-Maritime'], ['18' => 'Cher'], ['19' => 'Corrèze'], ['2A' => 'Corse-du-Sud'],
+ ['2B' => 'Haute-Corse'], ['21' => "Côte-d'Or"], ['22' => "Côtes-d'Armor"], ['23' => 'Creuse'], ['24' => 'Dordogne'],
+ ['25' => 'Doubs'], ['26' => 'Drôme'], ['27' => 'Eure'], ['28' => 'Eure-et-Loir'], ['29' => 'Finistère'], ['30' => 'Gard'],
+ ['31' => 'Haute-Garonne'], ['32' => 'Gers'], ['33' => 'Gironde'], ['34' => 'Hérault'], ['35' => 'Ille-et-Vilaine'],
+ ['36' => 'Indre'], ['37' => 'Indre-et-Loire'], ['38' => 'Isère'], ['39' => 'Jura'], ['40' => 'Landes'], ['41' => 'Loir-et-Cher'],
+ ['42' => 'Loire'], ['43' => 'Haute-Loire'], ['44' => 'Loire-Atlantique'], ['45' => 'Loiret'], ['46' => 'Lot'],
+ ['47' => 'Lot-et-Garonne'], ['48' => 'Lozère'], ['49' => 'Maine-et-Loire'], ['50' => 'Manche'], ['51' => 'Marne'],
+ ['52' => 'Haute-Marne'], ['53' => 'Mayenne'], ['54' => 'Meurthe-et-Moselle'], ['55' => 'Meuse'], ['56' => 'Morbihan'],
+ ['57' => 'Moselle'], ['58' => 'Nièvre'], ['59' => 'Nord'], ['60' => 'Oise'], ['61' => 'Orne'], ['62' => 'Pas-de-Calais'],
+ ['63' => 'Puy-de-Dôme'], ['64' => 'Pyrénées-Atlantiques'], ['65' => 'Hautes-Pyrénées'], ['66' => 'Pyrénées-Orientales'],
+ ['67' => 'Bas-Rhin'], ['68' => 'Haut-Rhin'], ['69' => 'Rhône'], ['70' => 'Haute-Saône'], ['71' => 'Saône-et-Loire'],
+ ['72' => 'Sarthe'], ['73' => 'Savoie'], ['74' => 'Haute-Savoie'], ['75' => 'Paris'], ['76' => 'Seine-Maritime'],
+ ['77' => 'Seine-et-Marne'], ['78' => 'Yvelines'], ['79' => 'Deux-Sèvres'], ['80' => 'Somme'], ['81' => 'Tarn'],
+ ['82' => 'Tarn-et-Garonne'], ['83' => 'Var'], ['84' => 'Vaucluse'], ['85' => 'Vendée'], ['86' => 'Vienne'],
+ ['87' => 'Haute-Vienne'], ['88' => 'Vosges'], ['89' => 'Yonne'], ['90' => 'Territoire de Belfort'], ['91' => 'Essonne'],
+ ['92' => 'Hauts-de-Seine'], ['93' => 'Seine-Saint-Denis'], ['94' => 'Val-de-Marne'], ['95' => "Val-d'Oise"],
+ ['971' => 'Guadeloupe'], ['972' => 'Martinique'], ['973' => 'Guyane'], ['974' => 'La Réunion'], ['976' => 'Mayotte'],
+ ];
+
+ protected static $secondaryAddressFormats = ['Apt. ###', 'Suite ###', 'Étage ###', 'Bât. ###', 'Chambre ###'];
+
+ /**
+ * @example 'Appt. 350'
+ */
+ public static function secondaryAddress()
+ {
+ return static::numerify(static::randomElement(static::$secondaryAddressFormats));
+ }
+
+ /**
+ * @example 'rue'
+ */
+ public static function streetPrefix()
+ {
+ return static::randomElement(static::$streetPrefix);
+ }
+
+ /**
+ * Randomly returns a french region.
+ *
+ * @example 'Guadeloupe'
+ *
+ * @return string
+ */
+ public static function region()
+ {
+ return static::randomElement(static::$regions);
+ }
+
+ /**
+ * Randomly returns a french department ('departmentNumber' => 'departmentName').
+ *
+ * @example array('2B' => 'Haute-Corse')
+ *
+ * @return array
+ */
+ public static function department()
+ {
+ return static::randomElement(static::$departments);
+ }
+
+ /**
+ * Randomly returns a french department name.
+ *
+ * @example 'Ardèche'
+ *
+ * @return string
+ */
+ public static function departmentName()
+ {
+ $randomDepartmentName = array_values(static::department());
+
+ return $randomDepartmentName[0];
+ }
+
+ /**
+ * Randomly returns a french department number.
+ *
+ * @example '59'
+ *
+ * @return string
+ */
+ public static function departmentNumber()
+ {
+ $randomDepartmentNumber = array_keys(static::department());
+
+ return $randomDepartmentNumber[0];
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/fr_FR/Color.php b/vendor/fakerphp/faker/src/Faker/Provider/fr_FR/Color.php
new file mode 100755
index 00000000..a0048ac4
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/fr_FR/Color.php
@@ -0,0 +1,40 @@
+generator->parse($format));
+
+ if ($this->isCatchPhraseValid($catchPhrase)) {
+ break;
+ }
+ } while (true);
+
+ return $catchPhrase;
+ }
+
+ /**
+ * Generates a siret number (14 digits) that passes the Luhn check.
+ *
+ * @see http://fr.wikipedia.org/wiki/Syst%C3%A8me_d'identification_du_r%C3%A9pertoire_des_%C3%A9tablissements
+ *
+ * @return string
+ */
+ public function siret($formatted = true)
+ {
+ $siret = self::siren(false);
+ $nicFormat = static::randomElement(static::$siretNicFormats);
+ $siret .= $this->numerify($nicFormat);
+ $siret .= Luhn::computeCheckDigit($siret);
+
+ if ($formatted) {
+ $siret = substr($siret, 0, 3) . ' ' . substr($siret, 3, 3) . ' ' . substr($siret, 6, 3) . ' ' . substr($siret, 9, 5);
+ }
+
+ return $siret;
+ }
+
+ /**
+ * Generates a siren number (9 digits) that passes the Luhn check.
+ *
+ * @see http://fr.wikipedia.org/wiki/Syst%C3%A8me_d%27identification_du_r%C3%A9pertoire_des_entreprises
+ *
+ * @return string
+ */
+ public static function siren($formatted = true)
+ {
+ $siren = self::numerify('%#######');
+ $siren .= Luhn::computeCheckDigit($siren);
+
+ if ($formatted) {
+ $siren = substr($siren, 0, 3) . ' ' . substr($siren, 3, 3) . ' ' . substr($siren, 6, 3);
+ }
+
+ return $siren;
+ }
+
+ /**
+ * @var array An array containing string which should not appear twice in a catch phrase.
+ */
+ protected static $wordsWhichShouldNotAppearTwice = ['sécurité', 'simpl'];
+
+ /**
+ * Validates a french catch phrase.
+ *
+ * @param string $catchPhrase The catch phrase to validate.
+ *
+ * @return bool (true if valid, false otherwise)
+ */
+ protected static function isCatchPhraseValid($catchPhrase)
+ {
+ foreach (static::$wordsWhichShouldNotAppearTwice as $word) {
+ // Fastest way to check if a piece of word does not appear twice.
+ $beginPos = strpos($catchPhrase, $word);
+ $endPos = strrpos($catchPhrase, $word);
+
+ if ($beginPos !== false && $beginPos != $endPos) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @see http://www.pole-emploi.fr/candidat/le-code-rome-et-les-fiches-metiers-@/article.jspz?id=60702
+ *
+ * @note Randomly took 300 from this list
+ */
+ protected static $jobTitleFormat = [
+ 'Agent d\'accueil',
+ 'Agent d\'enquêtes',
+ 'Agent d\'entreposage',
+ 'Agent de curage',
+ 'Agro-économiste',
+ 'Aide couvreur',
+ 'Aide à domicile',
+ 'Aide-déménageur',
+ 'Ambassadeur',
+ 'Analyste télématique',
+ 'Animateur d\'écomusée',
+ 'Animateur web',
+ 'Appareilleur-gazier',
+ 'Archéologue',
+ 'Armurier d\'art',
+ 'Armurier spectacle',
+ 'Artificier spectacle',
+ 'Artiste dramatique',
+ 'Aspigiculteur',
+ 'Assistant de justice',
+ 'Assistant des ventes',
+ 'Assistant logistique',
+ 'Assistant styliste',
+ 'Assurance',
+ 'Auteur-adaptateur',
+ 'Billettiste voyages',
+ 'Brigadier',
+ 'Bruiteur',
+ 'Bâtonnier d\'art',
+ 'Bûcheron',
+ 'Cameraman',
+ 'Capitaine de pêche',
+ 'Carrier',
+ 'Caviste',
+ 'Chansonnier',
+ 'Chanteur',
+ 'Chargé de recherche',
+ 'Chasseur-bagagiste',
+ 'Chef de fabrication',
+ 'Chef de scierie',
+ 'Chef des ventes',
+ 'Chef du personnel',
+ 'Chef géographe',
+ 'Chef monteur son',
+ 'Chef porion',
+ 'Chiropraticien',
+ 'Choréologue',
+ 'Chromiste',
+ 'Cintrier-machiniste',
+ 'Clerc hors rang',
+ 'Coach sportif',
+ 'Coffreur béton armé',
+ 'Coffreur-ferrailleur',
+ 'Commandant de police',
+ 'Commandant marine',
+ 'Commis de coupe',
+ 'Comptable unique',
+ 'Conception et études',
+ 'Conducteur de jumbo',
+ 'Conseiller culinaire',
+ 'Conseiller funéraire',
+ 'Conseiller relooking',
+ 'Consultant ergonome',
+ 'Contrebassiste',
+ 'Convoyeur garde',
+ 'Copiste offset',
+ 'Corniste',
+ 'Costumier-habilleur',
+ 'Coutelier d\'art',
+ 'Cueilleur de cerises',
+ 'Céramiste concepteur',
+ 'Danse',
+ 'Danseur',
+ 'Data manager',
+ 'Dee-jay',
+ 'Designer produit',
+ 'Diététicien conseil',
+ 'Diététique',
+ 'Doreur sur métaux',
+ 'Décorateur-costumier',
+ 'Défloqueur d\'amiante',
+ 'Dégustateur',
+ 'Délégué vétérinaire',
+ 'Délégué à la tutelle',
+ 'Désamianteur',
+ 'Détective',
+ 'Développeur web',
+ 'Ecotoxicologue',
+ 'Elagueur-botteur',
+ 'Elagueur-grimpeur',
+ 'Elastiqueur',
+ 'Eleveur d\'insectes',
+ 'Eleveur de chats',
+ 'Eleveur de volailles',
+ 'Embouteilleur',
+ 'Employé d\'accueil',
+ 'Employé d\'étage',
+ 'Employé de snack-bar',
+ 'Endivier',
+ 'Endocrinologue',
+ 'Epithésiste',
+ 'Essayeur-retoucheur',
+ 'Etainier',
+ 'Etancheur',
+ 'Etancheur-bardeur',
+ 'Etiqueteur',
+ 'Expert back-office',
+ 'Exploitant de tennis',
+ 'Extraction',
+ 'Facteur',
+ 'Facteur de clavecins',
+ 'Facteur de secteur',
+ 'Fantaisiste',
+ 'Façadier-bardeur',
+ 'Façadier-ravaleur',
+ 'Feutier',
+ 'Finance',
+ 'Flaconneur',
+ 'Foreur pétrole',
+ 'Formateur d\'italien',
+ 'Fossoyeur',
+ 'Fraiseur',
+ 'Fraiseur mouliste',
+ 'Frigoriste maritime',
+ 'Fromager',
+ 'Galeriste',
+ 'Gardien de résidence',
+ 'Garçon de chenil',
+ 'Garçon de hall',
+ 'Gendarme mobile',
+ 'Guitariste',
+ 'Gynécologue',
+ 'Géodésien',
+ 'Géologue prospecteur',
+ 'Géomètre',
+ 'Géomètre du cadastre',
+ 'Gérant d\'hôtel',
+ 'Gérant de tutelle',
+ 'Gériatre',
+ 'Hydrothérapie',
+ 'Hématologue',
+ 'Hôte de caisse',
+ 'Ingénieur bâtiment',
+ 'Ingénieur du son',
+ 'Ingénieur géologue',
+ 'Ingénieur géomètre',
+ 'Ingénieur halieute',
+ 'Ingénieur logistique',
+ 'Instituteur',
+ 'Jointeur de placage',
+ 'Juge des enfants',
+ 'Juriste financier',
+ 'Kiwiculteur',
+ 'Lexicographe',
+ 'Liftier',
+ 'Litigeur transport',
+ 'Logistique',
+ 'Logopède',
+ 'Magicien',
+ 'Manager d\'artiste',
+ 'Mannequin détail',
+ 'Maquilleur spectacle',
+ 'Marbrier-poseur',
+ 'Marin grande pêche',
+ 'Matelassier',
+ 'Maçon',
+ 'Maçon-fumiste',
+ 'Maçonnerie',
+ 'Maître de ballet',
+ 'Maïeuticien',
+ 'Menuisier',
+ 'Miroitier',
+ 'Modéliste industriel',
+ 'Moellonneur',
+ 'Moniteur de sport',
+ 'Monteur audiovisuel',
+ 'Monteur de fermettes',
+ 'Monteur de palettes',
+ 'Monteur en siège',
+ 'Monteur prototypiste',
+ 'Monteur-frigoriste',
+ 'Monteur-truquiste',
+ 'Mouleur sable',
+ 'Mouliste drapeur',
+ 'Mécanicien-armurier',
+ 'Médecin du sport',
+ 'Médecin scolaire',
+ 'Médiateur judiciaire',
+ 'Médiathécaire',
+ 'Net surfeur surfeuse',
+ 'Oenologue',
+ 'Opérateur de plateau',
+ 'Opérateur du son',
+ 'Opérateur géomètre',
+ 'Opérateur piquage',
+ 'Opérateur vidéo',
+ 'Ouvrier d\'abattoir',
+ 'Ouvrier serriste',
+ 'Ouvrier sidérurgiste',
+ 'Palefrenier',
+ 'Paléontologue',
+ 'Pareur en abattoir',
+ 'Parfumeur',
+ 'Parqueteur',
+ 'Percepteur',
+ 'Photographe d\'art',
+ 'Pilote automobile',
+ 'Pilote de soutireuse',
+ 'Pilote fluvial',
+ 'Piqueur en ganterie',
+ 'Pisteur secouriste',
+ 'Pizzaïolo',
+ 'Plaquiste enduiseur',
+ 'Plasticien',
+ 'Plisseur',
+ 'Poissonnier-traiteur',
+ 'Pontonnier',
+ 'Porion',
+ 'Porteur de hottes',
+ 'Porteur de journaux',
+ 'Portier',
+ 'Poseur de granit',
+ 'Posticheur spectacle',
+ 'Potier',
+ 'Praticien dentaire',
+ 'Praticiens médicaux',
+ 'Premier clerc',
+ 'Preneur de son',
+ 'Primeuriste',
+ 'Professeur d\'italien',
+ 'Projeteur béton armé',
+ 'Promotion des ventes',
+ 'Présentateur radio',
+ 'Pyrotechnicien',
+ 'Pédicure pour bovin',
+ 'Pédologue',
+ 'Pédopsychiatre',
+ 'Quincaillier',
+ 'Radio chargeur',
+ 'Ramasseur d\'asperges',
+ 'Ramasseur d\'endives',
+ 'Ravaleur-ragréeur',
+ 'Recherche',
+ 'Recuiseur',
+ 'Relieur-doreur',
+ 'Responsable de salle',
+ 'Responsable télécoms',
+ 'Revenue Manager',
+ 'Rippeur spectacle',
+ 'Rogneur',
+ 'Récupérateur',
+ 'Rédacteur des débats',
+ 'Régleur funéraire',
+ 'Régleur sur tour',
+ 'Sapeur-pompier',
+ 'Scannériste',
+ 'Scripte télévision',
+ 'Sculpteur sur verre',
+ 'Scénariste',
+ 'Second de cuisine',
+ 'Secrétaire juridique',
+ 'Semencier',
+ 'Sertisseur',
+ 'Services funéraires',
+ 'Solier-moquettiste',
+ 'Sommelier',
+ 'Sophrologue',
+ 'Staffeur',
+ 'Story boarder',
+ 'Stratifieur',
+ 'Stucateur',
+ 'Styliste graphiste',
+ 'Surjeteur-raseur',
+ 'Séismologue',
+ 'Technicien agricole',
+ 'Technicien bovin',
+ 'Technicien géomètre',
+ 'Technicien plateau',
+ 'Technicien énergie',
+ 'Terminologue',
+ 'Testeur informatique',
+ 'Toiliste',
+ 'Topographe',
+ 'Toréro',
+ 'Traducteur d\'édition',
+ 'Traffic manager',
+ 'Trieur de métaux',
+ 'Turbinier',
+ 'Téléconseiller',
+ 'Tôlier-traceur',
+ 'Vendeur carreau',
+ 'Vendeur en lingerie',
+ 'Vendeur en meubles',
+ 'Vendeur en épicerie',
+ 'Verrier d\'art',
+ 'Verrier à la calotte',
+ 'Verrier à la main',
+ 'Verrier à main levée',
+ 'Vidéo-jockey',
+ 'Vitrier',
+ ];
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/fr_FR/Internet.php b/vendor/fakerphp/faker/src/Faker/Provider/fr_FR/Internet.php
new file mode 100755
index 00000000..679919da
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/fr_FR/Internet.php
@@ -0,0 +1,9 @@
+numberBetween(1, 2);
+ }
+
+ $nir .=
+ // Year of birth (aa)
+ $this->numerify('##') .
+ // Mont of birth (mm)
+ sprintf('%02d', $this->numberBetween(1, 12));
+
+ // Department
+ $department = key(Address::department());
+ $nir .= $department;
+
+ // Town number, depends on department length
+ if (strlen($department) === 2) {
+ $nir .= $this->numerify('###');
+ } elseif (strlen($department) === 3) {
+ $nir .= $this->numerify('##');
+ }
+
+ // Born number (depending of town and month of birth)
+ $nir .= $this->numerify('###');
+
+ /**
+ * The key for a given NIR is `97 - 97 % NIR`
+ * NIR has to be an integer, so we have to do a little replacment
+ * for departments 2A and 2B
+ */
+ if ($department === '2A') {
+ $nirInteger = str_replace('2A', '19', $nir);
+ } elseif ($department === '2B') {
+ $nirInteger = str_replace('2B', '18', $nir);
+ } else {
+ $nirInteger = $nir;
+ }
+ $nir .= sprintf('%02d', 97 - $nirInteger % 97);
+
+ // Format is x xx xx xx xxx xxx xx
+ if ($formatted) {
+ $nir = substr($nir, 0, 1) . ' ' . substr($nir, 1, 2) . ' ' . substr($nir, 3, 2) . ' ' . substr($nir, 5, 2) . ' ' . substr($nir, 7, 3) . ' ' . substr($nir, 10, 3) . ' ' . substr($nir, 13, 2);
+ }
+
+ return $nir;
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/fr_FR/PhoneNumber.php b/vendor/fakerphp/faker/src/Faker/Provider/fr_FR/PhoneNumber.php
new file mode 100755
index 00000000..69c681d9
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/fr_FR/PhoneNumber.php
@@ -0,0 +1,148 @@
+phoneNumber07WithSeparator();
+
+ return str_replace(' ', '', $phoneNumber);
+ }
+
+ /**
+ * Only 073 to 079 are acceptable prefixes with 07
+ *
+ * @see http://www.arcep.fr/index.php?id=8146
+ */
+ public function phoneNumber07WithSeparator()
+ {
+ $phoneNumber = $this->generator->numberBetween(3, 9);
+ $phoneNumber .= $this->numerify('# ## ## ##');
+
+ return $phoneNumber;
+ }
+
+ public function phoneNumber08()
+ {
+ $phoneNumber = $this->phoneNumber08WithSeparator();
+
+ return str_replace(' ', '', $phoneNumber);
+ }
+
+ /**
+ * Valid formats for 08:
+ *
+ * 0# ## ## ##
+ * 1# ## ## ##
+ * 2# ## ## ##
+ * 91 ## ## ##
+ * 92 ## ## ##
+ * 93 ## ## ##
+ * 97 ## ## ##
+ * 98 ## ## ##
+ * 99 ## ## ##
+ *
+ * Formats 089(4|6)## ## ## are valid, but will be
+ * attributed when other 089 resource ranges are exhausted.
+ *
+ * @see https://www.arcep.fr/index.php?id=8146#c9625
+ * @see https://issuetracker.google.com/u/1/issues/73269839
+ */
+ public function phoneNumber08WithSeparator()
+ {
+ $regex = '([012]{1}\d{1}|(9[1-357-9])( \d{2}){3}';
+
+ return $this->regexify($regex);
+ }
+
+ /**
+ * @example '0601020304'
+ */
+ public function mobileNumber()
+ {
+ $format = static::randomElement(static::$mobileFormats);
+
+ return static::numerify($this->generator->parse($format));
+ }
+
+ /**
+ * @example '0891951357'
+ */
+ public function serviceNumber()
+ {
+ $format = static::randomElement(static::$serviceFormats);
+
+ return static::numerify($this->generator->parse($format));
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/fr_FR/Text.php b/vendor/fakerphp/faker/src/Faker/Provider/fr_FR/Text.php
new file mode 100755
index 00000000..bcd3167a
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/fr_FR/Text.php
@@ -0,0 +1,15532 @@
+ static::latitude(46.262740, 47.564721),
+ 'longitude' => static::longitude(17.077949, 20.604560),
+ ];
+ }
+
+ protected static $streetSuffix = [
+ 'árok', 'átjáró', 'dűlősor', 'dűlőút', 'erdősor', 'fasor', 'forduló', 'gát', 'határsor', 'határút', 'híd', 'játszótér', 'kert', 'körönd', 'körtér', 'körút', 'köz', 'lakótelep', 'lejáró', 'lejtő', 'lépcső', 'liget', 'mélyút', 'orom', 'országút', 'ösvény', 'park', 'part', 'pincesor', 'rakpart', 'sétány', 'sétaút', 'sor', 'sugárút', 'tér', 'tere', 'turistaút', 'udvar', 'út', 'útja', 'utca', 'üdülőpart',
+ ];
+ protected static $postcode = ['####'];
+ protected static $state = [
+ 'Budapest', 'Bács-Kiskun', 'Baranya', 'Békés', 'Borsod-Abaúj-Zemplén', 'Csongrád', 'Fejér', 'Győr-Moson-Sopron', 'Hajdú-Bihar', 'Heves', 'Jász-Nagykun-Szolnok', 'Komárom-Esztergom', 'Nógrád', 'Pest', 'Somogy', 'Szabolcs-Szatmár-Bereg', 'Tolna', 'Vas', 'Veszprém', 'Zala',
+ ];
+ protected static $country = [
+ 'Afganisztán', 'Albánia', 'Algéria', 'Amerikai Egyesült Államok', 'Andorra', 'Angola', 'Antigua és Barbuda', 'Argentína', 'Ausztria', 'Ausztrália', 'Azerbajdzsán',
+ 'Bahama-szigetek', 'Bahrein', 'Banglades', 'Barbados', 'Belgium', 'Belize', 'Benin', 'Bhután', 'Bolívia', 'Bosznia-Hercegovina', 'Botswana', 'Brazília', 'Brunei', 'Bulgária', 'Burkina Faso', 'Burma', 'Burundi',
+ 'Chile', 'Ciprus', 'Costa Rica', 'Csehország', 'Csád',
+ 'Dominikai Köztársaság', 'Dominikai Közösség', 'Dzsibuti', 'Dánia', 'Dél-Afrika', 'Dél-Korea', 'Dél-Szudán',
+ 'Ecuador', 'Egyenlítői-Guinea', 'Egyesült Arab Emírségek', 'Egyesült Királyság', 'Egyiptom', 'Elefántcsontpart', 'Eritrea', 'Etiópia',
+ 'Fehéroroszország', 'Fidzsi-szigetek', 'Finnország', 'Franciaország', 'Fülöp-szigetek',
+ 'Gabon', 'Gambia', 'Ghána', 'Grenada', 'Grúzia', 'Guatemala', 'Guinea', 'Guyana', 'Görögország',
+ 'Haiti', 'Hollandia', 'Horvátország',
+ 'India', 'Indonézia', 'Irak', 'Irán', 'Izland', 'Izrael',
+ 'Japán', 'Jemen', 'Jordánia',
+ 'Kambodzsa', 'Kamerun', 'Kanada', 'Katar', 'Kazahsztán', 'Kelet-Timor', 'Kenya', 'Kirgizisztán', 'Kiribati', 'Kolumbia', 'Kongói Demokratikus Köztársaság', 'Kongói Köztársaság', 'Kuba', 'Kuvait', 'Kína', 'Közép-Afrika',
+ 'Laosz', 'Lengyelország', 'Lesotho', 'Lettország', 'Libanon', 'Libéria', 'Liechtenstein', 'Litvánia', 'Luxemburg', 'Líbia',
+ 'Macedónia', 'Madagaszkár', 'Magyarország', 'Malawi', 'Maldív-szigetek', 'Mali', 'Malájzia', 'Marokkó', 'Marshall-szigetek', 'Mauritánia', 'Mexikó', 'Mikronézia', 'Moldova', 'Monaco', 'Mongólia', 'Montenegró', 'Mozambik', 'Málta',
+ 'Namíbia', 'Nauru', 'Nepál', 'Nicaragua', 'Niger', 'Nigéria', 'Norvégia', 'Németország',
+ 'Olaszország', 'Omán', 'Oroszország',
+ 'Pakisztán', 'Palau', 'Panama', 'Paraguay', 'Peru', 'Portugália', 'Pápua Új-Guinea',
+ 'Románia', 'Ruanda',
+ 'Saint Kitts és Nevis', 'Saint Vincent', 'Salamon-szigetek', 'Salvador', 'San Marino', 'Seychelle-szigetek', 'Spanyolország', 'Srí Lanka', 'Suriname', 'Svájc', 'Svédország', 'Szamoa', 'Szaúd-Arábia', 'Szenegál', 'Szerbia', 'Szingapúr', 'Szlovákia', 'Szlovénia', 'Szomália', 'Szudán', 'Szváziföld', 'Szíria', 'São Tomé és Príncipe',
+ 'Tadzsikisztán', 'Tanzánia', 'Thaiföld', 'Togo', 'Tonga', 'Trinidad és Tobago', 'Tunézia', 'Tuvalu', 'Törökország', 'Türkmenisztán',
+ 'Uganda', 'Ukrajna', 'Uruguay',
+ 'Vanuatu', 'Venezuela', 'Vietnám',
+ 'Zambia', 'Zimbabwe', 'Zöld-foki-szigetek',
+ 'Észak-Korea', 'Észtország', 'Írország', 'Örményország', 'Új-Zéland', 'Üzbegisztán',
+ ];
+
+ /**
+ * Source: https://hu.wikipedia.org/wiki/Magyarorsz%C3%A1g_v%C3%A1rosainak_list%C3%A1ja
+ */
+ protected static $capitals = ['Budapest'];
+ protected static $bigCities = [
+ 'Békéscsaba', 'Debrecen', 'Dunaújváros', 'Eger', 'Érd', 'Győr', 'Hódmezővásárhely', 'Kaposvár', 'Kecskemét', 'Miskolc', 'Nagykanizsa', 'Nyíregyháza', 'Pécs', 'Salgótarján', 'Sopron', 'Szeged', 'Székesfehérvár', 'Szekszárd', 'Szolnok', 'Szombathely', 'Tatabánya', 'Veszprém', 'Zalaegerszeg',
+ ];
+ protected static $smallerCities = [
+ 'Ajka', 'Aszód', 'Bácsalmás',
+ 'Baja', 'Baktalórántháza', 'Balassagyarmat', 'Balatonalmádi', 'Balatonfüred', 'Balmazújváros', 'Barcs', 'Bátonyterenye', 'Békés', 'Bélapátfalva', 'Berettyóújfalu', 'Bicske', 'Bóly', 'Bonyhád', 'Budakeszi',
+ 'Cegléd', 'Celldömölk', 'Cigánd', 'Csenger', 'Csongrád', 'Csorna', 'Csurgó',
+ 'Dabas', 'Derecske', 'Devecser', 'Dombóvár', 'Dunakeszi',
+ 'Edelény', 'Encs', 'Enying', 'Esztergom',
+ 'Fehérgyarmat', 'Fonyód', 'Füzesabony',
+ 'Gárdony', 'Gödöllő', 'Gönc', 'Gyál', 'Gyomaendrőd', 'Gyöngyös', 'Gyula',
+ 'Hajdúböszörmény', 'Hajdúhadház', 'Hajdúnánás', 'Hajdúszoboszló', 'Hatvan', 'Heves',
+ 'Ibrány',
+ 'Jánoshalma', 'Jászapáti', 'Jászberény',
+ 'Kalocsa', 'Kapuvár', 'Karcag', 'Kazincbarcika', 'Kemecse', 'Keszthely', 'Kisbér', 'Kiskőrös', 'Kiskunfélegyháza', 'Kiskunhalas', 'Kiskunmajsa', 'Kistelek', 'Kisvárda', 'Komárom', 'Komló', 'Körmend', 'Kőszeg', 'Kunhegyes', 'Kunszentmárton', 'Kunszentmiklós',
+ 'Lenti', 'Letenye',
+ 'Makó', 'Marcali', 'Martonvásár', 'Mátészalka', 'Mezőcsát', 'Mezőkovácsháza', 'Mezőkövesd', 'Mezőtúr', 'Mohács', 'Monor', 'Mór', 'Mórahalom', 'Mosonmagyaróvár',
+ 'Nagyatád', 'Nagykálló', 'Nagykáta', 'Nagykőrös', 'Nyíradony', 'Nyírbátor',
+ 'Orosháza', 'Oroszlány', 'Ózd',
+ 'Paks', 'Pannonhalma', 'Pápa', 'Pásztó', 'Pécsvárad', 'Pétervására', 'Pilisvörösvár', 'Polgárdi', 'Püspökladány', 'Putnok',
+ 'Ráckeve', 'Rétság',
+ 'Sárbogárd', 'Sarkad', 'Sárospatak', 'Sárvár', 'Sásd', 'Sátoraljaújhely', 'Sellye', 'Siklós', 'Siófok', 'Sümeg', 'Szarvas', 'Szécsény', 'Szeghalom', 'Szentendre', 'Szentes', 'Szentgotthárd', 'Szentlőrinc', 'Szerencs', 'Szigetszentmiklós', 'Szigetvár', 'Szikszó', 'Szob',
+ 'Tab', 'Tamási', 'Tapolca', 'Tata', 'Tét', 'Tiszafüred', 'Tiszakécske', 'Tiszaújváros', 'Tiszavasvári', 'Tokaj', 'Tolna', 'Törökszentmiklós',
+ 'Vác', 'Várpalota', 'Vásárosnamény', 'Vasvár', 'Vecsés',
+ 'Záhony', 'Zalaszentgrót', 'Zirc',
+ ];
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/hu_HU/Company.php b/vendor/fakerphp/faker/src/Faker/Provider/hu_HU/Company.php
new file mode 100755
index 00000000..75931991
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/hu_HU/Company.php
@@ -0,0 +1,13 @@
+generator->parse($format);
+ }
+
+ public static function country()
+ {
+ return static::randomElement(static::$country);
+ }
+
+ public static function postcode()
+ {
+ return static::toUpper(static::bothify(static::randomElement(static::$postcode)));
+ }
+
+ public static function regionSuffix()
+ {
+ return static::randomElement(static::$regionSuffix);
+ }
+
+ public static function region()
+ {
+ return static::randomElement(static::$region);
+ }
+
+ public static function cityPrefix()
+ {
+ return static::randomElement(static::$cityPrefix);
+ }
+
+ public function city()
+ {
+ return static::randomElement(static::$city);
+ }
+
+ public function streetPrefix()
+ {
+ return static::randomElement(static::$streetPrefix);
+ }
+
+ public static function street()
+ {
+ return static::randomElement(static::$street);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/hy_AM/Color.php b/vendor/fakerphp/faker/src/Faker/Provider/hy_AM/Color.php
new file mode 100755
index 00000000..ebdda0da
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/hy_AM/Color.php
@@ -0,0 +1,12 @@
+generator->parse(static::randomElement(static::$formats)));
+ }
+
+ public function code()
+ {
+ return static::randomElement(static::$codes);
+ }
+
+ public function numberFormat()
+ {
+ return static::randomElement(static::$numberFormats);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/id_ID/Address.php b/vendor/fakerphp/faker/src/Faker/Provider/id_ID/Address.php
new file mode 100755
index 00000000..28dd845c
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/id_ID/Address.php
@@ -0,0 +1,319 @@
+generator->parse($format);
+ }
+
+ public static function street()
+ {
+ return static::randomElement(static::$street);
+ }
+
+ public static function buildingNumber()
+ {
+ return (string) self::numberBetween(1, 999);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/id_ID/Color.php b/vendor/fakerphp/faker/src/Faker/Provider/id_ID/Color.php
new file mode 100755
index 00000000..14995b62
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/id_ID/Color.php
@@ -0,0 +1,40 @@
+generator->parse($lastNameRandomElement);
+ }
+
+ /**
+ * Return last name for male
+ *
+ * @return string last name
+ */
+ public static function lastNameMale()
+ {
+ return static::randomElement(static::$lastNameMale);
+ }
+
+ /**
+ * Return last name for female
+ *
+ * @return string last name
+ */
+ public static function lastNameFemale()
+ {
+ return static::randomElement(static::$lastNameFemale);
+ }
+
+ /**
+ * For academic title
+ *
+ * @return string suffix
+ */
+ public static function suffix()
+ {
+ return static::randomElement(static::$suffix);
+ }
+
+ /**
+ * Generates Nomor Induk Kependudukan (NIK)
+ *
+ * @see https://en.wikipedia.org/wiki/National_identification_number#Indonesia
+ *
+ * @param string|null $gender
+ * @param \DateTime|null $birthDate
+ *
+ * @return string
+ */
+ public function nik($gender = null, $birthDate = null)
+ {
+ // generate first numbers (region data)
+ $nik = $this->birthPlaceCode();
+ $nik .= $this->generator->numerify('##');
+
+ if (!$birthDate) {
+ $birthDate = $this->generator->dateTimeBetween();
+ }
+
+ if (!$gender) {
+ $gender = $this->generator->randomElement([self::GENDER_MALE, self::GENDER_FEMALE]);
+ }
+
+ // if gender is female, add 40 to days
+ if ($gender == self::GENDER_FEMALE) {
+ $nik .= $birthDate->format('d') + 40;
+ } else {
+ $nik .= $birthDate->format('d');
+ }
+
+ $nik .= $birthDate->format('my');
+
+ // add last random digits
+ $nik .= $this->generator->numerify('####');
+
+ return $nik;
+ }
+
+ /**
+ * Generates birth place code for NIK
+ *
+ * @see https://id.wikipedia.org/wiki/Nomor_Induk_Kependudukan
+ * @see http://informasipedia.com/wilayah-indonesia/daftar-kabupaten-kota-di-indonesia/
+ */
+ protected function birthPlaceCode()
+ {
+ return static::randomElement(static::$birthPlaceCode);
+ }
+}
diff --git a/vendor/fakerphp/faker/src/Faker/Provider/id_ID/PhoneNumber.php b/vendor/fakerphp/faker/src/Faker/Provider/id_ID/PhoneNumber.php
new file mode 100755
index 00000000..c0bfaf5b
--- /dev/null
+++ b/vendor/fakerphp/faker/src/Faker/Provider/id_ID/PhoneNumber.php
@@ -0,0 +1,55 @@
+ Icelandic names for women.
+ */
+ protected static $firstNameFemale = ['Aagot', 'Abela', 'Abigael', 'Ada', 'Adda', 'Addý', 'Adela', 'Adelía', 'Adríana', 'Aðalbjörg', 'Aðalbjört', 'Aðalborg', 'Aðaldís', 'Aðalfríður', 'Aðalheiður', 'Aðalrós', 'Aðalsteina', 'Aðalsteinunn', 'Aðalveig', 'Agata', 'Agatha', 'Agða', 'Agla', 'Agnea', 'Agnes', 'Agneta', 'Alanta', 'Alba', 'Alberta', 'Albína', 'Alda', 'Aldís', 'Aldný', 'Aleta', 'Aletta', 'Alexa', 'Alexandra', 'Alexandría', 'Alexis', 'Alexía', 'Alfa', 'Alfífa', 'Alice', 'Alida', 'Alída', 'Alína', 'Alís', 'Alísa', 'Alla', 'Allý', 'Alma', 'Alrún', 'Alva', 'Alvilda', 'Amadea', 'Amal', 'Amalía', 'Amanda', 'Amelía', 'Amilía', 'Amíra', 'Amy', 'Amý', 'Analía', 'Anastasía', 'Andra', 'Andrá', 'Andrea', 'Anetta', 'Angela', 'Angelíka', 'Anika', 'Anita', 'Aníka', 'Anína', 'Aníta', 'Anja', 'Ann', 'Anna', 'Annabella', 'Annalísa', 'Anne', 'Annelí', 'Annetta', 'Anney', 'Annika', 'Annía', 'Anný', 'Antonía', 'Apríl', 'Ardís', 'Arey', 'Arinbjörg', 'Aris', 'Arisa', 'Aría', 'Aríanna', 'Aríella', 'Arín', 'Arína', 'Arís', 'Armenía', 'Arna', 'Arnbjörg', 'Arnborg', 'Arndís', 'Arney', 'Arnfinna', 'Arnfríður', 'Arngerður', 'Arngunnur', 'Arnheiður', 'Arnhildur', 'Arnika', 'Arnkatla', 'Arnlaug', 'Arnleif', 'Arnlín', 'Arnljót', 'Arnóra', 'Arnrós', 'Arnrún', 'Arnþóra', 'Arnþrúður', 'Asírí', 'Askja', 'Assa', 'Astrid', 'Atalía', 'Atena', 'Athena', 'Atla', 'Atlanta', 'Auðbjörg', 'Auðbjört', 'Auðdís', 'Auðlín', 'Auðna', 'Auðný', 'Auðrún', 'Auður', 'Aurora', 'Axelía', 'Axelma', 'Aþena', 'Ágústa', 'Ágústína', 'Álfdís', 'Álfey', 'Álfgerður', 'Álfheiður', 'Álfhildur', 'Álfrós', 'Álfrún', 'Álfsól', 'Árbjörg', 'Árbjört', 'Árdís', 'Árelía', 'Árlaug', 'Ármey', 'Árna', 'Árndís', 'Árney', 'Árnheiður', 'Árnína', 'Árný', 'Áróra', 'Ársól', 'Ársæl', 'Árún', 'Árveig', 'Árvök', 'Árþóra', 'Ása', 'Ásbjörg', 'Ásborg', 'Ásdís', 'Ásfríður', 'Ásgerður', 'Áshildur', 'Áskatla', 'Ásla', 'Áslaug', 'Ásleif', 'Ásný', 'Ásrós', 'Ásrún', 'Ást', 'Ásta', 'Ástbjörg', 'Ástbjört', 'Ástdís', 'Ástfríður', 'Ástgerður', 'Ástheiður', 'Ásthildur', 'Ástríður', 'Ástrós', 'Ástrún', 'Ástveig', 'Ástþóra', 'Ástþrúður', 'Ásvör', 'Baldey', 'Baldrún', 'Baldvina', 'Barbara', 'Barbára', 'Bassí', 'Bára', 'Bebba', 'Begga', 'Belinda', 'Bella', 'Benedikta', 'Bengta', 'Benidikta', 'Benía', 'Beníta', 'Benna', 'Benney', 'Benný', 'Benta', 'Bentey', 'Bentína', 'Bera', 'Bergdís', 'Bergey', 'Bergfríður', 'Bergheiður', 'Berghildur', 'Berglaug', 'Berglind', 'Berglín', 'Bergljót', 'Bergmannía', 'Bergný', 'Bergrán', 'Bergrín', 'Bergrós', 'Bergrún', 'Bergþóra', 'Berit', 'Bernódía', 'Berta', 'Bertha', 'Bessí', 'Bestla', 'Beta', 'Betanía', 'Betsý', 'Bettý', 'Bil', 'Birgit', 'Birgitta', 'Birna', 'Birta', 'Birtna', 'Bíbí', 'Bína', 'Bjargdís', 'Bjargey', 'Bjargheiður', 'Bjarghildur', 'Bjarglind', 'Bjarkey', 'Bjarklind', 'Bjarma', 'Bjarndís', 'Bjarney', 'Bjarnfríður', 'Bjarngerður', 'Bjarnheiður', 'Bjarnhildur', 'Bjarnlaug', 'Bjarnrún', 'Bjarnveig', 'Bjarný', 'Bjarnþóra', 'Bjarnþrúður', 'Bjartey', 'Bjartmey', 'Björg', 'Björgey', 'Björgheiður', 'Björghildur', 'Björk', 'Björney', 'Björnfríður', 'Björt', 'Bláey', 'Blíða', 'Blín', 'Blómey', 'Blædís', 'Blær', 'Bobba', 'Boga', 'Bogdís', 'Bogey', 'Bogga', 'Boghildur', 'Borg', 'Borgdís', 'Borghildur', 'Borgný', 'Borgrún', 'Borgþóra', 'Botnía', 'Bóel', 'Bót', 'Bóthildur', 'Braga', 'Braghildur', 'Branddís', 'Brá', 'Brák', 'Brigitta', 'Brimdís', 'Brimhildur', 'Brimrún', 'Brit', 'Britt', 'Britta', 'Bríana', 'Bríanna', 'Bríet', 'Bryndís', 'Brynfríður', 'Bryngerður', 'Brynheiður', 'Brynhildur', 'Brynja', 'Brynný', 'Burkney', 'Bylgja', 'Camilla', 'Carla', 'Carmen', 'Cecilia', 'Cecilía', 'Charlotta', 'Charlotte', 'Christina', 'Christine', 'Clara', 'Daðey', 'Daðína', 'Dagbjörg', 'Dagbjört', 'Dagfríður', 'Daggrós', 'Dagheiður', 'Dagmar', 'Dagmey', 'Dagný', 'Dagrún', 'Daldís', 'Daley', 'Dalía', 'Dalla', 'Dallilja', 'Dalrós', 'Dana', 'Daney', 'Danfríður', 'Danheiður', 'Danhildur', 'Danía', 'Daníela', 'Daníella', 'Dara', 'Debora', 'Debóra', 'Dendý', 'Didda', 'Dilja', 'Diljá', 'Dimmblá', 'Dimmey', 'Día', 'Díana', 'Díanna', 'Díma', 'Dís', 'Dísa', 'Dísella', 'Donna', 'Doris', 'Dorothea', 'Dóa', 'Dómhildur', 'Dóra', 'Dórey', 'Dóris', 'Dórothea', 'Dórótea', 'Dóróthea', 'Drauma', 'Draumey', 'Drífa', 'Droplaug', 'Drótt', 'Dröfn', 'Dúa', 'Dúfa', 'Dúna', 'Dýrborg', 'Dýrfinna', 'Dýrleif', 'Dýrley', 'Dýrunn', 'Dæja', 'Dögg', 'Dögun', 'Ebba', 'Ebonney', 'Edda', 'Edel', 'Edil', 'Edit', 'Edith', 'Eðna', 'Efemía', 'Egedía', 'Eggrún', 'Egla', 'Eiðný', 'Eiðunn', 'Eik', 'Einbjörg', 'Eindís', 'Einey', 'Einfríður', 'Einhildur', 'Einína', 'Einrún', 'Eir', 'Eirdís', 'Eirfinna', 'Eiríka', 'Eirný', 'Eirún', 'Elba', 'Eldbjörg', 'Eldey', 'Eldlilja', 'Eldrún', 'Eleina', 'Elektra', 'Elena', 'Elenborg', 'Elfa', 'Elfur', 'Elina', 'Elinborg', 'Elisabeth', 'Elía', 'Elíana', 'Elín', 'Elína', 'Elíná', 'Elínbet', 'Elínbjörg', 'Elínbjört', 'Elínborg', 'Elíndís', 'Elíngunnur', 'Elínheiður', 'Elínrós', 'Elírós', 'Elísa', 'Elísabet', 'Elísabeth', 'Elka', 'Ella', 'Ellen', 'Elley', 'Ellisif', 'Ellín', 'Elly', 'Ellý', 'Elma', 'Elna', 'Elsa', 'Elsabet', 'Elsie', 'Elsí', 'Elsý', 'Elva', 'Elvi', 'Elvíra', 'Elvý', 'Embla', 'Emelía', 'Emelíana', 'Emelína', 'Emeralda', 'Emilía', 'Emilíana', 'Emilíanna', 'Emilý', 'Emma', 'Emmý', 'Emý', 'Enea', 'Eneka', 'Engilbjört', 'Engilráð', 'Engilrós', 'Engla', 'Enika', 'Enja', 'Enóla', 'Eres', 'Erika', 'Erin', 'Erla', 'Erlen', 'Erlín', 'Erna', 'Esja', 'Esmeralda', 'Ester', 'Esther', 'Estiva', 'Ethel', 'Etna', 'Eufemía', 'Eva', 'Evelyn', 'Evey', 'Evfemía', 'Evgenía', 'Evíta', 'Evlalía', 'Ey', 'Eybjörg', 'Eybjört', 'Eydís', 'Eyfríður', 'Eygerður', 'Eygló', 'Eyhildur', 'Eyja', 'Eyjalín', 'Eyleif', 'Eylín', 'Eyrós', 'Eyrún', 'Eyveig', 'Eyvör', 'Eyþóra', 'Eyþrúður', 'Fanndís', 'Fanney', 'Fannlaug', 'Fanny', 'Fanný', 'Febrún', 'Fema', 'Filipía', 'Filippa', 'Filippía', 'Finna', 'Finnbjörg', 'Finnbjörk', 'Finnboga', 'Finnborg', 'Finndís', 'Finney', 'Finnfríður', 'Finnlaug', 'Finnrós', 'Fía', 'Fídes', 'Fífa', 'Fjalldís', 'Fjóla', 'Flóra', 'Folda', 'Fransiska', 'Franziska', 'Frán', 'Fregn', 'Freydís', 'Freygerður', 'Freyja', 'Freylaug', 'Freyleif', 'Friðbjörg', 'Friðbjört', 'Friðborg', 'Friðdís', 'Friðdóra', 'Friðey', 'Friðfinna', 'Friðgerður', 'Friðjóna', 'Friðlaug', 'Friðleif', 'Friðlín', 'Friðmey', 'Friðný', 'Friðrika', 'Friðrikka', 'Friðrós', 'Friðrún', 'Friðsemd', 'Friðveig', 'Friðþóra', 'Frigg', 'Fríða', 'Fríður', 'Frostrós', 'Fróðný', 'Fura', 'Fönn', 'Gabríela', 'Gabríella', 'Gauja', 'Gauthildur', 'Gefjun', 'Gefn', 'Geira', 'Geirbjörg', 'Geirdís', 'Geirfinna', 'Geirfríður', 'Geirhildur', 'Geirlaug', 'Geirlöð', 'Geirný', 'Geirríður', 'Geirrún', 'Geirþrúður', 'Georgía', 'Gerða', 'Gerður', 'Gestheiður', 'Gestný', 'Gestrún', 'Gillý', 'Gilslaug', 'Gissunn', 'Gía', 'Gígja', 'Gísela', 'Gísla', 'Gísley', 'Gíslína', 'Gíslný', 'Gíslrún', 'Gíslunn', 'Gíta', 'Gjaflaug', 'Gloría', 'Gló', 'Glóa', 'Glóbjört', 'Glódís', 'Glóð', 'Glóey', 'Gná', 'Góa', 'Gógó', 'Grein', 'Gret', 'Greta', 'Grélöð', 'Grét', 'Gréta', 'Gríma', 'Grímey', 'Grímheiður', 'Grímhildur', 'Gróa', 'Guðbjörg', 'Guðbjört', 'Guðborg', 'Guðdís', 'Guðfinna', 'Guðfríður', 'Guðjóna', 'Guðlaug', 'Guðleif', 'Guðlín', 'Guðmey', 'Guðmunda', 'Guðmundína', 'Guðný', 'Guðríður', 'Guðrún', 'Guðsteina', 'Guðveig', 'Gullbrá', 'Gullveig', 'Gullý', 'Gumma', 'Gunnbjörg', 'Gunnbjört', 'Gunnborg', 'Gunndís', 'Gunndóra', 'Gunnella', 'Gunnfinna', 'Gunnfríður', 'Gunnharða', 'Gunnheiður', 'Gunnhildur', 'Gunnjóna', 'Gunnlaug', 'Gunnleif', 'Gunnlöð', 'Gunnrún', 'Gunnur', 'Gunnveig', 'Gunnvör', 'Gunný', 'Gunnþóra', 'Gunnþórunn', 'Gurrý', 'Gúa', 'Gyða', 'Gyðja', 'Gyðríður', 'Gytta', 'Gæfa', 'Gæflaug', 'Hadda', 'Haddý', 'Hafbjörg', 'Hafborg', 'Hafdís', 'Hafey', 'Hafliða', 'Haflína', 'Hafný', 'Hafrós', 'Hafrún', 'Hafsteina', 'Hafþóra', 'Halla', 'Hallbera', 'Hallbjörg', 'Hallborg', 'Halldís', 'Halldóra', 'Halley', 'Hallfríður', 'Hallgerður', 'Hallgunnur', 'Hallkatla', 'Hallný', 'Hallrún', 'Hallveig', 'Hallvör', 'Hanna', 'Hanney', 'Hansa', 'Hansína', 'Harpa', 'Hauður', 'Hákonía', 'Heba', 'Hedda', 'Hedí', 'Heiða', 'Heiðbjörg', 'Heiðbjörk', 'Heiðbjört', 'Heiðbrá', 'Heiðdís', 'Heiðlaug', 'Heiðlóa', 'Heiðný', 'Heiðrós', 'Heiðrún', 'Heiður', 'Heiðveig', 'Hekla', 'Helen', 'Helena', 'Helga', 'Hella', 'Helma', 'Hendrikka', 'Henný', 'Henrietta', 'Henrika', 'Henríetta', 'Hera', 'Herbjörg', 'Herbjört', 'Herborg', 'Herdís', 'Herfríður', 'Hergerður', 'Herlaug', 'Hermína', 'Hersilía', 'Herta', 'Hertha', 'Hervör', 'Herþrúður', 'Hilda', 'Hildegard', 'Hildibjörg', 'Hildigerður', 'Hildigunnur', 'Hildiríður', 'Hildisif', 'Hildur', 'Hilma', 'Himinbjörg', 'Hind', 'Hinrika', 'Hinrikka', 'Hjalta', 'Hjaltey', 'Hjálmdís', 'Hjálmey', 'Hjálmfríður', 'Hjálmgerður', 'Hjálmrós', 'Hjálmrún', 'Hjálmveig', 'Hjördís', 'Hjörfríður', 'Hjörleif', 'Hjörný', 'Hjörtfríður', 'Hlaðgerður', 'Hlédís', 'Hlíf', 'Hlín', 'Hlökk', 'Hólmbjörg', 'Hólmdís', 'Hólmfríður', 'Hrafna', 'Hrafnborg', 'Hrafndís', 'Hrafney', 'Hrafngerður', 'Hrafnheiður', 'Hrafnhildur', 'Hrafnkatla', 'Hrafnlaug', 'Hrafntinna', 'Hraundís', 'Hrefna', 'Hreindís', 'Hróðný', 'Hrólfdís', 'Hrund', 'Hrönn', 'Hugbjörg', 'Hugbjört', 'Hugborg', 'Hugdís', 'Hugljúf', 'Hugrún', 'Huld', 'Hulda', 'Huldís', 'Huldrún', 'Húnbjörg', 'Húndís', 'Húngerður', 'Hvönn', 'Hödd', 'Högna', 'Hörn', 'Ida', 'Idda', 'Iða', 'Iðunn', 'Ilmur', 'Immý', 'Ina', 'Inda', 'India', 'Indiana', 'Indía', 'Indíana', 'Indíra', 'Indra', 'Inga', 'Ingdís', 'Ingeborg', 'Inger', 'Ingey', 'Ingheiður', 'Inghildur', 'Ingibjörg', 'Ingibjört', 'Ingiborg', 'Ingifinna', 'Ingifríður', 'Ingigerður', 'Ingilaug', 'Ingileif', 'Ingilín', 'Ingimaría', 'Ingimunda', 'Ingiríður', 'Ingirós', 'Ingisól', 'Ingiveig', 'Ingrid', 'Ingrún', 'Ingunn', 'Ingveldur', 'Inna', 'Irena', 'Irene', 'Irja', 'Irma', 'Irmý', 'Irpa', 'Isabel', 'Isabella', 'Ída', 'Íma', 'Ína', 'Ír', 'Íren', 'Írena', 'Íris', 'Írunn', 'Ísabel', 'Ísabella', 'Ísadóra', 'Ísafold', 'Ísalind', 'Ísbjörg', 'Ísdís', 'Ísey', 'Ísfold', 'Ísgerður', 'Íshildur', 'Ísis', 'Íslaug', 'Ísleif', 'Ísmey', 'Ísold', 'Ísól', 'Ísrún', 'Íssól', 'Ísveig', 'Íunn', 'Íva', 'Jakobína', 'Jana', 'Jane', 'Janetta', 'Jannika', 'Jara', 'Jarún', 'Jarþrúður', 'Jasmín', 'Járnbrá', 'Járngerður', 'Jenetta', 'Jenna', 'Jenný', 'Jensína', 'Jessý', 'Jovina', 'Jóa', 'Jóanna', 'Jódís', 'Jófríður', 'Jóhanna', 'Jólín', 'Jóna', 'Jónanna', 'Jónasína', 'Jónbjörg', 'Jónbjört', 'Jóndís', 'Jóndóra', 'Jóney', 'Jónfríður', 'Jóngerð', 'Jónheiður', 'Jónhildur', 'Jóninna', 'Jónída', 'Jónína', 'Jónný', 'Jóný', 'Jóra', 'Jóríður', 'Jórlaug', 'Jórunn', 'Jósebína', 'Jósefín', 'Jósefína', 'Judith', 'Júdea', 'Júdit', 'Júlía', 'Júlíana', 'Júlíanna', 'Júlíetta', 'Júlírós', 'Júnía', 'Júníana', 'Jökla', 'Jökulrós', 'Jörgína', 'Kaðlín', 'Kaja', 'Kalla', 'Kamilla', 'Kamí', 'Kamma', 'Kapitola', 'Kapítóla', 'Kara', 'Karen', 'Karin', 'Karitas', 'Karí', 'Karín', 'Karína', 'Karítas', 'Karla', 'Karlinna', 'Karlína', 'Karlotta', 'Karolína', 'Karó', 'Karólín', 'Karólína', 'Kassandra', 'Kata', 'Katarína', 'Katerína', 'Katharina', 'Kathinka', 'Katinka', 'Katla', 'Katrín', 'Katrína', 'Katý', 'Kára', 'Kellý', 'Kendra', 'Ketilbjörg', 'Ketilfríður', 'Ketilríður', 'Kiddý', 'Kira', 'Kirsten', 'Kirstín', 'Kittý', 'Kjalvör', 'Klara', 'Kládía', 'Klementína', 'Kleópatra', 'Kolbjörg', 'Kolbrá', 'Kolbrún', 'Koldís', 'Kolfinna', 'Kolfreyja', 'Kolgríma', 'Kolka', 'Konkordía', 'Konný', 'Korka', 'Kormlöð', 'Kornelía', 'Kókó', 'Krista', 'Kristbjörg', 'Kristborg', 'Kristel', 'Kristensa', 'Kristey', 'Kristfríður', 'Kristgerður', 'Kristin', 'Kristine', 'Kristíana', 'Kristíanna', 'Kristín', 'Kristína', 'Kristjana', 'Kristjóna', 'Kristlaug', 'Kristlind', 'Kristlín', 'Kristný', 'Kristólína', 'Kristrós', 'Kristrún', 'Kristveig', 'Kristvina', 'Kristþóra', 'Kría', 'Kæja', 'Laila', 'Laíla', 'Lana', 'Lara', 'Laufey', 'Laufheiður', 'Laufhildur', 'Lauga', 'Laugey', 'Laugheiður', 'Lára', 'Lárensína', 'Láretta', 'Lárey', 'Lea', 'Leikný', 'Leila', 'Lena', 'Leonóra', 'Leóna', 'Leónóra', 'Lilja', 'Liljá', 'Liljurós', 'Lill', 'Lilla', 'Lillian', 'Lillý', 'Lily', 'Lilý', 'Lind', 'Linda', 'Linddís', 'Lingný', 'Lisbeth', 'Listalín', 'Liv', 'Líba', 'Líf', 'Lífdís', 'Lín', 'Lína', 'Línbjörg', 'Líndís', 'Líneik', 'Líney', 'Línhildur', 'Lísa', 'Lísabet', 'Lísandra', 'Lísbet', 'Lísebet', 'Lív', 'Ljósbjörg', 'Ljósbrá', 'Ljótunn', 'Lofn', 'Loftveig', 'Logey', 'Lokbrá', 'Lotta', 'Louisa', 'Lousie', 'Lovísa', 'Lóa', 'Lóreley', 'Lukka', 'Lúcía', 'Lúðvíka', 'Lúísa', 'Lúna', 'Lúsinda', 'Lúsía', 'Lúvísa', 'Lydia', 'Lydía', 'Lyngheiður', 'Lýdía', 'Læla', 'Maddý', 'Magda', 'Magdalena', 'Magðalena', 'Magga', 'Maggey', 'Maggý', 'Magna', 'Magndís', 'Magnea', 'Magnes', 'Magney', 'Magnfríður', 'Magnheiður', 'Magnhildur', 'Magnúsína', 'Magný', 'Magnþóra', 'Maía', 'Maídís', 'Maísól', 'Maj', 'Maja', 'Malen', 'Malena', 'Malía', 'Malín', 'Malla', 'Manda', 'Manúela', 'Mara', 'Mardís', 'Marela', 'Marella', 'Maren', 'Marey', 'Marfríður', 'Margit', 'Margot', 'Margret', 'Margrét', 'Margrjet', 'Margunnur', 'Marheiður', 'Maria', 'Marie', 'Marikó', 'Marinella', 'Marit', 'Marí', 'María', 'Maríam', 'Marían', 'Maríana', 'Maríanna', 'Marín', 'Marína', 'Marínella', 'Maríon', 'Marísa', 'Marísól', 'Marít', 'Maríuerla', 'Marja', 'Markrún', 'Marlaug', 'Marlena', 'Marlín', 'Marlís', 'Marólína', 'Marsa', 'Marselía', 'Marselína', 'Marsibil', 'Marsilía', 'Marsý', 'Marta', 'Martha', 'Martína', 'Mary', 'Marý', 'Matta', 'Mattea', 'Matthea', 'Matthilda', 'Matthildur', 'Matthía', 'Mattíana', 'Mattína', 'Mattý', 'Maxima', 'Mábil', 'Málfríður', 'Málhildur', 'Málmfríður', 'Mánadís', 'Máney', 'Mára', 'Meda', 'Mekkin', 'Mekkín', 'Melinda', 'Melissa', 'Melkorka', 'Melrós', 'Messíana', 'Metta', 'Mey', 'Mikaela', 'Mikaelína', 'Mikkalína', 'Milda', 'Mildríður', 'Milla', 'Millý', 'Minerva', 'Minna', 'Minney', 'Minný', 'Miriam', 'Mirja', 'Mirjam', 'Mirra', 'Mist', 'Mía', 'Mínerva', 'Míra', 'Míranda', 'Mítra', 'Mjaðveig', 'Mjalldís', 'Mjallhvít', 'Mjöll', 'Mona', 'Monika', 'Módís', 'Móeiður', 'Móey', 'Móheiður', 'Móna', 'Mónika', 'Móníka', 'Munda', 'Mundheiður', 'Mundhildur', 'Mundína', 'Myrra', 'Mýr', 'Mýra', 'Mýrún', 'Mörk', 'Nadia', 'Nadía', 'Nadja', 'Nana', 'Nanna', 'Nanný', 'Nansý', 'Naomí', 'Naómí', 'Natalie', 'Natalía', 'Náttsól', 'Nella', 'Nellý', 'Nenna', 'Nicole', 'Niðbjörg', 'Nikíta', 'Nikoletta', 'Nikólína', 'Ninja', 'Ninna', 'Nína', 'Níní', 'Njála', 'Njóla', 'Norma', 'Nóa', 'Nóra', 'Nótt', 'Nýbjörg', 'Odda', 'Oddbjörg', 'Oddfreyja', 'Oddfríður', 'Oddgerður', 'Oddhildur', 'Oddlaug', 'Oddleif', 'Oddný', 'Oddrún', 'Oddveig', 'Oddvör', 'Oktavía', 'Októvía', 'Olga', 'Ollý', 'Ora', 'Orka', 'Ormheiður', 'Ormhildur', 'Otkatla', 'Otta', 'Óda', 'Ófelía', 'Óla', 'Ólafía', 'Ólafína', 'Ólavía', 'Ólivía', 'Ólína', 'Ólöf', 'Ósa', 'Ósk', 'Ótta', 'Pamela', 'París', 'Patricia', 'Patrisía', 'Pála', 'Páldís', 'Páley', 'Pálfríður', 'Pálhanna', 'Pálheiður', 'Pálhildur', 'Pálín', 'Pálína', 'Pálmey', 'Pálmfríður', 'Pálrún', 'Perla', 'Peta', 'Petra', 'Petrea', 'Petrína', 'Petronella', 'Petrónella', 'Petrós', 'Petrún', 'Petrúnella', 'Pétrína', 'Pétrún', 'Pía', 'Polly', 'Pollý', 'Pría', 'Rafney', 'Rafnhildur', 'Ragna', 'Ragnbjörg', 'Ragney', 'Ragnfríður', 'Ragnheiður', 'Ragnhildur', 'Rakel', 'Ramóna', 'Randalín', 'Randíður', 'Randý', 'Ranka', 'Rannva', 'Rannveig', 'Ráðhildur', 'Rán', 'Rebekka', 'Reginbjörg', 'Regína', 'Rein', 'Renata', 'Reyn', 'Reyndís', 'Reynheiður', 'Reynhildur', 'Rikka', 'Ripley', 'Rita', 'Ríkey', 'Rín', 'Ríta', 'Ronja', 'Rorí', 'Roxanna', 'Róberta', 'Róbjörg', 'Rós', 'Rósa', 'Rósalind', 'Rósanna', 'Rósbjörg', 'Rósborg', 'Róselía', 'Rósey', 'Rósfríður', 'Róshildur', 'Rósinkara', 'Rósinkransa', 'Róska', 'Róslaug', 'Róslind', 'Róslinda', 'Róslín', 'Rósmary', 'Rósmarý', 'Rósmunda', 'Rósný', 'Runný', 'Rut', 'Ruth', 'Rúbý', 'Rún', 'Rúna', 'Rúndís', 'Rúnhildur', 'Rúrí', 'Röfn', 'Rögn', 'Röskva', 'Sabína', 'Sabrína', 'Saga', 'Salbjörg', 'Saldís', 'Salgerður', 'Salín', 'Salína', 'Salka', 'Salma', 'Salný', 'Salome', 'Salóme', 'Salvör', 'Sandra', 'Sanna', 'Santía', 'Sara', 'Sarína', 'Sefanía', 'Selja', 'Selka', 'Selma', 'Senía', 'Septíma', 'Sera', 'Serena', 'Seselía', 'Sesilía', 'Sesselía', 'Sesselja', 'Sessilía', 'Sif', 'Sigdís', 'Sigdóra', 'Sigfríð', 'Sigfríður', 'Sigga', 'Siggerður', 'Sigmunda', 'Signa', 'Signhildur', 'Signý', 'Sigríður', 'Sigrún', 'Sigurást', 'Sigurásta', 'Sigurbára', 'Sigurbirna', 'Sigurbjörg', 'Sigurbjört', 'Sigurborg', 'Sigurdís', 'Sigurdóra', 'Sigurdríf', 'Sigurdrífa', 'Sigurða', 'Sigurey', 'Sigurfinna', 'Sigurfljóð', 'Sigurgeira', 'Sigurhanna', 'Sigurhelga', 'Sigurhildur', 'Sigurjóna', 'Sigurlaug', 'Sigurleif', 'Sigurlilja', 'Sigurlinn', 'Sigurlín', 'Sigurlína', 'Sigurmunda', 'Sigurnanna', 'Sigurósk', 'Sigurrós', 'Sigursteina', 'Sigurunn', 'Sigurveig', 'Sigurvina', 'Sigurþóra', 'Sigyn', 'Sigþóra', 'Sigþrúður', 'Silfa', 'Silfá', 'Silfrún', 'Silja', 'Silka', 'Silla', 'Silva', 'Silvana', 'Silvía', 'Sirra', 'Sirrý', 'Siv', 'Sía', 'Símonía', 'Sísí', 'Síta', 'Sjöfn', 'Skarpheiður', 'Skugga', 'Skuld', 'Skúla', 'Skúlína', 'Snjáfríður', 'Snjáka', 'Snjófríður', 'Snjólaug', 'Snorra', 'Snót', 'Snæbjörg', 'Snæbjört', 'Snæborg', 'Snæbrá', 'Snædís', 'Snæfríður', 'Snælaug', 'Snærós', 'Snærún', 'Soffía', 'Sofie', 'Sofía', 'Solveig', 'Sonja', 'Sonný', 'Sophia', 'Sophie', 'Sól', 'Sóla', 'Sólbjörg', 'Sólbjört', 'Sólborg', 'Sólbrá', 'Sólbrún', 'Sóldís', 'Sóldögg', 'Sóley', 'Sólfríður', 'Sólgerður', 'Sólhildur', 'Sólín', 'Sólkatla', 'Sóllilja', 'Sólný', 'Sólrós', 'Sólrún', 'Sólveig', 'Sólvör', 'Sónata', 'Stefana', 'Stefanía', 'Stefánný', 'Steina', 'Steinbjörg', 'Steinborg', 'Steindís', 'Steindóra', 'Steiney', 'Steinfríður', 'Steingerður', 'Steinhildur', 'Steinlaug', 'Steinrós', 'Steinrún', 'Steinunn', 'Steinvör', 'Steinþóra', 'Stella', 'Stígheiður', 'Stígrún', 'Stína', 'Stjarna', 'Styrgerður', 'Sumarlína', 'Sumarrós', 'Sunna', 'Sunnefa', 'Sunneva', 'Sunniva', 'Sunníva', 'Susan', 'Súla', 'Súsan', 'Súsanna', 'Svafa', 'Svala', 'Svalrún', 'Svana', 'Svanbjörg', 'Svanbjört', 'Svanborg', 'Svandís', 'Svaney', 'Svanfríður', 'Svanheiður', 'Svanhildur', 'Svanhvít', 'Svanlaug', 'Svanrós', 'Svanþrúður', 'Svava', 'Svea', 'Sveina', 'Sveinbjörg', 'Sveinborg', 'Sveindís', 'Sveiney', 'Sveinfríður', 'Sveingerður', 'Sveinhildur', 'Sveinlaug', 'Sveinrós', 'Sveinrún', 'Sveinsína', 'Sveinveig', 'Sylgja', 'Sylva', 'Sylvía', 'Sæbjörg', 'Sæbjört', 'Sæborg', 'Sædís', 'Sæfinna', 'Sæfríður', 'Sæhildur', 'Sælaug', 'Sæmunda', 'Sæný', 'Særós', 'Særún', 'Sæsól', 'Sæunn', 'Sævör', 'Sölva', 'Sölvey', 'Sölvína', 'Tala', 'Talía', 'Tamar', 'Tamara', 'Tanía', 'Tanja', 'Tanya', 'Tanya', 'Tara', 'Tea', 'Teitný', 'Tekla', 'Telma', 'Tera', 'Teresa', 'Teresía', 'Thea', 'Thelma', 'Theodóra', 'Theódóra', 'Theresa', 'Tindra', 'Tinna', 'Tirsa', 'Tía', 'Tíbrá', 'Tína', 'Todda', 'Torbjörg', 'Torfey', 'Torfheiður', 'Torfhildur', 'Tóbý', 'Tóka', 'Tóta', 'Tristana', 'Trú', 'Tryggva', 'Tryggvína', 'Týra', 'Ugla', 'Una', 'Undína', 'Unna', 'Unnbjörg', 'Unndís', 'Unnur', 'Urður', 'Úa', 'Úlfa', 'Úlfdís', 'Úlfey', 'Úlfheiður', 'Úlfhildur', 'Úlfrún', 'Úlla', 'Úna', 'Úndína', 'Úranía', 'Úrsúla', 'Vagna', 'Vagnbjörg', 'Vagnfríður', 'Vaka', 'Vala', 'Valbjörg', 'Valbjörk', 'Valbjört', 'Valborg', 'Valdheiður', 'Valdís', 'Valentína', 'Valería', 'Valey', 'Valfríður', 'Valgerða', 'Valgerður', 'Valhildur', 'Valka', 'Vallý', 'Valný', 'Valrós', 'Valrún', 'Valva', 'Valý', 'Valþrúður', 'Vanda', 'Vár', 'Veig', 'Veiga', 'Venus', 'Vera', 'Veronika', 'Verónika', 'Veróníka', 'Vetrarrós', 'Vébjörg', 'Védís', 'Végerður', 'Vélaug', 'Véný', 'Vibeka', 'Victoría', 'Viðja', 'Vigdís', 'Vigný', 'Viktoria', 'Viktoría', 'Vilborg', 'Vildís', 'Vilfríður', 'Vilgerður', 'Vilhelmína', 'Villa', 'Villimey', 'Vilma', 'Vilný', 'Vinbjörg', 'Vinný', 'Vinsý', 'Virginía', 'Víbekka', 'Víf', 'Vígdögg', 'Víggunnur', 'Víóla', 'Víóletta', 'Vísa', 'Von', 'Von', 'Voney', 'Vordís', 'Ylfa', 'Ylfur', 'Ylja', 'Ylva', 'Ynja', 'Yrja', 'Yrsa', 'Ýja', 'Ýma', 'Ýr', 'Ýrr', 'Þalía', 'Þeba', 'Þeódís', 'Þeódóra', 'Þjóðbjörg', 'Þjóðhildur', 'Þoka', 'Þorbjörg', 'Þorfinna', 'Þorgerður', 'Þorgríma', 'Þorkatla', 'Þorlaug', 'Þorleif', 'Þorsteina', 'Þorstína', 'Þóra', 'Þóranna', 'Þórarna', 'Þórbjörg', 'Þórdís', 'Þórða', 'Þórelfa', 'Þórelfur', 'Þórey', 'Þórfríður', 'Þórgunna', 'Þórgunnur', 'Þórhalla', 'Þórhanna', 'Þórheiður', 'Þórhildur', 'Þórkatla', 'Þórlaug', 'Þórleif', 'Þórný', 'Þórodda', 'Þórsteina', 'Þórsteinunn', 'Þórstína', 'Þórunn', 'Þórveig', 'Þórvör', 'Þrá', 'Þrúða', 'Þrúður', 'Þula', 'Þura', 'Þurí', 'Þuríður', 'Þurý', 'Þúfa', 'Þyri', 'Þyrí', 'Þöll', 'Ægileif', 'Æsa', 'Æsgerður', 'Ögmunda', 'Ögn', 'Ölrún', 'Ölveig', 'Örbrún', 'Örk', 'Ösp'];
+
+ /**
+ * @var array
+ * assertThat($string, both(containsString("a"))->andAlso(containsString("b")));
+ *
+ */
+ function both(\Hamcrest\Matcher $matcher)
+ {
+ return \Hamcrest\Core\CombinableMatcher::both($matcher);
+ }
+}
+
+if (!function_exists('either')) {
+ /**
+ * This is useful for fluently combining matchers where either may pass,
+ * for example:
+ *
+ * assertThat($string, either(containsString("a"))->orElse(containsString("b")));
+ *
+ */
+ function either(\Hamcrest\Matcher $matcher)
+ {
+ return \Hamcrest\Core\CombinableMatcher::either($matcher);
+ }
+}
+
+if (!function_exists('describedAs')) {
+ /**
+ * Wraps an existing matcher and overrides the description when it fails.
+ */
+ function describedAs(/* args... */)
+ {
+ $args = func_get_args();
+ return call_user_func_array(array('\Hamcrest\Core\DescribedAs', 'describedAs'), $args);
+ }
+}
+
+if (!function_exists('everyItem')) {
+ /**
+ * @param Matcher $itemMatcher
+ * A matcher to apply to every element in an array.
+ *
+ * @return \Hamcrest\Core\Every
+ * Evaluates to TRUE for a collection in which every item matches $itemMatcher
+ */
+ function everyItem(\Hamcrest\Matcher $itemMatcher)
+ {
+ return \Hamcrest\Core\Every::everyItem($itemMatcher);
+ }
+}
+
+if (!function_exists('hasToString')) {
+ /**
+ * Does array size satisfy a given matcher?
+ */
+ function hasToString($matcher)
+ {
+ return \Hamcrest\Core\HasToString::hasToString($matcher);
+ }
+}
+
+if (!function_exists('is')) {
+ /**
+ * Decorates another Matcher, retaining the behavior but allowing tests
+ * to be slightly more expressive.
+ *
+ * For example: assertThat($cheese, equalTo($smelly))
+ * vs. assertThat($cheese, is(equalTo($smelly)))
+ */
+ function is($value)
+ {
+ return \Hamcrest\Core\Is::is($value);
+ }
+}
+
+if (!function_exists('anything')) {
+ /**
+ * This matcher always evaluates to true.
+ *
+ * @param string $description A meaningful string used when describing itself.
+ *
+ * @return \Hamcrest\Core\IsAnything
+ */
+ function anything($description = 'ANYTHING')
+ {
+ return \Hamcrest\Core\IsAnything::anything($description);
+ }
+}
+
+if (!function_exists('hasItem')) {
+ /**
+ * Test if the value is an array containing this matcher.
+ *
+ * Example:
+ *
+ * assertThat(array('a', 'b'), hasItem(equalTo('b')));
+ * //Convenience defaults to equalTo()
+ * assertThat(array('a', 'b'), hasItem('b'));
+ *
+ */
+ function hasItem(/* args... */)
+ {
+ $args = func_get_args();
+ return call_user_func_array(array('\Hamcrest\Core\IsCollectionContaining', 'hasItem'), $args);
+ }
+}
+
+if (!function_exists('hasItems')) {
+ /**
+ * Test if the value is an array containing elements that match all of these
+ * matchers.
+ *
+ * Example:
+ *
+ * assertThat(array('a', 'b', 'c'), hasItems(equalTo('a'), equalTo('b')));
+ *
+ */
+ function hasItems(/* args... */)
+ {
+ $args = func_get_args();
+ return call_user_func_array(array('\Hamcrest\Core\IsCollectionContaining', 'hasItems'), $args);
+ }
+}
+
+if (!function_exists('equalTo')) {
+ /**
+ * Is the value equal to another value, as tested by the use of the "=="
+ * comparison operator?
+ */
+ function equalTo($item)
+ {
+ return \Hamcrest\Core\IsEqual::equalTo($item);
+ }
+}
+
+if (!function_exists('identicalTo')) {
+ /**
+ * Tests of the value is identical to $value as tested by the "===" operator.
+ */
+ function identicalTo($value)
+ {
+ return \Hamcrest\Core\IsIdentical::identicalTo($value);
+ }
+}
+
+if (!function_exists('anInstanceOf')) {
+ /**
+ * Is the value an instance of a particular type?
+ * This version assumes no relationship between the required type and
+ * the signature of the method that sets it up, for example in
+ * assertThat($anObject, anInstanceOf('Thing'));
+ */
+ function anInstanceOf($theClass)
+ {
+ return \Hamcrest\Core\IsInstanceOf::anInstanceOf($theClass);
+ }
+}
+
+if (!function_exists('any')) {
+ /**
+ * Is the value an instance of a particular type?
+ * This version assumes no relationship between the required type and
+ * the signature of the method that sets it up, for example in
+ * assertThat($anObject, anInstanceOf('Thing'));
+ */
+ function any($theClass)
+ {
+ return \Hamcrest\Core\IsInstanceOf::anInstanceOf($theClass);
+ }
+}
+
+if (!function_exists('not')) {
+ /**
+ * Matches if value does not match $value.
+ */
+ function not($value)
+ {
+ return \Hamcrest\Core\IsNot::not($value);
+ }
+}
+
+if (!function_exists('nullValue')) {
+ /**
+ * Matches if value is null.
+ */
+ function nullValue()
+ {
+ return \Hamcrest\Core\IsNull::nullValue();
+ }
+}
+
+if (!function_exists('notNullValue')) {
+ /**
+ * Matches if value is not null.
+ */
+ function notNullValue()
+ {
+ return \Hamcrest\Core\IsNull::notNullValue();
+ }
+}
+
+if (!function_exists('sameInstance')) {
+ /**
+ * Creates a new instance of IsSame.
+ *
+ * @param mixed $object
+ * The predicate evaluates to true only when the argument is
+ * this object.
+ *
+ * @return \Hamcrest\Core\IsSame
+ */
+ function sameInstance($object)
+ {
+ return \Hamcrest\Core\IsSame::sameInstance($object);
+ }
+}
+
+if (!function_exists('typeOf')) {
+ /**
+ * Is the value a particular built-in type?
+ */
+ function typeOf($theType)
+ {
+ return \Hamcrest\Core\IsTypeOf::typeOf($theType);
+ }
+}
+
+if (!function_exists('set')) {
+ /**
+ * Matches if value (class, object, or array) has named $property.
+ */
+ function set($property)
+ {
+ return \Hamcrest\Core\Set::set($property);
+ }
+}
+
+if (!function_exists('notSet')) {
+ /**
+ * Matches if value (class, object, or array) does not have named $property.
+ */
+ function notSet($property)
+ {
+ return \Hamcrest\Core\Set::notSet($property);
+ }
+}
+
+if (!function_exists('closeTo')) {
+ /**
+ * Matches if value is a number equal to $value within some range of
+ * acceptable error $delta.
+ */
+ function closeTo($value, $delta)
+ {
+ return \Hamcrest\Number\IsCloseTo::closeTo($value, $delta);
+ }
+}
+
+if (!function_exists('comparesEqualTo')) {
+ /**
+ * The value is not > $value, nor < $value.
+ */
+ function comparesEqualTo($value)
+ {
+ return \Hamcrest\Number\OrderingComparison::comparesEqualTo($value);
+ }
+}
+
+if (!function_exists('greaterThan')) {
+ /**
+ * The value is > $value.
+ */
+ function greaterThan($value)
+ {
+ return \Hamcrest\Number\OrderingComparison::greaterThan($value);
+ }
+}
+
+if (!function_exists('greaterThanOrEqualTo')) {
+ /**
+ * The value is >= $value.
+ */
+ function greaterThanOrEqualTo($value)
+ {
+ return \Hamcrest\Number\OrderingComparison::greaterThanOrEqualTo($value);
+ }
+}
+
+if (!function_exists('atLeast')) {
+ /**
+ * The value is >= $value.
+ */
+ function atLeast($value)
+ {
+ return \Hamcrest\Number\OrderingComparison::greaterThanOrEqualTo($value);
+ }
+}
+
+if (!function_exists('lessThan')) {
+ /**
+ * The value is < $value.
+ */
+ function lessThan($value)
+ {
+ return \Hamcrest\Number\OrderingComparison::lessThan($value);
+ }
+}
+
+if (!function_exists('lessThanOrEqualTo')) {
+ /**
+ * The value is <= $value.
+ */
+ function lessThanOrEqualTo($value)
+ {
+ return \Hamcrest\Number\OrderingComparison::lessThanOrEqualTo($value);
+ }
+}
+
+if (!function_exists('atMost')) {
+ /**
+ * The value is <= $value.
+ */
+ function atMost($value)
+ {
+ return \Hamcrest\Number\OrderingComparison::lessThanOrEqualTo($value);
+ }
+}
+
+if (!function_exists('isEmptyString')) {
+ /**
+ * Matches if value is a zero-length string.
+ */
+ function isEmptyString()
+ {
+ return \Hamcrest\Text\IsEmptyString::isEmptyString();
+ }
+}
+
+if (!function_exists('emptyString')) {
+ /**
+ * Matches if value is a zero-length string.
+ */
+ function emptyString()
+ {
+ return \Hamcrest\Text\IsEmptyString::isEmptyString();
+ }
+}
+
+if (!function_exists('isEmptyOrNullString')) {
+ /**
+ * Matches if value is null or a zero-length string.
+ */
+ function isEmptyOrNullString()
+ {
+ return \Hamcrest\Text\IsEmptyString::isEmptyOrNullString();
+ }
+}
+
+if (!function_exists('nullOrEmptyString')) {
+ /**
+ * Matches if value is null or a zero-length string.
+ */
+ function nullOrEmptyString()
+ {
+ return \Hamcrest\Text\IsEmptyString::isEmptyOrNullString();
+ }
+}
+
+if (!function_exists('isNonEmptyString')) {
+ /**
+ * Matches if value is a non-zero-length string.
+ */
+ function isNonEmptyString()
+ {
+ return \Hamcrest\Text\IsEmptyString::isNonEmptyString();
+ }
+}
+
+if (!function_exists('nonEmptyString')) {
+ /**
+ * Matches if value is a non-zero-length string.
+ */
+ function nonEmptyString()
+ {
+ return \Hamcrest\Text\IsEmptyString::isNonEmptyString();
+ }
+}
+
+if (!function_exists('equalToIgnoringCase')) {
+ /**
+ * Matches if value is a string equal to $string, regardless of the case.
+ */
+ function equalToIgnoringCase($string)
+ {
+ return \Hamcrest\Text\IsEqualIgnoringCase::equalToIgnoringCase($string);
+ }
+}
+
+if (!function_exists('equalToIgnoringWhiteSpace')) {
+ /**
+ * Matches if value is a string equal to $string, regardless of whitespace.
+ */
+ function equalToIgnoringWhiteSpace($string)
+ {
+ return \Hamcrest\Text\IsEqualIgnoringWhiteSpace::equalToIgnoringWhiteSpace($string);
+ }
+}
+
+if (!function_exists('matchesPattern')) {
+ /**
+ * Matches if value is a string that matches regular expression $pattern.
+ */
+ function matchesPattern($pattern)
+ {
+ return \Hamcrest\Text\MatchesPattern::matchesPattern($pattern);
+ }
+}
+
+if (!function_exists('containsString')) {
+ /**
+ * Matches if value is a string that contains $substring.
+ */
+ function containsString($substring)
+ {
+ return \Hamcrest\Text\StringContains::containsString($substring);
+ }
+}
+
+if (!function_exists('containsStringIgnoringCase')) {
+ /**
+ * Matches if value is a string that contains $substring regardless of the case.
+ */
+ function containsStringIgnoringCase($substring)
+ {
+ return \Hamcrest\Text\StringContainsIgnoringCase::containsStringIgnoringCase($substring);
+ }
+}
+
+if (!function_exists('stringContainsInOrder')) {
+ /**
+ * Matches if value contains $substrings in a constrained order.
+ */
+ function stringContainsInOrder(/* args... */)
+ {
+ $args = func_get_args();
+ return call_user_func_array(array('\Hamcrest\Text\StringContainsInOrder', 'stringContainsInOrder'), $args);
+ }
+}
+
+if (!function_exists('endsWith')) {
+ /**
+ * Matches if value is a string that ends with $substring.
+ */
+ function endsWith($substring)
+ {
+ return \Hamcrest\Text\StringEndsWith::endsWith($substring);
+ }
+}
+
+if (!function_exists('startsWith')) {
+ /**
+ * Matches if value is a string that starts with $substring.
+ */
+ function startsWith($substring)
+ {
+ return \Hamcrest\Text\StringStartsWith::startsWith($substring);
+ }
+}
+
+if (!function_exists('arrayValue')) {
+ /**
+ * Is the value an array?
+ */
+ function arrayValue()
+ {
+ return \Hamcrest\Type\IsArray::arrayValue();
+ }
+}
+
+if (!function_exists('booleanValue')) {
+ /**
+ * Is the value a boolean?
+ */
+ function booleanValue()
+ {
+ return \Hamcrest\Type\IsBoolean::booleanValue();
+ }
+}
+
+if (!function_exists('boolValue')) {
+ /**
+ * Is the value a boolean?
+ */
+ function boolValue()
+ {
+ return \Hamcrest\Type\IsBoolean::booleanValue();
+ }
+}
+
+if (!function_exists('callableValue')) {
+ /**
+ * Is the value callable?
+ */
+ function callableValue()
+ {
+ return \Hamcrest\Type\IsCallable::callableValue();
+ }
+}
+
+if (!function_exists('doubleValue')) {
+ /**
+ * Is the value a float/double?
+ */
+ function doubleValue()
+ {
+ return \Hamcrest\Type\IsDouble::doubleValue();
+ }
+}
+
+if (!function_exists('floatValue')) {
+ /**
+ * Is the value a float/double?
+ */
+ function floatValue()
+ {
+ return \Hamcrest\Type\IsDouble::doubleValue();
+ }
+}
+
+if (!function_exists('integerValue')) {
+ /**
+ * Is the value an integer?
+ */
+ function integerValue()
+ {
+ return \Hamcrest\Type\IsInteger::integerValue();
+ }
+}
+
+if (!function_exists('intValue')) {
+ /**
+ * Is the value an integer?
+ */
+ function intValue()
+ {
+ return \Hamcrest\Type\IsInteger::integerValue();
+ }
+}
+
+if (!function_exists('numericValue')) {
+ /**
+ * Is the value a numeric?
+ */
+ function numericValue()
+ {
+ return \Hamcrest\Type\IsNumeric::numericValue();
+ }
+}
+
+if (!function_exists('objectValue')) {
+ /**
+ * Is the value an object?
+ */
+ function objectValue()
+ {
+ return \Hamcrest\Type\IsObject::objectValue();
+ }
+}
+
+if (!function_exists('anObject')) {
+ /**
+ * Is the value an object?
+ */
+ function anObject()
+ {
+ return \Hamcrest\Type\IsObject::objectValue();
+ }
+}
+
+if (!function_exists('resourceValue')) {
+ /**
+ * Is the value a resource?
+ */
+ function resourceValue()
+ {
+ return \Hamcrest\Type\IsResource::resourceValue();
+ }
+}
+
+if (!function_exists('scalarValue')) {
+ /**
+ * Is the value a scalar (boolean, integer, double, or string)?
+ */
+ function scalarValue()
+ {
+ return \Hamcrest\Type\IsScalar::scalarValue();
+ }
+}
+
+if (!function_exists('stringValue')) {
+ /**
+ * Is the value a string?
+ */
+ function stringValue()
+ {
+ return \Hamcrest\Type\IsString::stringValue();
+ }
+}
+
+if (!function_exists('hasXPath')) {
+ /**
+ * Wraps $matcher with {@link Hamcrest\Core\IsEqual)
+ * if it's not a matcher and the XPath in count()
+ * if it's an integer.
+ */
+ function hasXPath($xpath, $matcher = null)
+ {
+ return \Hamcrest\Xml\HasXPath::hasXPath($xpath, $matcher);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArray.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArray.php
new file mode 100755
index 00000000..9ea56970
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArray.php
@@ -0,0 +1,118 @@
+_elementMatchers = $elementMatchers;
+ }
+
+ protected function matchesSafely($array)
+ {
+ if (array_keys($array) != array_keys($this->_elementMatchers)) {
+ return false;
+ }
+
+ /** @var $matcher \Hamcrest\Matcher */
+ foreach ($this->_elementMatchers as $k => $matcher) {
+ if (!$matcher->matches($array[$k])) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ protected function describeMismatchSafely($actual, Description $mismatchDescription)
+ {
+ if (count($actual) != count($this->_elementMatchers)) {
+ $mismatchDescription->appendText('array length was ' . count($actual));
+
+ return;
+ } elseif (array_keys($actual) != array_keys($this->_elementMatchers)) {
+ $mismatchDescription->appendText('array keys were ')
+ ->appendValueList(
+ $this->descriptionStart(),
+ $this->descriptionSeparator(),
+ $this->descriptionEnd(),
+ array_keys($actual)
+ )
+ ;
+
+ return;
+ }
+
+ /** @var $matcher \Hamcrest\Matcher */
+ foreach ($this->_elementMatchers as $k => $matcher) {
+ if (!$matcher->matches($actual[$k])) {
+ $mismatchDescription->appendText('element ')->appendValue($k)
+ ->appendText(' was ')->appendValue($actual[$k]);
+
+ return;
+ }
+ }
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendList(
+ $this->descriptionStart(),
+ $this->descriptionSeparator(),
+ $this->descriptionEnd(),
+ $this->_elementMatchers
+ );
+ }
+
+ /**
+ * Evaluates to true only if each $matcher[$i] is satisfied by $array[$i].
+ *
+ * @factory ...
+ */
+ public static function anArray(/* args... */)
+ {
+ $args = func_get_args();
+
+ return new self(Util::createMatcherArray($args));
+ }
+
+ // -- Protected Methods
+
+ protected function descriptionStart()
+ {
+ return '[';
+ }
+
+ protected function descriptionSeparator()
+ {
+ return ', ';
+ }
+
+ protected function descriptionEnd()
+ {
+ return ']';
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayContaining.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayContaining.php
new file mode 100755
index 00000000..0e4a1eda
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayContaining.php
@@ -0,0 +1,63 @@
+_elementMatcher = $elementMatcher;
+ }
+
+ protected function matchesSafely($array)
+ {
+ foreach ($array as $element) {
+ if ($this->_elementMatcher->matches($element)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ protected function describeMismatchSafely($array, Description $mismatchDescription)
+ {
+ $mismatchDescription->appendText('was ')->appendValue($array);
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description
+ ->appendText('an array containing ')
+ ->appendDescriptionOf($this->_elementMatcher)
+ ;
+ }
+
+ /**
+ * Evaluates to true if any item in an array satisfies the given matcher.
+ *
+ * @param mixed $item as a {@link Hamcrest\Matcher} or a value.
+ *
+ * @return \Hamcrest\Arrays\IsArrayContaining
+ * @factory hasValue
+ */
+ public static function hasItemInArray($item)
+ {
+ return new self(Util::wrapValueWithIsEqual($item));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayContainingInAnyOrder.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayContainingInAnyOrder.php
new file mode 100755
index 00000000..9009026b
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayContainingInAnyOrder.php
@@ -0,0 +1,59 @@
+_elementMatchers = $elementMatchers;
+ }
+
+ protected function matchesSafelyWithDiagnosticDescription($array, Description $mismatchDescription)
+ {
+ $matching = new MatchingOnce($this->_elementMatchers, $mismatchDescription);
+
+ foreach ($array as $element) {
+ if (!$matching->matches($element)) {
+ return false;
+ }
+ }
+
+ return $matching->isFinished($array);
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendList('[', ', ', ']', $this->_elementMatchers)
+ ->appendText(' in any order')
+ ;
+ }
+
+ /**
+ * An array with elements that match the given matchers.
+ *
+ * @factory containsInAnyOrder ...
+ */
+ public static function arrayContainingInAnyOrder(/* args... */)
+ {
+ $args = func_get_args();
+
+ return new self(Util::createMatcherArray($args));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayContainingInOrder.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayContainingInOrder.php
new file mode 100755
index 00000000..61157404
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayContainingInOrder.php
@@ -0,0 +1,57 @@
+_elementMatchers = $elementMatchers;
+ }
+
+ protected function matchesSafelyWithDiagnosticDescription($array, Description $mismatchDescription)
+ {
+ $series = new SeriesMatchingOnce($this->_elementMatchers, $mismatchDescription);
+
+ foreach ($array as $element) {
+ if (!$series->matches($element)) {
+ return false;
+ }
+ }
+
+ return $series->isFinished();
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendList('[', ', ', ']', $this->_elementMatchers);
+ }
+
+ /**
+ * An array with elements that match the given matchers in the same order.
+ *
+ * @factory contains ...
+ */
+ public static function arrayContaining(/* args... */)
+ {
+ $args = func_get_args();
+
+ return new self(Util::createMatcherArray($args));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayContainingKey.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayContainingKey.php
new file mode 100755
index 00000000..523477e7
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayContainingKey.php
@@ -0,0 +1,75 @@
+_keyMatcher = $keyMatcher;
+ }
+
+ protected function matchesSafely($array)
+ {
+ foreach ($array as $key => $element) {
+ if ($this->_keyMatcher->matches($key)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ protected function describeMismatchSafely($array, Description $mismatchDescription)
+ {
+ //Not using appendValueList() so that keys can be shown
+ $mismatchDescription->appendText('array was ')
+ ->appendText('[')
+ ;
+ $loop = false;
+ foreach ($array as $key => $value) {
+ if ($loop) {
+ $mismatchDescription->appendText(', ');
+ }
+ $mismatchDescription->appendValue($key)->appendText(' => ')->appendValue($value);
+ $loop = true;
+ }
+ $mismatchDescription->appendText(']');
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description
+ ->appendText('array with key ')
+ ->appendDescriptionOf($this->_keyMatcher)
+ ;
+ }
+
+ /**
+ * Evaluates to true if any key in an array matches the given matcher.
+ *
+ * @param mixed $key as a {@link Hamcrest\Matcher} or a value.
+ *
+ * @return \Hamcrest\Arrays\IsArrayContainingKey
+ * @factory hasKey
+ */
+ public static function hasKeyInArray($key)
+ {
+ return new self(Util::wrapValueWithIsEqual($key));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayContainingKeyValuePair.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayContainingKeyValuePair.php
new file mode 100755
index 00000000..9ac3eba8
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayContainingKeyValuePair.php
@@ -0,0 +1,80 @@
+_keyMatcher = $keyMatcher;
+ $this->_valueMatcher = $valueMatcher;
+ }
+
+ protected function matchesSafely($array)
+ {
+ foreach ($array as $key => $value) {
+ if ($this->_keyMatcher->matches($key) && $this->_valueMatcher->matches($value)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ protected function describeMismatchSafely($array, Description $mismatchDescription)
+ {
+ //Not using appendValueList() so that keys can be shown
+ $mismatchDescription->appendText('array was ')
+ ->appendText('[')
+ ;
+ $loop = false;
+ foreach ($array as $key => $value) {
+ if ($loop) {
+ $mismatchDescription->appendText(', ');
+ }
+ $mismatchDescription->appendValue($key)->appendText(' => ')->appendValue($value);
+ $loop = true;
+ }
+ $mismatchDescription->appendText(']');
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText('array containing [')
+ ->appendDescriptionOf($this->_keyMatcher)
+ ->appendText(' => ')
+ ->appendDescriptionOf($this->_valueMatcher)
+ ->appendText(']')
+ ;
+ }
+
+ /**
+ * Test if an array has both an key and value in parity with each other.
+ *
+ * @factory hasEntry
+ */
+ public static function hasKeyValuePair($key, $value)
+ {
+ return new self(
+ Util::wrapValueWithIsEqual($key),
+ Util::wrapValueWithIsEqual($value)
+ );
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayWithSize.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayWithSize.php
new file mode 100755
index 00000000..074375ce
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/IsArrayWithSize.php
@@ -0,0 +1,73 @@
+_elementMatchers = $elementMatchers;
+ $this->_mismatchDescription = $mismatchDescription;
+ }
+
+ public function matches($item)
+ {
+ return $this->_isNotSurplus($item) && $this->_isMatched($item);
+ }
+
+ public function isFinished($items)
+ {
+ if (empty($this->_elementMatchers)) {
+ return true;
+ }
+
+ $this->_mismatchDescription
+ ->appendText('No item matches: ')->appendList('', ', ', '', $this->_elementMatchers)
+ ->appendText(' in ')->appendValueList('[', ', ', ']', $items)
+ ;
+
+ return false;
+ }
+
+ // -- Private Methods
+
+ private function _isNotSurplus($item)
+ {
+ if (empty($this->_elementMatchers)) {
+ $this->_mismatchDescription->appendText('Not matched: ')->appendValue($item);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ private function _isMatched($item)
+ {
+ /** @var $matcher \Hamcrest\Matcher */
+ foreach ($this->_elementMatchers as $i => $matcher) {
+ if ($matcher->matches($item)) {
+ unset($this->_elementMatchers[$i]);
+
+ return true;
+ }
+ }
+
+ $this->_mismatchDescription->appendText('Not matched: ')->appendValue($item);
+
+ return false;
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/SeriesMatchingOnce.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/SeriesMatchingOnce.php
new file mode 100755
index 00000000..12a912d8
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Arrays/SeriesMatchingOnce.php
@@ -0,0 +1,75 @@
+_elementMatchers = $elementMatchers;
+ $this->_keys = array_keys($elementMatchers);
+ $this->_mismatchDescription = $mismatchDescription;
+ }
+
+ public function matches($item)
+ {
+ return $this->_isNotSurplus($item) && $this->_isMatched($item);
+ }
+
+ public function isFinished()
+ {
+ if (!empty($this->_elementMatchers)) {
+ $nextMatcher = current($this->_elementMatchers);
+ $this->_mismatchDescription->appendText('No item matched: ')->appendDescriptionOf($nextMatcher);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ // -- Private Methods
+
+ private function _isNotSurplus($item)
+ {
+ if (empty($this->_elementMatchers)) {
+ $this->_mismatchDescription->appendText('Not matched: ')->appendValue($item);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ private function _isMatched($item)
+ {
+ $this->_nextMatchKey = array_shift($this->_keys);
+ $nextMatcher = array_shift($this->_elementMatchers);
+
+ if (!$nextMatcher->matches($item)) {
+ $this->_describeMismatch($nextMatcher, $item);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ private function _describeMismatch(Matcher $matcher, $item)
+ {
+ $this->_mismatchDescription->appendText('item with key ' . $this->_nextMatchKey . ': ');
+ $matcher->describeMismatch($item, $this->_mismatchDescription);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/AssertionError.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/AssertionError.php
new file mode 100755
index 00000000..3a2a0e7c
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/AssertionError.php
@@ -0,0 +1,10 @@
+append($text);
+
+ return $this;
+ }
+
+ public function appendDescriptionOf(SelfDescribing $value)
+ {
+ $value->describeTo($this);
+
+ return $this;
+ }
+
+ public function appendValue($value)
+ {
+ if (is_null($value)) {
+ $this->append('null');
+ } elseif (is_string($value)) {
+ $this->_toPhpSyntax($value);
+ } elseif (is_float($value)) {
+ $this->append('<');
+ $this->append($value);
+ $this->append('F>');
+ } elseif (is_bool($value)) {
+ $this->append('<');
+ $this->append($value ? 'true' : 'false');
+ $this->append('>');
+ } elseif (is_array($value) || $value instanceof \Iterator || $value instanceof \IteratorAggregate) {
+ $this->appendValueList('[', ', ', ']', $value);
+ } elseif (is_object($value) && !method_exists($value, '__toString')) {
+ $this->append('<');
+ $this->append(get_class($value));
+ $this->append('>');
+ } else {
+ $this->append('<');
+ $this->append($value);
+ $this->append('>');
+ }
+
+ return $this;
+ }
+
+ public function appendValueList($start, $separator, $end, $values)
+ {
+ $list = array();
+ foreach ($values as $v) {
+ $list[] = new SelfDescribingValue($v);
+ }
+
+ $this->appendList($start, $separator, $end, $list);
+
+ return $this;
+ }
+
+ public function appendList($start, $separator, $end, $values)
+ {
+ $this->append($start);
+
+ $separate = false;
+
+ foreach ($values as $value) {
+ /*if (!($value instanceof Hamcrest\SelfDescribing)) {
+ $value = new Hamcrest\Internal\SelfDescribingValue($value);
+ }*/
+
+ if ($separate) {
+ $this->append($separator);
+ }
+
+ $this->appendDescriptionOf($value);
+
+ $separate = true;
+ }
+
+ $this->append($end);
+
+ return $this;
+ }
+
+ // -- Protected Methods
+
+ /**
+ * Append the String $str to the description.
+ */
+ abstract protected function append($str);
+
+ // -- Private Methods
+
+ private function _toPhpSyntax($value)
+ {
+ $str = '"';
+ for ($i = 0, $len = strlen($value); $i < $len; ++$i) {
+ switch ($value[$i]) {
+ case '"':
+ $str .= '\\"';
+ break;
+
+ case "\t":
+ $str .= '\\t';
+ break;
+
+ case "\r":
+ $str .= '\\r';
+ break;
+
+ case "\n":
+ $str .= '\\n';
+ break;
+
+ default:
+ $str .= $value[$i];
+ }
+ }
+ $str .= '"';
+ $this->append($str);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/BaseMatcher.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/BaseMatcher.php
new file mode 100755
index 00000000..06055698
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/BaseMatcher.php
@@ -0,0 +1,30 @@
+appendText('was ')->appendValue($item);
+ }
+
+ public function __toString()
+ {
+ return StringDescription::toString($this);
+ }
+
+ public function __invoke()
+ {
+ return call_user_func_array(array($this, 'matches'), func_get_args());
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Collection/IsEmptyTraversable.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Collection/IsEmptyTraversable.php
new file mode 100755
index 00000000..8ab58ea5
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Collection/IsEmptyTraversable.php
@@ -0,0 +1,71 @@
+_empty = $empty;
+ }
+
+ public function matches($item)
+ {
+ if (!$item instanceof \Traversable) {
+ return false;
+ }
+
+ foreach ($item as $value) {
+ return !$this->_empty;
+ }
+
+ return $this->_empty;
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText($this->_empty ? 'an empty traversable' : 'a non-empty traversable');
+ }
+
+ /**
+ * Returns true if traversable is empty.
+ *
+ * @factory
+ */
+ public static function emptyTraversable()
+ {
+ if (!self::$_INSTANCE) {
+ self::$_INSTANCE = new self;
+ }
+
+ return self::$_INSTANCE;
+ }
+
+ /**
+ * Returns true if traversable is not empty.
+ *
+ * @factory
+ */
+ public static function nonEmptyTraversable()
+ {
+ if (!self::$_NOT_INSTANCE) {
+ self::$_NOT_INSTANCE = new self(false);
+ }
+
+ return self::$_NOT_INSTANCE;
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Collection/IsTraversableWithSize.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Collection/IsTraversableWithSize.php
new file mode 100755
index 00000000..c95edc5c
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Collection/IsTraversableWithSize.php
@@ -0,0 +1,47 @@
+false.
+ */
+class AllOf extends DiagnosingMatcher
+{
+
+ private $_matchers;
+
+ public function __construct(array $matchers)
+ {
+ Util::checkAllAreMatchers($matchers);
+
+ $this->_matchers = $matchers;
+ }
+
+ public function matchesWithDiagnosticDescription($item, Description $mismatchDescription)
+ {
+ /** @var $matcher \Hamcrest\Matcher */
+ foreach ($this->_matchers as $matcher) {
+ if (!$matcher->matches($item)) {
+ $mismatchDescription->appendDescriptionOf($matcher)->appendText(' ');
+ $matcher->describeMismatch($item, $mismatchDescription);
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendList('(', ' and ', ')', $this->_matchers);
+ }
+
+ /**
+ * Evaluates to true only if ALL of the passed in matchers evaluate to true.
+ *
+ * @factory ...
+ */
+ public static function allOf(/* args... */)
+ {
+ $args = func_get_args();
+
+ return new self(Util::createMatcherArray($args));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/AnyOf.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/AnyOf.php
new file mode 100755
index 00000000..4504279f
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/AnyOf.php
@@ -0,0 +1,58 @@
+true.
+ */
+class AnyOf extends ShortcutCombination
+{
+
+ public function __construct(array $matchers)
+ {
+ parent::__construct($matchers);
+ }
+
+ public function matches($item)
+ {
+ return $this->matchesWithShortcut($item, true);
+ }
+
+ public function describeTo(Description $description)
+ {
+ $this->describeToWithOperator($description, 'or');
+ }
+
+ /**
+ * Evaluates to true if ANY of the passed in matchers evaluate to true.
+ *
+ * @factory ...
+ */
+ public static function anyOf(/* args... */)
+ {
+ $args = func_get_args();
+
+ return new self(Util::createMatcherArray($args));
+ }
+
+ /**
+ * Evaluates to false if ANY of the passed in matchers evaluate to true.
+ *
+ * @factory ...
+ */
+ public static function noneOf(/* args... */)
+ {
+ $args = func_get_args();
+
+ return IsNot::not(
+ new self(Util::createMatcherArray($args))
+ );
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/CombinableMatcher.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/CombinableMatcher.php
new file mode 100755
index 00000000..e3b4aa78
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/CombinableMatcher.php
@@ -0,0 +1,78 @@
+_matcher = $matcher;
+ }
+
+ public function matches($item)
+ {
+ return $this->_matcher->matches($item);
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendDescriptionOf($this->_matcher);
+ }
+
+ /** Diversion from Hamcrest-Java... Logical "and" not permitted */
+ public function andAlso(Matcher $other)
+ {
+ return new self(new AllOf($this->_templatedListWith($other)));
+ }
+
+ /** Diversion from Hamcrest-Java... Logical "or" not permitted */
+ public function orElse(Matcher $other)
+ {
+ return new self(new AnyOf($this->_templatedListWith($other)));
+ }
+
+ /**
+ * This is useful for fluently combining matchers that must both pass.
+ * For example:
+ *
+ * assertThat($string, both(containsString("a"))->andAlso(containsString("b")));
+ *
+ *
+ * @factory
+ */
+ public static function both(Matcher $matcher)
+ {
+ return new self($matcher);
+ }
+
+ /**
+ * This is useful for fluently combining matchers where either may pass,
+ * for example:
+ *
+ * assertThat($string, either(containsString("a"))->orElse(containsString("b")));
+ *
+ *
+ * @factory
+ */
+ public static function either(Matcher $matcher)
+ {
+ return new self($matcher);
+ }
+
+ // -- Private Methods
+
+ private function _templatedListWith(Matcher $other)
+ {
+ return array($this->_matcher, $other);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/DescribedAs.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/DescribedAs.php
new file mode 100755
index 00000000..5b2583fa
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/DescribedAs.php
@@ -0,0 +1,68 @@
+_descriptionTemplate = $descriptionTemplate;
+ $this->_matcher = $matcher;
+ $this->_values = $values;
+ }
+
+ public function matches($item)
+ {
+ return $this->_matcher->matches($item);
+ }
+
+ public function describeTo(Description $description)
+ {
+ $textStart = 0;
+ while (preg_match(self::ARG_PATTERN, $this->_descriptionTemplate, $matches, PREG_OFFSET_CAPTURE, $textStart)) {
+ $text = $matches[0][0];
+ $index = $matches[1][0];
+ $offset = $matches[0][1];
+
+ $description->appendText(substr($this->_descriptionTemplate, $textStart, $offset - $textStart));
+ $description->appendValue($this->_values[$index]);
+
+ $textStart = $offset + strlen($text);
+ }
+
+ if ($textStart < strlen($this->_descriptionTemplate)) {
+ $description->appendText(substr($this->_descriptionTemplate, $textStart));
+ }
+ }
+
+ /**
+ * Wraps an existing matcher and overrides the description when it fails.
+ *
+ * @factory ...
+ */
+ public static function describedAs(/* $description, Hamcrest\Matcher $matcher, $values... */)
+ {
+ $args = func_get_args();
+ $description = array_shift($args);
+ $matcher = array_shift($args);
+ $values = $args;
+
+ return new self($description, $matcher, $values);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/Every.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/Every.php
new file mode 100755
index 00000000..d686f8da
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/Every.php
@@ -0,0 +1,56 @@
+_matcher = $matcher;
+ }
+
+ protected function matchesSafelyWithDiagnosticDescription($items, Description $mismatchDescription)
+ {
+ foreach ($items as $item) {
+ if (!$this->_matcher->matches($item)) {
+ $mismatchDescription->appendText('an item ');
+ $this->_matcher->describeMismatch($item, $mismatchDescription);
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText('every item is ')->appendDescriptionOf($this->_matcher);
+ }
+
+ /**
+ * @param Matcher $itemMatcher
+ * A matcher to apply to every element in an array.
+ *
+ * @return \Hamcrest\Core\Every
+ * Evaluates to TRUE for a collection in which every item matches $itemMatcher
+ *
+ * @factory
+ */
+ public static function everyItem(Matcher $itemMatcher)
+ {
+ return new self($itemMatcher);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/HasToString.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/HasToString.php
new file mode 100755
index 00000000..45bd9102
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/HasToString.php
@@ -0,0 +1,56 @@
+toString();
+ }
+
+ return (string) $actual;
+ }
+
+ /**
+ * Does array size satisfy a given matcher?
+ *
+ * @factory
+ */
+ public static function hasToString($matcher)
+ {
+ return new self(Util::wrapValueWithIsEqual($matcher));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/Is.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/Is.php
new file mode 100755
index 00000000..41266dc1
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/Is.php
@@ -0,0 +1,57 @@
+_matcher = $matcher;
+ }
+
+ public function matches($arg)
+ {
+ return $this->_matcher->matches($arg);
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText('is ')->appendDescriptionOf($this->_matcher);
+ }
+
+ public function describeMismatch($item, Description $mismatchDescription)
+ {
+ $this->_matcher->describeMismatch($item, $mismatchDescription);
+ }
+
+ /**
+ * Decorates another Matcher, retaining the behavior but allowing tests
+ * to be slightly more expressive.
+ *
+ * For example: assertThat($cheese, equalTo($smelly))
+ * vs. assertThat($cheese, is(equalTo($smelly)))
+ *
+ * @factory
+ */
+ public static function is($value)
+ {
+ return new self(Util::wrapValueWithIsEqual($value));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsAnything.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsAnything.php
new file mode 100755
index 00000000..f20e6c0d
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsAnything.php
@@ -0,0 +1,45 @@
+true.
+ */
+class IsAnything extends BaseMatcher
+{
+
+ private $_message;
+
+ public function __construct($message = 'ANYTHING')
+ {
+ $this->_message = $message;
+ }
+
+ public function matches($item)
+ {
+ return true;
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText($this->_message);
+ }
+
+ /**
+ * This matcher always evaluates to true.
+ *
+ * @param string $description A meaningful string used when describing itself.
+ *
+ * @return \Hamcrest\Core\IsAnything
+ * @factory
+ */
+ public static function anything($description = 'ANYTHING')
+ {
+ return new self($description);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsCollectionContaining.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsCollectionContaining.php
new file mode 100755
index 00000000..5e60426d
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsCollectionContaining.php
@@ -0,0 +1,93 @@
+_elementMatcher = $elementMatcher;
+ }
+
+ protected function matchesSafely($items)
+ {
+ foreach ($items as $item) {
+ if ($this->_elementMatcher->matches($item)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ protected function describeMismatchSafely($items, Description $mismatchDescription)
+ {
+ $mismatchDescription->appendText('was ')->appendValue($items);
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description
+ ->appendText('a collection containing ')
+ ->appendDescriptionOf($this->_elementMatcher)
+ ;
+ }
+
+ /**
+ * Test if the value is an array containing this matcher.
+ *
+ * Example:
+ *
+ * assertThat(array('a', 'b'), hasItem(equalTo('b')));
+ * //Convenience defaults to equalTo()
+ * assertThat(array('a', 'b'), hasItem('b'));
+ *
+ *
+ * @factory ...
+ */
+ public static function hasItem()
+ {
+ $args = func_get_args();
+ $firstArg = array_shift($args);
+
+ return new self(Util::wrapValueWithIsEqual($firstArg));
+ }
+
+ /**
+ * Test if the value is an array containing elements that match all of these
+ * matchers.
+ *
+ * Example:
+ *
+ * assertThat(array('a', 'b', 'c'), hasItems(equalTo('a'), equalTo('b')));
+ *
+ *
+ * @factory ...
+ */
+ public static function hasItems(/* args... */)
+ {
+ $args = func_get_args();
+ $matchers = array();
+
+ foreach ($args as $arg) {
+ $matchers[] = self::hasItem($arg);
+ }
+
+ return AllOf::allOf($matchers);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsEqual.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsEqual.php
new file mode 100755
index 00000000..523fba0b
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsEqual.php
@@ -0,0 +1,44 @@
+_item = $item;
+ }
+
+ public function matches($arg)
+ {
+ return (($arg == $this->_item) && ($this->_item == $arg));
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendValue($this->_item);
+ }
+
+ /**
+ * Is the value equal to another value, as tested by the use of the "=="
+ * comparison operator?
+ *
+ * @factory
+ */
+ public static function equalTo($item)
+ {
+ return new self($item);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsIdentical.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsIdentical.php
new file mode 100755
index 00000000..28f7b36e
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsIdentical.php
@@ -0,0 +1,38 @@
+_value = $value;
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendValue($this->_value);
+ }
+
+ /**
+ * Tests of the value is identical to $value as tested by the "===" operator.
+ *
+ * @factory
+ */
+ public static function identicalTo($value)
+ {
+ return new self($value);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsInstanceOf.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsInstanceOf.php
new file mode 100755
index 00000000..7a5c92a6
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsInstanceOf.php
@@ -0,0 +1,67 @@
+_theClass = $theClass;
+ }
+
+ protected function matchesWithDiagnosticDescription($item, Description $mismatchDescription)
+ {
+ if (!is_object($item)) {
+ $mismatchDescription->appendText('was ')->appendValue($item);
+
+ return false;
+ }
+
+ if (!($item instanceof $this->_theClass)) {
+ $mismatchDescription->appendText('[' . get_class($item) . '] ')
+ ->appendValue($item);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText('an instance of ')
+ ->appendText($this->_theClass)
+ ;
+ }
+
+ /**
+ * Is the value an instance of a particular type?
+ * This version assumes no relationship between the required type and
+ * the signature of the method that sets it up, for example in
+ * assertThat($anObject, anInstanceOf('Thing'));
+ *
+ * @factory any
+ */
+ public static function anInstanceOf($theClass)
+ {
+ return new self($theClass);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsNot.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsNot.php
new file mode 100755
index 00000000..167f0d06
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsNot.php
@@ -0,0 +1,44 @@
+_matcher = $matcher;
+ }
+
+ public function matches($arg)
+ {
+ return !$this->_matcher->matches($arg);
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText('not ')->appendDescriptionOf($this->_matcher);
+ }
+
+ /**
+ * Matches if value does not match $value.
+ *
+ * @factory
+ */
+ public static function not($value)
+ {
+ return new self(Util::wrapValueWithIsEqual($value));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsNull.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsNull.php
new file mode 100755
index 00000000..91a454c1
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsNull.php
@@ -0,0 +1,56 @@
+appendText('null');
+ }
+
+ /**
+ * Matches if value is null.
+ *
+ * @factory
+ */
+ public static function nullValue()
+ {
+ if (!self::$_INSTANCE) {
+ self::$_INSTANCE = new self();
+ }
+
+ return self::$_INSTANCE;
+ }
+
+ /**
+ * Matches if value is not null.
+ *
+ * @factory
+ */
+ public static function notNullValue()
+ {
+ if (!self::$_NOT_INSTANCE) {
+ self::$_NOT_INSTANCE = IsNot::not(self::nullValue());
+ }
+
+ return self::$_NOT_INSTANCE;
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsSame.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsSame.php
new file mode 100755
index 00000000..81078705
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsSame.php
@@ -0,0 +1,51 @@
+_object = $object;
+ }
+
+ public function matches($object)
+ {
+ return ($object === $this->_object) && ($this->_object === $object);
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText('sameInstance(')
+ ->appendValue($this->_object)
+ ->appendText(')')
+ ;
+ }
+
+ /**
+ * Creates a new instance of IsSame.
+ *
+ * @param mixed $object
+ * The predicate evaluates to true only when the argument is
+ * this object.
+ *
+ * @return \Hamcrest\Core\IsSame
+ * @factory
+ */
+ public static function sameInstance($object)
+ {
+ return new self($object);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsTypeOf.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsTypeOf.php
new file mode 100755
index 00000000..d24f0f94
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/IsTypeOf.php
@@ -0,0 +1,71 @@
+_theType = strtolower($theType);
+ }
+
+ public function matches($item)
+ {
+ return strtolower(gettype($item)) == $this->_theType;
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText(self::getTypeDescription($this->_theType));
+ }
+
+ public function describeMismatch($item, Description $description)
+ {
+ if ($item === null) {
+ $description->appendText('was null');
+ } else {
+ $description->appendText('was ')
+ ->appendText(self::getTypeDescription(strtolower(gettype($item))))
+ ->appendText(' ')
+ ->appendValue($item)
+ ;
+ }
+ }
+
+ public static function getTypeDescription($type)
+ {
+ if ($type == 'null') {
+ return 'null';
+ }
+
+ return (strpos('aeiou', substr($type, 0, 1)) === false ? 'a ' : 'an ')
+ . $type;
+ }
+
+ /**
+ * Is the value a particular built-in type?
+ *
+ * @factory
+ */
+ public static function typeOf($theType)
+ {
+ return new self($theType);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/Set.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/Set.php
new file mode 100755
index 00000000..cdc45d53
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/Set.php
@@ -0,0 +1,95 @@
+
+ * assertThat(array('a', 'b'), set('b'));
+ * assertThat($foo, set('bar'));
+ * assertThat('Server', notSet('defaultPort'));
+ *
+ *
+ * @todo Replace $property with a matcher and iterate all property names.
+ */
+class Set extends BaseMatcher
+{
+
+ private $_property;
+ private $_not;
+
+ public function __construct($property, $not = false)
+ {
+ $this->_property = $property;
+ $this->_not = $not;
+ }
+
+ public function matches($item)
+ {
+ if ($item === null) {
+ return false;
+ }
+ $property = $this->_property;
+ if (is_array($item)) {
+ $result = isset($item[$property]);
+ } elseif (is_object($item)) {
+ $result = isset($item->$property);
+ } elseif (is_string($item)) {
+ $result = isset($item::$$property);
+ } else {
+ throw new \InvalidArgumentException('Must pass an object, array, or class name');
+ }
+
+ return $this->_not ? !$result : $result;
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText($this->_not ? 'unset property ' : 'set property ')->appendText($this->_property);
+ }
+
+ public function describeMismatch($item, Description $description)
+ {
+ $value = '';
+ if (!$this->_not) {
+ $description->appendText('was not set');
+ } else {
+ $property = $this->_property;
+ if (is_array($item)) {
+ $value = $item[$property];
+ } elseif (is_object($item)) {
+ $value = $item->$property;
+ } elseif (is_string($item)) {
+ $value = $item::$$property;
+ }
+ parent::describeMismatch($value, $description);
+ }
+ }
+
+ /**
+ * Matches if value (class, object, or array) has named $property.
+ *
+ * @factory
+ */
+ public static function set($property)
+ {
+ return new self($property);
+ }
+
+ /**
+ * Matches if value (class, object, or array) does not have named $property.
+ *
+ * @factory
+ */
+ public static function notSet($property)
+ {
+ return new self($property, true);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/ShortcutCombination.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/ShortcutCombination.php
new file mode 100755
index 00000000..d93db74f
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Core/ShortcutCombination.php
@@ -0,0 +1,43 @@
+
+ */
+ private $_matchers;
+
+ public function __construct(array $matchers)
+ {
+ Util::checkAllAreMatchers($matchers);
+
+ $this->_matchers = $matchers;
+ }
+
+ protected function matchesWithShortcut($item, $shortcut)
+ {
+ /** @var $matcher \Hamcrest\Matcher */
+ foreach ($this->_matchers as $matcher) {
+ if ($matcher->matches($item) == $shortcut) {
+ return $shortcut;
+ }
+ }
+
+ return !$shortcut;
+ }
+
+ public function describeToWithOperator(Description $description, $operator)
+ {
+ $description->appendList('(', ' ' . $operator . ' ', ')', $this->_matchers);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Description.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Description.php
new file mode 100755
index 00000000..9a482dbf
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Description.php
@@ -0,0 +1,70 @@
+matchesWithDiagnosticDescription($item, new NullDescription());
+ }
+
+ public function describeMismatch($item, Description $mismatchDescription)
+ {
+ $this->matchesWithDiagnosticDescription($item, $mismatchDescription);
+ }
+
+ abstract protected function matchesWithDiagnosticDescription($item, Description $mismatchDescription);
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/FeatureMatcher.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/FeatureMatcher.php
new file mode 100755
index 00000000..59f6cc73
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/FeatureMatcher.php
@@ -0,0 +1,67 @@
+featureValueOf() in a subclass to pull out the feature to be
+ * matched against.
+ */
+abstract class FeatureMatcher extends TypeSafeDiagnosingMatcher
+{
+
+ private $_subMatcher;
+ private $_featureDescription;
+ private $_featureName;
+
+ /**
+ * Constructor.
+ *
+ * @param string $type
+ * @param string $subtype
+ * @param \Hamcrest\Matcher $subMatcher The matcher to apply to the feature
+ * @param string $featureDescription Descriptive text to use in describeTo
+ * @param string $featureName Identifying text for mismatch message
+ */
+ public function __construct($type, $subtype, Matcher $subMatcher, $featureDescription, $featureName)
+ {
+ parent::__construct($type, $subtype);
+
+ $this->_subMatcher = $subMatcher;
+ $this->_featureDescription = $featureDescription;
+ $this->_featureName = $featureName;
+ }
+
+ /**
+ * Implement this to extract the interesting feature.
+ *
+ * @param mixed $actual the target object
+ *
+ * @return mixed the feature to be matched
+ */
+ abstract protected function featureValueOf($actual);
+
+ public function matchesSafelyWithDiagnosticDescription($actual, Description $mismatchDescription)
+ {
+ $featureValue = $this->featureValueOf($actual);
+
+ if (!$this->_subMatcher->matches($featureValue)) {
+ $mismatchDescription->appendText($this->_featureName)
+ ->appendText(' was ')->appendValue($featureValue);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ final public function describeTo(Description $description)
+ {
+ $description->appendText($this->_featureDescription)->appendText(' ')
+ ->appendDescriptionOf($this->_subMatcher)
+ ;
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Internal/SelfDescribingValue.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Internal/SelfDescribingValue.php
new file mode 100755
index 00000000..995da71d
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Internal/SelfDescribingValue.php
@@ -0,0 +1,27 @@
+_value = $value;
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendValue($this->_value);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Matcher.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Matcher.php
new file mode 100755
index 00000000..e5dcf093
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Matcher.php
@@ -0,0 +1,50 @@
+
+ * Matcher implementations should NOT directly implement this interface.
+ * Instead, extend the {@link Hamcrest\BaseMatcher} abstract class,
+ * which will ensure that the Matcher API can grow to support
+ * new features and remain compatible with all Matcher implementations.
+ *
+ * For easy access to common Matcher implementations, use the static factory
+ * methods in {@link Hamcrest\CoreMatchers}.
+ *
+ * @see Hamcrest\CoreMatchers
+ * @see Hamcrest\BaseMatcher
+ */
+interface Matcher extends SelfDescribing
+{
+
+ /**
+ * Evaluates the matcher for argument $item.
+ *
+ * @param mixed $item the object against which the matcher is evaluated.
+ *
+ * @return boolean true if $item matches,
+ * otherwise false.
+ *
+ * @see Hamcrest\BaseMatcher
+ */
+ public function matches($item);
+
+ /**
+ * Generate a description of why the matcher has not accepted the item.
+ * The description will be part of a larger description of why a matching
+ * failed, so it should be concise.
+ * This method assumes that matches($item) is false, but
+ * will not check this.
+ *
+ * @param mixed $item The item that the Matcher has rejected.
+ * @param Description $description
+ * @return
+ */
+ public function describeMismatch($item, Description $description);
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/MatcherAssert.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/MatcherAssert.php
new file mode 100755
index 00000000..d546dbee
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/MatcherAssert.php
@@ -0,0 +1,118 @@
+
+ * // With an identifier
+ * assertThat("apple flavour", $apple->flavour(), equalTo("tasty"));
+ * // Without an identifier
+ * assertThat($apple->flavour(), equalTo("tasty"));
+ * // Evaluating a boolean expression
+ * assertThat("some error", $a > $b);
+ * assertThat($a > $b);
+ *
+ */
+ public static function assertThat(/* $args ... */)
+ {
+ $args = func_get_args();
+ switch (count($args)) {
+ case 1:
+ self::$_count++;
+ if (!$args[0]) {
+ throw new AssertionError();
+ }
+ break;
+
+ case 2:
+ self::$_count++;
+ if ($args[1] instanceof Matcher) {
+ self::doAssert('', $args[0], $args[1]);
+ } elseif (!$args[1]) {
+ throw new AssertionError($args[0]);
+ }
+ break;
+
+ case 3:
+ self::$_count++;
+ self::doAssert(
+ $args[0],
+ $args[1],
+ Util::wrapValueWithIsEqual($args[2])
+ );
+ break;
+
+ default:
+ throw new \InvalidArgumentException('assertThat() requires one to three arguments');
+ }
+ }
+
+ /**
+ * Returns the number of assertions performed.
+ *
+ * @return int
+ */
+ public static function getCount()
+ {
+ return self::$_count;
+ }
+
+ /**
+ * Resets the number of assertions performed to zero.
+ */
+ public static function resetCount()
+ {
+ self::$_count = 0;
+ }
+
+ /**
+ * Performs the actual assertion logic.
+ *
+ * If $matcher doesn't match $actual,
+ * throws a {@link Hamcrest\AssertionError} with a description
+ * of the failure along with the optional $identifier.
+ *
+ * @param string $identifier added to the message upon failure
+ * @param mixed $actual value to compare against $matcher
+ * @param \Hamcrest\Matcher $matcher applied to $actual
+ * @throws AssertionError
+ */
+ private static function doAssert($identifier, $actual, Matcher $matcher)
+ {
+ if (!$matcher->matches($actual)) {
+ $description = new StringDescription();
+ if (!empty($identifier)) {
+ $description->appendText($identifier . PHP_EOL);
+ }
+ $description->appendText('Expected: ')
+ ->appendDescriptionOf($matcher)
+ ->appendText(PHP_EOL . ' but: ');
+
+ $matcher->describeMismatch($actual, $description);
+
+ throw new AssertionError((string) $description);
+ }
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Matchers.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Matchers.php
new file mode 100755
index 00000000..23232e45
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Matchers.php
@@ -0,0 +1,713 @@
+
+ * assertThat($string, both(containsString("a"))->andAlso(containsString("b")));
+ *
+ */
+ public static function both(\Hamcrest\Matcher $matcher)
+ {
+ return \Hamcrest\Core\CombinableMatcher::both($matcher);
+ }
+
+ /**
+ * This is useful for fluently combining matchers where either may pass,
+ * for example:
+ *
+ * assertThat($string, either(containsString("a"))->orElse(containsString("b")));
+ *
+ */
+ public static function either(\Hamcrest\Matcher $matcher)
+ {
+ return \Hamcrest\Core\CombinableMatcher::either($matcher);
+ }
+
+ /**
+ * Wraps an existing matcher and overrides the description when it fails.
+ */
+ public static function describedAs(/* args... */)
+ {
+ $args = func_get_args();
+ return call_user_func_array(array('\Hamcrest\Core\DescribedAs', 'describedAs'), $args);
+ }
+
+ /**
+ * @param Matcher $itemMatcher
+ * A matcher to apply to every element in an array.
+ *
+ * @return \Hamcrest\Core\Every
+ * Evaluates to TRUE for a collection in which every item matches $itemMatcher
+ */
+ public static function everyItem(\Hamcrest\Matcher $itemMatcher)
+ {
+ return \Hamcrest\Core\Every::everyItem($itemMatcher);
+ }
+
+ /**
+ * Does array size satisfy a given matcher?
+ */
+ public static function hasToString($matcher)
+ {
+ return \Hamcrest\Core\HasToString::hasToString($matcher);
+ }
+
+ /**
+ * Decorates another Matcher, retaining the behavior but allowing tests
+ * to be slightly more expressive.
+ *
+ * For example: assertThat($cheese, equalTo($smelly))
+ * vs. assertThat($cheese, is(equalTo($smelly)))
+ */
+ public static function is($value)
+ {
+ return \Hamcrest\Core\Is::is($value);
+ }
+
+ /**
+ * This matcher always evaluates to true.
+ *
+ * @param string $description A meaningful string used when describing itself.
+ *
+ * @return \Hamcrest\Core\IsAnything
+ */
+ public static function anything($description = 'ANYTHING')
+ {
+ return \Hamcrest\Core\IsAnything::anything($description);
+ }
+
+ /**
+ * Test if the value is an array containing this matcher.
+ *
+ * Example:
+ *
+ * assertThat(array('a', 'b'), hasItem(equalTo('b')));
+ * //Convenience defaults to equalTo()
+ * assertThat(array('a', 'b'), hasItem('b'));
+ *
+ */
+ public static function hasItem(/* args... */)
+ {
+ $args = func_get_args();
+ return call_user_func_array(array('\Hamcrest\Core\IsCollectionContaining', 'hasItem'), $args);
+ }
+
+ /**
+ * Test if the value is an array containing elements that match all of these
+ * matchers.
+ *
+ * Example:
+ *
+ * assertThat(array('a', 'b', 'c'), hasItems(equalTo('a'), equalTo('b')));
+ *
+ */
+ public static function hasItems(/* args... */)
+ {
+ $args = func_get_args();
+ return call_user_func_array(array('\Hamcrest\Core\IsCollectionContaining', 'hasItems'), $args);
+ }
+
+ /**
+ * Is the value equal to another value, as tested by the use of the "=="
+ * comparison operator?
+ */
+ public static function equalTo($item)
+ {
+ return \Hamcrest\Core\IsEqual::equalTo($item);
+ }
+
+ /**
+ * Tests of the value is identical to $value as tested by the "===" operator.
+ */
+ public static function identicalTo($value)
+ {
+ return \Hamcrest\Core\IsIdentical::identicalTo($value);
+ }
+
+ /**
+ * Is the value an instance of a particular type?
+ * This version assumes no relationship between the required type and
+ * the signature of the method that sets it up, for example in
+ * assertThat($anObject, anInstanceOf('Thing'));
+ */
+ public static function anInstanceOf($theClass)
+ {
+ return \Hamcrest\Core\IsInstanceOf::anInstanceOf($theClass);
+ }
+
+ /**
+ * Is the value an instance of a particular type?
+ * This version assumes no relationship between the required type and
+ * the signature of the method that sets it up, for example in
+ * assertThat($anObject, anInstanceOf('Thing'));
+ */
+ public static function any($theClass)
+ {
+ return \Hamcrest\Core\IsInstanceOf::anInstanceOf($theClass);
+ }
+
+ /**
+ * Matches if value does not match $value.
+ */
+ public static function not($value)
+ {
+ return \Hamcrest\Core\IsNot::not($value);
+ }
+
+ /**
+ * Matches if value is null.
+ */
+ public static function nullValue()
+ {
+ return \Hamcrest\Core\IsNull::nullValue();
+ }
+
+ /**
+ * Matches if value is not null.
+ */
+ public static function notNullValue()
+ {
+ return \Hamcrest\Core\IsNull::notNullValue();
+ }
+
+ /**
+ * Creates a new instance of IsSame.
+ *
+ * @param mixed $object
+ * The predicate evaluates to true only when the argument is
+ * this object.
+ *
+ * @return \Hamcrest\Core\IsSame
+ */
+ public static function sameInstance($object)
+ {
+ return \Hamcrest\Core\IsSame::sameInstance($object);
+ }
+
+ /**
+ * Is the value a particular built-in type?
+ */
+ public static function typeOf($theType)
+ {
+ return \Hamcrest\Core\IsTypeOf::typeOf($theType);
+ }
+
+ /**
+ * Matches if value (class, object, or array) has named $property.
+ */
+ public static function set($property)
+ {
+ return \Hamcrest\Core\Set::set($property);
+ }
+
+ /**
+ * Matches if value (class, object, or array) does not have named $property.
+ */
+ public static function notSet($property)
+ {
+ return \Hamcrest\Core\Set::notSet($property);
+ }
+
+ /**
+ * Matches if value is a number equal to $value within some range of
+ * acceptable error $delta.
+ */
+ public static function closeTo($value, $delta)
+ {
+ return \Hamcrest\Number\IsCloseTo::closeTo($value, $delta);
+ }
+
+ /**
+ * The value is not > $value, nor < $value.
+ */
+ public static function comparesEqualTo($value)
+ {
+ return \Hamcrest\Number\OrderingComparison::comparesEqualTo($value);
+ }
+
+ /**
+ * The value is > $value.
+ */
+ public static function greaterThan($value)
+ {
+ return \Hamcrest\Number\OrderingComparison::greaterThan($value);
+ }
+
+ /**
+ * The value is >= $value.
+ */
+ public static function greaterThanOrEqualTo($value)
+ {
+ return \Hamcrest\Number\OrderingComparison::greaterThanOrEqualTo($value);
+ }
+
+ /**
+ * The value is >= $value.
+ */
+ public static function atLeast($value)
+ {
+ return \Hamcrest\Number\OrderingComparison::greaterThanOrEqualTo($value);
+ }
+
+ /**
+ * The value is < $value.
+ */
+ public static function lessThan($value)
+ {
+ return \Hamcrest\Number\OrderingComparison::lessThan($value);
+ }
+
+ /**
+ * The value is <= $value.
+ */
+ public static function lessThanOrEqualTo($value)
+ {
+ return \Hamcrest\Number\OrderingComparison::lessThanOrEqualTo($value);
+ }
+
+ /**
+ * The value is <= $value.
+ */
+ public static function atMost($value)
+ {
+ return \Hamcrest\Number\OrderingComparison::lessThanOrEqualTo($value);
+ }
+
+ /**
+ * Matches if value is a zero-length string.
+ */
+ public static function isEmptyString()
+ {
+ return \Hamcrest\Text\IsEmptyString::isEmptyString();
+ }
+
+ /**
+ * Matches if value is a zero-length string.
+ */
+ public static function emptyString()
+ {
+ return \Hamcrest\Text\IsEmptyString::isEmptyString();
+ }
+
+ /**
+ * Matches if value is null or a zero-length string.
+ */
+ public static function isEmptyOrNullString()
+ {
+ return \Hamcrest\Text\IsEmptyString::isEmptyOrNullString();
+ }
+
+ /**
+ * Matches if value is null or a zero-length string.
+ */
+ public static function nullOrEmptyString()
+ {
+ return \Hamcrest\Text\IsEmptyString::isEmptyOrNullString();
+ }
+
+ /**
+ * Matches if value is a non-zero-length string.
+ */
+ public static function isNonEmptyString()
+ {
+ return \Hamcrest\Text\IsEmptyString::isNonEmptyString();
+ }
+
+ /**
+ * Matches if value is a non-zero-length string.
+ */
+ public static function nonEmptyString()
+ {
+ return \Hamcrest\Text\IsEmptyString::isNonEmptyString();
+ }
+
+ /**
+ * Matches if value is a string equal to $string, regardless of the case.
+ */
+ public static function equalToIgnoringCase($string)
+ {
+ return \Hamcrest\Text\IsEqualIgnoringCase::equalToIgnoringCase($string);
+ }
+
+ /**
+ * Matches if value is a string equal to $string, regardless of whitespace.
+ */
+ public static function equalToIgnoringWhiteSpace($string)
+ {
+ return \Hamcrest\Text\IsEqualIgnoringWhiteSpace::equalToIgnoringWhiteSpace($string);
+ }
+
+ /**
+ * Matches if value is a string that matches regular expression $pattern.
+ */
+ public static function matchesPattern($pattern)
+ {
+ return \Hamcrest\Text\MatchesPattern::matchesPattern($pattern);
+ }
+
+ /**
+ * Matches if value is a string that contains $substring.
+ */
+ public static function containsString($substring)
+ {
+ return \Hamcrest\Text\StringContains::containsString($substring);
+ }
+
+ /**
+ * Matches if value is a string that contains $substring regardless of the case.
+ */
+ public static function containsStringIgnoringCase($substring)
+ {
+ return \Hamcrest\Text\StringContainsIgnoringCase::containsStringIgnoringCase($substring);
+ }
+
+ /**
+ * Matches if value contains $substrings in a constrained order.
+ */
+ public static function stringContainsInOrder(/* args... */)
+ {
+ $args = func_get_args();
+ return call_user_func_array(array('\Hamcrest\Text\StringContainsInOrder', 'stringContainsInOrder'), $args);
+ }
+
+ /**
+ * Matches if value is a string that ends with $substring.
+ */
+ public static function endsWith($substring)
+ {
+ return \Hamcrest\Text\StringEndsWith::endsWith($substring);
+ }
+
+ /**
+ * Matches if value is a string that starts with $substring.
+ */
+ public static function startsWith($substring)
+ {
+ return \Hamcrest\Text\StringStartsWith::startsWith($substring);
+ }
+
+ /**
+ * Is the value an array?
+ */
+ public static function arrayValue()
+ {
+ return \Hamcrest\Type\IsArray::arrayValue();
+ }
+
+ /**
+ * Is the value a boolean?
+ */
+ public static function booleanValue()
+ {
+ return \Hamcrest\Type\IsBoolean::booleanValue();
+ }
+
+ /**
+ * Is the value a boolean?
+ */
+ public static function boolValue()
+ {
+ return \Hamcrest\Type\IsBoolean::booleanValue();
+ }
+
+ /**
+ * Is the value callable?
+ */
+ public static function callableValue()
+ {
+ return \Hamcrest\Type\IsCallable::callableValue();
+ }
+
+ /**
+ * Is the value a float/double?
+ */
+ public static function doubleValue()
+ {
+ return \Hamcrest\Type\IsDouble::doubleValue();
+ }
+
+ /**
+ * Is the value a float/double?
+ */
+ public static function floatValue()
+ {
+ return \Hamcrest\Type\IsDouble::doubleValue();
+ }
+
+ /**
+ * Is the value an integer?
+ */
+ public static function integerValue()
+ {
+ return \Hamcrest\Type\IsInteger::integerValue();
+ }
+
+ /**
+ * Is the value an integer?
+ */
+ public static function intValue()
+ {
+ return \Hamcrest\Type\IsInteger::integerValue();
+ }
+
+ /**
+ * Is the value a numeric?
+ */
+ public static function numericValue()
+ {
+ return \Hamcrest\Type\IsNumeric::numericValue();
+ }
+
+ /**
+ * Is the value an object?
+ */
+ public static function objectValue()
+ {
+ return \Hamcrest\Type\IsObject::objectValue();
+ }
+
+ /**
+ * Is the value an object?
+ */
+ public static function anObject()
+ {
+ return \Hamcrest\Type\IsObject::objectValue();
+ }
+
+ /**
+ * Is the value a resource?
+ */
+ public static function resourceValue()
+ {
+ return \Hamcrest\Type\IsResource::resourceValue();
+ }
+
+ /**
+ * Is the value a scalar (boolean, integer, double, or string)?
+ */
+ public static function scalarValue()
+ {
+ return \Hamcrest\Type\IsScalar::scalarValue();
+ }
+
+ /**
+ * Is the value a string?
+ */
+ public static function stringValue()
+ {
+ return \Hamcrest\Type\IsString::stringValue();
+ }
+
+ /**
+ * Wraps $matcher with {@link Hamcrest\Core\IsEqual)
+ * if it's not a matcher and the XPath in count()
+ * if it's an integer.
+ */
+ public static function hasXPath($xpath, $matcher = null)
+ {
+ return \Hamcrest\Xml\HasXPath::hasXPath($xpath, $matcher);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/NullDescription.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/NullDescription.php
new file mode 100755
index 00000000..aae8e461
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/NullDescription.php
@@ -0,0 +1,43 @@
+_value = $value;
+ $this->_delta = $delta;
+ }
+
+ protected function matchesSafely($item)
+ {
+ return $this->_actualDelta($item) <= 0.0;
+ }
+
+ protected function describeMismatchSafely($item, Description $mismatchDescription)
+ {
+ $mismatchDescription->appendValue($item)
+ ->appendText(' differed by ')
+ ->appendValue($this->_actualDelta($item))
+ ;
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText('a numeric value within ')
+ ->appendValue($this->_delta)
+ ->appendText(' of ')
+ ->appendValue($this->_value)
+ ;
+ }
+
+ /**
+ * Matches if value is a number equal to $value within some range of
+ * acceptable error $delta.
+ *
+ * @factory
+ */
+ public static function closeTo($value, $delta)
+ {
+ return new self($value, $delta);
+ }
+
+ // -- Private Methods
+
+ private function _actualDelta($item)
+ {
+ return (abs(($item - $this->_value)) - $this->_delta);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Number/OrderingComparison.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Number/OrderingComparison.php
new file mode 100755
index 00000000..369d0cfa
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Number/OrderingComparison.php
@@ -0,0 +1,132 @@
+_value = $value;
+ $this->_minCompare = $minCompare;
+ $this->_maxCompare = $maxCompare;
+ }
+
+ protected function matchesSafely($other)
+ {
+ $compare = $this->_compare($this->_value, $other);
+
+ return ($this->_minCompare <= $compare) && ($compare <= $this->_maxCompare);
+ }
+
+ protected function describeMismatchSafely($item, Description $mismatchDescription)
+ {
+ $mismatchDescription
+ ->appendValue($item)->appendText(' was ')
+ ->appendText($this->_comparison($this->_compare($this->_value, $item)))
+ ->appendText(' ')->appendValue($this->_value)
+ ;
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText('a value ')
+ ->appendText($this->_comparison($this->_minCompare))
+ ;
+ if ($this->_minCompare != $this->_maxCompare) {
+ $description->appendText(' or ')
+ ->appendText($this->_comparison($this->_maxCompare))
+ ;
+ }
+ $description->appendText(' ')->appendValue($this->_value);
+ }
+
+ /**
+ * The value is not > $value, nor < $value.
+ *
+ * @factory
+ */
+ public static function comparesEqualTo($value)
+ {
+ return new self($value, 0, 0);
+ }
+
+ /**
+ * The value is > $value.
+ *
+ * @factory
+ */
+ public static function greaterThan($value)
+ {
+ return new self($value, -1, -1);
+ }
+
+ /**
+ * The value is >= $value.
+ *
+ * @factory atLeast
+ */
+ public static function greaterThanOrEqualTo($value)
+ {
+ return new self($value, -1, 0);
+ }
+
+ /**
+ * The value is < $value.
+ *
+ * @factory
+ */
+ public static function lessThan($value)
+ {
+ return new self($value, 1, 1);
+ }
+
+ /**
+ * The value is <= $value.
+ *
+ * @factory atMost
+ */
+ public static function lessThanOrEqualTo($value)
+ {
+ return new self($value, 0, 1);
+ }
+
+ // -- Private Methods
+
+ private function _compare($left, $right)
+ {
+ $a = $left;
+ $b = $right;
+
+ if ($a < $b) {
+ return -1;
+ } elseif ($a == $b) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+ private function _comparison($compare)
+ {
+ if ($compare > 0) {
+ return 'less than';
+ } elseif ($compare == 0) {
+ return 'equal to';
+ } else {
+ return 'greater than';
+ }
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/SelfDescribing.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/SelfDescribing.php
new file mode 100755
index 00000000..872fdf9c
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/SelfDescribing.php
@@ -0,0 +1,23 @@
+_out = (string) $out;
+ }
+
+ public function __toString()
+ {
+ return $this->_out;
+ }
+
+ /**
+ * Return the description of a {@link Hamcrest\SelfDescribing} object as a
+ * String.
+ *
+ * @param \Hamcrest\SelfDescribing $selfDescribing
+ * The object to be described.
+ *
+ * @return string
+ * The description of the object.
+ */
+ public static function toString(SelfDescribing $selfDescribing)
+ {
+ $self = new self();
+
+ return (string) $self->appendDescriptionOf($selfDescribing);
+ }
+
+ /**
+ * Alias for {@link toString()}.
+ */
+ public static function asString(SelfDescribing $selfDescribing)
+ {
+ return self::toString($selfDescribing);
+ }
+
+ // -- Protected Methods
+
+ protected function append($str)
+ {
+ $this->_out .= $str;
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/IsEmptyString.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/IsEmptyString.php
new file mode 100755
index 00000000..2ae61b96
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/IsEmptyString.php
@@ -0,0 +1,85 @@
+_empty = $empty;
+ }
+
+ public function matches($item)
+ {
+ return $this->_empty
+ ? ($item === '')
+ : is_string($item) && $item !== '';
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText($this->_empty ? 'an empty string' : 'a non-empty string');
+ }
+
+ /**
+ * Matches if value is a zero-length string.
+ *
+ * @factory emptyString
+ */
+ public static function isEmptyString()
+ {
+ if (!self::$_INSTANCE) {
+ self::$_INSTANCE = new self(true);
+ }
+
+ return self::$_INSTANCE;
+ }
+
+ /**
+ * Matches if value is null or a zero-length string.
+ *
+ * @factory nullOrEmptyString
+ */
+ public static function isEmptyOrNullString()
+ {
+ if (!self::$_NULL_OR_EMPTY_INSTANCE) {
+ self::$_NULL_OR_EMPTY_INSTANCE = AnyOf::anyOf(
+ IsNull::nullvalue(),
+ self::isEmptyString()
+ );
+ }
+
+ return self::$_NULL_OR_EMPTY_INSTANCE;
+ }
+
+ /**
+ * Matches if value is a non-zero-length string.
+ *
+ * @factory nonEmptyString
+ */
+ public static function isNonEmptyString()
+ {
+ if (!self::$_NOT_INSTANCE) {
+ self::$_NOT_INSTANCE = new self(false);
+ }
+
+ return self::$_NOT_INSTANCE;
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/IsEqualIgnoringCase.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/IsEqualIgnoringCase.php
new file mode 100755
index 00000000..3836a8c3
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/IsEqualIgnoringCase.php
@@ -0,0 +1,52 @@
+_string = $string;
+ }
+
+ protected function matchesSafely($item)
+ {
+ return strtolower($this->_string) === strtolower($item);
+ }
+
+ protected function describeMismatchSafely($item, Description $mismatchDescription)
+ {
+ $mismatchDescription->appendText('was ')->appendText($item);
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText('equalToIgnoringCase(')
+ ->appendValue($this->_string)
+ ->appendText(')')
+ ;
+ }
+
+ /**
+ * Matches if value is a string equal to $string, regardless of the case.
+ *
+ * @factory
+ */
+ public static function equalToIgnoringCase($string)
+ {
+ return new self($string);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/IsEqualIgnoringWhiteSpace.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/IsEqualIgnoringWhiteSpace.php
new file mode 100755
index 00000000..853692b0
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/IsEqualIgnoringWhiteSpace.php
@@ -0,0 +1,66 @@
+_string = $string;
+ }
+
+ protected function matchesSafely($item)
+ {
+ return (strtolower($this->_stripSpace($item))
+ === strtolower($this->_stripSpace($this->_string)));
+ }
+
+ protected function describeMismatchSafely($item, Description $mismatchDescription)
+ {
+ $mismatchDescription->appendText('was ')->appendText($item);
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText('equalToIgnoringWhiteSpace(')
+ ->appendValue($this->_string)
+ ->appendText(')')
+ ;
+ }
+
+ /**
+ * Matches if value is a string equal to $string, regardless of whitespace.
+ *
+ * @factory
+ */
+ public static function equalToIgnoringWhiteSpace($string)
+ {
+ return new self($string);
+ }
+
+ // -- Private Methods
+
+ private function _stripSpace($string)
+ {
+ $parts = preg_split("/[\r\n\t ]+/", $string);
+ foreach ($parts as $i => $part) {
+ $parts[$i] = trim($part, " \r\n\t");
+ }
+
+ return trim(implode(' ', $parts), " \r\n\t");
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/MatchesPattern.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/MatchesPattern.php
new file mode 100755
index 00000000..fa0d68ee
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/MatchesPattern.php
@@ -0,0 +1,40 @@
+_substring, (string) $item) >= 1;
+ }
+
+ protected function relationship()
+ {
+ return 'matching';
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/StringContains.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/StringContains.php
new file mode 100755
index 00000000..b92786b6
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/StringContains.php
@@ -0,0 +1,45 @@
+_substring);
+ }
+
+ /**
+ * Matches if value is a string that contains $substring.
+ *
+ * @factory
+ */
+ public static function containsString($substring)
+ {
+ return new self($substring);
+ }
+
+ // -- Protected Methods
+
+ protected function evalSubstringOf($item)
+ {
+ return (false !== strpos((string) $item, $this->_substring));
+ }
+
+ protected function relationship()
+ {
+ return 'containing';
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/StringContainsIgnoringCase.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/StringContainsIgnoringCase.php
new file mode 100755
index 00000000..69f37c25
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/StringContainsIgnoringCase.php
@@ -0,0 +1,40 @@
+_substring));
+ }
+
+ protected function relationship()
+ {
+ return 'containing in any case';
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/StringContainsInOrder.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/StringContainsInOrder.php
new file mode 100755
index 00000000..e75de65d
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/StringContainsInOrder.php
@@ -0,0 +1,66 @@
+_substrings = $substrings;
+ }
+
+ protected function matchesSafely($item)
+ {
+ $fromIndex = 0;
+
+ foreach ($this->_substrings as $substring) {
+ if (false === $fromIndex = strpos($item, $substring, $fromIndex)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ protected function describeMismatchSafely($item, Description $mismatchDescription)
+ {
+ $mismatchDescription->appendText('was ')->appendText($item);
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText('a string containing ')
+ ->appendValueList('', ', ', '', $this->_substrings)
+ ->appendText(' in order')
+ ;
+ }
+
+ /**
+ * Matches if value contains $substrings in a constrained order.
+ *
+ * @factory ...
+ */
+ public static function stringContainsInOrder(/* args... */)
+ {
+ $args = func_get_args();
+
+ if (isset($args[0]) && is_array($args[0])) {
+ $args = $args[0];
+ }
+
+ return new self($args);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/StringEndsWith.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/StringEndsWith.php
new file mode 100755
index 00000000..f802ee4d
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/StringEndsWith.php
@@ -0,0 +1,40 @@
+_substring))) === $this->_substring);
+ }
+
+ protected function relationship()
+ {
+ return 'ending with';
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/StringStartsWith.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/StringStartsWith.php
new file mode 100755
index 00000000..79c95656
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/StringStartsWith.php
@@ -0,0 +1,40 @@
+_substring)) === $this->_substring);
+ }
+
+ protected function relationship()
+ {
+ return 'starting with';
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/SubstringMatcher.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/SubstringMatcher.php
new file mode 100755
index 00000000..e560ad62
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Text/SubstringMatcher.php
@@ -0,0 +1,45 @@
+_substring = $substring;
+ }
+
+ protected function matchesSafely($item)
+ {
+ return $this->evalSubstringOf($item);
+ }
+
+ protected function describeMismatchSafely($item, Description $mismatchDescription)
+ {
+ $mismatchDescription->appendText('was "')->appendText($item)->appendText('"');
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText('a string ')
+ ->appendText($this->relationship())
+ ->appendText(' ')
+ ->appendValue($this->_substring)
+ ;
+ }
+
+ abstract protected function evalSubstringOf($string);
+
+ abstract protected function relationship();
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Type/IsArray.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Type/IsArray.php
new file mode 100755
index 00000000..9179102f
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Type/IsArray.php
@@ -0,0 +1,32 @@
+isHexadecimal($item)) {
+ return true;
+ }
+
+ return is_numeric($item);
+ }
+
+ /**
+ * Return if the string passed is a valid hexadecimal number.
+ * This check is necessary because PHP 7 doesn't recognize hexadecimal string as numeric anymore.
+ *
+ * @param mixed $item
+ * @return boolean
+ */
+ private function isHexadecimal($item)
+ {
+ if (is_string($item) && preg_match('/^0x(.*)$/', $item, $matches)) {
+ return ctype_xdigit($matches[1]);
+ }
+
+ return false;
+ }
+
+ /**
+ * Is the value a numeric?
+ *
+ * @factory
+ */
+ public static function numericValue()
+ {
+ return new self;
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Type/IsObject.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Type/IsObject.php
new file mode 100755
index 00000000..65918fcf
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Type/IsObject.php
@@ -0,0 +1,32 @@
+matchesSafelyWithDiagnosticDescription($item, new NullDescription());
+ }
+
+ final public function describeMismatchSafely($item, Description $mismatchDescription)
+ {
+ $this->matchesSafelyWithDiagnosticDescription($item, $mismatchDescription);
+ }
+
+ // -- Protected Methods
+
+ /**
+ * Subclasses should implement these. The item will already have been checked for
+ * the specific type.
+ */
+ abstract protected function matchesSafelyWithDiagnosticDescription($item, Description $mismatchDescription);
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/TypeSafeMatcher.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/TypeSafeMatcher.php
new file mode 100755
index 00000000..56e299a9
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/TypeSafeMatcher.php
@@ -0,0 +1,107 @@
+_expectedType = $expectedType;
+ $this->_expectedSubtype = $expectedSubtype;
+ }
+
+ final public function matches($item)
+ {
+ return $this->_isSafeType($item) && $this->matchesSafely($item);
+ }
+
+ final public function describeMismatch($item, Description $mismatchDescription)
+ {
+ if (!$this->_isSafeType($item)) {
+ parent::describeMismatch($item, $mismatchDescription);
+ } else {
+ $this->describeMismatchSafely($item, $mismatchDescription);
+ }
+ }
+
+ // -- Protected Methods
+
+ /**
+ * The item will already have been checked for the specific type and subtype.
+ */
+ abstract protected function matchesSafely($item);
+
+ /**
+ * The item will already have been checked for the specific type and subtype.
+ */
+ abstract protected function describeMismatchSafely($item, Description $mismatchDescription);
+
+ // -- Private Methods
+
+ private function _isSafeType($value)
+ {
+ switch ($this->_expectedType) {
+
+ case self::TYPE_ANY:
+ return true;
+
+ case self::TYPE_STRING:
+ return is_string($value) || is_numeric($value);
+
+ case self::TYPE_NUMERIC:
+ return is_numeric($value) || is_string($value);
+
+ case self::TYPE_ARRAY:
+ return is_array($value);
+
+ case self::TYPE_OBJECT:
+ return is_object($value)
+ && ($this->_expectedSubtype === null
+ || $value instanceof $this->_expectedSubtype);
+
+ case self::TYPE_RESOURCE:
+ return is_resource($value)
+ && ($this->_expectedSubtype === null
+ || get_resource_type($value) == $this->_expectedSubtype);
+
+ case self::TYPE_BOOLEAN:
+ return true;
+
+ default:
+ return true;
+
+ }
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Util.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Util.php
new file mode 100755
index 00000000..169b0366
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Util.php
@@ -0,0 +1,76 @@
+ all items are
+ */
+ public static function createMatcherArray(array $items)
+ {
+ //Extract single array item
+ if (count($items) == 1 && is_array($items[0])) {
+ $items = $items[0];
+ }
+
+ //Replace non-matchers
+ foreach ($items as &$item) {
+ if (!($item instanceof Matcher)) {
+ $item = Core\IsEqual::equalTo($item);
+ }
+ }
+
+ return $items;
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Xml/HasXPath.php b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Xml/HasXPath.php
new file mode 100755
index 00000000..d9764e45
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest/Xml/HasXPath.php
@@ -0,0 +1,195 @@
+_xpath = $xpath;
+ $this->_matcher = $matcher;
+ }
+
+ /**
+ * Matches if the XPath matches against the DOM node and the matcher.
+ *
+ * @param string|\DOMNode $actual
+ * @param Description $mismatchDescription
+ * @return bool
+ */
+ protected function matchesWithDiagnosticDescription($actual, Description $mismatchDescription)
+ {
+ if (is_string($actual)) {
+ $actual = $this->createDocument($actual);
+ } elseif (!$actual instanceof \DOMNode) {
+ $mismatchDescription->appendText('was ')->appendValue($actual);
+
+ return false;
+ }
+ $result = $this->evaluate($actual);
+ if ($result instanceof \DOMNodeList) {
+ return $this->matchesContent($result, $mismatchDescription);
+ } else {
+ return $this->matchesExpression($result, $mismatchDescription);
+ }
+ }
+
+ /**
+ * Creates and returns a DOMDocument from the given
+ * XML or HTML string.
+ *
+ * @param string $text
+ * @return \DOMDocument built from $text
+ * @throws \InvalidArgumentException if the document is not valid
+ */
+ protected function createDocument($text)
+ {
+ $document = new \DOMDocument();
+ if (preg_match('/^\s*<\?xml/', $text)) {
+ if (!@$document->loadXML($text)) {
+ throw new \InvalidArgumentException('Must pass a valid XML document');
+ }
+ } else {
+ if (!@$document->loadHTML($text)) {
+ throw new \InvalidArgumentException('Must pass a valid HTML or XHTML document');
+ }
+ }
+
+ return $document;
+ }
+
+ /**
+ * Applies the configured XPath to the DOM node and returns either
+ * the result if it's an expression or the node list if it's a query.
+ *
+ * @param \DOMNode $node context from which to issue query
+ * @return mixed result of expression or DOMNodeList from query
+ */
+ protected function evaluate(\DOMNode $node)
+ {
+ if ($node instanceof \DOMDocument) {
+ $xpathDocument = new \DOMXPath($node);
+
+ return $xpathDocument->evaluate($this->_xpath);
+ } else {
+ $xpathDocument = new \DOMXPath($node->ownerDocument);
+
+ return $xpathDocument->evaluate($this->_xpath, $node);
+ }
+ }
+
+ /**
+ * Matches if the list of nodes is not empty and the content of at least
+ * one node matches the configured matcher, if supplied.
+ *
+ * @param \DOMNodeList $nodes selected by the XPath query
+ * @param Description $mismatchDescription
+ * @return bool
+ */
+ protected function matchesContent(\DOMNodeList $nodes, Description $mismatchDescription)
+ {
+ if ($nodes->length == 0) {
+ $mismatchDescription->appendText('XPath returned no results');
+ } elseif ($this->_matcher === null) {
+ return true;
+ } else {
+ foreach ($nodes as $node) {
+ if ($this->_matcher->matches($node->textContent)) {
+ return true;
+ }
+ }
+ $content = array();
+ foreach ($nodes as $node) {
+ $content[] = $node->textContent;
+ }
+ $mismatchDescription->appendText('XPath returned ')
+ ->appendValue($content);
+ }
+
+ return false;
+ }
+
+ /**
+ * Matches if the result of the XPath expression matches the configured
+ * matcher or evaluates to true if there is none.
+ *
+ * @param mixed $result result of the XPath expression
+ * @param Description $mismatchDescription
+ * @return bool
+ */
+ protected function matchesExpression($result, Description $mismatchDescription)
+ {
+ if ($this->_matcher === null) {
+ if ($result) {
+ return true;
+ }
+ $mismatchDescription->appendText('XPath expression result was ')
+ ->appendValue($result);
+ } else {
+ if ($this->_matcher->matches($result)) {
+ return true;
+ }
+ $mismatchDescription->appendText('XPath expression result ');
+ $this->_matcher->describeMismatch($result, $mismatchDescription);
+ }
+
+ return false;
+ }
+
+ public function describeTo(Description $description)
+ {
+ $description->appendText('XML or HTML document with XPath "')
+ ->appendText($this->_xpath)
+ ->appendText('"');
+ if ($this->_matcher !== null) {
+ $description->appendText(' ');
+ $this->_matcher->describeTo($description);
+ }
+ }
+
+ /**
+ * Wraps $matcher with {@link Hamcrest\Core\IsEqual)
+ * if it's not a matcher and the XPath in count()
+ * if it's an integer.
+ *
+ * @factory
+ */
+ public static function hasXPath($xpath, $matcher = null)
+ {
+ if ($matcher === null || $matcher instanceof Matcher) {
+ return new self($xpath, $matcher);
+ } elseif (is_int($matcher) && strpos($xpath, 'count(') !== 0) {
+ $xpath = 'count(' . $xpath . ')';
+ }
+
+ return new self($xpath, IsEqual::equalTo($matcher));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/AbstractMatcherTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/AbstractMatcherTest.php
new file mode 100755
index 00000000..8a1fb2a9
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/AbstractMatcherTest.php
@@ -0,0 +1,68 @@
+assertTrue($matcher->matches($arg), $message);
+ }
+
+ public function assertDoesNotMatch(\Hamcrest\Matcher $matcher, $arg, $message)
+ {
+ $this->assertFalse($matcher->matches($arg), $message);
+ }
+
+ public function assertDescription($expected, \Hamcrest\Matcher $matcher)
+ {
+ $description = new \Hamcrest\StringDescription();
+ $description->appendDescriptionOf($matcher);
+ $this->assertEquals($expected, (string) $description, 'Expected description');
+ }
+
+ public function assertMismatchDescription($expected, \Hamcrest\Matcher $matcher, $arg)
+ {
+ $description = new \Hamcrest\StringDescription();
+ $this->assertFalse(
+ $matcher->matches($arg),
+ 'Precondtion: Matcher should not match item'
+ );
+ $matcher->describeMismatch($arg, $description);
+ $this->assertEquals(
+ $expected,
+ (string) $description,
+ 'Expected mismatch description'
+ );
+ }
+
+ public function testIsNullSafe()
+ {
+ //Should not generate any notices
+ $this->createMatcher()->matches(null);
+ $this->createMatcher()->describeMismatch(
+ null,
+ new \Hamcrest\NullDescription()
+ );
+ }
+
+ public function testCopesWithUnknownTypes()
+ {
+ //Should not generate any notices
+ $this->createMatcher()->matches(new UnknownType());
+ $this->createMatcher()->describeMismatch(
+ new UnknownType(),
+ new NullDescription()
+ );
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayContainingInAnyOrderTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayContainingInAnyOrderTest.php
new file mode 100755
index 00000000..45d9f138
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayContainingInAnyOrderTest.php
@@ -0,0 +1,54 @@
+assertDescription('[<1>, <2>] in any order', containsInAnyOrder(array(1, 2)));
+ }
+
+ public function testMatchesItemsInAnyOrder()
+ {
+ $this->assertMatches(containsInAnyOrder(array(1, 2, 3)), array(1, 2, 3), 'in order');
+ $this->assertMatches(containsInAnyOrder(array(1, 2, 3)), array(3, 2, 1), 'out of order');
+ $this->assertMatches(containsInAnyOrder(array(1)), array(1), 'single');
+ }
+
+ public function testAppliesMatchersInAnyOrder()
+ {
+ $this->assertMatches(
+ containsInAnyOrder(array(1, 2, 3)),
+ array(1, 2, 3),
+ 'in order'
+ );
+ $this->assertMatches(
+ containsInAnyOrder(array(1, 2, 3)),
+ array(3, 2, 1),
+ 'out of order'
+ );
+ $this->assertMatches(
+ containsInAnyOrder(array(1)),
+ array(1),
+ 'single'
+ );
+ }
+
+ public function testMismatchesItemsInAnyOrder()
+ {
+ $matcher = containsInAnyOrder(array(1, 2, 3));
+
+ $this->assertMismatchDescription('was null', $matcher, null);
+ $this->assertMismatchDescription('No item matches: <1>, <2>, <3> in []', $matcher, array());
+ $this->assertMismatchDescription('No item matches: <2>, <3> in [<1>]', $matcher, array(1));
+ $this->assertMismatchDescription('Not matched: <4>', $matcher, array(4, 3, 2, 1));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayContainingInOrderTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayContainingInOrderTest.php
new file mode 100755
index 00000000..a9e4e5b0
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayContainingInOrderTest.php
@@ -0,0 +1,48 @@
+assertDescription('[<1>, <2>]', arrayContaining(array(1, 2)));
+ }
+
+ public function testMatchesItemsInOrder()
+ {
+ $this->assertMatches(arrayContaining(array(1, 2, 3)), array(1, 2, 3), 'in order');
+ $this->assertMatches(arrayContaining(array(1)), array(1), 'single');
+ }
+
+ public function testAppliesMatchersInOrder()
+ {
+ $this->assertMatches(
+ arrayContaining(array(1, 2, 3)),
+ array(1, 2, 3),
+ 'in order'
+ );
+ $this->assertMatches(arrayContaining(array(1)), array(1), 'single');
+ }
+
+ public function testMismatchesItemsInAnyOrder()
+ {
+ if (defined('HHVM_VERSION')) {
+ $this->markTestSkipped('Broken on HHVM.');
+ }
+
+ $matcher = arrayContaining(array(1, 2, 3));
+ $this->assertMismatchDescription('was null', $matcher, null);
+ $this->assertMismatchDescription('No item matched: <1>', $matcher, array());
+ $this->assertMismatchDescription('No item matched: <2>', $matcher, array(1));
+ $this->assertMismatchDescription('item with key 0: was <4>', $matcher, array(4, 3, 2, 1));
+ $this->assertMismatchDescription('item with key 2: was <4>', $matcher, array(1, 2, 4));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayContainingKeyTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayContainingKeyTest.php
new file mode 100755
index 00000000..31770d8d
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayContainingKeyTest.php
@@ -0,0 +1,62 @@
+1);
+
+ $this->assertMatches(hasKey('a'), $array, 'Matches single key');
+ }
+
+ public function testMatchesArrayContainingKey()
+ {
+ $array = array('a'=>1, 'b'=>2, 'c'=>3);
+
+ $this->assertMatches(hasKey('a'), $array, 'Matches a');
+ $this->assertMatches(hasKey('c'), $array, 'Matches c');
+ }
+
+ public function testMatchesArrayContainingKeyWithIntegerKeys()
+ {
+ $array = array(1=>'A', 2=>'B');
+
+ assertThat($array, hasKey(1));
+ }
+
+ public function testMatchesArrayContainingKeyWithNumberKeys()
+ {
+ $array = array(1=>'A', 2=>'B');
+
+ assertThat($array, hasKey(1));
+
+ // very ugly version!
+ assertThat($array, IsArrayContainingKey::hasKeyInArray(2));
+ }
+
+ public function testHasReadableDescription()
+ {
+ $this->assertDescription('array with key "a"', hasKey('a'));
+ }
+
+ public function testDoesNotMatchEmptyArray()
+ {
+ $this->assertMismatchDescription('array was []', hasKey('Foo'), array());
+ }
+
+ public function testDoesNotMatchArrayMissingKey()
+ {
+ $array = array('a'=>1, 'b'=>2, 'c'=>3);
+
+ $this->assertMismatchDescription('array was ["a" => <1>, "b" => <2>, "c" => <3>]', hasKey('d'), $array);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayContainingKeyValuePairTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayContainingKeyValuePairTest.php
new file mode 100755
index 00000000..a415f9f7
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayContainingKeyValuePairTest.php
@@ -0,0 +1,36 @@
+1, 'b'=>2);
+
+ $this->assertMatches(hasKeyValuePair(equalTo('a'), equalTo(1)), $array, 'matcherA');
+ $this->assertMatches(hasKeyValuePair(equalTo('b'), equalTo(2)), $array, 'matcherB');
+ $this->assertMismatchDescription(
+ 'array was ["a" => <1>, "b" => <2>]',
+ hasKeyValuePair(equalTo('c'), equalTo(3)),
+ $array
+ );
+ }
+
+ public function testDoesNotMatchNull()
+ {
+ $this->assertMismatchDescription('was null', hasKeyValuePair(anything(), anything()), null);
+ }
+
+ public function testHasReadableDescription()
+ {
+ $this->assertDescription('array containing ["a" => <2>]', hasKeyValuePair(equalTo('a'), equalTo(2)));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayContainingTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayContainingTest.php
new file mode 100755
index 00000000..8d5bd810
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayContainingTest.php
@@ -0,0 +1,50 @@
+assertMatches(
+ hasItemInArray('a'),
+ array('a', 'b', 'c'),
+ "should matches array that contains 'a'"
+ );
+ }
+
+ public function testDoesNotMatchAnArrayThatDoesntContainAnElementMatchingTheGivenMatcher()
+ {
+ $this->assertDoesNotMatch(
+ hasItemInArray('a'),
+ array('b', 'c'),
+ "should not matches array that doesn't contain 'a'"
+ );
+ $this->assertDoesNotMatch(
+ hasItemInArray('a'),
+ array(),
+ 'should not match empty array'
+ );
+ }
+
+ public function testDoesNotMatchNull()
+ {
+ $this->assertDoesNotMatch(
+ hasItemInArray('a'),
+ null,
+ 'should not match null'
+ );
+ }
+
+ public function testHasAReadableDescription()
+ {
+ $this->assertDescription('an array containing "a"', hasItemInArray('a'));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayTest.php
new file mode 100755
index 00000000..e4db53e7
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayTest.php
@@ -0,0 +1,89 @@
+assertMatches(
+ anArray(array(equalTo('a'), equalTo('b'), equalTo('c'))),
+ array('a', 'b', 'c'),
+ 'should match array with matching elements'
+ );
+ }
+
+ public function testDoesNotMatchAnArrayWhenElementsDoNotMatch()
+ {
+ $this->assertDoesNotMatch(
+ anArray(array(equalTo('a'), equalTo('b'))),
+ array('b', 'c'),
+ 'should not match array with different elements'
+ );
+ }
+
+ public function testDoesNotMatchAnArrayOfDifferentSize()
+ {
+ $this->assertDoesNotMatch(
+ anArray(array(equalTo('a'), equalTo('b'))),
+ array('a', 'b', 'c'),
+ 'should not match larger array'
+ );
+ $this->assertDoesNotMatch(
+ anArray(array(equalTo('a'), equalTo('b'))),
+ array('a'),
+ 'should not match smaller array'
+ );
+ }
+
+ public function testDoesNotMatchNull()
+ {
+ $this->assertDoesNotMatch(
+ anArray(array(equalTo('a'))),
+ null,
+ 'should not match null'
+ );
+ }
+
+ public function testHasAReadableDescription()
+ {
+ $this->assertDescription(
+ '["a", "b"]',
+ anArray(array(equalTo('a'), equalTo('b')))
+ );
+ }
+
+ public function testHasAReadableMismatchDescriptionWhenKeysDontMatch()
+ {
+ $this->assertMismatchDescription(
+ 'array keys were [<1>, <2>]',
+ anArray(array(equalTo('a'), equalTo('b'))),
+ array(1 => 'a', 2 => 'b')
+ );
+ }
+
+ public function testSupportsMatchesAssociativeArrays()
+ {
+ $this->assertMatches(
+ anArray(array('x'=>equalTo('a'), 'y'=>equalTo('b'), 'z'=>equalTo('c'))),
+ array('x'=>'a', 'y'=>'b', 'z'=>'c'),
+ 'should match associative array with matching elements'
+ );
+ }
+
+ public function testDoesNotMatchAnAssociativeArrayWhenKeysDoNotMatch()
+ {
+ $this->assertDoesNotMatch(
+ anArray(array('x'=>equalTo('a'), 'y'=>equalTo('b'))),
+ array('x'=>'b', 'z'=>'c'),
+ 'should not match array with different keys'
+ );
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayWithSizeTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayWithSizeTest.php
new file mode 100755
index 00000000..8413c896
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Array/IsArrayWithSizeTest.php
@@ -0,0 +1,37 @@
+assertMatches(arrayWithSize(equalTo(3)), array(1, 2, 3), 'correct size');
+ $this->assertDoesNotMatch(arrayWithSize(equalTo(2)), array(1, 2, 3), 'incorrect size');
+ }
+
+ public function testProvidesConvenientShortcutForArrayWithSizeEqualTo()
+ {
+ $this->assertMatches(arrayWithSize(3), array(1, 2, 3), 'correct size');
+ $this->assertDoesNotMatch(arrayWithSize(2), array(1, 2, 3), 'incorrect size');
+ }
+
+ public function testEmptyArray()
+ {
+ $this->assertMatches(emptyArray(), array(), 'correct size');
+ $this->assertDoesNotMatch(emptyArray(), array(1), 'incorrect size');
+ }
+
+ public function testHasAReadableDescription()
+ {
+ $this->assertDescription('an array with size <3>', arrayWithSize(equalTo(3)));
+ $this->assertDescription('an empty array', emptyArray());
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/BaseMatcherTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/BaseMatcherTest.php
new file mode 100755
index 00000000..833e2c3e
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/BaseMatcherTest.php
@@ -0,0 +1,23 @@
+appendText('SOME DESCRIPTION');
+ }
+
+ public function testDescribesItselfWithToStringMethod()
+ {
+ $someMatcher = new \Hamcrest\SomeMatcher();
+ $this->assertEquals('SOME DESCRIPTION', (string) $someMatcher);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Collection/IsEmptyTraversableTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Collection/IsEmptyTraversableTest.php
new file mode 100755
index 00000000..2f15fb49
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Collection/IsEmptyTraversableTest.php
@@ -0,0 +1,77 @@
+assertMatches(
+ emptyTraversable(),
+ new \ArrayObject(array()),
+ 'an empty traversable'
+ );
+ }
+
+ public function testEmptyMatcherDoesNotMatchWhenNotEmpty()
+ {
+ $this->assertDoesNotMatch(
+ emptyTraversable(),
+ new \ArrayObject(array(1, 2, 3)),
+ 'a non-empty traversable'
+ );
+ }
+
+ public function testEmptyMatcherDoesNotMatchNull()
+ {
+ $this->assertDoesNotMatch(
+ emptyTraversable(),
+ null,
+ 'should not match null'
+ );
+ }
+
+ public function testEmptyMatcherHasAReadableDescription()
+ {
+ $this->assertDescription('an empty traversable', emptyTraversable());
+ }
+
+ public function testNonEmptyDoesNotMatchNull()
+ {
+ $this->assertDoesNotMatch(
+ nonEmptyTraversable(),
+ null,
+ 'should not match null'
+ );
+ }
+
+ public function testNonEmptyDoesNotMatchWhenEmpty()
+ {
+ $this->assertDoesNotMatch(
+ nonEmptyTraversable(),
+ new \ArrayObject(array()),
+ 'an empty traversable'
+ );
+ }
+
+ public function testNonEmptyMatchesWhenNotEmpty()
+ {
+ $this->assertMatches(
+ nonEmptyTraversable(),
+ new \ArrayObject(array(1, 2, 3)),
+ 'a non-empty traversable'
+ );
+ }
+
+ public function testNonEmptyNonEmptyMatcherHasAReadableDescription()
+ {
+ $this->assertDescription('a non-empty traversable', nonEmptyTraversable());
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Collection/IsTraversableWithSizeTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Collection/IsTraversableWithSizeTest.php
new file mode 100755
index 00000000..c1c67a7a
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Collection/IsTraversableWithSizeTest.php
@@ -0,0 +1,57 @@
+assertMatches(
+ traversableWithSize(equalTo(3)),
+ new \ArrayObject(array(1, 2, 3)),
+ 'correct size'
+ );
+ }
+
+ public function testDoesNotMatchWhenSizeIsIncorrect()
+ {
+ $this->assertDoesNotMatch(
+ traversableWithSize(equalTo(2)),
+ new \ArrayObject(array(1, 2, 3)),
+ 'incorrect size'
+ );
+ }
+
+ public function testDoesNotMatchNull()
+ {
+ $this->assertDoesNotMatch(
+ traversableWithSize(3),
+ null,
+ 'should not match null'
+ );
+ }
+
+ public function testProvidesConvenientShortcutForTraversableWithSizeEqualTo()
+ {
+ $this->assertMatches(
+ traversableWithSize(3),
+ new \ArrayObject(array(1, 2, 3)),
+ 'correct size'
+ );
+ }
+
+ public function testHasAReadableDescription()
+ {
+ $this->assertDescription(
+ 'a traversable with size <3>',
+ traversableWithSize(equalTo(3))
+ );
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/AllOfTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/AllOfTest.php
new file mode 100755
index 00000000..86b8c277
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/AllOfTest.php
@@ -0,0 +1,56 @@
+assertDescription(
+ '("good" and "bad" and "ugly")',
+ allOf('good', 'bad', 'ugly')
+ );
+ }
+
+ public function testMismatchDescriptionDescribesFirstFailingMatch()
+ {
+ $this->assertMismatchDescription(
+ '"good" was "bad"',
+ allOf('bad', 'good'),
+ 'bad'
+ );
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/AnyOfTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/AnyOfTest.php
new file mode 100755
index 00000000..3d62b935
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/AnyOfTest.php
@@ -0,0 +1,79 @@
+assertDescription(
+ '("good" or "bad" or "ugly")',
+ anyOf('good', 'bad', 'ugly')
+ );
+ }
+
+ public function testNoneOfEvaluatesToTheLogicalDisjunctionOfTwoOtherMatchers()
+ {
+ assertThat('good', not(noneOf('bad', 'good')));
+ assertThat('good', not(noneOf('good', 'good')));
+ assertThat('good', not(noneOf('good', 'bad')));
+
+ assertThat('good', noneOf('bad', startsWith('b')));
+ }
+
+ public function testNoneOfEvaluatesToTheLogicalDisjunctionOfManyOtherMatchers()
+ {
+ assertThat('good', not(noneOf('bad', 'good', 'bad', 'bad', 'bad')));
+ assertThat('good', noneOf('bad', 'bad', 'bad', 'bad', 'bad'));
+ }
+
+ public function testNoneOfSupportsMixedTypes()
+ {
+ $combined = noneOf(
+ equalTo(new \Hamcrest\Core\SampleBaseClass('good')),
+ equalTo(new \Hamcrest\Core\SampleBaseClass('ugly')),
+ equalTo(new \Hamcrest\Core\SampleSubClass('good'))
+ );
+
+ assertThat(new \Hamcrest\Core\SampleSubClass('bad'), $combined);
+ }
+
+ public function testNoneOfHasAReadableDescription()
+ {
+ $this->assertDescription(
+ 'not ("good" or "bad" or "ugly")',
+ noneOf('good', 'bad', 'ugly')
+ );
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/CombinableMatcherTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/CombinableMatcherTest.php
new file mode 100755
index 00000000..463c7543
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/CombinableMatcherTest.php
@@ -0,0 +1,59 @@
+_either_3_or_4 = \Hamcrest\Core\CombinableMatcher::either(equalTo(3))->orElse(equalTo(4));
+ $this->_not_3_and_not_4 = \Hamcrest\Core\CombinableMatcher::both(not(equalTo(3)))->andAlso(not(equalTo(4)));
+ }
+
+ protected function createMatcher()
+ {
+ return \Hamcrest\Core\CombinableMatcher::either(equalTo('irrelevant'))->orElse(equalTo('ignored'));
+ }
+
+ public function testBothAcceptsAndRejects()
+ {
+ assertThat(2, $this->_not_3_and_not_4);
+ assertThat(3, not($this->_not_3_and_not_4));
+ }
+
+ public function testAcceptsAndRejectsThreeAnds()
+ {
+ $tripleAnd = $this->_not_3_and_not_4->andAlso(equalTo(2));
+ assertThat(2, $tripleAnd);
+ assertThat(3, not($tripleAnd));
+ }
+
+ public function testBothDescribesItself()
+ {
+ $this->assertEquals('(not <3> and not <4>)', (string) $this->_not_3_and_not_4);
+ $this->assertMismatchDescription('was <3>', $this->_not_3_and_not_4, 3);
+ }
+
+ public function testEitherAcceptsAndRejects()
+ {
+ assertThat(3, $this->_either_3_or_4);
+ assertThat(6, not($this->_either_3_or_4));
+ }
+
+ public function testAcceptsAndRejectsThreeOrs()
+ {
+ $orTriple = $this->_either_3_or_4->orElse(greaterThan(10));
+
+ assertThat(11, $orTriple);
+ assertThat(9, not($orTriple));
+ }
+
+ public function testEitherDescribesItself()
+ {
+ $this->assertEquals('(<3> or <4>)', (string) $this->_either_3_or_4);
+ $this->assertMismatchDescription('was <6>', $this->_either_3_or_4, 6);
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/DescribedAsTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/DescribedAsTest.php
new file mode 100755
index 00000000..673ab41e
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/DescribedAsTest.php
@@ -0,0 +1,36 @@
+assertDescription('m1 description', $m1);
+ $this->assertDescription('m2 description', $m2);
+ }
+
+ public function testAppendsValuesToDescription()
+ {
+ $m = describedAs('value 1 = %0, value 2 = %1', anything(), 33, 97);
+
+ $this->assertDescription('value 1 = <33>, value 2 = <97>', $m);
+ }
+
+ public function testDelegatesMatchingToAnotherMatcher()
+ {
+ $m1 = describedAs('irrelevant', anything());
+ $m2 = describedAs('irrelevant', not(anything()));
+
+ $this->assertTrue($m1->matches(new \stdClass()));
+ $this->assertFalse($m2->matches('hi'));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/EveryTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/EveryTest.php
new file mode 100755
index 00000000..5eb153c5
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/EveryTest.php
@@ -0,0 +1,30 @@
+assertEquals('every item is a string containing "a"', (string) $each);
+
+ $this->assertMismatchDescription('an item was "BbB"', $each, array('BbB'));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/HasToStringTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/HasToStringTest.php
new file mode 100755
index 00000000..e2e136dc
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/HasToStringTest.php
@@ -0,0 +1,108 @@
+assertMatches(
+ hasToString(equalTo('php')),
+ new \Hamcrest\Core\PhpForm(),
+ 'correct __toString'
+ );
+ $this->assertMatches(
+ hasToString(equalTo('java')),
+ new \Hamcrest\Core\JavaForm(),
+ 'correct toString'
+ );
+ }
+
+ public function testPicksJavaOverPhpToString()
+ {
+ $this->assertMatches(
+ hasToString(equalTo('java')),
+ new \Hamcrest\Core\BothForms(),
+ 'correct toString'
+ );
+ }
+
+ public function testDoesNotMatchWhenToStringDoesNotMatch()
+ {
+ $this->assertDoesNotMatch(
+ hasToString(equalTo('mismatch')),
+ new \Hamcrest\Core\PhpForm(),
+ 'incorrect __toString'
+ );
+ $this->assertDoesNotMatch(
+ hasToString(equalTo('mismatch')),
+ new \Hamcrest\Core\JavaForm(),
+ 'incorrect toString'
+ );
+ $this->assertDoesNotMatch(
+ hasToString(equalTo('mismatch')),
+ new \Hamcrest\Core\BothForms(),
+ 'incorrect __toString'
+ );
+ }
+
+ public function testDoesNotMatchNull()
+ {
+ $this->assertDoesNotMatch(
+ hasToString(equalTo('a')),
+ null,
+ 'should not match null'
+ );
+ }
+
+ public function testProvidesConvenientShortcutForTraversableWithSizeEqualTo()
+ {
+ $this->assertMatches(
+ hasToString(equalTo('php')),
+ new \Hamcrest\Core\PhpForm(),
+ 'correct __toString'
+ );
+ }
+
+ public function testHasAReadableDescription()
+ {
+ $this->assertDescription(
+ 'an object with toString() "php"',
+ hasToString(equalTo('php'))
+ );
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/IsAnythingTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/IsAnythingTest.php
new file mode 100755
index 00000000..f68032e5
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/IsAnythingTest.php
@@ -0,0 +1,29 @@
+assertDescription('ANYTHING', anything());
+ }
+
+ public function testCanOverrideDescription()
+ {
+ $description = 'description';
+ $this->assertDescription($description, anything($description));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/IsCollectionContainingTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/IsCollectionContainingTest.php
new file mode 100755
index 00000000..a3929b54
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/IsCollectionContainingTest.php
@@ -0,0 +1,91 @@
+assertMatches(
+ $itemMatcher,
+ array('a', 'b', 'c'),
+ "should match list that contains 'a'"
+ );
+ }
+
+ public function testDoesNotMatchCollectionThatDoesntContainAnElementMatchingTheGivenMatcher()
+ {
+ $matcher1 = hasItem(equalTo('a'));
+ $this->assertDoesNotMatch(
+ $matcher1,
+ array('b', 'c'),
+ "should not match list that doesn't contain 'a'"
+ );
+
+ $matcher2 = hasItem(equalTo('a'));
+ $this->assertDoesNotMatch(
+ $matcher2,
+ array(),
+ 'should not match the empty list'
+ );
+ }
+
+ public function testDoesNotMatchNull()
+ {
+ $this->assertDoesNotMatch(
+ hasItem(equalTo('a')),
+ null,
+ 'should not match null'
+ );
+ }
+
+ public function testHasAReadableDescription()
+ {
+ $this->assertDescription('a collection containing "a"', hasItem(equalTo('a')));
+ }
+
+ public function testMatchesAllItemsInCollection()
+ {
+ $matcher1 = hasItems(equalTo('a'), equalTo('b'), equalTo('c'));
+ $this->assertMatches(
+ $matcher1,
+ array('a', 'b', 'c'),
+ 'should match list containing all items'
+ );
+
+ $matcher2 = hasItems('a', 'b', 'c');
+ $this->assertMatches(
+ $matcher2,
+ array('a', 'b', 'c'),
+ 'should match list containing all items (without matchers)'
+ );
+
+ $matcher3 = hasItems(equalTo('a'), equalTo('b'), equalTo('c'));
+ $this->assertMatches(
+ $matcher3,
+ array('c', 'b', 'a'),
+ 'should match list containing all items in any order'
+ );
+
+ $matcher4 = hasItems(equalTo('a'), equalTo('b'), equalTo('c'));
+ $this->assertMatches(
+ $matcher4,
+ array('e', 'c', 'b', 'a', 'd'),
+ 'should match list containing all items plus others'
+ );
+
+ $matcher5 = hasItems(equalTo('a'), equalTo('b'), equalTo('c'));
+ $this->assertDoesNotMatch(
+ $matcher5,
+ array('e', 'c', 'b', 'd'), // 'a' missing
+ 'should not match list unless it contains all items'
+ );
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/IsEqualTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/IsEqualTest.php
new file mode 100755
index 00000000..73e3ff07
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/IsEqualTest.php
@@ -0,0 +1,102 @@
+_arg = $arg;
+ }
+
+ public function __toString()
+ {
+ return $this->_arg;
+ }
+}
+
+class IsEqualTest extends \Hamcrest\AbstractMatcherTest
+{
+
+ protected function createMatcher()
+ {
+ return \Hamcrest\Core\IsEqual::equalTo('irrelevant');
+ }
+
+ public function testComparesObjectsUsingEqualityOperator()
+ {
+ assertThat("hi", equalTo("hi"));
+ assertThat("bye", not(equalTo("hi")));
+
+ assertThat(1, equalTo(1));
+ assertThat(1, not(equalTo(2)));
+
+ assertThat("2", equalTo(2));
+ }
+
+ public function testCanCompareNullValues()
+ {
+ assertThat(null, equalTo(null));
+
+ assertThat(null, not(equalTo('hi')));
+ assertThat('hi', not(equalTo(null)));
+ }
+
+ public function testComparesTheElementsOfAnArray()
+ {
+ $s1 = array('a', 'b');
+ $s2 = array('a', 'b');
+ $s3 = array('c', 'd');
+ $s4 = array('a', 'b', 'c', 'd');
+
+ assertThat($s1, equalTo($s1));
+ assertThat($s2, equalTo($s1));
+ assertThat($s3, not(equalTo($s1)));
+ assertThat($s4, not(equalTo($s1)));
+ }
+
+ public function testComparesTheElementsOfAnArrayOfPrimitiveTypes()
+ {
+ $i1 = array(1, 2);
+ $i2 = array(1, 2);
+ $i3 = array(3, 4);
+ $i4 = array(1, 2, 3, 4);
+
+ assertThat($i1, equalTo($i1));
+ assertThat($i2, equalTo($i1));
+ assertThat($i3, not(equalTo($i1)));
+ assertThat($i4, not(equalTo($i1)));
+ }
+
+ public function testRecursivelyTestsElementsOfArrays()
+ {
+ $i1 = array(array(1, 2), array(3, 4));
+ $i2 = array(array(1, 2), array(3, 4));
+ $i3 = array(array(5, 6), array(7, 8));
+ $i4 = array(array(1, 2, 3, 4), array(3, 4));
+
+ assertThat($i1, equalTo($i1));
+ assertThat($i2, equalTo($i1));
+ assertThat($i3, not(equalTo($i1)));
+ assertThat($i4, not(equalTo($i1)));
+ }
+
+ public function testIncludesTheResultOfCallingToStringOnItsArgumentInTheDescription()
+ {
+ $argumentDescription = 'ARGUMENT DESCRIPTION';
+ $argument = new \Hamcrest\Core\DummyToStringClass($argumentDescription);
+ $this->assertDescription('<' . $argumentDescription . '>', equalTo($argument));
+ }
+
+ public function testReturnsAnObviousDescriptionIfCreatedWithANestedMatcherByMistake()
+ {
+ $innerMatcher = equalTo('NestedMatcher');
+ $this->assertDescription('<' . (string) $innerMatcher . '>', equalTo($innerMatcher));
+ }
+
+ public function testReturnsGoodDescriptionIfCreatedWithNullReference()
+ {
+ $this->assertDescription('null', equalTo(null));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/IsIdenticalTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/IsIdenticalTest.php
new file mode 100755
index 00000000..9cc27946
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/IsIdenticalTest.php
@@ -0,0 +1,30 @@
+assertDescription('"ARG"', identicalTo('ARG'));
+ }
+
+ public function testReturnsReadableDescriptionFromToStringWhenInitialisedWithNull()
+ {
+ $this->assertDescription('null', identicalTo(null));
+ }
+}
diff --git a/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/IsInstanceOfTest.php b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/IsInstanceOfTest.php
new file mode 100755
index 00000000..f74cfdb5
--- /dev/null
+++ b/vendor/hamcrest/hamcrest-php/tests/Hamcrest/Core/IsInstanceOfTest.php
@@ -0,0 +1,51 @@
+_baseClassInstance = new \Hamcrest\Core\SampleBaseClass('good');
+ $this->_subClassInstance = new \Hamcrest\Core\SampleSubClass('good');
+ }
+
+ protected function createMatcher()
+ {
+ return \Hamcrest\Core\IsInstanceOf::anInstanceOf('stdClass');
+ }
+
+ public function testEvaluatesToTrueIfArgumentIsInstanceOfASpecificClass()
+ {
+ assertThat($this->_baseClassInstance, anInstanceOf('Hamcrest\Core\SampleBaseClass'));
+ assertThat($this->_subClassInstance, anInstanceOf('Hamcrest\Core\SampleSubClass'));
+ assertThat(null, not(anInstanceOf('Hamcrest\Core\SampleBaseClass')));
+ assertThat(new \stdClass(), not(anInstanceOf('Hamcrest\Core\SampleBaseClass')));
+ }
+
+ public function testEvaluatesToFalseIfArgumentIsNotAnObject()
+ {
+ assertThat(null, not(anInstanceOf('Hamcrest\Core\SampleBaseClass')));
+ assertThat(false, not(anInstanceOf('Hamcrest\Core\SampleBaseClass')));
+ assertThat(5, not(anInstanceOf('Hamcrest\Core\SampleBaseClass')));
+ assertThat('foo', not(anInstanceOf('Hamcrest\Core\SampleBaseClass')));
+ assertThat(array(1, 2, 3), not(anInstanceOf('Hamcrest\Core\SampleBaseClass')));
+ }
+
+ public function testHasAReadableDescription()
+ {
+ $this->assertDescription('an instance of stdClass', anInstanceOf('stdClass'));
+ }
+
+ public function testDecribesActualClassInMismatchMessage()
+ {
+ $this->assertMismatchDescription(
+ '[Hamcrest\Core\SampleBaseClass] Some text
+ + +HTML; + } + + protected function createMatcher() + { + return \Hamcrest\Xml\HasXPath::hasXPath('/users/user'); + } + + public function testMatchesWhenXPathIsFound() + { + assertThat('one match', self::$doc, hasXPath('user[id = "bob"]')); + assertThat('two matches', self::$doc, hasXPath('user[role = "user"]')); + } + + public function testDoesNotMatchWhenXPathIsNotFound() + { + assertThat( + 'no match', + self::$doc, + not(hasXPath('user[contains(id, "frank")]')) + ); + } + + public function testMatchesWhenExpressionWithoutMatcherEvaluatesToTrue() + { + assertThat( + 'one match', + self::$doc, + hasXPath('count(user[id = "bob"])') + ); + } + + public function testDoesNotMatchWhenExpressionWithoutMatcherEvaluatesToFalse() + { + assertThat( + 'no matches', + self::$doc, + not(hasXPath('count(user[id = "frank"])')) + ); + } + + public function testMatchesWhenExpressionIsEqual() + { + assertThat( + 'one match', + self::$doc, + hasXPath('count(user[id = "bob"])', 1) + ); + assertThat( + 'two matches', + self::$doc, + hasXPath('count(user[role = "user"])', 2) + ); + } + + public function testDoesNotMatchWhenExpressionIsNotEqual() + { + assertThat( + 'no match', + self::$doc, + not(hasXPath('count(user[id = "frank"])', 2)) + ); + assertThat( + 'one match', + self::$doc, + not(hasXPath('count(user[role = "admin"])', 2)) + ); + } + + public function testMatchesWhenContentMatches() + { + assertThat( + 'one match', + self::$doc, + hasXPath('user/name', containsString('ice')) + ); + assertThat( + 'two matches', + self::$doc, + hasXPath('user/role', equalTo('user')) + ); + } + + public function testDoesNotMatchWhenContentDoesNotMatch() + { + assertThat( + 'no match', + self::$doc, + not(hasXPath('user/name', containsString('Bobby'))) + ); + assertThat( + 'no matches', + self::$doc, + not(hasXPath('user/role', equalTo('owner'))) + ); + } + + public function testProvidesConvenientShortcutForHasXPathEqualTo() + { + assertThat('matches', self::$doc, hasXPath('count(user)', 3)); + assertThat('matches', self::$doc, hasXPath('user[2]/id', 'bob')); + } + + public function testProvidesConvenientShortcutForHasXPathCountEqualTo() + { + assertThat('matches', self::$doc, hasXPath('user[id = "charlie"]', 1)); + } + + public function testMatchesAcceptsXmlString() + { + assertThat('accepts XML string', self::$xml, hasXPath('user')); + } + + public function testMatchesAcceptsHtmlString() + { + assertThat('accepts HTML string', self::$html, hasXPath('body/h1', 'Heading')); + } + + public function testHasAReadableDescription() + { + $this->assertDescription( + 'XML or HTML document with XPath "/users/user"', + hasXPath('/users/user') + ); + $this->assertDescription( + 'XML or HTML document with XPath "count(/users/user)" <2>', + hasXPath('/users/user', 2) + ); + $this->assertDescription( + 'XML or HTML document with XPath "/users/user/name"' + . ' a string starting with "Alice"', + hasXPath('/users/user/name', startsWith('Alice')) + ); + } + + public function testHasAReadableMismatchDescription() + { + $this->assertMismatchDescription( + 'XPath returned no results', + hasXPath('/users/name'), + self::$doc + ); + $this->assertMismatchDescription( + 'XPath expression result was <3F>', + hasXPath('/users/user', 2), + self::$doc + ); + $this->assertMismatchDescription( + 'XPath returned ["alice", "bob", "charlie"]', + hasXPath('/users/user/id', 'Frank'), + self::$doc + ); + } +} diff --git a/vendor/hamcrest/hamcrest-php/tests/bootstrap.php b/vendor/hamcrest/hamcrest-php/tests/bootstrap.php new file mode 100755 index 00000000..bc4958d1 --- /dev/null +++ b/vendor/hamcrest/hamcrest-php/tests/bootstrap.php @@ -0,0 +1,11 @@ + +