First git commit
This commit is contained in:
commit
a830722f4c
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
vendor/
|
27
CONTRIBUTORS.md
Normal file
27
CONTRIBUTORS.md
Normal file
|
@ -0,0 +1,27 @@
|
|||
Contributors
|
||||
============
|
||||
|
||||
Development
|
||||
-----------
|
||||
|
||||
* Simon Vieille (deepblue)
|
||||
* Valérian Galliat (vava740)
|
||||
|
||||
Questions & Weightings
|
||||
----------------------
|
||||
|
||||
Some questions are inspired by [Linux Distribution Chooser](http://www.zegeniestudios.net/ldc/),
|
||||
a similar project that hasn't been updated since a while, and therefore
|
||||
giving biased results (but the questions are still relevant).
|
||||
|
||||
* Simon Vieille (deepblue)
|
||||
|
||||
OS's Descriptions
|
||||
-----------------
|
||||
|
||||
* Simon Vieille (deepblue)
|
||||
|
||||
Hosting
|
||||
-------
|
||||
|
||||
* [Simon Vieille (deepblue)](https://linux-test.deblan.org/)
|
19
LICENSE
Normal file
19
LICENSE
Normal file
|
@ -0,0 +1,19 @@
|
|||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://www.wtfpl.net/ for more details.
|
34
Makefile
Normal file
34
Makefile
Normal file
|
@ -0,0 +1,34 @@
|
|||
COMPOSER ?= composer
|
||||
PHPCS ?= vendor/bin/phpcs
|
||||
|
||||
PHPCS_FLAGS = --standard=PSR2
|
||||
PHPCS_DIRS = app src
|
||||
|
||||
all: composer
|
||||
|
||||
prod: COMPOSER_INSTALL_FLAGS += --no-dev
|
||||
prod: all optimize
|
||||
|
||||
composer:
|
||||
@echo
|
||||
#
|
||||
# Installing application's dependencies.
|
||||
#
|
||||
$(COMPOSER) install $(COMPOSER_INSTALL_FLAGS)
|
||||
|
||||
optimize:
|
||||
@echo
|
||||
#
|
||||
# Optimizing Composer's autoloader, can take some time.
|
||||
#
|
||||
$(COMPOSER) dump-autoload --optimize
|
||||
|
||||
update:
|
||||
@echo
|
||||
#
|
||||
# Updating application's depencies.
|
||||
#
|
||||
$(COMPOSER) update
|
||||
|
||||
cs:
|
||||
$(PHPCS) $(PHPCS_FLAGS) $(PHPCS_DIRS)
|
114
README.en.md
Normal file
114
README.en.md
Normal file
|
@ -0,0 +1,114 @@
|
|||
Linux Questionnaire
|
||||
===================
|
||||
|
||||
This project provides a questionnaire that determines
|
||||
the Linux distribution (or BSD system) which matches
|
||||
your preferences.
|
||||
|
||||
Contact & Support
|
||||
-----------------
|
||||
|
||||
### Project Management
|
||||
|
||||
* [Redmine](https://lab.deblan.org/client/projects/linux-questionnaire)
|
||||
|
||||
### Repository Browsers
|
||||
|
||||
* [Redmine](https://lab.deblan.org/client/projects/linux-questionnaire/repository)
|
||||
* [WebSVN](https://guest:guest@svn.deblan.org/websvn/listing.php?repname=linux-questionnaire)
|
||||
|
||||
### IRC
|
||||
|
||||
* Server: `ssl.neutralnetwork.org`
|
||||
* Channel: `#wiki`
|
||||
* [Web client](https://ssl.neutralnetwork.org/irc/?channels=%23wiki)
|
||||
|
||||
### Forum
|
||||
|
||||
* [Official topic](http://www.jeuxvideo.com/forums/1-38-7795760-1-0-1-0-questionnaire-choix-distribution.htm)
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
* [PHP](https://www.php.net/) >= 5.4
|
||||
* [Apache Subversion](https://subversion.apache.org/)
|
||||
* [Composer](https://getcomposer.org/)
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
svn co https://svn.deblan.org/svn/linux-questionnaire
|
||||
cd linux-questionnaire
|
||||
make
|
||||
|
||||
Composer
|
||||
--------
|
||||
|
||||
Composer can maybe be downloaded from your system's repositories.
|
||||
Else, follow the next instructions:
|
||||
|
||||
### Download
|
||||
|
||||
# With cURL
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
# With Wget
|
||||
wget -O - -q https://getcomposer.org/installer | php
|
||||
|
||||
You can now use it with `php composer.phar [arguments]`.
|
||||
|
||||
### Executable
|
||||
|
||||
mv composer.phar composer
|
||||
chmod +x composer
|
||||
|
||||
Use it with `./composer [arguments]`.
|
||||
|
||||
### Install
|
||||
|
||||
Assuming `~/bin` exists ans is in `$PATH`.
|
||||
|
||||
mv composer ~/bin
|
||||
|
||||
### Dependencies Installation (from `composer.lock`)
|
||||
|
||||
composer install
|
||||
|
||||
### Dependencies Update (will change `composer.lock`)
|
||||
|
||||
composer update
|
||||
|
||||
Makefile
|
||||
--------
|
||||
|
||||
A Makefile is provided to automate some tasks.
|
||||
|
||||
* `make` will install application's dependencies via Composer,
|
||||
* `make prod` will install dependencies without developmenent requirements
|
||||
and run `make optimize`,
|
||||
* `make optimize` will run Composer's autoloader dump script with classmap
|
||||
only, without dynamic autoload rules,
|
||||
* `make cs` will run PHP code sniffer with PSR-2 conventions.
|
||||
|
||||
Development Server
|
||||
------------------
|
||||
|
||||
Use PHP's built-in development server, for example on `localhost`, port 8080:
|
||||
|
||||
cd web
|
||||
php -S localhost:8080
|
||||
|
||||
Homepage Update
|
||||
---------------
|
||||
|
||||
When the `README.*.md` files are updated, we also need to update
|
||||
the matching views in `web/views/Questionnaire/readme.*.html.twig`. To do that,
|
||||
a simple console script was created.
|
||||
|
||||
### Help
|
||||
|
||||
app/console generate:readme -h
|
||||
|
||||
### Basic Generation
|
||||
|
||||
app/console generate:readme
|
114
README.fr.md
Normal file
114
README.fr.md
Normal file
|
@ -0,0 +1,114 @@
|
|||
Questionnaire Linux
|
||||
===================
|
||||
|
||||
Ce projet consiste en un questionnaire permettant de déterminer
|
||||
la distribution Linux (ou BSD) qui vous convient le plus.
|
||||
|
||||
Contact et support
|
||||
------------------
|
||||
|
||||
### Gestion de projet
|
||||
|
||||
* [Redmine](https://lab.deblan.org/client/projects/linux-questionnaire)
|
||||
|
||||
### Arborescense du code
|
||||
|
||||
* [Redmine](https://lab.deblan.org/client/projects/linux-questionnaire/repository)
|
||||
* [WebSVN](https://guest:guest@svn.deblan.org/websvn/listing.php?repname=linux-questionnaire)
|
||||
|
||||
### IRC
|
||||
|
||||
* Server: `ssl.neutralnetwork.org`
|
||||
* Channel: `#wiki`
|
||||
* [Web client](https://ssl.neutralnetwork.org/irc/?channels=%23wiki)
|
||||
|
||||
### Forum
|
||||
|
||||
* [Official topic](http://www.jeuxvideo.com/forums/1-38-7795760-1-0-1-0-questionnaire-choix-distribution.htm)
|
||||
|
||||
Prérequis
|
||||
---------
|
||||
|
||||
* [PHP](https://www.php.net/) >= 5.4
|
||||
* [Apache Subversion](https://subversion.apache.org/)
|
||||
* [Composer](https://getcomposer.org/)
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
svn co https://svn.deblan.org/svn/linux-questionnaire
|
||||
cd linux-questionnaire
|
||||
make
|
||||
|
||||
Composer
|
||||
--------
|
||||
|
||||
Composer est peut-être téléchargeable depuis votre gestionnaire de paquets.
|
||||
Sinon, suivez les instructions suivantes :
|
||||
|
||||
### Téléchargement
|
||||
|
||||
# Avec cURL
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
# Avec Wget
|
||||
wget -O - -q https://getcomposer.org/installer | php
|
||||
|
||||
Vous pouvez maintenant l'utiliser avec `php composer.phar [arguments]`.
|
||||
|
||||
### Exécutable
|
||||
|
||||
mv composer.phar composer
|
||||
chmod +x composer
|
||||
|
||||
S'utilise désormais avec `./composer [arguments]`.
|
||||
|
||||
### Installation
|
||||
|
||||
En partant du principe que le dossier `~/bin` existe et est dans le `$PATH`.
|
||||
|
||||
mv composer ~/bin
|
||||
|
||||
### Installation des dépendances (depuis `composer.lock`)
|
||||
|
||||
composer install
|
||||
|
||||
### Mise à jour des dépendances (modification de `composer.lock`)
|
||||
|
||||
composer update
|
||||
|
||||
Makefile
|
||||
--------
|
||||
|
||||
Un Makefile est intégré pour automatiser certaines tâches.
|
||||
|
||||
* `make` installera les dépendances de l'application avec Composer,
|
||||
* `make prod` installera les dépendances à l'exception de celles nécessaires
|
||||
seulement au développement, et lancera `make optimize`,
|
||||
* `make optimize` exécutera le script d'optimisation de Composer pour convertir
|
||||
les chargements dynamiques de classes en *classmap*,
|
||||
* `make cs` lancera un *code sniffer* PHP avec les conventions PSR-2.
|
||||
|
||||
Serveur de développement
|
||||
------------------------
|
||||
|
||||
Vous pouvez utiliser le serveur de développement intégré à PHP, par exemple
|
||||
sur `localhost`, port 8080 :
|
||||
|
||||
cd web
|
||||
php -S localhost:8080
|
||||
|
||||
Mise à jour de la page d'accueil
|
||||
--------------------------------
|
||||
|
||||
Quand les `README.*.md` sont modifiés, il faut aussi mettre à jour les
|
||||
vues correspondantes dans `web/views/Questionnaire/readme.*.html.twig`.
|
||||
Pour ça, un script a été créé.
|
||||
|
||||
### Aide
|
||||
|
||||
app/console generate:readme -h
|
||||
|
||||
### Génération de base
|
||||
|
||||
app/console generate:readme
|
31
TODO.md
Normal file
31
TODO.md
Normal file
|
@ -0,0 +1,31 @@
|
|||
Todo
|
||||
====
|
||||
|
||||
* Fix images in questionnaire config to not use an abslute path, using
|
||||
a placeholder variable in the text (compatible with translation).
|
||||
|
||||
* Maybe find another way to include image than the plain HTML in config
|
||||
file and translation.
|
||||
|
||||
* Show result value indicator.
|
||||
|
||||
* Take out some logic from controllers.
|
||||
|
||||
* Use service providers for most stuff in `app/bootstrap.php`.
|
||||
|
||||
* Peers:
|
||||
* externalize YAML parsing in `QuestionnairePeer`,
|
||||
* factorize peers to be injected as shared services.
|
||||
|
||||
* Maybe find a way to factorize site title and other variables,
|
||||
for example using a Makefile to convert `.dist` files, like
|
||||
`README.md.dist` with `%title%` replaced with real variable
|
||||
during make process in target `README.md`.
|
||||
|
||||
* Not tested, but I guess the local server shown in readme
|
||||
may not work, as it don't rewrite URL's with Apache config
|
||||
override (`.htaccess`), and the website currently don't work
|
||||
with `/index.php/*` links.
|
||||
|
||||
* Make the `.svnignore` work, or any way to ignore any directory
|
||||
and its content.
|
36
app/bootstrap.php
Normal file
36
app/bootstrap.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
/**
|
||||
* Wrap everything in a closure to preserve global scope and return the
|
||||
* application.
|
||||
*/
|
||||
return call_user_func(function () {
|
||||
$app = null;
|
||||
|
||||
/**
|
||||
* This closure will be used to require other init files with a clean
|
||||
* scope, with only access to `$app`.
|
||||
*/
|
||||
$closure = function () use (&$app) {
|
||||
require func_get_arg(0);
|
||||
};
|
||||
|
||||
$files = array();
|
||||
|
||||
foreach (new DirectoryIterator(__FILE__ . '.d') as $file) {
|
||||
if (!$file->isDot() && $file->isFile()) {
|
||||
$files[] = $file->getPathname();
|
||||
}
|
||||
}
|
||||
|
||||
// Sort init files, order is important
|
||||
sort($files);
|
||||
|
||||
foreach ($files as $file) {
|
||||
$closure($file);
|
||||
}
|
||||
|
||||
return $app;
|
||||
});
|
7
app/bootstrap.php.d/00-main.php
Normal file
7
app/bootstrap.php.d/00-main.php
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
use Questionnaire\Application;
|
||||
|
||||
$app = Application::getInstance();
|
||||
|
||||
$app['root_path'] = __DIR__ . '/../..';
|
9
app/bootstrap.php.d/10-config.php
Normal file
9
app/bootstrap.php.d/10-config.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
|
||||
$app['config.locator.path'] = $app['root_path'].'/app/config';
|
||||
|
||||
$app['config.locator'] = $app->share(function ($app) {
|
||||
return new FileLocator($app['config.locator.path']);
|
||||
});
|
15
app/bootstrap.php.d/20-console.php
Normal file
15
app/bootstrap.php.d/20-console.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
use Knp\Provider\ConsoleServiceProvider;
|
||||
use Questionnaire\Command\GenerateReadmeCommand;
|
||||
|
||||
$app->register(new ConsoleServiceProvider(), array(
|
||||
'console.name' => 'Linux Questionnaire',
|
||||
'console.version' => 'dev-master',
|
||||
'console.project_directory' => $app['root_path'],
|
||||
));
|
||||
|
||||
$app['console'] = $app->share($app->extend('console', function ($console) {
|
||||
$console->add(new GenerateReadmeCommand());
|
||||
return $console;
|
||||
}));
|
12
app/bootstrap.php.d/20-error.php
Normal file
12
app/bootstrap.php.d/20-error.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
$app->error(function (Exception $e, $code) use ($app) {
|
||||
return $app['twig']->render(
|
||||
'error.html.twig',
|
||||
array(
|
||||
'code' => $code,
|
||||
'name' => get_class($e),
|
||||
'exception' => $e,
|
||||
)
|
||||
);
|
||||
});
|
10
app/bootstrap.php.d/20-misc.php
Normal file
10
app/bootstrap.php.d/20-misc.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
use Silex\Provider\UrlGeneratorServiceProvider;
|
||||
use Silex\Provider\SessionServiceProvider;
|
||||
|
||||
use Nicl\Silex\MarkdownServiceProvider;
|
||||
|
||||
$app->register(new UrlGeneratorServiceProvider());
|
||||
$app->register(new SessionServiceProvider());
|
||||
$app->register(new MarkdownServiceProvider());
|
11
app/bootstrap.php.d/20-readme.php
Normal file
11
app/bootstrap.php.d/20-readme.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
use Questionnaire\Parser\ReadmeParser;
|
||||
|
||||
$app['dom_document'] = function ($app) {
|
||||
return new DOMDocument();
|
||||
};
|
||||
|
||||
$app['readme.parser'] = function ($app) {
|
||||
return new ReadmeParser($app['dom_document']);
|
||||
};
|
14
app/bootstrap.php.d/20-routing.php
Normal file
14
app/bootstrap.php.d/20-routing.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
use Symfony\Component\Routing\Loader\YamlFileLoader;
|
||||
|
||||
$app['routing.file'] = 'routing.yml';
|
||||
|
||||
$app['routing.loader'] = $app->share(function ($app) {
|
||||
return new YamlFileLoader($app['config.locator']);
|
||||
});
|
||||
|
||||
$app['routes'] = $app->share($app->extend('routes', function ($routes, $app) {
|
||||
$routes->addCollection($app['routing.loader']->load($app['routing.file']));
|
||||
return $routes;
|
||||
}));
|
15
app/bootstrap.php.d/20-twig.php
Normal file
15
app/bootstrap.php.d/20-twig.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
use Silex\Provider\TwigServiceProvider;
|
||||
|
||||
$app->register(new TwigServiceProvider(), array(
|
||||
'twig.path' => $app['root_path'].'/views',
|
||||
'breadcrumb_separator' => ' - ',
|
||||
));
|
||||
|
||||
$app->extend('twig', function ($twig, $app) {
|
||||
$twig->addGlobal('web_path', $app['request']->getBaseUrl().'/');
|
||||
$twig->addGlobal('breadcrumb_separator', $app['breadcrumb_separator']);
|
||||
$twig->addGlobal('bs', $app['breadcrumb_separator']);
|
||||
return $twig;
|
||||
});
|
58
app/bootstrap.php.d/30-trans.php
Normal file
58
app/bootstrap.php.d/30-trans.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
use Silex\Provider\TranslationServiceProvider;
|
||||
use Symfony\Component\Translation\Loader\YamlFileLoader;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\AcceptHeader;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
|
||||
$app->register(new TranslationServiceProvider(), array(
|
||||
'locale' => 'en',
|
||||
'locale_fallback' => 'en',
|
||||
'locales' => array('en', 'fr'), // Custom parameter, not Silex
|
||||
));
|
||||
|
||||
$app['translator'] = $app->share($app->extend('translator', function ($translator, $app) {
|
||||
$translator->addLoader('yaml', new YamlFileLoader());
|
||||
|
||||
foreach ($app['locales'] as $locale) {
|
||||
$file = $app['root_path'].'/app/locales/'.$locale.'.yml';
|
||||
|
||||
if (is_file($file)) {
|
||||
$translator->addResource('yaml', $file, $locale);
|
||||
}
|
||||
}
|
||||
|
||||
return $translator;
|
||||
}));
|
||||
|
||||
$app['routes'] = $app->share($app->extend('routes', function ($routes, $app) {
|
||||
$routes->addPrefix('/{_locale}');
|
||||
$routes->addDefaults(array('_locale' => $app['locale_fallbacks'][0]));
|
||||
$routes->addRequirements(array('_locale' => implode('|', $app['locales'])));
|
||||
|
||||
return $routes;
|
||||
}));
|
||||
|
||||
/**
|
||||
* Redirect home on right locale page, regarding of request accept locale or
|
||||
* default fallback.
|
||||
*/
|
||||
$app->get('/', function (Request $request) use ($app) {
|
||||
$accept = AcceptHeader::fromString($request->headers->get('Accept-Language'));
|
||||
|
||||
// Default locale fallback
|
||||
$foundLocale = $app['translator']->getLocale();
|
||||
|
||||
foreach ($app['locales'] as $locale) {
|
||||
if ($accept->has($locale)) {
|
||||
$foundLocale = $locale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new RedirectResponse($app['url_generator']->generate(
|
||||
'homepage',
|
||||
array('_locale' => $foundLocale)
|
||||
));
|
||||
});
|
215
app/config/questionnaire.yml
Normal file
215
app/config/questionnaire.yml
Normal file
|
@ -0,0 +1,215 @@
|
|||
questions:
|
||||
10:
|
||||
title: Pour vous, c'est quoi Linux ?
|
||||
choices:
|
||||
1: <img src="/assets/img/10-tty.png" alt="TTY" width="200">
|
||||
2: <img src="/assets/img/10-lxde.png" alt="LXDE" width="200">
|
||||
3: <img src="/assets/img/10-osx.png" alt="Mac OS X" width="200">
|
||||
20:
|
||||
title: Savez-vous ce qu'est une « distribution Linux » ?
|
||||
# required: [[question_id, choice_id]]
|
||||
choices:
|
||||
1: yes
|
||||
2: no
|
||||
30:
|
||||
title: Avez-vous déjà réussi à installer un système d'exploitation auparavant ?
|
||||
choices:
|
||||
1: yes
|
||||
2: no
|
||||
40:
|
||||
title: Savez-vous comment partitionner un disque dur ?
|
||||
choices:
|
||||
1: yes
|
||||
2: Non, je n'ai aucune idée de ce que « partitionnement » signifie
|
||||
3: Non, mais je sais ce que « partitionnement » signifie
|
||||
50:
|
||||
title: Quel genre d'installateur préférez vous ?
|
||||
choices:
|
||||
1: Graphique (pointer et clicker)
|
||||
2: En mode texte (clavier seulement)
|
||||
3: Je n'y prête pas d'importance, du moment que c'est facile et que ça marche
|
||||
60:
|
||||
title: Comment évalueriez-vous votre niveau de qualification technique en informatique ?
|
||||
choices:
|
||||
1: Débutant
|
||||
2: Intermediaire
|
||||
3: Avancé
|
||||
4: Expert
|
||||
70:
|
||||
title: Sur quel genre d'ordinateur allez-vous l'intaller ?
|
||||
choices:
|
||||
1: Un ordinateur portable (laptop)
|
||||
2: Un ordinateur de bureau (desktop)
|
||||
# 3: PS3
|
||||
4: Cela peut-être les deux
|
||||
80:
|
||||
title: Quel est la fonction première de cet ordinateur ?
|
||||
choices:
|
||||
1: Desktop / système personnel
|
||||
2: Station de travail
|
||||
3: Serveur
|
||||
90:
|
||||
title: Avez-vous un processeur 64 bits ?
|
||||
choices:
|
||||
1: yes
|
||||
2: no
|
||||
100:
|
||||
title: Quel âge à l'ordinateur sur lequel vous allez installer Linux ?
|
||||
choices:
|
||||
1: Il a plus que juste quelque années
|
||||
2: Juste quelques années
|
||||
3: Il est (presque) encore brillant
|
||||
110:
|
||||
title: Comment évalueriez-vous votre niveau de connaissance de Linux ?
|
||||
choices:
|
||||
1: Je n'ai jamais utilisé Linux auparavant / j'ai seulement essayé un petit peu
|
||||
2: J'utilise Linux depuis un moment maintenant
|
||||
3: Expérimenté, Je sais parfaitement où je vais
|
||||
120:
|
||||
title: Quel système de gestion de paquets préférez-vous ?
|
||||
choices:
|
||||
1: Je préfère le système DEB
|
||||
2: Je préfère le système RPM
|
||||
3: Je préfère compiler mes propres binaires
|
||||
4: Je préfère un autre
|
||||
5: Je ne sais pas / je n'y prête pas attention
|
||||
130:
|
||||
title: Avez-vous besoin que les paquets de développement soit installés ou aisément disponibles ?
|
||||
choices:
|
||||
1: Oui, aisément disponible
|
||||
2: Oui, sur le CD
|
||||
3: no
|
||||
140:
|
||||
title: Quel environement de bureau préférez-vous ?
|
||||
choices:
|
||||
1: Je préfère KDE
|
||||
2: Je préfère GNOME
|
||||
3: Je préfère LXDE
|
||||
4: Je préfère avoir (aussi) d'autres environements de bureau disponibles
|
||||
5: Je n'y prête pas attention
|
||||
150:
|
||||
title: Avez-vous besoin d'un accès facile à beaucoup de logiciels prêts à l'emploi ?
|
||||
choices:
|
||||
1: Oui, s'il vous plaît
|
||||
2: Non merci / je n'y prête pas attention
|
||||
160:
|
||||
title: Veuillez sélectionner ce qui s'adapte le mieux à vous :
|
||||
choices:
|
||||
1: Je préfère utiliser des logiciels parfaitement stables, complètement testés
|
||||
2: Je veux avoir les tout derniers logiciels mais néanmoins grandement stables
|
||||
3: ça ne me gêne pas de tester des choses nouvelles, excitantes mais expérimentales
|
||||
170:
|
||||
title: Pourquoi êtes-vous ici ?
|
||||
choices:
|
||||
1: Études
|
||||
2: Curiosité
|
||||
3: Windows sucks
|
||||
# 4: Cousin polonais
|
||||
180:
|
||||
title: Est-ce que la distribution Linux doit être gratuite ?
|
||||
choices:
|
||||
1: yes
|
||||
2: no
|
||||
190:
|
||||
title: Voulez-vous inclure les Live CDs dans les résultats ?
|
||||
choices:
|
||||
1: yes
|
||||
2: no
|
||||
|
||||
results:
|
||||
10:
|
||||
title: Debian
|
||||
info: debian
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
15:
|
||||
title: Debian (sid)
|
||||
info: debian-sid
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
|
||||
20:
|
||||
title: Fedora
|
||||
info: fedora
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
30:
|
||||
title: openSUSE
|
||||
info: opensuze
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
40:
|
||||
title: Arch Linux
|
||||
info: arch
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
50:
|
||||
title: Slackware
|
||||
info: slackware
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
60:
|
||||
title: Frugalware
|
||||
info: frugalware
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
70:
|
||||
title: Mageia
|
||||
info: mageia
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
80:
|
||||
title: Sabayon
|
||||
info: sabayon
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
90:
|
||||
title: Toutou Linux
|
||||
info: toutou-linux
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
100:
|
||||
title: Puppy Linux
|
||||
info: puppy-linux
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
110:
|
||||
title: SliTaz
|
||||
info: slitaz
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
120:
|
||||
title: FreeBSD
|
||||
info: freebsd
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
130:
|
||||
title: PC-BSD
|
||||
info: pcbsd
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
140:
|
||||
title: OpenBSD
|
||||
info: openbsd
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
150:
|
||||
title: LFS
|
||||
info: lfs
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
160:
|
||||
title: DragonFly BSD
|
||||
info: dragonfly
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
170:
|
||||
title: Centos
|
||||
info: centos
|
||||
weightings:
|
||||
10: {1: 1}
|
||||
180:
|
||||
title: Windows
|
||||
info: windows
|
||||
weightings:
|
||||
10: {1: 1}
|
19
app/config/routing.yml
Normal file
19
app/config/routing.yml
Normal file
|
@ -0,0 +1,19 @@
|
|||
homepage:
|
||||
path: /
|
||||
defaults: { _controller: Questionnaire\Controller\QuestionnaireController::indexAction, _locale: en }
|
||||
|
||||
start:
|
||||
path: /start
|
||||
defaults: { _controller: Questionnaire\Controller\QuestionnaireController::startAction }
|
||||
|
||||
step:
|
||||
path: /step/{step}
|
||||
defaults: { _controller: Questionnaire\Controller\QuestionnaireController::stepAction }
|
||||
|
||||
result:
|
||||
path: /result
|
||||
defaults: { _controller: Questionnaire\Controller\QuestionnaireController::resultAction }
|
||||
|
||||
distros:
|
||||
path: /distros
|
||||
defaults: { _controller: Os\Controller\OsController::indexAction }
|
6
app/console
Executable file
6
app/console
Executable file
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
$app = require __DIR__.'/bootstrap.php';
|
||||
|
||||
$app['console']->run();
|
14
app/deploy
Executable file
14
app/deploy
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/sh
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
deploy_preprod() {
|
||||
rsync -avzoK --delete -e ssh * weblinuxtest@deblan.fr:/services/web/www/linux-test.deblan.org/project/
|
||||
}
|
||||
|
||||
|
||||
deploy_preprod_lan() {
|
||||
rsync -avzoK --delete -e ssh * weblinuxtest@hinata:/services/web/www/linux-test.deblan.org/project/
|
||||
}
|
||||
|
||||
([ -n "$1" ] && deploy_$1) || deploy_preprod
|
20
app/distros/en/arch.md
Normal file
20
app/distros/en/arch.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
0
app/distros/en/centos.md
Normal file
0
app/distros/en/centos.md
Normal file
20
app/distros/en/debian-sid.md
Normal file
20
app/distros/en/debian-sid.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
20
app/distros/en/debian.md
Normal file
20
app/distros/en/debian.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
0
app/distros/en/dragonfly.md
Normal file
0
app/distros/en/dragonfly.md
Normal file
20
app/distros/en/fedora.md
Normal file
20
app/distros/en/fedora.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
0
app/distros/en/freebsd.md
Normal file
0
app/distros/en/freebsd.md
Normal file
20
app/distros/en/frugalware.md
Normal file
20
app/distros/en/frugalware.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
0
app/distros/en/lfs.md
Normal file
0
app/distros/en/lfs.md
Normal file
20
app/distros/en/mageia.md
Normal file
20
app/distros/en/mageia.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
0
app/distros/en/openbsd.md
Normal file
0
app/distros/en/openbsd.md
Normal file
20
app/distros/en/opensuze.md
Normal file
20
app/distros/en/opensuze.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
0
app/distros/en/pcbsd.md
Normal file
0
app/distros/en/pcbsd.md
Normal file
20
app/distros/en/puppy-linux.md
Normal file
20
app/distros/en/puppy-linux.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
20
app/distros/en/sabayon.md
Normal file
20
app/distros/en/sabayon.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
20
app/distros/en/slackware.md
Normal file
20
app/distros/en/slackware.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
20
app/distros/en/slitaz.md
Normal file
20
app/distros/en/slitaz.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
20
app/distros/en/toutou-linux.md
Normal file
20
app/distros/en/toutou-linux.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
0
app/distros/en/windows.md
Normal file
0
app/distros/en/windows.md
Normal file
20
app/distros/fr/arch.md
Normal file
20
app/distros/fr/arch.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
0
app/distros/fr/centos.md
Normal file
0
app/distros/fr/centos.md
Normal file
20
app/distros/fr/debian-sid.md
Normal file
20
app/distros/fr/debian-sid.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
20
app/distros/fr/debian.md
Normal file
20
app/distros/fr/debian.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
0
app/distros/fr/dragonfly.md
Normal file
0
app/distros/fr/dragonfly.md
Normal file
20
app/distros/fr/fedora.md
Normal file
20
app/distros/fr/fedora.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
0
app/distros/fr/freebsd.md
Normal file
0
app/distros/fr/freebsd.md
Normal file
20
app/distros/fr/frugalware.md
Normal file
20
app/distros/fr/frugalware.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
0
app/distros/fr/lfs.md
Normal file
0
app/distros/fr/lfs.md
Normal file
20
app/distros/fr/mageia.md
Normal file
20
app/distros/fr/mageia.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
0
app/distros/fr/openbsd.md
Normal file
0
app/distros/fr/openbsd.md
Normal file
20
app/distros/fr/opensuze.md
Normal file
20
app/distros/fr/opensuze.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
0
app/distros/fr/pcbsd.md
Normal file
0
app/distros/fr/pcbsd.md
Normal file
20
app/distros/fr/puppy-linux.md
Normal file
20
app/distros/fr/puppy-linux.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
20
app/distros/fr/sabayon.md
Normal file
20
app/distros/fr/sabayon.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
20
app/distros/fr/slackware.md
Normal file
20
app/distros/fr/slackware.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
20
app/distros/fr/slitaz.md
Normal file
20
app/distros/fr/slitaz.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
20
app/distros/fr/toutou-linux.md
Normal file
20
app/distros/fr/toutou-linux.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
0
app/distros/fr/windows.md
Normal file
0
app/distros/fr/windows.md
Normal file
25
app/locales/en.yml
Normal file
25
app/locales/en.yml
Normal file
|
@ -0,0 +1,25 @@
|
|||
base:
|
||||
home: Home
|
||||
distros: Distributions
|
||||
wiki: Wiki
|
||||
|
||||
index:
|
||||
start: Start now!
|
||||
source: Browse source
|
||||
|
||||
result:
|
||||
count: '{0} No result :(|{1} 1 result|]1,Inf] %count% results'
|
||||
|
||||
next: Next
|
||||
previous: Previous
|
||||
|
||||
yes: Yes
|
||||
no: No
|
||||
|
||||
#
|
||||
# Native language names ("Français" will be displayed as-is in English),
|
||||
# not needed to translate in other languages.
|
||||
#
|
||||
locale.native:
|
||||
en: English
|
||||
fr: Français
|
17
app/locales/fr.yml
Normal file
17
app/locales/fr.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
base:
|
||||
home: Accueil
|
||||
distros: Distributions
|
||||
wiki: Wiki
|
||||
|
||||
index:
|
||||
start: Commencer maintenant !
|
||||
source: Voir la source
|
||||
|
||||
result:
|
||||
count: '{0} Aucun résultat :(|{1} 1 résultat|]1,Inf] %count% résultats'
|
||||
|
||||
next: Suivant
|
||||
previous: Précédent
|
||||
|
||||
yes: Oui
|
||||
no: Non
|
28
composer.json
Normal file
28
composer.json
Normal file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"require": {
|
||||
"silex/silex": "1.*",
|
||||
"symfony/yaml": "2.*",
|
||||
"symfony/config": "2.*",
|
||||
"symfony/twig-bridge": "2.*",
|
||||
"nicl/silex-markdown": "1.*",
|
||||
"symfony/translation": "2.*",
|
||||
"knplabs/console-service-provider": "dev-master",
|
||||
|
||||
"components/jquery": "1.*",
|
||||
"twbs/bootstrap": "3.*"
|
||||
},
|
||||
|
||||
"require-dev": {
|
||||
"squizlabs/php_codesniffer": "1.*"
|
||||
},
|
||||
|
||||
"config": {
|
||||
"component-dir": "web/components"
|
||||
},
|
||||
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"": "src/"
|
||||
}
|
||||
}
|
||||
}
|
19
src/Os/Controller/OsController.php
Normal file
19
src/Os/Controller/OsController.php
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace Os\Controller;
|
||||
|
||||
use Silex\Application;
|
||||
use Questionnaire\Model\ResultPeer;
|
||||
|
||||
class OsController
|
||||
{
|
||||
public function indexAction(Application $app)
|
||||
{
|
||||
return $app['twig']->render(
|
||||
'Os/index.html.twig',
|
||||
array(
|
||||
'results' => ResultPeer::retrieveResults(),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
22
src/Questionnaire/Application.php
Normal file
22
src/Questionnaire/Application.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace Questionnaire;
|
||||
|
||||
use Silex\Application as SilexApplication;
|
||||
|
||||
/**
|
||||
* @deprecated The static version should be avoided, use DI instead.
|
||||
*/
|
||||
class Application extends SilexApplication
|
||||
{
|
||||
public static function getInstance()
|
||||
{
|
||||
static $app;
|
||||
|
||||
if (null === $app) {
|
||||
$app = new static;
|
||||
}
|
||||
|
||||
return $app;
|
||||
}
|
||||
}
|
229
src/Questionnaire/Command/GenerateReadmeCommand.php
Normal file
229
src/Questionnaire/Command/GenerateReadmeCommand.php
Normal file
|
@ -0,0 +1,229 @@
|
|||
<?php
|
||||
|
||||
namespace Questionnaire\Command;
|
||||
|
||||
use Knp\Command\Command;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Output\StreamOutput;
|
||||
|
||||
use Questionnaire\Parser\ReadmeParser;
|
||||
|
||||
class GenerateReadmeCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
protected $in;
|
||||
|
||||
/**
|
||||
* @var OutputInterface
|
||||
*/
|
||||
protected $out;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $closeOut;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('generate:readme')
|
||||
->setDescription(
|
||||
'Generate the HTML readme from Markdown with tags replacement.'
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
$this->addArgument(
|
||||
'in',
|
||||
InputArgument::OPTIONAL,
|
||||
'Markdown file to process, <info>README.*.md</info> by default, stdin if <info>-</info>.'
|
||||
);
|
||||
|
||||
$outDefault = '<info>web/views/Questionnaire/readme.*.html.twig</info>';
|
||||
|
||||
$this->addArgument(
|
||||
'out',
|
||||
InputArgument::OPTIONAL,
|
||||
'Output HTML file, '.$outDefault.' by default, stdout if <info>-</info>.'
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if (empty($input->getArgument('in')) && empty($input->getArgument('out'))) {
|
||||
$this->handleDefault($input, $output);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->before($input, $output);
|
||||
|
||||
$app = $this->getSilexApplication();
|
||||
$markdownParser = $app['markdown'];
|
||||
$readmeParser = $app['readme.parser'];
|
||||
|
||||
$md = stream_get_contents($this->in);
|
||||
$html = $markdownParser->transformMarkdown($md);
|
||||
|
||||
$html = sprintf(
|
||||
'
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
%s
|
||||
</body>
|
||||
</html>
|
||||
',
|
||||
$html
|
||||
);
|
||||
|
||||
$readmeParser->load($html);
|
||||
$readmeParser->stream($this->out);
|
||||
|
||||
$this->after();
|
||||
}
|
||||
|
||||
protected function before(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$in = $input->getArgument('in');
|
||||
$out = $input->getArgument('out');
|
||||
|
||||
if (empty($in) || empty($out)) {
|
||||
throw new \InvalidArgumentException('The `in` and `out` parameters must be provided together.');
|
||||
}
|
||||
|
||||
if ($in === '-') {
|
||||
$this->in = fopen('php://stdin', 'rb');
|
||||
} else {
|
||||
$this->validateFile($in, 'rb');
|
||||
$this->in = fopen($in, 'rb');
|
||||
}
|
||||
|
||||
if ($out === '-') {
|
||||
$this->out = $output;
|
||||
$this->closeOut = false;
|
||||
} else {
|
||||
try {
|
||||
$this->validateFile($out, 'wb');
|
||||
} catch (Exception $e) {
|
||||
$this->clean();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$this->out = new StreamOutput(fopen($out, 'wb'));
|
||||
$this->closeOut = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected function after()
|
||||
{
|
||||
$this->clean();
|
||||
}
|
||||
|
||||
protected function clean()
|
||||
{
|
||||
if (is_resource($this->in)) {
|
||||
fclose($this->in);
|
||||
}
|
||||
|
||||
if ($this->closeOut && is_resource($this->out->getStream())) {
|
||||
fclose($this->out->getStream());
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleDefault(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$app = $this->getSilexApplication();
|
||||
$dir = $this->getProjectDirectory();
|
||||
|
||||
$files = glob($dir.'/README.*.md');
|
||||
|
||||
if (empty($files)) {
|
||||
throw new \InvalidArgumentException('No file was found matching `README.*.md`.');
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
/**
|
||||
* Find the penultimate dot in string (assuming it ends with `\..{2}`).
|
||||
*
|
||||
* strrpos($input, '.', -4);
|
||||
*
|
||||
* Cut the filename from the penultimate dot plus 1 (don't include
|
||||
* the dot in the final string) until the end of the string minus 3
|
||||
* (don't take the last 3 characters).
|
||||
*
|
||||
* So, for `README.en.md`, this will extract `en`.
|
||||
*
|
||||
* For `README.en.markdown`, this will extract `markd` (stripping
|
||||
* final `own`), because this will find the last dot instead of
|
||||
* the penultimate dot.
|
||||
*/
|
||||
$lang = substr($file, strrpos($file, '.', -4) + 1, -3);
|
||||
|
||||
// Compote output file from input lang
|
||||
$targets[] = $app['twig.path'].'/Questionnaire/readme.'.$lang.'.html.twig';
|
||||
}
|
||||
|
||||
foreach ($files as $i => $file) {
|
||||
$input->setArgument('in', $file);
|
||||
$input->setArgument('out', $targets[$i]);
|
||||
|
||||
// Recursive execution for each file
|
||||
$this->execute($input, $output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param string $mode
|
||||
* @see fopen()
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function validateFile($file, $mode)
|
||||
{
|
||||
$read = 'r' === $mode[0];
|
||||
$write = in_array($mode[0], array('w', 'a', 'c'), true);
|
||||
$create = $write;
|
||||
|
||||
if ($mode[1] === '+') {
|
||||
if ($read) {
|
||||
$write = true;
|
||||
} elseif ($write) {
|
||||
$read = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_file($file)) {
|
||||
if ($create) {
|
||||
// Let the file be created
|
||||
return;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Given file "%s" does not exists.',
|
||||
$file
|
||||
));
|
||||
}
|
||||
|
||||
if ($read && !is_readable($file)) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Given file "%s" is not readable.',
|
||||
$file
|
||||
));
|
||||
}
|
||||
|
||||
if ($write && !is_writable($file)) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Given file "%s" is not writable.',
|
||||
$file
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
155
src/Questionnaire/Controller/QuestionnaireController.php
Normal file
155
src/Questionnaire/Controller/QuestionnaireController.php
Normal file
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
|
||||
namespace Questionnaire\Controller;
|
||||
|
||||
use Silex\Application;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
use Questionnaire\Model\Question;
|
||||
use Questionnaire\Model\ResultPeer;
|
||||
use Questionnaire\Model\QuestionPeer;
|
||||
|
||||
class QuestionnaireController
|
||||
{
|
||||
public function indexAction(Application $app)
|
||||
{
|
||||
return $app['twig']->render(
|
||||
'Questionnaire/index.html.twig'
|
||||
);
|
||||
}
|
||||
|
||||
public function startAction(Application $app)
|
||||
{
|
||||
$this->initUserResponses($app['session']);
|
||||
|
||||
return $this->redirectToStep(1, $app);
|
||||
}
|
||||
|
||||
public function stepAction($step, Application $app, Request $request)
|
||||
{
|
||||
$step = (int) $step;
|
||||
$realStep = $step - 1;
|
||||
|
||||
$questions = QuestionPeer::retrieveQuestions();
|
||||
|
||||
if ($step > count($questions)) {
|
||||
return $app->redirect($app['url_generator']->generate('result'));
|
||||
}
|
||||
|
||||
$question = $questions[$realStep];
|
||||
|
||||
if ($request->isMethod('post')) {
|
||||
$response = $request->request->get('response');
|
||||
|
||||
if ($response !== null) {
|
||||
$response = (int) $response;
|
||||
|
||||
if (isset($question->getChoices()[$response])) {
|
||||
$this->mergeUserResponse($question, $response, $app['session']);
|
||||
|
||||
return $this->redirectToStep($step + 1, $app);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$question->isCompatibleWithResponses($app['session']->get('responses', array()))) {
|
||||
return $this->redirectToStep($step + 1, $app);
|
||||
}
|
||||
|
||||
return $app['twig']->render(
|
||||
'Questionnaire/step.html.twig',
|
||||
array(
|
||||
'step' => $step,
|
||||
'question' => $question,
|
||||
'percent' => round((100 * $realStep) / count($questions)),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Migrate calculation algorithm in its own class.
|
||||
*/
|
||||
public function resultAction(Application $app)
|
||||
{
|
||||
$responses = $app['session']->get('responses', array());
|
||||
|
||||
if (empty($responses)) {
|
||||
return $this->redirectToStep(1, $app);
|
||||
}
|
||||
|
||||
$results = ResultPeer::retrieveResults();
|
||||
|
||||
foreach ($results as $result) {
|
||||
foreach ($responses as $questionId => $response) {
|
||||
if (isset($result->getWeightings()[$questionId][$response])) {
|
||||
$value = $result->getWeightings()[$questionId][$response];
|
||||
|
||||
if (false === $value) {
|
||||
$result->isOut(true);
|
||||
continue 2;
|
||||
}
|
||||
|
||||
$result->addWeighting($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$finalResults = [];
|
||||
|
||||
foreach ($results as $result) {
|
||||
if ($result->isOut()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$finalResults[] = $result;
|
||||
}
|
||||
|
||||
$hasLoop = true;
|
||||
$length = count($finalResults);
|
||||
|
||||
while ($hasLoop) {
|
||||
$hasLoop = false;
|
||||
|
||||
for ($u = 0; $u < $length - 1; $u++) {
|
||||
if ($finalResults[$u]->getValue() < $finalResults[$u + 1]->getValue()) {
|
||||
$a = $finalResults[$u + 1];
|
||||
$finalResults[$u + 1] = $finalResults[$u];
|
||||
$finalResults[$u] = $a;
|
||||
|
||||
$hasLoop = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $app['twig']->render(
|
||||
'Questionnaire/result.html.twig',
|
||||
array(
|
||||
'results' => $finalResults,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected function initUserResponses(Session $session)
|
||||
{
|
||||
$session->set('responses', array());
|
||||
}
|
||||
|
||||
protected function mergeUserResponse(Question $question, $response, Session $session)
|
||||
{
|
||||
$responses = $session->get('responses', array());
|
||||
|
||||
$responses[$question->getId()] = $response;
|
||||
|
||||
$session->set('responses', $responses);
|
||||
}
|
||||
|
||||
protected function redirectToStep($step, Application $app)
|
||||
{
|
||||
return $app->redirect($app['url_generator']->generate(
|
||||
'step',
|
||||
array(
|
||||
'step' => $step
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
116
src/Questionnaire/Model/Question.php
Normal file
116
src/Questionnaire/Model/Question.php
Normal file
|
@ -0,0 +1,116 @@
|
|||
<?php
|
||||
|
||||
namespace Questionnaire\Model;
|
||||
|
||||
class Question
|
||||
{
|
||||
protected $id;
|
||||
|
||||
protected $title;
|
||||
|
||||
protected $choices = array();
|
||||
|
||||
protected $required = array();
|
||||
|
||||
public function hydrate(array $data)
|
||||
{
|
||||
foreach ($data as $k => $v) {
|
||||
$setter = 'set'.ucfirst($k);
|
||||
|
||||
if (method_exists($this, $setter)) {
|
||||
$this->$setter($v);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setId($id)
|
||||
{
|
||||
$this->id = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setTitle($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function setChoices(array $choices)
|
||||
{
|
||||
$this->choices = $choices;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getChoices()
|
||||
{
|
||||
return $this->choices;
|
||||
}
|
||||
|
||||
public function setRequired(array $required)
|
||||
{
|
||||
$this->required = $required;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRequired()
|
||||
{
|
||||
return $this->required;
|
||||
}
|
||||
|
||||
public function getRequirements()
|
||||
{
|
||||
return $this->getRequired();
|
||||
}
|
||||
|
||||
public function hasRequirements()
|
||||
{
|
||||
return count($this->getRequirements()) > 0;
|
||||
}
|
||||
|
||||
public function isCompatibleWithResponses(array $response)
|
||||
{
|
||||
if (!$this->hasRequirements()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ($response as $questionId => $response) {
|
||||
$question = QuestionPeer::retrieveQuestionById($questionId);
|
||||
|
||||
if (null === $question) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($this->getRequirements() as $requirement) {
|
||||
list($requirementQuestionId, $requirementResponses) = $requirement;
|
||||
|
||||
if ($requirementQuestionId === $questionId) {
|
||||
if (!is_array($requirementResponses)) {
|
||||
$requirementResponses = array($requirementResponses);
|
||||
}
|
||||
|
||||
if (!in_array($response, $requirementResponses)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
136
src/Questionnaire/Model/QuestionPeer.php
Normal file
136
src/Questionnaire/Model/QuestionPeer.php
Normal file
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
|
||||
namespace Questionnaire\Model;
|
||||
|
||||
use Questionnaire\Application;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class QuestionPeer extends QuestionnairePeer
|
||||
{
|
||||
protected static $questions = array();
|
||||
|
||||
public static function retrieveQuestions()
|
||||
{
|
||||
if (!empty(self::$questions)) {
|
||||
return self::$questions;
|
||||
}
|
||||
|
||||
$yaml = self::getYaml();
|
||||
|
||||
$questions = isset($yaml['questions']) ? $yaml['questions'] : array();
|
||||
$collection = [];
|
||||
|
||||
foreach ($questions as $k => $v) {
|
||||
if ($errors = self::validateYamlEnty($k, $v)) {
|
||||
throw new \RuntimeException(
|
||||
'Invalid entry for index "'.$k.'" is not valid:'.PHP_EOL.implode(PHP_EOL, $errors)
|
||||
);
|
||||
}
|
||||
|
||||
$question = new Question();
|
||||
$collection[] = $question->hydrate(array_merge(array('id' => $k), $v));
|
||||
}
|
||||
|
||||
if (empty($collection)) {
|
||||
throw new \RuntimeException('At least one question must be defined.');
|
||||
}
|
||||
|
||||
return self::$questions = $collection;
|
||||
}
|
||||
|
||||
public static function retrieveQuestionById($id)
|
||||
{
|
||||
if (!is_int($id)) {
|
||||
throw \InvalidArgumentException('You must provide a valid integer id.');
|
||||
}
|
||||
|
||||
foreach (self::retrieveQuestions() as $d) {
|
||||
if ($d->getId() === $id) {
|
||||
return $d;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static function validateYamlEnty($key, $entry)
|
||||
{
|
||||
$errors = [];
|
||||
|
||||
if (!is_int($key)) {
|
||||
$errors[] = 'The key must be a integer.';
|
||||
}
|
||||
|
||||
if (!isset($entry['title'])) {
|
||||
$errors[] = '"title" index must be defined (string).';
|
||||
} else {
|
||||
if (!is_string($entry['title'])) {
|
||||
$errors[] = '"title" index must be defined as string.';
|
||||
} else {
|
||||
if (!trim($entry['title'])) {
|
||||
$errors[] = '"title" index value can not be empty.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($entry['choices'])) {
|
||||
$errors[] = '"choices" index must be defined (array).';
|
||||
} else {
|
||||
if (!is_array($entry['choices'])) {
|
||||
$errors[] = '"choices" index must be defined as array.';
|
||||
} else {
|
||||
if (empty($entry['choices'])) {
|
||||
$errors[] = '"choices" index value can not be empty.';
|
||||
} else {
|
||||
foreach ($entry['choices'] as $k => $v) {
|
||||
if (!is_int($k)) {
|
||||
$errors[] = 'Choice with key "'.$k.'" must have an integer key.';
|
||||
}
|
||||
|
||||
if (!is_string($v)) {
|
||||
$errors[] = 'Choice value with key "'.$k.'" must be a string.';
|
||||
} else {
|
||||
if (empty($v)) {
|
||||
$errors[] = 'Choice value with key "'.$k.'" cannot be empty.';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($entry['required'])) {
|
||||
if (!is_array($entry['required'])) {
|
||||
$errors[] = '"required" index must be defined as array.';
|
||||
}
|
||||
|
||||
if (empty($entry['required'])) {
|
||||
$errors[] = '"required" index value can not be empty if defined.';
|
||||
} else {
|
||||
foreach ($entry['required'] as $k => $v) {
|
||||
if (!is_array($v)) {
|
||||
$errors[] = 'At "required" index, value with key "'.$k.'" must be an array.';
|
||||
} else {
|
||||
if (count($v) !== 2) {
|
||||
$errors[] = 'At "required" index, value with key "'.$k.'" must have 2 values: question index and choice index.';
|
||||
} else {
|
||||
if (!is_int($v[0])) {
|
||||
$errors[] = 'At "required" index, value with key "'.$k.'" must have a integer for question\'s index.';
|
||||
} else {
|
||||
if ($v[0] >= $key) {
|
||||
$errors[] = 'At "required" index, value with key "'.$k.'" must have a value smaller than "'.$key.'".';
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_int($v[1]) && !is_array($v[1])) {
|
||||
$errors[] = 'At "required" index, value with key "'.$k.'" must have a integer or array for choice\'s index.';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return !empty($errors) ? $errors : null;
|
||||
}
|
||||
}
|
26
src/Questionnaire/Model/QuestionnairePeer.php
Normal file
26
src/Questionnaire/Model/QuestionnairePeer.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace Questionnaire\Model;
|
||||
|
||||
use Questionnaire\Application;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
abstract class QuestionnairePeer
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $yaml;
|
||||
|
||||
protected static function getYaml()
|
||||
{
|
||||
if (null !== self::$yaml) {
|
||||
return self::$yaml;
|
||||
}
|
||||
|
||||
$file = Application::getInstance()['config.locator']
|
||||
->locate('questionnaire.yml');
|
||||
|
||||
return self::$yaml = Yaml::parse($file);
|
||||
}
|
||||
}
|
109
src/Questionnaire/Model/Result.php
Normal file
109
src/Questionnaire/Model/Result.php
Normal file
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
|
||||
namespace Questionnaire\Model;
|
||||
|
||||
class Result
|
||||
{
|
||||
protected $title;
|
||||
|
||||
protected $value = 0;
|
||||
|
||||
protected $isOut = false;
|
||||
|
||||
protected $info;
|
||||
|
||||
protected $weightings = array();
|
||||
|
||||
public function hydrate(array $data)
|
||||
{
|
||||
foreach ($data as $k => $v) {
|
||||
$setter = 'set'.ucfirst($k);
|
||||
|
||||
if (method_exists($this, $setter)) {
|
||||
$this->$setter($v);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setTitle($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function setWeightings(array $weightings)
|
||||
{
|
||||
$this->weightings = $weightings;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWeightings()
|
||||
{
|
||||
return $this->weightings;
|
||||
}
|
||||
|
||||
public function setValue($value)
|
||||
{
|
||||
$this->value = (int) $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function setIsOut($isOut)
|
||||
{
|
||||
$this->isOut = (bool) $isOut;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIsOut()
|
||||
{
|
||||
return $this->isOut;
|
||||
}
|
||||
|
||||
public function isOut()
|
||||
{
|
||||
if (func_num_args() === 0) {
|
||||
return $this->getIsOut();
|
||||
}
|
||||
|
||||
return $this->setIsOut(func_get_arg(0));
|
||||
}
|
||||
|
||||
public function addWeighting($weighting)
|
||||
{
|
||||
return $this->setValue($this->getValue() + $weighting);
|
||||
}
|
||||
|
||||
public function setInfo($info)
|
||||
{
|
||||
$this->info = $info;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getInfo($locale)
|
||||
{
|
||||
if (null === $this->info) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$file = sprintf('../app/distros/%s/%s.md', $locale, $this->info);
|
||||
|
||||
return file_exists($file) ? file_get_contents($file) : '';
|
||||
}
|
||||
}
|
108
src/Questionnaire/Model/ResultPeer.php
Normal file
108
src/Questionnaire/Model/ResultPeer.php
Normal file
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
namespace Questionnaire\Model;
|
||||
|
||||
use Questionnaire\Configuration;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class ResultPeer extends QuestionnairePeer
|
||||
{
|
||||
protected static $results = array();
|
||||
|
||||
public static function retrieveResults()
|
||||
{
|
||||
if (!empty(self::$results)) {
|
||||
return self::$results;
|
||||
}
|
||||
|
||||
$yaml = self::getYaml();
|
||||
|
||||
$questions = isset($yaml['results']) ? $yaml['results'] : array();
|
||||
$collection = [];
|
||||
|
||||
foreach ($questions as $k => $v) {
|
||||
if ($errors = self::validateYamlEnty($k, $v)) {
|
||||
throw new \RuntimeException(
|
||||
'Invalid entry for index "'.$k.'" is not valid:'.PHP_EOL.implode(PHP_EOL, $errors)
|
||||
);
|
||||
}
|
||||
|
||||
$result = new Result();
|
||||
$collection[] = $result->hydrate(array_merge(array('id' => $k), $v));
|
||||
}
|
||||
|
||||
return self::$results = $collection;
|
||||
}
|
||||
|
||||
public static function retrieveResultById($id)
|
||||
{
|
||||
if (!is_int($id)) {
|
||||
throw \InvalidArgumentException('You must provide a valid integer id.');
|
||||
}
|
||||
|
||||
foreach (self::retrieveResults() as $d) {
|
||||
if ($d->getId() === $id) {
|
||||
return $d;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static function validateYamlEnty($key, $entry)
|
||||
{
|
||||
$errors = [];
|
||||
|
||||
if (!is_int($key)) {
|
||||
$errors[] = 'The key must be a integer.';
|
||||
}
|
||||
|
||||
if (!isset($entry['title'])) {
|
||||
$errors[] = '"title" index must be defined (string).';
|
||||
} else {
|
||||
if (!is_string($entry['title'])) {
|
||||
$errors[] = '"title" index must be defined as string.';
|
||||
} else {
|
||||
if (!trim($entry['title'])) {
|
||||
$errors[] = '"title" index value can not be empty.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($entry['weightings'])) {
|
||||
$errors[] = '"weightings" index must be defined (array).';
|
||||
} else {
|
||||
if (!is_array($entry['weightings'])) {
|
||||
$errors[] = '"weightings" index must be defined as array.';
|
||||
} else {
|
||||
if (empty($entry['weightings'])) {
|
||||
$errors[] = '"weightings" index value can not be empty.';
|
||||
} else {
|
||||
foreach ($entry['weightings'] as $k => $v) {
|
||||
if (!is_int($k)) {
|
||||
$errors[] = 'Weighting with key "'.$k.'" must have an integer key.';
|
||||
}
|
||||
|
||||
if (!is_array($v)) {
|
||||
$errors[] = 'Weighting value with key "'.$k.'" must be an array.';
|
||||
} else {
|
||||
foreach ($v as $q => $p) {
|
||||
if (!is_bool($p) && !is_int($p)) {
|
||||
$errors[] = 'Weighting value with key "'.$k.'" is invalid.';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (isset($entry['info'])) {
|
||||
// if (!file_exists(sprintf('info/%s.md', $entry['info']))) {
|
||||
// $errors[] = 'Info file does not exist.';
|
||||
// }
|
||||
// }
|
||||
|
||||
return !empty($errors) ? $errors : null;
|
||||
}
|
||||
}
|
40
src/Questionnaire/Parser/Parser.php
Normal file
40
src/Questionnaire/Parser/Parser.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Questionnaire\Parser;
|
||||
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Output\StreamOutput;
|
||||
|
||||
abstract class Parser implements ParserInterface
|
||||
{
|
||||
/**
|
||||
* @var OutputInterface
|
||||
*/
|
||||
protected $output;
|
||||
|
||||
public function stream(OutputInterface $output)
|
||||
{
|
||||
$this->output = $output;
|
||||
$this->doStream();
|
||||
$this->output = null;
|
||||
}
|
||||
|
||||
public function capture()
|
||||
{
|
||||
$output = fopen('php://temp', 'w+b');
|
||||
$this->stream(new StreamOutput($output));
|
||||
rewind($output);
|
||||
$data = stream_get_contents($output);
|
||||
fclose($output);
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function save($file)
|
||||
{
|
||||
$output = fopen($file, 'wb');
|
||||
$this->stream(new StreamOutput($output));
|
||||
fclose($file);
|
||||
}
|
||||
|
||||
abstract protected function doStream();
|
||||
}
|
27
src/Questionnaire/Parser/ParserInterface.php
Normal file
27
src/Questionnaire/Parser/ParserInterface.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Questionnaire\Parser;
|
||||
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
interface ParserInterface
|
||||
{
|
||||
/**
|
||||
* Parses data into given output.
|
||||
*/
|
||||
public function stream(OutputInterface $output);
|
||||
|
||||
/**
|
||||
* Captures the stream output into a string buffer.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function capture();
|
||||
|
||||
/**
|
||||
* Writes the stream output into given file.
|
||||
*
|
||||
* @param string $file
|
||||
*/
|
||||
public function save($file);
|
||||
}
|
112
src/Questionnaire/Parser/ReadmeParser.php
Normal file
112
src/Questionnaire/Parser/ReadmeParser.php
Normal file
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
|
||||
namespace Questionnaire\Parser;
|
||||
|
||||
class ReadmeParser extends Parser
|
||||
{
|
||||
/**
|
||||
* @var \DOMDocument
|
||||
*/
|
||||
protected $doc;
|
||||
|
||||
/**
|
||||
* @var \DOMNodelist
|
||||
*/
|
||||
protected $nodes;
|
||||
|
||||
/**
|
||||
* @var \DOMNode
|
||||
*/
|
||||
protected $node;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $cur;
|
||||
|
||||
/**
|
||||
* @param \DOMDocument $doc
|
||||
*/
|
||||
public function __construct(\DOMDocument $doc)
|
||||
{
|
||||
$this->doc = $doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $html
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function load($html)
|
||||
{
|
||||
$ok = $this->doc->loadHTML($html);
|
||||
|
||||
if (!$ok) {
|
||||
throw new \RuntimeException('Unable to load given HTML content.');
|
||||
}
|
||||
|
||||
$this->nodes = $this->doc->getElementsByTagName('body')->item(0)->childNodes;
|
||||
$this->cur = 0;
|
||||
}
|
||||
|
||||
public function doStream()
|
||||
{
|
||||
$output = $this->output;
|
||||
|
||||
$output->write('<div class="panel panel-default">');
|
||||
|
||||
$this->until('h1', 'say');
|
||||
$output->write('<div class="panel-heading">');
|
||||
$this->say();
|
||||
$output->write('</div>');
|
||||
|
||||
$this->until('p', 'say');
|
||||
$output->write('<div class="panel-body">');
|
||||
$this->say();
|
||||
$output->write('{% block start %}{% endblock %}');
|
||||
$output->write('</div>');
|
||||
|
||||
$output->write('<ul class="list-group">');
|
||||
|
||||
$ok = $this->until('h2', 'say');
|
||||
|
||||
do {
|
||||
$output->write('<li class="list-group-item">');
|
||||
$this->say();
|
||||
$ok = $this->until('h2', 'say');
|
||||
$output->write('</li>');
|
||||
} while ($ok);
|
||||
|
||||
$output->write('</ul>');
|
||||
$output->writeln('</div>');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tag
|
||||
* @param string $action
|
||||
* @todo Find a way to avoid the copy/paste of `$this->node` line.
|
||||
*/
|
||||
protected function until($tag, $action = null)
|
||||
{
|
||||
$this->node = $this->nodes->item($this->cur++);
|
||||
|
||||
while ($tag !== $this->node->nodeName) {
|
||||
if (null !== $action) {
|
||||
$this->$action();
|
||||
}
|
||||
|
||||
$this->node = $this->nodes->item($this->cur++);
|
||||
}
|
||||
|
||||
return null !== $this->node;
|
||||
}
|
||||
|
||||
protected function say()
|
||||
{
|
||||
$this->output->write($this->doc->saveHTML($this->node));
|
||||
}
|
||||
|
||||
protected function sayText()
|
||||
{
|
||||
$this->output->write($this->node->textContent);
|
||||
}
|
||||
}
|
35
views/Os/index.html.twig
Normal file
35
views/Os/index.html.twig
Normal file
|
@ -0,0 +1,35 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<nav>
|
||||
<ul class="list-group">
|
||||
{% for result in results %}
|
||||
<li class="list-group-item"><a href="#{{ result.title }}">{{ result.title }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<section>
|
||||
{% if results|length == 0 %}
|
||||
<h1>No result :(</h1>
|
||||
{% else %}
|
||||
{% for result in results %}
|
||||
<article id="{{ result.title }}">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">{{ result.title }}</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{ result.info(app.request.locale)|markdown }}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
13
views/Questionnaire/base.html.twig
Normal file
13
views/Questionnaire/base.html.twig
Normal file
|
@ -0,0 +1,13 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block content %}
|
||||
<h1>
|
||||
{% block heading %}
|
||||
{{ block('main_title') }}
|
||||
{% endblock %}
|
||||
</h1>
|
||||
|
||||
{% if block('main_title')|length %}<hr>{% endif %}
|
||||
|
||||
{% block questionnaire_content %}{% endblock %}
|
||||
{% endblock %}
|
19
views/Questionnaire/index.html.twig
Normal file
19
views/Questionnaire/index.html.twig
Normal file
|
@ -0,0 +1,19 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block content %}
|
||||
{% embed 'Questionnaire/readme.' ~ app.request.locale ~ '.html.twig' %}
|
||||
{% block start %}
|
||||
<p>
|
||||
<a class="btn btn-success" href="{{ path('start') }}">
|
||||
{{ 'index.start'|trans }}
|
||||
</a>
|
||||
<a
|
||||
class="btn btn-info"
|
||||
href="https://guest:guest@svn.deblan.org/websvn/listing.php?repname=linux-questionnaire"
|
||||
>
|
||||
{{ 'index.source'|trans }}
|
||||
</a>
|
||||
</p>
|
||||
{% endblock %}
|
||||
{% endembed %}
|
||||
{% endblock %}
|
131
views/Questionnaire/readme.en.html.twig
Normal file
131
views/Questionnaire/readme.en.html.twig
Normal file
|
@ -0,0 +1,131 @@
|
|||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><h1>Linux Questionnaire</h1></div>
|
||||
|
||||
<div class="panel-body"><p>This project provides a questionnaire that determines
|
||||
the Linux distribution (or BSD system) which matches
|
||||
your preferences.</p>{% block start %}{% endblock %}</div><ul class="list-group">
|
||||
|
||||
<li class="list-group-item"><h2>Contact & Support</h2>
|
||||
|
||||
<h3>Project Management</h3>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://lab.deblan.org/client/projects/linux-questionnaire">Redmine</a></li>
|
||||
</ul>
|
||||
<h3>Repository Browsers</h3>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://lab.deblan.org/client/projects/linux-questionnaire/repository">Redmine</a></li>
|
||||
<li><a href="https://guest:guest@svn.deblan.org/websvn/listing.php?repname=linux-questionnaire">WebSVN</a></li>
|
||||
</ul>
|
||||
<h3>IRC</h3>
|
||||
|
||||
<ul>
|
||||
<li>Server: <code>ssl.neutralnetwork.org</code>
|
||||
</li>
|
||||
<li>Channel: <code>#wiki</code>
|
||||
</li>
|
||||
<li><a href="https://ssl.neutralnetwork.org/irc/?channels=%23wiki">Web client</a></li>
|
||||
</ul>
|
||||
<h3>Forum</h3>
|
||||
|
||||
<ul>
|
||||
<li><a href="http://www.jeuxvideo.com/forums/1-38-7795760-1-0-1-0-questionnaire-choix-distribution.htm">Official topic</a></li>
|
||||
</ul>
|
||||
</li><li class="list-group-item"><h2>Requirements</h2>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://www.php.net/">PHP</a> >= 5.4</li>
|
||||
<li><a href="https://subversion.apache.org/">Apache Subversion</a></li>
|
||||
<li><a href="https://getcomposer.org/">Composer</a></li>
|
||||
</ul>
|
||||
</li><li class="list-group-item"><h2>Installation</h2>
|
||||
|
||||
<pre><code>svn co https://svn.deblan.org/svn/linux-questionnaire
|
||||
cd linux-questionnaire
|
||||
make
|
||||
</code></pre>
|
||||
|
||||
</li><li class="list-group-item"><h2>Composer</h2>
|
||||
|
||||
<p>Composer can maybe be downloaded from your system's repositories.
|
||||
Else, follow the next instructions:</p>
|
||||
|
||||
<h3>Download</h3>
|
||||
|
||||
<pre><code># With cURL
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
# With Wget
|
||||
wget -O - -q https://getcomposer.org/installer | php
|
||||
</code></pre>
|
||||
|
||||
<p>You can now use it with <code>php composer.phar [arguments]</code>.</p>
|
||||
|
||||
<h3>Executable</h3>
|
||||
|
||||
<pre><code>mv composer.phar composer
|
||||
chmod +x composer
|
||||
</code></pre>
|
||||
|
||||
<p>Use it with <code>./composer [arguments]</code>.</p>
|
||||
|
||||
<h3>Install</h3>
|
||||
|
||||
<p>Assuming <code>~/bin</code> exists ans is in <code>$PATH</code>.</p>
|
||||
|
||||
<pre><code>mv composer ~/bin
|
||||
</code></pre>
|
||||
|
||||
<h3>Dependencies Installation (from <code>composer.lock</code>)</h3>
|
||||
|
||||
<pre><code>composer install
|
||||
</code></pre>
|
||||
|
||||
<h3>Dependencies Update (will change <code>composer.lock</code>)</h3>
|
||||
|
||||
<pre><code>composer update
|
||||
</code></pre>
|
||||
|
||||
</li><li class="list-group-item"><h2>Makefile</h2>
|
||||
|
||||
<p>A Makefile is provided to automate some tasks.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<code>make</code> will install application's dependencies via Composer,</li>
|
||||
<li>
|
||||
<code>make prod</code> will install dependencies without developmenent requirements
|
||||
and run <code>make optimize</code>,</li>
|
||||
<li>
|
||||
<code>make optimize</code> will run Composer's autoloader dump script with classmap
|
||||
only, without dynamic autoload rules,</li>
|
||||
<li>
|
||||
<code>make cs</code> will run PHP code sniffer with PSR-2 conventions.</li>
|
||||
</ul>
|
||||
</li><li class="list-group-item"><h2>Development Server</h2>
|
||||
|
||||
<p>Use PHP's built-in development server, for example on <code>localhost</code>, port 8080:</p>
|
||||
|
||||
<pre><code>cd web
|
||||
php -S localhost:8080
|
||||
</code></pre>
|
||||
|
||||
</li><li class="list-group-item"><h2>Homepage Update</h2>
|
||||
|
||||
<p>When the <code>README.*.md</code> files are updated, we also need to update
|
||||
the matching views in <code>web/views/Questionnaire/readme.*.html.twig</code>. To do that,
|
||||
a simple console script was created.</p>
|
||||
|
||||
<h3>Help</h3>
|
||||
|
||||
<pre><code>app/console generate:readme -h
|
||||
</code></pre>
|
||||
|
||||
<h3>Basic Generation</h3>
|
||||
|
||||
<pre><code>app/console generate:readme
|
||||
</code></pre>
|
||||
|
||||
</li></ul></div>
|
131
views/Questionnaire/readme.fr.html.twig
Normal file
131
views/Questionnaire/readme.fr.html.twig
Normal file
|
@ -0,0 +1,131 @@
|
|||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><h1>Questionnaire Linux</h1></div>
|
||||
|
||||
<div class="panel-body"><p>Ce projet consiste en un questionnaire permettant de déterminer
|
||||
la distribution Linux (ou BSD) qui vous convient le plus.</p>{% block start %}{% endblock %}</div><ul class="list-group">
|
||||
|
||||
<li class="list-group-item"><h2>Contact et support</h2>
|
||||
|
||||
<h3>Gestion de projet</h3>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://lab.deblan.org/client/projects/linux-questionnaire">Redmine</a></li>
|
||||
</ul>
|
||||
<h3>Arborescense du code</h3>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://lab.deblan.org/client/projects/linux-questionnaire/repository">Redmine</a></li>
|
||||
<li><a href="https://guest:guest@svn.deblan.org/websvn/listing.php?repname=linux-questionnaire">WebSVN</a></li>
|
||||
</ul>
|
||||
<h3>IRC</h3>
|
||||
|
||||
<ul>
|
||||
<li>Server: <code>ssl.neutralnetwork.org</code>
|
||||
</li>
|
||||
<li>Channel: <code>#wiki</code>
|
||||
</li>
|
||||
<li><a href="https://ssl.neutralnetwork.org/irc/?channels=%23wiki">Web client</a></li>
|
||||
</ul>
|
||||
<h3>Forum</h3>
|
||||
|
||||
<ul>
|
||||
<li><a href="http://www.jeuxvideo.com/forums/1-38-7795760-1-0-1-0-questionnaire-choix-distribution.htm">Official topic</a></li>
|
||||
</ul>
|
||||
</li><li class="list-group-item"><h2>Prérequis</h2>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://www.php.net/">PHP</a> >= 5.4</li>
|
||||
<li><a href="https://subversion.apache.org/">Apache Subversion</a></li>
|
||||
<li><a href="https://getcomposer.org/">Composer</a></li>
|
||||
</ul>
|
||||
</li><li class="list-group-item"><h2>Installation</h2>
|
||||
|
||||
<pre><code>svn co https://svn.deblan.org/svn/linux-questionnaire
|
||||
cd linux-questionnaire
|
||||
make
|
||||
</code></pre>
|
||||
|
||||
</li><li class="list-group-item"><h2>Composer</h2>
|
||||
|
||||
<p>Composer est peut-être téléchargeable depuis votre gestionnaire de paquets.
|
||||
Sinon, suivez les instructions suivantes :</p>
|
||||
|
||||
<h3>Téléchargement</h3>
|
||||
|
||||
<pre><code># Avec cURL
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
# Avec Wget
|
||||
wget -O - -q https://getcomposer.org/installer | php
|
||||
</code></pre>
|
||||
|
||||
<p>Vous pouvez maintenant l'utiliser avec <code>php composer.phar [arguments]</code>.</p>
|
||||
|
||||
<h3>Exécutable</h3>
|
||||
|
||||
<pre><code>mv composer.phar composer
|
||||
chmod +x composer
|
||||
</code></pre>
|
||||
|
||||
<p>S'utilise désormais avec <code>./composer [arguments]</code>.</p>
|
||||
|
||||
<h3>Installation</h3>
|
||||
|
||||
<p>En partant du principe que le dossier <code>~/bin</code> existe et est dans le <code>$PATH</code>.</p>
|
||||
|
||||
<pre><code>mv composer ~/bin
|
||||
</code></pre>
|
||||
|
||||
<h3>Installation des dépendances (depuis <code>composer.lock</code>)</h3>
|
||||
|
||||
<pre><code>composer install
|
||||
</code></pre>
|
||||
|
||||
<h3>Mise à jour des dépendances (modification de <code>composer.lock</code>)</h3>
|
||||
|
||||
<pre><code>composer update
|
||||
</code></pre>
|
||||
|
||||
</li><li class="list-group-item"><h2>Makefile</h2>
|
||||
|
||||
<p>Un Makefile est intégré pour automatiser certaines tâches.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<code>make</code> installera les dépendances de l'application avec Composer,</li>
|
||||
<li>
|
||||
<code>make prod</code> installera les dépendances à l'exception de celles nécessaires
|
||||
seulement au développement, et lancera <code>make optimize</code>,</li>
|
||||
<li>
|
||||
<code>make optimize</code> exécutera le script d'optimisation de Composer pour convertir
|
||||
les chargements dynamiques de classes en <em>classmap</em>,</li>
|
||||
<li>
|
||||
<code>make cs</code> lancera un <em>code sniffer</em> PHP avec les conventions PSR-2.</li>
|
||||
</ul>
|
||||
</li><li class="list-group-item"><h2>Serveur de développement</h2>
|
||||
|
||||
<p>Vous pouvez utiliser le serveur de développement intégré à PHP, par exemple
|
||||
sur <code>localhost</code>, port 8080 :</p>
|
||||
|
||||
<pre><code>cd web
|
||||
php -S localhost:8080
|
||||
</code></pre>
|
||||
|
||||
</li><li class="list-group-item"><h2>Mise à jour de la page d'accueil</h2>
|
||||
|
||||
<p>Quand les <code>README.*.md</code> sont modifiés, il faut aussi mettre à jour les
|
||||
vues correspondantes dans <code>web/views/Questionnaire/readme.*.html.twig</code>.
|
||||
Pour ça, un script a été créé.</p>
|
||||
|
||||
<h3>Aide</h3>
|
||||
|
||||
<pre><code>app/console generate:readme -h
|
||||
</code></pre>
|
||||
|
||||
<h3>Génération de base</h3>
|
||||
|
||||
<pre><code>app/console generate:readme
|
||||
</code></pre>
|
||||
|
||||
</li></ul></div>
|
37
views/Questionnaire/result.html.twig
Normal file
37
views/Questionnaire/result.html.twig
Normal file
|
@ -0,0 +1,37 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<nav>
|
||||
<ul class="list-group">
|
||||
{% for result in results %}
|
||||
<li class="list-group-item"><a href="#{{ result.title }}">{{ result.title }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<section>
|
||||
<h1>
|
||||
{% set count = results|length %}
|
||||
{% transchoice count with {'%count%': count} %}
|
||||
result.count
|
||||
{% endtranschoice %}
|
||||
</h1>
|
||||
{% for result in results %}
|
||||
<article id="{{ result.title }}">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">{{ result.title }}</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{ result.info(app.request.locale)|markdown }}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
61
views/Questionnaire/step.html.twig
Normal file
61
views/Questionnaire/step.html.twig
Normal file
|
@ -0,0 +1,61 @@
|
|||
{% extends 'Questionnaire/base.html.twig' %}
|
||||
|
||||
{% block title %}
|
||||
{{ question.title }}
|
||||
{{ bs }}
|
||||
{{ parent() }}
|
||||
{% endblock %}
|
||||
|
||||
{% block questionnaire_content %}
|
||||
<div class="text-right">
|
||||
{{ percent }}%
|
||||
</div>
|
||||
<div class="progress progress-striped">
|
||||
<div
|
||||
class="progress-bar progress-bar-success"
|
||||
role="progressbar"
|
||||
aria-valuenow="{{ percent }}"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100"
|
||||
style="width: {{ percent }}%"
|
||||
>
|
||||
<span class="sr-only">{{ percent }}% Complete</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form action="{{ path('step', {step: step}) }}" method="post">
|
||||
<article>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">{{ question.title|trans }}</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% for key, choice in question.choices %}
|
||||
<p>
|
||||
<input
|
||||
type="radio"
|
||||
name="response"
|
||||
{% if loop.first %}
|
||||
checked
|
||||
{% endif %}
|
||||
value="{{ key }}"
|
||||
id="response_{{ key }}"
|
||||
>
|
||||
<label for="response_{{ key }}">
|
||||
{{ choice|trans|raw }}
|
||||
</label>
|
||||
</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<p>
|
||||
{% if step > 1 %}
|
||||
<a class="btn btn-success" href="{{ path('step', {step: step - 1}) }}">{{ 'previous'|trans }}</a>
|
||||
{% endif %}
|
||||
|
||||
<button class="btn btn-success" type="submit">{{ 'next'|trans }}</button>
|
||||
</p>
|
||||
</form>
|
||||
{% endblock %}
|
76
views/base.html.twig
Normal file
76
views/base.html.twig
Normal file
|
@ -0,0 +1,76 @@
|
|||
{% extends 'layout.html.twig' %}
|
||||
|
||||
{% block main_title %}Linux Questionnaire{% endblock %}
|
||||
|
||||
{% block title %}{{ block('main_title') }}{% endblock %}
|
||||
|
||||
{% block stylesheets %}
|
||||
{% set assets = assets|default([])|merge([
|
||||
web_path ~ 'components/bootstrap/css/bootstrap.min.css',
|
||||
web_path ~ 'components/bootstrap/css/bootstrap-theme.min.css',
|
||||
web_path ~ 'assets/css/main.css',
|
||||
]) %}
|
||||
|
||||
{{ parent() }}
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
{% import _self as macros %}
|
||||
|
||||
{% macro link(url, label) %}
|
||||
<li
|
||||
{% if app.request.getPathInfo == url %}
|
||||
class="active"
|
||||
{% endif %}
|
||||
>
|
||||
<a href="{{ url }}">{{ label }}</a>
|
||||
</li>
|
||||
{% endmacro %}
|
||||
|
||||
<nav class="navbar navbar-inverse navbar-top" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-hader">
|
||||
<ul class="nav navbar-nav">
|
||||
{{ macros.link(path('homepage'), 'base.home'|trans) }}
|
||||
{{ macros.link(path('distros'), 'base.distros'|trans) }}
|
||||
{{ macros.link('http://francoisautin.free.fr/wikilinux/pmwiki.php', 'base.wiki'|trans) }}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<form role="form" class="navbar-form navbar-right">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
{{ ('locale.native.' ~ app.locale)|trans }} <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
{% for locale in app.locales %}
|
||||
{% if locale != app.locale %}
|
||||
<li>
|
||||
<a
|
||||
href="{{ path(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')|merge({_locale: locale})) }}"
|
||||
>
|
||||
{{ ('locale.native.' ~ locale)|trans }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
{% set assets = assets|default([])|merge([
|
||||
web_path ~ 'components/jquery/jquery.min.js',
|
||||
web_path ~ 'components/bootstrap/js/bootstrap.min.js',
|
||||
]) %}
|
||||
|
||||
{{ parent() }}
|
||||
{% endblock %}
|
15
views/error.html.twig
Normal file
15
views/error.html.twig
Normal file
|
@ -0,0 +1,15 @@
|
|||
{% extends 'layout.html.twig' %}
|
||||
|
||||
{% block title %}
|
||||
Error {{ code }} - {{ name }}
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>{{ name }}</h1>
|
||||
|
||||
<p><em>In file "{{ exception.file }}" at line {{ exception.line }}</em></p>
|
||||
<p>{{ exception.message }}</p>
|
||||
|
||||
<h2>Stacktrace</h2>
|
||||
<pre>{{ exception.traceAsString }}</pre>
|
||||
{% endblock %}
|
20
views/layout.html.twig
Normal file
20
views/layout.html.twig
Normal file
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
{% block stylesheets %}
|
||||
{% for asset in assets %}
|
||||
<link href="{{ asset }}" rel="stylesheet">
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
{% block body %}{% endblock %}
|
||||
{% block javascripts %}
|
||||
{% for asset in assets %}
|
||||
<script src="{{ asset }}"></script>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
14
web/.htaccess
Normal file
14
web/.htaccess
Normal file
|
@ -0,0 +1,14 @@
|
|||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
|
||||
RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
|
||||
RewriteRule ^(.*) - [E=BASE:%1]
|
||||
|
||||
RewriteCond %{ENV:REDIRECT_STATUS} ^$
|
||||
RewriteRule ^index\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L]
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} -f
|
||||
RewriteRule .? - [L]
|
||||
|
||||
RewriteRule .? %{ENV:BASE}/index.php [L]
|
||||
</IfModule>
|
13
web/assets/css/main.css
Normal file
13
web/assets/css/main.css
Normal file
|
@ -0,0 +1,13 @@
|
|||
.navbar-top {
|
||||
border-radius: 0;
|
||||
border-width: 0 0 1px;
|
||||
}
|
||||
|
||||
.panel h2 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.panel h3 {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
BIN
web/assets/img/10-lxde.png
Normal file
BIN
web/assets/img/10-lxde.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
BIN
web/assets/img/10-osx.png
Normal file
BIN
web/assets/img/10-osx.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
BIN
web/assets/img/10-tty.png
Normal file
BIN
web/assets/img/10-tty.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
1
web/components/bootstrap
Symbolic link
1
web/components/bootstrap
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../vendor/twbs/bootstrap/dist
|
10337
web/components/jquery/jquery-built.js
vendored
Normal file
10337
web/components/jquery/jquery-built.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
511
web/components/jquery/jquery-migrate.js
vendored
Normal file
511
web/components/jquery/jquery-migrate.js
vendored
Normal file
|
@ -0,0 +1,511 @@
|
|||
/*!
|
||||
* jQuery Migrate - v1.1.1 - 2013-02-16
|
||||
* https://github.com/jquery/jquery-migrate
|
||||
* Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT
|
||||
*/
|
||||
(function( jQuery, window, undefined ) {
|
||||
// See http://bugs.jquery.com/ticket/13335
|
||||
// "use strict";
|
||||
|
||||
|
||||
var warnedAbout = {};
|
||||
|
||||
// List of warnings already given; public read only
|
||||
jQuery.migrateWarnings = [];
|
||||
|
||||
// Set to true to prevent console output; migrateWarnings still maintained
|
||||
// jQuery.migrateMute = false;
|
||||
|
||||
// Show a message on the console so devs know we're active
|
||||
if ( !jQuery.migrateMute && window.console && console.log ) {
|
||||
console.log("JQMIGRATE: Logging is active");
|
||||
}
|
||||
|
||||
// Set to false to disable traces that appear with warnings
|
||||
if ( jQuery.migrateTrace === undefined ) {
|
||||
jQuery.migrateTrace = true;
|
||||
}
|
||||
|
||||
// Forget any warnings we've already given; public
|
||||
jQuery.migrateReset = function() {
|
||||
warnedAbout = {};
|
||||
jQuery.migrateWarnings.length = 0;
|
||||
};
|
||||
|
||||
function migrateWarn( msg) {
|
||||
if ( !warnedAbout[ msg ] ) {
|
||||
warnedAbout[ msg ] = true;
|
||||
jQuery.migrateWarnings.push( msg );
|
||||
if ( window.console && console.warn && !jQuery.migrateMute ) {
|
||||
console.warn( "JQMIGRATE: " + msg );
|
||||
if ( jQuery.migrateTrace && console.trace ) {
|
||||
console.trace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function migrateWarnProp( obj, prop, value, msg ) {
|
||||
if ( Object.defineProperty ) {
|
||||
// On ES5 browsers (non-oldIE), warn if the code tries to get prop;
|
||||
// allow property to be overwritten in case some other plugin wants it
|
||||
try {
|
||||
Object.defineProperty( obj, prop, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
migrateWarn( msg );
|
||||
return value;
|
||||
},
|
||||
set: function( newValue ) {
|
||||
migrateWarn( msg );
|
||||
value = newValue;
|
||||
}
|
||||
});
|
||||
return;
|
||||
} catch( err ) {
|
||||
// IE8 is a dope about Object.defineProperty, can't warn there
|
||||
}
|
||||
}
|
||||
|
||||
// Non-ES5 (or broken) browser; just set the property
|
||||
jQuery._definePropertyBroken = true;
|
||||
obj[ prop ] = value;
|
||||
}
|
||||
|
||||
if ( document.compatMode === "BackCompat" ) {
|
||||
// jQuery has never supported or tested Quirks Mode
|
||||
migrateWarn( "jQuery is not compatible with Quirks Mode" );
|
||||
}
|
||||
|
||||
|
||||
var attrFn = jQuery( "<input/>", { size: 1 } ).attr("size") && jQuery.attrFn,
|
||||
oldAttr = jQuery.attr,
|
||||
valueAttrGet = jQuery.attrHooks.value && jQuery.attrHooks.value.get ||
|
||||
function() { return null; },
|
||||
valueAttrSet = jQuery.attrHooks.value && jQuery.attrHooks.value.set ||
|
||||
function() { return undefined; },
|
||||
rnoType = /^(?:input|button)$/i,
|
||||
rnoAttrNodeType = /^[238]$/,
|
||||
rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
|
||||
ruseDefault = /^(?:checked|selected)$/i;
|
||||
|
||||
// jQuery.attrFn
|
||||
migrateWarnProp( jQuery, "attrFn", attrFn || {}, "jQuery.attrFn is deprecated" );
|
||||
|
||||
jQuery.attr = function( elem, name, value, pass ) {
|
||||
var lowerName = name.toLowerCase(),
|
||||
nType = elem && elem.nodeType;
|
||||
|
||||
if ( pass ) {
|
||||
// Since pass is used internally, we only warn for new jQuery
|
||||
// versions where there isn't a pass arg in the formal params
|
||||
if ( oldAttr.length < 4 ) {
|
||||
migrateWarn("jQuery.fn.attr( props, pass ) is deprecated");
|
||||
}
|
||||
if ( elem && !rnoAttrNodeType.test( nType ) &&
|
||||
(attrFn ? name in attrFn : jQuery.isFunction(jQuery.fn[name])) ) {
|
||||
return jQuery( elem )[ name ]( value );
|
||||
}
|
||||
}
|
||||
|
||||
// Warn if user tries to set `type`, since it breaks on IE 6/7/8; by checking
|
||||
// for disconnected elements we don't warn on $( "<button>", { type: "button" } ).
|
||||
if ( name === "type" && value !== undefined && rnoType.test( elem.nodeName ) && elem.parentNode ) {
|
||||
migrateWarn("Can't change the 'type' of an input or button in IE 6/7/8");
|
||||
}
|
||||
|
||||
// Restore boolHook for boolean property/attribute synchronization
|
||||
if ( !jQuery.attrHooks[ lowerName ] && rboolean.test( lowerName ) ) {
|
||||
jQuery.attrHooks[ lowerName ] = {
|
||||
get: function( elem, name ) {
|
||||
// Align boolean attributes with corresponding properties
|
||||
// Fall back to attribute presence where some booleans are not supported
|
||||
var attrNode,
|
||||
property = jQuery.prop( elem, name );
|
||||
return property === true || typeof property !== "boolean" &&
|
||||
( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
|
||||
|
||||
name.toLowerCase() :
|
||||
undefined;
|
||||
},
|
||||
set: function( elem, value, name ) {
|
||||
var propName;
|
||||
if ( value === false ) {
|
||||
// Remove boolean attributes when set to false
|
||||
jQuery.removeAttr( elem, name );
|
||||
} else {
|
||||
// value is true since we know at this point it's type boolean and not false
|
||||
// Set boolean attributes to the same name and set the DOM property
|
||||
propName = jQuery.propFix[ name ] || name;
|
||||
if ( propName in elem ) {
|
||||
// Only set the IDL specifically if it already exists on the element
|
||||
elem[ propName ] = true;
|
||||
}
|
||||
|
||||
elem.setAttribute( name, name.toLowerCase() );
|
||||
}
|
||||
return name;
|
||||
}
|
||||
};
|
||||
|
||||
// Warn only for attributes that can remain distinct from their properties post-1.9
|
||||
if ( ruseDefault.test( lowerName ) ) {
|
||||
migrateWarn( "jQuery.fn.attr('" + lowerName + "') may use property instead of attribute" );
|
||||
}
|
||||
}
|
||||
|
||||
return oldAttr.call( jQuery, elem, name, value );
|
||||
};
|
||||
|
||||
// attrHooks: value
|
||||
jQuery.attrHooks.value = {
|
||||
get: function( elem, name ) {
|
||||
var nodeName = ( elem.nodeName || "" ).toLowerCase();
|
||||
if ( nodeName === "button" ) {
|
||||
return valueAttrGet.apply( this, arguments );
|
||||
}
|
||||
if ( nodeName !== "input" && nodeName !== "option" ) {
|
||||
migrateWarn("jQuery.fn.attr('value') no longer gets properties");
|
||||
}
|
||||
return name in elem ?
|
||||
elem.value :
|
||||
null;
|
||||
},
|
||||
set: function( elem, value ) {
|
||||
var nodeName = ( elem.nodeName || "" ).toLowerCase();
|
||||
if ( nodeName === "button" ) {
|
||||
return valueAttrSet.apply( this, arguments );
|
||||
}
|
||||
if ( nodeName !== "input" && nodeName !== "option" ) {
|
||||
migrateWarn("jQuery.fn.attr('value', val) no longer sets properties");
|
||||
}
|
||||
// Does not return so that setAttribute is also used
|
||||
elem.value = value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var matched, browser,
|
||||
oldInit = jQuery.fn.init,
|
||||
oldParseJSON = jQuery.parseJSON,
|
||||
// Note this does NOT include the #9521 XSS fix from 1.7!
|
||||
rquickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*|#([\w\-]*))$/;
|
||||
|
||||
// $(html) "looks like html" rule change
|
||||
jQuery.fn.init = function( selector, context, rootjQuery ) {
|
||||
var match;
|
||||
|
||||
if ( selector && typeof selector === "string" && !jQuery.isPlainObject( context ) &&
|
||||
(match = rquickExpr.exec( selector )) && match[1] ) {
|
||||
// This is an HTML string according to the "old" rules; is it still?
|
||||
if ( selector.charAt( 0 ) !== "<" ) {
|
||||
migrateWarn("$(html) HTML strings must start with '<' character");
|
||||
}
|
||||
// Now process using loose rules; let pre-1.8 play too
|
||||
if ( context && context.context ) {
|
||||
// jQuery object as context; parseHTML expects a DOM object
|
||||
context = context.context;
|
||||
}
|
||||
if ( jQuery.parseHTML ) {
|
||||
return oldInit.call( this, jQuery.parseHTML( jQuery.trim(selector), context, true ),
|
||||
context, rootjQuery );
|
||||
}
|
||||
}
|
||||
return oldInit.apply( this, arguments );
|
||||
};
|
||||
jQuery.fn.init.prototype = jQuery.fn;
|
||||
|
||||
// Let $.parseJSON(falsy_value) return null
|
||||
jQuery.parseJSON = function( json ) {
|
||||
if ( !json && json !== null ) {
|
||||
migrateWarn("jQuery.parseJSON requires a valid JSON string");
|
||||
return null;
|
||||
}
|
||||
return oldParseJSON.apply( this, arguments );
|
||||
};
|
||||
|
||||
jQuery.uaMatch = function( ua ) {
|
||||
ua = ua.toLowerCase();
|
||||
|
||||
var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
|
||||
/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
|
||||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
|
||||
/(msie) ([\w.]+)/.exec( ua ) ||
|
||||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
|
||||
[];
|
||||
|
||||
return {
|
||||
browser: match[ 1 ] || "",
|
||||
version: match[ 2 ] || "0"
|
||||
};
|
||||
};
|
||||
|
||||
// Don't clobber any existing jQuery.browser in case it's different
|
||||
if ( !jQuery.browser ) {
|
||||
matched = jQuery.uaMatch( navigator.userAgent );
|
||||
browser = {};
|
||||
|
||||
if ( matched.browser ) {
|
||||
browser[ matched.browser ] = true;
|
||||
browser.version = matched.version;
|
||||
}
|
||||
|
||||
// Chrome is Webkit, but Webkit is also Safari.
|
||||
if ( browser.chrome ) {
|
||||
browser.webkit = true;
|
||||
} else if ( browser.webkit ) {
|
||||
browser.safari = true;
|
||||
}
|
||||
|
||||
jQuery.browser = browser;
|
||||
}
|
||||
|
||||
// Warn if the code tries to get jQuery.browser
|
||||
migrateWarnProp( jQuery, "browser", jQuery.browser, "jQuery.browser is deprecated" );
|
||||
|
||||
jQuery.sub = function() {
|
||||
function jQuerySub( selector, context ) {
|
||||
return new jQuerySub.fn.init( selector, context );
|
||||
}
|
||||
jQuery.extend( true, jQuerySub, this );
|
||||
jQuerySub.superclass = this;
|
||||
jQuerySub.fn = jQuerySub.prototype = this();
|
||||
jQuerySub.fn.constructor = jQuerySub;
|
||||
jQuerySub.sub = this.sub;
|
||||
jQuerySub.fn.init = function init( selector, context ) {
|
||||
if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
|
||||
context = jQuerySub( context );
|
||||
}
|
||||
|
||||
return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
|
||||
};
|
||||
jQuerySub.fn.init.prototype = jQuerySub.fn;
|
||||
var rootjQuerySub = jQuerySub(document);
|
||||
migrateWarn( "jQuery.sub() is deprecated" );
|
||||
return jQuerySub;
|
||||
};
|
||||
|
||||
|
||||
// Ensure that $.ajax gets the new parseJSON defined in core.js
|
||||
jQuery.ajaxSetup({
|
||||
converters: {
|
||||
"text json": jQuery.parseJSON
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var oldFnData = jQuery.fn.data;
|
||||
|
||||
jQuery.fn.data = function( name ) {
|
||||
var ret, evt,
|
||||
elem = this[0];
|
||||
|
||||
// Handles 1.7 which has this behavior and 1.8 which doesn't
|
||||
if ( elem && name === "events" && arguments.length === 1 ) {
|
||||
ret = jQuery.data( elem, name );
|
||||
evt = jQuery._data( elem, name );
|
||||
if ( ( ret === undefined || ret === evt ) && evt !== undefined ) {
|
||||
migrateWarn("Use of jQuery.fn.data('events') is deprecated");
|
||||
return evt;
|
||||
}
|
||||
}
|
||||
return oldFnData.apply( this, arguments );
|
||||
};
|
||||
|
||||
|
||||
var rscriptType = /\/(java|ecma)script/i,
|
||||
oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack;
|
||||
|
||||
jQuery.fn.andSelf = function() {
|
||||
migrateWarn("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()");
|
||||
return oldSelf.apply( this, arguments );
|
||||
};
|
||||
|
||||
// Since jQuery.clean is used internally on older versions, we only shim if it's missing
|
||||
if ( !jQuery.clean ) {
|
||||
jQuery.clean = function( elems, context, fragment, scripts ) {
|
||||
// Set context per 1.8 logic
|
||||
context = context || document;
|
||||
context = !context.nodeType && context[0] || context;
|
||||
context = context.ownerDocument || context;
|
||||
|
||||
migrateWarn("jQuery.clean() is deprecated");
|
||||
|
||||
var i, elem, handleScript, jsTags,
|
||||
ret = [];
|
||||
|
||||
jQuery.merge( ret, jQuery.buildFragment( elems, context ).childNodes );
|
||||
|
||||
// Complex logic lifted directly from jQuery 1.8
|
||||
if ( fragment ) {
|
||||
// Special handling of each script element
|
||||
handleScript = function( elem ) {
|
||||
// Check if we consider it executable
|
||||
if ( !elem.type || rscriptType.test( elem.type ) ) {
|
||||
// Detach the script and store it in the scripts array (if provided) or the fragment
|
||||
// Return truthy to indicate that it has been handled
|
||||
return scripts ?
|
||||
scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
|
||||
fragment.appendChild( elem );
|
||||
}
|
||||
};
|
||||
|
||||
for ( i = 0; (elem = ret[i]) != null; i++ ) {
|
||||
// Check if we're done after handling an executable script
|
||||
if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
|
||||
// Append to fragment and handle embedded scripts
|
||||
fragment.appendChild( elem );
|
||||
if ( typeof elem.getElementsByTagName !== "undefined" ) {
|
||||
// handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
|
||||
jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
|
||||
|
||||
// Splice the scripts into ret after their former ancestor and advance our index beyond them
|
||||
ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
|
||||
i += jsTags.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
|
||||
var eventAdd = jQuery.event.add,
|
||||
eventRemove = jQuery.event.remove,
|
||||
eventTrigger = jQuery.event.trigger,
|
||||
oldToggle = jQuery.fn.toggle,
|
||||
oldLive = jQuery.fn.live,
|
||||
oldDie = jQuery.fn.die,
|
||||
ajaxEvents = "ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",
|
||||
rajaxEvent = new RegExp( "\\b(?:" + ajaxEvents + ")\\b" ),
|
||||
rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
|
||||
hoverHack = function( events ) {
|
||||
if ( typeof( events ) !== "string" || jQuery.event.special.hover ) {
|
||||
return events;
|
||||
}
|
||||
if ( rhoverHack.test( events ) ) {
|
||||
migrateWarn("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'");
|
||||
}
|
||||
return events && events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
|
||||
};
|
||||
|
||||
// Event props removed in 1.9, put them back if needed; no practical way to warn them
|
||||
if ( jQuery.event.props && jQuery.event.props[ 0 ] !== "attrChange" ) {
|
||||
jQuery.event.props.unshift( "attrChange", "attrName", "relatedNode", "srcElement" );
|
||||
}
|
||||
|
||||
// Undocumented jQuery.event.handle was "deprecated" in jQuery 1.7
|
||||
if ( jQuery.event.dispatch ) {
|
||||
migrateWarnProp( jQuery.event, "handle", jQuery.event.dispatch, "jQuery.event.handle is undocumented and deprecated" );
|
||||
}
|
||||
|
||||
// Support for 'hover' pseudo-event and ajax event warnings
|
||||
jQuery.event.add = function( elem, types, handler, data, selector ){
|
||||
if ( elem !== document && rajaxEvent.test( types ) ) {
|
||||
migrateWarn( "AJAX events should be attached to document: " + types );
|
||||
}
|
||||
eventAdd.call( this, elem, hoverHack( types || "" ), handler, data, selector );
|
||||
};
|
||||
jQuery.event.remove = function( elem, types, handler, selector, mappedTypes ){
|
||||
eventRemove.call( this, elem, hoverHack( types ) || "", handler, selector, mappedTypes );
|
||||
};
|
||||
|
||||
jQuery.fn.error = function() {
|
||||
var args = Array.prototype.slice.call( arguments, 0);
|
||||
migrateWarn("jQuery.fn.error() is deprecated");
|
||||
args.splice( 0, 0, "error" );
|
||||
if ( arguments.length ) {
|
||||
return this.bind.apply( this, args );
|
||||
}
|
||||
// error event should not bubble to window, although it does pre-1.7
|
||||
this.triggerHandler.apply( this, args );
|
||||
return this;
|
||||
};
|
||||
|
||||
jQuery.fn.toggle = function( fn, fn2 ) {
|
||||
|
||||
// Don't mess with animation or css toggles
|
||||
if ( !jQuery.isFunction( fn ) || !jQuery.isFunction( fn2 ) ) {
|
||||
return oldToggle.apply( this, arguments );
|
||||
}
|
||||
migrateWarn("jQuery.fn.toggle(handler, handler...) is deprecated");
|
||||
|
||||
// Save reference to arguments for access in closure
|
||||
var args = arguments,
|
||||
guid = fn.guid || jQuery.guid++,
|
||||
i = 0,
|
||||
toggler = function( event ) {
|
||||
// Figure out which function to execute
|
||||
var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
|
||||
jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
|
||||
|
||||
// Make sure that clicks stop
|
||||
event.preventDefault();
|
||||
|
||||
// and execute the function
|
||||
return args[ lastToggle ].apply( this, arguments ) || false;
|
||||
};
|
||||
|
||||
// link all the functions, so any of them can unbind this click handler
|
||||
toggler.guid = guid;
|
||||
while ( i < args.length ) {
|
||||
args[ i++ ].guid = guid;
|
||||
}
|
||||
|
||||
return this.click( toggler );
|
||||
};
|
||||
|
||||
jQuery.fn.live = function( types, data, fn ) {
|
||||
migrateWarn("jQuery.fn.live() is deprecated");
|
||||
if ( oldLive ) {
|
||||
return oldLive.apply( this, arguments );
|
||||
}
|
||||
jQuery( this.context ).on( types, this.selector, data, fn );
|
||||
return this;
|
||||
};
|
||||
|
||||
jQuery.fn.die = function( types, fn ) {
|
||||
migrateWarn("jQuery.fn.die() is deprecated");
|
||||
if ( oldDie ) {
|
||||
return oldDie.apply( this, arguments );
|
||||
}
|
||||
jQuery( this.context ).off( types, this.selector || "**", fn );
|
||||
return this;
|
||||
};
|
||||
|
||||
// Turn global events into document-triggered events
|
||||
jQuery.event.trigger = function( event, data, elem, onlyHandlers ){
|
||||
if ( !elem && !rajaxEvent.test( event ) ) {
|
||||
migrateWarn( "Global events are undocumented and deprecated" );
|
||||
}
|
||||
return eventTrigger.call( this, event, data, elem || document, onlyHandlers );
|
||||
};
|
||||
jQuery.each( ajaxEvents.split("|"),
|
||||
function( _, name ) {
|
||||
jQuery.event.special[ name ] = {
|
||||
setup: function() {
|
||||
var elem = this;
|
||||
|
||||
// The document needs no shimming; must be !== for oldIE
|
||||
if ( elem !== document ) {
|
||||
jQuery.event.add( document, name + "." + jQuery.guid, function() {
|
||||
jQuery.event.trigger( name, null, elem, true );
|
||||
});
|
||||
jQuery._data( this, name, jQuery.guid++ );
|
||||
}
|
||||
return false;
|
||||
},
|
||||
teardown: function() {
|
||||
if ( this !== document ) {
|
||||
jQuery.event.remove( document, name + "." + jQuery._data( this, name ) );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
})( jQuery, window );
|
3
web/components/jquery/jquery-migrate.min.js
vendored
Normal file
3
web/components/jquery/jquery-migrate.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
10337
web/components/jquery/jquery.js
vendored
Normal file
10337
web/components/jquery/jquery.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
4
web/components/jquery/jquery.min.js
vendored
Normal file
4
web/components/jquery/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
12376
web/components/require-built.js
Normal file
12376
web/components/require-built.js
Normal file
File diff suppressed because it is too large
Load diff
17
web/components/require.config.js
Normal file
17
web/components/require.config.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
var components = {
|
||||
"packages": [
|
||||
{
|
||||
"name": "jquery",
|
||||
"main": "jquery-built.js"
|
||||
}
|
||||
],
|
||||
"baseUrl": "components"
|
||||
};
|
||||
if (typeof require !== "undefined" && require.config) {
|
||||
require.config(components);
|
||||
} else {
|
||||
var require = components;
|
||||
}
|
||||
if (typeof exports !== "undefined" && typeof module !== "undefined") {
|
||||
module.exports = components;
|
||||
}
|
0
web/components/require.css
Normal file
0
web/components/require.css
Normal file
2036
web/components/require.js
Normal file
2036
web/components/require.js
Normal file
File diff suppressed because it is too large
Load diff
5
web/index.php
Normal file
5
web/index.php
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
$app = require __DIR__.'/../app/bootstrap.php';
|
||||
|
||||
$app->run();
|
Loading…
Reference in a new issue