+
+{% endblock %}
\ No newline at end of file
diff --git a/web/system/vendor/Cron/AbstractField.php b/web/system/vendor/Cron/AbstractField.php
new file mode 100644
index 0000000..c0616a2
--- /dev/null
+++ b/web/system/vendor/Cron/AbstractField.php
@@ -0,0 +1,104 @@
+isIncrementsOfRanges($value)) {
+ return $this->isInIncrementsOfRanges($dateValue, $value);
+ } elseif ($this->isRange($value)) {
+ return $this->isInRange($dateValue, $value);
+ }
+
+ return $value == '*' || $dateValue == $value;
+ }
+
+ /**
+ * Check if a value is a range
+ *
+ * @param string $value Value to test
+ *
+ * @return bool
+ */
+ public function isRange($value)
+ {
+ return strpos($value, '-') !== false;
+ }
+
+ /**
+ * Check if a value is an increments of ranges
+ *
+ * @param string $value Value to test
+ *
+ * @return bool
+ */
+ public function isIncrementsOfRanges($value)
+ {
+ return strpos($value, '/') !== false;
+ }
+
+ /**
+ * Test if a value is within a range
+ *
+ * @param string $dateValue Set date value
+ * @param string $value Value to test
+ *
+ * @return bool
+ */
+ public function isInRange($dateValue, $value)
+ {
+ $parts = array_map('trim', explode('-', $value, 2));
+
+ return $dateValue >= $parts[0] && $dateValue <= $parts[1];
+ }
+
+ /**
+ * Test if a value is within an increments of ranges (offset[-to]/step size)
+ *
+ * @param string $dateValue Set date value
+ * @param string $value Value to test
+ *
+ * @return bool
+ */
+ public function isInIncrementsOfRanges($dateValue, $value)
+ {
+ $parts = array_map('trim', explode('/', $value, 2));
+ $stepSize = isset($parts[1]) ? $parts[1] : 0;
+ if (($parts[0] == '*' || $parts[0] === '0') && 0 !== $stepSize) {
+ return (int) $dateValue % $stepSize == 0;
+ }
+
+ $range = explode('-', $parts[0], 2);
+ $offset = $range[0];
+ $to = isset($range[1]) ? $range[1] : $dateValue;
+ // Ensure that the date value is within the range
+ if ($dateValue < $offset || $dateValue > $to) {
+ return false;
+ }
+
+ if ($dateValue > $offset && 0 === $stepSize) {
+ return false;
+ }
+
+ for ($i = $offset; $i <= $to; $i+= $stepSize) {
+ if ($i == $dateValue) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/web/system/vendor/Cron/CronExpression.php b/web/system/vendor/Cron/CronExpression.php
new file mode 100644
index 0000000..b59662a
--- /dev/null
+++ b/web/system/vendor/Cron/CronExpression.php
@@ -0,0 +1,355 @@
+ '0 0 1 1 *',
+ '@annually' => '0 0 1 1 *',
+ '@monthly' => '0 0 1 * *',
+ '@weekly' => '0 0 * * 0',
+ '@daily' => '0 0 * * *',
+ '@hourly' => '0 * * * *'
+ );
+
+ if (isset($mappings[$expression])) {
+ $expression = $mappings[$expression];
+ }
+
+ return new static($expression, $fieldFactory ?: new FieldFactory());
+ }
+
+ /**
+ * Validate a CronExpression.
+ *
+ * @param string $expression The CRON expression to validate.
+ *
+ * @return bool True if a valid CRON expression was passed. False if not.
+ * @see Cron\CronExpression::factory
+ */
+ public static function isValidExpression($expression)
+ {
+ try {
+ self::factory($expression);
+ } catch (\InvalidArgumentException $e) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Parse a CRON expression
+ *
+ * @param string $expression CRON expression (e.g. '8 * * * *')
+ * @param FieldFactory $fieldFactory Factory to create cron fields
+ */
+ public function __construct($expression, FieldFactory $fieldFactory)
+ {
+ $this->fieldFactory = $fieldFactory;
+ $this->setExpression($expression);
+ }
+
+ /**
+ * Set or change the CRON expression
+ *
+ * @param string $value CRON expression (e.g. 8 * * * *)
+ *
+ * @return CronExpression
+ * @throws \InvalidArgumentException if not a valid CRON expression
+ */
+ public function setExpression($value)
+ {
+ $this->cronParts = preg_split('/\s/', $value, -1, PREG_SPLIT_NO_EMPTY);
+ if (count($this->cronParts) < 5) {
+ throw new \InvalidArgumentException(
+ $value . ' is not a valid CRON expression'
+ );
+ }
+
+ foreach ($this->cronParts as $position => $part) {
+ $this->setPart($position, $part);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set part of the CRON expression
+ *
+ * @param int $position The position of the CRON expression to set
+ * @param string $value The value to set
+ *
+ * @return CronExpression
+ * @throws \InvalidArgumentException if the value is not valid for the part
+ */
+ public function setPart($position, $value)
+ {
+ if (!$this->fieldFactory->getField($position)->validate($value)) {
+ throw new \InvalidArgumentException(
+ 'Invalid CRON field value ' . $value . ' at position ' . $position
+ );
+ }
+
+ $this->cronParts[$position] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get a next run date relative to the current date or a specific date
+ *
+ * @param string|\DateTime $currentTime Relative calculation date
+ * @param int $nth Number of matches to skip before returning a
+ * matching next run date. 0, the default, will return the current
+ * date and time if the next run date falls on the current date and
+ * time. Setting this value to 1 will skip the first match and go to
+ * the second match. Setting this value to 2 will skip the first 2
+ * matches and so on.
+ * @param bool $allowCurrentDate Set to TRUE to return the current date if
+ * it matches the cron expression.
+ *
+ * @return \DateTime
+ * @throws \RuntimeException on too many iterations
+ */
+ public function getNextRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false)
+ {
+ return $this->getRunDate($currentTime, $nth, false, $allowCurrentDate);
+ }
+
+ /**
+ * Get a previous run date relative to the current date or a specific date
+ *
+ * @param string|\DateTime $currentTime Relative calculation date
+ * @param int $nth Number of matches to skip before returning
+ * @param bool $allowCurrentDate Set to TRUE to return the
+ * current date if it matches the cron expression
+ *
+ * @return \DateTime
+ * @throws \RuntimeException on too many iterations
+ * @see Cron\CronExpression::getNextRunDate
+ */
+ public function getPreviousRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false)
+ {
+ return $this->getRunDate($currentTime, $nth, true, $allowCurrentDate);
+ }
+
+ /**
+ * Get multiple run dates starting at the current date or a specific date
+ *
+ * @param int $total Set the total number of dates to calculate
+ * @param string|\DateTime $currentTime Relative calculation date
+ * @param bool $invert Set to TRUE to retrieve previous dates
+ * @param bool $allowCurrentDate Set to TRUE to return the
+ * current date if it matches the cron expression
+ *
+ * @return array Returns an array of run dates
+ */
+ public function getMultipleRunDates($total, $currentTime = 'now', $invert = false, $allowCurrentDate = false)
+ {
+ $matches = array();
+ for ($i = 0; $i < max(0, $total); $i++) {
+ try {
+ $matches[] = $this->getRunDate($currentTime, $i, $invert, $allowCurrentDate);
+ } catch (\RuntimeException $e) {
+ break;
+ }
+ }
+
+ return $matches;
+ }
+
+ /**
+ * Get all or part of the CRON expression
+ *
+ * @param string $part Specify the part to retrieve or NULL to get the full
+ * cron schedule string.
+ *
+ * @return string|null Returns the CRON expression, a part of the
+ * CRON expression, or NULL if the part was specified but not found
+ */
+ public function getExpression($part = null)
+ {
+ if (null === $part) {
+ return implode(' ', $this->cronParts);
+ } elseif (array_key_exists($part, $this->cronParts)) {
+ return $this->cronParts[$part];
+ }
+
+ return null;
+ }
+
+ /**
+ * Helper method to output the full expression.
+ *
+ * @return string Full CRON expression
+ */
+ public function __toString()
+ {
+ return $this->getExpression();
+ }
+
+ /**
+ * Determine if the cron is due to run based on the current date or a
+ * specific date. This method assumes that the current number of
+ * seconds are irrelevant, and should be called once per minute.
+ *
+ * @param string|\DateTime $currentTime Relative calculation date
+ *
+ * @return bool Returns TRUE if the cron is due to run or FALSE if not
+ */
+ public function isDue($currentTime = 'now')
+ {
+ if ('now' === $currentTime) {
+ $currentDate = date('Y-m-d H:i');
+ $currentTime = strtotime($currentDate);
+ } elseif ($currentTime instanceof \DateTime) {
+ $currentDate = clone $currentTime;
+ // Ensure time in 'current' timezone is used
+ $currentDate->setTimezone(new \DateTimeZone(date_default_timezone_get()));
+ $currentDate = $currentDate->format('Y-m-d H:i');
+ $currentTime = strtotime($currentDate);
+ } else {
+ $currentTime = new \DateTime($currentTime);
+ $currentTime->setTime($currentTime->format('H'), $currentTime->format('i'), 0);
+ $currentDate = $currentTime->format('Y-m-d H:i');
+ $currentTime = $currentTime->getTimeStamp();
+ }
+
+ try {
+ return $this->getNextRunDate($currentDate, 0, true)->getTimestamp() == $currentTime;
+ } catch (\Exception $e) {
+ return false;
+ }
+ }
+
+ /**
+ * Get the next or previous run date of the expression relative to a date
+ *
+ * @param string|\DateTime $currentTime Relative calculation date
+ * @param int $nth Number of matches to skip before returning
+ * @param bool $invert Set to TRUE to go backwards in time
+ * @param bool $allowCurrentDate Set to TRUE to return the
+ * current date if it matches the cron expression
+ *
+ * @return \DateTime
+ * @throws \RuntimeException on too many iterations
+ */
+ protected function getRunDate($currentTime = null, $nth = 0, $invert = false, $allowCurrentDate = false)
+ {
+ if ($currentTime instanceof \DateTime) {
+ $currentDate = clone $currentTime;
+ } else {
+ $currentDate = new \DateTime($currentTime ?: 'now');
+ $currentDate->setTimezone(new \DateTimeZone(date_default_timezone_get()));
+ }
+
+ $currentDate->setTime($currentDate->format('H'), $currentDate->format('i'), 0);
+ $nextRun = clone $currentDate;
+ $nth = (int) $nth;
+
+ // We don't have to satisfy * or null fields
+ $parts = array();
+ $fields = array();
+ foreach (self::$order as $position) {
+ $part = $this->getExpression($position);
+ if (null === $part || '*' === $part) {
+ continue;
+ }
+ $parts[$position] = $part;
+ $fields[$position] = $this->fieldFactory->getField($position);
+ }
+
+ // Set a hard limit to bail on an impossible date
+ for ($i = 0; $i < 1000; $i++) {
+
+ foreach ($parts as $position => $part) {
+ $satisfied = false;
+ // Get the field object used to validate this part
+ $field = $fields[$position];
+ // Check if this is singular or a list
+ if (strpos($part, ',') === false) {
+ $satisfied = $field->isSatisfiedBy($nextRun, $part);
+ } else {
+ foreach (array_map('trim', explode(',', $part)) as $listPart) {
+ if ($field->isSatisfiedBy($nextRun, $listPart)) {
+ $satisfied = true;
+ break;
+ }
+ }
+ }
+
+ // If the field is not satisfied, then start over
+ if (!$satisfied) {
+ $field->increment($nextRun, $invert);
+ continue 2;
+ }
+ }
+
+ // Skip this match if needed
+ if ((!$allowCurrentDate && $nextRun == $currentDate) || --$nth > -1) {
+ $this->fieldFactory->getField(0)->increment($nextRun, $invert);
+ continue;
+ }
+
+ return $nextRun;
+ }
+
+ // @codeCoverageIgnoreStart
+ throw new \RuntimeException('Impossible CRON expression');
+ // @codeCoverageIgnoreEnd
+ }
+}
diff --git a/web/system/vendor/Cron/DayOfMonthField.php b/web/system/vendor/Cron/DayOfMonthField.php
new file mode 100644
index 0000000..86129c9
--- /dev/null
+++ b/web/system/vendor/Cron/DayOfMonthField.php
@@ -0,0 +1,103 @@
+
+ */
+class DayOfMonthField extends AbstractField
+{
+ /**
+ * Get the nearest day of the week for a given day in a month
+ *
+ * @param int $currentYear Current year
+ * @param int $currentMonth Current month
+ * @param int $targetDay Target day of the month
+ *
+ * @return \DateTime Returns the nearest date
+ */
+ private static function getNearestWeekday($currentYear, $currentMonth, $targetDay)
+ {
+ $tday = str_pad($targetDay, 2, '0', STR_PAD_LEFT);
+ $target = \DateTime::createFromFormat('Y-m-d', "$currentYear-$currentMonth-$tday");
+ $currentWeekday = (int) $target->format('N');
+
+ if ($currentWeekday < 6) {
+ return $target;
+ }
+
+ $lastDayOfMonth = $target->format('t');
+
+ foreach (array(-1, 1, -2, 2) as $i) {
+ $adjusted = $targetDay + $i;
+ if ($adjusted > 0 && $adjusted <= $lastDayOfMonth) {
+ $target->setDate($currentYear, $currentMonth, $adjusted);
+ if ($target->format('N') < 6 && $target->format('m') == $currentMonth) {
+ return $target;
+ }
+ }
+ }
+ }
+
+ public function isSatisfiedBy(\DateTime $date, $value)
+ {
+ // ? states that the field value is to be skipped
+ if ($value == '?') {
+ return true;
+ }
+
+ $fieldValue = $date->format('d');
+
+ // Check to see if this is the last day of the month
+ if ($value == 'L') {
+ return $fieldValue == $date->format('t');
+ }
+
+ // Check to see if this is the nearest weekday to a particular value
+ if (strpos($value, 'W')) {
+ // Parse the target day
+ $targetDay = substr($value, 0, strpos($value, 'W'));
+ // Find out if the current day is the nearest day of the week
+ return $date->format('j') == self::getNearestWeekday(
+ $date->format('Y'),
+ $date->format('m'),
+ $targetDay
+ )->format('j');
+ }
+
+ return $this->isSatisfied($date->format('d'), $value);
+ }
+
+ public function increment(\DateTime $date, $invert = false)
+ {
+ if ($invert) {
+ $date->modify('previous day');
+ $date->setTime(23, 59);
+ } else {
+ $date->modify('next day');
+ $date->setTime(0, 0);
+ }
+
+ return $this;
+ }
+
+ public function validate($value)
+ {
+ return (bool) preg_match('/^[\*,\/\-\?LW0-9A-Za-z]+$/', $value);
+ }
+}
diff --git a/web/system/vendor/Cron/DayOfWeekField.php b/web/system/vendor/Cron/DayOfWeekField.php
new file mode 100644
index 0000000..8e33b19
--- /dev/null
+++ b/web/system/vendor/Cron/DayOfWeekField.php
@@ -0,0 +1,134 @@
+convertLiterals($value);
+
+ $currentYear = $date->format('Y');
+ $currentMonth = $date->format('m');
+ $lastDayOfMonth = $date->format('t');
+
+ // Find out if this is the last specific weekday of the month
+ if (strpos($value, 'L')) {
+ $weekday = str_replace('7', '0', substr($value, 0, strpos($value, 'L')));
+ $tdate = clone $date;
+ $tdate->setDate($currentYear, $currentMonth, $lastDayOfMonth);
+ while ($tdate->format('w') != $weekday) {
+ $tdate->setDate($currentYear, $currentMonth, --$lastDayOfMonth);
+ }
+
+ return $date->format('j') == $lastDayOfMonth;
+ }
+
+ // Handle # hash tokens
+ if (strpos($value, '#')) {
+ list($weekday, $nth) = explode('#', $value);
+
+ // 0 and 7 are both Sunday, however 7 matches date('N') format ISO-8601
+ if ($weekday === '0') {
+ $weekday = 7;
+ }
+
+ // Validate the hash fields
+ if ($weekday < 0 || $weekday > 7) {
+ throw new \InvalidArgumentException("Weekday must be a value between 0 and 7. {$weekday} given");
+ }
+ if ($nth > 5) {
+ throw new \InvalidArgumentException('There are never more than 5 of a given weekday in a month');
+ }
+ // The current weekday must match the targeted weekday to proceed
+ if ($date->format('N') != $weekday) {
+ return false;
+ }
+
+ $tdate = clone $date;
+ $tdate->setDate($currentYear, $currentMonth, 1);
+ $dayCount = 0;
+ $currentDay = 1;
+ while ($currentDay < $lastDayOfMonth + 1) {
+ if ($tdate->format('N') == $weekday) {
+ if (++$dayCount >= $nth) {
+ break;
+ }
+ }
+ $tdate->setDate($currentYear, $currentMonth, ++$currentDay);
+ }
+
+ return $date->format('j') == $currentDay;
+ }
+
+ // Handle day of the week values
+ if (strpos($value, '-')) {
+ $parts = explode('-', $value);
+ if ($parts[0] == '7') {
+ $parts[0] = '0';
+ } elseif ($parts[1] == '0') {
+ $parts[1] = '7';
+ }
+ $value = implode('-', $parts);
+ }
+
+ // Test to see which Sunday to use -- 0 == 7 == Sunday
+ $format = in_array(7, str_split($value)) ? 'N' : 'w';
+ $fieldValue = $date->format($format);
+
+ return $this->isSatisfied($fieldValue, $value);
+ }
+
+ public function increment(\DateTime $date, $invert = false)
+ {
+ if ($invert) {
+ $date->modify('-1 day');
+ $date->setTime(23, 59, 0);
+ } else {
+ $date->modify('+1 day');
+ $date->setTime(0, 0, 0);
+ }
+
+ return $this;
+ }
+
+ public function validate($value)
+ {
+ $value = $this->convertLiterals($value);
+
+ foreach (explode(',', $value) as $expr) {
+ if (!preg_match('/^(\*|[0-7](L?|#[1-5]))([\/\,\-][0-7]+)*$/', $expr)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private function convertLiterals($string)
+ {
+ return str_ireplace(
+ array('SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'),
+ range(0, 6),
+ $string
+ );
+ }
+}
diff --git a/web/system/vendor/Cron/FieldFactory.php b/web/system/vendor/Cron/FieldFactory.php
new file mode 100644
index 0000000..5aa86f6
--- /dev/null
+++ b/web/system/vendor/Cron/FieldFactory.php
@@ -0,0 +1,55 @@
+fields[$position])) {
+ switch ($position) {
+ case 0:
+ $this->fields[$position] = new MinutesField();
+ break;
+ case 1:
+ $this->fields[$position] = new HoursField();
+ break;
+ case 2:
+ $this->fields[$position] = new DayOfMonthField();
+ break;
+ case 3:
+ $this->fields[$position] = new MonthField();
+ break;
+ case 4:
+ $this->fields[$position] = new DayOfWeekField();
+ break;
+ case 5:
+ $this->fields[$position] = new YearField();
+ break;
+ default:
+ throw new \InvalidArgumentException(
+ $position . ' is not a valid position'
+ );
+ }
+ }
+
+ return $this->fields[$position];
+ }
+}
diff --git a/web/system/vendor/Cron/FieldInterface.php b/web/system/vendor/Cron/FieldInterface.php
new file mode 100644
index 0000000..3823fbf
--- /dev/null
+++ b/web/system/vendor/Cron/FieldInterface.php
@@ -0,0 +1,39 @@
+isSatisfied($date->format('H'), $value);
+ }
+
+ public function increment(\DateTime $date, $invert = false)
+ {
+ // Change timezone to UTC temporarily. This will
+ // allow us to go back or forwards and hour even
+ // if DST will be changed between the hours.
+ $timezone = $date->getTimezone();
+ $localMinutes = $date->format('i');
+ $date->setTimezone(new \DateTimeZone('UTC'));
+ // handle timezones with non-hour-offsets
+ $utcMinutes = $date->format('i');
+ $minDiff = $localMinutes - $utcMinutes;
+ if ($invert) {
+ $date->modify('-1 hour');
+ $date->setTime($date->format('H'), 59 - $minDiff);
+ } else {
+ $date->modify('+1 hour');
+ $date->setTime($date->format('H'), 0 - $minDiff);
+ }
+ $date->setTimezone($timezone);
+
+ return $this;
+ }
+
+ public function validate($value)
+ {
+ return (bool) preg_match('/^[\*,\/\-0-9]+$/', $value);
+ }
+}
diff --git a/web/system/vendor/Cron/LICENSE b/web/system/vendor/Cron/LICENSE
new file mode 100644
index 0000000..c6d88ac
--- /dev/null
+++ b/web/system/vendor/Cron/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2011 Michael Dowling and contributors
+
+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/web/system/vendor/Cron/MinutesField.php b/web/system/vendor/Cron/MinutesField.php
new file mode 100644
index 0000000..cfa2b09
--- /dev/null
+++ b/web/system/vendor/Cron/MinutesField.php
@@ -0,0 +1,30 @@
+isSatisfied($date->format('i'), $value);
+ }
+
+ public function increment(\DateTime $date, $invert = false)
+ {
+ if ($invert) {
+ $date->modify('-1 minute');
+ } else {
+ $date->modify('+1 minute');
+ }
+
+ return $this;
+ }
+
+ public function validate($value)
+ {
+ return (bool) preg_match('/^[\*,\/\-0-9]+$/', $value);
+ }
+}
diff --git a/web/system/vendor/Cron/MonthField.php b/web/system/vendor/Cron/MonthField.php
new file mode 100644
index 0000000..0205c17
--- /dev/null
+++ b/web/system/vendor/Cron/MonthField.php
@@ -0,0 +1,44 @@
+isSatisfied($date->format('m'), $value);
+ }
+
+ public function increment(DateTime $date, $invert = false)
+ {
+ if ($invert) {
+ $date->modify('last day of previous month');
+ $date->setTime(23, 59);
+ } else {
+ $date->modify('first day of next month');
+ $date->setTime(0, 0);
+ }
+
+ return $this;
+ }
+
+ public function validate($value)
+ {
+ return (bool) preg_match('/^[\*,\/\-0-9A-Z]+$/', $value);
+ }
+}
diff --git a/web/system/vendor/Cron/YearField.php b/web/system/vendor/Cron/YearField.php
new file mode 100644
index 0000000..b526dde
--- /dev/null
+++ b/web/system/vendor/Cron/YearField.php
@@ -0,0 +1,34 @@
+isSatisfied($date->format('Y'), $value);
+ }
+
+ public function increment(\DateTime $date, $invert = false)
+ {
+ if ($invert) {
+ $date->modify('-1 year');
+ $date->setDate($date->format('Y'), 12, 31);
+ $date->setTime(23, 59, 0);
+ } else {
+ $date->modify('+1 year');
+ $date->setDate($date->format('Y'), 1, 1);
+ $date->setTime(0, 0, 0);
+ }
+
+ return $this;
+ }
+
+ public function validate($value)
+ {
+ return (bool) preg_match('/^[\*,\/\-0-9]+$/', $value);
+ }
+}
diff --git a/web/system/vendor/cron.php b/web/system/vendor/cron.php
new file mode 100644
index 0000000..8cddfb8
--- /dev/null
+++ b/web/system/vendor/cron.php
@@ -0,0 +1,18 @@
+
\ No newline at end of file