commit 9a7a9e3593270eb7e979b03f6d3b52dab84bd665
Author: Simon Vieille
Date: Mon Mar 2 21:22:57 2015 +0100
init
diff --git a/README b/README
new file mode 100644
index 0000000..1c24539
--- /dev/null
+++ b/README
@@ -0,0 +1,2 @@
+CMS Install is a cli tool that helps you to download and install popular CMS.
+It works on Linux/Unix systems.
diff --git a/cms b/cms
new file mode 100755
index 0000000..ea872fc
--- /dev/null
+++ b/cms
@@ -0,0 +1,16 @@
+#!/usr/bin/env php
+init();
+}
+catch(Exception $e) {
+ Cli::printError('Fatal error', $e->getMessage());
+ die(1);
+}
diff --git a/config/00_app.yml b/config/00_app.yml
new file mode 100644
index 0000000..7847890
--- /dev/null
+++ b/config/00_app.yml
@@ -0,0 +1,42 @@
+app:
+ version: 0.1
+ author: 'Simon Vieille'
+ contact: 'simon@deblan.fr / www.deblan.tv'
+ rules:
+ "version|v-s" : ~
+ "list|l-s" : ~
+ "help|h-s" : ~
+ "install|i=s" : ~
+ "to|d=s" : ~
+ "create-dir|cd" : ~
+
+ configuration:
+ to: {hide: true}
+ create-dir: {hide: true}
+ version:
+ description: "Show CMS Installer version"
+ param: ~
+ callback:
+ class: Information
+ method: version
+
+ help:
+ description: "Show help"
+ param: '[command]'
+ callback:
+ class: Information
+ method: help
+
+ list:
+ description: "Show CMS list"
+ param: '[cms]'
+ callback:
+ class: Information
+ method: list
+
+ install:
+ param: 'name [--version version] [--to destination [--create-dir]]'
+ description: "Install a CMS"
+ callback:
+ class: Installation
+ method: install
diff --git a/config/00_ressources.yml b/config/00_ressources.yml
new file mode 100644
index 0000000..7b3ab0a
--- /dev/null
+++ b/config/00_ressources.yml
@@ -0,0 +1,45 @@
+ressources:
+ cms:
+ Wordpress:
+ versions:
+ default:
+ callback: Wordpress
+ url: http://fr.wordpress.org/latest-fr_FR.zip
+ local:
+ callback: Wordpress
+ url: http://localhost/~simon/wp.zip
+
+ Drupal:
+ versions:
+ default:
+ description: "Recommended release (version 7)"
+ url: http://ftp.drupal.org/files/projects/drupal-7.12.zip
+ v7.12:
+ description: "Recommended release (version 6)"
+ url: http://ftp.drupal.org/files/projects/drupal-7.12.zip
+ v6.25:
+ description: "Recommended release (version 6)"
+ url: http://ftp.drupal.org/files/projects/drupal-6.25.zip
+ v7dev:
+ description: "Development release (version 7)"
+ url: http://ftp.drupal.org/files/projects/drupal-7.x-dev.zip
+ v6dev:
+ description: "Development release (version 6)"
+ url: http://ftp.drupal.org/files/projects/drupal-6.x-dev.zip
+
+ Joomla:
+ versions:
+ default:
+ url: http://aide.joomla.fr/telechargements/joomla-2-5-package-d-installation-et-patchs/joomla-2-5-4-edition-francophone/download
+ v2.5:
+ url: http://aide.joomla.fr/telechargements/joomla-2-5-package-d-installation-et-patchs/joomla-2-5-4-edition-francophone/download
+ v1.7:
+ url: http://aide.joomla.fr/telechargements/joomla-1-7-package-d-installation-et-patchs/joomla-1-7-5-edition-francophone/download
+ v1.5:
+ url: http://aide.joomla.fr/telechargements/joomla-1-5-packages-d-installation-et-patchs/joomla-1-5-26-stable-fr/download
+
+ Pluxml:
+ versions:
+ default:
+ callback: Pluxml
+ url: http://telechargements.pluxml.org/download.php
diff --git a/lib/Zend/Console/Getopt.php b/lib/Zend/Console/Getopt.php
new file mode 100644
index 0000000..d603566
--- /dev/null
+++ b/lib/Zend/Console/Getopt.php
@@ -0,0 +1,970 @@
+ self::MODE_ZEND,
+ self::CONFIG_DASHDASH => true,
+ self::CONFIG_IGNORECASE => false,
+ self::CONFIG_PARSEALL => true,
+ );
+
+ /**
+ * Stores the command-line arguments for the calling applicaion.
+ *
+ * @var array
+ */
+ protected $_argv = array();
+
+ /**
+ * Stores the name of the calling applicaion.
+ *
+ * @var string
+ */
+ protected $_progname = '';
+
+ /**
+ * Stores the list of legal options for this application.
+ *
+ * @var array
+ */
+ protected $_rules = array();
+
+ /**
+ * Stores alternate spellings of legal options.
+ *
+ * @var array
+ */
+ protected $_ruleMap = array();
+
+ /**
+ * Stores options given by the user in the current invocation
+ * of the application, as well as parameters given in options.
+ *
+ * @var array
+ */
+ protected $_options = array();
+
+ /**
+ * Stores the command-line arguments other than options.
+ *
+ * @var array
+ */
+ protected $_remainingArgs = array();
+
+ /**
+ * State of the options: parsed or not yet parsed?
+ *
+ * @var boolean
+ */
+ protected $_parsed = false;
+
+ /**
+ * The constructor takes one to three parameters.
+ *
+ * The first parameter is $rules, which may be a string for
+ * gnu-style format, or a structured array for Zend-style format.
+ *
+ * The second parameter is $argv, and it is optional. If not
+ * specified, $argv is inferred from the global argv.
+ *
+ * The third parameter is an array of configuration parameters
+ * to control the behavior of this instance of Getopt; it is optional.
+ *
+ * @param array $rules
+ * @param array $argv
+ * @param array $getoptConfig
+ * @return void
+ */
+ public function __construct($rules, $argv = null, $getoptConfig = array())
+ {
+ if (!isset($_SERVER['argv'])) {
+ require_once 'Zend/Console/Getopt/Exception.php';
+ if (ini_get('register_argc_argv') == false) {
+ throw new Zend_Console_Getopt_Exception(
+ "argv is not available, because ini option 'register_argc_argv' is set Off"
+ );
+ } else {
+ throw new Zend_Console_Getopt_Exception(
+ '$_SERVER["argv"] is not set, but Zend_Console_Getopt cannot work without this information.'
+ );
+ }
+ }
+
+ $this->_progname = $_SERVER['argv'][0];
+ $this->setOptions($getoptConfig);
+ $this->addRules($rules);
+ if (!is_array($argv)) {
+ $argv = array_slice($_SERVER['argv'], 1);
+ }
+ if (isset($argv)) {
+ $this->addArguments((array)$argv);
+ }
+ }
+
+ /**
+ * Return the state of the option seen on the command line of the
+ * current application invocation. This function returns true, or the
+ * parameter to the option, if any. If the option was not given,
+ * this function returns null.
+ *
+ * The magic __get method works in the context of naming the option
+ * as a virtual member of this class.
+ *
+ * @param string $key
+ * @return string
+ */
+ public function __get($key)
+ {
+ return $this->getOption($key);
+ }
+
+ /**
+ * Test whether a given option has been seen.
+ *
+ * @param string $key
+ * @return boolean
+ */
+ public function __isset($key)
+ {
+ $this->parse();
+ if (isset($this->_ruleMap[$key])) {
+ $key = $this->_ruleMap[$key];
+ return isset($this->_options[$key]);
+ }
+ return false;
+ }
+
+ /**
+ * Set the value for a given option.
+ *
+ * @param string $key
+ * @param string $value
+ * @return void
+ */
+ public function __set($key, $value)
+ {
+ $this->parse();
+ if (isset($this->_ruleMap[$key])) {
+ $key = $this->_ruleMap[$key];
+ $this->_options[$key] = $value;
+ }
+ }
+
+ /**
+ * Return the current set of options and parameters seen as a string.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->toString();
+ }
+
+ /**
+ * Unset an option.
+ *
+ * @param string $key
+ * @return void
+ */
+ public function __unset($key)
+ {
+ $this->parse();
+ if (isset($this->_ruleMap[$key])) {
+ $key = $this->_ruleMap[$key];
+ unset($this->_options[$key]);
+ }
+ }
+
+ /**
+ * Define additional command-line arguments.
+ * These are appended to those defined when the constructor was called.
+ *
+ * @param array $argv
+ * @throws Zend_Console_Getopt_Exception When not given an array as parameter
+ * @return Zend_Console_Getopt Provides a fluent interface
+ */
+ public function addArguments($argv)
+ {
+ if(!is_array($argv)) {
+ require_once 'Zend/Console/Getopt/Exception.php';
+ throw new Zend_Console_Getopt_Exception(
+ "Parameter #1 to addArguments should be an array");
+ }
+ $this->_argv = array_merge($this->_argv, $argv);
+ $this->_parsed = false;
+ return $this;
+ }
+
+ /**
+ * Define full set of command-line arguments.
+ * These replace any currently defined.
+ *
+ * @param array $argv
+ * @throws Zend_Console_Getopt_Exception When not given an array as parameter
+ * @return Zend_Console_Getopt Provides a fluent interface
+ */
+ public function setArguments($argv)
+ {
+ if(!is_array($argv)) {
+ require_once 'Zend/Console/Getopt/Exception.php';
+ throw new Zend_Console_Getopt_Exception(
+ "Parameter #1 to setArguments should be an array");
+ }
+ $this->_argv = $argv;
+ $this->_parsed = false;
+ return $this;
+ }
+
+ /**
+ * Define multiple configuration options from an associative array.
+ * These are not program options, but properties to configure
+ * the behavior of Zend_Console_Getopt.
+ *
+ * @param array $getoptConfig
+ * @return Zend_Console_Getopt Provides a fluent interface
+ */
+ public function setOptions($getoptConfig)
+ {
+ if (isset($getoptConfig)) {
+ foreach ($getoptConfig as $key => $value) {
+ $this->setOption($key, $value);
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Define one configuration option as a key/value pair.
+ * These are not program options, but properties to configure
+ * the behavior of Zend_Console_Getopt.
+ *
+ * @param string $configKey
+ * @param string $configValue
+ * @return Zend_Console_Getopt Provides a fluent interface
+ */
+ public function setOption($configKey, $configValue)
+ {
+ if ($configKey !== null) {
+ $this->_getoptConfig[$configKey] = $configValue;
+ }
+ return $this;
+ }
+
+ /**
+ * Define additional option rules.
+ * These are appended to the rules defined when the constructor was called.
+ *
+ * @param array $rules
+ * @return Zend_Console_Getopt Provides a fluent interface
+ */
+ public function addRules($rules)
+ {
+ $ruleMode = $this->_getoptConfig['ruleMode'];
+ switch ($this->_getoptConfig['ruleMode']) {
+ case self::MODE_ZEND:
+ if (is_array($rules)) {
+ $this->_addRulesModeZend($rules);
+ break;
+ }
+ // intentional fallthrough
+ case self::MODE_GNU:
+ $this->_addRulesModeGnu($rules);
+ break;
+ default:
+ /**
+ * Call addRulesModeFoo() for ruleMode 'foo'.
+ * The developer should subclass Getopt and
+ * provide this method.
+ */
+ $method = '_addRulesMode' . ucfirst($ruleMode);
+ $this->$method($rules);
+ }
+ $this->_parsed = false;
+ return $this;
+ }
+
+ /**
+ * Return the current set of options and parameters seen as a string.
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ $this->parse();
+ $s = array();
+ foreach ($this->_options as $flag => $value) {
+ $s[] = $flag . '=' . ($value === true ? 'true' : $value);
+ }
+ return implode(' ', $s);
+ }
+
+ /**
+ * Return the current set of options and parameters seen
+ * as an array of canonical options and parameters.
+ *
+ * Clusters have been expanded, and option aliases
+ * have been mapped to their primary option names.
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $this->parse();
+ $s = array();
+ foreach ($this->_options as $flag => $value) {
+ $s[] = $flag;
+ if ($value !== true) {
+ $s[] = $value;
+ }
+ }
+ return $s;
+ }
+
+ /**
+ * Return the current set of options and parameters seen in Json format.
+ *
+ * @return string
+ */
+ public function toJson()
+ {
+ $this->parse();
+ $j = array();
+ foreach ($this->_options as $flag => $value) {
+ $j['options'][] = array(
+ 'option' => array(
+ 'flag' => $flag,
+ 'parameter' => $value
+ )
+ );
+ }
+
+ /**
+ * @see Zend_Json
+ */
+ require_once 'Zend/Json.php';
+ $json = Zend_Json::encode($j);
+
+ return $json;
+ }
+
+ /**
+ * Return the current set of options and parameters seen in XML format.
+ *
+ * @return string
+ */
+ public function toXml()
+ {
+ $this->parse();
+ $doc = new DomDocument('1.0', 'utf-8');
+ $optionsNode = $doc->createElement('options');
+ $doc->appendChild($optionsNode);
+ foreach ($this->_options as $flag => $value) {
+ $optionNode = $doc->createElement('option');
+ $optionNode->setAttribute('flag', utf8_encode($flag));
+ if ($value !== true) {
+ $optionNode->setAttribute('parameter', utf8_encode($value));
+ }
+ $optionsNode->appendChild($optionNode);
+ }
+ $xml = $doc->saveXML();
+ return $xml;
+ }
+
+ /**
+ * Return a list of options that have been seen in the current argv.
+ *
+ * @return array
+ */
+ public function getOptions()
+ {
+ $this->parse();
+ return array_keys($this->_options);
+ }
+
+ /**
+ * Return the state of the option seen on the command line of the
+ * current application invocation.
+ *
+ * This function returns true, or the parameter value to the option, if any.
+ * If the option was not given, this function returns false.
+ *
+ * @param string $flag
+ * @return mixed
+ */
+ public function getOption($flag)
+ {
+ $this->parse();
+ if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) {
+ $flag = strtolower($flag);
+ }
+ if (isset($this->_ruleMap[$flag])) {
+ $flag = $this->_ruleMap[$flag];
+ if (isset($this->_options[$flag])) {
+ return $this->_options[$flag];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return the arguments from the command-line following all options found.
+ *
+ * @return array
+ */
+ public function getRemainingArgs()
+ {
+ $this->parse();
+ return $this->_remainingArgs;
+ }
+
+ /**
+ * Return a useful option reference, formatted for display in an
+ * error message.
+ *
+ * Note that this usage information is provided in most Exceptions
+ * generated by this class.
+ *
+ * @return string
+ */
+ public function getUsageMessage()
+ {
+ $usage = "Usage: {$this->_progname} [ options ]\n";
+ $maxLen = 20;
+ $lines = array();
+ foreach ($this->_rules as $rule) {
+ $flags = array();
+ if (is_array($rule['alias'])) {
+ foreach ($rule['alias'] as $flag) {
+ $flags[] = (strlen($flag) == 1 ? '-' : '--') . $flag;
+ }
+ }
+ $linepart['name'] = implode('|', $flags);
+ if (isset($rule['param']) && $rule['param'] != 'none') {
+ $linepart['name'] .= ' ';
+ switch ($rule['param']) {
+ case 'optional':
+ $linepart['name'] .= "[ <{$rule['paramType']}> ]";
+ break;
+ case 'required':
+ $linepart['name'] .= "<{$rule['paramType']}>";
+ break;
+ }
+ }
+ if (strlen($linepart['name']) > $maxLen) {
+ $maxLen = strlen($linepart['name']);
+ }
+ $linepart['help'] = '';
+ if (isset($rule['help'])) {
+ $linepart['help'] .= $rule['help'];
+ }
+ $lines[] = $linepart;
+ }
+ foreach ($lines as $linepart) {
+ $usage .= sprintf("%s %s\n",
+ str_pad($linepart['name'], $maxLen),
+ $linepart['help']);
+ }
+ return $usage;
+ }
+
+ /**
+ * Define aliases for options.
+ *
+ * The parameter $aliasMap is an associative array
+ * mapping option name (short or long) to an alias.
+ *
+ * @param array $aliasMap
+ * @throws Zend_Console_Getopt_Exception
+ * @return Zend_Console_Getopt Provides a fluent interface
+ */
+ public function setAliases($aliasMap)
+ {
+ foreach ($aliasMap as $flag => $alias)
+ {
+ if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) {
+ $flag = strtolower($flag);
+ $alias = strtolower($alias);
+ }
+ if (!isset($this->_ruleMap[$flag])) {
+ continue;
+ }
+ $flag = $this->_ruleMap[$flag];
+ if (isset($this->_rules[$alias]) || isset($this->_ruleMap[$alias])) {
+ $o = (strlen($alias) == 1 ? '-' : '--') . $alias;
+ require_once 'Zend/Console/Getopt/Exception.php';
+ throw new Zend_Console_Getopt_Exception(
+ "Option \"$o\" is being defined more than once.");
+ }
+ $this->_rules[$flag]['alias'][] = $alias;
+ $this->_ruleMap[$alias] = $flag;
+ }
+ return $this;
+ }
+
+ /**
+ * Define help messages for options.
+ *
+ * The parameter $help_map is an associative array
+ * mapping option name (short or long) to the help string.
+ *
+ * @param array $helpMap
+ * @return Zend_Console_Getopt Provides a fluent interface
+ */
+ public function setHelp($helpMap)
+ {
+ foreach ($helpMap as $flag => $help)
+ {
+ if (!isset($this->_ruleMap[$flag])) {
+ continue;
+ }
+ $flag = $this->_ruleMap[$flag];
+ $this->_rules[$flag]['help'] = $help;
+ }
+ return $this;
+ }
+
+ /**
+ * Parse command-line arguments and find both long and short
+ * options.
+ *
+ * Also find option parameters, and remaining arguments after
+ * all options have been parsed.
+ *
+ * @return Zend_Console_Getopt|null Provides a fluent interface
+ */
+ public function parse()
+ {
+ if ($this->_parsed === true) {
+ return;
+ }
+ $argv = $this->_argv;
+ $this->_options = array();
+ $this->_remainingArgs = array();
+ while (count($argv) > 0) {
+ if ($argv[0] == '--') {
+ array_shift($argv);
+ if ($this->_getoptConfig[self::CONFIG_DASHDASH]) {
+ $this->_remainingArgs = array_merge($this->_remainingArgs, $argv);
+ break;
+ }
+ }
+ if (substr($argv[0], 0, 2) == '--') {
+ $this->_parseLongOption($argv);
+ } else if (substr($argv[0], 0, 1) == '-' && ('-' != $argv[0] || count($argv) >1)) {
+ $this->_parseShortOptionCluster($argv);
+ } else if($this->_getoptConfig[self::CONFIG_PARSEALL]) {
+ $this->_remainingArgs[] = array_shift($argv);
+ } else {
+ /*
+ * We should put all other arguments in _remainingArgs and stop parsing
+ * since CONFIG_PARSEALL is false.
+ */
+ $this->_remainingArgs = array_merge($this->_remainingArgs, $argv);
+ break;
+ }
+ }
+ $this->_parsed = true;
+ return $this;
+ }
+
+ /**
+ * Parse command-line arguments for a single long option.
+ * A long option is preceded by a double '--' character.
+ * Long options may not be clustered.
+ *
+ * @param mixed &$argv
+ * @return void
+ */
+ protected function _parseLongOption(&$argv)
+ {
+ $optionWithParam = ltrim(array_shift($argv), '-');
+ $l = explode('=', $optionWithParam, 2);
+ $flag = array_shift($l);
+ $param = array_shift($l);
+ if (isset($param)) {
+ array_unshift($argv, $param);
+ }
+ $this->_parseSingleOption($flag, $argv);
+ }
+
+ /**
+ * Parse command-line arguments for short options.
+ * Short options are those preceded by a single '-' character.
+ * Short options may be clustered.
+ *
+ * @param mixed &$argv
+ * @return void
+ */
+ protected function _parseShortOptionCluster(&$argv)
+ {
+ $flagCluster = ltrim(array_shift($argv), '-');
+ foreach (str_split($flagCluster) as $flag) {
+ $this->_parseSingleOption($flag, $argv);
+ }
+ }
+
+ /**
+ * Parse command-line arguments for a single option.
+ *
+ * @param string $flag
+ * @param mixed $argv
+ * @throws Zend_Console_Getopt_Exception
+ * @return void
+ */
+ protected function _parseSingleOption($flag, &$argv)
+ {
+ if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) {
+ $flag = strtolower($flag);
+ }
+ if (!isset($this->_ruleMap[$flag])) {
+ require_once 'Zend/Console/Getopt/Exception.php';
+ throw new Zend_Console_Getopt_Exception(
+ "Option \"$flag\" is not recognized.",
+ $this->getUsageMessage());
+ }
+ $realFlag = $this->_ruleMap[$flag];
+ switch ($this->_rules[$realFlag]['param']) {
+ case 'required':
+ if (count($argv) > 0) {
+ $param = array_shift($argv);
+ $this->_checkParameterType($realFlag, $param);
+ } else {
+ require_once 'Zend/Console/Getopt/Exception.php';
+ throw new Zend_Console_Getopt_Exception(
+ "Option \"$flag\" requires a parameter.",
+ $this->getUsageMessage());
+ }
+ break;
+ case 'optional':
+ if (count($argv) > 0 && substr($argv[0], 0, 1) != '-') {
+ $param = array_shift($argv);
+ $this->_checkParameterType($realFlag, $param);
+ } else {
+ $param = true;
+ }
+ break;
+ default:
+ $param = true;
+ }
+ $this->_options[$realFlag] = $param;
+ }
+
+ /**
+ * Return true if the parameter is in a valid format for
+ * the option $flag.
+ * Throw an exception in most other cases.
+ *
+ * @param string $flag
+ * @param string $param
+ * @throws Zend_Console_Getopt_Exception
+ * @return bool
+ */
+ protected function _checkParameterType($flag, $param)
+ {
+ $type = 'string';
+ if (isset($this->_rules[$flag]['paramType'])) {
+ $type = $this->_rules[$flag]['paramType'];
+ }
+ switch ($type) {
+ case 'word':
+ if (preg_match('/\W/', $param)) {
+ require_once 'Zend/Console/Getopt/Exception.php';
+ throw new Zend_Console_Getopt_Exception(
+ "Option \"$flag\" requires a single-word parameter, but was given \"$param\".",
+ $this->getUsageMessage());
+ }
+ break;
+ case 'integer':
+ if (preg_match('/\D/', $param)) {
+ require_once 'Zend/Console/Getopt/Exception.php';
+ throw new Zend_Console_Getopt_Exception(
+ "Option \"$flag\" requires an integer parameter, but was given \"$param\".",
+ $this->getUsageMessage());
+ }
+ break;
+ case 'string':
+ default:
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Define legal options using the gnu-style format.
+ *
+ * @param string $rules
+ * @return void
+ */
+ protected function _addRulesModeGnu($rules)
+ {
+ $ruleArray = array();
+
+ /**
+ * Options may be single alphanumeric characters.
+ * Options may have a ':' which indicates a required string parameter.
+ * No long options or option aliases are supported in GNU style.
+ */
+ preg_match_all('/([a-zA-Z0-9]:?)/', $rules, $ruleArray);
+ foreach ($ruleArray[1] as $rule) {
+ $r = array();
+ $flag = substr($rule, 0, 1);
+ if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) {
+ $flag = strtolower($flag);
+ }
+ $r['alias'][] = $flag;
+ if (substr($rule, 1, 1) == ':') {
+ $r['param'] = 'required';
+ $r['paramType'] = 'string';
+ } else {
+ $r['param'] = 'none';
+ }
+ $this->_rules[$flag] = $r;
+ $this->_ruleMap[$flag] = $flag;
+ }
+ }
+
+ /**
+ * Define legal options using the Zend-style format.
+ *
+ * @param array $rules
+ * @throws Zend_Console_Getopt_Exception
+ * @return void
+ */
+ protected function _addRulesModeZend($rules)
+ {
+ foreach ($rules as $ruleCode => $helpMessage)
+ {
+ // this may have to translate the long parm type if there
+ // are any complaints that =string will not work (even though that use
+ // case is not documented)
+ if (in_array(substr($ruleCode, -2, 1), array('-', '='))) {
+ $flagList = substr($ruleCode, 0, -2);
+ $delimiter = substr($ruleCode, -2, 1);
+ $paramType = substr($ruleCode, -1);
+ } else {
+ $flagList = $ruleCode;
+ $delimiter = $paramType = null;
+ }
+ if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) {
+ $flagList = strtolower($flagList);
+ }
+ $flags = explode('|', $flagList);
+ $rule = array();
+ $mainFlag = $flags[0];
+ foreach ($flags as $flag) {
+ if (empty($flag)) {
+ require_once 'Zend/Console/Getopt/Exception.php';
+ throw new Zend_Console_Getopt_Exception(
+ "Blank flag not allowed in rule \"$ruleCode\".");
+ }
+ if (strlen($flag) == 1) {
+ if (isset($this->_ruleMap[$flag])) {
+ require_once 'Zend/Console/Getopt/Exception.php';
+ throw new Zend_Console_Getopt_Exception(
+ "Option \"-$flag\" is being defined more than once.");
+ }
+ $this->_ruleMap[$flag] = $mainFlag;
+ $rule['alias'][] = $flag;
+ } else {
+ if (isset($this->_rules[$flag]) || isset($this->_ruleMap[$flag])) {
+ require_once 'Zend/Console/Getopt/Exception.php';
+ throw new Zend_Console_Getopt_Exception(
+ "Option \"--$flag\" is being defined more than once.");
+ }
+ $this->_ruleMap[$flag] = $mainFlag;
+ $rule['alias'][] = $flag;
+ }
+ }
+ if (isset($delimiter)) {
+ switch ($delimiter) {
+ case self::PARAM_REQUIRED:
+ $rule['param'] = 'required';
+ break;
+ case self::PARAM_OPTIONAL:
+ default:
+ $rule['param'] = 'optional';
+ }
+ switch (substr($paramType, 0, 1)) {
+ case self::TYPE_WORD:
+ $rule['paramType'] = 'word';
+ break;
+ case self::TYPE_INTEGER:
+ $rule['paramType'] = 'integer';
+ break;
+ case self::TYPE_STRING:
+ default:
+ $rule['paramType'] = 'string';
+ }
+ } else {
+ $rule['param'] = 'none';
+ }
+ $rule['help'] = $helpMessage;
+ $this->_rules[$mainFlag] = $rule;
+ }
+ }
+
+}
diff --git a/lib/Zend/Console/Getopt/Exception.php b/lib/Zend/Console/Getopt/Exception.php
new file mode 100644
index 0000000..cabb406
--- /dev/null
+++ b/lib/Zend/Console/Getopt/Exception.php
@@ -0,0 +1,66 @@
+usage = $usage;
+ parent::__construct($message);
+ }
+
+ /**
+ * Returns the usage
+ *
+ * @return string
+ */
+ public function getUsageMessage()
+ {
+ return $this->usage;
+ }
+}
diff --git a/lib/Zend/Console_Getopt.class.php b/lib/Zend/Console_Getopt.class.php
new file mode 100644
index 0000000..70da745
--- /dev/null
+++ b/lib/Zend/Console_Getopt.class.php
@@ -0,0 +1,7 @@
+_rules;
+ }
+}
diff --git a/lib/app/CmsInstallerApp.class.php b/lib/app/CmsInstallerApp.class.php
new file mode 100644
index 0000000..602eaa6
--- /dev/null
+++ b/lib/app/CmsInstallerApp.class.php
@@ -0,0 +1,98 @@
+argv = $argv;
+
+ $files = sfFinder::type('file')->name('*.yml')->in(ROOT.DIRECTORY_SEPARATOR.'config');
+
+ foreach($files as $file) {
+ $config = sfYaml::load($file);
+
+ if($config) {
+ if(mySfYaml::getAll()) {
+ mySfYaml::merge($file);
+ }
+ else {
+ mySfYaml::load($file);
+ }
+ }
+ }
+ }
+
+ public function init() {
+ $this->opts = new Console_Getopt(mySfYaml::get('app_rules'));
+
+ if(count($this->argv) > 1) {
+ try {
+ $this->opts->parse();
+ foreach($this->opts->getOptions() as $arg) {
+ $opt_config = mySfYaml::get('app_configuration_'.$arg);
+
+ if(!isset($opt_config['callback'])) {
+ throw new CmsInstallerException($arg.' has not a callback configuration (callback parameter not found).');
+ }
+
+ if(!isset($opt_config['callback']['class'])) {
+ throw new CmsInstallerException($arg.' has not a callback configuration (class parameter not found).');
+ }
+
+ if(!isset($opt_config['callback']['method'])) {
+ throw new CmsInstallerException($arg.' has not a callback configuration (class method not found).');
+ }
+
+ $this->callback($opt_config['callback']['class'], $opt_config['callback']['method'], $this->get($arg));
+ }
+ }
+ catch(Zend_Console_Getopt_Exception $e) {
+ CmsInstallerApp::showError('Invalid argument', 'Show help by using --help argument.');
+ }
+ catch(CmsInstallerException $e) {
+ CmsInstallerApp::showError('Configuration error', $e->getMessage());
+ }
+ }
+ }
+
+ private function callback($class, $method, $value) {
+ $class.= 'Task';
+ $method = 'execute'.ucfirst($method);
+
+ if(!class_exists($class)) {
+ throw new CmsInstallerException($class.' class does not exist');
+ }
+
+ if(!method_exists($class, $method)) {
+ throw new CmsInstallerException($class.'::'.$method.' does not exist');
+ }
+
+ $callback = new $class($value, $this);
+ $callback->$method();
+ }
+
+ public function get($param) {
+ try {
+ return $this->opts->getOption($param);
+ }
+ catch(Zend_Console_Getopt_Exception $e) {
+ CmsInstallerApp::showError('Invalid argument', '"'.$param.'" is not a valid argument. Show help by using --help argument.');
+ }
+ }
+
+ public static function showError($title, $message) {
+ Cli::printError($title, $message);
+ exit(1);
+ }
+
+ public function getArgv($n=null) {
+ return $n === null ? $this->argv : (isset($this->argv[$n]) ? $this->argv[$n] : null);
+ }
+
+ public function getOpts() {
+ return $this->opts;
+ }
+}
diff --git a/lib/autoload/Autoload.class.php b/lib/autoload/Autoload.class.php
new file mode 100644
index 0000000..df92e16
--- /dev/null
+++ b/lib/autoload/Autoload.class.php
@@ -0,0 +1,21 @@
+name('*.class.php')->in(ROOT.DIRECTORY_SEPARATOR.'lib');
+
+ foreach($files as $file) {
+ if(basename($file) == $class.'.class.php') {
+ require_once $file;
+ }
+ }
+ }
+}
+
diff --git a/lib/cli/Cli.class.php b/lib/cli/Cli.class.php
new file mode 100644
index 0000000..5126fce
--- /dev/null
+++ b/lib/cli/Cli.class.php
@@ -0,0 +1,89 @@
+ self::$width) {
+ $title.= "\n";
+ }
+ else {
+ $title = str_pad($title, self::$width, ' ', STR_PAD_RIGHT);
+ }
+ $output.= $cliColors->getColoredString(' '.$title, $foreground, $background).' ';
+ }
+
+ $output.= $message.($eol ? PHP_EOL : '');
+
+ fwrite($out, $output);
+ }
+
+ public static function printError($title, $message) {
+ self::printMessage($title, $message, 'red', 'white', STDERR);
+ }
+
+ public static function printNotice($title, $message) {
+ self::printMessage($title, $message, 'light_red', 'white');
+ }
+
+ public static function printInfo($title, $message) {
+ self::printMessage($title, $message, 'green', null);
+ }
+
+ public static function printInfoNoEOL($title, $message) {
+ self::printMessage($title, $message, 'green', null, STDOUT, false);
+ }
+
+ public static function printPrompt($title) {
+ self::printMessage($title, '', 'cyan', null, STDOUT, false);
+ }
+
+ public static function printBlankLine() {
+ echo PHP_EOL;
+ }
+
+ public static function prompt($title, $required=true, $default=null, $authorized_values=array()) {
+ $ask = true;
+ $promptValue = $default;
+ if(!empty($authorized_values)) {
+ $title.= ' ('.implode(', ', $authorized_values).')';
+ }
+
+ if($default !== null) {
+ $title.= ' ['.$default.']';
+ }
+
+ do {
+ self::printPrompt($title);
+ $promptValue = trim(fgets(STDIN));
+
+ if(!$required && empty($promptValue)) {
+ if(!empty($default)) {
+ $promptValue = $default;
+ }
+ $ask = false;
+ }
+ elseif($required && empty($promptValue)) {
+ if(!empty($default)) {
+ $promptValue = $default;
+ $ask = false;
+ }
+ else {
+ self::printNotice('> Required.', '');
+ }
+ }
+ elseif(!empty($authorized_values) && !in_array($promptValue, $authorized_values)) {
+ self::printNotice('Oops', 'Forbidden value, please try again.');
+ }
+ else {
+ $ask = false;
+ }
+ } while($ask);
+
+ return $promptValue;
+ }
+}
diff --git a/lib/cli/CliColors.class.php b/lib/cli/CliColors.class.php
new file mode 100644
index 0000000..a09f51c
--- /dev/null
+++ b/lib/cli/CliColors.class.php
@@ -0,0 +1,76 @@
+foreground_colors['black'] = '0;30';
+ $this->foreground_colors['dark_gray'] = '1;30';
+ $this->foreground_colors['blue'] = '0;34';
+ $this->foreground_colors['light_blue'] = '1;34';
+ $this->foreground_colors['green'] = '0;32';
+ $this->foreground_colors['light_green'] = '1;32';
+ $this->foreground_colors['cyan'] = '0;36';
+ $this->foreground_colors['light_cyan'] = '1;36';
+ $this->foreground_colors['red'] = '0;31';
+ $this->foreground_colors['light_red'] = '1;31';
+ $this->foreground_colors['purple'] = '0;35';
+ $this->foreground_colors['light_purple'] = '1;35';
+ $this->foreground_colors['brown'] = '0;33';
+ $this->foreground_colors['yellow'] = '1;33';
+ $this->foreground_colors['light_gray'] = '0;37';
+ $this->foreground_colors['white'] = '1;37';
+
+ $this->background_colors['black'] = '40';
+ $this->background_colors['red'] = '41';
+ $this->background_colors['green'] = '42';
+ $this->background_colors['yellow'] = '43';
+ $this->background_colors['blue'] = '44';
+ $this->background_colors['magenta'] = '45';
+ $this->background_colors['cyan'] = '46';
+ $this->background_colors['light_gray'] = '47';
+ }
+
+ public static function getInstance() {
+ if(is_null(self::$_instance)) {
+ self::$_instance = new CliColors();
+ }
+ return self::$_instance;
+ }
+
+ // Returns colored string
+ public function getColoredString($string, $foreground_color = null, $background_color = null) {
+ $colored_string = "";
+
+ // Check if given foreground color found
+ if (isset($this->foreground_colors[$foreground_color])) {
+ $colored_string .= "\033[" . $this->foreground_colors[$foreground_color] . "m";
+ }
+ // Check if given background color found
+ if (isset($this->background_colors[$background_color])) {
+ $colored_string .= "\033[" . $this->background_colors[$background_color] . "m";
+ }
+
+ // Add string and end coloring
+ $colored_string .= $string . "\033[0m";
+
+ return $colored_string;
+ }
+
+ // Returns all foreground color names
+ public function getForegroundColors() {
+ return array_keys($this->foreground_colors);
+ }
+
+ // Returns all background color names
+ public function getBackgroundColors() {
+ return array_keys($this->background_colors);
+ }
+}
+
diff --git a/lib/exception/CmsInstallerException.class.php b/lib/exception/CmsInstallerException.class.php
new file mode 100644
index 0000000..70dbff2
--- /dev/null
+++ b/lib/exception/CmsInstallerException.class.php
@@ -0,0 +1,4 @@
+ $value) {
+ if(!isset($global_config[$key])) {
+ $global_config[$key] = $value;
+ }
+ else {
+ if(is_array($value)) {
+ foreach($value as $vkey => $vvalue) {
+ if(!isset($global_config[$key][$vkey])) {
+ $global_config[$key][$vkey] = $vvalue;
+ }
+ else {
+ self::recursiveMerge($global_config[$key], $value);
+ }
+ }
+ }
+ else {
+ $global_config[$key] = $value;
+ }
+ }
+ }
+ }
+
+ public static function getAll() {
+ return self::$global_config;
+ }
+
+ public static function get($var) {
+ if(!self::$file_loaded) {
+ throw new Exception('Yaml file is not loaded yet, please see sfYaml::load method');
+ }
+
+ $road = self::$global_config;
+
+ $parts = explode('_', $var);
+
+ while(true) {
+ $shift = array_shift($parts);
+
+ if(isset($road[$shift])) {
+ if(empty($parts)) {
+ return $road[$shift];
+ }
+ else {
+ $road = $road[$shift];
+ }
+ }
+ else {
+ return null;
+ }
+ }
+ }
+}
diff --git a/lib/sfYaml/sfYaml.class.php b/lib/sfYaml/sfYaml.class.php
new file mode 100644
index 0000000..a45917e
--- /dev/null
+++ b/lib/sfYaml/sfYaml.class.php
@@ -0,0 +1,133 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * sfYaml offers convenience methods to load and dump YAML.
+ *
+ * @package symfony
+ * @subpackage yaml
+ * @author Fabien Potencier
+ * @version SVN: $Id: sfYaml.class.php 8988 2008-05-15 20:24:26Z fabien $
+ */
+class sfYaml
+{
+ static protected
+ $spec = '1.2';
+
+ /**
+ * Sets the YAML specification version to use.
+ *
+ * @param string $version The YAML specification version
+ */
+ static public function setSpecVersion($version)
+ {
+ if (!in_array($version, array('1.1', '1.2')))
+ {
+ throw new InvalidArgumentException(sprintf('Version %s of the YAML specifications is not supported', $version));
+ }
+
+ self::$spec = $version;
+ }
+
+ /**
+ * Gets the YAML specification version to use.
+ *
+ * @return string The YAML specification version
+ */
+ static public function getSpecVersion()
+ {
+ return self::$spec;
+ }
+
+ /**
+ * Loads YAML into a PHP array.
+ *
+ * The load method, when supplied with a YAML stream (string or file),
+ * will do its best to convert YAML in a file into a PHP array.
+ *
+ * Usage:
+ *
+ * $array = sfYaml::load('config.yml');
+ * print_r($array);
+ *
+ *
+ * @param string $input Path of YAML file or string containing YAML
+ *
+ * @return array The YAML converted to a PHP array
+ *
+ * @throws InvalidArgumentException If the YAML is not valid
+ */
+ public static function load($input)
+ {
+ $file = '';
+
+ // if input is a file, process it
+ if (strpos($input, "\n") === false && is_file($input))
+ {
+ $file = $input;
+
+ ob_start();
+ $retval = include($input);
+ $content = ob_get_clean();
+
+ // if an array is returned by the config file assume it's in plain php form else in YAML
+ $input = is_array($retval) ? $retval : $content;
+ }
+
+ // if an array is returned by the config file assume it's in plain php form else in YAML
+ if (is_array($input))
+ {
+ return $input;
+ }
+
+ $yaml = new sfYamlParser();
+
+ try
+ {
+ $ret = $yaml->parse($input);
+ }
+ catch (Exception $e)
+ {
+ throw new InvalidArgumentException(sprintf('Unable to parse %s: %s', $file ? sprintf('file "%s"', $file) : 'string', $e->getMessage()));
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Dumps a PHP array to a YAML string.
+ *
+ * The dump method, when supplied with an array, will do its best
+ * to convert the array into friendly YAML.
+ *
+ * @param array $array PHP array
+ * @param integer $inline The level where you switch to inline YAML
+ *
+ * @return string A YAML string representing the original PHP array
+ */
+ public static function dump($array, $inline = 2)
+ {
+ require_once dirname(__FILE__).'/sfYamlDumper.php';
+
+ $yaml = new sfYamlDumper();
+
+ return $yaml->dump($array, $inline);
+ }
+}
+
+/**
+ * Wraps echo to automatically provide a newline.
+ *
+ * @param string $string The string to echo with new line
+ */
+function echoln($string)
+{
+ echo $string."\n";
+}
diff --git a/lib/sfYaml/sfYamlDumper.class.php b/lib/sfYaml/sfYamlDumper.class.php
new file mode 100644
index 0000000..130f236
--- /dev/null
+++ b/lib/sfYaml/sfYamlDumper.class.php
@@ -0,0 +1,58 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * sfYamlDumper dumps PHP variables to YAML strings.
+ *
+ * @package symfony
+ * @subpackage yaml
+ * @author Fabien Potencier
+ * @version SVN: $Id: sfYamlDumper.class.php 10575 2008-08-01 13:08:42Z nicolas $
+ */
+class sfYamlDumper
+{
+ /**
+ * Dumps a PHP value to YAML.
+ *
+ * @param mixed $input The PHP value
+ * @param integer $inline The level where you switch to inline YAML
+ * @param integer $indent The level o indentation indentation (used internally)
+ *
+ * @return string The YAML representation of the PHP value
+ */
+ public function dump($input, $inline = 0, $indent = 0)
+ {
+ $output = '';
+ $prefix = $indent ? str_repeat(' ', $indent) : '';
+
+ if ($inline <= 0 || !is_array($input) || empty($input))
+ {
+ $output .= $prefix.sfYamlInline::dump($input);
+ }
+ else
+ {
+ $isAHash = array_keys($input) !== range(0, count($input) - 1);
+
+ foreach ($input as $key => $value)
+ {
+ $willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value);
+
+ $output .= sprintf('%s%s%s%s',
+ $prefix,
+ $isAHash ? sfYamlInline::dump($key).':' : '-',
+ $willBeInlined ? ' ' : "\n",
+ $this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + 2)
+ ).($willBeInlined ? "\n" : '');
+ }
+ }
+
+ return $output;
+ }
+}
diff --git a/lib/sfYaml/sfYamlInline.class.php b/lib/sfYaml/sfYamlInline.class.php
new file mode 100644
index 0000000..3bb1868
--- /dev/null
+++ b/lib/sfYaml/sfYamlInline.class.php
@@ -0,0 +1,440 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * sfYamlInline implements a YAML parser/dumper for the YAML inline syntax.
+ *
+ * @package symfony
+ * @subpackage yaml
+ * @author Fabien Potencier
+ * @version SVN: $Id: sfYamlInline.class.php 16177 2009-03-11 08:32:48Z fabien $
+ */
+class sfYamlInline
+{
+ const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')';
+
+ /**
+ * Convert a YAML string to a PHP array.
+ *
+ * @param string $value A YAML string
+ *
+ * @return array A PHP array representing the YAML string
+ */
+ static public function load($value)
+ {
+ $value = trim($value);
+
+ if (0 == strlen($value))
+ {
+ return '';
+ }
+
+ if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2)
+ {
+ $mbEncoding = mb_internal_encoding();
+ mb_internal_encoding('ASCII');
+ }
+
+ switch ($value[0])
+ {
+ case '[':
+ $result = self::parseSequence($value);
+ break;
+ case '{':
+ $result = self::parseMapping($value);
+ break;
+ default:
+ $result = self::parseScalar($value);
+ }
+
+ if (isset($mbEncoding))
+ {
+ mb_internal_encoding($mbEncoding);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Dumps a given PHP variable to a YAML string.
+ *
+ * @param mixed $value The PHP variable to convert
+ *
+ * @return string The YAML string representing the PHP array
+ */
+ static public function dump($value)
+ {
+ if ('1.1' === sfYaml::getSpecVersion())
+ {
+ $trueValues = array('true', 'on', '+', 'yes', 'y');
+ $falseValues = array('false', 'off', '-', 'no', 'n');
+ }
+ else
+ {
+ $trueValues = array('true');
+ $falseValues = array('false');
+ }
+
+ switch (true)
+ {
+ case is_resource($value):
+ throw new InvalidArgumentException('Unable to dump PHP resources in a YAML file.');
+ case is_object($value):
+ return '!!php/object:'.serialize($value);
+ case is_array($value):
+ return self::dumpArray($value);
+ case null === $value:
+ return 'null';
+ case true === $value:
+ return 'true';
+ case false === $value:
+ return 'false';
+ case ctype_digit($value):
+ return is_string($value) ? "'$value'" : (int) $value;
+ case is_numeric($value):
+ return is_infinite($value) ? str_ireplace('INF', '.Inf', strval($value)) : (is_string($value) ? "'$value'" : $value);
+ case false !== strpos($value, "\n") || false !== strpos($value, "\r"):
+ return sprintf('"%s"', str_replace(array('"', "\n", "\r"), array('\\"', '\n', '\r'), $value));
+ case preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ - ? | < > = ! % @ ` ]/x', $value):
+ return sprintf("'%s'", str_replace('\'', '\'\'', $value));
+ case '' == $value:
+ return "''";
+ case preg_match(self::getTimestampRegex(), $value):
+ return "'$value'";
+ case in_array(strtolower($value), $trueValues):
+ return "'$value'";
+ case in_array(strtolower($value), $falseValues):
+ return "'$value'";
+ case in_array(strtolower($value), array('null', '~')):
+ return "'$value'";
+ default:
+ return $value;
+ }
+ }
+
+ /**
+ * Dumps a PHP array to a YAML string.
+ *
+ * @param array $value The PHP array to dump
+ *
+ * @return string The YAML string representing the PHP array
+ */
+ static protected function dumpArray($value)
+ {
+ // array
+ $keys = array_keys($value);
+ if (
+ (1 == count($keys) && '0' == $keys[0])
+ ||
+ (count($keys) > 1 && array_reduce($keys, create_function('$v,$w', 'return (integer) $v + $w;'), 0) == count($keys) * (count($keys) - 1) / 2))
+ {
+ $output = array();
+ foreach ($value as $val)
+ {
+ $output[] = self::dump($val);
+ }
+
+ return sprintf('[%s]', implode(', ', $output));
+ }
+
+ // mapping
+ $output = array();
+ foreach ($value as $key => $val)
+ {
+ $output[] = sprintf('%s: %s', self::dump($key), self::dump($val));
+ }
+
+ return sprintf('{ %s }', implode(', ', $output));
+ }
+
+ /**
+ * Parses a scalar to a YAML string.
+ *
+ * @param scalar $scalar
+ * @param string $delimiters
+ * @param array $stringDelimiter
+ * @param integer $i
+ * @param boolean $evaluate
+ *
+ * @return string A YAML string
+ */
+ static public function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true)
+ {
+ if (in_array($scalar[$i], $stringDelimiters))
+ {
+ // quoted scalar
+ $output = self::parseQuotedScalar($scalar, $i);
+ }
+ else
+ {
+ // "normal" string
+ if (!$delimiters)
+ {
+ $output = substr($scalar, $i);
+ $i += strlen($output);
+
+ // remove comments
+ if (false !== $strpos = strpos($output, ' #'))
+ {
+ $output = rtrim(substr($output, 0, $strpos));
+ }
+ }
+ else if (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match))
+ {
+ $output = $match[1];
+ $i += strlen($output);
+ }
+ else
+ {
+ throw new InvalidArgumentException(sprintf('Malformed inline YAML string (%s).', $scalar));
+ }
+
+ $output = $evaluate ? self::evaluateScalar($output) : $output;
+ }
+
+ return $output;
+ }
+
+ /**
+ * Parses a quoted scalar to YAML.
+ *
+ * @param string $scalar
+ * @param integer $i
+ *
+ * @return string A YAML string
+ */
+ static protected function parseQuotedScalar($scalar, &$i)
+ {
+ if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match))
+ {
+ throw new InvalidArgumentException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i)));
+ }
+
+ $output = substr($match[0], 1, strlen($match[0]) - 2);
+
+ if ('"' == $scalar[$i])
+ {
+ // evaluate the string
+ $output = str_replace(array('\\"', '\\n', '\\r'), array('"', "\n", "\r"), $output);
+ }
+ else
+ {
+ // unescape '
+ $output = str_replace('\'\'', '\'', $output);
+ }
+
+ $i += strlen($match[0]);
+
+ return $output;
+ }
+
+ /**
+ * Parses a sequence to a YAML string.
+ *
+ * @param string $sequence
+ * @param integer $i
+ *
+ * @return string A YAML string
+ */
+ static protected function parseSequence($sequence, &$i = 0)
+ {
+ $output = array();
+ $len = strlen($sequence);
+ $i += 1;
+
+ // [foo, bar, ...]
+ while ($i < $len)
+ {
+ switch ($sequence[$i])
+ {
+ case '[':
+ // nested sequence
+ $output[] = self::parseSequence($sequence, $i);
+ break;
+ case '{':
+ // nested mapping
+ $output[] = self::parseMapping($sequence, $i);
+ break;
+ case ']':
+ return $output;
+ case ',':
+ case ' ':
+ break;
+ default:
+ $isQuoted = in_array($sequence[$i], array('"', "'"));
+ $value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i);
+
+ if (!$isQuoted && false !== strpos($value, ': '))
+ {
+ // embedded mapping?
+ try
+ {
+ $value = self::parseMapping('{'.$value.'}');
+ }
+ catch (InvalidArgumentException $e)
+ {
+ // no, it's not
+ }
+ }
+
+ $output[] = $value;
+
+ --$i;
+ }
+
+ ++$i;
+ }
+
+ throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $sequence));
+ }
+
+ /**
+ * Parses a mapping to a YAML string.
+ *
+ * @param string $mapping
+ * @param integer $i
+ *
+ * @return string A YAML string
+ */
+ static protected function parseMapping($mapping, &$i = 0)
+ {
+ $output = array();
+ $len = strlen($mapping);
+ $i += 1;
+
+ // {foo: bar, bar:foo, ...}
+ while ($i < $len)
+ {
+ switch ($mapping[$i])
+ {
+ case ' ':
+ case ',':
+ ++$i;
+ continue 2;
+ case '}':
+ return $output;
+ }
+
+ // key
+ $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);
+
+ // value
+ $done = false;
+ while ($i < $len)
+ {
+ switch ($mapping[$i])
+ {
+ case '[':
+ // nested sequence
+ $output[$key] = self::parseSequence($mapping, $i);
+ $done = true;
+ break;
+ case '{':
+ // nested mapping
+ $output[$key] = self::parseMapping($mapping, $i);
+ $done = true;
+ break;
+ case ':':
+ case ' ':
+ break;
+ default:
+ $output[$key] = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i);
+ $done = true;
+ --$i;
+ }
+
+ ++$i;
+
+ if ($done)
+ {
+ continue 2;
+ }
+ }
+ }
+
+ throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $mapping));
+ }
+
+ /**
+ * Evaluates scalars and replaces magic values.
+ *
+ * @param string $scalar
+ *
+ * @return string A YAML string
+ */
+ static protected function evaluateScalar($scalar)
+ {
+ $scalar = trim($scalar);
+
+ if ('1.1' === sfYaml::getSpecVersion())
+ {
+ $trueValues = array('true', 'on', '+', 'yes', 'y');
+ $falseValues = array('false', 'off', '-', 'no', 'n');
+ }
+ else
+ {
+ $trueValues = array('true');
+ $falseValues = array('false');
+ }
+
+ switch (true)
+ {
+ case 'null' == strtolower($scalar):
+ case '' == $scalar:
+ case '~' == $scalar:
+ return null;
+ case 0 === strpos($scalar, '!str'):
+ return (string) substr($scalar, 5);
+ case 0 === strpos($scalar, '! '):
+ return intval(self::parseScalar(substr($scalar, 2)));
+ case 0 === strpos($scalar, '!!php/object:'):
+ return unserialize(substr($scalar, 13));
+ case ctype_digit($scalar):
+ $raw = $scalar;
+ $cast = intval($scalar);
+ return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
+ case in_array(strtolower($scalar), $trueValues):
+ return true;
+ case in_array(strtolower($scalar), $falseValues):
+ return false;
+ case is_numeric($scalar):
+ return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar);
+ case 0 == strcasecmp($scalar, '.inf'):
+ case 0 == strcasecmp($scalar, '.NaN'):
+ return -log(0);
+ case 0 == strcasecmp($scalar, '-.inf'):
+ return log(0);
+ case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
+ return floatval(str_replace(',', '', $scalar));
+ case preg_match(self::getTimestampRegex(), $scalar):
+ return strtotime($scalar);
+ default:
+ return (string) $scalar;
+ }
+ }
+
+ static protected function getTimestampRegex()
+ {
+ return <<[0-9][0-9][0-9][0-9])
+ -(?P[0-9][0-9]?)
+ -(?P[0-9][0-9]?)
+ (?:(?:[Tt]|[ \t]+)
+ (?P[0-9][0-9]?)
+ :(?P[0-9][0-9])
+ :(?P[0-9][0-9])
+ (?:\.(?P[0-9]*))?
+ (?:[ \t]*(?PZ|(?P[-+])(?P[0-9][0-9]?)
+ (?::(?P[0-9][0-9]))?))?)?
+ $~x
+EOF;
+ }
+}
diff --git a/lib/sfYaml/sfYamlParser.class.php b/lib/sfYaml/sfYamlParser.class.php
new file mode 100644
index 0000000..820de59
--- /dev/null
+++ b/lib/sfYaml/sfYamlParser.class.php
@@ -0,0 +1,620 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (!defined('PREG_BAD_UTF8_OFFSET_ERROR'))
+{
+ define('PREG_BAD_UTF8_OFFSET_ERROR', 5);
+}
+
+/**
+ * sfYamlParser parses YAML strings to convert them to PHP arrays.
+ *
+ * @package symfony
+ * @subpackage yaml
+ * @author Fabien Potencier
+ * @version SVN: $Id: sfYamlParser.class.php 10832 2008-08-13 07:46:08Z fabien $
+ */
+class sfYamlParser
+{
+ protected
+ $offset = 0,
+ $lines = array(),
+ $currentLineNb = -1,
+ $currentLine = '',
+ $refs = array();
+
+ /**
+ * Constructor
+ *
+ * @param integer $offset The offset of YAML document (used for line numbers in error messages)
+ */
+ public function __construct($offset = 0)
+ {
+ $this->offset = $offset;
+ }
+
+ /**
+ * Parses a YAML string to a PHP value.
+ *
+ * @param string $value A YAML string
+ *
+ * @return mixed A PHP value
+ *
+ * @throws InvalidArgumentException If the YAML is not valid
+ */
+ public function parse($value)
+ {
+ $this->currentLineNb = -1;
+ $this->currentLine = '';
+ $this->lines = explode("\n", $this->cleanup($value));
+
+ if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2)
+ {
+ $mbEncoding = mb_internal_encoding();
+ mb_internal_encoding('UTF-8');
+ }
+
+ $data = array();
+ while ($this->moveToNextLine())
+ {
+ if ($this->isCurrentLineEmpty())
+ {
+ continue;
+ }
+
+ // tab?
+ if (preg_match('#^\t+#', $this->currentLine))
+ {
+ throw new InvalidArgumentException(sprintf('A YAML file cannot contain tabs as indentation at line %d (%s).', $this->getRealCurrentLineNb() + 1, $this->currentLine));
+ }
+
+ $isRef = $isInPlace = $isProcessed = false;
+ if (preg_match('#^\-((?P\s+)(?P.+?))?\s*$#u', $this->currentLine, $values))
+ {
+ if (isset($values['value']) && preg_match('#^&(?P[[^ ]+) *(?P].*)#u', $values['value'], $matches))
+ {
+ $isRef = $matches['ref'];
+ $values['value'] = $matches['value'];
+ }
+
+ // array
+ if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#'))
+ {
+ $c = $this->getRealCurrentLineNb() + 1;
+ $parser = new sfYamlParser($c);
+ $parser->refs =& $this->refs;
+ $data[] = $parser->parse($this->getNextEmbedBlock());
+ }
+ else
+ {
+ if (isset($values['leadspaces'])
+ && ' ' == $values['leadspaces']
+ && preg_match('#^(?P'.sfYamlInline::REGEX_QUOTED_STRING.'|[^ \'"\{].*?) *\:(\s+(?P.+?))?\s*$#u', $values['value'], $matches))
+ {
+ // this is a compact notation element, add to next block and parse
+ $c = $this->getRealCurrentLineNb();
+ $parser = new sfYamlParser($c);
+ $parser->refs =& $this->refs;
+
+ $block = $values['value'];
+ if (!$this->isNextLineIndented())
+ {
+ $block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + 2);
+ }
+
+ $data[] = $parser->parse($block);
+ }
+ else
+ {
+ $data[] = $this->parseValue($values['value']);
+ }
+ }
+ }
+ else if (preg_match('#^(?P'.sfYamlInline::REGEX_QUOTED_STRING.'|[^ \'"].*?) *\:(\s+(?P.+?))?\s*$#u', $this->currentLine, $values))
+ {
+ $key = sfYamlInline::parseScalar($values['key']);
+
+ if ('<<' === $key)
+ {
+ if (isset($values['value']) && '*' === substr($values['value'], 0, 1))
+ {
+ $isInPlace = substr($values['value'], 1);
+ if (!array_key_exists($isInPlace, $this->refs))
+ {
+ throw new InvalidArgumentException(sprintf('Reference "%s" does not exist at line %s (%s).', $isInPlace, $this->getRealCurrentLineNb() + 1, $this->currentLine));
+ }
+ }
+ else
+ {
+ if (isset($values['value']) && $values['value'] !== '')
+ {
+ $value = $values['value'];
+ }
+ else
+ {
+ $value = $this->getNextEmbedBlock();
+ }
+ $c = $this->getRealCurrentLineNb() + 1;
+ $parser = new sfYamlParser($c);
+ $parser->refs =& $this->refs;
+ $parsed = $parser->parse($value);
+
+ $merged = array();
+ if (!is_array($parsed))
+ {
+ throw new InvalidArgumentException(sprintf("YAML merge keys used with a scalar value instead of an array at line %s (%s)", $this->getRealCurrentLineNb() + 1, $this->currentLine));
+ }
+ else if (isset($parsed[0]))
+ {
+ // Numeric array, merge individual elements
+ foreach (array_reverse($parsed) as $parsedItem)
+ {
+ if (!is_array($parsedItem))
+ {
+ throw new InvalidArgumentException(sprintf("Merge items must be arrays at line %s (%s).", $this->getRealCurrentLineNb() + 1, $parsedItem));
+ }
+ $merged = array_merge($parsedItem, $merged);
+ }
+ }
+ else
+ {
+ // Associative array, merge
+ $merged = array_merge($merged, $parsed);
+ }
+
+ $isProcessed = $merged;
+ }
+ }
+ else if (isset($values['value']) && preg_match('#^&(?P[[^ ]+) *(?P].*)#u', $values['value'], $matches))
+ {
+ $isRef = $matches['ref'];
+ $values['value'] = $matches['value'];
+ }
+
+ if ($isProcessed)
+ {
+ // Merge keys
+ $data = $isProcessed;
+ }
+ // hash
+ else if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#'))
+ {
+ // if next line is less indented or equal, then it means that the current value is null
+ if ($this->isNextLineIndented())
+ {
+ $data[$key] = null;
+ }
+ else
+ {
+ $c = $this->getRealCurrentLineNb() + 1;
+ $parser = new sfYamlParser($c);
+ $parser->refs =& $this->refs;
+ $data[$key] = $parser->parse($this->getNextEmbedBlock());
+ }
+ }
+ else
+ {
+ if ($isInPlace)
+ {
+ $data = $this->refs[$isInPlace];
+ }
+ else
+ {
+ $data[$key] = $this->parseValue($values['value']);
+ }
+ }
+ }
+ else
+ {
+ // 1-liner followed by newline
+ if (2 == count($this->lines) && empty($this->lines[1]))
+ {
+ $value = sfYamlInline::load($this->lines[0]);
+ if (is_array($value))
+ {
+ $first = reset($value);
+ if ('*' === substr($first, 0, 1))
+ {
+ $data = array();
+ foreach ($value as $alias)
+ {
+ $data[] = $this->refs[substr($alias, 1)];
+ }
+ $value = $data;
+ }
+ }
+
+ if (isset($mbEncoding))
+ {
+ mb_internal_encoding($mbEncoding);
+ }
+
+ return $value;
+ }
+
+ switch (preg_last_error())
+ {
+ case PREG_INTERNAL_ERROR:
+ $error = 'Internal PCRE error on line';
+ break;
+ case PREG_BACKTRACK_LIMIT_ERROR:
+ $error = 'pcre.backtrack_limit reached on line';
+ break;
+ case PREG_RECURSION_LIMIT_ERROR:
+ $error = 'pcre.recursion_limit reached on line';
+ break;
+ case PREG_BAD_UTF8_ERROR:
+ $error = 'Malformed UTF-8 data on line';
+ break;
+ case PREG_BAD_UTF8_OFFSET_ERROR:
+ $error = 'Offset doesn\'t correspond to the begin of a valid UTF-8 code point on line';
+ break;
+ default:
+ $error = 'Unable to parse line';
+ }
+
+ throw new InvalidArgumentException(sprintf('%s %d (%s).', $error, $this->getRealCurrentLineNb() + 1, $this->currentLine));
+ }
+
+ if ($isRef)
+ {
+ $this->refs[$isRef] = end($data);
+ }
+ }
+
+ if (isset($mbEncoding))
+ {
+ mb_internal_encoding($mbEncoding);
+ }
+
+ return empty($data) ? null : $data;
+ }
+
+ /**
+ * Returns the current line number (takes the offset into account).
+ *
+ * @return integer The current line number
+ */
+ protected function getRealCurrentLineNb()
+ {
+ return $this->currentLineNb + $this->offset;
+ }
+
+ /**
+ * Returns the current line indentation.
+ *
+ * @return integer The current line indentation
+ */
+ protected function getCurrentLineIndentation()
+ {
+ return strlen($this->currentLine) - strlen(ltrim($this->currentLine, ' '));
+ }
+
+ /**
+ * Returns the next embed block of YAML.
+ *
+ * @param integer $indentation The indent level at which the block is to be read, or null for default
+ *
+ * @return string A YAML string
+ */
+ protected function getNextEmbedBlock($indentation = null)
+ {
+ $this->moveToNextLine();
+
+ if (null === $indentation)
+ {
+ $newIndent = $this->getCurrentLineIndentation();
+
+ if (!$this->isCurrentLineEmpty() && 0 == $newIndent)
+ {
+ throw new InvalidArgumentException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine));
+ }
+ }
+ else
+ {
+ $newIndent = $indentation;
+ }
+
+ $data = array(substr($this->currentLine, $newIndent));
+
+ while ($this->moveToNextLine())
+ {
+ if ($this->isCurrentLineEmpty())
+ {
+ if ($this->isCurrentLineBlank())
+ {
+ $data[] = substr($this->currentLine, $newIndent);
+ }
+
+ continue;
+ }
+
+ $indent = $this->getCurrentLineIndentation();
+
+ if (preg_match('#^(?P *)$#', $this->currentLine, $match))
+ {
+ // empty line
+ $data[] = $match['text'];
+ }
+ else if ($indent >= $newIndent)
+ {
+ $data[] = substr($this->currentLine, $newIndent);
+ }
+ else if (0 == $indent)
+ {
+ $this->moveToPreviousLine();
+
+ break;
+ }
+ else
+ {
+ throw new InvalidArgumentException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine));
+ }
+ }
+
+ return implode("\n", $data);
+ }
+
+ /**
+ * Moves the parser to the next line.
+ */
+ protected function moveToNextLine()
+ {
+ if ($this->currentLineNb >= count($this->lines) - 1)
+ {
+ return false;
+ }
+
+ $this->currentLine = $this->lines[++$this->currentLineNb];
+
+ return true;
+ }
+
+ /**
+ * Moves the parser to the previous line.
+ */
+ protected function moveToPreviousLine()
+ {
+ $this->currentLine = $this->lines[--$this->currentLineNb];
+ }
+
+ /**
+ * Parses a YAML value.
+ *
+ * @param string $value A YAML value
+ *
+ * @return mixed A PHP value
+ */
+ protected function parseValue($value)
+ {
+ if ('*' === substr($value, 0, 1))
+ {
+ if (false !== $pos = strpos($value, '#'))
+ {
+ $value = substr($value, 1, $pos - 2);
+ }
+ else
+ {
+ $value = substr($value, 1);
+ }
+
+ if (!array_key_exists($value, $this->refs))
+ {
+ throw new InvalidArgumentException(sprintf('Reference "%s" does not exist (%s).', $value, $this->currentLine));
+ }
+ return $this->refs[$value];
+ }
+
+ if (preg_match('/^(?P\||>)(?P\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P +#.*)?$/', $value, $matches))
+ {
+ $modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : '';
+
+ return $this->parseFoldedScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), intval(abs($modifiers)));
+ }
+ else
+ {
+ return sfYamlInline::load($value);
+ }
+ }
+
+ /**
+ * Parses a folded scalar.
+ *
+ * @param string $separator The separator that was used to begin this folded scalar (| or >)
+ * @param string $indicator The indicator that was used to begin this folded scalar (+ or -)
+ * @param integer $indentation The indentation that was used to begin this folded scalar
+ *
+ * @return string The text value
+ */
+ protected function parseFoldedScalar($separator, $indicator = '', $indentation = 0)
+ {
+ $separator = '|' == $separator ? "\n" : ' ';
+ $text = '';
+
+ $notEOF = $this->moveToNextLine();
+
+ while ($notEOF && $this->isCurrentLineBlank())
+ {
+ $text .= "\n";
+
+ $notEOF = $this->moveToNextLine();
+ }
+
+ if (!$notEOF)
+ {
+ return '';
+ }
+
+ if (!preg_match('#^(?P'.($indentation ? str_repeat(' ', $indentation) : ' +').')(?P.*)$#u', $this->currentLine, $matches))
+ {
+ $this->moveToPreviousLine();
+
+ return '';
+ }
+
+ $textIndent = $matches['indent'];
+ $previousIndent = 0;
+
+ $text .= $matches['text'].$separator;
+ while ($this->currentLineNb + 1 < count($this->lines))
+ {
+ $this->moveToNextLine();
+
+ if (preg_match('#^(?P {'.strlen($textIndent).',})(?P.+)$#u', $this->currentLine, $matches))
+ {
+ if (' ' == $separator && $previousIndent != $matches['indent'])
+ {
+ $text = substr($text, 0, -1)."\n";
+ }
+ $previousIndent = $matches['indent'];
+
+ $text .= str_repeat(' ', $diff = strlen($matches['indent']) - strlen($textIndent)).$matches['text'].($diff ? "\n" : $separator);
+ }
+ else if (preg_match('#^(?P *)$#', $this->currentLine, $matches))
+ {
+ $text .= preg_replace('#^ {1,'.strlen($textIndent).'}#', '', $matches['text'])."\n";
+ }
+ else
+ {
+ $this->moveToPreviousLine();
+
+ break;
+ }
+ }
+
+ if (' ' == $separator)
+ {
+ // replace last separator by a newline
+ $text = preg_replace('/ (\n*)$/', "\n$1", $text);
+ }
+
+ switch ($indicator)
+ {
+ case '':
+ $text = preg_replace('#\n+$#s', "\n", $text);
+ break;
+ case '+':
+ break;
+ case '-':
+ $text = preg_replace('#\n+$#s', '', $text);
+ break;
+ }
+
+ return $text;
+ }
+
+ /**
+ * Returns true if the next line is indented.
+ *
+ * @return Boolean Returns true if the next line is indented, false otherwise
+ */
+ protected function isNextLineIndented()
+ {
+ $currentIndentation = $this->getCurrentLineIndentation();
+ $notEOF = $this->moveToNextLine();
+
+ while ($notEOF && $this->isCurrentLineEmpty())
+ {
+ $notEOF = $this->moveToNextLine();
+ }
+
+ if (false === $notEOF)
+ {
+ return false;
+ }
+
+ $ret = false;
+ if ($this->getCurrentLineIndentation() <= $currentIndentation)
+ {
+ $ret = true;
+ }
+
+ $this->moveToPreviousLine();
+
+ return $ret;
+ }
+
+ /**
+ * Returns true if the current line is blank or if it is a comment line.
+ *
+ * @return Boolean Returns true if the current line is empty or if it is a comment line, false otherwise
+ */
+ protected function isCurrentLineEmpty()
+ {
+ return $this->isCurrentLineBlank() || $this->isCurrentLineComment();
+ }
+
+ /**
+ * Returns true if the current line is blank.
+ *
+ * @return Boolean Returns true if the current line is blank, false otherwise
+ */
+ protected function isCurrentLineBlank()
+ {
+ return '' == trim($this->currentLine, ' ');
+ }
+
+ /**
+ * Returns true if the current line is a comment line.
+ *
+ * @return Boolean Returns true if the current line is a comment line, false otherwise
+ */
+ protected function isCurrentLineComment()
+ {
+ //checking explicitly the first char of the trim is faster than loops or strpos
+ $ltrimmedLine = ltrim($this->currentLine, ' ');
+ return $ltrimmedLine[0] === '#';
+ }
+
+ /**
+ * Cleanups a YAML string to be parsed.
+ *
+ * @param string $value The input YAML string
+ *
+ * @return string A cleaned up YAML string
+ */
+ protected function cleanup($value)
+ {
+ $value = str_replace(array("\r\n", "\r"), "\n", $value);
+
+ if (!preg_match("#\n$#", $value))
+ {
+ $value .= "\n";
+ }
+
+ // strip YAML header
+ $count = 0;
+ $value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#su', '', $value, -1, $count);
+ $this->offset += $count;
+
+ // remove leading comments
+ $trimmedValue = preg_replace('#^(\#.*?\n)+#s', '', $value, -1, $count);
+ if ($count == 1)
+ {
+ // items have been removed, update the offset
+ $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
+ $value = $trimmedValue;
+ }
+
+ // remove start of the document marker (---)
+ $trimmedValue = preg_replace('#^\-\-\-.*?\n#s', '', $value, -1, $count);
+ if ($count == 1)
+ {
+ // items have been removed, update the offset
+ $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
+ $value = $trimmedValue;
+
+ // remove end of the document marker (...)
+ $value = preg_replace('#\.\.\.\s*$#s', '', $value);
+ }
+
+ return $value;
+ }
+}
diff --git a/lib/task/BasicTask.class.php b/lib/task/BasicTask.class.php
new file mode 100644
index 0000000..270f726
--- /dev/null
+++ b/lib/task/BasicTask.class.php
@@ -0,0 +1,19 @@
+value = $value;
+ $this->cmsInstallerApp = $app;
+ }
+
+ protected function getValue() {
+ return $this->value;
+ }
+
+ protected function getCmsInstallerApp() {
+ return $this->cmsInstallerApp;
+ }
+}
diff --git a/lib/task/InformationTask.class.php b/lib/task/InformationTask.class.php
new file mode 100644
index 0000000..06bc1a3
--- /dev/null
+++ b/lib/task/InformationTask.class.php
@@ -0,0 +1,52 @@
+getCmsInstallerApp()->getOpts()->getRules() as $opt => $rule) {
+ if(!mySfYaml::get('app_configuration_'.$opt.'_hide')) {
+ if(($this->getValue() !== true && $this->getValue() == $opt) || $this->getValue() === true) {
+ $name = '--'.$opt.(isset($rule['alias'][1]) ? ',-'.$rule['alias'][1] : '');
+ $param = mySfYaml::get('app_configuration_'.$opt.'_param');
+ $description = mySfYaml::get('app_configuration_'.$opt.'_description');
+
+ Cli::printNotice($opt, '');
+ Cli::printInfo(' Command', $name);
+ if(!empty($param)) {
+ Cli::printInfo(' Param', $param);
+ }
+ Cli::printInfo(' Description', $description);
+ Cli::printBlankLine();
+ }
+ }
+ }
+ }
+
+ public function executeVersion() {
+ Cli::printNotice('Cms Installer', '');
+ Cli::printBlankLine();
+ Cli::printInfo('Version', mySfYaml::get('app_version'));
+ Cli::printInfo('Author', mySfYaml::get('app_author'));
+ Cli::printInfo('Contact', mySfYaml::get('app_contact'));
+ }
+
+ public function executeList() {
+ $cmss = mySfYaml::get('ressources_cms');
+
+ if(is_array($cmss)) {
+ foreach($cmss as $cms_name => $cms_info) {
+ if(($this->getValue() !== true && $this->getValue() == $cms_name) || $this->getValue() === true) {
+ Cli::printNotice($cms_name, '');
+ if(isset($cms_info['versions']) && is_array($cms_info['versions'])) {
+ foreach($cms_info['versions'] as $version => $info) {
+ $description = !empty($info['description']) ? $info['description'] : 'No description.';
+ Cli::printInfo(' '.$version, $description);
+ Cli::printInfo(' ', $info['url']);
+ Cli::printInfo(' ', $this->getCmsInstallerApp()->getArgv(0).' --install "'.$cms_name.'" --version "'.$version.'"');
+ Cli::printBlankLine();
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/task/InstallationTask.class.php b/lib/task/InstallationTask.class.php
new file mode 100644
index 0000000..786658b
--- /dev/null
+++ b/lib/task/InstallationTask.class.php
@@ -0,0 +1,137 @@
+arg_cms = $this->getValue();
+ $this->arg_version = ($v = $this->getCmsInstallerApp()->get('version')) ? $v : 'default';
+
+ $this->cms_configuration = mySfYaml::get('ressources_cms_'.$this->arg_cms);
+ $this->cms_version = mySfYaml::get('ressources_cms_'.$this->arg_cms.'_versions_'.$this->arg_version);
+ $this->cms_version_url = mySfYaml::get('ressources_cms_'.$this->arg_cms.'_versions_'.$this->arg_version.'_url');
+ $this->cms_callback = mySfYaml::get('ressources_cms_'.$this->arg_cms.'_versions_'.$this->arg_version.'_callback');
+ $this->destination = ($dir = $this->getCmsInstallerApp()->get('to')) ? $dir : '.';
+
+ try {
+ if($this->getCmsInstallerApp()->get('create-dir') && !is_dir($this->destination)) {
+ if(!@mkdir($this->destination)) {
+ throw new CmsInstallerException('The directory "'.$this->destination.'" can not be created');
+ }
+ }
+
+ if(!$this->cms_configuration) {
+ throw new CmsInstallerException($this->arg_cms.' is not a valid cms. Show cms list by using --list argument.');
+ }
+
+ if(!$this->cms_version) {
+ throw new CmsInstallerException($this->arg_version.' is not a valid cms version for '.$this->arg_cms.'. Show cms list by using --list argument.');
+ }
+
+ if(!$this->cms_version_url) {
+ throw new CmsInstallerException($this->arg_cms.' (version '.$this->arg_version.') has not valid configuration (url not found). Show cms list by using --list argument.');
+ }
+
+ Cli::printNotice('CMS: ', $this->arg_cms);
+ Cli::printNotice('Version: ', $this->arg_version);
+ Cli::printNotice('Download from: ', $this->cms_version_url);
+ Cli::printBlankLine();
+
+ $this->tempName = $this->getTempName();
+ $this->download();
+ echo PHP_EOL;
+ $this->unpack();
+ $this->clearFile();
+
+ if($this->cms_callback) {
+ $callback = $this->cms_callback.'InstallationTask';
+
+ if(!class_exists($callback)) {
+ throw new CmsInstallerException($this->arg_cms.' (version '.$this->arg_version.') has not valid configuration (callback "'.$callback.'" class not found).');
+ }
+ Cli::printBlankLine();
+ $callback = new $callback($this->destination, $this->arg_version);
+ $callback->execute();
+ }
+ }
+ catch(CmsInstallerException $e) {
+ Cli::printError('Error', $e->getMessage());
+ exit(1);
+ }
+
+ exit(0);
+ }
+
+ public static function progressBar($curl, $fd) {
+ if($curl) {
+ $purcent = round(100*$fd/$curl, 2);
+ $progress = str_pad($purcent.'%', 5, ' ', STR_PAD_RIGHT);
+ echo "\r";
+ Cli::printInfoNoEOL('Progress', $progress);
+ }
+ }
+
+ public function download() {
+ Cli::printInfo('Download started', 'Please wait...');
+
+ $fileopen = fopen($this->tempName, 'w');
+ $curl = curl_init($this->cms_version_url);
+
+ curl_setopt($curl, CURLOPT_FILE, $fileopen);
+ curl_setopt($curl, CURLOPT_NOPROGRESS, false);
+ curl_setopt($curl, CURLOPT_PROGRESSFUNCTION, 'InstallationTask::progressBar');
+ curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
+
+ if(curl_errno($curl)) {
+ fclose($fileopen);
+ $this->clearFile();
+ throw new CmsInstallerException('Download has failed.');
+ }
+
+ curl_exec($curl);
+ curl_close($curl);
+ fclose($fileopen);
+ }
+
+ public function unpack() {
+ Cli::printInfo('Unpack', 'Please wait...');
+
+ $finfo = new finfo(FILEINFO_MIME);
+ $ftype = explode(';', $finfo->file($this->tempName));
+ $type = $ftype[0];
+
+ if(!is_dir($this->destination)) {
+ throw new CmsInstallerException('Extract destination does not exist (extract to '.$this->destination.').');
+ }
+ else {
+ if(!is_writable($this->destination)) {
+ throw new CmsInstallerException('Extract destination is not writable (extract to '.$this->destination.').');
+ }
+ }
+
+ if(in_array($type, array('application/zip', 'application/x-zip', 'application/x-zip-compressed'))) {
+ $zip = new ZipArchive();
+ if(!$zip->open($this->tempName)) {
+ throw new CmsInstallerException('ZipArchive can not open package.');
+ }
+
+ $zip->extractTo($this->destination);
+ $zip->close();
+ Cli::printInfo('Extact to', $this->destination);
+ }
+ elseif(in_array($type, array('application/x-tar', 'application/x-gtar', ))) {
+ throw new CmsInstallerException('Sorry but tar files are not supported yet...');
+ }
+ else {
+ throw new CmsInstallerException('The archive is either in unknown format or damaged.');
+ }
+ }
+
+ public function getTempName() {
+ return $this->arg_cms.'-'.mt_rand();
+ }
+
+ public function clearFile() {
+ if(is_file($this->tempName)) {
+ unlink($this->tempName);
+ }
+ }
+}
diff --git a/lib/task/installationTask/BasicInstallationTask.class.php b/lib/task/installationTask/BasicInstallationTask.class.php
new file mode 100644
index 0000000..cb5aa47
--- /dev/null
+++ b/lib/task/installationTask/BasicInstallationTask.class.php
@@ -0,0 +1,13 @@
+destination = getcwd().DIRECTORY_SEPARATOR.$destination;
+ $this->version = $version;
+ }
+
+ abstract public function execute();
+}
diff --git a/lib/task/installationTask/PluxmlInstallationTask.class.php b/lib/task/installationTask/PluxmlInstallationTask.class.php
new file mode 100644
index 0000000..4b3d24b
--- /dev/null
+++ b/lib/task/installationTask/PluxmlInstallationTask.class.php
@@ -0,0 +1,185 @@
+ Cli::prompt('Your name:', true),
+ 'login' => Cli::prompt('Username:', true),
+ 'pwd' => Cli::prompt('Password:', true, StringUtil::genPassword()),
+ );
+
+
+ define('PLX_ROOT', $this->destination.DIRECTORY_SEPARATOR.'pluxml'.DIRECTORY_SEPARATOR);
+ define('PLX_CORE', PLX_ROOT.'core'.DIRECTORY_SEPARATOR);
+ define('PLX_CONF', PLX_ROOT.'data'.DIRECTORY_SEPARATOR.'configuration'.DIRECTORY_SEPARATOR.'parametres.xml');
+
+ require_once PLX_ROOT.DIRECTORY_SEPARATOR.'config.php';
+
+ $lang = DEFAULT_LANG;
+
+ loadLang(PLX_CORE.'lang/'.$lang.DIRECTORY_SEPARATOR.'install.php');
+ loadLang(PLX_CORE.'lang/'.$lang.DIRECTORY_SEPARATOR.'core.php');
+
+ require_once PLX_CORE.'lib'.DIRECTORY_SEPARATOR.'class.plx.glob.php';
+ require_once PLX_CORE.'lib'.DIRECTORY_SEPARATOR.'class.plx.utils.php';
+
+ if(!is_dir($dir=$this->destination.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'images')) {
+ @mkdir($dir, 0755);
+ }
+ if(!is_dir($dir=$this->destination.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'documents')) {
+ @mkdir($dir, 0755);
+ }
+
+ $version = trim(file_get_contents(PLX_ROOT.'version'));
+
+ $config = array('title'=>'PluXml',
+ 'description'=>plxUtils::strRevCheck(L_SITE_DESCRIPTION),
+ 'meta_description'=>'',
+ 'meta_keywords'=>'',
+ 'racine'=>$racine,
+ 'delta'=>'+00:00',
+ 'allow_com'=>1,
+ 'mod_com'=>0,
+ 'mod_art'=>0,
+ 'capcha'=>1,
+ 'style'=>'defaut',
+ 'clef'=>plxUtils::charAleatoire(15),
+ 'bypage'=>5,
+ 'bypage_archives'=>5,
+ 'bypage_admin'=>10,
+ 'bypage_admin_coms'=>10,
+ 'bypage_feed'=>8,
+ 'tri'=>'desc',
+ 'tri_coms'=>'asc',
+ 'images_l'=>800,
+ 'images_h'=>600,
+ 'miniatures_l'=>200,
+ 'miniatures_h'=>100,
+ 'images'=>'data/images/',
+ 'documents'=>'data/documents/',
+ 'racine_articles'=>'data/articles/',
+ 'racine_commentaires'=>'data/commentaires/',
+ 'racine_statiques'=>'data/statiques/',
+ 'racine_themes'=>'themes/',
+ 'racine_plugins'=>'plugins/',
+ 'statiques'=>'data/configuration/statiques.xml',
+ 'categories'=>'data/configuration/categories.xml',
+ 'users'=>'data/configuration/users.xml',
+ 'tags'=>'data/configuration/tags.xml',
+ 'plugins'=>'data/configuration/plugins.xml',
+ 'homestatic'=>'',
+ 'urlrewriting'=>0,
+ 'gzip'=>0,
+ 'feed_chapo'=>0,
+ 'feed_footer'=>'',
+ 'version'=>$version,
+ 'default_lang'=>$lang,
+ 'userfolders'=>0,
+ );
+
+ $this->install($content, $config);
+
+ Cli::printNotice('Finished', 'You can now use the Pluxml.');
+ }
+
+ private function install($content, $config) {
+
+# Création du fichier de configuration
+ $xml = ''."\n";
+ $xml .= ''."\n";
+ foreach($config as $k=>$v) {
+ if(is_numeric($v))
+ $xml .= "\t".$v." \n";
+ else
+ $xml .= "\t \n";
+ }
+ $xml .= ' ';
+ plxUtils::write($xml,PLX_CONF);
+
+# Création du fichier des utilisateurs
+ $salt = plxUtils::charAleatoire(10);
+ $xml = ''."\n";
+ $xml .= "\n";
+ $xml .= "\t".''."\n";
+ $xml .= "\t\t".' '."\n";
+ $xml .= "\t\t".' '."\n";
+ $xml .= "\t\t".' '."\n";
+ $xml .= "\t\t".' '."\n";
+ $xml .= "\t\t".' '."\n";
+ $xml .= "\t\t".' '."\n";
+ $xml .= "\t\t".' '."\n";
+ $xml .= "\t \n";
+ $xml .= " ";
+ plxUtils::write($xml,PLX_ROOT.$config['users']);
+
+# Création du fichier des categories
+ $xml = ''."\n";
+ $xml .= ''."\n";
+ $xml .= "\t".' '."\n";
+ $xml .= ' ';
+ plxUtils::write($xml,PLX_ROOT.$config['categories']);
+
+# Création du fichier des pages statiques
+ $xml = ''."\n";
+ $xml .= ''."\n";
+ $xml .= "\t".' '."\n";
+ $xml .= ' ';
+ plxUtils::write($xml,PLX_ROOT.$config['statiques']);
+ $cs = '
';
+ plxUtils::write($cs,PLX_ROOT.$config['racine_statiques'].'001.'.L_DEFAULT_STATIC_URL.'.php');
+
+# Création du premier article
+ $xml = ''."\n";
+ $xml .= '
+
+ 1
+
+
+
+
+
+ '.plxUtils::strRevCheck(L_DEFAULT_ARTICLE_CONTENT).'
]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ';
+ plxUtils::write($xml,PLX_ROOT.$config['racine_articles'].'0001.001.001.'.@date('YmdHi').'.'.L_DEFAULT_ARTICLE_URL.'.xml');
+
+# Création du fichier des tags servant de cache
+ $xml = ''."\n";
+ $xml .= ''."\n";
+ $xml .= "\t".' '."\n";
+ $xml .= ' ';
+ plxUtils::write($xml,PLX_ROOT.$config['tags']);
+
+# Création du fichier des plugins
+ $xml = ''."\n";
+ $xml .= ''."\n";
+ $xml .= ' ';
+ plxUtils::write($xml,PLX_ROOT.$config['plugins']);
+
+# Création du premier commentaire
+ $xml = ''."\n";
+ $xml .= '
+
+ normal
+ 127.0.0.1
+
+
+
+ ';
+ plxUtils::write($xml,PLX_ROOT.$config['racine_commentaires'].'0001.'.@date('U').'-1.xml');
+ }
+}
diff --git a/lib/task/installationTask/WordpressInstallationTask.class.php b/lib/task/installationTask/WordpressInstallationTask.class.php
new file mode 100644
index 0000000..62e0d53
--- /dev/null
+++ b/lib/task/installationTask/WordpressInstallationTask.class.php
@@ -0,0 +1,467 @@
+db_name = null;
+ $this->db_username = 'root';
+ $this->db_password = '';
+ $this->db_hostname = 'localhost';
+
+ do {
+ $config_ok = true;
+
+ $this->db_name = Cli::prompt('Database name:', true, $this->db_name);
+ $this->db_username = Cli::prompt('Database username:', true, $this->db_username);
+ $this->db_password = Cli::prompt('Database password:', false, $this->db_password);
+ $this->db_hostname = Cli::prompt('Database hostname:', true, $this->db_hostname);
+ $this->db_charset = Cli::prompt('Database charset:', true, 'utf8');
+ $this->db_prefix = Cli::prompt('Database table prefix:', true, 'wp_');
+ Cli::printBlankLine();
+
+ $config_ok = true;
+
+ if(!@mysql_connect($this->db_hostname, $this->db_username, $this->db_password)) {
+ $config_ok = false;
+ Cli::printNotice('Database login has failed:', mysql_error());
+ }
+ if(!@mysql_select_db($this->db_name)) {
+ $config_ok = false;
+ Cli::printNotice('Select database has failed:', mysql_error());
+ }
+
+ if($config_ok) {
+ Cli::printBlankLine();
+ }
+ }
+ while(!$config_ok);
+
+ Cli::printNotice('Security configuration', '');
+ $this->auth_key = Cli::prompt('Auth key (unique):', true, StringUtil::genPassword());
+ $this->secure_auth_key = Cli::prompt('Secure auth key (unique):', true, StringUtil::genPassword());
+ $this->logged_in_key = Cli::prompt('Logged in key (unique):', true, StringUtil::genPassword());
+ $this->nonce_key = Cli::prompt('Nonce key (unique):', true, StringUtil::genPassword());
+ $this->secure_auth_salt = Cli::prompt('Secure auth salt (unique):', true, StringUtil::genPassword());
+ $this->auth_salt = Cli::prompt('Auth salt (unique):', true, StringUtil::genPassword());
+ $this->logged_in_salt = Cli::prompt('Logged in salt (unique):', true, StringUtil::genPassword());
+ $this->nonce_salt = Cli::prompt('Nonce in salt (unique):', true, StringUtil::genPassword());
+ Cli::printBlankLine();
+
+ Cli::printNotice('Wordpress configuration', '');
+ $this->site_url = Cli::prompt('Blog url (with http://)', true, 'http://localhost/wordpress/');
+ $this->wplang = Cli::prompt('Lang', true, 'fr_FR');
+ $this->wptitle = Cli::prompt('Blog title', true, 'My new blog');
+ Cli::printBlankLine();
+
+ Cli::printNotice('Admin user configuration', '');
+ $this->username = Cli::prompt('Admin username:', true, 'admin');
+ $this->password = Cli::prompt('Admin password:', true, StringUtil::genPassword());
+
+ $this->email = null;
+ do {
+ if($this->email !== null) {
+ Cli::printNotice(' > Please enter en valid email.', '');
+ }
+ $this->email = Cli::prompt('Admin email:', true);
+ }
+ while(!filter_var($this->email, FILTER_VALIDATE_EMAIL));
+
+ Cli::printBlankLine();
+
+ try {
+ $this->setDatabaseConfigurationFile();
+ $this->initDatabase();
+ }
+ catch(CmsInstallerException $e) {
+ Cli::printError('Error during configuration', $e->getMessage());
+ }
+ }
+
+ private function setDatabaseConfigurationFile() {
+ $configSample = $this->destination.DIRECTORY_SEPARATOR.'wordpress'.DIRECTORY_SEPARATOR.'wp-config-sample.php';
+ $configFile = $this->destination.DIRECTORY_SEPARATOR.'wordpress'.DIRECTORY_SEPARATOR.'wp-config.php';
+
+ if(!file_exists($configSample)) {
+ throw new CmsInstallerException('Database configuration sample file does not exist.');
+ }
+
+
+$config = <<db_name');
+define('DB_USER', '$this->db_username');
+define('DB_PASSWORD', '$this->db_password');
+define('DB_HOST', '$this->db_hostname');
+define('DB_CHARSET', '$this->db_charset');
+define('DB_COLLATE', '');
+define('AUTH_KEY', '$this->auth_key');
+define('SECURE_AUTH_KEY', '$this->secure_auth_key');
+define('LOGGED_IN_KEY', '$this->logged_in_key');
+define('NONCE_KEY', '$this->nonce_key');
+define('AUTH_SALT', '$this->auth_salt');
+define('SECURE_AUTH_SALT', '$this->secure_auth_salt');
+define('LOGGED_IN_SALT', '$this->logged_in_salt');
+define('NONCE_SALT', '$this->nonce_salt');
+\$table_prefix = '$this->db_prefix';
+define('WPLANG', '$this->wplang');
+define('WP_DEBUG', false);
+if ( !defined('ABSPATH') )
+ define('ABSPATH', dirname(__FILE__) . '/');
+require_once(ABSPATH . 'wp-settings.php');
+EOF;
+
+ if(!@file_put_contents($configFile, $config)) {
+ throw new CmsInstallerException('Error while creation database configuration file.');
+ }
+
+ Cli::printNotice('Database configuration file', 'done.');
+ }
+
+ private function initDatabase() {
+ $sql = array(
+"SET NAMES ".$this->db_charset,
+"CREATE TABLE IF NOT EXISTS `wp_commentmeta` (
+ `meta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+ `comment_id` bigint(20) unsigned NOT NULL DEFAULT '0',
+ `meta_key` varchar(255) DEFAULT NULL,
+ `meta_value` longtext,
+ PRIMARY KEY (`meta_id`),
+ KEY `comment_id` (`comment_id`),
+ KEY `meta_key` (`meta_key`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1",
+
+"CREATE TABLE IF NOT EXISTS `wp_comments` (
+ `comment_ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+ `comment_post_ID` bigint(20) unsigned NOT NULL DEFAULT '0',
+ `comment_author` tinytext NOT NULL,
+ `comment_author_email` varchar(100) NOT NULL DEFAULT '',
+ `comment_author_url` varchar(200) NOT NULL DEFAULT '',
+ `comment_author_IP` varchar(100) NOT NULL DEFAULT '',
+ `comment_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `comment_date_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `comment_content` text NOT NULL,
+ `comment_karma` int(11) NOT NULL DEFAULT '0',
+ `comment_approved` varchar(20) NOT NULL DEFAULT '1',
+ `comment_agent` varchar(255) NOT NULL DEFAULT '',
+ `comment_type` varchar(20) NOT NULL DEFAULT '',
+ `comment_parent` bigint(20) unsigned NOT NULL DEFAULT '0',
+ `user_id` bigint(20) unsigned NOT NULL DEFAULT '0',
+ PRIMARY KEY (`comment_ID`),
+ KEY `comment_approved` (`comment_approved`),
+ KEY `comment_post_ID` (`comment_post_ID`),
+ KEY `comment_approved_date_gmt` (`comment_approved`,`comment_date_gmt`),
+ KEY `comment_date_gmt` (`comment_date_gmt`),
+ KEY `comment_parent` (`comment_parent`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2",
+
+"INSERT INTO `wp_comments` (`comment_ID`, `comment_post_ID`, `comment_author`, `comment_author_email`, `comment_author_url`, `comment_author_IP`, `comment_date`, `comment_date_gmt`, `comment_content`, `comment_karma`, `comment_approved`, `comment_agent`, `comment_type`, `comment_parent`, `user_id`) VALUES
+(1, 1, 'Monsieur WordPress', '', 'http://wordpress.org/', '', '2012-04-09 03:30:58', '2012-04-09 03:30:58', 'Bonjour, ceci est un commentaire. Pour supprimer un commentaire, connectez-vous, et affichez les commentaires de cet article. Vous pourrez alors les modifier ou les supprimer.', 0, '1', '', '', 0, 0)",
+
+"CREATE TABLE IF NOT EXISTS `wp_links` (
+ `link_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+ `link_url` varchar(255) NOT NULL DEFAULT '',
+ `link_name` varchar(255) NOT NULL DEFAULT '',
+ `link_image` varchar(255) NOT NULL DEFAULT '',
+ `link_target` varchar(25) NOT NULL DEFAULT '',
+ `link_description` varchar(255) NOT NULL DEFAULT '',
+ `link_visible` varchar(20) NOT NULL DEFAULT 'Y',
+ `link_owner` bigint(20) unsigned NOT NULL DEFAULT '1',
+ `link_rating` int(11) NOT NULL DEFAULT '0',
+ `link_updated` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `link_rel` varchar(255) NOT NULL DEFAULT '',
+ `link_notes` mediumtext NOT NULL,
+ `link_rss` varchar(255) NOT NULL DEFAULT '',
+ PRIMARY KEY (`link_id`),
+ KEY `link_visible` (`link_visible`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=8",
+
+"INSERT INTO `wp_links` (`link_id`, `link_url`, `link_name`, `link_image`, `link_target`, `link_description`, `link_visible`, `link_owner`, `link_rating`, `link_updated`, `link_rel`, `link_notes`, `link_rss`) VALUES
+(1, 'http://codex.wordpress.org/', 'Documentation', '', '', '', 'Y', 1, 0, '0000-00-00 00:00:00', '', '', ''),
+(2, 'http://wordpress.org/news/', 'WordPress Blog', '', '', '', 'Y', 1, 0, '0000-00-00 00:00:00', '', '', 'http://wordpress.org/news/feed/'),
+(3, 'http://wordpress.org/extend/ideas/', 'Suggest Ideas', '', '', '', 'Y', 1, 0, '0000-00-00 00:00:00', '', '', ''),
+(4, 'http://wordpress.org/support/', 'Support Forum', '', '', '', 'Y', 1, 0, '0000-00-00 00:00:00', '', '', ''),
+(5, 'http://wordpress.org/extend/plugins/', 'Plugins', '', '', '', 'Y', 1, 0, '0000-00-00 00:00:00', '', '', ''),
+(6, 'http://wordpress.org/extend/themes/', 'Themes', '', '', '', 'Y', 1, 0, '0000-00-00 00:00:00', '', '', ''),
+(7, 'http://planet.wordpress.org/', 'WordPress Planet', '', '', '', 'Y', 1, 0, '0000-00-00 00:00:00', '', '', '')",
+
+"CREATE TABLE IF NOT EXISTS `wp_options` (
+ `option_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+ `blog_id` int(11) NOT NULL DEFAULT '0',
+ `option_name` varchar(64) NOT NULL DEFAULT '',
+ `option_value` longtext NOT NULL,
+ `autoload` varchar(20) NOT NULL DEFAULT 'yes',
+ PRIMARY KEY (`option_id`),
+ UNIQUE KEY `option_name` (`option_name`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=106",
+
+"INSERT INTO `wp_options` (`option_id`, `blog_id`, `option_name`, `option_value`, `autoload`) VALUES
+(1, 0, '_site_transient_timeout_theme_roots', '1333949458', 'yes'),
+(2, 0, '_site_transient_theme_roots', 'a:2:{s:12:\"twentyeleven\";s:7:\"/themes\";s:9:\"twentyten\";s:7:\"/themes\";}', 'yes'),
+(3, 0, 'siteurl', '".addslashes($this->site_url)."', 'yes'),
+(4, 0, 'blogname', '".addslashes($this->wptitle)."', 'yes'),
+(5, 0, 'blogdescription', 'Un site utilisant WordPress', 'yes'),
+(6, 0, 'users_can_register', '0', 'yes'),
+(7, 0, 'admin_email', '".$this->email."', 'yes'),
+(8, 0, 'start_of_week', '1', 'yes'),
+(9, 0, 'use_balanceTags', '0', 'yes'),
+(10, 0, 'use_smilies', '1', 'yes'),
+(11, 0, 'require_name_email', '1', 'yes'),
+(12, 0, 'comments_notify', '1', 'yes'),
+(13, 0, 'posts_per_rss', '10', 'yes'),
+(14, 0, 'rss_use_excerpt', '0', 'yes'),
+(15, 0, 'mailserver_url', 'mail.example.com', 'yes'),
+(16, 0, 'mailserver_login', 'login@example.com', 'yes'),
+(17, 0, 'mailserver_pass', 'password', 'yes'),
+(18, 0, 'mailserver_port', '110', 'yes'),
+(19, 0, 'default_category', '1', 'yes'),
+(20, 0, 'default_comment_status', 'open', 'yes'),
+(21, 0, 'default_ping_status', 'open', 'yes'),
+(22, 0, 'default_pingback_flag', '1', 'yes'),
+(23, 0, 'default_post_edit_rows', '20', 'yes'),
+(24, 0, 'posts_per_page', '10', 'yes'),
+(25, 0, 'date_format', 'j F Y', 'yes'),
+(26, 0, 'time_format', 'G \\h i \\m\\i\\n', 'yes'),
+(27, 0, 'links_updated_date_format', 'j F Y, G \\h i \\m\\i\\n', 'yes'),
+(28, 0, 'links_recently_updated_prepend', '', 'yes'),
+(29, 0, 'links_recently_updated_append', ' ', 'yes'),
+(30, 0, 'links_recently_updated_time', '120', 'yes'),
+(31, 0, 'comment_moderation', '0', 'yes'),
+(32, 0, 'moderation_notify', '1', 'yes'),
+(33, 0, 'permalink_structure', '', 'yes'),
+(34, 0, 'gzipcompression', '0', 'yes'),
+(35, 0, 'hack_file', '0', 'yes'),
+(36, 0, 'blog_charset', 'UTF-8', 'yes'),
+(37, 0, 'moderation_keys', '', 'no'),
+(38, 0, 'active_plugins', 'a:0:{}', 'yes'),
+(39, 0, 'home', '".addslashes($this->site_url)."', 'yes'),
+(40, 0, 'category_base', '', 'yes'),
+(41, 0, 'ping_sites', 'http://rpc.pingomatic.com/', 'yes'),
+(42, 0, 'advanced_edit', '0', 'yes'),
+(43, 0, 'comment_max_links', '2', 'yes'),
+(44, 0, 'gmt_offset', '0', 'yes'),
+(45, 0, 'default_email_category', '1', 'yes'),
+(46, 0, 'recently_edited', '', 'no'),
+(47, 0, 'template', 'twentyeleven', 'yes'),
+(48, 0, 'stylesheet', 'twentyeleven', 'yes'),
+(49, 0, 'comment_whitelist', '1', 'yes'),
+(50, 0, 'blacklist_keys', '', 'no'),
+(51, 0, 'comment_registration', '0', 'yes'),
+(52, 0, 'rss_language', 'en', 'yes'),
+(53, 0, 'html_type', 'text/html', 'yes'),
+(54, 0, 'use_trackback', '0', 'yes'),
+(55, 0, 'default_role', 'subscriber', 'yes'),
+(56, 0, 'db_version', '19470', 'yes'),
+(57, 0, 'uploads_use_yearmonth_folders', '1', 'yes'),
+(58, 0, 'upload_path', '', 'yes'),
+(59, 0, 'blog_public', '1', 'yes'),
+(60, 0, 'default_link_category', '2', 'yes'),
+(61, 0, 'show_on_front', 'posts', 'yes'),
+(62, 0, 'tag_base', '', 'yes'),
+(63, 0, 'show_avatars', '1', 'yes'),
+(64, 0, 'avatar_rating', 'G', 'yes'),
+(65, 0, 'upload_url_path', '', 'yes'),
+(66, 0, 'thumbnail_size_w', '150', 'yes'),
+(67, 0, 'thumbnail_size_h', '150', 'yes'),
+(68, 0, 'thumbnail_crop', '1', 'yes'),
+(69, 0, 'medium_size_w', '300', 'yes'),
+(70, 0, 'medium_size_h', '300', 'yes'),
+(71, 0, 'avatar_default', 'mystery', 'yes'),
+(72, 0, 'enable_app', '0', 'yes'),
+(73, 0, 'enable_xmlrpc', '0', 'yes'),
+(74, 0, 'large_size_w', '1024', 'yes'),
+(75, 0, 'large_size_h', '1024', 'yes'),
+(76, 0, 'image_default_link_type', 'file', 'yes'),
+(77, 0, 'image_default_size', '', 'yes'),
+(78, 0, 'image_default_align', '', 'yes'),
+(79, 0, 'close_comments_for_old_posts', '0', 'y/es'),
+(80, 0, 'close_comments_days_old', '14', 'yes'),
+(81, 0, 'thread_comments', '1', 'yes'),
+(82, 0, 'thread_comments_depth', '5', 'yes'),
+(83, 0, 'page_comments', '0', 'yes'),
+(84, 0, 'comments_per_page', '50', 'yes'),
+(85, 0, 'default_comments_page', 'newest', 'yes'),
+(86, 0, 'comment_order', 'asc', 'yes'),
+(87, 0, 'sticky_posts', 'a:0:{}', 'yes'),
+(88, 0, 'widget_categories', 'a:2:{i:2;a:4:{s:5:\"title\";s:0:\"\";s:5:\"count\";i:0;s:12:\"hierarchical\";i:0;s:8:\"dropdown\";i:0;}s:12:\"_multiwidget\";i:1;}', 'yes'),
+(89, 0, 'widget_text', 'a:0:{}', 'yes'),
+(90, 0, 'widget_rss', 'a:0:{}', 'yes'),
+(91, 0, 'timezone_string', '', 'yes'),
+(92, 0, 'embed_autourls', '1', 'yes'),
+(93, 0, 'embed_size_w', '', 'yes'),
+(94, 0, 'embed_size_h', '600', 'yes'),
+(95, 0, 'page_for_posts', '0', 'yes'),
+(96, 0, 'page_on_front', '0', 'yes'),
+(97, 0, 'default_post_format', '0', 'yes'),
+(98, 0, 'initial_db_version', '19470', 'yes'),
+(99, 0, 'wp_user_roles', 'a:5:{s:13:\"administrator\";a:2:{s:4:\"name\";s:13:\"Administrator\";s:12:\"capabilities\";a:62:{s:13:\"switch_themes\";b:1;s:11:\"edit_themes\";b:1;s:16:\"activate_plugins\";b:1;s:12:\"edit_plugins\";b:1;s:10:\"edit_users\";b:1;s:10:\"edit_files\";b:1;s:14:\"manage_options\";b:1;s:17:\"moderate_comments\";b:1;s:17:\"manage_categories\";b:1;s:12:\"manage_links\";b:1;s:12:\"upload_files\";b:1;s:6:\"import\";b:1;s:15:\"unfiltered_html\";b:1;s:10:\"edit_posts\";b:1;s:17:\"edit_others_posts\";b:1;s:20:\"edit_published_posts\";b:1;s:13:\"publish_posts\";b:1;s:10:\"edit_pages\";b:1;s:4:\"read\";b:1;s:8:\"level_10\";b:1;s:7:\"level_9\";b:1;s:7:\"level_8\";b:1;s:7:\"level_7\";b:1;s:7:\"level_6\";b:1;s:7:\"level_5\";b:1;s:7:\"level_4\";b:1;s:7:\"level_3\";b:1;s:7:\"level_2\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:17:\"edit_others_pages\";b:1;s:20:\"edit_published_pages\";b:1;s:13:\"publish_pages\";b:1;s:12:\"delete_pages\";b:1;s:19:\"delete_others_pages\";b:1;s:22:\"delete_published_pages\";b:1;s:12:\"delete_posts\";b:1;s:19:\"delete_others_posts\";b:1;s:22:\"delete_published_posts\";b:1;s:20:\"delete_private_posts\";b:1;s:18:\"edit_private_posts\";b:1;s:18:\"read_private_posts\";b:1;s:20:\"delete_private_pages\";b:1;s:18:\"edit_private_pages\";b:1;s:18:\"read_private_pages\";b:1;s:12:\"delete_users\";b:1;s:12:\"create_users\";b:1;s:17:\"unfiltered_upload\";b:1;s:14:\"edit_dashboard\";b:1;s:14:\"update_plugins\";b:1;s:14:\"delete_plugins\";b:1;s:15:\"install_plugins\";b:1;s:13:\"update_themes\";b:1;s:14:\"install_themes\";b:1;s:11:\"update_core\";b:1;s:10:\"list_users\";b:1;s:12:\"remove_users\";b:1;s:9:\"add_users\";b:1;s:13:\"promote_users\";b:1;s:18:\"edit_theme_options\";b:1;s:13:\"delete_themes\";b:1;s:6:\"export\";b:1;}}s:6:\"editor\";a:2:{s:4:\"name\";s:6:\"Editor\";s:12:\"capabilities\";a:34:{s:17:\"moderate_comments\";b:1;s:17:\"manage_categories\";b:1;s:12:\"manage_links\";b:1;s:12:\"upload_files\";b:1;s:15:\"unfiltered_html\";b:1;s:10:\"edit_posts\";b:1;s:17:\"edit_others_posts\";b:1;s:20:\"edit_published_posts\";b:1;s:13:\"publish_posts\";b:1;s:10:\"edit_pages\";b:1;s:4:\"read\";b:1;s:7:\"level_7\";b:1;s:7:\"level_6\";b:1;s:7:\"level_5\";b:1;s:7:\"level_4\";b:1;s:7:\"level_3\";b:1;s:7:\"level_2\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:17:\"edit_others_pages\";b:1;s:20:\"edit_published_pages\";b:1;s:13:\"publish_pages\";b:1;s:12:\"delete_pages\";b:1;s:19:\"delete_others_pages\";b:1;s:22:\"delete_published_pages\";b:1;s:12:\"delete_posts\";b:1;s:19:\"delete_others_posts\";b:1;s:22:\"delete_published_posts\";b:1;s:20:\"delete_private_posts\";b:1;s:18:\"edit_private_posts\";b:1;s:18:\"read_private_posts\";b:1;s:20:\"delete_private_pages\";b:1;s:18:\"edit_private_pages\";b:1;s:18:\"read_private_pages\";b:1;}}s:6:\"author\";a:2:{s:4:\"name\";s:6:\"Author\";s:12:\"capabilities\";a:10:{s:12:\"upload_files\";b:1;s:10:\"edit_posts\";b:1;s:20:\"edit_published_posts\";b:1;s:13:\"publish_posts\";b:1;s:4:\"read\";b:1;s:7:\"level_2\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:12:\"delete_posts\";b:1;s:22:\"delete_published_posts\";b:1;}}s:11:\"contributor\";a:2:{s:4:\"name\";s:11:\"Contributor\";s:12:\"capabilities\";a:5:{s:10:\"edit_posts\";b:1;s:4:\"read\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:12:\"delete_posts\";b:1;}}s:10:\"subscriber\";a:2:{s:4:\"name\";s:10:\"Subscriber\";s:12:\"capabilities\";a:2:{s:4:\"read\";b:1;s:7:\"level_0\";b:1;}}}', 'yes'),
+(100, 0, 'widget_search', 'a:2:{i:2;a:1:{s:5:\"title\";s:0:\"\";}s:12:\"_multiwidget\";i:1;}', 'yes'),
+(101, 0, 'widget_recent-posts', 'a:2:{i:2;a:2:{s:5:\"title\";s:0:\"\";s:6:\"number\";i:5;}s:12:\"_multiwidget\";i:1;}', 'yes'),
+(102, 0, 'widget_recent-comments', 'a:2:{i:2;a:2:{s:5:\"title\";s:0:\"\";s:6:\"number\";i:5;}s:12:\"_multiwidget\";i:1;}', 'yes'),
+(103, 0, 'widget_archives', 'a:2:{i:2;a:3:{s:5:\"title\";s:0:\"\";s:5:\"count\";i:0;s:8:\"dropdown\";i:0;}s:12:\"_multiwidget\";i:1;}', 'yes'),
+(104, 0, 'widget_meta', 'a:2:{i:2;a:1:{s:5:\"title\";s:0:\"\";}s:12:\"_multiwidget\";i:1;}', 'yes'),
+(105, 0, 'sidebars_widgets', 'a:7:{s:19:\"wp_inactive_widgets\";a:0:{}s:9:\"sidebar-1\";a:6:{i:0;s:8:\"search-2\";i:1;s:14:\"recent-posts-2\";i:2;s:17:\"recent-comments-2\";i:3;s:10:\"archives-2\";i:4;s:12:\"categories-2\";i:5;s:6:\"meta-2\";}s:9:\"sidebar-2\";a:0:{}s:9:\"sidebar-3\";a:0:{}s:9:\"sidebar-4\";a:0:{}s:9:\"sidebar-5\";a:0:{}s:13:\"array_version\";i:3;}', 'yes')",
+
+"CREATE TABLE IF NOT EXISTS `wp_postmeta` (
+ `meta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+ `post_id` bigint(20) unsigned NOT NULL DEFAULT '0',
+ `meta_key` varchar(255) DEFAULT NULL,
+ `meta_value` longtext,
+ PRIMARY KEY (`meta_id`),
+ KEY `post_id` (`post_id`),
+ KEY `meta_key` (`meta_key`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2",
+
+"INSERT INTO `wp_postmeta` (`meta_id`, `post_id`, `meta_key`, `meta_value`) VALUES
+(1, 2, '_wp_page_template', 'default')",
+
+"CREATE TABLE IF NOT EXISTS `wp_posts` (
+ `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+ `post_author` bigint(20) unsigned NOT NULL DEFAULT '0',
+ `post_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `post_date_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `post_content` longtext NOT NULL,
+ `post_title` text NOT NULL,
+ `post_excerpt` text NOT NULL,
+ `post_status` varchar(20) NOT NULL DEFAULT 'publish',
+ `comment_status` varchar(20) NOT NULL DEFAULT 'open',
+ `ping_status` varchar(20) NOT NULL DEFAULT 'open',
+ `post_password` varchar(20) NOT NULL DEFAULT '',
+ `post_name` varchar(200) NOT NULL DEFAULT '',
+ `to_ping` text NOT NULL,
+ `pinged` text NOT NULL,
+ `post_modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `post_modified_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `post_content_filtered` text NOT NULL,
+ `post_parent` bigint(20) unsigned NOT NULL DEFAULT '0',
+ `guid` varchar(255) NOT NULL DEFAULT '',
+ `menu_order` int(11) NOT NULL DEFAULT '0',
+ `post_type` varchar(20) NOT NULL DEFAULT 'post',
+ `post_mime_type` varchar(100) NOT NULL DEFAULT '',
+ `comment_count` bigint(20) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`),
+ KEY `post_name` (`post_name`),
+ KEY `type_status_date` (`post_type`,`post_status`,`post_date`,`ID`),
+ KEY `post_parent` (`post_parent`),
+ KEY `post_author` (`post_author`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3",
+
+"INSERT INTO `wp_posts` (`ID`, `post_author`, `post_date`, `post_date_gmt`, `post_content`, `post_title`, `post_excerpt`, `post_status`, `comment_status`, `ping_status`, `post_password`, `post_name`, `to_ping`, `pinged`, `post_modified`, `post_modified_gmt`, `post_content_filtered`, `post_parent`, `guid`, `menu_order`, `post_type`, `post_mime_type`, `comment_count`) VALUES
+(1, 1, '2012-04-09 03:30:58', '2012-04-09 03:30:58', 'Bienvenue dans WordPress. Ceci est votre premier article. Modifiez-le ou supprimez-le, puis lancez-vous !', 'Bonjour tout le monde !', '', 'publish', 'open', 'open', '', 'bonjour-tout-le-monde', '', '', '2012-04-09 03:30:58', '2012-04-09 03:30:58', '', 0, '".addslashes($this->site_url)."/?p=1', 0, 'post', '', 1),
+(2, 1, '2012-04-09 03:30:58', '2012-04-09 03:30:58', 'Voici un exemple de page. Elle est différente d''un article de blog, en cela qu''elle restera à la même place, et s''affichera dans le menu de navigation de votre site (en fonction de votre thème). La plupart des gens commencent par écrire une page « À Propos » qui les présente aux visiteurs potentiels du site. Vous pourriez y écrire quelque chose de ce tenant :\n\nBonjour ! Je suis un mécanicien qui aspire à devenir un acteur, et ceci est mon blog. J''habite à Bordeaux, j''ai un super chien baptisé Russell, et j''aime la vodka-ananas (ainsi que perdre mon temps à regarder la pluie tomber). \n\n...ou bien quelque chose comme ça :\n\nLa société 123 Machin Truc a été créée en 1971, et n''a cessé de proposer au public des machins-trucs de qualité depuis cette année. Située à Saint-Remy-en-Bouzemont-Saint-Genest-et-Isson, 123 Machin Truc emploie 2 000 personnes, et fabrique toutes sortes de bidules super pour la communauté bouzemontoise. \n\nEtant donné que vous êtes un nouvel utilisateur de WordPress, vous devriez vous rendre sur votre site_url)."/wp-admin/\">tableau de bord pour effacer la présente page, et créer de nouvelles pages avec votre propre contenu. Amusez-vous bien !', 'Page d’exemple', '', 'publish', 'open', 'open', '', 'page-d-exemple', '', '', '2012-04-09 03:30:58', '2012-04-09 03:30:58', '', 0, 'http://".addslashes($this->site_url)."/?page_id=2', 0, 'page', '', 0)",
+
+"CREATE TABLE IF NOT EXISTS `wp_terms` (
+ `term_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+ `name` varchar(200) NOT NULL DEFAULT '',
+ `slug` varchar(200) NOT NULL DEFAULT '',
+ `term_group` bigint(10) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`term_id`),
+ UNIQUE KEY `slug` (`slug`),
+ KEY `name` (`name`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3",
+
+"INSERT INTO `wp_terms` (`term_id`, `name`, `slug`, `term_group`) VALUES
+(1, 'Non classé', 'non-classe', 0),
+(2, 'Liens', 'liens', 0)",
+
+"CREATE TABLE IF NOT EXISTS `wp_term_relationships` (
+ `object_id` bigint(20) unsigned NOT NULL DEFAULT '0',
+ `term_taxonomy_id` bigint(20) unsigned NOT NULL DEFAULT '0',
+ `term_order` int(11) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`object_id`,`term_taxonomy_id`),
+ KEY `term_taxonomy_id` (`term_taxonomy_id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8",
+
+"INSERT INTO `wp_term_relationships` (`object_id`, `term_taxonomy_id`, `term_order`) VALUES
+(1, 2, 0),
+(2, 2, 0),
+(3, 2, 0),
+(4, 2, 0),
+(5, 2, 0),
+(6, 2, 0),
+(7, 2, 0),
+(1, 1, 0)",
+
+"CREATE TABLE IF NOT EXISTS `wp_term_taxonomy` (
+ `term_taxonomy_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+ `term_id` bigint(20) unsigned NOT NULL DEFAULT '0',
+ `taxonomy` varchar(32) NOT NULL DEFAULT '',
+ `description` longtext NOT NULL,
+ `parent` bigint(20) unsigned NOT NULL DEFAULT '0',
+ `count` bigint(20) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`term_taxonomy_id`),
+ UNIQUE KEY `term_id_taxonomy` (`term_id`,`taxonomy`),
+ KEY `taxonomy` (`taxonomy`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3",
+
+"INSERT INTO `wp_term_taxonomy` (`term_taxonomy_id`, `term_id`, `taxonomy`, `description`, `parent`, `count`) VALUES
+(1, 1, 'category', '', 0, 1),
+(2, 2, 'link_category', '', 0, 7)",
+
+"CREATE TABLE IF NOT EXISTS `wp_usermeta` (
+ `umeta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+ `user_id` bigint(20) unsigned NOT NULL DEFAULT '0',
+ `meta_key` varchar(255) DEFAULT NULL,
+ `meta_value` longtext,
+ PRIMARY KEY (`umeta_id`),
+ KEY `user_id` (`user_id`),
+ KEY `meta_key` (`meta_key`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=14",
+
+"INSERT INTO `wp_usermeta` (`umeta_id`, `user_id`, `meta_key`, `meta_value`) VALUES
+(1, 1, 'first_name', ''),
+(2, 1, 'last_name', ''),
+(3, 1, 'nickname', 'admin'),
+(4, 1, 'description', ''),
+(5, 1, 'rich_editing', 'true'),
+(6, 1, 'comment_shortcuts', 'false'),
+(7, 1, 'admin_color', 'fresh'),
+(8, 1, 'use_ssl', '0'),
+(9, 1, 'show_admin_bar_front', 'true'),
+(10, 1, 'wp_capabilities', 'a:1:{s:13:\"administrator\";s:1:\"1\";}'),
+(11, 1, 'wp_user_level', '10'),
+(12, 1, 'dismissed_wp_pointers', 'wp330_toolbar,wp330_media_uploader,wp330_saving_widgets'),
+(13, 1, 'show_welcome_panel', '1')",
+
+"CREATE TABLE IF NOT EXISTS `wp_users` (
+ `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+ `user_login` varchar(60) NOT NULL DEFAULT '',
+ `user_pass` varchar(64) NOT NULL DEFAULT '',
+ `user_nicename` varchar(50) NOT NULL DEFAULT '',
+ `user_email` varchar(100) NOT NULL DEFAULT '',
+ `user_url` varchar(100) NOT NULL DEFAULT '',
+ `user_registered` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `user_activation_key` varchar(60) NOT NULL DEFAULT '',
+ `user_status` int(11) NOT NULL DEFAULT '0',
+ `display_name` varchar(250) NOT NULL DEFAULT '',
+ PRIMARY KEY (`ID`),
+ KEY `user_login_key` (`user_login`),
+ KEY `user_nicename` (`user_nicename`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2",
+
+"INSERT INTO `wp_users` (`ID`, `user_login`, `user_pass`, `user_nicename`, `user_email`, `user_url`, `user_registered`, `user_activation_key`, `user_status`, `display_name`) VALUES
+(1, '".addslashes($this->username)."', '".md5($this->password)."', '".addslashes($this->username)."', '".addslashes($this->email)."', '', NOW(), '', 0, '".addslashes($this->username)."')"
+);
+
+ if(!@mysql_connect($this->db_hostname, $this->db_username, $this->db_password)) {
+ Cli::printNotice('Database login has failed:', mysql_error());
+ exit(1);
+ }
+ elseif(!@mysql_select_db($this->db_name)) {
+ Cli::printNotice('Select database has failed:', mysql_error());
+ exit(1);
+ }
+
+ foreach($sql as $req) {
+ @mysql_query($req) or (Cli::printNotice('SQL error', mysql_error()));
+ }
+
+ Cli::printBlankLine();
+ Cli::printNotice('Finished', 'You can now use the wordpress.');
+ }
+}
diff --git a/lib/util/StringUtil.class.php b/lib/util/StringUtil.class.php
new file mode 100644
index 0000000..d5dfd4d
--- /dev/null
+++ b/lib/util/StringUtil.class.php
@@ -0,0 +1,19 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+
+/**
+ *
+ * Allow to build rules to find files and directories.
+ *
+ * All rules may be invoked several times, except for ->in() method.
+ * Some rules are cumulative (->name() for example) whereas others are destructive
+ * (most recent value is used, ->maxdepth() method for example).
+ *
+ * All methods return the current sfFinder object to allow easy chaining:
+ *
+ * $files = sfFinder::type('file')->name('*.php')->in(.);
+ *
+ * Interface loosely based on perl File::Find::Rule module.
+ *
+ * @package symfony
+ * @subpackage util
+ * @author Fabien Potencier
+ * @version SVN: $Id: sfFinder.class.php 32891 2011-08-05 07:48:34Z fabien $
+ */
+class sfFinder
+{
+ protected $type = 'file';
+ protected $names = array();
+ protected $prunes = array();
+ protected $discards = array();
+ protected $execs = array();
+ protected $mindepth = 0;
+ protected $sizes = array();
+ protected $maxdepth = 1000000;
+ protected $relative = false;
+ protected $follow_link = false;
+ protected $sort = false;
+ protected $ignore_version_control = true;
+
+ /**
+ * Sets maximum directory depth.
+ *
+ * Finder will descend at most $level levels of directories below the starting point.
+ *
+ * @param int $level
+ * @return sfFinder current sfFinder object
+ */
+ public function maxdepth($level)
+ {
+ $this->maxdepth = $level;
+
+ return $this;
+ }
+
+ /**
+ * Sets minimum directory depth.
+ *
+ * Finder will start applying tests at level $level.
+ *
+ * @param int $level
+ * @return sfFinder current sfFinder object
+ */
+ public function mindepth($level)
+ {
+ $this->mindepth = $level;
+
+ return $this;
+ }
+
+ public function get_type()
+ {
+ return $this->type;
+ }
+
+ /**
+ * Sets the type of elements to returns.
+ *
+ * @param string $name directory or file or any (for both file and directory)
+ * @return sfFinder new sfFinder object
+ */
+ public static function type($name)
+ {
+ $finder = new self();
+ return $finder->setType($name);
+ }
+ /**
+ * Sets the type of elements to returns.
+ *
+ * @param string $name directory or file or any (for both file and directory)
+ * @return sfFinder Current object
+ */
+ public function setType($name)
+ {
+ $name = strtolower($name);
+
+ if (substr($name, 0, 3) === 'dir')
+ {
+ $this->type = 'directory';
+
+ return $this;
+ }
+ if ($name === 'any')
+ {
+ $this->type = 'any';
+
+ return $this;
+ }
+
+ $this->type = 'file';
+
+ return $this;
+ }
+
+ /*
+ * glob, patterns (must be //) or strings
+ */
+ protected function to_regex($str)
+ {
+ if (preg_match('/^(!)?([^a-zA-Z0-9\\\\]).+?\\2[ims]?$/', $str))
+ {
+ return $str;
+ }
+
+ return sfGlobToRegex::glob_to_regex($str);
+ }
+
+ protected function args_to_array($arg_list, $not = false)
+ {
+ $list = array();
+ $nbArgList = count($arg_list);
+ for ($i = 0; $i < $nbArgList; $i++)
+ {
+ if (is_array($arg_list[$i]))
+ {
+ foreach ($arg_list[$i] as $arg)
+ {
+ $list[] = array($not, $this->to_regex($arg));
+ }
+ }
+ else
+ {
+ $list[] = array($not, $this->to_regex($arg_list[$i]));
+ }
+ }
+
+ return $list;
+ }
+
+ /**
+ * Adds rules that files must match.
+ *
+ * You can use patterns (delimited with / sign), globs or simple strings.
+ *
+ * $finder->name('*.php')
+ * $finder->name('/\.php$/') // same as above
+ * $finder->name('test.php')
+ *
+ * @param list a list of patterns, globs or strings
+ * @return sfFinder Current object
+ */
+ public function name()
+ {
+ $args = func_get_args();
+ $this->names = array_merge($this->names, $this->args_to_array($args));
+
+ return $this;
+ }
+
+ /**
+ * Adds rules that files must not match.
+ *
+ * @see ->name()
+ * @param list a list of patterns, globs or strings
+ * @return sfFinder Current object
+ */
+ public function not_name()
+ {
+ $args = func_get_args();
+ $this->names = array_merge($this->names, $this->args_to_array($args, true));
+
+ return $this;
+ }
+
+ /**
+ * Adds tests for file sizes.
+ *
+ * $finder->size('> 10K');
+ * $finder->size('<= 1Ki');
+ * $finder->size(4);
+ *
+ * @param list a list of comparison strings
+ * @return sfFinder Current object
+ */
+ public function size()
+ {
+ $args = func_get_args();
+ $numargs = count($args);
+ for ($i = 0; $i < $numargs; $i++)
+ {
+ $this->sizes[] = new sfNumberCompare($args[$i]);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Traverses no further.
+ *
+ * @param list a list of patterns, globs to match
+ * @return sfFinder Current object
+ */
+ public function prune()
+ {
+ $args = func_get_args();
+ $this->prunes = array_merge($this->prunes, $this->args_to_array($args));
+
+ return $this;
+ }
+
+ /**
+ * Discards elements that matches.
+ *
+ * @param list a list of patterns, globs to match
+ * @return sfFinder Current object
+ */
+ public function discard()
+ {
+ $args = func_get_args();
+ $this->discards = array_merge($this->discards, $this->args_to_array($args));
+
+ return $this;
+ }
+
+ /**
+ * Ignores version control directories.
+ *
+ * Currently supports Subversion, CVS, DARCS, Gnu Arch, Monotone, Bazaar-NG, GIT, Mercurial
+ *
+ * @param bool $ignore falase when version control directories shall be included (default is true)
+ *
+ * @return sfFinder Current object
+ */
+ public function ignore_version_control($ignore = true)
+ {
+ $this->ignore_version_control = $ignore;
+
+ return $this;
+ }
+
+ /**
+ * Returns files and directories ordered by name
+ *
+ * @return sfFinder Current object
+ */
+ public function sort_by_name()
+ {
+ $this->sort = 'name';
+
+ return $this;
+ }
+
+ /**
+ * Returns files and directories ordered by type (directories before files), then by name
+ *
+ * @return sfFinder Current object
+ */
+ public function sort_by_type()
+ {
+ $this->sort = 'type';
+
+ return $this;
+ }
+
+ /**
+ * Executes function or method for each element.
+ *
+ * Element match if functino or method returns true.
+ *
+ * $finder->exec('myfunction');
+ * $finder->exec(array($object, 'mymethod'));
+ *
+ * @param mixed function or method to call
+ * @return sfFinder Current object
+ */
+ public function exec()
+ {
+ $args = func_get_args();
+ $numargs = count($args);
+ for ($i = 0; $i < $numargs; $i++)
+ {
+ if (is_array($args[$i]) && !method_exists($args[$i][0], $args[$i][1]))
+ {
+ throw new sfException(sprintf('method "%s" does not exist for object "%s".', $args[$i][1], $args[$i][0]));
+ }
+ if (!is_array($args[$i]) && !function_exists($args[$i]))
+ {
+ throw new sfException(sprintf('function "%s" does not exist.', $args[$i]));
+ }
+
+ $this->execs[] = $args[$i];
+ }
+
+ return $this;
+ }
+
+ /**
+ * Returns relative paths for all files and directories.
+ *
+ * @return sfFinder Current object
+ */
+ public function relative()
+ {
+ $this->relative = true;
+
+ return $this;
+ }
+
+ /**
+ * Symlink following.
+ *
+ * @return sfFinder Current object
+ */
+ public function follow_link()
+ {
+ $this->follow_link = true;
+
+ return $this;
+ }
+
+ /**
+ * Searches files and directories which match defined rules.
+ *
+ * @return array list of files and directories
+ */
+ public function in()
+ {
+ $files = array();
+ $here_dir = getcwd();
+
+ $finder = clone $this;
+
+ if ($this->ignore_version_control)
+ {
+ $ignores = array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg');
+
+ $finder->discard($ignores)->prune($ignores);
+ }
+
+ // first argument is an array?
+ $numargs = func_num_args();
+ $arg_list = func_get_args();
+ if ($numargs === 1 && is_array($arg_list[0]))
+ {
+ $arg_list = $arg_list[0];
+ $numargs = count($arg_list);
+ }
+
+ for ($i = 0; $i < $numargs; $i++)
+ {
+ $dir = realpath($arg_list[$i]);
+
+ if (!is_dir($dir))
+ {
+ continue;
+ }
+
+ $dir = str_replace('\\', '/', $dir);
+
+ // absolute path?
+ if (!self::isPathAbsolute($dir))
+ {
+ $dir = $here_dir.'/'.$dir;
+ }
+
+ $new_files = str_replace('\\', '/', $finder->search_in($dir));
+
+ if ($this->relative)
+ {
+ $new_files = preg_replace('#^'.preg_quote(rtrim($dir, '/'), '#').'/#', '', $new_files);
+ }
+
+ $files = array_merge($files, $new_files);
+ }
+
+ if ($this->sort === 'name')
+ {
+ sort($files);
+ }
+
+ return array_unique($files);
+ }
+
+ protected function search_in($dir, $depth = 0)
+ {
+ if ($depth > $this->maxdepth)
+ {
+ return array();
+ }
+
+ $dir = realpath($dir);
+
+ if ((!$this->follow_link) && is_link($dir))
+ {
+ return array();
+ }
+
+ $files = array();
+ $temp_files = array();
+ $temp_folders = array();
+ if (is_dir($dir) && is_readable($dir))
+ {
+ $current_dir = opendir($dir);
+ while (false !== $entryname = readdir($current_dir))
+ {
+ if ($entryname == '.' || $entryname == '..') continue;
+
+ $current_entry = $dir.DIRECTORY_SEPARATOR.$entryname;
+ if ((!$this->follow_link) && is_link($current_entry))
+ {
+ continue;
+ }
+
+ if (is_dir($current_entry))
+ {
+ if ($this->sort === 'type')
+ {
+ $temp_folders[$entryname] = $current_entry;
+ }
+ else
+ {
+ if (($this->type === 'directory' || $this->type === 'any') && ($depth >= $this->mindepth) && !$this->is_discarded($dir, $entryname) && $this->match_names($dir, $entryname) && $this->exec_ok($dir, $entryname))
+ {
+ $files[] = $current_entry;
+ }
+
+ if (!$this->is_pruned($dir, $entryname))
+ {
+ $files = array_merge($files, $this->search_in($current_entry, $depth + 1));
+ }
+ }
+ }
+ else
+ {
+ if (($this->type !== 'directory' || $this->type === 'any') && ($depth >= $this->mindepth) && !$this->is_discarded($dir, $entryname) && $this->match_names($dir, $entryname) && $this->size_ok($dir, $entryname) && $this->exec_ok($dir, $entryname))
+ {
+ if ($this->sort === 'type')
+ {
+ $temp_files[] = $current_entry;
+ }
+ else
+ {
+ $files[] = $current_entry;
+ }
+ }
+ }
+ }
+
+ if ($this->sort === 'type')
+ {
+ ksort($temp_folders);
+ foreach($temp_folders as $entryname => $current_entry)
+ {
+ if (($this->type === 'directory' || $this->type === 'any') && ($depth >= $this->mindepth) && !$this->is_discarded($dir, $entryname) && $this->match_names($dir, $entryname) && $this->exec_ok($dir, $entryname))
+ {
+ $files[] = $current_entry;
+ }
+
+ if (!$this->is_pruned($dir, $entryname))
+ {
+ $files = array_merge($files, $this->search_in($current_entry, $depth + 1));
+ }
+ }
+
+ sort($temp_files);
+ $files = array_merge($files, $temp_files);
+ }
+
+ closedir($current_dir);
+ }
+
+ return $files;
+ }
+
+ protected function match_names($dir, $entry)
+ {
+ if (!count($this->names)) return true;
+
+ // Flags indicating that there was attempts to match
+ // at least one "not_name" or "name" rule respectively
+ // to following variables:
+ $one_not_name_rule = false;
+ $one_name_rule = false;
+
+ foreach ($this->names as $args)
+ {
+ list($not, $regex) = $args;
+ $not ? $one_not_name_rule = true : $one_name_rule = true;
+ if (preg_match($regex, $entry))
+ {
+ // We must match ONLY ONE "not_name" or "name" rule:
+ // if "not_name" rule matched then we return "false"
+ // if "name" rule matched then we return "true"
+ return $not ? false : true;
+ }
+ }
+
+ if ($one_not_name_rule && $one_name_rule)
+ {
+ return false;
+ }
+ else if ($one_not_name_rule)
+ {
+ return true;
+ }
+ else if ($one_name_rule)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ protected function size_ok($dir, $entry)
+ {
+ if (0 === count($this->sizes)) return true;
+
+ if (!is_file($dir.DIRECTORY_SEPARATOR.$entry)) return true;
+
+ $filesize = filesize($dir.DIRECTORY_SEPARATOR.$entry);
+ foreach ($this->sizes as $number_compare)
+ {
+ if (!$number_compare->test($filesize)) return false;
+ }
+
+ return true;
+ }
+
+ protected function is_pruned($dir, $entry)
+ {
+ if (0 === count($this->prunes)) return false;
+
+ foreach ($this->prunes as $args)
+ {
+ $regex = $args[1];
+ if (preg_match($regex, $entry)) return true;
+ }
+
+ return false;
+ }
+
+ protected function is_discarded($dir, $entry)
+ {
+ if (0 === count($this->discards)) return false;
+
+ foreach ($this->discards as $args)
+ {
+ $regex = $args[1];
+ if (preg_match($regex, $entry)) return true;
+ }
+
+ return false;
+ }
+
+ protected function exec_ok($dir, $entry)
+ {
+ if (0 === count($this->execs)) return true;
+
+ foreach ($this->execs as $exec)
+ {
+ if (!call_user_func_array($exec, array($dir, $entry))) return false;
+ }
+
+ return true;
+ }
+
+ public static function isPathAbsolute($path)
+ {
+ if ($path{0} === '/' || $path{0} === '\\' ||
+ (strlen($path) > 3 && ctype_alpha($path{0}) &&
+ $path{1} === ':' &&
+ ($path{2} === '\\' || $path{2} === '/')
+ )
+ )
+ {
+ return true;
+ }
+
+ return false;
+ }
+}
+
+/**
+ * Match globbing patterns against text.
+ *
+ * if match_glob("foo.*", "foo.bar") echo "matched\n";
+ *
+ * // prints foo.bar and foo.baz
+ * $regex = glob_to_regex("foo.*");
+ * for (array('foo.bar', 'foo.baz', 'foo', 'bar') as $t)
+ * {
+ * if (/$regex/) echo "matched: $car\n";
+ * }
+ *
+ * sfGlobToRegex implements glob(3) style matching that can be used to match
+ * against text, rather than fetching names from a filesystem.
+ *
+ * based on perl Text::Glob module.
+ *
+ * @package symfony
+ * @subpackage util
+ * @author Fabien Potencier php port
+ * @author Richard Clamp perl version
+ * @copyright 2004-2005 Fabien Potencier
+ * @copyright 2002 Richard Clamp
+ * @version SVN: $Id: sfFinder.class.php 32891 2011-08-05 07:48:34Z fabien $
+ */
+class sfGlobToRegex
+{
+ protected static $strict_leading_dot = true;
+ protected static $strict_wildcard_slash = true;
+
+ public static function setStrictLeadingDot($boolean)
+ {
+ self::$strict_leading_dot = $boolean;
+ }
+
+ public static function setStrictWildcardSlash($boolean)
+ {
+ self::$strict_wildcard_slash = $boolean;
+ }
+
+ /**
+ * Returns a compiled regex which is the equiavlent of the globbing pattern.
+ *
+ * @param string $glob pattern
+ * @return string regex
+ */
+ public static function glob_to_regex($glob)
+ {
+ $first_byte = true;
+ $escaping = false;
+ $in_curlies = 0;
+ $regex = '';
+ $sizeGlob = strlen($glob);
+ for ($i = 0; $i < $sizeGlob; $i++)
+ {
+ $car = $glob[$i];
+ if ($first_byte)
+ {
+ if (self::$strict_leading_dot && $car !== '.')
+ {
+ $regex .= '(?=[^\.])';
+ }
+
+ $first_byte = false;
+ }
+
+ if ($car === '/')
+ {
+ $first_byte = true;
+ }
+
+ if ($car === '.' || $car === '(' || $car === ')' || $car === '|' || $car === '+' || $car === '^' || $car === '$')
+ {
+ $regex .= "\\$car";
+ }
+ elseif ($car === '*')
+ {
+ $regex .= ($escaping ? '\\*' : (self::$strict_wildcard_slash ? '[^/]*' : '.*'));
+ }
+ elseif ($car === '?')
+ {
+ $regex .= ($escaping ? '\\?' : (self::$strict_wildcard_slash ? '[^/]' : '.'));
+ }
+ elseif ($car === '{')
+ {
+ $regex .= ($escaping ? '\\{' : '(');
+ if (!$escaping) ++$in_curlies;
+ }
+ elseif ($car === '}' && $in_curlies)
+ {
+ $regex .= ($escaping ? '}' : ')');
+ if (!$escaping) --$in_curlies;
+ }
+ elseif ($car === ',' && $in_curlies)
+ {
+ $regex .= ($escaping ? ',' : '|');
+ }
+ elseif ($car === '\\')
+ {
+ if ($escaping)
+ {
+ $regex .= '\\\\';
+ $escaping = false;
+ }
+ else
+ {
+ $escaping = true;
+ }
+
+ continue;
+ }
+ else
+ {
+ $regex .= $car;
+ }
+ $escaping = false;
+ }
+
+ return '#^'.$regex.'$#';
+ }
+}
+
+/**
+ * Numeric comparisons.
+ *
+ * sfNumberCompare compiles a simple comparison to an anonymous
+ * subroutine, which you can call with a value to be tested again.
+
+ * Now this would be very pointless, if sfNumberCompare didn't understand
+ * magnitudes.
+
+ * The target value may use magnitudes of kilobytes (k, ki),
+ * megabytes (m, mi), or gigabytes (g, gi). Those suffixed
+ * with an i use the appropriate 2**n version in accordance with the
+ * IEC standard: http://physics.nist.gov/cuu/Units/binary.html
+ *
+ * based on perl Number::Compare module.
+ *
+ * @package symfony
+ * @subpackage util
+ * @author Fabien Potencier php port
+ * @author Richard Clamp perl version
+ * @copyright 2004-2005 Fabien Potencier
+ * @copyright 2002 Richard Clamp
+ * @see http://physics.nist.gov/cuu/Units/binary.html
+ * @version SVN: $Id: sfFinder.class.php 32891 2011-08-05 07:48:34Z fabien $
+ */
+class sfNumberCompare
+{
+ protected $test = '';
+
+ public function __construct($test)
+ {
+ $this->test = $test;
+ }
+
+ public function test($number)
+ {
+ if (!preg_match('{^([<>]=?)?(.*?)([kmg]i?)?$}i', $this->test, $matches))
+ {
+ throw new sfException(sprintf('don\'t understand "%s" as a test.', $this->test));
+ }
+
+ $target = array_key_exists(2, $matches) ? $matches[2] : '';
+ $magnitude = array_key_exists(3, $matches) ? $matches[3] : '';
+ if (strtolower($magnitude) === 'k') $target *= 1000;
+ if (strtolower($magnitude) === 'ki') $target *= 1024;
+ if (strtolower($magnitude) === 'm') $target *= 1000000;
+ if (strtolower($magnitude) === 'mi') $target *= 1024*1024;
+ if (strtolower($magnitude) === 'g') $target *= 1000000000;
+ if (strtolower($magnitude) === 'gi') $target *= 1024*1024*1024;
+
+ $comparison = array_key_exists(1, $matches) ? $matches[1] : '==';
+ if ($comparison === '==' || $comparison == '')
+ {
+ return ($number == $target);
+ }
+ if ($comparison === '>')
+ {
+ return ($number > $target);
+ }
+ if ($comparison === '>=')
+ {
+ return ($number >= $target);
+ }
+ if ($comparison === '<')
+ {
+ return ($number < $target);
+ }
+ if ($comparison === '<=')
+ {
+ return ($number <= $target);
+ }
+
+ return false;
+ }
+}
diff --git a/videos/preview-2.ogv b/videos/preview-2.ogv
new file mode 100644
index 0000000..a3e5ac5
Binary files /dev/null and b/videos/preview-2.ogv differ
diff --git a/website/logo.svg b/website/logo.svg
new file mode 100644
index 0000000..0ddfbe4
--- /dev/null
+++ b/website/logo.svg
@@ -0,0 +1,301 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+ CMSInstaller
+
+
+