first commit after reset
authorBenjamin Auder <benjamin.a@mailoo.org>
Thu, 5 Feb 2015 10:57:31 +0000 (11:57 +0100)
committerBenjamin Auder <benjamin.a@mailoo.org>
Thu, 5 Feb 2015 10:57:31 +0000 (11:57 +0100)
115 files changed:
.gitignore [new file with mode: 0644]
.travis.yml [new file with mode: 0644]
LICENSE [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
app/.htaccess [new file with mode: 0644]
app/AppCache.php [new file with mode: 0644]
app/AppKernel.php [new file with mode: 0644]
app/Resources/views/Form/fields.html.twig [new file with mode: 0644]
app/Resources/views/base.html.twig [new file with mode: 0644]
app/SymfonyRequirements.php [new file with mode: 0644]
app/autoload.php [new file with mode: 0644]
app/cache/.gitkeep [new file with mode: 0644]
app/check.php [new file with mode: 0644]
app/config/config.yml [new file with mode: 0644]
app/config/config_dev.yml [new file with mode: 0644]
app/config/config_prod.yml [new file with mode: 0644]
app/config/config_test.yml [new file with mode: 0644]
app/config/parameters.yml.dist [new file with mode: 0644]
app/config/routing.yml [new file with mode: 0644]
app/config/routing_dev.yml [new file with mode: 0644]
app/config/security.yml [new file with mode: 0644]
app/console [new file with mode: 0755]
app/logs/.gitkeep [new file with mode: 0755]
app/phpunit.xml.dist [new file with mode: 0644]
composer.json [new file with mode: 0644]
composer.lock [new file with mode: 0644]
resetCacheLogs.php [new file with mode: 0644]
src/.htaccess [new file with mode: 0644]
src/Mixstore/StaticBundle/Controller/MainController.php [new file with mode: 0644]
src/Mixstore/StaticBundle/DependencyInjection/Configuration.php [new file with mode: 0644]
src/Mixstore/StaticBundle/DependencyInjection/MixstoreStoreExtension.php [new file with mode: 0644]
src/Mixstore/StaticBundle/MixstoreStaticBundle.php [new file with mode: 0644]
src/Mixstore/StaticBundle/Resources/config/routing.yml [new file with mode: 0644]
src/Mixstore/StaticBundle/Resources/config/services.yml [new file with mode: 0644]
src/Mixstore/StaticBundle/Resources/views/about.html.twig [new file with mode: 0644]
src/Mixstore/StaticBundle/Resources/views/home.html.twig [new file with mode: 0644]
src/Mixstore/StaticBundle/Resources/views/policy.html.twig [new file with mode: 0644]
src/Mixstore/StoreBundle/Controller/PackageController.php [new file with mode: 0644]
src/Mixstore/StoreBundle/Controller/UsecaseController.php [new file with mode: 0644]
src/Mixstore/StoreBundle/DependencyInjection/Configuration.php [new file with mode: 0644]
src/Mixstore/StoreBundle/DependencyInjection/MixstoreStoreExtension.php [new file with mode: 0644]
src/Mixstore/StoreBundle/Entity/Language.php [new file with mode: 0644]
src/Mixstore/StoreBundle/Entity/Package.php [new file with mode: 0644]
src/Mixstore/StoreBundle/Entity/PackageRepository.php [new file with mode: 0644]
src/Mixstore/StoreBundle/Entity/Usecase.php [new file with mode: 0644]
src/Mixstore/StoreBundle/Entity/UsecaseRepository.php [new file with mode: 0644]
src/Mixstore/StoreBundle/MixstoreStoreBundle.php [new file with mode: 0644]
src/Mixstore/StoreBundle/Resources/config/routing.yml [new file with mode: 0644]
src/Mixstore/StoreBundle/Resources/config/services.yml [new file with mode: 0644]
src/Mixstore/StoreBundle/Resources/views/Package/list.html.twig [new file with mode: 0644]
src/Mixstore/StoreBundle/Resources/views/Package/list_content.html.twig [new file with mode: 0644]
src/Mixstore/StoreBundle/Resources/views/Package/view.html.twig [new file with mode: 0644]
src/Mixstore/StoreBundle/Resources/views/Usecase/list.html.twig [new file with mode: 0644]
src/Mixstore/StoreBundle/Resources/views/Usecase/list_content.html.twig [new file with mode: 0644]
src/Mixstore/StoreBundle/Resources/views/Usecase/view.html.twig [new file with mode: 0644]
src/Mixstore/StoreBundle/Resources/views/upsert-email.txt.twig [new file with mode: 0644]
src/Mixstore/StoreBundle/Resources/views/upsert.html.twig [new file with mode: 0644]
src/Mixstore/UserBundle/Controller/BoardController.php [new file with mode: 0644]
src/Mixstore/UserBundle/Controller/MyAdminController.php [new file with mode: 0644]
src/Mixstore/UserBundle/DependencyInjection/Configuration.php [new file with mode: 0644]
src/Mixstore/UserBundle/DependencyInjection/MixstoreUserExtension.php [new file with mode: 0644]
src/Mixstore/UserBundle/Entity/User.php [new file with mode: 0644]
src/Mixstore/UserBundle/Form/Type/ProfileFormType.php [new file with mode: 0644]
src/Mixstore/UserBundle/Form/Type/RegistrationFormType.php [new file with mode: 0644]
src/Mixstore/UserBundle/MixstoreUserBundle.php [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/config/config.yml [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/config/routing.yml [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/config/services.yml [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/views/Admin/users.html.twig [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/views/Board/index.html.twig [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/views/ChangePassword/changePassword.html.twig [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/views/Profile/edit.html.twig [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/views/Profile/show.html.twig [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/views/Registration/checkEmail.html.twig [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/views/Registration/confirmed.html.twig [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/views/Registration/email.txt.twig [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/views/Registration/register.html.twig [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/views/Resetting/checkEmail.html.twig [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/views/Resetting/email.txt.twig [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/views/Resetting/passwordAlreadyRequested.html.twig [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/views/Resetting/request.html.twig [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/views/Resetting/reset.html.twig [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/views/Security/login.html.twig [new file with mode: 0644]
src/Mixstore/UserBundle/Resources/views/layout.html.twig [new file with mode: 0644]
web/.htaccess [new file with mode: 0644]
web/app.php [new file with mode: 0644]
web/app_dev.php [new file with mode: 0644]
web/apple-touch-icon.png [new file with mode: 0644]
web/config.php [new file with mode: 0644]
web/favicon.ico [new file with mode: 0644]
web/mixstore/css/base.css [new file with mode: 0644]
web/mixstore/css/form.css [new file with mode: 0644]
web/mixstore/css/static/about.css [new file with mode: 0644]
web/mixstore/css/static/home.css [new file with mode: 0644]
web/mixstore/css/static/policy.css [new file with mode: 0644]
web/mixstore/css/store/table.css [new file with mode: 0644]
web/mixstore/css/store/upsert.css [new file with mode: 0644]
web/mixstore/css/store/view-package.css [new file with mode: 0644]
web/mixstore/css/store/view-usecase.css [new file with mode: 0644]
web/mixstore/css/summernote.min.css [new file with mode: 0644]
web/mixstore/css/user/admin.css [new file with mode: 0644]
web/mixstore/css/user/board.css [new file with mode: 0644]
web/mixstore/css/user/common.css [new file with mode: 0644]
web/mixstore/fonts/glyphicons-halflings-regular.eot [new file with mode: 0644]
web/mixstore/fonts/glyphicons-halflings-regular.svg [new file with mode: 0644]
web/mixstore/fonts/glyphicons-halflings-regular.ttf [new file with mode: 0644]
web/mixstore/fonts/glyphicons-halflings-regular.woff [new file with mode: 0644]
web/mixstore/images/banner.png [new file with mode: 0644]
web/mixstore/images/favicon.png [new file with mode: 0644]
web/mixstore/images/iris_pca.png [new file with mode: 0644]
web/mixstore/images/pkg_banners/.gitignore [new file with mode: 0644]
web/mixstore/js/stupidtable.min.js [new file with mode: 0644]
web/mixstore/js/summernote.min.js [new file with mode: 0644]
web/robots.txt [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..0fe0b8c
--- /dev/null
@@ -0,0 +1,11 @@
+/web/bundles/
+/app/bootstrap.php.cache
+/app/cache/*
+/app/config/parameters.yml
+/app/logs/*
+!app/cache/.gitkeep
+!app/logs/.gitkeep
+/build/
+/vendor/
+/bin/
+*~
diff --git a/.travis.yml b/.travis.yml
new file mode 100644 (file)
index 0000000..955248a
--- /dev/null
@@ -0,0 +1,10 @@
+language: php
+
+php:
+  - 5.3.3
+  - 5.3
+  - 5.4
+
+before_script: composer install -n
+
+script: phpunit -c app
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..d128d49
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2014 Benjamin Auder
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..faa8be4
--- /dev/null
+++ b/README
@@ -0,0 +1,12 @@
+mixstore utilise Symfony2 ; organisation des répertoires :
+
+    app/: La configuration de l'application,
+    src/: Le code PHP du projet,
+    vendor/: Les bibliothèques tierces,
+    web/: Le répertoire Web racine.
+
+Le répertoire Web racine est l'endroit ou se situent tous les fichiers statiques 
+et publics comme les images, les feuilles de styles et les fichiers javascript.
+C'est aussi le dossier contenant le point d'entrée web/app.php
+
+[Voir http://symfony.com/fr/doc/current/quick_tour/the_architecture.html]
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..9289471
--- /dev/null
+++ b/TODO
@@ -0,0 +1,8 @@
+Sure :
+ - translations
+ - add defensive checks at many places to avoid ugly error screens (duplicate key, ...etc)
+ - (re)factor some controllers code
+
+Maybe :
+ - redirect after page access http://knplabs.com/blog/2012/01/13/redirect-after-registration-in-symfony2/
+ - move assets to bundles instead of web/mixstore
diff --git a/app/.htaccess b/app/.htaccess
new file mode 100644 (file)
index 0000000..fb1de45
--- /dev/null
@@ -0,0 +1,7 @@
+<IfModule mod_authz_core.c>
+    Require all denied
+</IfModule>
+<IfModule !mod_authz_core.c>
+    Order deny,allow
+    Deny from all
+</IfModule>
diff --git a/app/AppCache.php b/app/AppCache.php
new file mode 100644 (file)
index 0000000..ddb51db
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+
+require_once __DIR__.'/AppKernel.php';
+
+use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;
+
+class AppCache extends HttpCache
+{
+}
diff --git a/app/AppKernel.php b/app/AppKernel.php
new file mode 100644 (file)
index 0000000..37f8b6c
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+
+use Symfony\Component\HttpKernel\Kernel;
+use Symfony\Component\Config\Loader\LoaderInterface;
+
+class AppKernel extends Kernel
+{
+    public function registerBundles()
+    {
+        $bundles = array(
+            new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
+            new Symfony\Bundle\SecurityBundle\SecurityBundle(),
+            new Symfony\Bundle\TwigBundle\TwigBundle(),
+            new Symfony\Bundle\MonologBundle\MonologBundle(),
+            new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
+            new Symfony\Bundle\AsseticBundle\AsseticBundle(),
+            new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
+            new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
+            new FOS\UserBundle\FOSUserBundle(),
+            new Mixstore\StaticBundle\MixstoreStaticBundle(),
+            new Mixstore\UserBundle\MixstoreUserBundle(),
+            new Mixstore\StoreBundle\MixstoreStoreBundle(),
+        );
+
+        if (in_array($this->getEnvironment(), array('dev', 'test'))) {
+            $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
+            $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle();
+            $bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle();
+        }
+
+        return $bundles;
+    }
+
+    public function registerContainerConfiguration(LoaderInterface $loader)
+    {
+        $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
+    }
+}
diff --git a/app/Resources/views/Form/fields.html.twig b/app/Resources/views/Form/fields.html.twig
new file mode 100644 (file)
index 0000000..90fc47b
--- /dev/null
@@ -0,0 +1,32 @@
+{# Global styles for forms (uniform display) #}
+
+{% block form_widget_simple %}
+    {% set type = type|default('text') %}
+    <div class="col-sm-8">
+               <input class="form-control" type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
+       </div>
+{% endblock form_widget_simple %}
+
+{% block form_row %}
+{% spaceless %}
+    <div class="form-group">
+        {{ form_label(form) }}
+        {{ form_widget(form) }}
+        {{ form_errors(form) }}
+    </div>
+{% endspaceless %}
+{% endblock form_row %}
+
+{% block form_errors %}
+{% spaceless %}
+    {% if errors|length > 0 %}
+    <div class="col-xs-12 col-sm-8 col-sm-offset-2">
+               <ul>
+                       {% for error in errors %}
+                               <li>{{ error.message }}</li>
+                       {% endfor %}
+               </ul>
+       </div>
+       {% endif %}
+{% endspaceless %}
+{% endblock form_errors %}
diff --git a/app/Resources/views/base.html.twig b/app/Resources/views/base.html.twig
new file mode 100644 (file)
index 0000000..a1730a2
--- /dev/null
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+       <meta charset="UTF-8" />
+       <title>{% block title %}mixstore - {% endblock %}</title>
+       {% block header %}
+       <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootswatch/3.1.1/united/bootstrap.min.css">
+       <link rel="stylesheet" href="{{ asset('mixstore/css/base.css') }}" />
+       <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Merienda+One">
+       {% endblock %}
+       <link rel="icon" type="image/x-icon" href="{{ asset('mixstore/images/favicon.png') }}" />
+</head>
+
+<body>
+
+<div class="navbar navbar-default">
+       <div class="navbar-header">
+               <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-responsive-collapse">
+                       <span class="icon-bar"></span>
+                       <span class="icon-bar"></span>
+                       <span class="icon-bar"></span>
+               </button>
+               <a class="navbar-brand" href="{{ path('mixstore_static_home') }}">Home</a>
+       </div>
+       <div class="navbar-collapse collapse navbar-responsive-collapse">
+               <ul class="nav navbar-nav navbar-left">
+                       <li><a href="{{ path('mixstore_static_about') }}">About</a></li>
+                       <li><a href="{{ path('mixstore_static_policy') }}">Policy</a></li>
+               </ul>
+               
+               <ul class="nav navbar-nav navbar-center">
+                       <li id="storemenu"><a href="{{ path('mixstore_store_package_list') }}">Store</a></li>
+               </ul>
+               <ul class="nav navbar-nav navbar-right">
+               {% if is_granted("IS_AUTHENTICATED_REMEMBERED") %}
+                       <li class="dropdown">
+                               <a href="#" class="dropdown-toggle" data-toggle="dropdown">Menu <b class="caret"></b></a>
+                               <ul class="dropdown-menu">
+                                       <li><a href="{{ path('mixstore_user_board') }}">User board</a></li>
+                                       <li class="divider"></li>
+                                       <li><a href="{{ path('fos_user_profile_show') }}">See profile</a></li>
+                                       <li><a href="{{ path('fos_user_profile_edit') }}">Edit profile</a></li>
+                                       <li><a href="{{ path('fos_user_change_password') }}">Change password</a></li>
+                                       <li><a href="{{ path('fos_user_security_logout') }}">{{ 'layout.logout'|trans({}, 'FOSUserBundle') }}</a></li>
+                               </ul>
+                       </li>
+               {% else %}
+                       <li id="loginmenu">
+                       <a href="{{ path('fos_user_security_login') }}">
+                               {{ 'layout.login'|trans({}, 'FOSUserBundle') }}
+                       </a>
+                       </li>
+               {% endif %}
+               </ul>
+       </div>
+</div>
+
+<div class="container-fluid">
+       {% block content %}{% endblock %}
+</div>
+
+<footer>
+       &copy; Mixstore team 2014 
+       &nbsp;&nbsp;&nbsp; - &nbsp;&nbsp;&nbsp; 
+       <a href="mailto:contact@mixstore.org">Contact us</a>
+</footer>
+
+{% block javascripts %}
+<script src="//code.jquery.com/jquery-2.1.0.min.js"></script>
+<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
+{% endblock %}
+
+</body>
+
+</html>
diff --git a/app/SymfonyRequirements.php b/app/SymfonyRequirements.php
new file mode 100644 (file)
index 0000000..fb70f80
--- /dev/null
@@ -0,0 +1,687 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/*
+ * Users of PHP 5.2 should be able to run the requirements checks.
+ * This is why the file and all classes must be compatible with PHP 5.2+
+ * (e.g. not using namespaces and closures).
+ *
+ * ************** CAUTION **************
+ *
+ * DO NOT EDIT THIS FILE as it will be overridden by Composer as part of
+ * the installation/update process. The original file resides in the
+ * SensioDistributionBundle.
+ *
+ * ************** CAUTION **************
+ */
+
+/**
+ * Represents a single PHP requirement, e.g. an installed extension.
+ * It can be a mandatory requirement or an optional recommendation.
+ * There is a special subclass, named PhpIniRequirement, to check a php.ini configuration.
+ *
+ * @author Tobias Schultze <http://tobion.de>
+ */
+class Requirement
+{
+    private $fulfilled;
+    private $testMessage;
+    private $helpText;
+    private $helpHtml;
+    private $optional;
+
+    /**
+     * Constructor that initializes the requirement.
+     *
+     * @param Boolean     $fulfilled   Whether the requirement is fulfilled
+     * @param string      $testMessage The message for testing the requirement
+     * @param string      $helpHtml    The help text formatted in HTML for resolving the problem
+     * @param string|null $helpText    The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
+     * @param Boolean     $optional    Whether this is only an optional recommendation not a mandatory requirement
+     */
+    public function __construct($fulfilled, $testMessage, $helpHtml, $helpText = null, $optional = false)
+    {
+        $this->fulfilled = (Boolean) $fulfilled;
+        $this->testMessage = (string) $testMessage;
+        $this->helpHtml = (string) $helpHtml;
+        $this->helpText = null === $helpText ? strip_tags($this->helpHtml) : (string) $helpText;
+        $this->optional = (Boolean) $optional;
+    }
+
+    /**
+     * Returns whether the requirement is fulfilled.
+     *
+     * @return Boolean true if fulfilled, otherwise false
+     */
+    public function isFulfilled()
+    {
+        return $this->fulfilled;
+    }
+
+    /**
+     * Returns the message for testing the requirement.
+     *
+     * @return string The test message
+     */
+    public function getTestMessage()
+    {
+        return $this->testMessage;
+    }
+
+    /**
+     * Returns the help text for resolving the problem
+     *
+     * @return string The help text
+     */
+    public function getHelpText()
+    {
+        return $this->helpText;
+    }
+
+    /**
+     * Returns the help text formatted in HTML.
+     *
+     * @return string The HTML help
+     */
+    public function getHelpHtml()
+    {
+        return $this->helpHtml;
+    }
+
+    /**
+     * Returns whether this is only an optional recommendation and not a mandatory requirement.
+     *
+     * @return Boolean true if optional, false if mandatory
+     */
+    public function isOptional()
+    {
+        return $this->optional;
+    }
+}
+
+/**
+ * Represents a PHP requirement in form of a php.ini configuration.
+ *
+ * @author Tobias Schultze <http://tobion.de>
+ */
+class PhpIniRequirement extends Requirement
+{
+    /**
+     * Constructor that initializes the requirement.
+     *
+     * @param string           $cfgName    The configuration name used for ini_get()
+     * @param Boolean|callback $evaluation Either a Boolean indicating whether the configuration should evaluate to true or false,
+                                                    or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
+     * @param Boolean $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
+                                                    This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
+                                                    Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
+     * @param string|null $testMessage The message for testing the requirement (when null and $evaluation is a Boolean a default message is derived)
+     * @param string|null $helpHtml    The help text formatted in HTML for resolving the problem (when null and $evaluation is a Boolean a default help is derived)
+     * @param string|null $helpText    The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
+     * @param Boolean     $optional    Whether this is only an optional recommendation not a mandatory requirement
+     */
+    public function __construct($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null, $optional = false)
+    {
+        $cfgValue = ini_get($cfgName);
+
+        if (is_callable($evaluation)) {
+            if (null === $testMessage || null === $helpHtml) {
+                throw new InvalidArgumentException('You must provide the parameters testMessage and helpHtml for a callback evaluation.');
+            }
+
+            $fulfilled = call_user_func($evaluation, $cfgValue);
+        } else {
+            if (null === $testMessage) {
+                $testMessage = sprintf('%s %s be %s in php.ini',
+                    $cfgName,
+                    $optional ? 'should' : 'must',
+                    $evaluation ? 'enabled' : 'disabled'
+                );
+            }
+
+            if (null === $helpHtml) {
+                $helpHtml = sprintf('Set <strong>%s</strong> to <strong>%s</strong> in php.ini<a href="#phpini">*</a>.',
+                    $cfgName,
+                    $evaluation ? 'on' : 'off'
+                );
+            }
+
+            $fulfilled = $evaluation == $cfgValue;
+        }
+
+        parent::__construct($fulfilled || ($approveCfgAbsence && false === $cfgValue), $testMessage, $helpHtml, $helpText, $optional);
+    }
+}
+
+/**
+ * A RequirementCollection represents a set of Requirement instances.
+ *
+ * @author Tobias Schultze <http://tobion.de>
+ */
+class RequirementCollection implements IteratorAggregate
+{
+    private $requirements = array();
+
+    /**
+     * Gets the current RequirementCollection as an Iterator.
+     *
+     * @return Traversable A Traversable interface
+     */
+    public function getIterator()
+    {
+        return new ArrayIterator($this->requirements);
+    }
+
+    /**
+     * Adds a Requirement.
+     *
+     * @param Requirement $requirement A Requirement instance
+     */
+    public function add(Requirement $requirement)
+    {
+        $this->requirements[] = $requirement;
+    }
+
+    /**
+     * Adds a mandatory requirement.
+     *
+     * @param Boolean     $fulfilled   Whether the requirement is fulfilled
+     * @param string      $testMessage The message for testing the requirement
+     * @param string      $helpHtml    The help text formatted in HTML for resolving the problem
+     * @param string|null $helpText    The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
+     */
+    public function addRequirement($fulfilled, $testMessage, $helpHtml, $helpText = null)
+    {
+        $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, false));
+    }
+
+    /**
+     * Adds an optional recommendation.
+     *
+     * @param Boolean     $fulfilled   Whether the recommendation is fulfilled
+     * @param string      $testMessage The message for testing the recommendation
+     * @param string      $helpHtml    The help text formatted in HTML for resolving the problem
+     * @param string|null $helpText    The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
+     */
+    public function addRecommendation($fulfilled, $testMessage, $helpHtml, $helpText = null)
+    {
+        $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, true));
+    }
+
+    /**
+     * Adds a mandatory requirement in form of a php.ini configuration.
+     *
+     * @param string           $cfgName    The configuration name used for ini_get()
+     * @param Boolean|callback $evaluation Either a Boolean indicating whether the configuration should evaluate to true or false,
+                                                    or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
+     * @param Boolean $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
+                                                    This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
+                                                    Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
+     * @param string      $testMessage The message for testing the requirement (when null and $evaluation is a Boolean a default message is derived)
+     * @param string      $helpHtml    The help text formatted in HTML for resolving the problem (when null and $evaluation is a Boolean a default help is derived)
+     * @param string|null $helpText    The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
+     */
+    public function addPhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null)
+    {
+        $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, false));
+    }
+
+    /**
+     * Adds an optional recommendation in form of a php.ini configuration.
+     *
+     * @param string           $cfgName    The configuration name used for ini_get()
+     * @param Boolean|callback $evaluation Either a Boolean indicating whether the configuration should evaluate to true or false,
+                                                    or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
+     * @param Boolean $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
+                                                    This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
+                                                    Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
+     * @param string      $testMessage The message for testing the requirement (when null and $evaluation is a Boolean a default message is derived)
+     * @param string      $helpHtml    The help text formatted in HTML for resolving the problem (when null and $evaluation is a Boolean a default help is derived)
+     * @param string|null $helpText    The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
+     */
+    public function addPhpIniRecommendation($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null)
+    {
+        $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, true));
+    }
+
+    /**
+     * Adds a requirement collection to the current set of requirements.
+     *
+     * @param RequirementCollection $collection A RequirementCollection instance
+     */
+    public function addCollection(RequirementCollection $collection)
+    {
+        $this->requirements = array_merge($this->requirements, $collection->all());
+    }
+
+    /**
+     * Returns both requirements and recommendations.
+     *
+     * @return array Array of Requirement instances
+     */
+    public function all()
+    {
+        return $this->requirements;
+    }
+
+    /**
+     * Returns all mandatory requirements.
+     *
+     * @return array Array of Requirement instances
+     */
+    public function getRequirements()
+    {
+        $array = array();
+        foreach ($this->requirements as $req) {
+            if (!$req->isOptional()) {
+                $array[] = $req;
+            }
+        }
+
+        return $array;
+    }
+
+    /**
+     * Returns the mandatory requirements that were not met.
+     *
+     * @return array Array of Requirement instances
+     */
+    public function getFailedRequirements()
+    {
+        $array = array();
+        foreach ($this->requirements as $req) {
+            if (!$req->isFulfilled() && !$req->isOptional()) {
+                $array[] = $req;
+            }
+        }
+
+        return $array;
+    }
+
+    /**
+     * Returns all optional recommendations.
+     *
+     * @return array Array of Requirement instances
+     */
+    public function getRecommendations()
+    {
+        $array = array();
+        foreach ($this->requirements as $req) {
+            if ($req->isOptional()) {
+                $array[] = $req;
+            }
+        }
+
+        return $array;
+    }
+
+    /**
+     * Returns the recommendations that were not met.
+     *
+     * @return array Array of Requirement instances
+     */
+    public function getFailedRecommendations()
+    {
+        $array = array();
+        foreach ($this->requirements as $req) {
+            if (!$req->isFulfilled() && $req->isOptional()) {
+                $array[] = $req;
+            }
+        }
+
+        return $array;
+    }
+
+    /**
+     * Returns whether a php.ini configuration is not correct.
+     *
+     * @return Boolean php.ini configuration problem?
+     */
+    public function hasPhpIniConfigIssue()
+    {
+        foreach ($this->requirements as $req) {
+            if (!$req->isFulfilled() && $req instanceof PhpIniRequirement) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns the PHP configuration file (php.ini) path.
+     *
+     * @return string|false php.ini file path
+     */
+    public function getPhpIniConfigPath()
+    {
+        return get_cfg_var('cfg_file_path');
+    }
+}
+
+/**
+ * This class specifies all requirements and optional recommendations that
+ * are necessary to run the Symfony Standard Edition.
+ *
+ * @author Tobias Schultze <http://tobion.de>
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class SymfonyRequirements extends RequirementCollection
+{
+    const REQUIRED_PHP_VERSION = '5.3.3';
+
+    /**
+     * Constructor that initializes the requirements.
+     */
+    public function __construct()
+    {
+        /* mandatory requirements follow */
+
+        $installedPhpVersion = phpversion();
+
+        $this->addRequirement(
+            version_compare($installedPhpVersion, self::REQUIRED_PHP_VERSION, '>='),
+            sprintf('PHP version must be at least %s (%s installed)', self::REQUIRED_PHP_VERSION, $installedPhpVersion),
+            sprintf('You are running PHP version "<strong>%s</strong>", but Symfony needs at least PHP "<strong>%s</strong>" to run.
+                Before using Symfony, upgrade your PHP installation, preferably to the latest version.',
+                $installedPhpVersion, self::REQUIRED_PHP_VERSION),
+            sprintf('Install PHP %s or newer (installed version is %s)', self::REQUIRED_PHP_VERSION, $installedPhpVersion)
+        );
+
+        $this->addRequirement(
+            version_compare($installedPhpVersion, '5.3.16', '!='),
+            'PHP version must not be 5.3.16 as Symfony won\'t work properly with it',
+            'Install PHP 5.3.17 or newer (or downgrade to an earlier PHP version)'
+        );
+
+        $this->addRequirement(
+            is_dir(__DIR__.'/../vendor/composer'),
+            'Vendor libraries must be installed',
+            'Vendor libraries are missing. Install composer following instructions from <a href="http://getcomposer.org/">http://getcomposer.org/</a>. ' .
+                'Then run "<strong>php composer.phar install</strong>" to install them.'
+        );
+
+        $baseDir = basename(__DIR__);
+
+        $this->addRequirement(
+            is_writable(__DIR__.'/cache'),
+            "$baseDir/cache/ directory must be writable",
+            "Change the permissions of the \"<strong>$baseDir/cache/</strong>\" directory so that the web server can write into it."
+        );
+
+        $this->addRequirement(
+            is_writable(__DIR__.'/logs'),
+            "$baseDir/logs/ directory must be writable",
+            "Change the permissions of the \"<strong>$baseDir/logs/</strong>\" directory so that the web server can write into it."
+        );
+
+        $this->addPhpIniRequirement(
+            'date.timezone', true, false,
+            'date.timezone setting must be set',
+            'Set the "<strong>date.timezone</strong>" setting in php.ini<a href="#phpini">*</a> (like Europe/Paris).'
+        );
+
+        if (version_compare($installedPhpVersion, self::REQUIRED_PHP_VERSION, '>=')) {
+            $timezones = array();
+            foreach (DateTimeZone::listAbbreviations() as $abbreviations) {
+                foreach ($abbreviations as $abbreviation) {
+                    $timezones[$abbreviation['timezone_id']] = true;
+                }
+            }
+
+            $this->addRequirement(
+                isset($timezones[date_default_timezone_get()]),
+                sprintf('Configured default timezone "%s" must be supported by your installation of PHP', date_default_timezone_get()),
+                'Your default timezone is not supported by PHP. Check for typos in your <strong>php.ini</strong> file and have a look at the list of deprecated timezones at <a href="http://php.net/manual/en/timezones.others.php">http://php.net/manual/en/timezones.others.php</a>.'
+            );
+        }
+
+        $this->addRequirement(
+            function_exists('json_encode'),
+            'json_encode() must be available',
+            'Install and enable the <strong>JSON</strong> extension.'
+        );
+
+        $this->addRequirement(
+            function_exists('session_start'),
+            'session_start() must be available',
+            'Install and enable the <strong>session</strong> extension.'
+        );
+
+        $this->addRequirement(
+            function_exists('ctype_alpha'),
+            'ctype_alpha() must be available',
+            'Install and enable the <strong>ctype</strong> extension.'
+        );
+
+        $this->addRequirement(
+            function_exists('token_get_all'),
+            'token_get_all() must be available',
+            'Install and enable the <strong>Tokenizer</strong> extension.'
+        );
+
+        $this->addRequirement(
+            function_exists('simplexml_import_dom'),
+            'simplexml_import_dom() must be available',
+            'Install and enable the <strong>SimpleXML</strong> extension.'
+        );
+
+        if (function_exists('apc_store') && ini_get('apc.enabled')) {
+            if (version_compare($installedPhpVersion, '5.4.0', '>=')) {
+                $this->addRequirement(
+                    version_compare(phpversion('apc'), '3.1.13', '>='),
+                    'APC version must be at least 3.1.13 when using PHP 5.4',
+                    'Upgrade your <strong>APC</strong> extension (3.1.13+).'
+                );
+            } else {
+                $this->addRequirement(
+                    version_compare(phpversion('apc'), '3.0.17', '>='),
+                    'APC version must be at least 3.0.17',
+                    'Upgrade your <strong>APC</strong> extension (3.0.17+).'
+                );
+            }
+        }
+
+        $this->addPhpIniRequirement('detect_unicode', false);
+
+        if (extension_loaded('suhosin')) {
+            $this->addPhpIniRequirement(
+                'suhosin.executor.include.whitelist',
+                create_function('$cfgValue', 'return false !== stripos($cfgValue, "phar");'),
+                false,
+                'suhosin.executor.include.whitelist must be configured correctly in php.ini',
+                'Add "<strong>phar</strong>" to <strong>suhosin.executor.include.whitelist</strong> in php.ini<a href="#phpini">*</a>.'
+            );
+        }
+
+        if (extension_loaded('xdebug')) {
+            $this->addPhpIniRequirement(
+                'xdebug.show_exception_trace', false, true
+            );
+
+            $this->addPhpIniRequirement(
+                'xdebug.scream', false, true
+            );
+
+            $this->addPhpIniRecommendation(
+                'xdebug.max_nesting_level',
+                create_function('$cfgValue', 'return $cfgValue > 100;'),
+                true,
+                'xdebug.max_nesting_level should be above 100 in php.ini',
+                'Set "<strong>xdebug.max_nesting_level</strong>" to e.g. "<strong>250</strong>" in php.ini<a href="#phpini">*</a> to stop Xdebug\'s infinite recursion protection erroneously throwing a fatal error in your project.'
+            );
+        }
+
+        $pcreVersion = defined('PCRE_VERSION') ? (float) PCRE_VERSION : null;
+
+        $this->addRequirement(
+            null !== $pcreVersion,
+            'PCRE extension must be available',
+            'Install the <strong>PCRE</strong> extension (version 8.0+).'
+        );
+
+        /* optional recommendations follow */
+
+        $this->addRecommendation(
+            file_get_contents(__FILE__) === file_get_contents(__DIR__.'/../vendor/sensio/distribution-bundle/Sensio/Bundle/DistributionBundle/Resources/skeleton/app/SymfonyRequirements.php'),
+            'Requirements file should be up-to-date',
+            'Your requirements file is outdated. Run composer install and re-check your configuration.'
+        );
+
+        $this->addRecommendation(
+            version_compare($installedPhpVersion, '5.3.4', '>='),
+            'You should use at least PHP 5.3.4 due to PHP bug #52083 in earlier versions',
+            'Your project might malfunction randomly due to PHP bug #52083 ("Notice: Trying to get property of non-object"). Install PHP 5.3.4 or newer.'
+        );
+
+        $this->addRecommendation(
+            version_compare($installedPhpVersion, '5.3.8', '>='),
+            'When using annotations you should have at least PHP 5.3.8 due to PHP bug #55156',
+            'Install PHP 5.3.8 or newer if your project uses annotations.'
+        );
+
+        $this->addRecommendation(
+            version_compare($installedPhpVersion, '5.4.0', '!='),
+            'You should not use PHP 5.4.0 due to the PHP bug #61453',
+            'Your project might not work properly due to the PHP bug #61453 ("Cannot dump definitions which have method calls"). Install PHP 5.4.1 or newer.'
+        );
+
+        $this->addRecommendation(
+            version_compare($installedPhpVersion, '5.4.11', '>='),
+            'When using the logout handler from the Symfony Security Component, you should have at least PHP 5.4.11 due to PHP bug #63379 (as a workaround, you can also set invalidate_session to false in the security logout handler configuration)',
+            'Install PHP 5.4.11 or newer if your project uses the logout handler from the Symfony Security Component.'
+        );
+
+        $this->addRecommendation(
+            (version_compare($installedPhpVersion, '5.3.18', '>=') && version_compare($installedPhpVersion, '5.4.0', '<'))
+            ||
+            version_compare($installedPhpVersion, '5.4.8', '>='),
+            'You should use PHP 5.3.18+ or PHP 5.4.8+ to always get nice error messages for fatal errors in the development environment due to PHP bug #61767/#60909',
+            'Install PHP 5.3.18+ or PHP 5.4.8+ if you want nice error messages for all fatal errors in the development environment.'
+        );
+
+        if (null !== $pcreVersion) {
+            $this->addRecommendation(
+                $pcreVersion >= 8.0,
+                sprintf('PCRE extension should be at least version 8.0 (%s installed)', $pcreVersion),
+                '<strong>PCRE 8.0+</strong> is preconfigured in PHP since 5.3.2 but you are using an outdated version of it. Symfony probably works anyway but it is recommended to upgrade your PCRE extension.'
+            );
+        }
+
+        $this->addRecommendation(
+            class_exists('DomDocument'),
+            'PHP-XML module should be installed',
+            'Install and enable the <strong>PHP-XML</strong> module.'
+        );
+
+        $this->addRecommendation(
+            function_exists('mb_strlen'),
+            'mb_strlen() should be available',
+            'Install and enable the <strong>mbstring</strong> extension.'
+        );
+
+        $this->addRecommendation(
+            function_exists('iconv'),
+            'iconv() should be available',
+            'Install and enable the <strong>iconv</strong> extension.'
+        );
+
+        $this->addRecommendation(
+            function_exists('utf8_decode'),
+            'utf8_decode() should be available',
+            'Install and enable the <strong>XML</strong> extension.'
+        );
+
+        if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $this->addRecommendation(
+                function_exists('posix_isatty'),
+                'posix_isatty() should be available',
+                'Install and enable the <strong>php_posix</strong> extension (used to colorize the CLI output).'
+            );
+        }
+
+        $this->addRecommendation(
+            class_exists('Locale'),
+            'intl extension should be available',
+            'Install and enable the <strong>intl</strong> extension (used for validators).'
+        );
+
+        if (class_exists('Collator')) {
+            $this->addRecommendation(
+                null !== new Collator('fr_FR'),
+                'intl extension should be correctly configured',
+                'The intl extension does not behave properly. This problem is typical on PHP 5.3.X x64 WIN builds.'
+            );
+        }
+
+        if (class_exists('Locale')) {
+            if (defined('INTL_ICU_VERSION')) {
+                $version = INTL_ICU_VERSION;
+            } else {
+                $reflector = new ReflectionExtension('intl');
+
+                ob_start();
+                $reflector->info();
+                $output = strip_tags(ob_get_clean());
+
+                preg_match('/^ICU version +(?:=> )?(.*)$/m', $output, $matches);
+                $version = $matches[1];
+            }
+
+            $this->addRecommendation(
+                version_compare($version, '4.0', '>='),
+                'intl ICU version should be at least 4+',
+                'Upgrade your <strong>intl</strong> extension with a newer ICU version (4+).'
+            );
+        }
+
+        $accelerator =
+            (extension_loaded('eaccelerator') && ini_get('eaccelerator.enable'))
+            ||
+            (extension_loaded('apc') && ini_get('apc.enabled'))
+            ||
+            (extension_loaded('Zend OPcache') && ini_get('opcache.enable'))
+            ||
+            (extension_loaded('xcache') && ini_get('xcache.cacher'))
+            ||
+            (extension_loaded('wincache') && ini_get('wincache.ocenabled'))
+        ;
+
+        $this->addRecommendation(
+            $accelerator,
+            'a PHP accelerator should be installed',
+            'Install and enable a <strong>PHP accelerator</strong> like APC (highly recommended).'
+        );
+
+        $this->addPhpIniRecommendation('short_open_tag', false);
+
+        $this->addPhpIniRecommendation('magic_quotes_gpc', false, true);
+
+        $this->addPhpIniRecommendation('register_globals', false, true);
+
+        $this->addPhpIniRecommendation('session.auto_start', false);
+
+        $this->addRecommendation(
+            class_exists('PDO'),
+            'PDO should be installed',
+            'Install <strong>PDO</strong> (mandatory for Doctrine).'
+        );
+
+        if (class_exists('PDO')) {
+            $drivers = PDO::getAvailableDrivers();
+            $this->addRecommendation(
+                count($drivers),
+                sprintf('PDO should have some drivers installed (currently available: %s)', count($drivers) ? implode(', ', $drivers) : 'none'),
+                'Install <strong>PDO drivers</strong> (mandatory for Doctrine).'
+            );
+        }
+    }
+}
diff --git a/app/autoload.php b/app/autoload.php
new file mode 100644 (file)
index 0000000..70526bb
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+
+use Doctrine\Common\Annotations\AnnotationRegistry;
+use Composer\Autoload\ClassLoader;
+
+/**
+ * @var ClassLoader $loader
+ */
+$loader = require __DIR__.'/../vendor/autoload.php';
+
+AnnotationRegistry::registerLoader(array($loader, 'loadClass'));
+
+return $loader;
diff --git a/app/cache/.gitkeep b/app/cache/.gitkeep
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/app/check.php b/app/check.php
new file mode 100644 (file)
index 0000000..91b826b
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+
+require_once dirname(__FILE__).'/SymfonyRequirements.php';
+
+$symfonyRequirements = new SymfonyRequirements();
+
+$iniPath = $symfonyRequirements->getPhpIniConfigPath();
+
+echo "********************************\n";
+echo "*                              *\n";
+echo "*  Symfony requirements check  *\n";
+echo "*                              *\n";
+echo "********************************\n\n";
+
+echo $iniPath ? sprintf("* Configuration file used by PHP: %s\n\n", $iniPath) : "* WARNING: No configuration file (php.ini) used by PHP!\n\n";
+
+echo "** ATTENTION **\n";
+echo "*  The PHP CLI can use a different php.ini file\n";
+echo "*  than the one used with your web server.\n";
+if ('\\' == DIRECTORY_SEPARATOR) {
+    echo "*  (especially on the Windows platform)\n";
+}
+echo "*  To be on the safe side, please also launch the requirements check\n";
+echo "*  from your web server using the web/config.php script.\n";
+
+echo_title('Mandatory requirements');
+
+$checkPassed = true;
+foreach ($symfonyRequirements->getRequirements() as $req) {
+    /** @var $req Requirement */
+    echo_requirement($req);
+    if (!$req->isFulfilled()) {
+        $checkPassed = false;
+    }
+}
+
+echo_title('Optional recommendations');
+
+foreach ($symfonyRequirements->getRecommendations() as $req) {
+    echo_requirement($req);
+}
+
+exit($checkPassed ? 0 : 1);
+
+/**
+ * Prints a Requirement instance
+ */
+function echo_requirement(Requirement $requirement)
+{
+    $result = $requirement->isFulfilled() ? 'OK' : ($requirement->isOptional() ? 'WARNING' : 'ERROR');
+    echo ' ' . str_pad($result, 9);
+    echo $requirement->getTestMessage() . "\n";
+
+    if (!$requirement->isFulfilled()) {
+        echo sprintf("          %s\n\n", $requirement->getHelpText());
+    }
+}
+
+function echo_title($title)
+{
+    echo "\n** $title **\n\n";
+}
diff --git a/app/config/config.yml b/app/config/config.yml
new file mode 100644 (file)
index 0000000..1972a0e
--- /dev/null
@@ -0,0 +1,83 @@
+imports:
+    - { resource: parameters.yml }
+    - { resource: security.yml }
+
+framework:
+    #esi:             ~
+    translator:      { fallback: "%locale%" }
+    secret:          "%secret%"
+    router:
+        resource: "%kernel.root_dir%/config/routing.yml"
+        strict_requirements: ~
+    form:            ~
+    csrf_protection: ~
+    validation:      { enable_annotations: true }
+    templating:
+        engines: ['twig']
+        #assets_base_url: './'
+        #assets_version: SomeVersionScheme
+    default_locale:  "%locale%"
+    trusted_hosts:   ~
+    trusted_proxies: ~
+    session:
+        # handler_id set to null will use default session handler from php.ini
+        handler_id:  ~
+    fragments:       ~
+    http_method_override: true
+
+# Twig Configuration
+twig:
+    debug:            "%kernel.debug%"
+    strict_variables: "%kernel.debug%"
+
+# Assetic Configuration
+assetic:
+    debug:          "%kernel.debug%"
+    use_controller: false
+    bundles:        [ ]
+    #java: /usr/bin/java
+    filters:
+        cssrewrite: ~
+        #closure:
+        #    jar: "%kernel.root_dir%/Resources/java/compiler.jar"
+        #yui_css:
+        #    jar: "%kernel.root_dir%/Resources/java/yuicompressor-2.4.7.jar"
+
+# Doctrine Configuration
+doctrine:
+    dbal:
+        driver:   "%database_driver%"
+        host:     "%database_host%"
+        port:     "%database_port%"
+        dbname:   "%database_name%"
+        user:     "%database_user%"
+        password: "%database_password%"
+        charset:  UTF8
+        # if using pdo_sqlite as your database driver, add the path in parameters.yml
+        # e.g. database_path: "%kernel.root_dir%/data/data.db3"
+        # path:     "%database_path%"
+
+    orm:
+        auto_generate_proxy_classes: "%kernel.debug%"
+        auto_mapping: true
+
+# Swiftmailer Configuration
+swiftmailer:
+    transport: "%mailer_transport%"
+    host:      "%mailer_host%"
+    username:  "%mailer_user%"
+    password:  "%mailer_password%"
+    spool:     { type: memory }
+
+fos_user:
+    db_driver: orm
+    firewall_name: main
+    user_class: Mixstore\UserBundle\Entity\User
+    registration:
+        form:
+            type: mixstore_user_registration
+            validation_groups: [MixstoreRegistration]
+    profile:
+        form:
+            type: mixstore_user_profile
+            validation_groups: [MixstoreProfile]
diff --git a/app/config/config_dev.yml b/app/config/config_dev.yml
new file mode 100644 (file)
index 0000000..914c34a
--- /dev/null
@@ -0,0 +1,36 @@
+imports:
+    - { resource: config.yml }
+
+framework:
+    router:
+        resource: "%kernel.root_dir%/config/routing_dev.yml"
+        strict_requirements: true
+    profiler: { only_exceptions: false }
+
+web_profiler:
+    toolbar: true
+    intercept_redirects: false
+
+monolog:
+    handlers:
+        main:
+            type:   stream
+            path:   "%kernel.logs_dir%/%kernel.environment%.log"
+            level:  debug
+        console:
+            type:   console
+            bubble: false
+        # uncomment to get logging in your browser
+        # you may have to allow bigger header sizes in your Web server configuration
+        #firephp:
+        #    type:   firephp
+        #    level:  info
+        #chromephp:
+        #    type:   chromephp
+        #    level:  info
+
+assetic:
+    use_controller: true
+
+#swiftmailer:
+#    delivery_address: me@example.com
diff --git a/app/config/config_prod.yml b/app/config/config_prod.yml
new file mode 100644 (file)
index 0000000..342837a
--- /dev/null
@@ -0,0 +1,25 @@
+imports:
+    - { resource: config.yml }
+
+#framework:
+#    validation:
+#        cache: apc
+
+#doctrine:
+#    orm:
+#        metadata_cache_driver: apc
+#        result_cache_driver: apc
+#        query_cache_driver: apc
+
+monolog:
+    handlers:
+        main:
+            type:         fingers_crossed
+            action_level: error
+            handler:      nested
+        nested:
+            type:  stream
+            path:  "%kernel.logs_dir%/%kernel.environment%.log"
+            level: debug
+        console:
+            type:  console
diff --git a/app/config/config_test.yml b/app/config/config_test.yml
new file mode 100644 (file)
index 0000000..2f6d925
--- /dev/null
@@ -0,0 +1,16 @@
+imports:
+    - { resource: config_dev.yml }
+
+framework:
+    test: ~
+    session:
+        storage_id: session.storage.mock_file
+    profiler:
+        collect: false
+
+web_profiler:
+    toolbar: false
+    intercept_redirects: false
+
+swiftmailer:
+    disable_delivery: true
diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist
new file mode 100644 (file)
index 0000000..8b317c2
--- /dev/null
@@ -0,0 +1,15 @@
+parameters:
+    database_driver:   pdo_mysql
+    database_host:     127.0.0.1
+    database_port:     ~
+    database_name:     symfony
+    database_user:     root
+    database_password: ~
+
+    mailer_transport:  smtp
+    mailer_host:       127.0.0.1
+    mailer_user:       ~
+    mailer_password:   ~
+
+    locale:            en
+    secret:            ThisTokenIsNotSoSecretChangeIt
diff --git a/app/config/routing.yml b/app/config/routing.yml
new file mode 100644 (file)
index 0000000..5b942db
--- /dev/null
@@ -0,0 +1,8 @@
+mixstore_static:
+    resource: "@MixstoreStaticBundle/Resources/config/routing.yml"
+
+mixstore_store:
+    resource: "@MixstoreStoreBundle/Resources/config/routing.yml"
+
+mixstore_user:
+    resource: "@MixstoreUserBundle/Resources/config/routing.yml"
diff --git a/app/config/routing_dev.yml b/app/config/routing_dev.yml
new file mode 100644 (file)
index 0000000..ff93a02
--- /dev/null
@@ -0,0 +1,14 @@
+_wdt:
+    resource: "@WebProfilerBundle/Resources/config/routing/wdt.xml"
+    prefix:   /_wdt
+
+_profiler:
+    resource: "@WebProfilerBundle/Resources/config/routing/profiler.xml"
+    prefix:   /_profiler
+
+_configurator:
+    resource: "@SensioDistributionBundle/Resources/config/routing/webconfigurator.xml"
+    prefix:   /_configurator
+
+_main:
+    resource: routing.yml
diff --git a/app/config/security.yml b/app/config/security.yml
new file mode 100644 (file)
index 0000000..65642a4
--- /dev/null
@@ -0,0 +1,37 @@
+security:
+    encoders:
+        FOS\UserBundle\Model\UserInterface: sha512
+
+    role_hierarchy:
+        ROLE_ADMIN: ROLE_USER
+        ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
+
+    providers:
+        fos_userbundle:
+            id: fos_user.user_provider.username
+
+    firewalls:
+        main:
+            pattern: ^/
+            form_login:
+                provider: fos_userbundle
+                csrf_provider: form.csrf_provider
+                login_path: fos_user_security_login 
+                check_path: fos_user_security_check
+                #http://fr.openclassrooms.com/forum/sujet/redirection-after-login-fosuser-96549
+                always_use_default_target_path: true
+                default_target_path: /board
+            logout:
+                path: /security/logout
+                target: /
+            anonymous: true
+        dev:
+            pattern:  ^/(_(profiler|wdt)|css|images|js)/
+            security: false
+
+    access_control:
+        - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
+        - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
+        - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
+        - { path: ^/admin/, role: ROLE_ADMIN }
+        #- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
diff --git a/app/console b/app/console
new file mode 100755 (executable)
index 0000000..fa6a36e
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env php
+<?php
+
+// if you don't want to setup permissions the proper way, just uncomment the following PHP line
+// read http://symfony.com/doc/current/book/installation.html#configuration-and-setup for more information
+//umask(0000);
+
+set_time_limit(0);
+
+require_once __DIR__.'/bootstrap.php.cache';
+require_once __DIR__.'/AppKernel.php';
+
+use Symfony\Bundle\FrameworkBundle\Console\Application;
+use Symfony\Component\Console\Input\ArgvInput;
+use Symfony\Component\Debug\Debug;
+
+$input = new ArgvInput();
+$env = $input->getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev');
+$debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(array('--no-debug', '')) && $env !== 'prod';
+
+if ($debug) {
+    Debug::enable();
+}
+
+$kernel = new AppKernel($env, $debug);
+$application = new Application($kernel);
+$application->run($input);
diff --git a/app/logs/.gitkeep b/app/logs/.gitkeep
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/app/phpunit.xml.dist b/app/phpunit.xml.dist
new file mode 100644 (file)
index 0000000..82a3a08
--- /dev/null
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- http://phpunit.de/manual/current/en/appendixes.configuration.html -->
+<phpunit
+    backupGlobals               = "false"
+    backupStaticAttributes      = "false"
+    colors                      = "true"
+    convertErrorsToExceptions   = "true"
+    convertNoticesToExceptions  = "true"
+    convertWarningsToExceptions = "true"
+    processIsolation            = "false"
+    stopOnFailure               = "false"
+    syntaxCheck                 = "false"
+    bootstrap                   = "bootstrap.php.cache" >
+
+    <testsuites>
+        <testsuite name="Project Test Suite">
+            <directory>../src/*/*Bundle/Tests</directory>
+            <directory>../src/*/Bundle/*Bundle/Tests</directory>
+        </testsuite>
+    </testsuites>
+
+    <!--
+    <php>
+        <server name="KERNEL_DIR" value="/path/to/your/app/" />
+    </php>
+    -->
+
+    <filter>
+        <whitelist>
+            <directory>../src</directory>
+            <exclude>
+                <directory>../src/*/*Bundle/Resources</directory>
+                <directory>../src/*/*Bundle/Tests</directory>
+                <directory>../src/*/Bundle/*Bundle/Resources</directory>
+                <directory>../src/*/Bundle/*Bundle/Tests</directory>
+            </exclude>
+        </whitelist>
+    </filter>
+
+</phpunit>
diff --git a/composer.json b/composer.json
new file mode 100644 (file)
index 0000000..f3dc0d5
--- /dev/null
@@ -0,0 +1,53 @@
+{
+    "name": "symfony/framework-standard-edition",
+    "license": "MIT",
+    "type": "project",
+    "description": "The \"Symfony Standard Edition\" distribution",
+    "autoload": {
+        "psr-0": { "": "src/" }
+    },
+    "require": {
+        "php": ">=5.3.3",
+        "symfony/symfony": "~2.4",
+        "doctrine/orm": "~2.2,>=2.2.3",
+        "doctrine/doctrine-bundle": "~1.2",
+        "twig/extensions": "~1.0",
+        "symfony/assetic-bundle": "~2.3",
+        "symfony/swiftmailer-bundle": "~2.3",
+        "symfony/monolog-bundle": "~2.4",
+        "sensio/distribution-bundle": "~2.3",
+        "sensio/framework-extra-bundle": "~3.0",
+        "sensio/generator-bundle": "~2.3",
+        "incenteev/composer-parameter-handler": "~2.0",
+        "friendsofsymfony/user-bundle": "~2.0@dev"
+    },
+    "scripts": {
+        "post-install-cmd": [
+            "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
+            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
+            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
+            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
+            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile"
+        ],
+        "post-update-cmd": [
+            "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
+            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
+            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
+            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
+            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile"
+        ]
+    },
+    "config": {
+        "bin-dir": "bin"
+    },
+    "extra": {
+        "symfony-app-dir": "app",
+        "symfony-web-dir": "web",
+        "incenteev-parameters": {
+            "file": "app/config/parameters.yml"
+        },
+        "branch-alias": {
+            "dev-master": "2.4-dev"
+        }
+    }
+}
diff --git a/composer.lock b/composer.lock
new file mode 100644 (file)
index 0000000..648c638
--- /dev/null
@@ -0,0 +1,1657 @@
+{
+    "_readme": [
+        "This file locks the dependencies of your project to a known state",
+        "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+        "This file is @generated automatically"
+    ],
+    "hash": "297297b8355018bf874ad9e6c8129078",
+    "packages": [
+        {
+            "name": "doctrine/annotations",
+            "version": "v1.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/annotations.git",
+                "reference": "d9b1a37e9351ddde1f19f09a02e3d6ee92e82efd"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/annotations/zipball/d9b1a37e9351ddde1f19f09a02e3d6ee92e82efd",
+                "reference": "d9b1a37e9351ddde1f19f09a02e3d6ee92e82efd",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/lexer": "1.*",
+                "php": ">=5.3.2"
+            },
+            "require-dev": {
+                "doctrine/cache": "1.*",
+                "phpunit/phpunit": "4.*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.3.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Doctrine\\Common\\Annotations\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com",
+                    "homepage": "http://www.jwage.com/",
+                    "role": "Creator"
+                },
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com",
+                    "homepage": "http://www.instaclick.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com",
+                    "homepage": "http://jmsyst.com",
+                    "role": "Developer of wrapped JMSSerializerBundle"
+                }
+            ],
+            "description": "Docblock Annotations Parser",
+            "homepage": "http://www.doctrine-project.org",
+            "keywords": [
+                "annotations",
+                "docblock",
+                "parser"
+            ],
+            "time": "2014-07-06 15:52:21"
+        },
+        {
+            "name": "doctrine/cache",
+            "version": "v1.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/cache.git",
+                "reference": "e16d7adf45664a50fa86f515b6d5e7f670130449"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/cache/zipball/e16d7adf45664a50fa86f515b6d5e7f670130449",
+                "reference": "e16d7adf45664a50fa86f515b6d5e7f670130449",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2"
+            },
+            "conflict": {
+                "doctrine/common": ">2.2,<2.4"
+            },
+            "require-dev": {
+                "phpunit/phpunit": ">=3.7",
+                "satooshi/php-coveralls": "~0.6"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Doctrine\\Common\\Cache\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com",
+                    "homepage": "http://www.jwage.com/",
+                    "role": "Creator"
+                },
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com",
+                    "homepage": "http://www.instaclick.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com",
+                    "homepage": "http://jmsyst.com",
+                    "role": "Developer of wrapped JMSSerializerBundle"
+                }
+            ],
+            "description": "Caching library offering an object-oriented API for many cache backends",
+            "homepage": "http://www.doctrine-project.org",
+            "keywords": [
+                "cache",
+                "caching"
+            ],
+            "time": "2013-10-25 19:04:14"
+        },
+        {
+            "name": "doctrine/collections",
+            "version": "v1.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/collections.git",
+                "reference": "b99c5c46c87126201899afe88ec490a25eedd6a2"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/collections/zipball/b99c5c46c87126201899afe88ec490a25eedd6a2",
+                "reference": "b99c5c46c87126201899afe88ec490a25eedd6a2",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.2.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Doctrine\\Common\\Collections\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jonathan H. Wage",
+                    "email": "jonwage@gmail.com",
+                    "homepage": "http://www.jwage.com/",
+                    "role": "Creator"
+                },
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com",
+                    "homepage": "http://www.instaclick.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com",
+                    "homepage": "https://github.com/schmittjoh",
+                    "role": "Developer of wrapped JMSSerializerBundle"
+                }
+            ],
+            "description": "Collections Abstraction library",
+            "homepage": "http://www.doctrine-project.org",
+            "keywords": [
+                "array",
+                "collections",
+                "iterator"
+            ],
+            "time": "2014-02-03 23:07:43"
+        },
+        {
+            "name": "doctrine/common",
+            "version": "v2.4.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/common.git",
+                "reference": "5db6ab40e4c531f14dad4ca96a394dfce5d4255b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/common/zipball/5db6ab40e4c531f14dad4ca96a394dfce5d4255b",
+                "reference": "5db6ab40e4c531f14dad4ca96a394dfce5d4255b",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/annotations": "1.*",
+                "doctrine/cache": "1.*",
+                "doctrine/collections": "1.*",
+                "doctrine/inflector": "1.*",
+                "doctrine/lexer": "1.*",
+                "php": ">=5.3.2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~3.7"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.4.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Doctrine\\Common\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com",
+                    "homepage": "http://www.jwage.com/",
+                    "role": "Creator"
+                },
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com",
+                    "homepage": "http://www.instaclick.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com",
+                    "homepage": "http://jmsyst.com",
+                    "role": "Developer of wrapped JMSSerializerBundle"
+                }
+            ],
+            "description": "Common Library for Doctrine projects",
+            "homepage": "http://www.doctrine-project.org",
+            "keywords": [
+                "annotations",
+                "collections",
+                "eventmanager",
+                "persistence",
+                "spl"
+            ],
+            "time": "2014-05-21 19:28:51"
+        },
+        {
+            "name": "doctrine/dbal",
+            "version": "v2.4.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/dbal.git",
+                "reference": "fec965d330c958e175c39e61c3f6751955af32d0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/dbal/zipball/fec965d330c958e175c39e61c3f6751955af32d0",
+                "reference": "fec965d330c958e175c39e61c3f6751955af32d0",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/common": "~2.4",
+                "php": ">=5.3.2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "3.7.*",
+                "symfony/console": "~2.0"
+            },
+            "suggest": {
+                "symfony/console": "Allows use of the command line interface"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Doctrine\\DBAL\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com",
+                    "homepage": "http://www.jwage.com/",
+                    "role": "Creator"
+                },
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com",
+                    "homepage": "http://www.instaclick.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                }
+            ],
+            "description": "Database Abstraction Layer",
+            "homepage": "http://www.doctrine-project.org",
+            "keywords": [
+                "database",
+                "dbal",
+                "persistence",
+                "queryobject"
+            ],
+            "time": "2014-01-01 16:43:57"
+        },
+        {
+            "name": "doctrine/doctrine-bundle",
+            "version": "v1.2.0",
+            "target-dir": "Doctrine/Bundle/DoctrineBundle",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/DoctrineBundle.git",
+                "reference": "765b0d87fcc3e839c74817b7211258cbef3a4fb9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/765b0d87fcc3e839c74817b7211258cbef3a4fb9",
+                "reference": "765b0d87fcc3e839c74817b7211258cbef3a4fb9",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/dbal": ">=2.2,<2.5-dev",
+                "jdorn/sql-formatter": "~1.1",
+                "php": ">=5.3.2",
+                "symfony/doctrine-bridge": "~2.2",
+                "symfony/framework-bundle": "~2.2"
+            },
+            "require-dev": {
+                "doctrine/orm": ">=2.2,<2.5-dev",
+                "symfony/validator": "~2.2",
+                "symfony/yaml": "~2.2"
+            },
+            "suggest": {
+                "doctrine/orm": "The Doctrine ORM integration is optional in the bundle.",
+                "symfony/web-profiler-bundle": "to use the data collector"
+            },
+            "type": "symfony-bundle",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.2.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Doctrine\\Bundle\\DoctrineBundle": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                }
+            ],
+            "description": "Symfony DoctrineBundle",
+            "homepage": "http://www.doctrine-project.org",
+            "keywords": [
+                "database",
+                "dbal",
+                "orm",
+                "persistence"
+            ],
+            "time": "2013-03-25 20:13:59"
+        },
+        {
+            "name": "doctrine/inflector",
+            "version": "v1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/inflector.git",
+                "reference": "54b8333d2a5682afdc690060c1cf384ba9f47f08"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/inflector/zipball/54b8333d2a5682afdc690060c1cf384ba9f47f08",
+                "reference": "54b8333d2a5682afdc690060c1cf384ba9f47f08",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Doctrine\\Common\\Inflector\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com",
+                    "homepage": "http://www.jwage.com/",
+                    "role": "Creator"
+                },
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com",
+                    "homepage": "http://www.instaclick.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Johannes M. Schmitt",
+                    "email": "schmittjoh@gmail.com",
+                    "homepage": "http://jmsyst.com",
+                    "role": "Developer of wrapped JMSSerializerBundle"
+                }
+            ],
+            "description": "Common String Manipulations with regard to casing and singular/plural rules.",
+            "homepage": "http://www.doctrine-project.org",
+            "keywords": [
+                "inflection",
+                "pluarlize",
+                "singuarlize",
+                "string"
+            ],
+            "time": "2013-01-10 21:49:15"
+        },
+        {
+            "name": "doctrine/lexer",
+            "version": "v1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/lexer.git",
+                "reference": "2f708a85bb3aab5d99dab8be435abd73e0b18acb"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/lexer/zipball/2f708a85bb3aab5d99dab8be435abd73e0b18acb",
+                "reference": "2f708a85bb3aab5d99dab8be435abd73e0b18acb",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Doctrine\\Common\\Lexer\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com",
+                    "homepage": "http://www.instaclick.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com",
+                    "homepage": "http://jmsyst.com",
+                    "role": "Developer of wrapped JMSSerializerBundle"
+                }
+            ],
+            "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.",
+            "homepage": "http://www.doctrine-project.org",
+            "keywords": [
+                "lexer",
+                "parser"
+            ],
+            "time": "2013-01-12 18:59:04"
+        },
+        {
+            "name": "doctrine/orm",
+            "version": "v2.4.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/doctrine2.git",
+                "reference": "fc19c3b53dcd00e6584db40669fdd699c4671f97"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/doctrine2/zipball/fc19c3b53dcd00e6584db40669fdd699c4671f97",
+                "reference": "fc19c3b53dcd00e6584db40669fdd699c4671f97",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/collections": "~1.1",
+                "doctrine/dbal": "~2.4",
+                "ext-pdo": "*",
+                "php": ">=5.3.2",
+                "symfony/console": "~2.0"
+            },
+            "require-dev": {
+                "satooshi/php-coveralls": "dev-master",
+                "symfony/yaml": "~2.1"
+            },
+            "suggest": {
+                "symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
+            },
+            "bin": [
+                "bin/doctrine",
+                "bin/doctrine.php"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.4.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Doctrine\\ORM\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com",
+                    "homepage": "http://www.jwage.com/",
+                    "role": "Creator"
+                },
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com",
+                    "homepage": "http://www.instaclick.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                }
+            ],
+            "description": "Object-Relational-Mapper for PHP",
+            "homepage": "http://www.doctrine-project.org",
+            "keywords": [
+                "database",
+                "orm"
+            ],
+            "time": "2014-07-11 03:05:53"
+        },
+        {
+            "name": "friendsofsymfony/user-bundle",
+            "version": "dev-master",
+            "target-dir": "FOS/UserBundle",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/FriendsOfSymfony/FOSUserBundle.git",
+                "reference": "ef7ca325929ff102fff521653a2e3b88c7a40361"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/FriendsOfSymfony/FOSUserBundle/zipball/ef7ca325929ff102fff521653a2e3b88c7a40361",
+                "reference": "ef7ca325929ff102fff521653a2e3b88c7a40361",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2",
+                "symfony/form": "~2.1",
+                "symfony/framework-bundle": "~2.1",
+                "symfony/security-bundle": "~2.1"
+            },
+            "require-dev": {
+                "doctrine/doctrine-bundle": "*",
+                "swiftmailer/swiftmailer": ">=4.3, <6.0",
+                "symfony/validator": "~2.1",
+                "symfony/yaml": "~2.1",
+                "twig/twig": "~1.5",
+                "willdurand/propel-typehintable-behavior": "dev-master"
+            },
+            "suggest": {
+                "willdurand/propel-typehintable-behavior": "Needed when using the propel implementation"
+            },
+            "type": "symfony-bundle",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "FOS\\UserBundle": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Christophe Coevoet",
+                    "email": "stof@notk.org"
+                },
+                {
+                    "name": "Thibault Duplessis",
+                    "email": "thibault.duplessis@gmail.com",
+                    "homepage": "http://ornicar.github.com"
+                },
+                {
+                    "name": "FriendsOfSymfony Community",
+                    "homepage": "https://github.com/friendsofsymfony/FOSUserBundle/contributors"
+                }
+            ],
+            "description": "Symfony FOSUserBundle",
+            "homepage": "http://friendsofsymfony.github.com",
+            "keywords": [
+                "User management"
+            ],
+            "time": "2014-07-09 10:33:42"
+        },
+        {
+            "name": "incenteev/composer-parameter-handler",
+            "version": "v2.1.0",
+            "target-dir": "Incenteev/ParameterHandler",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Incenteev/ParameterHandler.git",
+                "reference": "143272a0a09c62616a3c8011fc165a10c6b35241"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Incenteev/ParameterHandler/zipball/143272a0a09c62616a3c8011fc165a10c6b35241",
+                "reference": "143272a0a09c62616a3c8011fc165a10c6b35241",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3",
+                "symfony/yaml": "~2.0"
+            },
+            "require-dev": {
+                "composer/composer": "1.0.*@dev",
+                "phpspec/prophecy-phpunit": "~1.0",
+                "symfony/filesystem": "~2.2"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Incenteev\\ParameterHandler": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Christophe Coevoet",
+                    "email": "stof@notk.org"
+                }
+            ],
+            "description": "Composer script handling your ignored parameter file",
+            "homepage": "https://github.com/Incenteev/ParameterHandler",
+            "keywords": [
+                "parameters management"
+            ],
+            "time": "2013-12-07 10:10:39"
+        },
+        {
+            "name": "jdorn/sql-formatter",
+            "version": "v1.2.17",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/jdorn/sql-formatter.git",
+                "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/jdorn/sql-formatter/zipball/64990d96e0959dff8e059dfcdc1af130728d92bc",
+                "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.2.4"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "3.7.*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.3.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "lib"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jeremy Dorn",
+                    "email": "jeremy@jeremydorn.com",
+                    "homepage": "http://jeremydorn.com/"
+                }
+            ],
+            "description": "a PHP SQL highlighting library",
+            "homepage": "https://github.com/jdorn/sql-formatter/",
+            "keywords": [
+                "highlight",
+                "sql"
+            ],
+            "time": "2014-01-12 16:20:24"
+        },
+        {
+            "name": "kriswallsmith/assetic",
+            "version": "v1.1.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/kriswallsmith/assetic.git",
+                "reference": "735cffd3982c6e8cdebe292d5db39d077f65890f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/kriswallsmith/assetic/zipball/735cffd3982c6e8cdebe292d5db39d077f65890f",
+                "reference": "735cffd3982c6e8cdebe292d5db39d077f65890f",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.1",
+                "symfony/process": "~2.1"
+            },
+            "require-dev": {
+                "cssmin/cssmin": "*",
+                "joliclic/javascript-packer": "*",
+                "kamicane/packager": "*",
+                "leafo/lessphp": "*",
+                "leafo/scssphp": "*",
+                "leafo/scssphp-compass": "*",
+                "mrclay/minify": "*",
+                "phpunit/phpunit": "~3.7",
+                "ptachoire/cssembed": "*",
+                "twig/twig": "~1.6"
+            },
+            "suggest": {
+                "leafo/lessphp": "Assetic provides the integration with the lessphp LESS compiler",
+                "leafo/scssphp": "Assetic provides the integration with the scssphp SCSS compiler",
+                "leafo/scssphp-compass": "Assetic provides the integration with the SCSS compass plugin",
+                "ptachoire/cssembed": "Assetic provides the integration with phpcssembed to embed data uris",
+                "twig/twig": "Assetic provides the integration with the Twig templating engine"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Assetic": "src/"
+                },
+                "files": [
+                    "src/functions.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Kris Wallsmith",
+                    "email": "kris.wallsmith@gmail.com",
+                    "homepage": "http://kriswallsmith.net/"
+                }
+            ],
+            "description": "Asset Management for PHP",
+            "homepage": "https://github.com/kriswallsmith/assetic",
+            "keywords": [
+                "assets",
+                "compression",
+                "minification"
+            ],
+            "time": "2013-07-19 00:03:27"
+        },
+        {
+            "name": "monolog/monolog",
+            "version": "1.10.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Seldaek/monolog.git",
+                "reference": "25b16e801979098cb2f120e697bfce454b18bf23"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/25b16e801979098cb2f120e697bfce454b18bf23",
+                "reference": "25b16e801979098cb2f120e697bfce454b18bf23",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0",
+                "psr/log": "~1.0"
+            },
+            "require-dev": {
+                "aws/aws-sdk-php": "~2.4, >2.4.8",
+                "doctrine/couchdb": "~1.0@dev",
+                "graylog2/gelf-php": "~1.0",
+                "phpunit/phpunit": "~3.7.0",
+                "raven/raven": "~0.5",
+                "ruflin/elastica": "0.90.*"
+            },
+            "suggest": {
+                "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
+                "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
+                "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
+                "ext-mongo": "Allow sending log messages to a MongoDB server",
+                "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
+                "raven/raven": "Allow sending log messages to a Sentry server",
+                "rollbar/rollbar": "Allow sending log messages to Rollbar",
+                "ruflin/elastica": "Allow sending log messages to an Elastic Search server"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.10.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Monolog\\": "src/Monolog"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "j.boggiano@seld.be",
+                    "homepage": "http://seld.be",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
+            "homepage": "http://github.com/Seldaek/monolog",
+            "keywords": [
+                "log",
+                "logging",
+                "psr-3"
+            ],
+            "time": "2014-06-04 16:30:04"
+        },
+        {
+            "name": "psr/log",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/log.git",
+                "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
+                "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
+                "shasum": ""
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Psr\\Log\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for logging libraries",
+            "keywords": [
+                "log",
+                "psr",
+                "psr-3"
+            ],
+            "time": "2012-12-21 11:40:51"
+        },
+        {
+            "name": "sensio/distribution-bundle",
+            "version": "v2.3.4",
+            "target-dir": "Sensio/Bundle/DistributionBundle",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sensiolabs/SensioDistributionBundle.git",
+                "reference": "66df91b4bd637a83299d8072aed3658bfd3b3021"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sensiolabs/SensioDistributionBundle/zipball/66df91b4bd637a83299d8072aed3658bfd3b3021",
+                "reference": "66df91b4bd637a83299d8072aed3658bfd3b3021",
+                "shasum": ""
+            },
+            "require": {
+                "symfony/framework-bundle": "~2.2"
+            },
+            "type": "symfony-bundle",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.3.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Sensio\\Bundle\\DistributionBundle": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                }
+            ],
+            "description": "The base bundle for the Symfony Distributions",
+            "keywords": [
+                "configuration",
+                "distribution"
+            ],
+            "time": "2013-08-22 05:04:53"
+        },
+        {
+            "name": "sensio/framework-extra-bundle",
+            "version": "v3.0.1",
+            "target-dir": "Sensio/Bundle/FrameworkExtraBundle",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sensiolabs/SensioFrameworkExtraBundle.git",
+                "reference": "dbc1e5aa830f3bf8063b29102add3c1e476d616e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sensiolabs/SensioFrameworkExtraBundle/zipball/dbc1e5aa830f3bf8063b29102add3c1e476d616e",
+                "reference": "dbc1e5aa830f3bf8063b29102add3c1e476d616e",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/common": "~2.2",
+                "symfony/framework-bundle": "~2.5"
+            },
+            "require-dev": {
+                "symfony/expression-language": "~2.4",
+                "symfony/security-bundle": "~2.4"
+            },
+            "suggest": {
+                "symfony/expression-language": "",
+                "symfony/security-bundle": ""
+            },
+            "type": "symfony-bundle",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Sensio\\Bundle\\FrameworkExtraBundle": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                }
+            ],
+            "description": "This bundle provides a way to configure your controllers with annotations",
+            "keywords": [
+                "annotations",
+                "controllers"
+            ],
+            "time": "2014-05-22 23:27:44"
+        },
+        {
+            "name": "sensio/generator-bundle",
+            "version": "v2.3.5",
+            "target-dir": "Sensio/Bundle/GeneratorBundle",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sensiolabs/SensioGeneratorBundle.git",
+                "reference": "8b7a33aa3d22388443b6de0b0cf184122e9f60d2"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sensiolabs/SensioGeneratorBundle/zipball/8b7a33aa3d22388443b6de0b0cf184122e9f60d2",
+                "reference": "8b7a33aa3d22388443b6de0b0cf184122e9f60d2",
+                "shasum": ""
+            },
+            "require": {
+                "symfony/console": "~2.0",
+                "symfony/framework-bundle": "~2.2"
+            },
+            "require-dev": {
+                "doctrine/orm": "~2.2,>=2.2.3",
+                "symfony/doctrine-bridge": "~2.2",
+                "twig/twig": "~1.11"
+            },
+            "type": "symfony-bundle",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.3.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Sensio\\Bundle\\GeneratorBundle": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                }
+            ],
+            "description": "This bundle generates code for you",
+            "time": "2014-04-28 14:01:06"
+        },
+        {
+            "name": "swiftmailer/swiftmailer",
+            "version": "v5.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/swiftmailer/swiftmailer.git",
+                "reference": "2b9af56cc676c338d52fca4c657e5bdff73bb7af"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/2b9af56cc676c338d52fca4c657e5bdff73bb7af",
+                "reference": "2b9af56cc676c338d52fca4c657e5bdff73bb7af",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.2.4"
+            },
+            "require-dev": {
+                "mockery/mockery": "~0.9.1"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.2-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "lib/swift_required.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                },
+                {
+                    "name": "Chris Corbyn"
+                }
+            ],
+            "description": "Swiftmailer, free feature-rich PHP mailer",
+            "homepage": "http://swiftmailer.org",
+            "keywords": [
+                "mail",
+                "mailer"
+            ],
+            "time": "2014-06-13 11:44:54"
+        },
+        {
+            "name": "symfony/assetic-bundle",
+            "version": "v2.3.0",
+            "target-dir": "Symfony/Bundle/AsseticBundle",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/AsseticBundle.git",
+                "reference": "146dd3cb46b302bd471560471c6aaa930483dac1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/AsseticBundle/zipball/146dd3cb46b302bd471560471c6aaa930483dac1",
+                "reference": "146dd3cb46b302bd471560471c6aaa930483dac1",
+                "shasum": ""
+            },
+            "require": {
+                "kriswallsmith/assetic": "~1.1",
+                "php": ">=5.3.0",
+                "symfony/framework-bundle": "~2.1"
+            },
+            "require-dev": {
+                "symfony/class-loader": "~2.1",
+                "symfony/console": "~2.1",
+                "symfony/css-selector": "~2.1",
+                "symfony/dom-crawler": "~2.1",
+                "symfony/form": "~2.1",
+                "symfony/twig-bundle": "~2.1",
+                "symfony/yaml": "~2.1"
+            },
+            "suggest": {
+                "symfony/twig-bundle": "~2.1"
+            },
+            "type": "symfony-bundle",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Symfony\\Bundle\\AsseticBundle": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Kris Wallsmith",
+                    "email": "kris.wallsmith@gmail.com",
+                    "homepage": "http://kriswallsmith.net/"
+                }
+            ],
+            "description": "Integrates Assetic into Symfony2",
+            "homepage": "https://github.com/symfony/AsseticBundle",
+            "keywords": [
+                "assets",
+                "compression",
+                "minification"
+            ],
+            "time": "2013-05-16 05:32:23"
+        },
+        {
+            "name": "symfony/icu",
+            "version": "v1.2.1",
+            "target-dir": "Symfony/Component/Icu",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/Icu.git",
+                "reference": "98e197da54df1f966dd5e8a4992135703569c987"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/Icu/zipball/98e197da54df1f966dd5e8a4992135703569c987",
+                "reference": "98e197da54df1f966dd5e8a4992135703569c987",
+                "shasum": ""
+            },
+            "require": {
+                "lib-icu": ">=4.4",
+                "php": ">=5.3.3",
+                "symfony/intl": "~2.3"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Symfony\\Component\\Icu\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                },
+                {
+                    "name": "Bernhard Schussek",
+                    "email": "bschussek@gmail.com"
+                }
+            ],
+            "description": "Contains an excerpt of the ICU data and classes to load it.",
+            "homepage": "http://symfony.com",
+            "keywords": [
+                "icu",
+                "intl"
+            ],
+            "time": "2013-10-04 10:06:38"
+        },
+        {
+            "name": "symfony/monolog-bundle",
+            "version": "v2.6.0",
+            "target-dir": "Symfony/Bundle/MonologBundle",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/MonologBundle.git",
+                "reference": "e1d4aa99c7440b11e9dfbfef7ed63084401dbc6a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/MonologBundle/zipball/e1d4aa99c7440b11e9dfbfef7ed63084401dbc6a",
+                "reference": "e1d4aa99c7440b11e9dfbfef7ed63084401dbc6a",
+                "shasum": ""
+            },
+            "require": {
+                "monolog/monolog": "~1.8",
+                "php": ">=5.3.2",
+                "symfony/config": "~2.3",
+                "symfony/dependency-injection": "~2.3",
+                "symfony/http-kernel": "~2.3",
+                "symfony/monolog-bridge": "~2.3"
+            },
+            "require-dev": {
+                "symfony/console": "~2.3",
+                "symfony/yaml": "~2.3"
+            },
+            "type": "symfony-bundle",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.6.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Symfony\\Bundle\\MonologBundle": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony MonologBundle",
+            "homepage": "http://symfony.com",
+            "keywords": [
+                "log",
+                "logging"
+            ],
+            "time": "2014-06-04 16:49:13"
+        },
+        {
+            "name": "symfony/swiftmailer-bundle",
+            "version": "v2.3.7",
+            "target-dir": "Symfony/Bundle/SwiftmailerBundle",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/SwiftmailerBundle.git",
+                "reference": "e98defd402f72e8b54a029ba4d3ac4cb51dc3577"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/SwiftmailerBundle/zipball/e98defd402f72e8b54a029ba4d3ac4cb51dc3577",
+                "reference": "e98defd402f72e8b54a029ba4d3ac4cb51dc3577",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2",
+                "swiftmailer/swiftmailer": ">=4.2.0,~5.0",
+                "symfony/swiftmailer-bridge": "~2.1"
+            },
+            "require-dev": {
+                "symfony/config": "~2.1",
+                "symfony/dependency-injection": "~2.1",
+                "symfony/http-kernel": "~2.1",
+                "symfony/yaml": "~2.1"
+            },
+            "type": "symfony-bundle",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.3-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Symfony\\Bundle\\SwiftmailerBundle": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony SwiftmailerBundle",
+            "homepage": "http://symfony.com",
+            "time": "2014-04-05 17:15:52"
+        },
+        {
+            "name": "symfony/symfony",
+            "version": "v2.5.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/symfony.git",
+                "reference": "e66ee967571b89234c90946fe0d50dad195ad29c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/symfony/zipball/e66ee967571b89234c90946fe0d50dad195ad29c",
+                "reference": "e66ee967571b89234c90946fe0d50dad195ad29c",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/common": "~2.2",
+                "php": ">=5.3.3",
+                "psr/log": "~1.0",
+                "symfony/icu": "~1.0",
+                "twig/twig": "~1.12"
+            },
+            "replace": {
+                "symfony/browser-kit": "self.version",
+                "symfony/class-loader": "self.version",
+                "symfony/config": "self.version",
+                "symfony/console": "self.version",
+                "symfony/css-selector": "self.version",
+                "symfony/debug": "self.version",
+                "symfony/dependency-injection": "self.version",
+                "symfony/doctrine-bridge": "self.version",
+                "symfony/dom-crawler": "self.version",
+                "symfony/event-dispatcher": "self.version",
+                "symfony/expression-language": "self.version",
+                "symfony/filesystem": "self.version",
+                "symfony/finder": "self.version",
+                "symfony/form": "self.version",
+                "symfony/framework-bundle": "self.version",
+                "symfony/http-foundation": "self.version",
+                "symfony/http-kernel": "self.version",
+                "symfony/intl": "self.version",
+                "symfony/locale": "self.version",
+                "symfony/monolog-bridge": "self.version",
+                "symfony/options-resolver": "self.version",
+                "symfony/process": "self.version",
+                "symfony/propel1-bridge": "self.version",
+                "symfony/property-access": "self.version",
+                "symfony/proxy-manager-bridge": "self.version",
+                "symfony/routing": "self.version",
+                "symfony/security": "self.version",
+                "symfony/security-acl": "self.version",
+                "symfony/security-bundle": "self.version",
+                "symfony/security-core": "self.version",
+                "symfony/security-csrf": "self.version",
+                "symfony/security-http": "self.version",
+                "symfony/serializer": "self.version",
+                "symfony/stopwatch": "self.version",
+                "symfony/swiftmailer-bridge": "self.version",
+                "symfony/templating": "self.version",
+                "symfony/translation": "self.version",
+                "symfony/twig-bridge": "self.version",
+                "symfony/twig-bundle": "self.version",
+                "symfony/validator": "self.version",
+                "symfony/web-profiler-bundle": "self.version",
+                "symfony/yaml": "self.version"
+            },
+            "require-dev": {
+                "doctrine/data-fixtures": "1.0.*",
+                "doctrine/dbal": "~2.2",
+                "doctrine/orm": "~2.2,>=2.2.3",
+                "egulias/email-validator": "1.1.0",
+                "ircmaxell/password-compat": "1.0.*",
+                "monolog/monolog": "~1.3",
+                "ocramius/proxy-manager": ">=0.3.1,<0.6-dev",
+                "propel/propel1": "1.6.*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.5-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Symfony\\": "src/"
+                },
+                "classmap": [
+                    "src/Symfony/Component/HttpFoundation/Resources/stubs",
+                    "src/Symfony/Component/Intl/Resources/stubs"
+                ],
+                "files": [
+                    "src/Symfony/Component/Intl/Resources/stubs/functions.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                }
+            ],
+            "description": "The Symfony PHP framework",
+            "homepage": "http://symfony.com",
+            "keywords": [
+                "framework"
+            ],
+            "time": "2014-07-15 15:39:46"
+        },
+        {
+            "name": "twig/extensions",
+            "version": "v1.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/fabpot/Twig-extensions.git",
+                "reference": "c0ab818595338dd5569369bfce2552d02cec5d50"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/fabpot/Twig-extensions/zipball/c0ab818595338dd5569369bfce2552d02cec5d50",
+                "reference": "c0ab818595338dd5569369bfce2552d02cec5d50",
+                "shasum": ""
+            },
+            "require": {
+                "twig/twig": "~1.12"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Twig_Extensions_": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                }
+            ],
+            "description": "Common additional features for Twig that do not directly belong in core",
+            "homepage": "https://github.com/fabpot/Twig-extensions",
+            "keywords": [
+                "i18n",
+                "text"
+            ],
+            "time": "2014-07-05 10:01:35"
+        },
+        {
+            "name": "twig/twig",
+            "version": "v1.16.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/fabpot/Twig.git",
+                "reference": "8ce37115802e257a984a82d38254884085060024"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/fabpot/Twig/zipball/8ce37115802e257a984a82d38254884085060024",
+                "reference": "8ce37115802e257a984a82d38254884085060024",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.2.4"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.16-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Twig_": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                },
+                {
+                    "name": "Armin Ronacher2",
+                    "email": "armin.ronacher@active-4.com",
+                    "role": "Project Founder"
+                },
+                {
+                    "name": "Twig Team",
+                    "homepage": "https://github.com/fabpot/Twig/graphs/contributors",
+                    "role": "Contributors"
+                }
+            ],
+            "description": "Twig, the flexible, fast, and secure template language for PHP",
+            "homepage": "http://twig.sensiolabs.org",
+            "keywords": [
+                "templating"
+            ],
+            "time": "2014-07-05 12:19:05"
+        }
+    ],
+    "packages-dev": [
+
+    ],
+    "aliases": [
+
+    ],
+    "minimum-stability": "stable",
+    "stability-flags": {
+        "friendsofsymfony/user-bundle": 20
+    },
+    "platform": {
+        "php": ">=5.3.3"
+    },
+    "platform-dev": [
+
+    ]
+}
diff --git a/resetCacheLogs.php b/resetCacheLogs.php
new file mode 100644 (file)
index 0000000..b72cb18
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+
+shell_exec
+('bash -c "
+    if [ -d app/cache ]; then
+        rm -rf app/cache/*
+    fi
+    if [ -d app/logs ]; then
+        rm -rf app/logs/*
+    fi
+    chmod 777 app/{cache,logs}
+" ');
diff --git a/src/.htaccess b/src/.htaccess
new file mode 100644 (file)
index 0000000..fb1de45
--- /dev/null
@@ -0,0 +1,7 @@
+<IfModule mod_authz_core.c>
+    Require all denied
+</IfModule>
+<IfModule !mod_authz_core.c>
+    Order deny,allow
+    Deny from all
+</IfModule>
diff --git a/src/Mixstore/StaticBundle/Controller/MainController.php b/src/Mixstore/StaticBundle/Controller/MainController.php
new file mode 100644 (file)
index 0000000..c73ce03
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+
+namespace Mixstore\StaticBundle\Controller;
+
+use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+
+class MainController extends Controller
+{
+       public function homeAction()
+       {
+               $pkgRepository = $this
+                       ->getDoctrine()
+                       ->getManager()
+                       ->getRepository('MixstoreStoreBundle:Package');
+               
+               //get news
+               $news = $pkgRepository
+                       ->getLastNews();
+               
+               //get images sources for carousel
+               $bannersArray = $pkgRepository
+                       ->getBannersUrls();
+               
+               return $this->render('MixstoreStaticBundle::home.html.twig', array(
+                       'bannersArray' => $bannersArray,
+                       'news' => $news,
+               ));
+       }
+       
+       public function aboutAction()
+       {
+               return $this->render('MixstoreStaticBundle::about.html.twig');
+       }
+       
+       public function policyAction()
+       {
+               return $this->render('MixstoreStaticBundle::policy.html.twig');
+       }
+}
diff --git a/src/Mixstore/StaticBundle/DependencyInjection/Configuration.php b/src/Mixstore/StaticBundle/DependencyInjection/Configuration.php
new file mode 100644 (file)
index 0000000..1707288
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+
+namespace Mixstore\MainBundle\DependencyInjection;
+
+use Symfony\Component\Config\Definition\Builder\TreeBuilder;
+use Symfony\Component\Config\Definition\ConfigurationInterface;
+
+/**
+ * This is the class that validates and merges configuration from your app/config files
+ *
+ * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
+ */
+class Configuration implements ConfigurationInterface
+{
+    /**
+     * {@inheritDoc}
+     */
+    public function getConfigTreeBuilder()
+    {
+        $treeBuilder = new TreeBuilder();
+        $rootNode = $treeBuilder->root('mixstore_static');
+
+        // Here you should define the parameters that are allowed to
+        // configure your bundle. See the documentation linked above for
+        // more information on that topic.
+
+        return $treeBuilder;
+    }
+}
diff --git a/src/Mixstore/StaticBundle/DependencyInjection/MixstoreStoreExtension.php b/src/Mixstore/StaticBundle/DependencyInjection/MixstoreStoreExtension.php
new file mode 100644 (file)
index 0000000..1fa333d
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+
+namespace Mixstore\MainBundle\DependencyInjection;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\Config\FileLocator;
+use Symfony\Component\HttpKernel\DependencyInjection\Extension;
+use Symfony\Component\DependencyInjection\Loader;
+
+/**
+ * This is the class that loads and manages your bundle configuration
+ *
+ * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
+ */
+class MixstoreStoreExtension extends Extension
+{
+    /**
+     * {@inheritDoc}
+     */
+    public function load(array $configs, ContainerBuilder $container)
+    {
+        $configuration = new Configuration();
+        $config = $this->processConfiguration($configuration, $configs);
+
+        $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
+        $loader->load('services.yml');
+    }
+}
diff --git a/src/Mixstore/StaticBundle/MixstoreStaticBundle.php b/src/Mixstore/StaticBundle/MixstoreStaticBundle.php
new file mode 100644 (file)
index 0000000..afb1c94
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+
+namespace Mixstore\StaticBundle;
+
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+class MixstoreStaticBundle extends Bundle
+{
+}
diff --git a/src/Mixstore/StaticBundle/Resources/config/routing.yml b/src/Mixstore/StaticBundle/Resources/config/routing.yml
new file mode 100644 (file)
index 0000000..21b055d
--- /dev/null
@@ -0,0 +1,11 @@
+mixstore_static_home:
+    pattern: /
+    defaults: { _controller: MixstoreStaticBundle:Main:home }
+
+mixstore_static_about:
+    pattern: /about
+    defaults: { _controller: MixstoreStaticBundle:Main:about }
+
+mixstore_static_policy:
+    pattern: /policy
+    defaults: { _controller: MixstoreStaticBundle:Main:policy }
diff --git a/src/Mixstore/StaticBundle/Resources/config/services.yml b/src/Mixstore/StaticBundle/Resources/config/services.yml
new file mode 100644 (file)
index 0000000..ea30561
--- /dev/null
@@ -0,0 +1 @@
+#empty
diff --git a/src/Mixstore/StaticBundle/Resources/views/about.html.twig b/src/Mixstore/StaticBundle/Resources/views/about.html.twig
new file mode 100644 (file)
index 0000000..0714614
--- /dev/null
@@ -0,0 +1,222 @@
+{% extends "::base.html.twig" %}
+
+{% block title %}{{ parent() }}about{% endblock %}
+
+{% block header %}
+{{ parent() }}
+<link rel="stylesheet" href="{{ asset('mixstore/css/static/about.css') }}">
+{% endblock %}
+
+{% block content %}
+
+<div id="maintext" class="row">
+
+<div class="col-xs-12 borderbottom">
+
+<h2>Origins</h2>
+
+In the late 1990's, three researchers wrote some code in MATLAB to classify data using 
+mixture models. Initially named XEM for "EM-algorithms on miXture models", 
+it was quickly renamed into mixmod, and rewritten in C++ from 2001. 
+Since then, mixmod has been extended in several directions including:
+<ul>
+       <li>supervised classification</li>
+       <li>categorical data handling</li>
+       <li>heterogeneous data handling</li>
+</ul>
+...and the code is constantly evolving. {# still in constant evolution #} 
+More details can be found on the <a href="http://www.mixmod.org">dedicated website</a>.
+
+There exist now many packages related to mixture models, each of them specialized in 
+some domain. Although mixmod can (arguably) be considered as one of the first of its kind, 
+it would be rather arbitrary to give him a central position. 
+That is why mixmod is "only" part of the mix-store.
+
+{# (mixmod permet de faire + de choses : renvoyer au site web + doc...) #}
+
+<h2>Summary</h2>
+
+Mixstore is a website gathering libraries dedicated to data modeling as 
+a mixture of probabilistic components. The computed mixture can be used 
+for various purposes including
+<ul>
+       <li>density estimation</li>
+       <li>clustering (unsupervised classification)</li>
+       <li>(supervised) classification</li>
+       <li>regression, ...</li>
+</ul>
+
+<h2>Example</h2>
+
+<p>
+To start using any of the softwares present in the store, we need a dataset. 
+We choose here an old classic: the Iris dataset introduced by Ronald Fisher in 1936. 
+Despite its classicity this dataset is not so easy to analyze, as we will see in the following. 
+</p>
+
+<p>
+The <a href="http://en.wikipedia.org/wiki/Iris_flower_data_set">Iris dataset</a> 
+contains 150 rows, each of them composed of 4 continuous attributes which 
+corresponds to some flowers measurements. 3 species are equally represented : (Iris) 
+Setosa, Versicolor and Virginica.
+</p>
+
+<p>
+       <figure>
+       <img src="{{ asset('mixstore/images/iris_pca.png') }}" alt="PCA components of iris dataset"/><br/>
+       <caption>The two first PCA components of Iris dataset (image found 
+       <a href="http://www.wanderinformatiker.at/unipages/general/img/iris_pca1.png">here</a>)</caption>
+       </figure>
+</p>
+
+<p>
+As the figure suggests the goal on this dataset is to discriminate Iris species. 
+That is to say, our goal is to find a way to answer these questions: 
+"are two given elements in the same group ?", "which group does a given element belongs to ?".
+</p>
+
+<p>
+The mixstore packages take a more general approach: they (try to) learn the data generation 
+process, and then deduce the groups compositions. Thus, the two above questions can easily 
+be answered by using the mathematical formulas describing the classes.
+Although this approach has several advantages (low sensitivity to outliers, likelihood 
+to rank models...), finding the adequate model is challenging. 
+We will not dive into such model selection details.
+{# This is a more general and harder problem. #}
+</p>
+
+</div>
+
+<div class="col-xs-12">
+
+<p>
+Density for 2 groups:
+££f^{(2)}(x) = \pi_1^{(2)} g_1^{(2)}(x) + \pi_2^{(2)} g_2^{(2)}(x)££
+where £g_i^{(2)} = (2 \pi)^{-d/2} \left| \Sigma_i^{(2)} \right|^{-1/2} \mbox{exp}\left( -\frac{1}{2} \, {}^T(x - \mu_i^{(2)}) (\Sigma_i^{(2)})^{-1} (x - \mu_i^{(2)}) \right)£.<br/>
+£x = (x_1,x_2,x_3,x_4)£ with the following correspondances.
+<ul>
+       <li>£x_1£: sepal length;</li>
+       <li>£x_2£: sepal width;</li>
+       <li>£x_3£: petal length;</li>
+       <li>£x_4£: petal width.</li>
+</ul>
+</p>
+
+</div>
+
+<div class="col-xs-12 col-sm-6">
+\begin{align*}
+\pi_1^{(2)} &= 0.33\\
+\mu_1^{(2)} &= (5.01 3.43 1.46 0.25)\\
+\Sigma_1^{(2)} &=
+       \begin{pmatrix}
+       0.15&0.13&0.02&0.01\\
+       0.13&0.18&0.02&0.01\\
+       0.02&0.02&0.03&0.01\\
+       0.01&0.01&0.01&0.01
+       \end{pmatrix}
+\end{align*}
+</div>
+
+<div class="col-xs-12 col-sm-6">
+\begin{align*}
+\pi_2^{(2)} &= 0.67\\
+\mu_2^{(2)} &= (6.26 2.87 4.91 1.68)\\
+\Sigma_2^{(2)} &= 
+       \begin{pmatrix}
+       0.40&0.11&0.40&0.14\\
+       0.11&0.11&0.12&0.07\\
+       0.40&0.12&0.61&0.26\\
+       0.14&0.07&0.26&0.17
+       \end{pmatrix}
+\end{align*}
+</div>
+
+<div class="col-xs-12 borderbottom">
+Penalized log-likelihood (BIC): <b>-561.73</b>
+</div>
+
+<div class="col-xs-12">
+
+<p>
+Density for 3 groups:
+££f^{(3)}(x) = \pi_1^{(3)} g_1^{(3)}(x) + \pi_2^{(3)} g_2^{(3)}(x) + \pi_3^{(3)} g_3^{(3)}(x)££
+(Same parameterizations for cluster densities £g_i^{(3)}£).<br/>
+</p>
+
+</div>
+
+<div class="col-xs-12 col-md-4">
+\begin{align*}
+\pi_1^{(3)} &= 0.33\\
+\mu_1^{(3)} &= (5.01 3.43 1.46 0.25)\\
+\Sigma_1^{(3)} &=
+       \begin{pmatrix}
+       0.13&0.11&0.02&0.01\\
+       0.11&0.15&0.01&0.01\\
+       0.02&0.01&0.03&0.01\\
+       0.01&0.01&0.01&0.01
+       \end{pmatrix}
+\end{align*}
+</div>
+
+<div class="col-xs-12 col-md-4">
+\begin{align*}
+\pi_2^{(3)} &= 0.30\\
+\mu_2^{(3)} &= (5.91 2.78 4.20 1.30)\\
+\Sigma_2^{(3)} &= 
+       \begin{pmatrix}
+       0.23&0.08&0.15&0.04\\
+       0.08&0.08&0.07&0.03\\
+       0.15&0.07&0.17&0.05\\
+       0.04&0.03&0.05&0.03
+       \end{pmatrix}
+\end{align*}
+</div>
+
+<div class="col-xs-12 col-md-4">
+\begin{align*}
+\pi_3^{(3)} &= 0.37\\
+\mu_3^{(3)} &= (6.55 2.95 5.48 1.96)\\
+\Sigma_3^{(3)} &= 
+       \begin{pmatrix}
+       0.43&0.11&0.33&0.07\\
+       0.11&0.12&0.09&0.06\\
+       0.33&0.09&0.36&0.09\\
+       0.07&0.06&0.09&0.09
+       \end{pmatrix}
+\end{align*}
+</div>
+
+<div class="col-xs-12 borderbottom">
+Penalized log-likelihood (BIC): <b>-562.55</b>
+</div>
+
+<div class="col-xs-12">
+
+<p>
+As initially stated, the dataset is difficult to cluster because although we know there are 
+3 species, 2 of them are almost undinstinguishable. That is why log-likelihood values are very close. 
+We usually consider that a method is good on Iris dataset when it finds 3 clusters, 
+but 2 is also a correct answer.
+</p>
+
+</div>
+
+</div>
+
+{% endblock %}
+
+{% block javascripts %}
+{{ parent() }}
+<script type="text/x-mathjax-config">
+MathJax.Hub.Config({
+       tex2jax: {
+               inlineMath: [['£','£']],
+               displayMath: [['££','££']],
+               skipTags: ["script","noscript","style"]//,"textarea","pre","code"]
+       }
+});
+</script>
+<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML"></script>
+{% endblock %}
diff --git a/src/Mixstore/StaticBundle/Resources/views/home.html.twig b/src/Mixstore/StaticBundle/Resources/views/home.html.twig
new file mode 100644 (file)
index 0000000..6d4cc1c
--- /dev/null
@@ -0,0 +1,100 @@
+{% extends "::base.html.twig" %}
+
+{% block title %}{{ parent() }}home{% endblock %}
+
+{% block header %}
+{{ parent() }}
+<link rel="stylesheet" href="{{ asset('mixstore/css/static/home.css') }}">
+{% endblock %}
+
+{% block content %}
+
+<div id="home-carousel" class="carousel slide borderbottom" data-ride="carousel">
+       <!-- Indicators -->
+       <div class="carousel-playpause">
+               <span class="glyphicon glyphicon-play" id="playbutton"></span>
+               <span class="glyphicon glyphicon-pause" id="pausebutton"></span>
+       </div>
+
+       <!-- Wrapper for slides -->
+       <div class="carousel-inner">
+               <div class="item">
+                       <img src="{{ asset('mixstore/images/banner.png') }}" alt="mixstore main banner">
+               </div>
+               {% for key,value in bannersArray %}
+               <div class="item">
+                       <a href="{{ path('mixstore_store_package_view', { id: key }) }}">
+                               <img src="{{ asset('mixstore/images/pkg_banners/' ~ value) }}" alt="some package banner">
+                       </a>
+               </div>
+               {% endfor %}
+       </div>
+
+       <!-- Controls -->
+       <a class="left carousel-control" href="#home-carousel" data-slide="prev">
+               <span class="glyphicon glyphicon-chevron-left"></span>
+       </a>
+       <a class="right carousel-control" href="#home-carousel" data-slide="next">
+               <span class="glyphicon glyphicon-chevron-right"></span>
+       </a>
+</div>
+
+<div class="row borderbottom">
+
+<div class="col-xs-12 col-sm-6 column">
+       <h2>What ?</h2>
+       <p class="justify">Every software, library or package referenced here attempts to <span class="bold">cluster data</span> 
+       into groups defined as the components of a <span class="bold">mixture of probabilistic models</span>. 
+       The resulting classes can be used e.g. for supervised classification or regression.</p>
+       <p class="center-txt"><a href="{{ path('mixstore_static_about') }}">Read more details</a>.</p>
+</div>
+
+<div class="col-xs-12 col-sm-6 column grey-bg xs-shrink">
+       <h2>Where ?</h2>
+       <a href="{{ path('mixstore_store_package_list') }}" class="btn btn-primary btn-lg">In the store !</a>
+</div>
+
+</div>
+
+<div class="row">
+
+<div class="col-xs-12 col-sm-6 column grey-bg xs-shrink">
+       <h2>How ?</h2>
+       <p class="center-txt"><a href="{{ path('mixstore_static_policy') }}">Policy</a> to add a package or feedback.</p>
+</div>
+
+<div class="col-xs-12 col-sm-6 column">
+       <h2>News</h2>
+       <table>
+               {% for newsItem in news %}
+               <tr>
+                       <td class="bold">{{ newsItem.created | date('Y-m-d / H:i:s') }}</td>
+                       <td><a href="{{ path('mixstore_store_package_view', { id: newsItem.id }) }}">{{ newsItem.name }}</a></td>
+               </tr>
+               {% endfor %}
+       </table>
+</div>
+
+</div>
+
+{% endblock %}
+
+{% block javascripts %}
+{{ parent() }}
+<script>
+       $('.glyphicon-play').click(function() {
+               $('#home-carousel').carousel('cycle');
+               $('#playbutton').hide();
+               $('#pausebutton').show();
+       });
+       $('.glyphicon-pause').click(function() {
+               $('#home-carousel').carousel('pause');
+               $('#playbutton').show();
+               $('#pausebutton').hide();
+       });
+       $( document ).ready(function() {
+               $('.carousel-inner .item').eq(0).addClass('active');
+               $('#playbutton').hide();
+       });
+</script>
+{% endblock %}
diff --git a/src/Mixstore/StaticBundle/Resources/views/policy.html.twig b/src/Mixstore/StaticBundle/Resources/views/policy.html.twig
new file mode 100644 (file)
index 0000000..f88668e
--- /dev/null
@@ -0,0 +1,74 @@
+{% extends "::base.html.twig" %}
+
+{% block title %}{{ parent() }}policy{% endblock %}
+
+{% block header %}
+{{ parent() }}
+<link rel="stylesheet" href="{{ asset('mixstore/css/static/policy.css') }}">
+{% endblock %}
+
+{% block content %}
+
+<div id="maintext" class="row">
+
+<h2 class="center">Procedure to add and maintain packages or usecases</h2>
+
+<ol class="policy">
+       <li>
+       Registration is mandatory: follow <a href="{{ path('fos_user_registration_register') }}">this link</a>, 
+       and fill in your name and email address. Neither of them will ever be displayed on the website, 
+       but internally we like to identify people modifying the mixstore pages.
+       </li>
+
+       <li>
+       Once signed up you should be able to <a href="{{ path('fos_user_security_login') }}">login</a>. 
+       Logging in gets you to the main <a href="{{ path('mixstore_user_board') }}">board</a>. 
+       All your actions on the website start from here.
+       </li>
+
+       <li>
+       Both sections (packages and usecases) have a link "add some new thing". Click on either of them 
+       to add for example a new package. The following fields are mandatory :
+       <ul>
+               <li>Name: the name of your package.
+               </li>
+               <li>Headline: a few words to describe what the package does.
+               </li>
+               <li>Url: a web link to (at least) download the package.
+               </li>
+               <li>Authors: a (unstructured) list of authors.
+               </li>
+               <li>Contact: an email address for any exchange related to the package.
+               </li>
+       </ul>
+       <p>
+               Only the description field is optional, because you might already have the description page 
+               on your own website. But even in this case it might be good for SEO, and to give a preview 
+               of your website to mixstore users.
+       </p>
+       <p>
+               Mixstore improves the visibility of your package. In return, <span class="red">we kindly ask 
+               you to provide a visible link to Mixstore on your website.</span>
+       </p></li>
+       
+       <li>
+       Finally, a usecase has the following fields (all mandatory):
+       <ul>
+               <li>Institution: the structure where the work took place. Either academic, 
+               industry (please be more specific) or personal usage.
+               </li>
+               <li>Softwares: a list of packages involved (all in the store).
+               </li>
+               <li>Headline: a few words describing the context of the usecase.
+               </li>
+               <li>Description: an extended abstract showing how the softwares were used.
+               </li>
+               <li>Contact: an email address for any exchange related to the usecase.
+               </li>
+       </ul>
+       </li>
+</ol>
+
+</div>
+
+{% endblock %}
diff --git a/src/Mixstore/StoreBundle/Controller/PackageController.php b/src/Mixstore/StoreBundle/Controller/PackageController.php
new file mode 100644 (file)
index 0000000..8538f4d
--- /dev/null
@@ -0,0 +1,222 @@
+<?php
+
+namespace Mixstore\StoreBundle\Controller;
+
+use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+use Mixstore\StoreBundle\Entity\Package;
+use Mixstore\StoreBundle\Entity\Language;
+use Mixstore\StoreBundle\Entity\PackageRepository;
+use Mixstore\StoreBundle\Entity\Usecase;
+use Mixstore\StoreBundle\Entity\UsecaseRepository;
+
+class PackageController extends Controller
+{
+       public function viewAction($id)
+       {
+               $em = $this
+                       ->getDoctrine()
+                       ->getManager();
+               
+               $package = $em
+                       ->getRepository('MixstoreStoreBundle:Package')
+                       ->find($id);
+               
+               //pass usecases count + rating (to link with feedbacks)
+               $countAndRating = $em
+                       ->getRepository('MixstoreStoreBundle:Usecase')
+                       ->countByPkgId($id);
+               if ($countAndRating['rating'] == '')
+                       $countAndRating['rating'] = 'NA';
+               $package->rating = $countAndRating['rating'];
+               $package->ucscount = $countAndRating['ucscount'];
+               
+               $user = $this->getUser();
+               $owner = (!is_null($user) && $package->getUser()->getId() == $user->getId());
+               
+               return $this->render('MixstoreStoreBundle:Package:view.html.twig', array(
+                       'pkg' => $package,
+                       'owner' => $owner,
+               ));
+       }
+       
+       public function listAction()
+       {
+               $em = $this
+                       ->getDoctrine()
+                       ->getManager();
+               
+               $packages = $em
+                       ->getRepository('MixstoreStoreBundle:Package')
+                       ->findAll();
+
+               $ucsRepository = $em
+                       ->getRepository('MixstoreStoreBundle:Usecase');
+               
+               for ($i=0; $i<count($packages); $i++)
+               {
+                       $countAndRating = $ucsRepository->countByPkgId($packages[$i]->getId());
+                       if ($countAndRating['rating'] == '')
+                               $countAndRating['rating'] = 'NA';
+                       $packages[$i]->ucscount = $countAndRating['ucscount'];
+                       $packages[$i]->rating = $countAndRating['rating'];
+               }
+               
+               return $this->render('MixstoreStoreBundle:Package:list.html.twig', array(
+                       'packages' => $packages,
+               ));
+       }
+
+       public function upsertAction($id)
+       {
+               $em = $this
+                       ->getDoctrine()
+                       ->getManager();
+               
+               $package = $em
+                       ->getRepository('MixstoreStoreBundle:Package')
+                       ->safeFindById($id);
+               
+               //TODO: place this at another location to avoid code redundancy
+               $user = $this->getUser();
+               if (is_null($user) || (
+                       !in_array('ROLE_ADMIN', $user->getRoles()) && 
+                       !is_null($package->getUser()) && 
+                       $package->getUser()->getId() != $this->getUser()->getId()))
+               {
+                       //TODO: nice error page
+                       return $this->redirect($this->generateUrl('mixstore_static_home'));
+               }
+
+               $formBuilder = $this->createFormBuilder($package);
+               $formBuilder
+                       ->add('name', 'text')
+                       ->add('headline', 'text')
+                       ->add('url', 'text')
+                       ->add('description', 'textarea', array('required' => false))
+                       ->add('dependencies', 'text', array('required' => false))
+                       ->add('authors', 'text')
+                       ->add('contact', 'text')
+                       ->add('language', 'entity', array(
+                               'class' => 'MixstoreStoreBundle:Language',
+                               'property' => 'name',
+                               'query_builder' => function(\Doctrine\ORM\EntityRepository $er) {
+                                       return $er->createQueryBuilder('l')
+                                               ->orderBy('l.name', 'ASC');
+                               }))
+                       ->add('bannerfile', 'file', array('label' => 'Banner (1000x300)', 'required' => false))
+                       ->add('removebanner', 'checkbox', array('label' => 'Remove banner', 'required' => false));
+               $form = $formBuilder->getForm();
+               
+               $request = $this->get('request');
+               if ($request->getMethod() == 'POST') {
+                       // Link request <-> form ; $package contains data entered in the form
+                       $form->bind($request);
+                       if ($form->isValid()) {
+                               $package->setUser($this->getUser());
+                               $package->setModified(new \DateTime('now'));
+                               
+                               //HACK: text editor insert extra <p></p><br> tags for an empty description
+                               $description = $package->getDescription();
+                               if (trim(str_replace('<br>','', str_replace('<p>','', str_replace('</p>','', $description)))) == '')
+                                       $package->setDescription('');
+                               
+                               $bannerfile = $form['bannerfile']->getData();
+                               $extension = (is_null($bannerfile) ? null : $bannerfile->guessExtension());
+                               
+                               $bannersDir = $this->get('kernel')->getRootDir().'/../web/mixstore/images/pkg_banners';
+                               
+                               if (!is_null($extension) && ($extension == 'jpeg' || $extension == 'png'))
+                               {
+                                       if (is_null($package->getBannerPath()))
+                                       {
+                                               $filename = uniqid(rand(), true);
+                                               $package->setBannerpath($filename);
+                                       }
+                                       else
+                                               $filename = $package->getBannerpath(); 
+                                       $bannerfile->move($bannersDir, $filename);
+                                       
+                                       //HACK: currently hard-coded
+                                       $newwidth = 1000;
+                                       $newheight = 300;
+                                       
+                                       $source = ($extension == 'jpeg' 
+                                               ? imagecreatefromjpeg($bannersDir.'/'.$filename)
+                                               : imagecreatefrompng($bannersDir.'/'.$filename));
+
+                                       $resizedFile = imagecreatetruecolor($newwidth, $newheight);
+                                       list($width, $height) = getimagesize($bannersDir.'/'.$filename);
+                                       imagecopyresized($resizedFile, $source, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
+                                       
+                                       ($extension == 'jpeg' 
+                                               ? imagejpeg($resizedFile, $bannersDir.'/'.$filename)
+                                               : imagepng($resizedFile, $bannersDir.'/'.$filename));
+                                       
+                                       imagedestroy($resizedFile);
+                               }
+                               else if ($package->removebanner == TRUE)
+                               {
+                                       unlink($bannersDir.'/'.$package->getBannerpath());
+                                       $package->setBannerpath(null);
+                               }
+                                               
+                               $em->persist($package);
+                               $em->flush();
+                               return $this->redirect($this->generateUrl('mixstore_store_package_view', array('id' => $package->getId())));
+                       }
+               }
+               
+               //Email notifications [temporary ??!!]
+               $users = $em
+                       ->getRepository('MixstoreUserBundle:User')
+                       ->findAll();
+               $receivers = array();
+               foreach ($users as $user)
+               {
+                       if ($user->getEmailnotif1() || ($id <= 0 && $user->getEmailNotif0()))
+                               $receivers[] = $user->getEmail();
+               }
+               if (count($receivers) > 0)
+               {
+                       $message = \Swift_Message::newInstance()
+                               ->setSubject('Package '.($id > 0 ? 'update' : 'creation'))
+                               ->setFrom('contact@mixstore.org')
+                               ->setTo($receivers)
+                               ->setBody($this->renderView('MixstoreStoreBundle::upsert-email.txt.twig', array(
+                                       'name' => $this->getUser()->getName(),
+                                       'surname' => $this->getUser()->getSurname(),
+                                       'email' => $this->getUser()->getEmail(),
+                                       'type' => 'Package',
+                                       'id' => $package->getId(),
+                               )));
+                       $this->get('mailer')->send($message);
+               }
+               
+               return $this->render('MixstoreStoreBundle::upsert.html.twig', array(
+                       'title' => ($id > 0 ? 'Edit package' : 'New package'),
+                       'form' => $form->createView(),
+               ));
+       }
+       
+       public function deleteAction($id)
+       {
+               $em = $this->getDoctrine()->getManager();
+
+               $package = $em
+                       ->getRepository('MixstoreStoreBundle:Package')
+                       ->findById($id)[0];
+               
+               $user = $this->getUser();
+               if (is_null($user) || (
+                       !in_array('ROLE_ADMIN', $user->getRoles()) && 
+                       $package->getUser()->getId() != $this->getUser()->getId()))
+               {
+                       //TODO: nice error page
+                       return $this->redirect($this->generateUrl('mixstore_static_home'));
+               }
+               
+               $em->remove($package);
+               $em->flush();
+               return $this->redirect($this->generateUrl('mixstore_user_board'));
+       }
+}
diff --git a/src/Mixstore/StoreBundle/Controller/UsecaseController.php b/src/Mixstore/StoreBundle/Controller/UsecaseController.php
new file mode 100644 (file)
index 0000000..6db9709
--- /dev/null
@@ -0,0 +1,169 @@
+<?php
+
+namespace Mixstore\StoreBundle\Controller;
+
+use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+use Mixstore\StoreBundle\Entity\Package;
+use Mixstore\StoreBundle\Entity\PackageRepository;
+use Mixstore\StoreBundle\Entity\Usecase;
+
+class UsecaseController extends Controller
+{
+       public function viewAction($id)
+       {
+               $usecase = $this
+                       ->getDoctrine()
+                       ->getManager()
+                       ->getRepository('MixstoreStoreBundle:Usecase')
+                       ->find($id);
+               
+               $user = $this->getUser();
+               $owner = (!is_null($user) && $usecase->getUser()->getId() == $user->getId());
+               
+               return $this->render('MixstoreStoreBundle:Usecase:view.html.twig', array(
+                       'ucs' => $usecase,
+                       'owner' => $owner,
+               ));
+       }
+       
+       public function listAction($pkgid)
+       {
+               $em = $this
+                       ->getDoctrine()
+                       ->getManager();
+               
+               $pkgName = $em
+                       ->getRepository('MixstoreStoreBundle:Package')
+                       ->find($pkgid)
+                       ->getName();
+               
+               return $this->render('MixstoreStoreBundle:Usecase:list.html.twig', array(
+                       'usecases' => $em
+                               ->getRepository('MixstoreStoreBundle:Usecase')
+                               ->findByPackage($pkgid),
+                       'pkgname' => $pkgName,
+               ));
+       }
+
+       public function upsertAction($id, $pkgid)
+       {
+               $em = $this
+                       ->getDoctrine()
+                       ->getManager();
+               
+               $usecase = $em
+                       ->getRepository('MixstoreStoreBundle:Usecase')
+                       ->safeFindById($id);
+               
+               //TODO: place this in an external service (used at several locations)
+               $user = $this->getUser();
+               if (is_null($user) || (
+                       !in_array('ROLE_ADMIN', $user->getRoles()) && 
+                       !is_null($usecase->getUser()) && 
+                       $usecase->getUser()->getId() != $this->getUser()->getId()))
+               {
+                       //TODO: nice error page
+                       return $this->redirect($this->generateUrl('mixstore_static_home'));
+               }
+               
+               //http://symfony.com/doc/current/reference/forms/types/entity.html
+               if ($pkgid > 0)
+               {
+                       $package = $em
+                               ->getRepository('MixstoreStoreBundle:Package')
+                               ->findById($pkgid);
+               }
+
+               $formBuilder = $this->createFormBuilder($usecase);
+               if ($pkgid > 0)
+               {
+                       $formBuilder
+                               ->add('package', 'entity', array(
+                                       'class' => 'MixstoreStoreBundle:Package',
+                                       'choices' => $package,
+                                       'property' => 'name',
+                                       'read_only' => true));
+               }
+               else
+               {
+                       $formBuilder
+                               ->add('package', 'entity', array(
+                                       'class' => 'MixstoreStoreBundle:Package',
+                                       'property' => 'name'));
+               }
+               $formBuilder
+                       ->add('institution', 'text')
+                       ->add('headline', 'text')
+                       ->add('description', 'textarea')
+                       ->add('contact', 'text')
+                       ->add('grade', 'choice', array('choices' => range(0, 10)));
+               $form = $formBuilder->getForm();
+               
+               $request = $this->get('request');
+               if ($request->getMethod() == 'POST') {
+                       // Link request <-> form ; $usecase contains data entered in the form
+                       $form->bind($request);
+                       if ($form->isValid()) {
+                               $usecase->setUser($this->getUser());
+                               $usecase->setModified(new \DateTime('now'));
+                               $em->persist($usecase);
+                               $em->flush();
+                               return $this->redirect($this->generateUrl('mixstore_store_usecase_view', array('id' => $usecase->getId())));
+                       }
+               }
+               
+               //Email notifications [temporary ??!!]
+               $users = $em
+                       ->getRepository('MixstoreUserBundle:User')
+                       ->findAll();
+               $receivers = array();
+               foreach ($users as $user)
+               {
+                       if ($user->getEmailnotif1() || ($id <= 0 && $user->getEmailNotif0()))
+                               $receivers[] = $user->getEmail();
+               }
+               if (count($receivers) > 0)
+               {
+                       $message = \Swift_Message::newInstance()
+                               ->setSubject('Usecase '.($id > 0 ? 'update' : 'creation'))
+                               ->setFrom('contact@mixstore.org')
+                               ->setTo($receivers)
+                               ->setBody($this->renderView('MixstoreStoreBundle::upsert-email.txt.twig', array(
+                                       'name' => $this->getUser()->getName(),
+                                       'surname' => $this->getUser()->getSurname(),
+                                       'email' => $this->getUser()->getEmail(),
+                                       'type' => 'Usecase',
+                                       'id' => $usecase->getId(),
+                               )));
+                       $this->get('mailer')->send($message);
+               }
+               
+               return $this->render('MixstoreStoreBundle::upsert.html.twig', array(
+                       'title' => ($id > 0 ? 'Edit usecase' : 'New usecase'),
+                       'form' => $form->createView(),
+               ));
+       }
+       
+       public function deleteAction($id)
+       {
+               $usecase = $this
+                       ->getDoctrine()
+                       ->getManager()
+                       ->getRepository('MixstoreStoreBundle:Usecase')
+                       ->findById($id)[0];
+               
+               $user = $this->getUser();
+               if (is_null($user) || (
+                       !in_array('ROLE_ADMIN', $user->getRoles()) && 
+                       $usecase->getUser()->getId() != $this->getUser()->getId()))
+               {
+                       //TODO: nice error page
+                       return $this->redirect($this->generateUrl('mixstore_static_home'));
+               }
+               
+               $em = $this->getDoctrine()->getManager();
+               $em->remove($usecase);
+               $em->flush();
+               return $this->redirect($this->generateUrl('mixstore_user_board'));
+       }
+}
diff --git a/src/Mixstore/StoreBundle/DependencyInjection/Configuration.php b/src/Mixstore/StoreBundle/DependencyInjection/Configuration.php
new file mode 100644 (file)
index 0000000..8e6dc7d
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+
+namespace Mixstore\StoreBundle\DependencyInjection;
+
+use Symfony\Component\Config\Definition\Builder\TreeBuilder;
+use Symfony\Component\Config\Definition\ConfigurationInterface;
+
+/**
+ * This is the class that validates and merges configuration from your app/config files
+ *
+ * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
+ */
+class Configuration implements ConfigurationInterface
+{
+    /**
+     * {@inheritDoc}
+     */
+    public function getConfigTreeBuilder()
+    {
+        $treeBuilder = new TreeBuilder();
+        $rootNode = $treeBuilder->root('mixstore_store');
+
+        // Here you should define the parameters that are allowed to
+        // configure your bundle. See the documentation linked above for
+        // more information on that topic.
+
+        return $treeBuilder;
+    }
+}
diff --git a/src/Mixstore/StoreBundle/DependencyInjection/MixstoreStoreExtension.php b/src/Mixstore/StoreBundle/DependencyInjection/MixstoreStoreExtension.php
new file mode 100644 (file)
index 0000000..36f03cf
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+
+namespace Mixstore\StoreBundle\DependencyInjection;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\Config\FileLocator;
+use Symfony\Component\HttpKernel\DependencyInjection\Extension;
+use Symfony\Component\DependencyInjection\Loader;
+
+/**
+ * This is the class that loads and manages your bundle configuration
+ *
+ * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
+ */
+class MixstoreStoreExtension extends Extension
+{
+    /**
+     * {@inheritDoc}
+     */
+    public function load(array $configs, ContainerBuilder $container)
+    {
+        $configuration = new Configuration();
+        $config = $this->processConfiguration($configuration, $configs);
+
+        $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
+        $loader->load('services.yml');
+    }
+}
diff --git a/src/Mixstore/StoreBundle/Entity/Language.php b/src/Mixstore/StoreBundle/Entity/Language.php
new file mode 100644 (file)
index 0000000..4607953
--- /dev/null
@@ -0,0 +1,75 @@
+<?php
+
+namespace Mixstore\StoreBundle\Entity;
+
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * Language
+ *
+ * @ORM\Table()
+ * @ORM\Entity
+ */
+class Language
+{
+    /**
+     * @var integer
+     *
+     * @ORM\Column(name="id", type="integer")
+     * @ORM\Id
+     * @ORM\GeneratedValue(strategy="AUTO")
+     */
+    private $id;
+
+    /**
+     * @var string
+     *
+     * @ORM\Column(name="name", type="string", length=32, unique=true)
+     */
+    private $name;
+
+       public function __construct($name)
+       {
+               $this->name = $name;
+       }
+       
+    /**
+     * Get id
+     *
+     * @return integer 
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    /**
+     * Set name
+     *
+     * @param string $name
+     * @return Language
+     */
+    public function setName($name)
+    {
+        $this->name = $name;
+
+        return $this;
+    }
+
+    /**
+     * Get name
+     *
+     * @return string 
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+}
+
+/*
+* current languages
+C, C#, C++, Java, Julia, Python, R, Fortran, Lua, Matlab, Octave, Scilab
+* others
+Javascript,Objective-C,Perl, PHP,Ruby,Shell,Scala, Go,Groovy,Ada, Android,Boo, Clojure, Common Lisp, Delphi, Eiffel, Erlang, Fantom,Haskell,Node.js, OCaml,Prolog
+*/
diff --git a/src/Mixstore/StoreBundle/Entity/Package.php b/src/Mixstore/StoreBundle/Entity/Package.php
new file mode 100644 (file)
index 0000000..cf05bb5
--- /dev/null
@@ -0,0 +1,397 @@
+<?php
+
+namespace Mixstore\StoreBundle\Entity;
+
+use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Validator\Constraints as Assert;
+
+/**
+ * Package
+ *
+ * @ORM\Table()
+ * @ORM\Entity(repositoryClass="Mixstore\StoreBundle\Entity\PackageRepository")
+ */
+class Package
+{
+       /**
+        * @var integer
+        *
+        * @ORM\Column(name="id", type="integer")
+        * @ORM\Id
+        * @ORM\GeneratedValue(strategy="AUTO")
+        */
+       private $id;
+
+       /**
+        * @ORM\Column(type="datetime")
+        * @Assert\NotBlank()
+        */
+       private $created;
+
+       /**
+        * @ORM\Column(type="datetime")
+        * @Assert\NotBlank()
+        */
+       private $modified;
+
+       /**
+        * @ORM\Column(type="string", unique=true)
+        * @Assert\NotBlank()
+        */
+       private $name;
+
+       /**
+        * @ORM\Column(type="text")
+        * @Assert\NotBlank()
+        */
+       private $headline;
+
+       /**
+        * @ORM\Column(type="string")
+        * @Assert\NotBlank()
+        * @Assert\Url()
+        */
+       private $url;
+       
+       /**
+        * @ORM\Column(type="text", nullable=true)
+        */
+       private $description;
+
+       /**
+        * @ORM\Column(type="text", nullable=true)
+        */
+       private $dependencies;
+       
+       /**
+        * @ORM\Column(type="text")
+        * @Assert\NotBlank()
+        */
+       private $authors;
+       
+       /**
+        * @ORM\Column(type="string")
+        * @Assert\NotBlank()
+        * @Assert\Email()
+        */
+       private $contact; //un email
+       
+       /**
+       * @ORM\ManyToOne(targetEntity="Mixstore\UserBundle\Entity\User")
+       * @ORM\JoinColumn(nullable=false)
+       */
+       private $user; //owner of the package: "webmaster"...
+
+       /**
+       * @ORM\ManyToOne(targetEntity="Mixstore\StoreBundle\Entity\Language")
+       * @ORM\JoinColumn(nullable=false)
+       */
+       private $language;
+
+       /**
+        * @ORM\Column(type="string", nullable=true)
+        */
+       private $bannerpath; //chemin vers banner image
+
+       // ---
+       //quick ugly way: TOFIX
+       public $bannerfile;
+       public $removebanner;
+       // ---
+
+       public function __construct()
+       {
+               $this->user = null;
+               $this->id = 0;
+               $this->created = new \DateTime('now');
+               $this->modified = new \DateTime('now');
+       }
+       
+       /**
+        * Get id
+        *
+        * @return integer 
+        */
+       public function getId()
+       {
+               return $this->id;
+       }
+       
+       //un package a un "webmaster ID" (masqué sur la page du package, mais permettant de savoir qui a le droit de l'éditer)
+
+       /**
+        * Set name
+        *
+        * @param string $name
+        * @return Package
+        */
+       public function setName($name)
+       {
+               $this->name = $name;
+
+               return $this;
+       }
+
+       /**
+        * Get name
+        *
+        * @return string 
+        */
+       public function getName()
+       {
+               return $this->name;
+       }
+
+       /**
+        * Set url
+        *
+        * @param string $url
+        * @return Package
+        */
+       public function setUrl($url)
+       {
+               $this->url = $url;
+
+               return $this;
+       }
+
+       /**
+        * Get url
+        *
+        * @return string 
+        */
+       public function getUrl()
+       {
+               return $this->url;
+       }
+
+       /**
+        * Set description
+        *
+        * @param string $description
+        * @return Package
+        */
+       public function setDescription($description)
+       {
+               $this->description = $description;
+
+               return $this;
+       }
+
+       /**
+        * Get description
+        *
+        * @return string 
+        */
+       public function getDescription()
+       {
+               return $this->description;
+       }
+
+       /**
+        * Set authors
+        *
+        * @param string $authors
+        * @return Package
+        */
+       public function setAuthors($authors)
+       {
+               $this->authors = $authors;
+
+               return $this;
+       }
+
+       /**
+        * Get authors
+        *
+        * @return string 
+        */
+       public function getAuthors()
+       {
+               return $this->authors;
+       }
+
+       /**
+        * Set contact
+        *
+        * @param string $contact
+        * @return Package
+        */
+       public function setContact($contact)
+       {
+               $this->contact = $contact;
+
+               return $this;
+       }
+
+       /**
+        * Get contact
+        *
+        * @return string 
+        */
+       public function getContact()
+       {
+               return $this->contact;
+       }
+
+       /**
+        * Set user
+        *
+        * @param \Mixstore\UserBundle\Entity\User $user
+        * @return Package
+        */
+       public function setUser(\Mixstore\UserBundle\Entity\User $user)
+       {
+               $this->user = $user;
+
+               return $this;
+       }
+
+       /**
+        * Get user
+        *
+        * @return \Mixstore\UserBundle\Entity\User 
+        */
+       public function getUser()
+       {
+               return $this->user;
+       }
+
+    /**
+     * Set headline
+     *
+     * @param string $headline
+     * @return Package
+     */
+    public function setHeadline($headline)
+    {
+        $this->headline = $headline;
+
+        return $this;
+    }
+
+    /**
+     * Get headline
+     *
+     * @return string 
+     */
+    public function getHeadline()
+    {
+        return $this->headline;
+    }
+
+    /**
+     * Set bannerpath
+     *
+     * @param string $bannerpath
+     * @return Package
+     */
+    public function setBannerpath($bannerpath)
+    {
+        $this->bannerpath = $bannerpath;
+
+        return $this;
+    }
+
+    /**
+     * Get bannerpath
+     *
+     * @return string 
+     */
+    public function getBannerpath()
+    {
+        return $this->bannerpath;
+    }
+
+    /**
+     * Set modified
+     *
+     * @param \DateTime $modified
+     * @return Package
+     */
+    public function setModified($modified)
+    {
+        $this->modified = $modified;
+
+        return $this;
+    }
+
+    /**
+     * Get modified
+     *
+     * @return \DateTime 
+     */
+    public function getModified()
+    {
+        return $this->modified;
+    }
+
+    /**
+     * Set language
+     *
+     * @param \Mixstore\StoreBundle\Entity\Language $language
+     * @return Package
+     */
+    public function setLanguage(\Mixstore\StoreBundle\Entity\Language $language)
+    {
+        $this->language = $language;
+
+        return $this;
+    }
+
+    /**
+     * Get language
+     *
+     * @return \Mixstore\StoreBundle\Entity\Language 
+     */
+    public function getLanguage()
+    {
+        return $this->language;
+    }
+
+    /**
+     * Set created
+     *
+     * @param \DateTime $created
+     * @return Package
+     */
+    public function setCreated($created)
+    {
+        $this->created = $created;
+
+        return $this;
+    }
+
+    /**
+     * Get created
+     *
+     * @return \DateTime 
+     */
+    public function getCreated()
+    {
+        return $this->created;
+    }
+
+    /**
+     * Set dependencies
+     *
+     * @param string $dependencies
+     * @return Package
+     */
+    public function setDependencies($dependencies)
+    {
+        $this->dependencies = $dependencies;
+
+        return $this;
+    }
+
+    /**
+     * Get dependencies
+     *
+     * @return string 
+     */
+    public function getDependencies()
+    {
+        return $this->dependencies;
+    }
+}
diff --git a/src/Mixstore/StoreBundle/Entity/PackageRepository.php b/src/Mixstore/StoreBundle/Entity/PackageRepository.php
new file mode 100644 (file)
index 0000000..fc2a332
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+
+namespace Mixstore\StoreBundle\Entity;
+
+use Doctrine\ORM\EntityRepository;
+
+class PackageRepository extends EntityRepository
+{      
+       function safeFindById($id)
+       {
+               if ($id > 0)
+               {
+                       $qb = $this->createQueryBuilder('p');
+                       $qb->where('p.id = '.$id);
+                       $package = $qb->getQuery()->getResult()[0];
+               }
+               else 
+                       $package = new Package();
+               
+               return $package;
+    }
+    
+    function getAllNames()
+    {
+               return $this
+                       ->createQueryBuilder('p')
+                       ->select('p.id, p.name')
+                       ->getQuery()
+                       ->getResult();
+       }
+       
+       function getBannersUrls()
+       {
+               $bannersUrls = $this
+                       ->createQueryBuilder('p')
+                       ->select('p.id, p.bannerpath')
+                       ->where('p.bannerpath IS NOT NULL')
+                       ->getQuery()
+                       ->getResult();
+               $result = array();
+               for ($i=0; $i<count($bannersUrls); $i++)
+                       $result[$bannersUrls[$i]['id']] = $bannersUrls[$i]['bannerpath'];
+               return $result;
+       }
+       
+       function getLastNews()
+       {
+               return $this
+                       ->createQueryBuilder('p')
+                       ->select('p.id, p.name, p.created')
+                       ->orderBy('p.created', 'DESC')
+                       ->setMaxResults(3) //currently hard-coded
+                       ->getQuery()
+                       ->getResult();
+       }
+}
diff --git a/src/Mixstore/StoreBundle/Entity/Usecase.php b/src/Mixstore/StoreBundle/Entity/Usecase.php
new file mode 100644 (file)
index 0000000..3f06b4b
--- /dev/null
@@ -0,0 +1,304 @@
+<?php
+
+namespace Mixstore\StoreBundle\Entity;
+
+use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Validator\Constraints as Assert;
+
+/**
+ * Usecase
+ *
+ * @ORM\Table()
+ * @ORM\Entity(repositoryClass="Mixstore\StoreBundle\Entity\UsecaseRepository")
+ */
+class Usecase
+{
+       /**
+        * @var integer
+        *
+        * @ORM\Column(name="id", type="integer")
+        * @ORM\Id
+        * @ORM\GeneratedValue(strategy="AUTO")
+        */
+       private $id;
+
+       /**
+        * @ORM\Column(type="datetime")
+        * @Assert\NotBlank()
+        */
+       private $created;
+
+       /**
+        * @ORM\Column(type="datetime")
+        * @Assert\NotBlank()
+        */
+       private $modified;
+
+       /**
+        * @ORM\Column(type="string")
+        * @Assert\NotBlank()
+        */
+       private $institution;
+
+       /**
+        * @ORM\Column(type="string")
+        * @Assert\NotBlank()
+        */
+       private $headline; //titre du usecase
+       
+       /**
+        * @ORM\Column(type="text")
+        * @Assert\NotBlank()
+        */
+       private $description;
+       
+       /**
+        * @ORM\Column(type="string")
+        * @Assert\NotBlank()
+        * @Assert\Email()
+        */
+       private $contact; //un email
+       
+       /**
+       * @ORM\ManyToOne(targetEntity="Mixstore\UserBundle\Entity\User")
+       * @ORM\JoinColumn(nullable=false)
+       */
+       private $user; //owner of the usecase: "webmaster"...
+
+       /**
+        * @ORM\Column(type="decimal")
+        * @Assert\NotBlank()
+        */
+       private $grade; //from 0 to 10 (integer, in fact)
+
+       /**
+       * @ORM\ManyToOne(targetEntity="Mixstore\StoreBundle\Entity\Package")
+       * @ORM\JoinColumn(nullable=false)
+       */
+       private $package;
+
+       public function __construct()
+       {
+               $this->user = null;
+               $this->id = 0;
+               $this->created = new \DateTime("now");
+               $this->modified = new \DateTime("now");
+       }
+       
+       /**
+        * Get id
+        *
+        * @return integer 
+        */
+       public function getId()
+       {
+               return $this->id;
+       }
+
+       /**
+        * Set institution
+        *
+        * @param string $institution
+        * @return Usecase
+        */
+       public function setInstitution($institution)
+       {
+               $this->institution = $institution;
+
+               return $this;
+       }
+
+       /**
+        * Get institution
+        *
+        * @return string 
+        */
+       public function getInstitution()
+       {
+               return $this->institution;
+       }
+
+       /**
+        * Set description
+        *
+        * @param string $description
+        * @return Usecase
+        */
+       public function setDescription($description)
+       {
+               $this->description = $description;
+
+               return $this;
+       }
+
+       /**
+        * Get description
+        *
+        * @return string 
+        */
+       public function getDescription()
+       {
+               return $this->description;
+       }
+
+       /**
+        * Set contact
+        *
+        * @param string $contact
+        * @return Usecase
+        */
+       public function setContact($contact)
+       {
+               $this->contact = $contact;
+
+               return $this;
+       }
+
+       /**
+        * Get contact
+        *
+        * @return string 
+        */
+       public function getContact()
+       {
+               return $this->contact;
+       }
+
+       /**
+        * Set user
+        *
+        * @param \Mixstore\UserBundle\Entity\User $user
+        * @return Usecase
+        */
+       public function setUser(\Mixstore\UserBundle\Entity\User $user)
+       {
+               $this->user = $user;
+
+               return $this;
+       }
+
+       /**
+        * Get user
+        *
+        * @return \Mixstore\UserBundle\Entity\User 
+        */
+       public function getUser()
+       {
+               return $this->user;
+       }
+       
+    /**
+     * Set headline
+     *
+     * @param string $headline
+     * @return Usecase
+     */
+    public function setHeadline($headline)
+    {
+        $this->headline = $headline;
+
+        return $this;
+    }
+
+    /**
+     * Get headline
+     *
+     * @return string 
+     */
+    public function getHeadline()
+    {
+        return $this->headline;
+    }
+
+    /**
+     * Set package
+     *
+     * @param \Mixstore\StoreBundle\Entity\Package $package
+     * @return Usecase
+     */
+    public function setPackage(\Mixstore\StoreBundle\Entity\Package $package)
+    {
+        $this->package = $package;
+
+        return $this;
+    }
+
+    /**
+     * Get package
+     *
+     * @return \Mixstore\StoreBundle\Entity\Package 
+     */
+    public function getPackage()
+    {
+        return $this->package;
+    }
+
+    /**
+     * Set grade
+     *
+     * @param boolean $happy
+     * @return Usecase
+     */
+    public function setGrade($grade)
+    {
+        $this->grade = $grade;
+
+        return $this;
+    }
+
+    /**
+     * Get grade
+     *
+     * @return boolean 
+     */
+    public function getGrade()
+    {
+        return $this->grade;
+    }
+
+    /**
+     * Set created
+     *
+     * @param \DateTime $created
+     * @return Usecase
+     */
+    public function setCreated($created)
+    {
+        $this->created = $created;
+
+        return $this;
+    }
+
+    /**
+     * Get created
+     *
+     * @return \DateTime 
+     */
+    public function getCreated()
+    {
+        return $this->created;
+    }
+
+    /**
+     * Set modified
+     *
+     * @param \DateTime $modified
+     * @return Usecase
+     */
+    public function setModified($modified)
+    {
+        $this->modified = $modified;
+
+        return $this;
+    }
+
+    /**
+     * Get modified
+     *
+     * @return \DateTime 
+     */
+    public function getModified()
+    {
+        return $this->modified;
+    }
+}
diff --git a/src/Mixstore/StoreBundle/Entity/UsecaseRepository.php b/src/Mixstore/StoreBundle/Entity/UsecaseRepository.php
new file mode 100644 (file)
index 0000000..df339a4
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+namespace Mixstore\StoreBundle\Entity;
+
+use Doctrine\ORM\EntityRepository;
+
+class UsecaseRepository extends EntityRepository
+{
+       function safeFindById($id)
+       {
+               if ($id > 0)
+               {
+                       $qb = $this->createQueryBuilder('u');
+                       $qb->where('u.id = '.$id);
+                       $usecase = $qb->getQuery()->getResult()[0];
+               }
+               else 
+                       $usecase = new Usecase();
+               
+               return $usecase;
+       }
+       
+       function countByPkgId($pkgid)
+       {
+               return $this
+                       ->createQueryBuilder('u')
+                       ->select('COUNT(u.id) AS ucscount, AVG(u.grade) AS rating')
+                       ->where('u.package = '.$pkgid)
+                       ->getQuery()
+                       ->getResult()[0];
+                       //->getSingleScalarResult();
+       }
+}
diff --git a/src/Mixstore/StoreBundle/MixstoreStoreBundle.php b/src/Mixstore/StoreBundle/MixstoreStoreBundle.php
new file mode 100644 (file)
index 0000000..85b55ef
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+
+namespace Mixstore\StoreBundle;
+
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+class MixstoreStoreBundle extends Bundle
+{
+}
diff --git a/src/Mixstore/StoreBundle/Resources/config/routing.yml b/src/Mixstore/StoreBundle/Resources/config/routing.yml
new file mode 100644 (file)
index 0000000..6fcad18
--- /dev/null
@@ -0,0 +1,48 @@
+mixstore_store_package_list:
+    pattern: /package/list
+    defaults: { _controller: MixstoreStoreBundle:Package:list }
+
+mixstore_store_package_view:
+    pattern: /package/view/{id}
+    defaults: { _controller: MixstoreStoreBundle:Package:view }
+    requirements:
+        id: \d+
+
+mixstore_store_package_upsert:
+    #id = 0 means "new package"
+    pattern: /package/upsert/{id}
+    defaults: { _controller: MixstoreStoreBundle:Package:upsert, id: 0 }
+    requirements:
+        id: \d+
+
+mixstore_store_package_delete:
+    pattern: /package/delete/{id}
+    defaults: { _controller: MixstoreStoreBundle:Package:delete }
+    requirements:
+        id: \d+
+
+mixstore_store_usecase_list:
+    pattern: /usecase/list/{pkgid}
+    defaults: { _controller: MixstoreStoreBundle:Usecase:list }
+    requirements:
+        pkgid: \d+
+
+mixstore_store_usecase_view:
+    pattern: /usecase/view/{id}
+    defaults: { _controller: MixstoreStoreBundle:Usecase:view }
+    requirements:
+        id: \d+
+
+mixstore_store_usecase_upsert:
+    #id = 0 means "new usecase"
+    pattern: /usecase/upsert/{id}/{pkgid}
+    defaults: { _controller: MixstoreStoreBundle:Usecase:upsert, id: 0, pkgid: 0 }
+    requirements:
+        id: \d+
+        pkgid: \d+
+
+mixstore_store_usecase_delete:
+    pattern: /usecase/delete/{id}
+    defaults: { _controller: MixstoreStoreBundle:Usecase:delete }
+    requirements:
+        id: \d+
diff --git a/src/Mixstore/StoreBundle/Resources/config/services.yml b/src/Mixstore/StoreBundle/Resources/config/services.yml
new file mode 100644 (file)
index 0000000..ea30561
--- /dev/null
@@ -0,0 +1 @@
+#empty
diff --git a/src/Mixstore/StoreBundle/Resources/views/Package/list.html.twig b/src/Mixstore/StoreBundle/Resources/views/Package/list.html.twig
new file mode 100644 (file)
index 0000000..ec42d12
--- /dev/null
@@ -0,0 +1,28 @@
+{% extends "::base.html.twig" %}
+
+{% block title %}{{ parent() }}Store{% endblock %}
+
+{% block header %}
+{{ parent() }}
+<link rel="stylesheet" href="{{ asset('mixstore/css/store/table.css') }}">
+{% endblock %}
+
+{% block content %}
+
+<div class="row">
+       <h2 class="center-txt">All packages</h2>
+       {% include "MixstoreStoreBundle:Package:list_content.html.twig" %}
+</div>
+
+{% endblock %}
+
+{% block javascripts %}
+{{ parent() }}
+<script type="text/javascript" src="{{ asset('mixstore/js/stupidtable.min.js') }}"></script>
+<script>
+$(document).ready(function() 
+{ 
+       $(".sortable").stupidtable();
+});
+</script>
+{% endblock %}
diff --git a/src/Mixstore/StoreBundle/Resources/views/Package/list_content.html.twig b/src/Mixstore/StoreBundle/Resources/views/Package/list_content.html.twig
new file mode 100644 (file)
index 0000000..fe79a6f
--- /dev/null
@@ -0,0 +1,22 @@
+<table class="sortable">
+       <thead>
+               <th data-sort="string">Name</th>
+               <th>Headline</th>
+               <th data-sort="string">Language</th>
+               <th>Grade/10 &ndash; #feedbacks</th>
+       </thead>
+       <tbody>
+       {% for pkg in packages %}
+               <tr>
+                       <td><a href="{{ path('mixstore_store_package_view', { id: pkg.id }) }}">{{ pkg.name }}</a></td>
+                       <td><a href="{{ path('mixstore_store_package_view', { id: pkg.id }) }}">{{ pkg.headline }}</a></td>
+                       <td>{{ pkg.language.name }}</td>
+                       <td>
+                               <a href="{{ path('mixstore_store_usecase_list', { pkgid: pkg.id }) }}">
+                               {% if pkg.rating != 'NA' %} {{ pkg.rating | number_format(2, '.', '') }} {% else %} NA {% endif %} &ndash; {{ pkg.ucscount }}
+                               </a>
+                       </td>
+               </tr>
+       {% endfor %}
+       </tbody>
+</table>
diff --git a/src/Mixstore/StoreBundle/Resources/views/Package/view.html.twig b/src/Mixstore/StoreBundle/Resources/views/Package/view.html.twig
new file mode 100644 (file)
index 0000000..497853d
--- /dev/null
@@ -0,0 +1,66 @@
+{% extends "::base.html.twig" %}
+
+{% block title %}{{ parent() }}package{% endblock %}
+
+{% block header %}
+{{ parent() }}
+<link rel="stylesheet" href="{{ asset('mixstore/css/store/view-package.css') }}">
+{% endblock %}
+
+{% block content %}
+
+{% if pkg.bannerpath != '' %}
+<div class="row">
+       <img id="pkgimage" src={{ asset('mixstore/images/pkg_banners/' ~ pkg.bannerpath) }}>
+</div>
+{% endif %}
+
+<div id="header" class="row">
+       <h1><a href="{{ pkg.url }}">{{ pkg.name }}</a></h2>
+       <h3>{{ pkg.headline }}</h4>
+</div>
+
+{%  if pkg.description != '' %}
+<div id="description" class="row">
+       {{ pkg.description | raw }}
+</div>
+{%  endif %}
+
+{%  if pkg.dependencies != ''  %}
+<div id="dependencies" class="row">
+       Dependencies: {{ pkg.dependencies }}
+</div>
+{%  endif %}
+
+<div id="contact" class="row">
+<p>
+       <span class="bold">Authors: </span>{{ pkg.authors }}
+</p>
+<p>
+       <a href="mailto:{{ pkg.contact }}">Contact</a>
+</p>
+</div>
+
+<div id="moreinfo" class="row">
+<p>
+       <a href="{{ path('mixstore_store_usecase_list', { pkgid: pkg.id }) }}">Rating: {% if pkg.rating != 'NA' %} {{ pkg.rating | number_format(2, '.', '') }} {% else %} NA {% endif %} &ndash; #feedbacks: {{ pkg.ucscount }}</a>
+       &nbsp; &mdash; &nbsp;
+       <a href="{{ path('mixstore_store_usecase_upsert', { pkgid: pkg.id }) }}"><button type="button" class="btn btn-primary">New feedback</button></a>
+</p>
+<p>
+       Last updated: {{ pkg.modified | date('Y-m-d / H:i:s') }}
+</p>
+</div>
+
+{% if owner or is_granted('ROLE_ADMIN') %}
+<div id="admin" class="row">
+<div class="col-xs-6 flush-right">
+       <a href="{{ path('mixstore_store_package_upsert', { id: pkg.id }) }}"><button type="button" class="btn btn-primary">Edit</button></a>
+</div>
+<div class="col-xs-6">
+       <a href="{{ path('mixstore_store_package_delete', { id: pkg.id }) }}"><button type="button" class="btn btn-primary">Delete</button></a>
+</div>
+</div>
+{% endif %}
+
+{% endblock %}
diff --git a/src/Mixstore/StoreBundle/Resources/views/Usecase/list.html.twig b/src/Mixstore/StoreBundle/Resources/views/Usecase/list.html.twig
new file mode 100644 (file)
index 0000000..ca76db3
--- /dev/null
@@ -0,0 +1,28 @@
+{% extends "::base.html.twig" %}
+
+{% block title %}{{ parent() }}usecases{% endblock %}
+
+{% block header %}
+{{ parent() }}
+<link rel="stylesheet" href="{{ asset('mixstore/css/store/table.css') }}">
+{% endblock %}
+
+{% block content %}
+
+<div class="row">
+       <h2 class="center-txt">Usecases for package {{ pkgname }}</h2>
+       {% include "MixstoreStoreBundle:Usecase:list_content.html.twig" %}
+</div>
+
+{% endblock %}
+
+{% block javascripts %}
+{{ parent() }}
+<script type="text/javascript" src="{{ asset('mixstore/js/stupidtable.min.js') }}"></script>
+<script>
+$(document).ready(function() 
+{ 
+       $(".sortable").stupidtable();
+});
+</script>
+{% endblock %}
diff --git a/src/Mixstore/StoreBundle/Resources/views/Usecase/list_content.html.twig b/src/Mixstore/StoreBundle/Resources/views/Usecase/list_content.html.twig
new file mode 100644 (file)
index 0000000..bf9b219
--- /dev/null
@@ -0,0 +1,16 @@
+<table class="sortable">
+       <thead>
+               <th>Package</th>
+               <th>Headline</th>
+               <th data-sort="float">Grade/10</th>
+       </thead>
+       <tbody>
+       {% for ucs in usecases %}
+               <tr>
+                       <td>{{ ucs.package.name }}</td>
+                       <td><a href="{{ path('mixstore_store_usecase_view', { id: ucs.id }) }}">{{ ucs.headline }}</a></td>
+                       <td>{{ ucs.grade }}</td>
+               </tr>
+       {% endfor %}
+       </tbody>
+</table>
diff --git a/src/Mixstore/StoreBundle/Resources/views/Usecase/view.html.twig b/src/Mixstore/StoreBundle/Resources/views/Usecase/view.html.twig
new file mode 100644 (file)
index 0000000..9fe1f31
--- /dev/null
@@ -0,0 +1,45 @@
+{% extends "::base.html.twig" %}
+
+{% block title %}{{ parent() }}Usecase{% endblock %}
+
+{% block header %}
+{{ parent() }}
+<link rel="stylesheet" href="{{ asset('mixstore/css/store/view-usecase.css') }}">
+{% endblock %}
+
+{% block content %}
+
+<div id="header" class="row">
+       <h2>{{ ucs.institution }}</h2>
+       <h4>{{ ucs.package.name }}</h4>
+</div>
+
+<div id="description" class="row">
+       {{ ucs.description | raw }}
+</div>
+
+<div id="contact" class="row">
+       <a href="mailto:{{ ucs.contact }}">Contact</a>
+</div>
+
+<div id="moreinfo" class="row">
+<p>
+       Grade: {{ ucs.grade }}
+</p>
+<p>
+       Last updated: {{ ucs.modified | date('Y-m-d / H:i:s') }}
+</p>
+</div>
+
+{% if owner or is_granted('ROLE_ADMIN') %}
+<div id="admin" class="row">
+<div class="col-xs-6 flush-right">
+       <a href="{{ path('mixstore_store_usecase_upsert', { id: ucs.id }) }}"><button type="button" class="btn btn-primary">Edit</button></a>
+</div>
+<div class="col-xs-6">
+       <a href="{{ path('mixstore_store_usecase_delete', { id: ucs.id }) }}"><button type="button" class="btn btn-primary">Delete</button></a>
+</div>
+</div>
+{% endif %}
+
+{% endblock %}
diff --git a/src/Mixstore/StoreBundle/Resources/views/upsert-email.txt.twig b/src/Mixstore/StoreBundle/Resources/views/upsert-email.txt.twig
new file mode 100644 (file)
index 0000000..f11db01
--- /dev/null
@@ -0,0 +1,5 @@
+{% if is_granted('ROLE_ADMIN') %}
+By {{ name }} {{ surname }} ({{ email }}).
+{% endif %}
+
+View online : {% if type == 'Package' %} {{ url('mixstore_store_package_view', { id: id }) }} {% else %} {{ url('mixstore_store_usecase_view', { id: id }) }} {% endif %}.
diff --git a/src/Mixstore/StoreBundle/Resources/views/upsert.html.twig b/src/Mixstore/StoreBundle/Resources/views/upsert.html.twig
new file mode 100644 (file)
index 0000000..d8b92d8
--- /dev/null
@@ -0,0 +1,81 @@
+{% extends "::base.html.twig" %}
+
+{% block title %}{{ parent() }}upsert package{% endblock %}
+
+{% block header %}
+{{ parent() }}
+<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css">
+<link rel="stylesheet" href="{{ asset('mixstore/css/summernote.min.css') }}" />
+
+<!-- include codemirror (codemirror.css, codemirror.js, xml.js, formatting.js) -->
+<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/3.20.0/codemirror.min.css" />
+<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/3.20.0/theme/monokai.min.css" />
+<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/codemirror/3.20.0/codemirror.min.js"></script>
+<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/codemirror/3.20.0/mode/xml/xml.min.js"></script>
+<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/codemirror/2.36.0/formatting.min.js"></script>
+
+<link rel="stylesheet" href="{{ asset('mixstore/css/store/upsert.css') }}" />
+<link rel="stylesheet" href="{{ asset('mixstore/css/form.css') }}" />
+{% endblock %}
+
+{% block content %}
+
+{% form_theme form ':Form:fields.html.twig' %}
+
+<div class="row center-txt">
+       <h3>{{ title }}</h3>
+       {% if 'ackage' in title %}<p class="red">Please don't forget to add a link to mixstore on your website. Thanks !</p>{% endif %}
+</div>
+
+<form name="upsert_form" method="post" {{ form_enctype(form) }} class="form-horizontal">
+       {{ form_widget(form) }}
+       <div class="form-group">
+               <div class="col-sm-8 col-sm-offset-2">
+                       <button type="submit" class="btn btn-primary" onclick="saveValidateSubmit()">Submit</button>
+               </div>
+       </div>
+</form>
+
+{% endblock content %}
+
+{%block javascripts %}
+{{ parent() }}
+<script src="{{ asset('mixstore/js/summernote.min.js') }}"></script>
+
+<script>
+
+$(document).ready(function()
+{
+       //add label classes
+       $('label').addClass('col-sm-2 control-label');
+
+
+    $('#form_description').summernote({
+               height: 150,
+               codemirror: { // codemirror options
+                       theme: 'monokai',
+                       lineNumbers: false,
+                       viewportMargin: Infinity //does not work, see below
+               }
+       });
+       //HACK (summernote set inline height for codable element...)
+       //$('note-codable').css('height', '');
+       //NOTE: there is also a bug after full screen : no autoresize...
+
+       $('.note-editor').addClass('col-sm-8');
+
+});
+
+function saveValidateSubmit()
+{
+       $('#form_description').html($('.note-editable').code());
+       //TODO: improve, should work also for code
+       //http://hackerwins.github.io/summernote/features.html#api-summernote
+       
+       //document.forms['upsert_form'].validate();
+       document.forms['upsert_form'].submit();
+}
+
+</script>
+
+{% endblock %}
diff --git a/src/Mixstore/UserBundle/Controller/BoardController.php b/src/Mixstore/UserBundle/Controller/BoardController.php
new file mode 100644 (file)
index 0000000..4e36e0e
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+
+namespace Mixstore\UserBundle\Controller;
+
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+
+class BoardController extends Controller
+{
+       public function indexAction()
+       {
+               if (is_null($this->getUser()))
+                       //TODO: nice error page
+                       return $this->redirect($this->generateUrl('mixstore_static_home'));
+               
+               $em = $this
+                       ->getDoctrine()
+                       ->getManager();
+               
+               $ucsRepository = $em
+                       ->getRepository('MixstoreStoreBundle:Usecase');
+               
+               $usecases = $ucsRepository
+                       ->findByUser($this->getUser()->getId());
+               
+               for ($i=0; $i<count($usecases); $i++)
+                       $usecases[$i]->software = $usecases[$i]->getPackage()->getName();
+               
+               $packages = $em
+                       ->getRepository('MixstoreStoreBundle:Package')
+                       ->findByUser($this->getUser()->getId());
+               
+               //TODO: fix code redundancy (see PackageController.php)
+               for ($i=0; $i<count($packages); $i++)
+               {
+                       $countAndRating = $ucsRepository->countByPkgId($packages[$i]->getId());
+                       if (is_null($countAndRating['rating']) || $countAndRating['rating'] == '')
+                               $countAndRating['rating'] = 'NA';
+                       $packages[$i]->ucscount = $countAndRating['ucscount'];
+                       $packages[$i]->rating = $countAndRating['rating'];
+               }
+               
+               return $this->render('MixstoreUserBundle:Board:index.html.twig', array(
+                       'packages' => $packages,
+                       'usecases' => $usecases,
+               ));
+       }
+}
diff --git a/src/Mixstore/UserBundle/Controller/MyAdminController.php b/src/Mixstore/UserBundle/Controller/MyAdminController.php
new file mode 100644 (file)
index 0000000..a025dab
--- /dev/null
@@ -0,0 +1,110 @@
+<?php
+
+namespace Mixstore\UserBundle\Controller;
+
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+use Mixstore\StoreBundle\Entity\Language;
+
+class MyAdminController extends Controller
+{
+       //helper
+       private function checkSuperAdmin()
+       {
+               $sadmin = $this->getUser();
+               if (is_null($sadmin) || !in_array('ROLE_SUPER_ADMIN', $sadmin->getRoles()))
+                       //TODO: nice error page
+                       return $this->redirect($this->generateUrl('mixstore_static_home'));
+       }
+       
+       //set initial languages
+       public function setLanguageAction()
+       {
+               $this->checkSuperAdmin();
+               
+               $em = $this->getDoctrine()->getManager();
+               foreach (array('C', 'C#', 'C++', 'Fortran', 'Java', 'Julia', 'Lua', 'MATLAB', 'Octave', 'Python', 'R', 'Scilab') as $lgName)
+                       $em->persist(new Language($lgName));
+               $em->flush();
+               
+               return new Response('OK');
+       }
+       
+       public function addLanguageAction($lgname)
+       {
+               $this->checkSuperAdmin();
+               
+               $em = $this->getDoctrine()->getManager();
+               $em->persist(new Language($lgname));
+               $em->flush();
+               
+               return new Response('OK');
+       }
+       
+       public function usersAction()
+       {
+               $this->checkSuperAdmin();
+               
+               return $this->render('MixstoreUserBundle:Admin:users.html.twig', array(
+               'users' => $this
+                       ->getDoctrine()
+                       ->getManager()
+                       ->getRepository('MixstoreUserBundle:User')
+                       ->findAll(),
+               ));
+       }
+       
+       public function toggleAction()
+       {
+               $this->checkSuperAdmin();
+               
+               //get id of user to toggle
+               $userId = $this->getRequest()->get('id');
+               //get user to toggle
+               $em = $this->getDoctrine()->getManager();
+               $user = $em
+                       ->getRepository('MixstoreUserBundle:User')
+                       ->findById($userId)[0];
+               
+               if (in_array('ROLE_ADMIN', $user->getRoles()))
+                       $user->setRoles(array('ROLE_USER'));
+               else
+                       $user->setRoles(array('ROLE_ADMIN'));
+               
+               //save new state
+               $em->persist($user);
+               $em->flush();
+               
+               //dummy unused answer (no error case for the moment)
+               return new Response('OK');
+       }
+       
+       public function deleteAction($id)
+       {
+               $this->checkSuperAdmin();
+               
+               $em = $this->getDoctrine()->getManager();
+               $user = $em
+                       ->getRepository('MixstoreUserBundle:User')
+                       ->findById($id)[0];
+               $em->remove($user);
+               $em->flush();
+               
+               return new Response('OK');
+       }
+       
+       //unique usage: set super admin
+       public function setsaAction()
+       {
+               $em = $this->getDoctrine()->getManager();
+               $sadmin = $em
+                       ->getRepository('MixstoreUserBundle:User')
+                       ->findById(1)[0]; //HACK: hard-coded ID
+               
+               $sadmin->setRoles(array('ROLE_ADMIN', 'ROLE_SUPER_ADMIN'));
+               $em->persist($sadmin);
+               $em->flush();
+               
+               return new response('OK');
+       }
+}
diff --git a/src/Mixstore/UserBundle/DependencyInjection/Configuration.php b/src/Mixstore/UserBundle/DependencyInjection/Configuration.php
new file mode 100644 (file)
index 0000000..99c2d0d
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+
+namespace Mixstore\UserBundle\DependencyInjection;
+
+use Symfony\Component\Config\Definition\Builder\TreeBuilder;
+use Symfony\Component\Config\Definition\ConfigurationInterface;
+
+/**
+ * This is the class that validates and merges configuration from your app/config files
+ *
+ * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
+ */
+class Configuration implements ConfigurationInterface
+{
+    /**
+     * {@inheritDoc}
+     */
+    public function getConfigTreeBuilder()
+    {
+        $treeBuilder = new TreeBuilder();
+        $rootNode = $treeBuilder->root('mixstore_user');
+
+        // Here you should define the parameters that are allowed to
+        // configure your bundle. See the documentation linked above for
+        // more information on that topic.
+
+        return $treeBuilder;
+    }
+}
diff --git a/src/Mixstore/UserBundle/DependencyInjection/MixstoreUserExtension.php b/src/Mixstore/UserBundle/DependencyInjection/MixstoreUserExtension.php
new file mode 100644 (file)
index 0000000..0e9711b
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+
+namespace Mixstore\UserBundle\DependencyInjection;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\Config\FileLocator;
+use Symfony\Component\HttpKernel\DependencyInjection\Extension;
+use Symfony\Component\DependencyInjection\Loader;
+
+/**
+ * This is the class that loads and manages your bundle configuration
+ *
+ * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
+ */
+class MixstoreUserExtension extends Extension
+{
+    /**
+     * {@inheritDoc}
+     */
+    public function load(array $configs, ContainerBuilder $container)
+    {
+        $configuration = new Configuration();
+        $config = $this->processConfiguration($configuration, $configs);
+
+        $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
+        $loader->load('services.yml');
+    }
+}
diff --git a/src/Mixstore/UserBundle/Entity/User.php b/src/Mixstore/UserBundle/Entity/User.php
new file mode 100644 (file)
index 0000000..0d8e5f0
--- /dev/null
@@ -0,0 +1,163 @@
+<?php
+
+namespace Mixstore\UserBundle\Entity;
+
+use FOS\UserBundle\Model\User as BaseUser;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity()
+ * @ORM\Table(name="ms_user")
+ */
+class User extends BaseUser
+{
+    /**
+     * @ORM\Id
+     * @ORM\Column(type="integer")
+     * @ORM\GeneratedValue(strategy="AUTO")
+     */
+    protected $id;
+    
+    /**
+     * @ORM\Column(type="string")
+     */
+    private $name;
+    
+    /**
+     * @ORM\Column(type="string")
+     */
+    private $surname;
+
+    /**
+     * @ORM\Column(type="boolean")
+     */
+    private $emailnotif0 = false;
+
+    /**
+     * @ORM\Column(type="boolean")
+     */
+    private $emailnotif1 = false;
+    
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Get id
+     *
+     * @return integer 
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    /**
+     * Set name
+     *
+     * @param string $name
+     * @return User
+     */
+    public function setName($name)
+    {
+        $this->name = $name;
+
+        return $this;
+    }
+
+    /**
+     * Get name
+     *
+     * @return string 
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * Set surname
+     *
+     * @param string $surname
+     * @return User
+     */
+    public function setSurname($surname)
+    {
+        $this->surname = $surname;
+
+        return $this;
+    }
+
+    /**
+     * Get surname
+     *
+     * @return string 
+     */
+    public function getSurname()
+    {
+        return $this->surname;
+    }
+    
+    /**
+     * Set email (override base behavior)
+     *
+     * @param string $email
+     * @return User
+     */
+    public function setEmail($email)
+       {
+               //http://stackoverflow.com/questions/8832916/remove-replace-the-username-field-with-email-using-fosuserbundle-in-symfony2
+               $email = is_null($email) ? '' : $email;
+               parent::setEmail($email);
+               $this->setUsername($email);
+               
+               return $this;
+       }
+
+    /**
+     * Set emailnotif0
+     *
+     * @param boolean $emailnotif0
+     * @return User
+     */
+    public function setEmailnotif0($emailnotif0)
+    {
+        $this->emailnotif0 = $emailnotif0;
+
+        return $this;
+    }
+
+    /**
+     * Get emailnotif0
+     *
+     * @return boolean 
+     */
+    public function getEmailnotif0()
+    {
+        return $this->emailnotif0;
+    }
+
+    /**
+     * Set emailnotif1
+     *
+     * @param boolean $emailnotif1
+     * @return User
+     */
+    public function setEmailnotif1($emailnotif1)
+    {
+        $this->emailnotif1 = $emailnotif1;
+
+        return $this;
+    }
+
+    /**
+     * Get emailnotif1
+     *
+     * @return boolean 
+     */
+    public function getEmailnotif1()
+    {
+        return $this->emailnotif1;
+    }
+}
diff --git a/src/Mixstore/UserBundle/Form/Type/ProfileFormType.php b/src/Mixstore/UserBundle/Form/Type/ProfileFormType.php
new file mode 100644 (file)
index 0000000..12e4bc2
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+
+namespace Mixstore\UserBundle\Form\Type;
+
+use Symfony\Component\Form\FormBuilderInterface;
+use FOS\UserBundle\Form\Type\ProfileFormType as BaseType;
+use Symfony\Component\Security\Core\SecurityContext;
+
+class ProfileFormType extends BaseType
+{
+       public function buildForm(FormBuilderInterface $builder, array $options)
+       {
+               parent::buildForm($builder, $options);
+
+               // add your custom field
+               $builder->remove('username');  // we use email as the username
+               $builder->add('name'); // first name
+               $builder->add('surname'); // last name
+               
+               //$user = $this->securityContext->getToken()->getUser();
+               // email notifications on packages/usecases creation
+               $builder->add('emailnotif0', 'checkbox', array('label' => 'Email notifications', 'required' => false));
+               // ...also on updates
+               $builder->add('emailnotif1', 'checkbox', array('label' => 'Also on updates', 'required' => false));
+       }
+
+       public function getName()
+       {
+               return 'mixstore_user_profile';
+       }
+}
diff --git a/src/Mixstore/UserBundle/Form/Type/RegistrationFormType.php b/src/Mixstore/UserBundle/Form/Type/RegistrationFormType.php
new file mode 100644 (file)
index 0000000..3d2c9f6
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+
+namespace Mixstore\UserBundle\Form\Type;
+
+use Symfony\Component\Form\FormBuilderInterface;
+use FOS\UserBundle\Form\Type\RegistrationFormType as BaseType;
+
+class RegistrationFormType extends BaseType
+{
+       public function buildForm(FormBuilderInterface $builder, array $options)
+       {
+               parent::buildForm($builder, $options);
+
+               // add your custom field
+               $builder->remove('username');  // we use email as the username
+               $builder->add('name'); // first name
+               $builder->add('surname'); // last name
+       }
+
+       public function getName()
+       {
+               return 'mixstore_user_registration';
+       }
+}
diff --git a/src/Mixstore/UserBundle/MixstoreUserBundle.php b/src/Mixstore/UserBundle/MixstoreUserBundle.php
new file mode 100644 (file)
index 0000000..754248d
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+
+namespace Mixstore\UserBundle;
+
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+class MixstoreUserBundle extends Bundle
+{
+       public function getParent()
+    {
+        return 'FOSUserBundle';
+    }
+}
diff --git a/src/Mixstore/UserBundle/Resources/config/config.yml b/src/Mixstore/UserBundle/Resources/config/config.yml
new file mode 100644 (file)
index 0000000..0888e2a
--- /dev/null
@@ -0,0 +1,74 @@
+Mixstore\UserBundle\Entity\User:
+    properties:
+    # Your custom fields in your user entity...
+        name:
+            - NotBlank:
+                message: mixstore_user.name.blank
+                groups: [ "MixstoreProfile" ]
+            - Length:
+                min: 2
+                minMessage: mixstore_user.name.short
+                max: 255
+                maxMessage: mixstore_user.name.long
+                groups: [ "MixstoreProfile" ]
+        surname:
+            - NotBlank:
+                message: mixstore_user.surname.blank
+                groups: [ "MixstoreProfile" ]
+            - Length:
+                min: 2
+                minMessage: mixstore_user.surname.short
+                max: 255
+                maxMessage: mixstore_user.surname.long
+                groups: [ "MixstoreProfile" ]
+
+# Note: We still want to validate the email
+# See FOSUserBundle/Resources/config/validation/orm.xml to understand
+# the UniqueEntity constraint that was originally applied to both
+# username and email fields
+#
+# As you can see, we are only applying the UniqueEntity constraint to 
+# the email field and not the username field.
+FOS\UserBundle\Model\User:
+    constraints:
+        - Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity: 
+             fields: email
+             errorPath: email 
+             message: fos_user.email.already_used
+             groups: [ "MixstoreRegistration", "MixstoreProfile" ]
+
+    properties:
+        email:
+            - NotBlank:
+                message: fos_user.email.blank
+                groups: [ "MixstoreRegistration", "MixstoreProfile" ]
+            - Length:
+                min: 2
+                minMessage: fos_user.email.short
+                max: 255
+                maxMessage: fos_user.email.long
+                groups: [ "MixstoreRegistration", "ResetPassword" ]
+            - Email:
+                message: fos_user.email.invalid
+                groups: [ "MixstoreRegistration", "MixstoreProfile" ]
+        plainPassword:
+            - NotBlank:
+                message: fos_user.password.blank
+                groups: [ "MixstoreRegistration", "ResetPassword", "ChangePassword" ]
+            - Length:
+                min: 2
+                minMessage: fos_user.password.blank
+                groups: [ "MixstoreRegistration", "MixstoreProfile", "ResetPassword", "ChangePassword"]
+
+FOS\UserBundle\Model\Group:
+    properties:
+        name:
+            - NotBlank:
+                message: fos_user.group.blank
+                groups: [ "MixstoreRegistration" ]
+            - Length:
+                min: 2
+                minMessage: fos_user.group.short
+                max: 255
+                maxMessage: fos_user.group.long
+                groups: [ "MixstoreRegistration" ]
diff --git a/src/Mixstore/UserBundle/Resources/config/routing.yml b/src/Mixstore/UserBundle/Resources/config/routing.yml
new file mode 100644 (file)
index 0000000..2f7107b
--- /dev/null
@@ -0,0 +1,50 @@
+fos_user_security:
+    resource: "@FOSUserBundle/Resources/config/routing/security.xml"
+    prefix: /security
+
+fos_user_profile:
+    resource: "@FOSUserBundle/Resources/config/routing/profile.xml"
+    prefix: /profile
+
+fos_user_register:
+    resource: "@FOSUserBundle/Resources/config/routing/registration.xml"
+    prefix: /register
+
+fos_user_resetting:
+    resource: "@FOSUserBundle/Resources/config/routing/resetting.xml"
+    prefix: /resetting
+
+fos_user_change_password:
+    resource: "@FOSUserBundle/Resources/config/routing/change_password.xml"
+    prefix: /security
+
+mixstore_user_board:
+    pattern: /board
+    defaults: { _controller: MixstoreUserBundle:Board:index }
+
+
+mixstore_user_admin_setsa:
+    pattern: /setsa
+    defaults: { _controller: MixstoreUserBundle:MyAdmin:setsa }
+
+mixstore_user_admin_users:
+    pattern: /admin/users
+    defaults: { _controller: MixstoreUserBundle:MyAdmin:users }
+
+mixstore_user_admin_toggle:
+    pattern: /admin/toggle
+    defaults: { _controller: MixstoreUserBundle:MyAdmin:toggle }
+
+mixstore_user_admin_delete:
+    pattern: /admin/delete/{id}
+    defaults: { _controller: MixstoreUserBundle:MyAdmin:delete }
+    requirements:
+        id: \d+
+
+mixstore_user_admin_addlanguage:
+    pattern: /admin/addLanguage/{lgname}
+    defaults: { _controller: MixstoreUserBundle:MyAdmin:addLanguage }
+
+mixstore_user_admin_setlanguage:
+    pattern: /admin/setLanguage
+    defaults: { _controller: MixstoreUserBundle:MyAdmin:setLanguage }
diff --git a/src/Mixstore/UserBundle/Resources/config/services.yml b/src/Mixstore/UserBundle/Resources/config/services.yml
new file mode 100644 (file)
index 0000000..f5e7fd2
--- /dev/null
@@ -0,0 +1,11 @@
+services:
+    mixstore_user.registration.form.type:
+        class: Mixstore\UserBundle\Form\Type\RegistrationFormType
+        arguments: [%fos_user.model.user.class%]
+        tags:
+            - { name: form.type, alias: mixstore_user_registration }
+    mixstore_user.profile.form.type:
+        class: Mixstore\UserBundle\Form\Type\ProfileFormType
+        arguments: [%fos_user.model.user.class%]
+        tags:
+            - { name: form.type, alias: mixstore_user_profile }
diff --git a/src/Mixstore/UserBundle/Resources/views/Admin/users.html.twig b/src/Mixstore/UserBundle/Resources/views/Admin/users.html.twig
new file mode 100644 (file)
index 0000000..e2c032f
--- /dev/null
@@ -0,0 +1,72 @@
+{% extends "::base.html.twig" %}
+
+{% block title %}{{ parent() }}users{% endblock %}
+
+{% block header %}
+{{ parent() }}
+<link rel="stylesheet" href="{{ asset('mixstore/css/user/admin.css') }}">
+{% endblock %}
+
+{% block content %}
+
+{% if is_granted('ROLE_SUPER_ADMIN') %}
+
+<div class="center">
+<h2>All users</h2>
+<h4>Click on a line to toggle privileges. Admins in <span class="blue">blue</span>. Super-admin(s) in <span class="red">red</span></h4>
+<table>
+       <thead>
+               <th>First name</th>
+               <th>Last name</th>
+               <th>Email</th>
+               <th></th>
+       </thead>
+       <tbody>
+       {% for user in users %}
+               <tr id="{{ user.id }}"
+               {% if 'ROLE_SUPER_ADMIN' in user.roles %}
+                       {{ 'class="red"' }}
+               {% elseif 'ROLE_ADMIN' in user.roles %}
+                       {{ 'class="user blue"' }}
+               {% else %}
+                       {{ 'class="user"' }}
+               {% endif %}
+               >
+                       <td>{{ user.name }}</td>
+                       <td>{{ user.surname }}</td>
+                       <td>{{ user.email }}</td>
+                       <td><a href="{{ path('mixstore_user_admin_delete', { id: user.id }) }}">Delete</a></td>
+               </tr>
+       {% endfor %}
+       </tbody>
+</table>
+</div>
+
+{% endif %}
+
+{% endblock %}
+
+{% block javascripts %}
+{{ parent() }}
+<script>
+$( "tr" ).click(function()
+{
+       //do nothing if super-admin is clicked
+       if ($(this).attr('class').indexOf("red") >= 0)
+               return;
+       
+       //save id for use in AJAX call
+       id = $(this).attr('id');
+    
+    //http://stackoverflow.com/questions/13584591/how-to-integrate-ajax-with-symfony2
+       $.post(
+               "{{ path('mixstore_user_admin_toggle') }}",               
+               {id: id}, 
+               function(response)
+               {
+                       $('#' + id).toggleClass("blue");
+               },
+               "text");
+});
+</script>
+{% endblock %}
diff --git a/src/Mixstore/UserBundle/Resources/views/Board/index.html.twig b/src/Mixstore/UserBundle/Resources/views/Board/index.html.twig
new file mode 100644 (file)
index 0000000..a343f21
--- /dev/null
@@ -0,0 +1,36 @@
+{% extends "::base.html.twig" %}
+
+{% block title %}{{ parent() }}user board{% endblock %}
+
+{% block header %}
+{{ parent() }}
+<link rel="stylesheet" href="{{ asset('mixstore/css/store/table.css') }}">
+<link rel="stylesheet" href="{{ asset('mixstore/css/user/board.css') }}">
+{% endblock %}
+
+{% block content %}
+
+<div id="packages" class="row">
+       <h2>My packages</h2>
+       {% include "MixstoreStoreBundle:Package:list_content.html.twig" %}
+       <a class="addnew" href="{{ path('mixstore_store_package_upsert') }}"><button type="button" class="btn btn-primary">New package</button></a>
+</div>
+
+<div id="usecases" class="row">
+       <h2>My usecases</h2>
+       {% include "MixstoreStoreBundle:Usecase:list_content.html.twig" %}
+       <a class="addnew" href="{{ path('mixstore_store_usecase_upsert') }}"><button type="button" class="btn btn-primary">New usecase</button></a> 
+</div>
+
+{% endblock %}
+
+{% block javascripts %}
+{{ parent() }}
+<script type="text/javascript" src="{{ asset('mixstore/js/stupidtable.min.js') }}"></script>
+<script>
+$(document).ready(function() 
+{ 
+       $(".sortable").stupidtable();
+});
+</script>
+{% endblock %}
diff --git a/src/Mixstore/UserBundle/Resources/views/ChangePassword/changePassword.html.twig b/src/Mixstore/UserBundle/Resources/views/ChangePassword/changePassword.html.twig
new file mode 100644 (file)
index 0000000..c0b4e7f
--- /dev/null
@@ -0,0 +1,18 @@
+{% extends "FOSUserBundle::layout.html.twig" %}
+
+{% block title %}{{ parent() }}change password{% endblock %}
+
+{% block fos_user_content %}
+{% trans_default_domain 'FOSUserBundle' %}
+
+<form action="{{ path('fos_user_change_password') }}"  method="post" class="fos_user_change_password form-horizontal">
+       {# TODO: do not ask for current password (?!) #}
+       {{ form_widget(form) }}
+       <div class="form-group">
+               <div class="col-sm-8 col-sm-offset-2">
+                       <button type="submit" class="btn btn-primary">{{ 'change_password.submit'|trans }}</button>
+               </div>
+       </div>
+</form>
+
+{% endblock fos_user_content %}
diff --git a/src/Mixstore/UserBundle/Resources/views/Profile/edit.html.twig b/src/Mixstore/UserBundle/Resources/views/Profile/edit.html.twig
new file mode 100644 (file)
index 0000000..66946ba
--- /dev/null
@@ -0,0 +1,18 @@
+{% extends "FOSUserBundle::layout.html.twig" %}
+
+{% block title %}{{ parent() }}edit profile{% endblock %}
+
+{% block fos_user_content %}
+{% trans_default_domain 'FOSUserBundle' %}
+
+<form action="{{ path('fos_user_profile_edit') }}" {{ form_enctype(form) }} method="post" class="fos_user_profile_edit form-horizontal">
+       {# TODO: do not ask for current password #}
+       {{ form_widget(form) }}
+       <div class="form-group">
+               <div class="col-sm-8 col-sm-offset-2">
+                       <button type="submit" class="btn btn-primary">{{ 'profile.edit.submit'|trans }}</button>
+               </div>
+       </div>
+</form>
+
+{% endblock fos_user_content %}
diff --git a/src/Mixstore/UserBundle/Resources/views/Profile/show.html.twig b/src/Mixstore/UserBundle/Resources/views/Profile/show.html.twig
new file mode 100644 (file)
index 0000000..442af44
--- /dev/null
@@ -0,0 +1,21 @@
+{% extends "FOSUserBundle::layout.html.twig" %}
+
+{% block title %}{{ parent() }}profile{% endblock %}
+
+{% block fos_user_content %}
+{% trans_default_domain 'FOSUserBundle' %}
+
+<div class="row">
+       <div class="col-xs-12 col-sm-7 col-sm-offset-5 fos_user_user_show">
+               <p>{{ 'profile.show.email'|trans }}: {{ user.email }}</p>
+               <p>First name: {{ user.name }}</p>
+               <p>Last name: {{ user.surname }}</p>
+               {% if user.emailnotif1 %}
+               <p>Notifications enabled for any creation or update</p>
+               {% elseif user.emailnotif0 %}
+               <p>Notifications enabled on packages/usecases creations</p>
+               {% endif %}
+       </div>
+</div>
+
+{% endblock fos_user_content %}
diff --git a/src/Mixstore/UserBundle/Resources/views/Registration/checkEmail.html.twig b/src/Mixstore/UserBundle/Resources/views/Registration/checkEmail.html.twig
new file mode 100644 (file)
index 0000000..f92f0b1
--- /dev/null
@@ -0,0 +1,10 @@
+{% extends "FOSUserBundle::layout.html.twig" %}
+
+{% block title %}{{ parent() }}check email{% endblock %}
+
+{% block fos_user_content %}
+{% trans_default_domain 'FOSUserBundle' %}
+
+    <div class="top-spaced col-xs-12 center-txt">{{ 'registration.check_email'|trans({'%email%': user.email}) }}</div>
+
+{% endblock fos_user_content %}
diff --git a/src/Mixstore/UserBundle/Resources/views/Registration/confirmed.html.twig b/src/Mixstore/UserBundle/Resources/views/Registration/confirmed.html.twig
new file mode 100644 (file)
index 0000000..b18c00a
--- /dev/null
@@ -0,0 +1,14 @@
+{% extends "FOSUserBundle::layout.html.twig" %}
+
+{% block title %}{{ parent() }}registration confirmed{% endblock %}
+
+{% block fos_user_content %}
+{% trans_default_domain 'FOSUserBundle' %}
+
+    <div class="top-spaced col-xs-12 center-txt">{{ 'registration.confirmed'|trans({'%username%': user.username}) }}</div>
+    {% if app.session is not empty %}
+        {% set targetUrl = app.session.get('_security.' ~ app.security.token.providerKey ~ '.target_path') %}
+        {% if targetUrl is not empty %}<div class="col-xs-12 center-txt"><a href="{{ targetUrl }}">{{ 'registration.back'|trans }}</a></div>{% endif %}
+    {% endif %}
+
+{% endblock fos_user_content %}
diff --git a/src/Mixstore/UserBundle/Resources/views/Registration/email.txt.twig b/src/Mixstore/UserBundle/Resources/views/Registration/email.txt.twig
new file mode 100644 (file)
index 0000000..726f539
--- /dev/null
@@ -0,0 +1,12 @@
+{% trans_default_domain 'FOSUserBundle' %}
+{% block subject %}
+{% autoescape false %}
+{{ 'registration.email.subject'|trans({'%username%': user.username, '%confirmationUrl%': confirmationUrl}) }}
+{% endautoescape %}
+{% endblock %}
+{% block body_text %}
+{% autoescape false %}
+{{ 'registration.email.message'|trans({'%username%': user.username, '%confirmationUrl%': confirmationUrl}) }}
+{% endautoescape %}
+{% endblock %}
+{% block body_html %}{% endblock %}
diff --git a/src/Mixstore/UserBundle/Resources/views/Registration/register.html.twig b/src/Mixstore/UserBundle/Resources/views/Registration/register.html.twig
new file mode 100644 (file)
index 0000000..3514b25
--- /dev/null
@@ -0,0 +1,17 @@
+{% extends "FOSUserBundle::layout.html.twig" %}
+
+{% block title %}{{ parent() }}register{% endblock %}
+
+{% block fos_user_content %}
+{% trans_default_domain 'FOSUserBundle' %}
+
+<form action="{{ path('fos_user_registration_register') }}" {{ form_enctype(form) }} method="post" class="fos_user_registration_register form-horizontal">
+       {{ form_widget(form) }}
+       <div class="form-group">
+      <div class="col-sm-8 col-sm-offset-2">
+        <button type="submit" class="btn btn-primary">{{ 'registration.submit'|trans }}</button>
+      </div>
+    </div>
+</form>
+
+{% endblock fos_user_content %}
diff --git a/src/Mixstore/UserBundle/Resources/views/Resetting/checkEmail.html.twig b/src/Mixstore/UserBundle/Resources/views/Resetting/checkEmail.html.twig
new file mode 100644 (file)
index 0000000..70e036f
--- /dev/null
@@ -0,0 +1,14 @@
+{% extends "FOSUserBundle::layout.html.twig" %}
+
+{% block title %}{{ parent() }}check email{% endblock %}
+
+{% block fos_user_content %}
+{% trans_default_domain 'FOSUserBundle' %}
+
+<div class="row">
+       <div class="col-xs-12 col-sm-6 col-sm-offset-3 fos_user_user_show">
+               {{ 'resetting.check_email'|trans({'%email%': email}) }}
+       </div>
+</div>
+
+{% endblock %}
diff --git a/src/Mixstore/UserBundle/Resources/views/Resetting/email.txt.twig b/src/Mixstore/UserBundle/Resources/views/Resetting/email.txt.twig
new file mode 100644 (file)
index 0000000..409aeeb
--- /dev/null
@@ -0,0 +1,12 @@
+{% trans_default_domain 'FOSUserBundle' %}
+{% block subject %}
+{% autoescape false %}
+{{ 'resetting.email.subject'|trans({'%username%': user.username, '%confirmationUrl%': confirmationUrl}) }}
+{% endautoescape %}
+{% endblock %}
+{% block body_text %}
+{% autoescape false %}
+{{ 'resetting.email.message'|trans({'%username%': user.username, '%confirmationUrl%': confirmationUrl}) }}
+{% endautoescape %}
+{% endblock %}
+{% block body_html %}{% endblock %}
diff --git a/src/Mixstore/UserBundle/Resources/views/Resetting/passwordAlreadyRequested.html.twig b/src/Mixstore/UserBundle/Resources/views/Resetting/passwordAlreadyRequested.html.twig
new file mode 100644 (file)
index 0000000..7e71a0c
--- /dev/null
@@ -0,0 +1,12 @@
+{% extends "FOSUserBundle::layout.html.twig" %}
+
+{% block title %}{{ parent() }}password already requested{% endblock %}
+
+{% block fos_user_content %}
+{% trans_default_domain 'FOSUserBundle' %}
+
+<div class="row">
+       <div class="col-xs-12 col-sm-6 col-sm-offset-3 fos_user_user_show">{{ 'resetting.password_already_requested'|trans }}</div>
+</div>
+
+{% endblock fos_user_content %}
diff --git a/src/Mixstore/UserBundle/Resources/views/Resetting/request.html.twig b/src/Mixstore/UserBundle/Resources/views/Resetting/request.html.twig
new file mode 100644 (file)
index 0000000..2fa5cf5
--- /dev/null
@@ -0,0 +1,25 @@
+{% extends "FOSUserBundle::layout.html.twig" %}
+
+{% block title %}{{ parent() }}request{% endblock %}
+
+{% block fos_user_content %}
+{% trans_default_domain 'FOSUserBundle' %}
+
+<form action="{{ path('fos_user_resetting_send_email') }}" method="post" class="fos_user_resetting_request form-horizontal">
+    <div class="form-group">
+        {% if invalid_username is defined %}
+            <p class="red center-txt">{{ 'resetting.request.invalid_username'|trans({'%username%': invalid_username}) }}</p>
+        {% endif %}
+        <label for="username" class="col-sm-2 control-label">{{ 'resetting.request.username'|trans }}</label>
+        <div class="col-sm-8">
+                       <input class="form-control" type="text" id="username" name="username" required="required" />
+               </div>
+    </div>
+    <div class="form-group">
+      <div class="col-sm-8 col-sm-offset-2">
+        <button type="submit" class="btn btn-primary">{{ 'resetting.request.submit'|trans }}</button>
+      </div>
+    </div>
+</form>
+
+{% endblock fos_user_content %}
diff --git a/src/Mixstore/UserBundle/Resources/views/Resetting/reset.html.twig b/src/Mixstore/UserBundle/Resources/views/Resetting/reset.html.twig
new file mode 100644 (file)
index 0000000..8c8527c
--- /dev/null
@@ -0,0 +1,17 @@
+{% extends "FOSUserBundle::layout.html.twig" %}
+
+{% block title %}{{ parent() }}reset{% endblock %}
+
+{% block fos_user_content %}
+{% trans_default_domain 'FOSUserBundle' %}
+
+<form action="{{ path('fos_user_resetting_reset', {'token': token}) }}" {{ form_enctype(form) }} method="post" class="fos_user_resetting_reset form-horizontal">
+    {{ form_widget(form) }}
+       <div class="form-group">
+      <div class="col-sm-8 col-sm-offset-2">
+        <button type="submit" class="btn btn-primary">{{ 'resetting.reset.submit'|trans }}</button>
+      </div>
+    </div>
+</form>
+
+{% endblock fos_user_content %}
diff --git a/src/Mixstore/UserBundle/Resources/views/Security/login.html.twig b/src/Mixstore/UserBundle/Resources/views/Security/login.html.twig
new file mode 100644 (file)
index 0000000..dd985b0
--- /dev/null
@@ -0,0 +1,54 @@
+{% extends "FOSUserBundle::layout.html.twig" %}
+
+{% block title %}{{ parent() }}login{% endblock %}
+
+{% block fos_user_content %}
+{% trans_default_domain 'FOSUserBundle' %}
+
+{% if error %}
+       <div class="row">
+               <div class="error col-xs-12">{{ error|trans }}</div>
+       </div>
+{% endif %}
+
+<div class="row">
+
+<form action="{{ path('fos_user_security_check') }}" method="post" class="fos_user_security_login form-horizontal">
+       <input type="hidden" name="_csrf_token" value="{{ csrf_token }}" />
+       <div class="form-group">
+               <label for="username" class="col-sm-2 control-label">Email</label>
+               <div class="col-sm-8">
+                       <input type="text" class="form-control" id="username" name="_username" value="{{ last_username }}">
+               </div>
+       </div>
+       <div class="form-group">
+               <label for="password" class="col-sm-2 control-label">{{ 'security.login.password'|trans }}</label>
+               <div class="col-sm-8">
+                       <input type="password" class="form-control" id="password" name="_password" required="required placeholder="Password">
+               </div>
+       </div>
+       <div class="form-group">
+               <label for="remember_me" class="col-sm-2 control-label">{{ 'security.login.remember_me'|trans }}</label>
+               <div class="col-sm-8">
+                       <input type="checkbox" id="remember_me" name="_remember_me" value="on">
+               </div>
+       </div>
+       <div class="form-group">
+               <div class="col-sm-8 col-sm-offset-2">
+                       <button type="submit" class="btn btn-primary">{{ 'security.login.submit'|trans }}</button>
+               </div>
+       </div>
+</form>
+
+</div>
+
+<div class="row">
+
+<div id="afterform" class="col-xs-11 col-xs-offset-1 col-sm-10 col-sm-offset-2">
+<p>New user ? <a href="{{ path('fos_user_registration_register') }}">Sign up</a> first !</p>
+<p><a href="{{ path('fos_user_resetting_request') }}">I have forgotten my password</a></p>
+</div>
+
+</div>
+
+{% endblock fos_user_content %}
diff --git a/src/Mixstore/UserBundle/Resources/views/layout.html.twig b/src/Mixstore/UserBundle/Resources/views/layout.html.twig
new file mode 100644 (file)
index 0000000..0bab823
--- /dev/null
@@ -0,0 +1,39 @@
+{% extends "::base.html.twig" %}
+
+{% block title %}{{ parent() }}user / {% endblock %}
+
+{% block header %}
+{{ parent() }}
+<link rel="stylesheet" href="{{ asset('mixstore/css/user/common.css') }}">
+<link rel="stylesheet" href="{{ asset('mixstore/css/form.css') }}">
+{% endblock %}
+
+{% block content %}
+
+{% for type, messages in app.session.flashbag.all() %}
+       {% for key, message in messages %}
+               <div class="row">
+                       <div class="col-xs-12 flash-message">
+                               {{ message|trans({}, 'FOSUserBundle') }}
+                       </div>
+               </div>
+       {% endfor %}
+{% endfor %}
+
+{% if form is defined %}
+       {% form_theme form ':Form:fields.html.twig' %}
+{% endif %}
+
+{% block fos_user_content %}
+{% endblock fos_user_content %}
+
+{% endblock %}
+
+{% block javascripts %}
+{{ parent() }}
+<script>
+$(document).ready(function() {
+       $('label').addClass('col-sm-2 control-label');
+});
+</script>
+{% endblock %}
diff --git a/web/.htaccess b/web/.htaccess
new file mode 100644 (file)
index 0000000..0c5f37d
--- /dev/null
@@ -0,0 +1,52 @@
+# Use the front controller as index file. It serves as a fallback solution when
+# every other rewrite/redirect fails (e.g. in an aliased environment without
+# mod_rewrite). Additionally, this reduces the matching process for the
+# start page (path "/") because otherwise Apache will apply the rewriting rules
+# to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl).
+DirectoryIndex app.php
+
+<IfModule mod_rewrite.c>
+    RewriteEngine On
+
+    # Determine the RewriteBase automatically and set it as environment variable.
+    # If you are using Apache aliases to do mass virtual hosting or installed the
+    # project in a subdirectory, the base path will be prepended to allow proper
+    # resolution of the app.php file and to redirect to the correct URI. It will
+    # work in environments without path prefix as well, providing a safe, one-size
+    # fits all solution. But as you do not need it in this case, you can comment
+    # the following 2 lines to eliminate the overhead.
+    RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
+    RewriteRule ^(.*) - [E=BASE:%1]
+
+    # Redirect to URI without front controller to prevent duplicate content
+    # (with and without `/app.php`). Only do this redirect on the initial
+    # rewrite by Apache and not on subsequent cycles. Otherwise we would get an
+    # endless redirect loop (request -> rewrite to front controller ->
+    # redirect -> request -> ...).
+    # So in case you get a "too many redirects" error or you always get redirected
+    # to the start page because your Apache does not expose the REDIRECT_STATUS
+    # environment variable, you have 2 choices:
+    # - disable this feature by commenting the following 2 lines or
+    # - use Apache >= 2.3.9 and replace all L flags by END flags and remove the
+    #   following RewriteCond (best solution)
+    RewriteCond %{ENV:REDIRECT_STATUS} ^$
+    RewriteRule ^app\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L]
+
+    # If the requested filename exists, simply serve it.
+    # We only want to let Apache serve files and not directories.
+    RewriteCond %{REQUEST_FILENAME} -f
+    RewriteRule .? - [L]
+
+    # Rewrite all other queries to the front controller.
+    RewriteRule .? %{ENV:BASE}/app.php [L]
+</IfModule>
+
+<IfModule !mod_rewrite.c>
+    <IfModule mod_alias.c>
+        # When mod_rewrite is not available, we instruct a temporary redirect of
+        # the start page to the front controller explicitly so that the website
+        # and the generated links can still be used.
+        RedirectMatch 302 ^/$ /app.php/
+        # RedirectTemp cannot be used instead
+    </IfModule>
+</IfModule>
diff --git a/web/app.php b/web/app.php
new file mode 100644 (file)
index 0000000..4f591c1
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+
+use Symfony\Component\ClassLoader\ApcClassLoader;
+use Symfony\Component\HttpFoundation\Request;
+
+$loader = require_once __DIR__.'/../app/bootstrap.php.cache';
+
+// Use APC for autoloading to improve performance.
+// Change 'sf2' to a unique prefix in order to prevent cache key conflicts
+// with other applications also using APC.
+/*
+$apcLoader = new ApcClassLoader('sf2', $loader);
+$loader->unregister();
+$apcLoader->register(true);
+*/
+
+require_once __DIR__.'/../app/AppKernel.php';
+//require_once __DIR__.'/../app/AppCache.php';
+
+$kernel = new AppKernel('prod', false);
+$kernel->loadClassCache();
+//$kernel = new AppCache($kernel);
+
+// When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter
+//Request::enableHttpMethodParameterOverride();
+$request = Request::createFromGlobals();
+$response = $kernel->handle($request);
+$response->send();
+$kernel->terminate($request, $response);
diff --git a/web/app_dev.php b/web/app_dev.php
new file mode 100644 (file)
index 0000000..872a882
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Debug\Debug;
+
+// If you don't want to setup permissions the proper way, just uncomment the following PHP line
+// read http://symfony.com/doc/current/book/installation.html#configuration-and-setup for more information
+//umask(0000);
+
+// This check prevents access to debug front controllers that are deployed by accident to production servers.
+// Feel free to remove this, extend it, or make something more sophisticated.
+if (isset($_SERVER['HTTP_CLIENT_IP'])
+    || isset($_SERVER['HTTP_X_FORWARDED_FOR'])
+    || !in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', 'fe80::1', '::1'))
+) {
+    header('HTTP/1.0 403 Forbidden');
+    exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
+}
+
+$loader = require_once __DIR__.'/../app/bootstrap.php.cache';
+Debug::enable();
+
+require_once __DIR__.'/../app/AppKernel.php';
+
+$kernel = new AppKernel('dev', true);
+$kernel->loadClassCache();
+$request = Request::createFromGlobals();
+$response = $kernel->handle($request);
+$response->send();
+$kernel->terminate($request, $response);
diff --git a/web/apple-touch-icon.png b/web/apple-touch-icon.png
new file mode 100644 (file)
index 0000000..11f17e6
Binary files /dev/null and b/web/apple-touch-icon.png differ
diff --git a/web/config.php b/web/config.php
new file mode 100644 (file)
index 0000000..162acfc
--- /dev/null
@@ -0,0 +1,124 @@
+<?php
+
+if (!isset($_SERVER['HTTP_HOST'])) {
+    exit('This script cannot be run from the CLI. Run it from a browser.');
+}
+
+if (!in_array(@$_SERVER['REMOTE_ADDR'], array(
+    '127.0.0.1',
+    '::1',
+))) {
+    header('HTTP/1.0 403 Forbidden');
+    exit('This script is only accessible from localhost.');
+}
+
+require_once dirname(__FILE__).'/../app/SymfonyRequirements.php';
+
+$symfonyRequirements = new SymfonyRequirements();
+
+$majorProblems = $symfonyRequirements->getFailedRequirements();
+$minorProblems = $symfonyRequirements->getFailedRecommendations();
+
+?>
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="robots" content="noindex,nofollow" />
+        <title>Symfony Configuration</title>
+        <link rel="stylesheet" href="bundles/framework/css/structure.css" media="all" />
+        <link rel="stylesheet" href="bundles/framework/css/body.css" media="all" />
+        <link rel="stylesheet" href="bundles/sensiodistribution/webconfigurator/css/install.css" media="all" />
+    </head>
+    <body>
+        <div id="content">
+            <div class="header clear-fix">
+                <div class="header-logo">
+                    <img src="bundles/framework/images/logo_symfony.png" alt="Symfony" />
+                </div>
+
+                <div class="search">
+                  <form method="get" action="http://symfony.com/search">
+                    <div class="form-row">
+
+                      <label for="search-id">
+                          <img src="bundles/framework/images/grey_magnifier.png" alt="Search on Symfony website" />
+                      </label>
+
+                      <input name="q" id="search-id" type="search" placeholder="Search on Symfony website" />
+
+                      <button type="submit" class="sf-button">
+                          <span class="border-l">
+                            <span class="border-r">
+                                <span class="btn-bg">OK</span>
+                            </span>
+                        </span>
+                      </button>
+                    </div>
+                   </form>
+                </div>
+            </div>
+
+            <div class="sf-reset">
+                <div class="block">
+                    <div class="symfony-block-content">
+                        <h1 class="title">Welcome!</h1>
+                        <p>Welcome to your new Symfony project.</p>
+                        <p>
+                            This script will guide you through the basic configuration of your project.
+                            You can also do the same by editing the ‘<strong>app/config/parameters.yml</strong>’ file directly.
+                        </p>
+
+                        <?php if (count($majorProblems)): ?>
+                            <h2 class="ko">Major problems</h2>
+                            <p>Major problems have been detected and <strong>must</strong> be fixed before continuing:</p>
+                            <ol>
+                                <?php foreach ($majorProblems as $problem): ?>
+                                    <li><?php echo $problem->getHelpHtml() ?></li>
+                                <?php endforeach; ?>
+                            </ol>
+                        <?php endif; ?>
+
+                        <?php if (count($minorProblems)): ?>
+                            <h2>Recommendations</h2>
+                            <p>
+                                <?php if (count($majorProblems)): ?>Additionally, to<?php else: ?>To<?php endif; ?> enhance your Symfony experience,
+                                it’s recommended that you fix the following:
+                            </p>
+                            <ol>
+                                <?php foreach ($minorProblems as $problem): ?>
+                                    <li><?php echo $problem->getHelpHtml() ?></li>
+                                <?php endforeach; ?>
+                            </ol>
+                        <?php endif; ?>
+
+                        <?php if ($symfonyRequirements->hasPhpIniConfigIssue()): ?>
+                            <p id="phpini">*
+                                <?php if ($symfonyRequirements->getPhpIniConfigPath()): ?>
+                                    Changes to the <strong>php.ini</strong> file must be done in "<strong><?php echo $symfonyRequirements->getPhpIniConfigPath() ?></strong>".
+                                <?php else: ?>
+                                    To change settings, create a "<strong>php.ini</strong>".
+                                <?php endif; ?>
+                            </p>
+                        <?php endif; ?>
+
+                        <?php if (!count($majorProblems) && !count($minorProblems)): ?>
+                            <p class="ok">Your configuration looks good to run Symfony.</p>
+                        <?php endif; ?>
+
+                        <ul class="symfony-install-continue">
+                            <?php if (!count($majorProblems)): ?>
+                                <li><a href="app_dev.php/_configurator/">Configure your Symfony Application online</a></li>
+                                <li><a href="app_dev.php/">Bypass configuration and go to the Welcome page</a></li>
+                            <?php endif; ?>
+                            <?php if (count($majorProblems) || count($minorProblems)): ?>
+                                <li><a href="config.php">Re-check configuration</a></li>
+                            <?php endif; ?>
+                        </ul>
+                    </div>
+                </div>
+            </div>
+            <div class="version">Symfony Standard Edition</div>
+        </div>
+    </body>
+</html>
diff --git a/web/favicon.ico b/web/favicon.ico
new file mode 100644 (file)
index 0000000..8648036
Binary files /dev/null and b/web/favicon.ico differ
diff --git a/web/mixstore/css/base.css b/web/mixstore/css/base.css
new file mode 100644 (file)
index 0000000..8605f5c
--- /dev/null
@@ -0,0 +1,129 @@
+html {
+       position: relative;
+       min-height: 100%;
+}
+
+body {
+       /* Margin bottom by footer height + 15px (??) */
+       margin-bottom: 65px;
+       font-size: 16px;
+       overflow-x: hidden; /* fix extra margin;
+http://stackoverflow.com/questions/23768152/using-container-fluid-within-bootstrap-cause-horizontal-scrollbar */
+}
+
+/*
+div {
+       font-size: 1.1em;
+}*/
+
+div.container-fluid {
+       margin-left: -15px;
+       margin-right: -15px;
+}
+
+div.row {
+       margin-left: 0;
+       margin-right: 0;
+}
+
+footer {
+       position: absolute;
+       bottom: 0;
+       width: 100%;
+       /* Set the fixed height of the footer here */
+       height: 65px;
+       background-color: #dd4814;
+       padding-top: 25px;
+       color: white;
+       text-align: center;
+}
+
+footer a {
+       color: black;
+}
+
+footer a:hover {
+       color: darkgrey;
+}
+
+/*
+.navbar-header {
+       padding-left: 5px;
+}
+.navbar-right {
+       padding-right: 5px;
+}
+*/
+
+.navbar {
+       border-radius: 0;
+       -webkit-border-radius: 0;
+       -moz-border-radius: 0;
+}
+
+.navbar-default .navbar-brand {
+       font-style: italic;
+       color: #C0C0C0;
+}
+
+@media screen and (min-width: 768px) { 
+li#storemenu {
+       display: block;
+       position: absolute;
+       top: 0;
+       left: 46%;
+}
+}
+
+@media (min-width: 768px) {
+.navbar-nav>li>a {/* middle between dd4814 and 97310e */
+background-color:#ba3c11;
+}
+}
+
+li#storemenu > a {
+       font-family: 'Merienda One', sans-serif;
+}
+
+li#loginmenu > a {
+       font-family: 'Merienda One', sans-serif;
+}
+
+div.navbar {
+       margin-bottom: 0;
+}
+
+@media screen and (max-width: 767px) {
+div.navbar-collapse {
+       padding-left: 0;
+       padding-right: 0;
+}
+ul.nav {
+       margin: 0;
+       padding: 0;
+}
+}
+
+.center-txt {
+       text-align: center;
+}
+
+.justify {
+       text-align: justify;
+}
+
+.bold {
+       font-weight: bold;
+}
+
+.red {
+       color: #ff0000;
+}
+
+.blue {
+       color: #0000ff;
+}
+
+.top-spaced {
+       margin-top: 20px;
+}
diff --git a/web/mixstore/css/form.css b/web/mixstore/css/form.css
new file mode 100644 (file)
index 0000000..3830495
--- /dev/null
@@ -0,0 +1,20 @@
+form {
+       margin-top: 25px;
+}
+
+div#afterform {
+       margin-top: 20px;
+}
+
+select {
+       margin-top: 9px;
+}
+
+input[type="checkbox"] {
+       margin-top: 13px;
+}
+
+input[type="file"] {
+       margin-top: 5px;
+       /*height: 48px; doesn't work well - TOFIX */
+}
diff --git a/web/mixstore/css/static/about.css b/web/mixstore/css/static/about.css
new file mode 100644 (file)
index 0000000..2bc4d18
--- /dev/null
@@ -0,0 +1,40 @@
+div#maintext {
+       padding-left: 5%;
+       padding-right: 5%;
+       padding-bottom: 15px;
+}
+
+figure {
+       text-align: center;
+}
+
+figure img {
+       width: 75%;
+}
+
+@media screen and (max-width: 500px) {
+figure img {
+       width: 95%;
+       width: 95%;
+}
+}
+
+@media screen and (min-width: 768px) {
+figure img {
+       width: 60%;
+       width: 60%;
+}
+}
+
+@media screen and (min-width: 1024px) {
+figure img {
+       width: 600px;
+       width: 500px;
+}
+}
+
+div.borderbottom {
+       border-bottom: 1px solid grey;
+       margin-bottom: 20px;
+       padding-bottom: 15px;
+}
diff --git a/web/mixstore/css/static/home.css b/web/mixstore/css/static/home.css
new file mode 100644 (file)
index 0000000..774987e
--- /dev/null
@@ -0,0 +1,114 @@
+div#carousel-example-generic {
+       border-bottom: 1px solid black;
+}
+
+h2, h3 {
+       text-align: center;
+}
+
+h2 {
+       font-size: 48px;
+}
+
+p, table {
+       font-size: 17px; /*1.3em*/
+}
+
+table {
+       margin: 0 auto;
+       width: 95%;
+       margin-top: 15px;
+}
+
+td {
+       border: 1px solid grey;
+       padding: 5px;
+}
+
+div.column {
+       text-align: center;
+       height: 350px;
+       padding-top: 30px;
+}
+
+@media screen and (max-width: 400px) {
+div.column {
+       padding-top: 15px;
+}
+}
+
+@media screen and (max-width: 767px) {
+div.column {
+       background-color: white;
+       border-bottom: 1px solid black;
+}
+div.xs-shrink {
+       height: 200px;
+}
+h2 {
+       padding-bottom: 15px;
+}
+}
+
+@media screen and (min-width: 768px) {
+div.column {
+       padding-left: 3%;
+       padding-right: 3%;
+}
+h2 {
+       padding-bottom: 24px;
+}
+}
+
+@media screen and (min-width: 1024px) {
+div.column {
+       padding-left: 5%;
+       padding-right: 5%;
+}
+}
+
+div.borderbottom {
+       border-bottom: 1px solid grey;
+}
+
+.grey-bg {
+       background-color: lightgrey;
+}
+
+div#home-carousel {
+       margin-top: 0;
+       width: 100%;
+}
+
+div.carousel-playpause {
+       position: absolute;
+       bottom: 1px;
+       z-index: 15;
+       width: 100%;
+       text-align: center;
+       list-style: none;
+       margin-bottom: 0;
+}
+
+div.carousel-playpause span {
+       padding-left: 0;
+       padding-right: 0;
+       font-size: 115%;
+       cursor: pointer;
+}
+
+@media screen and (min-width: 768px) {
+div.carousel-playpause span {
+       font-size: 150%;
+}
+}
+
+div.carousel-inner div.item img {
+       width: 100%;
+}
+
+@media screen and (max-width: 515px) {
+div.carousel-inner div.item img {
+       height: 150px;
+}
+}
diff --git a/web/mixstore/css/static/policy.css b/web/mixstore/css/static/policy.css
new file mode 100644 (file)
index 0000000..1900030
--- /dev/null
@@ -0,0 +1,18 @@
+div#maintext {
+       padding-left: 5%;
+       padding-right: 5%;
+}
+
+ol.policy li {
+       padding-top: 10px;
+       padding-bottom: 10px;
+}
+
+ol.policy li ul {
+       margin-bottom: 3px;
+}
+
+ol.policy li ul li {
+       padding-top: 1px;
+       padding-bottom: 1px;
+}
diff --git a/web/mixstore/css/store/table.css b/web/mixstore/css/store/table.css
new file mode 100644 (file)
index 0000000..bb1cca0
--- /dev/null
@@ -0,0 +1,50 @@
+table {
+       margin-left: auto;
+       margin-right: auto;
+       width: 100%;
+}
+
+@media screen and (min-width: 768px) { 
+table {
+       width: 95%;
+}
+}
+
+table, th, td {
+       text-align: center;
+}
+
+table > thead > tr > th {
+       border: 1px solid #ccc;
+       background-color: #E6FFCC;
+       padding: 13px 5px 13px 5px;
+}
+
+table > tbody > tr > td {
+       border: 1px solid #ccc;
+}
+
+tr:nth-of-type(even) { 
+       background: #eee; 
+}
+
+tr:nth-of-type(odd) { 
+       background: #fff; 
+}
+
+td a {
+       color: #2C3E50;
+       text-decoration: none;
+       display: block;
+       padding: 13px 5px 13px 5px;
+}
+
+td a:hover {
+       text-decoration: none;
+       color: #2C3E50;
+}
+
+th[data-sort]{
+       cursor:pointer;
+       color: #480000;
+}
diff --git a/web/mixstore/css/store/upsert.css b/web/mixstore/css/store/upsert.css
new file mode 100644 (file)
index 0000000..278b91b
--- /dev/null
@@ -0,0 +1,29 @@
+.btn-default {
+       background-color: #333
+}
+
+.note-editor {
+       padding-left: 0;
+       padding-right: 0;
+}
+
+.note-editor .note-editable {
+       background-color: #eee;
+}
+
+.note-editor .note-codable {
+       color: white;
+       background-color: #333;
+}
+
+/* next 2 rules should be used, but do not work with summernote [TOFIX] */
+/*
+.CodeMirror {
+       border: 1px solid #eee;
+       height: auto;
+}
+.CodeMirror-scroll {
+       overflow-y: hidden;
+       overflow-x: auto;
+}
+*/
diff --git a/web/mixstore/css/store/view-package.css b/web/mixstore/css/store/view-package.css
new file mode 100644 (file)
index 0000000..64f7e8e
--- /dev/null
@@ -0,0 +1,44 @@
+#pkgimage {
+       display: block;
+       width: 100%;
+}
+
+#header {
+       text-align: center;
+       padding-top: 15px;
+       padding-bottom: 15px;
+       border-bottom: 1px solid #ccc;
+}
+
+#description {
+       border-bottom: 1px solid #ccc;
+       padding: 15px 0 15px 15px;
+}
+
+#dependencies {
+       border-bottom: 1px solid #ccc;
+       padding: 15px 0 15px 15px;
+}
+
+#contact {
+       margin-top: 20px;
+       padding-left: 15px;
+}
+
+#moreinfo {
+       padding-left: 15px;
+}
+
+.flush-right {
+       text-align: right;
+}
+
+@media screen and (max-width: 515px) {
+img#pkgimage {
+       height: 150px;
+}
+}
+
+#admin {
+       margin-bottom: 20px;
+}
diff --git a/web/mixstore/css/store/view-usecase.css b/web/mixstore/css/store/view-usecase.css
new file mode 100644 (file)
index 0000000..115f433
--- /dev/null
@@ -0,0 +1,30 @@
+/* TODO: merge with view-package.css */
+
+#header {
+       text-align: center;
+       padding-top: 15px;
+       padding-bottom: 15px;
+       border-bottom: 1px solid #ccc;
+}
+
+#description {
+       border-bottom: 1px solid #ccc;
+       padding: 15px 0 15px 15px;
+       margin-bottom: 20px;
+}
+
+#contact {
+       padding-left: 15px;
+}
+
+#moreinfo {
+       padding-left: 15px;
+}
+
+.flush-right {
+       text-align: right;
+}
+
+#admin {
+       margin-bottom: 20px;
+}
diff --git a/web/mixstore/css/summernote.min.css b/web/mixstore/css/summernote.min.css
new file mode 100644 (file)
index 0000000..4dc3d1b
--- /dev/null
@@ -0,0 +1 @@
+.note-editor{border:1px solid #a9a9a9}.note-editor .note-dropzone{position:absolute;z-index:1;display:none;color:#87cefa;background-color:white;border:2px dashed #87cefa;opacity:.95;pointer-event:none}.note-editor .note-dropzone .note-dropzone-message{display:table-cell;font-size:28px;font-weight:bold;text-align:center;vertical-align:middle}.note-editor .note-dropzone.hover{color:#098ddf;border:2px dashed #098ddf}.note-editor.dragover .note-dropzone{display:table}.note-editor.fullscreen{position:fixed;top:0;left:0;z-index:1050;width:100%}.note-editor.fullscreen .note-editable{background-color:white}.note-editor.fullscreen .note-resizebar{display:none}.note-editor.codeview .note-editable{display:none}.note-editor.codeview .note-codable{display:block}.note-editor .note-toolbar{padding-bottom:5px;padding-left:5px;margin:0;background-color:#f5f5f5;border-bottom:1px solid #a9a9a9}.note-editor .note-toolbar>.btn-group{margin-top:5px;margin-right:5px;margin-left:0}.note-editor .note-toolbar .note-table .dropdown-menu{min-width:0;padding:5px}.note-editor .note-toolbar .note-table .dropdown-menu .note-dimension-picker{font-size:18px}.note-editor .note-toolbar .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-mousecatcher{position:absolute!important;z-index:3;width:10em;height:10em;cursor:pointer}.note-editor .note-toolbar .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-unhighlighted{position:relative!important;z-index:1;width:5em;height:5em;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIj4+Pjp6ekKlAqjAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKhmnaJzPAAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC') repeat}.note-editor .note-toolbar .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-highlighted{position:absolute!important;z-index:2;width:1em;height:1em;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIjd6vvD2f9LKLW+AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKwNDEVT0AAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC') repeat}.note-editor .note-toolbar .note-style h1,.note-editor .note-toolbar .note-style h2,.note-editor .note-toolbar .note-style h3,.note-editor .note-toolbar .note-style h4,.note-editor .note-toolbar .note-style h5,.note-editor .note-toolbar .note-style h6,.note-editor .note-toolbar .note-style blockquote{margin:0}.note-editor .note-toolbar .note-color .dropdown-toggle{width:20px;padding-left:5px}.note-editor .note-toolbar .note-color .dropdown-menu{min-width:290px}.note-editor .note-toolbar .note-color .dropdown-menu .btn-group{margin:0}.note-editor .note-toolbar .note-color .dropdown-menu .btn-group:first-child{margin:0 5px}.note-editor .note-toolbar .note-color .dropdown-menu .btn-group .note-palette-title{margin:2px 7px;font-size:12px;text-align:center;border-bottom:1px solid #eee}.note-editor .note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset{padding:0 3px;margin:5px;font-size:12px;cursor:pointer;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.note-editor .note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset:hover{background:#eee}.note-editor .note-toolbar .note-para .dropdown-menu{min-width:216px;padding:5px}.note-editor .note-toolbar .note-para .dropdown-menu>div:first-child{margin-right:5px}.note-editor .note-statusbar{background-color:#f5f5f5}.note-editor .note-statusbar .note-resizebar{width:100%;height:8px;cursor:s-resize;border-top:1px solid #a9a9a9}.note-editor .note-statusbar .note-resizebar .note-icon-bar{width:20px;margin:1px auto;border-top:1px solid #a9a9a9}.note-editor .note-popover .popover{max-width:none}.note-editor .note-popover .popover .popover-content{padding:5px}.note-editor .note-popover .popover .popover-content a{display:inline-block;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}.note-editor .note-popover .popover .popover-content .btn-group+.btn-group{margin-left:5px}.note-editor .note-popover .popover .arrow{left:20px}.note-editor .note-handle .note-control-selection{position:absolute;display:none;border:1px solid black}.note-editor .note-handle .note-control-selection>div{position:absolute}.note-editor .note-handle .note-control-selection .note-control-selection-bg{width:100%;height:100%;background-color:black;-webkit-opacity:.3;-khtml-opacity:.3;-moz-opacity:.3;opacity:.3;-ms-filter:alpha(opacity=30);filter:alpha(opacity=30)}.note-editor .note-handle .note-control-selection .note-control-handle{width:7px;height:7px;border:1px solid black}.note-editor .note-handle .note-control-selection .note-control-holder{width:7px;height:7px;border:1px solid black}.note-editor .note-handle .note-control-selection .note-control-sizing{width:7px;height:7px;background-color:white;border:1px solid black}.note-editor .note-handle .note-control-selection .note-control-nw{top:-5px;left:-5px;border-right:0;border-bottom:0}.note-editor .note-handle .note-control-selection .note-control-ne{top:-5px;right:-5px;border-bottom:0;border-left:none}.note-editor .note-handle .note-control-selection .note-control-sw{bottom:-5px;left:-5px;border-top:0;border-right:0}.note-editor .note-handle .note-control-selection .note-control-se{right:-5px;bottom:-5px;cursor:se-resize}.note-editor .note-handle .note-control-selection .note-control-selection-info{right:0;bottom:0;padding:5px;margin:5px;font-size:12px;color:white;background-color:black;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;-webkit-opacity:.7;-khtml-opacity:.7;-moz-opacity:.7;opacity:.7;-ms-filter:alpha(opacity=70);filter:alpha(opacity=70)}.note-editor .note-dialog>div{display:none}.note-editor .note-dialog .note-image-dialog .note-dropzone{min-height:100px;margin-bottom:10px;font-size:30px;line-height:4;color:lightgray;text-align:center;border:4px dashed lightgray}.note-editor .note-dialog .note-help-dialog{font-size:12px;color:#ccc;background:transparent;background-color:#222!important;border:0;-webkit-opacity:.9;-khtml-opacity:.9;-moz-opacity:.9;opacity:.9;-ms-filter:alpha(opacity=90);filter:alpha(opacity=90)}.note-editor .note-dialog .note-help-dialog .modal-content{background:transparent;border:1px solid white;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.note-editor .note-dialog .note-help-dialog a{font-size:12px;color:white}.note-editor .note-dialog .note-help-dialog .title{padding-bottom:5px;font-size:14px;font-weight:bold;color:white;border-bottom:white 1px solid}.note-editor .note-dialog .note-help-dialog .modal-close{font-size:14px;color:#dd0;cursor:pointer}.note-editor .note-dialog .note-help-dialog .note-shortcut-layout{width:100%}.note-editor .note-dialog .note-help-dialog .note-shortcut-layout td{vertical-align:top}.note-editor .note-dialog .note-help-dialog .note-shortcut{margin-top:8px}.note-editor .note-dialog .note-help-dialog .note-shortcut th{font-size:13px;color:#dd0;text-align:left}.note-editor .note-dialog .note-help-dialog .note-shortcut td:first-child{min-width:110px;padding-right:10px;font-family:"Courier New";color:#dd0;text-align:right}.note-editor .note-editable{padding:10px;overflow:auto;outline:0}.note-editor .note-editable[contenteditable="false"]{background-color:#e5e5e5}.note-editor .note-codable{display:none;width:100%;padding:10px;margin-bottom:0;font-family:Menlo,Monaco,monospace,sans-serif;font-size:14px;color:#ccc;background-color:#222;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;box-shadow:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;resize:none}.note-editor .dropdown-menu{min-width:90px}.note-editor .dropdown-menu.right{right:0;left:auto}.note-editor .dropdown-menu.right::before{right:9px;left:auto!important}.note-editor .dropdown-menu.right::after{right:10px;left:auto!important}.note-editor .dropdown-menu li a i{color:deepskyblue;visibility:hidden}.note-editor .dropdown-menu li a.checked i{visibility:visible}.note-editor .note-fontsize-10{font-size:10px}.note-editor .note-color-palette{line-height:1}.note-editor .note-color-palette div .note-color-btn{width:17px;height:17px;padding:0;margin:0;border:1px solid #fff}.note-editor .note-color-palette div .note-color-btn:hover{border:1px solid #000}
\ No newline at end of file
diff --git a/web/mixstore/css/user/admin.css b/web/mixstore/css/user/admin.css
new file mode 100644 (file)
index 0000000..2231dd7
--- /dev/null
@@ -0,0 +1,26 @@
+tr.user {
+       cursor: pointer;
+}
+
+h2, h4 {
+       text-align: center;
+}
+
+table {
+       margin: 0 auto;
+       width: 75%;
+       margin-top: 15px;
+}
+
+td {
+       border: 1px solid grey;
+       padding: 5px;
+}
+
+tr:nth-child(even) {
+       background-color: #eee;
+}
+
+tr:nth-child(odd) {
+       background-color: #fff;
+}
diff --git a/web/mixstore/css/user/board.css b/web/mixstore/css/user/board.css
new file mode 100644 (file)
index 0000000..4e8be2e
--- /dev/null
@@ -0,0 +1,18 @@
+a.addnew {
+       display: block;
+       text-align: center;
+       margin-top: 10px;
+}
+
+h2 {
+       text-align: center;
+}
+
+#packages {
+       border-bottom: 1px solid #ccc;
+       padding-bottom: 25px;
+}
+
+#usecases {
+       padding-bottom: 10px;
+}
diff --git a/web/mixstore/css/user/common.css b/web/mixstore/css/user/common.css
new file mode 100644 (file)
index 0000000..08137e2
--- /dev/null
@@ -0,0 +1,23 @@
+div.fos_user_user_show {
+       padding-top: 15px;
+       margin-bottom: 0;
+}
+
+h1 {
+       color: grey;
+       text-align: center;
+       margin-top: 15px;
+       margin-bottom: 15px;
+}
+
+div.flash-message {
+       text-align: center;
+       margin-top: 20px;
+       color: blue;
+}
+
+div.error {
+       text-align: center;
+       margin-top: 20px;
+       color: red;
+}
diff --git a/web/mixstore/fonts/glyphicons-halflings-regular.eot b/web/mixstore/fonts/glyphicons-halflings-regular.eot
new file mode 100644 (file)
index 0000000..4a4ca86
Binary files /dev/null and b/web/mixstore/fonts/glyphicons-halflings-regular.eot differ
diff --git a/web/mixstore/fonts/glyphicons-halflings-regular.svg b/web/mixstore/fonts/glyphicons-halflings-regular.svg
new file mode 100644 (file)
index 0000000..e3e2dc7
--- /dev/null
@@ -0,0 +1,229 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
+<font-face units-per-em="1200" ascent="960" descent="-240" />
+<missing-glyph horiz-adv-x="500" />
+<glyph />
+<glyph />
+<glyph unicode="&#xd;" />
+<glyph unicode=" " />
+<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" />
+<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" />
+<glyph unicode="&#xa0;" />
+<glyph unicode="&#x2000;" horiz-adv-x="652" />
+<glyph unicode="&#x2001;" horiz-adv-x="1304" />
+<glyph unicode="&#x2002;" horiz-adv-x="652" />
+<glyph unicode="&#x2003;" horiz-adv-x="1304" />
+<glyph unicode="&#x2004;" horiz-adv-x="434" />
+<glyph unicode="&#x2005;" horiz-adv-x="326" />
+<glyph unicode="&#x2006;" horiz-adv-x="217" />
+<glyph unicode="&#x2007;" horiz-adv-x="217" />
+<glyph unicode="&#x2008;" horiz-adv-x="163" />
+<glyph unicode="&#x2009;" horiz-adv-x="260" />
+<glyph unicode="&#x200a;" horiz-adv-x="72" />
+<glyph unicode="&#x202f;" horiz-adv-x="260" />
+<glyph unicode="&#x205f;" horiz-adv-x="326" />
+<glyph unicode="&#x20ac;" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" />
+<glyph unicode="&#x2212;" d="M200 400h900v300h-900v-300z" />
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#x2601;" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" />
+<glyph unicode="&#x2709;" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" />
+<glyph unicode="&#x270f;" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" />
+<glyph unicode="&#xe001;" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" />
+<glyph unicode="&#xe002;" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q18 -55 86 -75.5t147 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" />
+<glyph unicode="&#xe003;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" />
+<glyph unicode="&#xe005;" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" />
+<glyph unicode="&#xe006;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" />
+<glyph unicode="&#xe007;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" />
+<glyph unicode="&#xe008;" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" />
+<glyph unicode="&#xe009;" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" />
+<glyph unicode="&#xe010;" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe011;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe012;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe013;" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" />
+<glyph unicode="&#xe014;" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" />
+<glyph unicode="&#xe015;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" />
+<glyph unicode="&#xe016;" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" />
+<glyph unicode="&#xe017;" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" />
+<glyph unicode="&#xe018;" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" />
+<glyph unicode="&#xe019;" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" />
+<glyph unicode="&#xe020;" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" />
+<glyph unicode="&#xe021;" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" />
+<glyph unicode="&#xe022;" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" />
+<glyph unicode="&#xe023;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" />
+<glyph unicode="&#xe024;" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" />
+<glyph unicode="&#xe025;" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" />
+<glyph unicode="&#xe026;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" />
+<glyph unicode="&#xe027;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" />
+<glyph unicode="&#xe028;" d="M0 25v475l200 700h800l199 -700l1 -475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" />
+<glyph unicode="&#xe029;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" />
+<glyph unicode="&#xe030;" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" />
+<glyph unicode="&#xe031;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" />
+<glyph unicode="&#xe032;" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" />
+<glyph unicode="&#xe033;" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" />
+<glyph unicode="&#xe034;" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" />
+<glyph unicode="&#xe035;" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" />
+<glyph unicode="&#xe036;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" />
+<glyph unicode="&#xe037;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" />
+<glyph unicode="&#xe038;" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" />
+<glyph unicode="&#xe039;" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" />
+<glyph unicode="&#xe040;" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" />
+<glyph unicode="&#xe041;" d="M0 700l1 475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" />
+<glyph unicode="&#xe042;" d="M1 700l1 475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" />
+<glyph unicode="&#xe043;" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" />
+<glyph unicode="&#xe044;" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" />
+<glyph unicode="&#xe045;" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" />
+<glyph unicode="&#xe046;" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" />
+<glyph unicode="&#xe047;" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" />
+<glyph unicode="&#xe048;" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v71l471 -1q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" />
+<glyph unicode="&#xe049;" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" />
+<glyph unicode="&#xe050;" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " />
+<glyph unicode="&#xe051;" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" />
+<glyph unicode="&#xe052;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe053;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe054;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe055;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe056;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe057;" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe058;" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" />
+<glyph unicode="&#xe059;" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" />
+<glyph unicode="&#xe060;" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " />
+<glyph unicode="&#xe062;" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" />
+<glyph unicode="&#xe063;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" />
+<glyph unicode="&#xe064;" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 139t-64 210zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" />
+<glyph unicode="&#xe065;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" />
+<glyph unicode="&#xe066;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" />
+<glyph unicode="&#xe067;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q61 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l567 567l-137 137l-430 -431l-146 147z" />
+<glyph unicode="&#xe068;" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" />
+<glyph unicode="&#xe069;" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe070;" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe071;" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" />
+<glyph unicode="&#xe072;" d="M200 0l900 550l-900 550v-1100z" />
+<glyph unicode="&#xe073;" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
+<glyph unicode="&#xe074;" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
+<glyph unicode="&#xe075;" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" />
+<glyph unicode="&#xe076;" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" />
+<glyph unicode="&#xe077;" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" />
+<glyph unicode="&#xe078;" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" />
+<glyph unicode="&#xe079;" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" />
+<glyph unicode="&#xe080;" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" />
+<glyph unicode="&#xe081;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" />
+<glyph unicode="&#xe082;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h600v200h-600v-200z" />
+<glyph unicode="&#xe083;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141 z" />
+<glyph unicode="&#xe084;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" />
+<glyph unicode="&#xe085;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM364 700h143q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5 q19 0 30 -10t11 -26q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-50 0 -90.5 -12t-75 -38.5t-53.5 -74.5t-19 -114zM500 300h200v100h-200 v-100z" />
+<glyph unicode="&#xe086;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" />
+<glyph unicode="&#xe087;" d="M0 500v200h195q31 125 98.5 199.5t206.5 100.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200v-206 q149 48 201 206h-201v200h200q-25 74 -75.5 127t-124.5 77v-204h-200v203q-75 -23 -130 -77t-79 -126h209v-200h-210z" />
+<glyph unicode="&#xe088;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" />
+<glyph unicode="&#xe089;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" />
+<glyph unicode="&#xe090;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" />
+<glyph unicode="&#xe091;" d="M0 547l600 453v-300h600v-300h-600v-301z" />
+<glyph unicode="&#xe092;" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" />
+<glyph unicode="&#xe093;" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" />
+<glyph unicode="&#xe094;" d="M104 600h296v600h300v-600h298l-449 -600z" />
+<glyph unicode="&#xe095;" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" />
+<glyph unicode="&#xe096;" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" />
+<glyph unicode="&#xe097;" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" />
+<glyph unicode="&#xe101;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5h-207q-21 0 -33 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" />
+<glyph unicode="&#xe102;" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111q1 1 1 6.5t-1.5 15t-3.5 17.5l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6 h-111v-100zM100 0h400v400h-400v-400zM200 900q-3 0 14 48t36 96l18 47l213 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" />
+<glyph unicode="&#xe103;" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" />
+<glyph unicode="&#xe104;" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" />
+<glyph unicode="&#xe105;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" />
+<glyph unicode="&#xe106;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" />
+<glyph unicode="&#xe107;" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 34 -48 36.5t-48 -29.5l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" />
+<glyph unicode="&#xe108;" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -20 -13 -28.5t-32 0.5l-94 78h-222l-94 -78q-19 -9 -32 -0.5t-13 28.5 v64q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" />
+<glyph unicode="&#xe109;" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" />
+<glyph unicode="&#xe110;" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" />
+<glyph unicode="&#xe111;" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" />
+<glyph unicode="&#xe112;" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" />
+<glyph unicode="&#xe113;" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" />
+<glyph unicode="&#xe114;" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" />
+<glyph unicode="&#xe115;" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" />
+<glyph unicode="&#xe116;" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" />
+<glyph unicode="&#xe117;" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" />
+<glyph unicode="&#xe118;" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" />
+<glyph unicode="&#xe119;" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" />
+<glyph unicode="&#xe120;" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" />
+<glyph unicode="&#xe121;" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" />
+<glyph unicode="&#xe122;" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM100 500v250v8v8v7t0.5 7t1.5 5.5t2 5t3 4t4.5 3.5t6 1.5t7.5 0.5h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35 q-55 337 -55 351zM1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe123;" d="M74 350q0 21 13.5 35.5t33.5 14.5h18l117 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5q-18 -36 -18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-8 -3 -23 -8.5 t-65 -20t-103 -25t-132.5 -19.5t-158.5 -9q-125 0 -245.5 20.5t-178.5 40.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" />
+<glyph unicode="&#xe124;" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" />
+<glyph unicode="&#xe125;" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q124 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 213l100 212h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" />
+<glyph unicode="&#xe126;" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q124 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" />
+<glyph unicode="&#xe127;" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" />
+<glyph unicode="&#xe128;" d="M-101 651q0 72 54 110t139 38l302 -1l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 17 -10.5t26.5 -26t16.5 -36.5v-526q0 -13 -86 -93.5t-94 -80.5h-341q-16 0 -29.5 20t-19.5 41l-130 339h-107q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l107 89v502l-343 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM1000 201v600h200v-600h-200z" />
+<glyph unicode="&#xe129;" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6.5v7.5v6.5v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" />
+<glyph unicode="&#xe130;" d="M2 585q-16 -31 6 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85q0 -51 -0.5 -153.5t-0.5 -148.5q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM77 565l236 339h503 l89 -100v-294l-340 -130q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" />
+<glyph unicode="&#xe131;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM298 701l2 -201h300l-2 -194l402 294l-402 298v-197h-300z" />
+<glyph unicode="&#xe132;" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l402 -294l-2 194h300l2 201h-300v197z" />
+<glyph unicode="&#xe133;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" />
+<glyph unicode="&#xe134;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" />
+<glyph unicode="&#xe135;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -33 5.5 -92.5t7.5 -87.5q0 -9 17 -44t16 -60 q12 0 23 -5.5t23 -15t20 -13.5q24 -12 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55t-20 -57q42 -71 87 -80q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q104 -3 221 112q30 29 47 47t34.5 49t20.5 62q-14 9 -37 9.5t-36 7.5q-14 7 -49 15t-52 19q-9 0 -39.5 -0.5 t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5t5.5 57.5 q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 39 2 44q31 -13 58 -14.5t39 3.5l11 4q7 36 -16.5 53.5t-64.5 28.5t-56 23q-19 -3 -37 0 q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -45.5 0.5t-45.5 -2.5q-21 -7 -52 -26.5t-34 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -90.5t-29.5 -79.5zM518 916q3 12 16 30t16 25q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -24 17 -66.5t17 -43.5 q-9 2 -31 5t-36 5t-32 8t-30 14zM692 1003h1h-1z" />
+<glyph unicode="&#xe136;" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" />
+<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" />
+<glyph unicode="&#xe138;" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" />
+<glyph unicode="&#xe139;" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" />
+<glyph unicode="&#xe140;" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" />
+<glyph unicode="&#xe141;" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM514 609q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-14 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" />
+<glyph unicode="&#xe142;" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -78.5 -16.5t-67.5 -51.5l-389 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23 q38 0 53 -36q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60 l517 511q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" />
+<glyph unicode="&#xe143;" d="M80 784q0 131 98.5 229.5t230.5 98.5q143 0 241 -129q103 129 246 129q129 0 226 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100q-71 70 -104.5 105.5t-77 89.5t-61 99 t-17.5 91zM250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-105 48.5q-74 0 -132 -83l-118 -171l-114 174q-51 80 -123 80q-60 0 -109.5 -49.5t-49.5 -118.5z" />
+<glyph unicode="&#xe144;" d="M57 353q0 -95 66 -159l141 -142q68 -66 159 -66q93 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-8 9 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141q7 -7 19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -17q47 -49 77 -100l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" />
+<glyph unicode="&#xe145;" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" />
+<glyph unicode="&#xe146;" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" />
+<glyph unicode="&#xe148;" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335q-6 1 -15.5 4t-11.5 3q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5 v-307l64 -14q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5 zM700 237q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" />
+<glyph unicode="&#xe149;" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -28 16.5 -69.5t28 -62.5t41.5 -72h241v-100h-197q8 -50 -2.5 -115 t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q33 1 103 -16t103 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221z" />
+<glyph unicode="&#xe150;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" />
+<glyph unicode="&#xe151;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" />
+<glyph unicode="&#xe152;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" />
+<glyph unicode="&#xe153;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" />
+<glyph unicode="&#xe154;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" />
+<glyph unicode="&#xe155;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" />
+<glyph unicode="&#xe156;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" />
+<glyph unicode="&#xe157;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" />
+<glyph unicode="&#xe158;" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" />
+<glyph unicode="&#xe159;" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" />
+<glyph unicode="&#xe160;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" />
+<glyph unicode="&#xe161;" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" />
+<glyph unicode="&#xe162;" d="M217 519q8 -19 31 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8h9q14 0 26 15q11 13 274.5 321.5t264.5 308.5q14 19 5 36q-8 17 -31 17l-301 -1q1 4 78 219.5t79 227.5q2 15 -5 27l-9 9h-9q-15 0 -25 -16q-4 -6 -98 -111.5t-228.5 -257t-209.5 -237.5q-16 -19 -6 -41 z" />
+<glyph unicode="&#xe163;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " />
+<glyph unicode="&#xe164;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" />
+<glyph unicode="&#xe165;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" />
+<glyph unicode="&#xe166;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe167;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe168;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe169;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 400l697 1l3 699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe170;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l249 -237l-1 697zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe171;" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" />
+<glyph unicode="&#xe172;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" />
+<glyph unicode="&#xe173;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" />
+<glyph unicode="&#xe174;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" />
+<glyph unicode="&#xe175;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" />
+<glyph unicode="&#xe176;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" />
+<glyph unicode="&#xe177;" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" />
+<glyph unicode="&#xe178;" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" />
+<glyph unicode="&#xe179;" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -116q-25 -17 -43.5 -51.5t-18.5 -65.5v-359z" />
+<glyph unicode="&#xe180;" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" />
+<glyph unicode="&#xe181;" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" />
+<glyph unicode="&#xe182;" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q17 18 13.5 41t-22.5 37l-192 136q-19 14 -45 12t-42 -19l-118 -118q-142 101 -268 227t-227 268l118 118q17 17 20 41.5t-11 44.5 l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" />
+<glyph unicode="&#xe183;" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-20 0 -35 14.5t-15 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" />
+<glyph unicode="&#xe184;" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" />
+<glyph unicode="&#xe185;" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" />
+<glyph unicode="&#xe186;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
+<glyph unicode="&#xe187;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
+<glyph unicode="&#xe188;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" />
+<glyph unicode="&#xe189;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" />
+<glyph unicode="&#xe190;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" />
+<glyph unicode="&#xe191;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
+<glyph unicode="&#xe192;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
+<glyph unicode="&#xe193;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" />
+<glyph unicode="&#xe194;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" />
+<glyph unicode="&#xe195;" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" />
+<glyph unicode="&#xe197;" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300h200 l-300 -300z" />
+<glyph unicode="&#xe198;" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104.5t60.5 178.5q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" />
+<glyph unicode="&#xe199;" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
+<glyph unicode="&#xe200;" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
+</font>
+</defs></svg> 
\ No newline at end of file
diff --git a/web/mixstore/fonts/glyphicons-halflings-regular.ttf b/web/mixstore/fonts/glyphicons-halflings-regular.ttf
new file mode 100644 (file)
index 0000000..67fa00b
Binary files /dev/null and b/web/mixstore/fonts/glyphicons-halflings-regular.ttf differ
diff --git a/web/mixstore/fonts/glyphicons-halflings-regular.woff b/web/mixstore/fonts/glyphicons-halflings-regular.woff
new file mode 100644 (file)
index 0000000..8c54182
Binary files /dev/null and b/web/mixstore/fonts/glyphicons-halflings-regular.woff differ
diff --git a/web/mixstore/images/banner.png b/web/mixstore/images/banner.png
new file mode 100644 (file)
index 0000000..34735c0
Binary files /dev/null and b/web/mixstore/images/banner.png differ
diff --git a/web/mixstore/images/favicon.png b/web/mixstore/images/favicon.png
new file mode 100644 (file)
index 0000000..4c01f14
Binary files /dev/null and b/web/mixstore/images/favicon.png differ
diff --git a/web/mixstore/images/iris_pca.png b/web/mixstore/images/iris_pca.png
new file mode 100644 (file)
index 0000000..71fe470
Binary files /dev/null and b/web/mixstore/images/iris_pca.png differ
diff --git a/web/mixstore/images/pkg_banners/.gitignore b/web/mixstore/images/pkg_banners/.gitignore
new file mode 100644 (file)
index 0000000..d6b7ef3
--- /dev/null
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/web/mixstore/js/stupidtable.min.js b/web/mixstore/js/stupidtable.min.js
new file mode 100644 (file)
index 0000000..f735a65
--- /dev/null
@@ -0,0 +1 @@
+(function(c){c.fn.stupidtable=function(b){return this.each(function(){var a=c(this);b=b||{};b=c.extend({},c.fn.stupidtable.default_sort_fns,b);a.on("click.stupidtable","th",function(){var d=c(this),f=0,g=c.fn.stupidtable.dir;a.find("th").slice(0,d.index()).each(function(){var a=c(this).attr("colspan")||1;f+=parseInt(a,10)});var e=d.data("sort-default")||g.ASC;d.data("sort-dir")&&(e=d.data("sort-dir")===g.ASC?g.DESC:g.ASC);var l=d.data("sort")||null;null!==l&&(a.trigger("beforetablesort",{column:f, direction:e}),a.css("display"),setTimeout(function(){var h=[],m=b[l],k=a.children("tbody").children("tr");k.each(function(a,b){var d=c(b).children().eq(f),e=d.data("sort-value"),d="undefined"!==typeof e?e:d.text();h.push([d,b])});h.sort(function(a,b){return m(a[0],b[0])});e!=g.ASC&&h.reverse();k=c.map(h,function(a){return a[1]});a.children("tbody").append(k);a.find("th").data("sort-dir",null).removeClass("sorting-desc sorting-asc");d.data("sort-dir",e).addClass("sorting-"+e);a.trigger("aftertablesort", {column:f,direction:e});a.css("display")},10))})})};c.fn.stupidtable.dir={ASC:"asc",DESC:"desc"};c.fn.stupidtable.default_sort_fns={"int":function(b,a){return parseInt(b,10)-parseInt(a,10)},"float":function(b,a){return parseFloat(b)-parseFloat(a)},string:function(b,a){return b<a?-1:b>a?1:0},"string-ins":function(b,a){b=b.toLowerCase();a=a.toLowerCase();return b<a?-1:b>a?1:0}}})(jQuery);
diff --git a/web/mixstore/js/summernote.min.js b/web/mixstore/js/summernote.min.js
new file mode 100644 (file)
index 0000000..f7b9287
--- /dev/null
@@ -0,0 +1,2 @@
+!function(a){"function"==typeof define&&define.amd?define(["jquery","codemirror"],a):a(window.jQuery,window.CodeMirror)}(function(a,b){"function"!=typeof Array.prototype.reduce&&(Array.prototype.reduce=function(a,b){var c,d,e=this.length>>>0,f=!1;for(1<arguments.length&&(d=b,f=!0),c=0;e>c;++c)this.hasOwnProperty(c)&&(f?d=a(d,this[c],c,this):(d=this[c],f=!0));if(!f)throw new TypeError("Reduce of empty array with no initial value");return d});var c={bMac:navigator.appVersion.indexOf("Mac")>-1,bMSIE:navigator.userAgent.indexOf("MSIE")>-1,bFF:navigator.userAgent.indexOf("Firefox")>-1,jqueryVersion:parseFloat(a.fn.jquery),bCodeMirror:!!b},d=function(){var a=function(a){return function(b){return a===b}},b=function(a,b){return a===b},c=function(){return!0},d=function(){return!1},e=function(a){return function(){return!a.apply(a,arguments)}},f=function(a){return a};return{eq:a,eq2:b,ok:c,fail:d,not:e,self:f}}(),e=function(){var a=function(a){return a[0]},b=function(a){return a[a.length-1]},c=function(a){return a.slice(0,a.length-1)},e=function(a){return a.slice(1)},f=function(a,b){var c=a.indexOf(b);return-1===c?null:a[c+1]},g=function(a,b){var c=a.indexOf(b);return-1===c?null:a[c-1]},h=function(a,b){return b=b||d.self,a.reduce(function(a,c){return a+b(c)},0)},i=function(a){for(var b=[],c=-1,d=a.length;++c<d;)b[c]=a[c];return b},j=function(c,d){if(0===c.length)return[];var f=e(c);return f.reduce(function(a,c){var e=b(a);return d(b(e),c)?e[e.length]=c:a[a.length]=[c],a},[[a(c)]])},k=function(a){for(var b=[],c=0,d=a.length;d>c;c++)a[c]&&b.push(a[c]);return b};return{head:a,last:b,initial:c,tail:e,prev:g,next:f,sum:h,from:i,compact:k,clusterBy:j}}(),f=function(){var b=function(b){return b&&a(b).hasClass("note-editable")},g=function(b){return b&&a(b).hasClass("note-control-sizing")},h=function(a){var b=function(b){return function(){return a.find(b)}};return{editor:function(){return a},dropzone:b(".note-dropzone"),toolbar:b(".note-toolbar"),editable:b(".note-editable"),codable:b(".note-codable"),statusbar:b(".note-statusbar"),popover:b(".note-popover"),handle:b(".note-handle"),dialog:b(".note-dialog")}},i=function(a){return function(b){return b&&b.nodeName===a}},j=function(a){return a&&/^DIV|^P|^LI|^H[1-7]/.test(a.nodeName)},k=function(a){return a&&/^UL|^OL/.test(a.nodeName)},l=function(a){return a&&/^TD|^TH/.test(a.nodeName)},m=function(a,c){for(;a;){if(c(a))return a;if(b(a))break;a=a.parentNode}return null},n=function(a,b){b=b||d.fail;var c=[];return m(a,function(a){return c.push(a),b(a)}),c},o=function(b,c){for(var d=n(b),e=c;e;e=e.parentNode)if(a.inArray(e,d)>-1)return e;return null},p=function(a,b){var c=[],d=!1,e=!1;return function f(g){if(g){if(g===a&&(d=!0),d&&!e&&c.push(g),g===b)return void(e=!0);for(var h=0,i=g.childNodes.length;i>h;h++)f(g.childNodes[h])}}(o(a,b)),c},q=function(a,b){b=b||d.fail;for(var c=[];a&&(c.push(a),!b(a));)a=a.previousSibling;return c},r=function(a,b){b=b||d.fail;for(var c=[];a&&(c.push(a),!b(a));)a=a.nextSibling;return c},s=function(a,b){var c=[];return b=b||d.ok,function e(d){a!==d&&b(d)&&c.push(d);for(var f=0,g=d.childNodes.length;g>f;f++)e(d.childNodes[f])}(a),c},t=function(a,b){var c=b.nextSibling,d=b.parentNode;return c?d.insertBefore(a,c):d.appendChild(a),a},u=function(b,c){return a.each(c,function(a,c){b.appendChild(c)}),b},v=i("#text"),w=function(a){return v(a)?a.nodeValue.length:a.childNodes.length},x=function(a){for(var b=0;a=a.previousSibling;)b+=1;return b},y=function(b,c){var f=e.initial(n(c,d.eq(b)));return a.map(f,x).reverse()},z=function(a,b){for(var c=a,d=0,e=b.length;e>d;d++)c=c.childNodes[b[d]];return c},A=function(a,b){if(0===b)return a;if(b>=w(a))return a.nextSibling;if(v(a))return a.splitText(b);var c=a.childNodes[b];return a=t(a.cloneNode(!1),a),u(a,r(c))},B=function(a,b,c){var e=n(b,d.eq(a));return 1===e.length?A(b,c):e.reduce(function(a,d){var e=d.cloneNode(!1);return t(e,d),a===b&&(a=A(a,c)),u(e,r(a)),e})},C=function(a,b){if(a&&a.parentNode){if(a.removeNode)return a.removeNode(b);var c=a.parentNode;if(!b){var d,e,f=[];for(d=0,e=a.childNodes.length;e>d;d++)f.push(a.childNodes[d]);for(d=0,e=f.length;e>d;d++)c.insertBefore(f[d],a)}c.removeChild(a)}},D=function(a){return f.isTextarea(a[0])?a.val():a.html()};return{blank:c.bMSIE?"&nbsp;":"<br/>",emptyPara:"<p><br/></p>",isEditable:b,isControlSizing:g,buildLayoutInfo:h,isText:v,isPara:j,isList:k,isTable:i("TABLE"),isCell:l,isAnchor:i("A"),isDiv:i("DIV"),isLi:i("LI"),isSpan:i("SPAN"),isB:i("B"),isU:i("U"),isS:i("S"),isI:i("I"),isImg:i("IMG"),isTextarea:i("TEXTAREA"),ancestor:m,listAncestor:n,listNext:r,listPrev:q,listDescendant:s,commonAncestor:o,listBetween:p,insertAfter:t,position:x,makeOffsetPath:y,fromOffsetPath:z,split:B,remove:C,html:D}}(),g={version:"0.5.1",options:{width:null,height:null,focus:!1,tabsize:null,styleWithSpan:!0,disableLinkTarget:!1,disableDragAndDrop:!1,codemirror:null,lang:"en-US",direction:null,toolbar:[["style",["style"]],["font",["bold","italic","underline","clear"]],["fontname",["fontname"]],["color",["color"]],["para",["ul","ol","paragraph"]],["height",["height"]],["table",["table"]],["insert",["link","picture","video"]],["view",["fullscreen","codeview"]],["help",["help"]]],oninit:null,onfocus:null,onblur:null,onenter:null,onkeyup:null,onkeydown:null,onImageUpload:null,onImageUploadError:null,onToolbarClick:null,keyMap:{pc:{"CTRL+Z":"undo","CTRL+Y":"redo",TAB:"tab","SHIFT+TAB":"untab","CTRL+B":"bold","CTRL+I":"italic","CTRL+U":"underline","CTRL+SHIFT+S":"strikethrough","CTRL+BACKSLASH":"removeFormat","CTRL+SHIFT+L":"justifyLeft","CTRL+SHIFT+E":"justifyCenter","CTRL+SHIFT+R":"justifyRight","CTRL+SHIFT+J":"justifyFull","CTRL+SHIFT+NUM7":"insertUnorderedList","CTRL+SHIFT+NUM8":"insertOrderedList","CTRL+LEFTBRACKET":"outdent","CTRL+RIGHTBRACKET":"indent","CTRL+NUM0":"formatPara","CTRL+NUM1":"formatH1","CTRL+NUM2":"formatH2","CTRL+NUM3":"formatH3","CTRL+NUM4":"formatH4","CTRL+NUM5":"formatH5","CTRL+NUM6":"formatH6","CTRL+ENTER":"insertHorizontalRule"},mac:{"CMD+Z":"undo","CMD+SHIFT+Z":"redo",TAB:"tab","SHIFT+TAB":"untab","CMD+B":"bold","CMD+I":"italic","CMD+U":"underline","CMD+SHIFT+S":"strikethrough","CMD+BACKSLASH":"removeFormat","CMD+SHIFT+L":"justifyLeft","CMD+SHIFT+E":"justifyCenter","CMD+SHIFT+R":"justifyRight","CMD+SHIFT+J":"justifyFull","CMD+SHIFT+NUM7":"insertUnorderedList","CMD+SHIFT+NUM8":"insertOrderedList","CMD+LEFTBRACKET":"outdent","CMD+RIGHTBRACKET":"indent","CMD+NUM0":"formatPara","CMD+NUM1":"formatH1","CMD+NUM2":"formatH2","CMD+NUM3":"formatH3","CMD+NUM4":"formatH4","CMD+NUM5":"formatH5","CMD+NUM6":"formatH6","CMD+ENTER":"insertHorizontalRule"}}},lang:{"en-US":{font:{bold:"Bold",italic:"Italic",underline:"Underline",strike:"Strike",clear:"Remove Font Style",height:"Line Height",name:"Font Family",size:"Font Size"},image:{image:"Picture",insert:"Insert Image",resizeFull:"Resize Full",resizeHalf:"Resize Half",resizeQuarter:"Resize Quarter",floatLeft:"Float Left",floatRight:"Float Right",floatNone:"Float None",dragImageHere:"Drag an image here",selectFromFiles:"Select from files",url:"Image URL",remove:"Remove Image"},link:{link:"Link",insert:"Insert Link",unlink:"Unlink",edit:"Edit",textToDisplay:"Text to display",url:"To what URL should this link go?",openInNewWindow:"Open in new window"},video:{video:"Video",videoLink:"Video Link",insert:"Insert Video",url:"Video URL?",providers:"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)"},table:{table:"Table"},hr:{insert:"Insert Horizontal Rule"},style:{style:"Style",normal:"Normal",blockquote:"Quote",pre:"Code",h1:"Header 1",h2:"Header 2",h3:"Header 3",h4:"Header 4",h5:"Header 5",h6:"Header 6"},lists:{unordered:"Unordered list",ordered:"Ordered list"},options:{help:"Help",fullscreen:"Full Screen",codeview:"Code View"},paragraph:{paragraph:"Paragraph",outdent:"Outdent",indent:"Indent",left:"Align left",center:"Align center",right:"Align right",justify:"Justify full"},color:{recent:"Recent Color",more:"More Color",background:"BackColor",foreground:"FontColor",transparent:"Transparent",setTransparent:"Set transparent",reset:"Reset",resetToDefault:"Reset to default"},shortcut:{shortcuts:"Keyboard shortcuts",close:"Close",textFormatting:"Text formatting",action:"Action",paragraphFormatting:"Paragraph formatting",documentStyle:"Document Style"},history:{undo:"Undo",redo:"Redo"}}}},h=function(){var b=function(b){return a.Deferred(function(c){a.extend(new FileReader,{onload:function(a){var b=a.target.result;c.resolve(b)},onerror:function(){c.reject(this)}}).readAsDataURL(b)}).promise()},c=function(b){return a.Deferred(function(c){a("<img>").one("load",function(){c.resolve(a(this))}).one("error abort",function(){c.reject(a(this))}).css({display:"none"}).appendTo(document.body).attr("src",b)}).promise()};return{readFileAsDataURL:b,createImage:c}}(),i={isEdit:function(a){return-1!==[8,9,13,32].indexOf(a)},nameFromCode:{8:"BACKSPACE",9:"TAB",13:"ENTER",32:"SPACE",48:"NUM0",49:"NUM1",50:"NUM2",51:"NUM3",52:"NUM4",53:"NUM5",54:"NUM6",55:"NUM7",56:"NUM8",66:"B",69:"E",73:"I",74:"J",75:"K",76:"L",82:"R",83:"S",85:"U",89:"Y",90:"Z",191:"SLASH",219:"LEFTBRACKET",220:"BACKSLASH",221:"RIGHTBRACKET"}},j=function(){var b=function(b,d){if(c.jqueryVersion<1.9){var e={};return a.each(d,function(a,c){e[c]=b.css(c)}),e}return b.css.call(b,d)};this.stylePara=function(b,c){a.each(b.nodes(f.isPara),function(b,d){a(d).css(c)})},this.current=function(c,d){var e=a(f.isText(c.sc)?c.sc.parentNode:c.sc),g=["font-family","font-size","text-align","list-style-type","line-height"],h=b(e,g)||{};if(h["font-size"]=parseInt(h["font-size"]),h["font-bold"]=document.queryCommandState("bold")?"bold":"normal",h["font-italic"]=document.queryCommandState("italic")?"italic":"normal",h["font-underline"]=document.queryCommandState("underline")?"underline":"normal",c.isOnList()){var i=["circle","disc","disc-leading-zero","square"],j=a.inArray(h["list-style-type"],i)>-1;h["list-style"]=j?"unordered":"ordered"}else h["list-style"]="none";var k=f.ancestor(c.sc,f.isPara);if(k&&k.style["line-height"])h["line-height"]=k.style.lineHeight;else{var l=parseInt(h["line-height"])/parseInt(h["font-size"]);h["line-height"]=l.toFixed(1)}return h.image=f.isImg(d)&&d,h.anchor=c.isOnAnchor()&&f.ancestor(c.sc,f.isAnchor),h.aAncestor=f.listAncestor(c.sc,f.isEditable),h}},k=function(){var b=!!document.createRange,c=function(a,b){var c,d,g=a.parentElement(),h=document.body.createTextRange(),i=e.from(g.childNodes);for(c=0;c<i.length;c++)if(!f.isText(i[c])){if(h.moveToElementText(i[c]),h.compareEndPoints("StartToStart",a)>=0)break;d=i[c]}if(0!==c&&f.isText(i[c-1])){var j=document.body.createTextRange(),k=null;j.moveToElementText(d||g),j.collapse(!d),k=d?d.nextSibling:g.firstChild;var l=a.duplicate();l.setEndPoint("StartToStart",j);for(var m=l.text.replace(/[\r\n]/g,"").length;m>k.nodeValue.length&&k.nextSibling;)m-=k.nodeValue.length,k=k.nextSibling;{k.nodeValue}b&&k.nextSibling&&f.isText(k.nextSibling)&&m===k.nodeValue.length&&(m-=k.nodeValue.length,k=k.nextSibling),g=k,c=m}return{cont:g,offset:c}},g=function(a){var b=function(a,c){var g,h;if(f.isText(a)){var i=f.listPrev(a,d.not(f.isText)),j=e.last(i).previousSibling;g=j||a.parentNode,c+=e.sum(e.tail(i),f.length),h=!j}else{if(g=a.childNodes[c]||a,f.isText(g))return b(g,c);c=0,h=!1}return{cont:g,collapseToStart:h,offset:c}},c=document.body.createTextRange(),g=b(a.cont,a.offset);return c.moveToElementText(g.cont),c.collapse(g.collapseToStart),c.moveStart("character",g.offset),c},h=function(c,h,i,j){this.sc=c,this.so=h,this.ec=i,this.eo=j;var k=function(){if(b){var a=document.createRange();return a.setStart(c,h),a.setEnd(i,j),a}var d=g({cont:c,offset:h});return d.setEndPoint("EndToEnd",g({cont:i,offset:j})),d};this.select=function(){var a=k();if(b){var c=document.getSelection();c.rangeCount>0&&c.removeAllRanges(),c.addRange(a)}else a.select()},this.nodes=function(b){var g=f.listBetween(c,i),h=e.compact(a.map(g,function(a){return f.ancestor(a,b)}));return a.map(e.clusterBy(h,d.eq2),e.head)},this.commonAncestor=function(){return f.commonAncestor(c,i)};var l=function(a){return function(){var b=f.ancestor(c,a);return!!b&&b===f.ancestor(i,a)}};this.isOnEditable=l(f.isEditable),this.isOnList=l(f.isList),this.isOnAnchor=l(f.isAnchor),this.isOnCell=l(f.isCell),this.isCollapsed=function(){return c===i&&h===j},this.insertNode=function(a){var c=k();b?c.insertNode(a):c.pasteHTML(a.outerHTML)},this.toString=function(){var a=k();return b?a.toString():a.text},this.bookmark=function(a){return{s:{path:f.makeOffsetPath(a,c),offset:h},e:{path:f.makeOffsetPath(a,i),offset:j}}}};return{create:function(a,d,e,f){if(0===arguments.length)if(b){var g=document.getSelection();if(0===g.rangeCount)return null;var i=g.getRangeAt(0);a=i.startContainer,d=i.startOffset,e=i.endContainer,f=i.endOffset}else{var j=document.selection.createRange(),k=j.duplicate();k.collapse(!1);var l=j;l.collapse(!0);var m=c(l,!0),n=c(k,!1);a=m.cont,d=m.offset,e=n.cont,f=n.offset}else 2===arguments.length&&(e=a,f=d);return new h(a,d,e,f)},createFromNode:function(a){return this.create(a,0,a,1)},createFromBookmark:function(a,b){var c=f.fromOffsetPath(a,b.s.path),d=b.s.offset,e=f.fromOffsetPath(a,b.e.path),g=b.e.offset;return new h(c,d,e,g)}}}(),l=function(){this.tab=function(a,b){var c=f.ancestor(a.commonAncestor(),f.isCell),d=f.ancestor(c,f.isTable),g=f.listDescendant(d,f.isCell),h=e[b?"prev":"next"](g,c);h&&k.create(h,0).select()},this.createTable=function(b,c){for(var d,e=[],g=0;b>g;g++)e.push("<td>"+f.blank+"</td>");d=e.join("");for(var h,i=[],j=0;c>j;j++)i.push("<tr>"+d+"</tr>");h=i.join("");var k='<table class="table table-bordered">'+h+"</table>";return a(k)[0]}},m=function(){var b=new j,d=new l;this.saveRange=function(a){a.data("range",k.create())},this.restoreRange=function(a){var b=a.data("range");b&&b.select()},this.currentStyle=function(a){var c=k.create();return c.isOnEditable()&&b.current(c,a)},this.undo=function(a){a.data("NoteHistory").undo(a)},this.redo=function(a){a.data("NoteHistory").redo(a)};for(var e=this.recordUndo=function(a){a.data("NoteHistory").recordUndo(a)},g=["bold","italic","underline","strikethrough","justifyLeft","justifyCenter","justifyRight","justifyFull","insertOrderedList","insertUnorderedList","indent","outdent","formatBlock","removeFormat","backColor","foreColor","insertHorizontalRule","fontName"],i=0,m=g.length;m>i;i++)this[g[i]]=function(a){return function(b,c){e(b),document.execCommand(a,!1,c)}}(g[i]);var n=function(b,c,d){e(b);var g=new Array(d+1).join("&nbsp;");c.insertNode(a('<span id="noteTab">'+g+"</span>")[0]);var h=a("#noteTab").removeAttr("id");c=k.create(h[0],1),c.select(),f.remove(h[0])};this.tab=function(a,b){var c=k.create();c.isCollapsed()&&c.isOnCell()?d.tab(c):n(a,c,b.tabsize)},this.untab=function(){var a=k.create();a.isCollapsed()&&a.isOnCell()&&d.tab(a,!0)},this.insertImage=function(a,b){h.createImage(b).then(function(b){e(a),b.css({display:"",width:Math.min(a.width(),b.width())}),k.create().insertNode(b[0])}).fail(function(){var b=a.data("callbacks");b.onImageUploadError&&b.onImageUploadError()})},this.insertVideo=function(b,c){e(b);var d,f=/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/,g=c.match(f),h=/\/\/instagram.com\/p\/(.[a-zA-Z0-9]*)/,i=c.match(h),j=/\/\/vine.co\/v\/(.[a-zA-Z0-9]*)/,l=c.match(j),m=/\/\/(player.)?vimeo.com\/([a-z]*\/)*([0-9]{6,11})[?]?.*/,n=c.match(m),o=/.+dailymotion.com\/(video|hub)\/([^_]+)[^#]*(#video=([^_&]+))?/,p=c.match(o);if(g&&11===g[2].length){var q=g[2];d=a("<iframe>").attr("src","//www.youtube.com/embed/"+q).attr("width","640").attr("height","360")}else i&&i[0].length>0?d=a("<iframe>").attr("src",i[0]+"/embed/").attr("width","612").attr("height","710").attr("scrolling","no").attr("allowtransparency","true"):l&&l[0].length>0?d=a("<iframe>").attr("src",l[0]+"/embed/simple").attr("width","600").attr("height","600").attr("class","vine-embed"):n&&n[3].length>0?d=a("<iframe webkitallowfullscreen mozallowfullscreen allowfullscreen>").attr("src","//player.vimeo.com/video/"+n[3]).attr("width","640").attr("height","360"):p&&p[2].length>0&&(d=a("<iframe>").attr("src","//www.dailymotion.com/embed/video/"+p[2]).attr("width","640").attr("height","360"));d&&(d.attr("frameborder",0),k.create().insertNode(d[0]))},this.formatBlock=function(a,b){e(a),b=c.bMSIE?"<"+b+">":b,document.execCommand("FormatBlock",!1,b)},this.formatPara=function(a){this.formatBlock(a,"P")};for(var i=1;6>=i;i++)this["formatH"+i]=function(a){return function(b){this.formatBlock(b,"H"+a)}}(i);this.fontSize=function(a,b){e(a),document.execCommand("fontSize",!1,3),c.bFF?a.find("font[size=3]").removeAttr("size").css("font-size",b+"px"):a.find("span").filter(function(){return"medium"===this.style.fontSize}).css("font-size",b+"px")},this.lineHeight=function(a,c){e(a),b.stylePara(k.create(),{lineHeight:c})},this.unlink=function(a){var b=k.create();if(b.isOnAnchor()){e(a);var c=f.ancestor(b.sc,f.isAnchor);b=k.createFromNode(c),b.select(),document.execCommand("unlink")}},this.createLink=function(b,d,g){var h=k.create();e(b);var i=d;if(-1!==d.indexOf("@")&&-1===d.indexOf(":")?i="mailto:"+d:-1===d.indexOf("://")&&(i="http://"+d),(c.bMSIE||c.bFF)&&h.isCollapsed()){h.insertNode(a('<A id="linkAnchor">'+d+"</A>")[0]);var j=a("#linkAnchor").attr("href",i).removeAttr("id");h=k.createFromNode(j[0]),h.select()}else document.execCommand("createlink",!1,i),h=k.create();a.each(h.nodes(f.isAnchor),function(b,c){g?a(c).attr("target","_blank"):a(c).removeAttr("target")})},this.getLinkInfo=function(){var b=k.create(),c=!0,d="";if(b.isOnAnchor()){var e=f.ancestor(b.sc,f.isAnchor);b=k.createFromNode(e),c="_blank"===a(e).attr("target"),d=e.href}return{text:b.toString(),url:d,newWindow:c}},this.getVideoInfo=function(){var a=k.create();if(a.isOnAnchor()){var b=f.ancestor(a.sc,f.isAnchor);a=k.createFromNode(b)}return{text:a.toString()}},this.color=function(a,b){var c=JSON.parse(b),d=c.foreColor,f=c.backColor;e(a),d&&document.execCommand("foreColor",!1,d),f&&document.execCommand("backColor",!1,f)},this.insertTable=function(a,b){e(a);var c=b.split("x");k.create().insertNode(d.createTable(c[0],c[1]))},this.floatMe=function(a,b,c){e(a),c.css("float",b)},this.resize=function(a,b,c){e(a),c.css({width:a.width()*b+"px",height:""})},this.resizeTo=function(a,b,c){var d;if(c){var e=a.y/a.x,f=b.data("ratio");d={width:f>e?a.x:a.y/f,height:f>e?a.x*f:a.y}}else d={width:a.x,height:a.y};b.css(d)},this.removeMedia=function(a,b,c){e(a),c.detach()}},n=function(){var a=[],b=[],c=function(a){var b=a[0],c=k.create();return{contents:a.html(),bookmark:c.bookmark(b),scrollTop:a.scrollTop()}},d=function(a,b){a.html(b.contents).scrollTop(b.scrollTop),k.createFromBookmark(a[0],b.bookmark).select()};this.undo=function(e){var f=c(e);0!==a.length&&(d(e,a.pop()),b.push(f))},this.redo=function(e){var f=c(e);0!==b.length&&(d(e,b.pop()),a.push(f))},this.recordUndo=function(d){b=[],a.push(c(d))}},o=function(){this.update=function(b,c){var d=function(b,c){b.find(".dropdown-menu li a").each(function(){var b=a(this).data("value")+""==c+"";this.className=b?"checked":""})},f=function(a,c){var d=b.find(a);d.toggleClass("active",c())},g=b.find(".note-fontname");if(g.length>0){var h=c["font-family"];h&&(h=e.head(h.split(",")),h=h.replace(/\'/g,""),g.find(".note-current-fontname").text(h),d(g,h))}var i=b.find(".note-fontsize");i.find(".note-current-fontsize").text(c["font-size"]),d(i,parseFloat(c["font-size"]));var j=b.find(".note-height");d(j,parseFloat(c["line-height"])),f('button[data-event="bold"]',function(){return"bold"===c["font-bold"]}),f('button[data-event="italic"]',function(){return"italic"===c["font-italic"]}),f('button[data-event="underline"]',function(){return"underline"===c["font-underline"]}),f('button[data-event="justifyLeft"]',function(){return"left"===c["text-align"]||"start"===c["text-align"]}),f('button[data-event="justifyCenter"]',function(){return"center"===c["text-align"]}),f('button[data-event="justifyRight"]',function(){return"right"===c["text-align"]}),f('button[data-event="justifyFull"]',function(){return"justify"===c["text-align"]}),f('button[data-event="insertUnorderedList"]',function(){return"unordered"===c["list-style"]}),f('button[data-event="insertOrderedList"]',function(){return"ordered"===c["list-style"]})},this.updateRecentColor=function(b,c,d){var e=a(b).closest(".note-color"),f=e.find(".note-recent-color"),g=JSON.parse(f.attr("data-value"));g[c]=d,f.attr("data-value",JSON.stringify(g));var h="backColor"===c?"background-color":"color";f.find("i").css(h,d)},this.updateFullscreen=function(a,b){var c=a.find('button[data-event="fullscreen"]');c.toggleClass("active",b)},this.updateCodeview=function(a,b){var c=a.find('button[data-event="codeview"]');c.toggleClass("active",b)},this.activate=function(a){a.find("button").not('button[data-event="codeview"]').removeClass("disabled")},this.deactivate=function(a){a.find("button").not('button[data-event="codeview"]').addClass("disabled")}},p=function(){var b=function(b,c){var d=a(c),e=d.position(),f=d.height();b.css({display:"block",left:e.left,top:e.top+f})};this.update=function(a,c){var d=a.find(".note-link-popover");if(c.anchor){var e=d.find("a");e.attr("href",c.anchor.href).html(c.anchor.href),b(d,c.anchor)}else d.hide();var f=a.find(".note-image-popover");c.image?b(f,c.image):f.hide()},this.hide=function(a){a.children().hide()}},q=function(){this.update=function(b,c){var d=b.find(".note-control-selection");if(c.image){var e=a(c.image),f=e.position(),g={w:e.width(),h:e.height()};d.css({display:"block",left:f.left,top:f.top,width:g.w,height:g.h}).data("target",c.image);var h=g.w+"x"+g.h;d.find(".note-control-selection-info").text(h)}else d.hide()},this.hide=function(a){a.children().hide()}},r=function(){var b=function(a,b){a.toggleClass("disabled",!b),a.attr("disabled",!b)};this.showImageDialog=function(c,d){return a.Deferred(function(a){var e=d.find(".note-image-dialog"),f=d.find(".note-image-input"),g=d.find(".note-image-url"),h=d.find(".note-image-btn");e.one("shown.bs.modal",function(c){c.stopPropagation(),f.replaceWith(f.clone().on("change",function(){e.modal("hide"),a.resolve(this.files)})),h.click(function(b){b.preventDefault(),e.modal("hide"),a.resolve(g.val())}),g.keyup(function(){b(h,g.val())}).val("").focus()}).one("hidden.bs.modal",function(a){a.stopPropagation(),c.focus(),f.off("change"),g.off("keyup"),h.off("click")}).modal("show")})},this.showVideoDialog=function(c,d,e){return a.Deferred(function(a){var f=d.find(".note-video-dialog"),g=f.find(".note-video-url"),h=f.find(".note-video-btn");f.one("shown.bs.modal",function(c){c.stopPropagation(),g.val(e.text).keyup(function(){b(h,g.val())}).trigger("keyup").trigger("focus"),h.click(function(b){b.preventDefault(),f.modal("hide"),a.resolve(g.val())})}).one("hidden.bs.modal",function(a){a.stopPropagation(),c.focus(),g.off("keyup"),h.off("click")}).modal("show")})},this.showLinkDialog=function(c,d,e){return a.Deferred(function(a){var f=d.find(".note-link-dialog"),g=f.find(".note-link-text"),h=f.find(".note-link-url"),i=f.find(".note-link-btn"),j=f.find("input[type=checkbox]");f.one("shown.bs.modal",function(c){c.stopPropagation(),g.val(e.text),h.keyup(function(){b(i,h.val()),e.text||g.val(h.val())}).val(e.url).trigger("focus"),j.prop("checked",e.newWindow),i.one("click",function(b){b.preventDefault(),f.modal("hide"),a.resolve(h.val(),j.is(":checked"))})}).one("hidden.bs.modal",function(a){a.stopPropagation(),c.focus(),h.off("keyup")}).modal("show")}).promise()},this.showHelpDialog=function(a,b){var c=b.find(".note-help-dialog");c.one("hidden.bs.modal",function(b){b.stopPropagation(),a.focus()}).modal("show")}},s=function(){var d=new m,e=new o,g=new p,j=new q,k=new r,l=function(b){var c=a(b).closest(".note-editor");return c.length>0&&f.buildLayoutInfo(c)},s=function(b,c){d.restoreRange(b);var e=b.data("callbacks");e.onImageUpload?e.onImageUpload(c,d,b):a.each(c,function(a,c){h.readFileAsDataURL(c).then(function(a){d.insertImage(b,a)}).fail(function(){e.onImageUploadError&&e.onImageUploadError()})})},t=function(a){f.isImg(a.target)&&a.preventDefault()},u=function(a){var b=l(a.currentTarget||a.target),c=d.currentStyle(a.target);c&&(e.update(b.toolbar(),c),g.update(b.popover(),c),j.update(b.handle(),c))},v=function(a){var b=l(a.currentTarget||a.target);g.hide(b.popover()),j.hide(b.handle())},w=function(b){if(f.isControlSizing(b.target)){var c=l(b.target),e=c.handle(),h=c.popover(),i=c.editable(),k=c.editor(),m=e.find(".note-control-selection").data("target"),n=a(m),o=n.offset(),p=a(document).scrollTop();k.on("mousemove",function(a){d.resizeTo({x:a.clientX-o.left,y:a.clientY-(o.top-p)},n,!a.shiftKey),j.update(e,{image:m}),g.update(h,{image:m})}).one("mouseup",function(){k.off("mousemove")}),n.data("ratio")||n.data("ratio",n.height()/n.width()),d.recordUndo(i),b.stopPropagation(),b.preventDefault()}},x=function(b){var c=a(b.target).closest("[data-event]");c.length>0&&b.preventDefault()},y=function(g){var h=a(g.target).closest("[data-event]");if(h.length>0){var i,j,m,n=h.attr("data-event"),o=h.attr("data-value"),p=l(g.target),q=p.editor(),r=p.toolbar(),t=p.dialog(),v=p.editable(),w=p.codable(),x=q.data("options");if(-1!==a.inArray(n,["resize","floatMe","removeMedia"])){var y=p.handle(),z=y.find(".note-control-selection");m=a(z.data("target"))}if(d[n]&&(v.trigger("focus"),d[n](v,o,m)),-1!==a.inArray(n,["backColor","foreColor"]))e.updateRecentColor(h[0],n,o);else if("showLinkDialog"===n){v.focus();var A=d.getLinkInfo();d.saveRange(v),k.showLinkDialog(v,t,A).then(function(a,b){d.restoreRange(v),d.createLink(v,a,b)})}else if("showImageDialog"===n)v.focus(),k.showImageDialog(v,t).then(function(a){"string"==typeof a?(d.restoreRange(v),d.insertImage(v,a)):s(v,a)});else if("showVideoDialog"===n){v.focus();var B=d.getVideoInfo();d.saveRange(v),k.showVideoDialog(v,t,B).then(function(a){d.restoreRange(v),d.insertVideo(v,a)})}else if("showHelpDialog"===n)k.showHelpDialog(v,t);else if("fullscreen"===n){var C=a("html, body"),D=function(a){q.css("width",a.w),v.css("height",a.h),w.css("height",a.h),w.data("cmEditor")&&w.data("cmEditor").setSize(null,a.h)};q.toggleClass("fullscreen");var E=q.hasClass("fullscreen");E?(v.data("orgHeight",v.css("height")),a(window).on("resize",function(){D({w:a(window).width(),h:a(window).height()-r.outerHeight()})}).trigger("resize"),C.css("overflow","hidden")):(a(window).off("resize"),D({w:x.width||"",h:v.data("orgHeight")}),C.css("overflow","auto")),e.updateFullscreen(r,E)}else if("codeview"===n){q.toggleClass("codeview");var F=q.hasClass("codeview");if(F){if(w.val(v.html()),w.height(v.height()),e.deactivate(r),w.focus(),c.bCodeMirror){j=b.fromTextArea(w[0],a.extend({mode:"text/html",lineNumbers:!0},x.codemirror));var G=q.data("options").codemirror.tern||!1;G&&(i=new b.TernServer(G),j.ternServer=i,j.on("cursorActivity",function(a){i.updateArgHints(a)})),j.setSize(null,v.outerHeight()),j.autoFormatRange&&j.autoFormatRange({line:0,ch:0},{line:j.lineCount(),ch:j.getTextArea().value.length}),w.data("cmEditor",j)}}else c.bCodeMirror&&(j=w.data("cmEditor"),w.val(j.getValue()),j.toTextArea()),v.html(w.val()||f.emptyPara),v.height(x.height?w.height():"auto"),e.activate(r),v.focus();e.updateCodeview(p.toolbar(),F)}u(g)}},z=24,A=function(b){var c=a(document),d=l(b.target).editable(),e=d.offset().top-c.scrollTop();c.on("mousemove",function(a){var b=a.clientY-(e+z);d.height(b)}).one("mouseup",function(){c.off("mousemove")}),b.stopPropagation(),b.preventDefault()},B=18,C=function(b){var c,d=a(b.target.parentNode),e=d.next(),f=d.find(".note-dimension-picker-mousecatcher"),g=d.find(".note-dimension-picker-highlighted"),h=d.find(".note-dimension-picker-unhighlighted");if(void 0===b.offsetX){var i=a(b.target).offset();c={x:b.pageX-i.left,y:b.pageY-i.top}}else c={x:b.offsetX,y:b.offsetY};var j={c:Math.ceil(c.x/B)||1,r:Math.ceil(c.y/B)||1};g.css({width:j.c+"em",height:j.r+"em"}),f.attr("data-value",j.c+"x"+j.r),3<j.c&&j.c<10&&h.css({width:j.c+1+"em"}),3<j.r&&j.r<10&&h.css({height:j.r+1+"em"}),e.html(j.c+" x "+j.r)},D=function(b){var c=a(),d=b.dropzone,e=b.dropzone.find(".note-dropzone-message");a(document).on("dragenter",function(a){var f=b.editor.hasClass("codeview");f||0!==c.length||(b.editor.addClass("dragover"),d.width(b.editor.width()),d.height(b.editor.height()),e.text("Drag Image Here")),c=c.add(a.target)}).on("dragleave",function(a){c=c.not(a.target),0===c.length&&b.editor.removeClass("dragover")}).on("drop",function(){c=a(),b.editor.removeClass("dragover")}),d.on("dragenter",function(){d.addClass("hover"),e.text("Drop Image")}).on("dragleave",function(){d.removeClass("hover"),e.text("Drag Image Here")}),d.on("drop",function(a){var b=a.originalEvent.dataTransfer;if(b&&b.files){var c=l(a.currentTarget||a.target);c.editable().focus(),s(c.editable(),b.files)}a.preventDefault()}).on("dragover",!1)};this.bindKeyMap=function(a,b){var c=a.editor,e=a.editable;e.on("keydown",function(a){var f=[];a.metaKey&&f.push("CMD"),a.ctrlKey&&f.push("CTRL"),a.shiftKey&&f.push("SHIFT");var g=i.nameFromCode[a.keyCode];g&&f.push(g);var h=b[f.join("+")];h?(a.preventDefault(),d[h](e,c.data("options"))):i.isEdit(a.keyCode)&&d.recordUndo(e)})},this.attach=function(a,b){var e=b.keyMap[c.bMac?"mac":"pc"];this.bindKeyMap(a,e),a.editable.on("mousedown",t),a.editable.on("keyup mouseup",u),a.editable.on("scroll",v),b.disableDragAndDrop||D(a),a.handle.on("mousedown",w),a.toolbar.on("click",y),a.popover.on("click",y),a.toolbar.on("mousedown",x),a.popover.on("mousedown",x),a.statusbar.on("mousedown",A);var f=a.toolbar,g=f.find(".note-dimension-picker-mousecatcher");g.on("mousemove",C),a.editable.on("blur",function(){d.saveRange(a.editable)}),a.editor.data("options",b),b.styleWithSpan&&!c.bMSIE&&setTimeout(function(){document.execCommand("styleWithCSS",0,!0)}),a.editable.data("NoteHistory",new n),b.onenter&&a.editable.keypress(function(a){a.keyCode===i.ENTER&&b.onenter(a)}),b.onfocus&&a.editable.focus(b.onfocus),b.onblur&&a.editable.blur(b.onblur),b.onkeyup&&a.editable.keyup(b.onkeyup),b.onkeydown&&a.editable.keydown(b.onkeydown),b.onpaste&&a.editable.on("paste",b.onpaste),b.onToolbarClick&&a.toolbar.click(b.onToolbarClick),a.editable.data("callbacks",{onChange:b.onChange,onAutoSave:b.onAutoSave,onImageUpload:b.onImageUpload,onImageUploadError:b.onImageUploadError,onFileUpload:b.onFileUpload,onFileUploadError:b.onFileUpload})},this.dettach=function(a){a.editable.off(),a.toolbar.off(),a.handle.off(),a.popover.off()}},t=function(){var b,d,e,g,h;b={picture:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small" title="'+a.image.image+'" data-event="showImageDialog" tabindex="-1"><i class="fa fa-picture-o icon-picture"></i></button>'},link:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small" title="'+a.link.link+'" data-event="showLinkDialog" tabindex="-1"><i class="fa fa-link icon-link"></i></button>'},video:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small" title="'+a.video.video+'" data-event="showVideoDialog" tabindex="-1"><i class="fa fa-youtube-play icon-play"></i></button>'},table:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small dropdown-toggle" title="'+a.table.table+'" data-toggle="dropdown" tabindex="-1"><i class="fa fa-table icon-table"></i> <span class="caret"></span></button><ul class="dropdown-menu"><div class="note-dimension-picker"><div class="note-dimension-picker-mousecatcher" data-event="insertTable" data-value="1x1"></div><div class="note-dimension-picker-highlighted"></div><div class="note-dimension-picker-unhighlighted"></div></div><div class="note-dimension-display"> 1 x 1 </div></ul>'},style:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small dropdown-toggle" title="'+a.style.style+'" data-toggle="dropdown" tabindex="-1"><i class="fa fa-magic icon-magic"></i> <span class="caret"></span></button><ul class="dropdown-menu"><li><a data-event="formatBlock" data-value="p">'+a.style.normal+'</a></li><li><a data-event="formatBlock" data-value="blockquote"><blockquote>'+a.style.blockquote+'</blockquote></a></li><li><a data-event="formatBlock" data-value="pre">'+a.style.pre+'</a></li><li><a data-event="formatBlock" data-value="h1"><h1>'+a.style.h1+'</h1></a></li><li><a data-event="formatBlock" data-value="h2"><h2>'+a.style.h2+'</h2></a></li><li><a data-event="formatBlock" data-value="h3"><h3>'+a.style.h3+'</h3></a></li><li><a data-event="formatBlock" data-value="h4"><h4>'+a.style.h4+'</h4></a></li><li><a data-event="formatBlock" data-value="h5"><h5>'+a.style.h5+'</h5></a></li><li><a data-event="formatBlock" data-value="h6"><h6>'+a.style.h6+"</h6></a></li></ul>"
+},fontname:function(a){var b=["Serif","Sans","Arial","Arial Black","Courier","Courier New","Comic Sans MS","Helvetica","Impact","Lucida Grande","Lucida Sans","Tahoma","Times","Times New Roman","Verdana"],c='<button type="button" class="btn btn-default btn-sm btn-small dropdown-toggle" data-toggle="dropdown" title="'+a.font.name+'" tabindex="-1"><span class="note-current-fontname">Arial</span> <b class="caret"></b></button>';c+='<ul class="dropdown-menu">';for(var d=0;d<b.length;d++)c+='<li><a data-event="fontName" data-value="'+b[d]+'"><i class="fa fa-check icon-ok"></i> '+b[d]+"</a></li>";return c+="</ul>"},fontsize:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small dropdown-toggle" data-toggle="dropdown" title="'+a.font.size+'" tabindex="-1"><span class="note-current-fontsize">11</span> <b class="caret"></b></button><ul class="dropdown-menu"><li><a data-event="fontSize" data-value="8"><i class="fa fa-check icon-ok"></i> 8</a></li><li><a data-event="fontSize" data-value="9"><i class="fa fa-check icon-ok"></i> 9</a></li><li><a data-event="fontSize" data-value="10"><i class="fa fa-check icon-ok"></i> 10</a></li><li><a data-event="fontSize" data-value="11"><i class="fa fa-check icon-ok"></i> 11</a></li><li><a data-event="fontSize" data-value="12"><i class="fa fa-check icon-ok"></i> 12</a></li><li><a data-event="fontSize" data-value="14"><i class="fa fa-check icon-ok"></i> 14</a></li><li><a data-event="fontSize" data-value="18"><i class="fa fa-check icon-ok"></i> 18</a></li><li><a data-event="fontSize" data-value="24"><i class="fa fa-check icon-ok"></i> 24</a></li><li><a data-event="fontSize" data-value="36"><i class="fa fa-check icon-ok"></i> 36</a></li></ul>'},color:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small note-recent-color" title="'+a.color.recent+'" data-event="color" data-value=\'{"backColor":"yellow"}\' tabindex="-1"><i class="fa fa-font icon-font" style="color:black;background-color:yellow;"></i></button><button type="button" class="btn btn-default btn-sm btn-small dropdown-toggle" title="'+a.color.more+'" data-toggle="dropdown" tabindex="-1"><span class="caret"></span></button><ul class="dropdown-menu"><li><div class="btn-group"><div class="note-palette-title">'+a.color.background+'</div><div class="note-color-reset" data-event="backColor" data-value="inherit" title="'+a.color.transparent+'">'+a.color.setTransparent+'</div><div class="note-color-palette" data-target-event="backColor"></div></div><div class="btn-group"><div class="note-palette-title">'+a.color.foreground+'</div><div class="note-color-reset" data-event="foreColor" data-value="inherit" title="'+a.color.reset+'">'+a.color.resetToDefault+'</div><div class="note-color-palette" data-target-event="foreColor"></div></div></li></ul>'},bold:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small" title="'+a.font.bold+'" data-shortcut="Ctrl+B" data-mac-shortcut="⌘+B" data-event="bold" tabindex="-1"><i class="fa fa-bold icon-bold"></i></button>'},italic:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small" title="'+a.font.italic+'" data-shortcut="Ctrl+I" data-mac-shortcut="⌘+I" data-event="italic" tabindex="-1"><i class="fa fa-italic icon-italic"></i></button>'},underline:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small" title="'+a.font.underline+'" data-shortcut="Ctrl+U" data-mac-shortcut="⌘+U" data-event="underline" tabindex="-1"><i class="fa fa-underline icon-underline"></i></button>'},clear:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small" title="'+a.font.clear+'" data-shortcut="Ctrl+\\" data-mac-shortcut="⌘+\\" data-event="removeFormat" tabindex="-1"><i class="fa fa-eraser icon-eraser"></i></button>'},ul:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small" title="'+a.lists.unordered+'" data-shortcut="Ctrl+Shift+8" data-mac-shortcut="⌘+⇧+7" data-event="insertUnorderedList" tabindex="-1"><i class="fa fa-list-ul icon-list-ul"></i></button>'},ol:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small" title="'+a.lists.ordered+'" data-shortcut="Ctrl+Shift+7" data-mac-shortcut="⌘+⇧+8" data-event="insertOrderedList" tabindex="-1"><i class="fa fa-list-ol icon-list-ol"></i></button>'},paragraph:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small dropdown-toggle" title="'+a.paragraph.paragraph+'" data-toggle="dropdown" tabindex="-1"><i class="fa fa-align-left icon-align-left"></i>  <span class="caret"></span></button><div class="dropdown-menu"><div class="note-align btn-group"><button type="button" class="btn btn-default btn-sm btn-small" title="'+a.paragraph.left+'" data-shortcut="Ctrl+Shift+L" data-mac-shortcut="⌘+⇧+L" data-event="justifyLeft" tabindex="-1"><i class="fa fa-align-left icon-align-left"></i></button><button type="button" class="btn btn-default btn-sm btn-small" title="'+a.paragraph.center+'" data-shortcut="Ctrl+Shift+E" data-mac-shortcut="⌘+⇧+E" data-event="justifyCenter" tabindex="-1"><i class="fa fa-align-center icon-align-center"></i></button><button type="button" class="btn btn-default btn-sm btn-small" title="'+a.paragraph.right+'" data-shortcut="Ctrl+Shift+R" data-mac-shortcut="⌘+⇧+R" data-event="justifyRight" tabindex="-1"><i class="fa fa-align-right icon-align-right"></i></button><button type="button" class="btn btn-default btn-sm btn-small" title="'+a.paragraph.justify+'" data-shortcut="Ctrl+Shift+J" data-mac-shortcut="⌘+⇧+J" data-event="justifyFull" tabindex="-1"><i class="fa fa-align-justify icon-align-justify"></i></button></div><div class="note-list btn-group"><button type="button" class="btn btn-default btn-sm btn-small" title="'+a.paragraph.outdent+'" data-shortcut="Ctrl+[" data-mac-shortcut="⌘+[" data-event="outdent" tabindex="-1"><i class="fa fa-outdent icon-indent-left"></i></button><button type="button" class="btn btn-default btn-sm btn-small" title="'+a.paragraph.indent+'" data-shortcut="Ctrl+]" data-mac-shortcut="⌘+]" data-event="indent" tabindex="-1"><i class="fa fa-indent icon-indent-right"></i></button></div></div>'},height:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small dropdown-toggle" data-toggle="dropdown" title="'+a.font.height+'" tabindex="-1"><i class="fa fa-text-height icon-text-height"></i>&nbsp; <b class="caret"></b></button><ul class="dropdown-menu"><li><a data-event="lineHeight" data-value="1.0"><i class="fa fa-check icon-ok"></i> 1.0</a></li><li><a data-event="lineHeight" data-value="1.2"><i class="fa fa-check icon-ok"></i> 1.2</a></li><li><a data-event="lineHeight" data-value="1.4"><i class="fa fa-check icon-ok"></i> 1.4</a></li><li><a data-event="lineHeight" data-value="1.5"><i class="fa fa-check icon-ok"></i> 1.5</a></li><li><a data-event="lineHeight" data-value="1.6"><i class="fa fa-check icon-ok"></i> 1.6</a></li><li><a data-event="lineHeight" data-value="1.8"><i class="fa fa-check icon-ok"></i> 1.8</a></li><li><a data-event="lineHeight" data-value="2.0"><i class="fa fa-check icon-ok"></i> 2.0</a></li><li><a data-event="lineHeight" data-value="3.0"><i class="fa fa-check icon-ok"></i> 3.0</a></li></ul>'},help:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small" title="'+a.options.help+'" data-event="showHelpDialog" tabindex="-1"><i class="fa fa-question icon-question"></i></button>'},fullscreen:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small" title="'+a.options.fullscreen+'" data-event="fullscreen" tabindex="-1"><i class="fa fa-arrows-alt icon-fullscreen"></i></button>'},codeview:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small" title="'+a.options.codeview+'" data-event="codeview" tabindex="-1"><i class="fa fa-code icon-code"></i></button>'},undo:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small" title="'+a.history.undo+'" data-event="undo" tabindex="-1"><i class="fa fa-undo icon-undo"></i></button>'},redo:function(a){return'<button type="button" class="btn btn-default btn-sm btn-small" title="'+a.history.redo+'" data-event="redo" tabindex="-1"><i class="fa fa-repeat icon-repeat"></i></button>'}},d=function(a){return'<div class="note-popover"><div class="note-link-popover popover bottom in" style="display: none;"><div class="arrow"></div><div class="popover-content note-link-content"><a href="http://www.google.com" target="_blank">www.google.com</a>&nbsp;&nbsp;<div class="note-insert btn-group"><button type="button" class="btn btn-default btn-sm btn-small" title="'+a.link.edit+'" data-event="showLinkDialog" tabindex="-1"><i class="fa fa-edit icon-edit"></i></button><button type="button" class="btn btn-default btn-sm btn-small" title="'+a.link.unlink+'" data-event="unlink" tabindex="-1"><i class="fa fa-unlink icon-unlink"></i></button></div></div></div><div class="note-image-popover popover bottom in" style="display: none;"><div class="arrow"></div><div class="popover-content note-image-content"><div class="btn-group"><button type="button" class="btn btn-default btn-sm btn-small" title="'+a.image.resizeFull+'" data-event="resize" data-value="1" tabindex="-1"><span class="note-fontsize-10">100%</span> </button><button type="button" class="btn btn-default btn-sm btn-small" title="'+a.image.resizeHalf+'" data-event="resize" data-value="0.5" tabindex="-1"><span class="note-fontsize-10">50%</span> </button><button type="button" class="btn btn-default btn-sm btn-small" title="'+a.image.resizeQuarter+'" data-event="resize" data-value="0.25" tabindex="-1"><span class="note-fontsize-10">25%</span> </button></div><div class="btn-group"><button type="button" class="btn btn-default btn-sm btn-small" title="'+a.image.floatLeft+'" data-event="floatMe" data-value="left" tabindex="-1"><i class="fa fa-align-left icon-align-left"></i></button><button type="button" class="btn btn-default btn-sm btn-small" title="'+a.image.floatRight+'" data-event="floatMe" data-value="right" tabindex="-1"><i class="fa fa-align-right icon-align-right"></i></button><button type="button" class="btn btn-default btn-sm btn-small" title="'+a.image.floatNone+'" data-event="floatMe" data-value="none" tabindex="-1"><i class="fa fa-align-justify icon-align-justify"></i></button></div><div class="btn-group"><button type="button" class="btn btn-default btn-sm btn-small" title="'+a.image.remove+'" data-event="removeMedia" data-value="none" tabindex="-1"><i class="fa fa-trash-o icon-trash"></i></button></div></div></div></div>'};var e=function(){return'<div class="note-handle"><div class="note-control-selection"><div class="note-control-selection-bg"></div><div class="note-control-holder note-control-nw"></div><div class="note-control-holder note-control-ne"></div><div class="note-control-holder note-control-sw"></div><div class="note-control-sizing note-control-se"></div><div class="note-control-selection-info"></div></div></div>'},i=function(a){return'<table class="note-shortcut"><thead><tr><th></th><th>'+a.shortcut.textFormatting+"</th></tr></thead><tbody><tr><td>⌘ + B</td><td>"+a.font.bold+"</td></tr><tr><td>⌘ + I</td><td>"+a.font.italic+"</td></tr><tr><td>⌘ + U</td><td>"+a.font.underline+"</td></tr><tr><td>⌘ + ⇧ + S</td><td>"+a.font.strike+"</td></tr><tr><td>⌘ + \\</td><td>"+a.font.clear+"</td></tr></tr></tbody></table>"},j=function(a){return'<table class="note-shortcut"><thead><tr><th></th><th>'+a.shortcut.action+"</th></tr></thead><tbody><tr><td>⌘ + Z</td><td>"+a.history.undo+"</td></tr><tr><td>⌘ + ⇧ + Z</td><td>"+a.history.redo+"</td></tr><tr><td>⌘ + ]</td><td>"+a.paragraph.indent+"</td></tr><tr><td>⌘ + [</td><td>"+a.paragraph.outdent+"</td></tr><tr><td>⌘ + ENTER</td><td>"+a.hr.insert+"</td></tr></tbody></table>"},k=function(a,b){var c='<table class="note-shortcut"><thead><tr><th></th><th>'+a.shortcut.extraKeys+"</th></tr></thead><tbody>";for(var d in b.extraKeys)b.extraKeys.hasOwnProperty(d)&&(c+="<tr><td>"+d+"</td><td>"+b.extraKeys[d]+"</td></tr>");return c+="</tbody></table>"},l=function(a){return'<table class="note-shortcut"><thead><tr><th></th><th>'+a.shortcut.paragraphFormatting+"</th></tr></thead><tbody><tr><td>⌘ + ⇧ + L</td><td>"+a.paragraph.left+"</td></tr><tr><td>⌘ + ⇧ + E</td><td>"+a.paragraph.center+"</td></tr><tr><td>⌘ + ⇧ + R</td><td>"+a.paragraph.right+"</td></tr><tr><td>⌘ + ⇧ + J</td><td>"+a.paragraph.justify+"</td></tr><tr><td>⌘ + ⇧ + NUM7</td><td>"+a.lists.ordered+"</td></tr><tr><td>⌘ + ⇧ + NUM8</td><td>"+a.lists.unordered+"</td></tr></tbody></table>"},m=function(a){return'<table class="note-shortcut"><thead><tr><th></th><th>'+a.shortcut.documentStyle+"</th></tr></thead><tbody><tr><td>⌘ + NUM0</td><td>"+a.style.normal+"</td></tr><tr><td>⌘ + NUM1</td><td>"+a.style.h1+"</td></tr><tr><td>⌘ + NUM2</td><td>"+a.style.h2+"</td></tr><tr><td>⌘ + NUM3</td><td>"+a.style.h3+"</td></tr><tr><td>⌘ + NUM4</td><td>"+a.style.h4+"</td></tr><tr><td>⌘ + NUM5</td><td>"+a.style.h5+"</td></tr><tr><td>⌘ + NUM6</td><td>"+a.style.h6+"</td></tr></tbody></table>"},n=function(a,b){var c='<table class="note-shortcut-layout"><tbody><tr><td>'+j(a,b)+"</td><td>"+i(a,b)+"</td></tr><tr><td>"+m(a,b)+"</td><td>"+l(a,b)+"</td></tr>";return b.extraKeys&&(c+='<tr><td colspan="2">'+k(a,b)+"</td></tr>"),c+="</tbody</table>"},o=function(a){return a.replace(/⌘/g,"Ctrl").replace(/⇧/g,"Shift")};g=function(a,b){var d=function(){return'<div class="note-image-dialog modal" aria-hidden="false"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" aria-hidden="true" tabindex="-1">&times;</button><h4>'+a.image.insert+'</h4></div><div class="modal-body"><div class="row-fluid"><h5>'+a.image.selectFromFiles+'</h5><input class="note-image-input" type="file" name="files" accept="image/*" /><h5>'+a.image.url+'</h5><input class="note-image-url form-control span12" type="text" /></div></div><div class="modal-footer"><button href="#" class="btn btn-primary note-image-btn disabled" disabled="disabled">'+a.image.insert+"</button></div></div></div></div>"},e=function(){return'<div class="note-link-dialog modal" aria-hidden="false"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" aria-hidden="true" tabindex="-1">&times;</button><h4>'+a.link.insert+'</h4></div><div class="modal-body"><div class="row-fluid"><div class="form-group"><label>'+a.link.textToDisplay+'</label><input class="note-link-text form-control span12" disabled type="text" /></div><div class="form-group"><label>'+a.link.url+'</label><input class="note-link-url form-control span12" type="text" /></div>'+(b.disableLinkTarget?"":'<div class="checkbox"><label><input type="checkbox" checked> '+a.link.openInNewWindow+"</label></div>")+'</div></div><div class="modal-footer"><button href="#" class="btn btn-primary note-link-btn disabled" disabled="disabled">'+a.link.insert+"</button></div></div></div></div>"},f=function(){return'<div class="note-video-dialog modal" aria-hidden="false"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" aria-hidden="true" tabindex="-1">&times;</button><h4>'+a.video.insert+'</h4></div><div class="modal-body"><div class="row-fluid"><div class="form-group"><label>'+a.video.url+'</label>&nbsp;<small class="text-muted">'+a.video.providers+'</small><input class="note-video-url form-control span12" type="text" /></div></div></div><div class="modal-footer"><button href="#" class="btn btn-primary note-video-btn disabled" disabled="disabled">'+a.video.insert+"</button></div></div></div></div>"},g=function(){return'<div class="note-help-dialog modal" aria-hidden="false"><div class="modal-dialog"><div class="modal-content"><div class="modal-body"><a class="modal-close pull-right" aria-hidden="true" tabindex="-1">'+a.shortcut.close+'</a><div class="title">'+a.shortcut.shortcuts+"</div>"+(c.bMac?n(a,b):o(n(a,b)))+'<p class="text-center"><a href="//hackerwins.github.io/summernote/" target="_blank">Summernote 0.5.1</a> · <a href="//github.com/HackerWins/summernote" target="_blank">Project</a> · <a href="//github.com/HackerWins/summernote/issues" target="_blank">Issues</a></p></div></div></div></div>'};return'<div class="note-dialog">'+d()+e()+f()+g()+"</div>"},h=function(){return'<div class="note-resizebar"><div class="note-icon-bar"></div><div class="note-icon-bar"></div><div class="note-icon-bar"></div></div>'};var p=function(b,d){b.find("button").each(function(b,d){var e=a(d),f=e.attr(c.bMac?"data-mac-shortcut":"data-shortcut");f&&e.attr("title",function(a,b){return b+" ("+f+")"})}).tooltip({container:"body",trigger:"hover",placement:d||"top"}).on("click",function(){a(this).tooltip("hide")})},q=[["#000000","#424242","#636363","#9C9C94","#CEC6CE","#EFEFEF","#F7F7F7","#FFFFFF"],["#FF0000","#FF9C00","#FFFF00","#00FF00","#00FFFF","#0000FF","#9C00FF","#FF00FF"],["#F7C6CE","#FFE7CE","#FFEFC6","#D6EFD6","#CEDEE7","#CEE7F7","#D6D6E7","#E7D6DE"],["#E79C9C","#FFC69C","#FFE79C","#B5D6A5","#A5C6CE","#9CC6EF","#B5A5D6","#D6A5BD"],["#E76363","#F7AD6B","#FFD663","#94BD7B","#73A5AD","#6BADDE","#8C7BC6","#C67BA5"],["#CE0000","#E79439","#EFC631","#6BA54A","#4A7B8C","#3984C6","#634AA5","#A54A7B"],["#9C0000","#B56308","#BD9400","#397B21","#104A5A","#085294","#311873","#731842"],["#630000","#7B3900","#846300","#295218","#083139","#003163","#21104A","#4A1031"]],r=function(b){b.find(".note-color-palette").each(function(){for(var b=a(this),c=b.attr("data-target-event"),d=[],e=0,f=q.length;f>e;e++){for(var g=q[e],h=[],i=0,j=g.length;j>i;i++){var k=g[i];h.push(['<button type="button" class="note-color-btn" style="background-color:',k,';" data-event="',c,'" data-value="',k,'" title="',k,'" data-toggle="button" tabindex="-1"></button>'].join(""))}d.push("<div>"+h.join("")+"</div>")}b.html(d.join(""))})};this.createLayout=function(c,i){var j=c.next();if(!j||!j.hasClass("note-editor")){var k=a('<div class="note-editor"></div>');i.width&&k.width(i.width),i.height>0&&a('<div class="note-statusbar">'+h()+"</div>").prependTo(k);var l=!c.is(":disabled"),m=a('<div class="note-editable" contentEditable="'+l+'"></div>').prependTo(k);i.height&&m.height(i.height),i.direction&&m.attr("dir",i.direction),m.html(f.html(c)||f.emptyPara),a('<textarea class="note-codable"></textarea>').prependTo(k);for(var n=a.summernote.lang[i.lang],o="",q=0,s=i.toolbar.length;s>q;q++){var t=i.toolbar[q];o+='<div class="note-'+t[0]+' btn-group">';for(var u=0,v=t[1].length;v>u;u++)o+=b[t[1][u]](n);o+="</div>"}o='<div class="note-toolbar btn-toolbar">'+o+"</div>";var w=a(o).prependTo(k);r(w),p(w,"bottom");var x=a(d(n)).prependTo(k);p(x),a(e()).prependTo(k);var y=a(g(n,i)).prependTo(k);y.find("button.close, a.modal-close").click(function(){a(this).closest(".modal").modal("hide")}),a('<div class="note-dropzone"><div class="note-dropzone-message"></div></div>').prependTo(k),k.insertAfter(c),c.hide()}},this.layoutInfoFromHolder=function(a){var b=a.next();if(b.hasClass("note-editor")){var c=f.buildLayoutInfo(b);for(var d in c)c.hasOwnProperty(d)&&(c[d]=c[d].call());return c}},this.removeLayout=function(a){var b=this.layoutInfoFromHolder(a);b&&(a.html(b.editable.html()),b.editor.remove(),a.show())}};a.summernote=a.summernote||{},a.extend(a.summernote,g);var u=new t,v=new s;a.fn.extend({summernote:function(b){if(b=a.extend({},a.summernote.options,b),this.each(function(c,d){var e=a(d);u.createLayout(e,b);var g=u.layoutInfoFromHolder(e);v.attach(g,b),f.isTextarea(e[0])&&e.closest("form").submit(function(){e.html(e.code())})}),this.first()&&b.focus){var c=u.layoutInfoFromHolder(this.first());c.editable.focus()}return this.length>0&&b.oninit&&b.oninit(),this},code:function(b){if(void 0===b){var d=this.first();if(0===d.length)return;var e=u.layoutInfoFromHolder(d);if(e&&e.editable){var f=e.editor.hasClass("codeview");return f&&c.bCodeMirror&&e.codable.data("cmEditor").save(),f?e.codable.val():e.editable.html()}return d.html()}return this.each(function(c,d){var e=u.layoutInfoFromHolder(a(d));e&&e.editable&&e.editable.html(b)}),this},destroy:function(){return this.each(function(b,c){var d=a(c),e=u.layoutInfoFromHolder(d);e&&e.editable&&(v.dettach(e),u.removeLayout(d))}),this}})});
\ No newline at end of file
diff --git a/web/robots.txt b/web/robots.txt
new file mode 100644 (file)
index 0000000..214e411
--- /dev/null
@@ -0,0 +1,4 @@
+# www.robotstxt.org/
+# www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156449
+
+User-agent: *