Compare commits

..

No commits in common. "5adc180307264f56fd23701a81e4d1d150ed0da3" and "00534c42f0eef51bf4548aacc70f9bc206ef6120" have entirely different histories.

209 changed files with 1181 additions and 5467 deletions

View File

@ -1 +0,0 @@
.git*

View File

@ -1 +0,0 @@
DOCKER_SERVICE_80_TAGS=urlprefix-zeg1jeux.${APP_DOMAIN}

3
.gitignore vendored
View File

@ -1,5 +1,2 @@
.env
cache/
tests/
minelife.html
vendors/keygen/__pycache__

View File

@ -1,7 +0,0 @@
MYOS ?= ../myos
MYOS_REPOSITORY ?= https://github.com/aynicos/myos
-include $(MYOS)/make/include.mk
$(MYOS):
-@git clone $(MYOS_REPOSITORY) $(MYOS)
ENV_VARS += DOCKER_INTERNAL_DOCKER_HOST

View File

@ -10,6 +10,3 @@ sudo apt install python3-gpg python3-jwcrypto
python3 -m pip install -U pgpy pynentry SecureBytes
```
```
sudo vendor/jaklis/setup.sh
```

View File

@ -8,7 +8,7 @@ error_reporting(E_ALL);
session_start();
define('DEFAULT_SEARCH_RADIUS', 50);
define('DEFAULT_RADIUS', 50);
define('TAILLE_SPRITE', 32);
define('DEMI_TAILLE_SPRITE', (TAILLE_SPRITE/2));
@ -18,8 +18,6 @@ define('SONAR_DURATION', 5);
define("LAT_ASTROPORT_ONE", 44.22484418236386);
define("LON_ASTROPORT_ONE", 1.6395813014177014);
define('MAX_NEARBY_PLACES', 15);
class Player {
private $pubkey;
@ -56,6 +54,12 @@ $players = [
new Player('8PTThXiUSwwuPoqQWw3tuAn4MpvzQzpKhs6LMuiozS7Z', 'kimamila')
];
if (!isset($_SESSION['radius'])) {
$_SESSION['radius'] = DEFAULT_RADIUS;
}
/*
=====================
@ -81,7 +85,7 @@ $games = [
]
];
$radiuses = [5, 10, 20, 50, 100];
$radiuses = [5, 10, 20, 50];
define('DEFAULT_GAME', 'spationaute');
@ -89,16 +93,11 @@ if (!isset($_SESSION['gameId'])) {
$_SESSION['gameId'] = DEFAULT_GAME;
}
define('GAME_JS_DIR', 'themes/'. $_SESSION['gameId'] . '/js/map');
define('DEFAULT_WEBPAGE_TITLE', 'La bureautique');
$javascripts = [
'header' => [],
'footer' => []
];
require_once('functions.php');

View File

@ -1,98 +0,0 @@
FROM seblucas/alpine-nginx-php as dist
LABEL maintainer aynic.os <support+docker@asycn.io>
ARG DOCKER_BUILD_DIR
ARG DOCKER_MACHINE=x86_64
ARG DOCKER_SYSTEM=Linux
RUN apk upgrade --no-cache \
&& apk add --no-cache \
bash \
ca-certificates \
gettext \
libc6-compat \
libsodium \
make \
py3-gpgme \
py3-pip
ARG IPFS_VERSION=0.16.0
RUN { OS="$(echo ${DOCKER_SYSTEM} |awk '{print tolower($0)}')"; \
ARCH="$(echo ${DOCKER_MACHINE})"; \
wget -qO - https://github.com/koalaman/shellcheck/releases/download/stable/shellcheck-stable.${OS}.${ARCH}.tar.xz \
|tar --strip-components 1 -C /usr/local/bin -xJf - shellcheck-stable/shellcheck; } \
&& { ARCH="$(echo ${DOCKER_MACHINE} |awk '/x86_64/ {print "amd64"}; /aarch64/ {print "arm64"}')"; \
wget -qO - https://github.com/ipfs/kubo/releases/download/v${IPFS_VERSION}/kubo_v${IPFS_VERSION}_${OS}-${ARCH}.tar.gz \
|tar --strip-components 1 -C /usr/local/bin -xzf - kubo/ipfs; } \
&& mkdir -p /usr/local/lib/shellspec \
&& wget -qO - https://github.com/shellspec/shellspec/archive/refs/heads/master.tar.gz \
|tar --strip-components 1 -C /usr/local/lib/shellspec -xzf - \
&& ln -s /usr/local/lib/shellspec/shellspec /usr/local/bin/shellspec
RUN apk add --no-cache --virtual .build-deps \
build-base \
cargo \
libffi-dev \
openssl-dev \
py3-wheel \
python3-dev \
swig \
&& mkdir -p /usr/local/src/jaklis \
&& wget -qO - https://github.com/aynicos/jaklis/archive/master.tar.gz \
|tar --strip-components 1 -C /usr/local/src/jaklis -xzf - \
&& pip3 install -r /usr/local/src/jaklis/requirements.txt \
&& ln -s /usr/local/src/jaklis/jaklis.py /usr/local/bin/jaklis \
&& chmod 0755 /usr/local/bin/jaklis \
&& /usr/local/bin/jaklis --help >/dev/null \
&& mkdir -p /usr/local/src/dpgpid \
&& wget -qO - https://github.com/aynicos/dpgpid/archive/wip.tar.gz \
|tar --strip-components 1 -C /usr/local/src/dpgpid -xzf - \
&& pip3 install -r /usr/local/src/dpgpid/requirements.txt \
&& ln -s /usr/local/src/dpgpid/keygen /usr/local/bin/keygen \
&& chmod 0755 /usr/local/bin/keygen \
&& /usr/local/bin/keygen --help >/dev/null \
&& rm -rf /root/.cache \
&& apk del --no-network .build-deps \
&& find ./lib -type f -executable -exec scanelf --needed --nobanner --format '%n#p' '{}' ';' \
|tr ',' '\n' \
|sort -u \
|awk 'system("[ -e /lib/"$1" -o -e /usr/lib/"$1" -o -e ./lib/python'"${PYTHON_RELEASE}"'/site-packages/*/"$1" ]") == 0 { next } { print "so:" $1 }' \
|xargs -rt apk add --no-cache
RUN sed -i 's/^}/ location \/ { index index.php; }\n}/' /etc/nginx/http.d/default.conf
FROM dist as master
ARG DOCKER_BUILD_DIR
ARG DOCKER_GID
ARG SHELL=/bin/bash
ARG UID
ARG USER
ENV UID=${UID}
ENV GID=${UID}
ENV USER=nginx
# If we provide a numeric UID
RUN [ "$UID" -eq "$UID" ] 2>/dev/null \
# Remove user with $UID if it is not our $USER
&& if [ "$(getent passwd $UID |awk -F: '{print $1}')" != "$USER" ]; then \
sed -i '/^'$(getent passwd $UID |awk -F: '{print $1}')':x:'$UID':/d' /etc/passwd; \
sed -i '/^'$(getent group $GID |awk -F: '{print $1}')':x:'$GID':/d' /etc/group; \
fi \
# Force $UID if our $USER already exists
&& sed -i 's/^'$USER':x:[0-9]\+:[0-9]\+:/'$USER':x:'$UID':'$GID':/' /etc/passwd \
&& sed -i 's/^'$USER':x:[0-9]\+:/'$USER':x:'$GID':/' /etc/group \
# Create $USER if it does not exist
&& if [ "$(getent passwd $UID)" = "" ]; then \
echo "$USER:x:$UID:$GID::/home/$USER:$SHELL" >> /etc/passwd; \
echo "$USER:\!:$(($(date +%s) / 60 / 60 / 24)):0:99999:7:::" >> /etc/shadow; \
echo "$USER:x:$GID:" >> /etc/group; \
fi \
&& mkdir -p /home/$USER \
&& chown $UID:$GID /home/$USER \
|| true
ENV SHELL=${SHELL}
WORKDIR /var/www
RUN rm /etc/php7/conf.d/00_opcache.ini
RUN sed -i 's/^;php_flag[display_errors] = off/php_flag[display_errors] = on/' /etc/php7/php-fpm.d/www.conf

View File

@ -1,25 +0,0 @@
version: '3.6'
services:
docker:
environment:
- ENV=${ENV}
- SHELL=${DOCKER_SHELL}
labels:
- SERVICE_80_CHECK_HTTP=/
- SERVICE_80_NAME=${COMPOSE_SERVICE_NAME}-docker-80
- SERVICE_80_TAGS=${DOCKER_SERVICE_80_TAGS}
networks:
- private
- public
extra_hosts:
- astroport.localhost:${DOCKER_INTERNAL_DOCKER_HOST}
networks:
private:
external: true
name: ${DOCKER_NETWORK_PRIVATE}
public:
external: true
name: ${DOCKER_NETWORK_PUBLIC}

View File

@ -1,34 +0,0 @@
version: '3.6'
services:
docker:
build:
args:
- DOCKER_BUILD_DIR=docker
- GID=${GID}
- IPFS_VERSION=${IPFS_VERSION:-0.16.0}
- UID=${UID}
- USER=${USER}
context: ../
dockerfile: docker/Dockerfile
ports:
- 80
restart: always
volumes:
- ipfs:${HOME}/.ipfs:cached,ro
- data:/var/www:delegated
working_dir: /var/www
volumes:
ipfs:
driver: local
driver_opts:
type: none
device: ${HOME}/.ipfs
o: bind
data:
driver: local
driver_opts:
type: none
device: ${APP_DIR:-.}
o: bind

View File

@ -1,30 +0,0 @@
<?php
require_once('config.php');
require_once('lib/Gchange.class.php');
$gchange = new Gchange();
$javascripts['header'][] = 'lib/js/farfetched.js';
$bodyIds = 'farfetched';
include_once('header.php');
?>
<section id="shippable">
<h2>Envoi possible</h2>
<ul id="shippable-offers" class="offers-list">
</ul>
</section>
<section id="immaterial">
<h2>Offres immatérielles</h2>
<ul id="immaterial-offers" class="offers-list">
</ul>
</section>
<?php
include_once('footer.php');

View File

@ -5,28 +5,22 @@
</footer>
<?php
if (isset($_SESSION['gameId']) and isset($bodyIds) and strpos($bodyIds, 'startpage') === false) {
// if (isset($_SESSION['gameId']) and ((isset($bodyIds) and strpos($bodyIds, 'startpage') === false)) or (!isset($bodyIds))) {
$themeJSDir = 'themes/'. $_SESSION['gameId'] . '/js';
$files = scandir($themeJSDir);
$files = array_slice($files, 2);
// $themeJSDir = 'themes/'. $_SESSION['gameId'] . '/js';
// $files = scandir($themeJSDir);
// $files = array_slice($files, 2);
foreach ($files as $f) {
// foreach ($files as $f) {
// echo '
// <script type="text/javascript" src="'. $themeJSDir . '/' . $f .'"></script>
// ';
// }
// }
foreach ($javascripts['footer'] as $js) {
echo '
<script src="'. $js . '"></script>
';
echo '
<script type="text/javascript" src="'. $themeJSDir . '/' . $f .'"></script>
';
}
}
?>
<script type="text/javascript" src="assets/js/places.js"></script>
</body>
</html>

View File

@ -8,7 +8,7 @@ $webpageTitle = isset($webpageTitle) ? $webpageTitle : DEFAULT_WEBPAGE_TITLE;
<title><?php echo $webpageTitle; ?></title>
<?php
if (isset($_SESSION['gameId']) and ((isset($bodyIds) and strpos($bodyIds, 'startpage') === false)) or (!isset($bodyIds))) {
if (isset($_SESSION['gameId']) and isset($bodyIds) and strpos($bodyIds, 'startpage') === false) {
$themeCSSDir = 'themes/'. $_SESSION['gameId'] . '/css';
$files = scandir($themeCSSDir);
@ -26,15 +26,6 @@ $webpageTitle = isset($webpageTitle) ? $webpageTitle : DEFAULT_WEBPAGE_TITLE;
<link rel="stylesheet" type="text/css" href="themes/deco.css" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<?php
foreach ($javascripts['header'] as $js) {
echo '
<script src="'. $js . '"></script>
';
}
?>
</head>
<?php
$bodyIds = !isset($bodyIds) ? '' : ' id="'. $bodyIds .'"';

View File

@ -1,50 +1,11 @@
<?php
require_once('config.php');
require_once('lib/Gchange.class.php');
require_once('lib/Keygen.class.php');
require_once('lib/Fred.class.php');
$bodyIds = 'home';
include_once('header.php');
$gchange = new Gchange();
$keygen = new Keygen();
// $ipfsHost = 'http://astroport.localhost:8080';
$ipfsHost = 'http://libra.copylaradio.com:8080';
try {
$player = $gchange->getUser($_SESSION['player_pubkey']);
} catch (Exception $errMsg) {
ErrorsHandler::kaput($errMsg);
}
try {
$twLink = $ipfsHost . '/ipns/' . $keygen->getIPNSPub($_SESSION['salt'], $_SESSION['pepper']);
} catch (Exception $errMsg) {
$twLink = '#';
$fred = new Fred();
$twLink = $ipfsHost . '/ipns/' . $fred->donneMoiLaPutainDeClefIPNS($_SESSION['salt'], $_SESSION['pepper']);
}
echo '
<header>
Bienvenue '. $player->getUserName() . ' !
<!-- ('. substr($player->getUserGchangeId(), 0, 8) . ') -->
</header>
<nav>
<ul>
<li id="dashboard-map">
@ -62,30 +23,6 @@ echo '
</span>
</a>
</li>
<li id="dashboard-farfetched">
<a href="farfetched.php">
<span>
À distance ou en livraison
</span>
</a>
</li>
<li id="dashboard-minelife">
<a href="minelife/index.html">
<span>
Manuel
</span>
</a>
</li>
<li id="dashboard-tiddlywiki">
<a href="'. $twLink .'">
<span>
'. ('Mon TiddlyWiki') .'
</span>
</a>
</li>
</ul>

View File

@ -4,7 +4,7 @@ require_once('Message.class.php');
function compareMsgDate ($msg1, $msg2) {
return ($msg1->getDate() < $msg2->getDate()) ? -1 : 1;
return ($msg1->getDate() < $msg2->getDate()) ? false : true;
}
class Conversation {

View File

@ -75,14 +75,14 @@ class DAO {
'duniter' => 2,
'cesiumplus' => 5,
'gchange' => 1,
'gchange' => 10,
];
private $nodeTimeoutIncrement = [
'duniter' => 2,
'cesiumplus' => 10,
'gchange' => 3
'gchange' => 10
];
private $node = NULL;
@ -115,8 +115,8 @@ class DAO {
if (!in_array($unit, $this->units)) {
$out = [];
$out[] = 'L\'unité renseignée n\'existe pas.';
$out[] = 'Vérifiez votre synthaxe.';
$out[] = _('L\'unité renseignée n\'existe pas.');
$out[] = _('Vérifiez votre synthaxe.');
$this->decease($out);
@ -205,7 +205,7 @@ class DAO {
<html>
<head>
<meta charset="utf-8" />
<title>'. ('Erreur critique') . '</title>
<title>'. _('Erreur critique') . '</title>
<style>
@ -251,16 +251,16 @@ class DAO {
if ($this->displayType == 'img') {
return ('DUĞ1');
return _('DUĞ1');
} else {
return ('DU<sub>Ğ1</sub>');
return _('DU<sub>Ğ1</sub>');
}
} else {
return ('Ğ1');
return _('Ğ1');
}
}
@ -476,22 +476,20 @@ class DAO {
if (empty($json)) {
$out = [];
$out[] = ('Aucun noeud '. $nodeType .' n\'a été trouvé ou la requête n\'a pas abouti.');
$out[] = ('Noeud interrogés : ');
$out[] = _('Aucun noeud '. $nodeType .' n\'a été trouvé ou la requête n\'a pas abouti.');
$out[] = _('Noeud interrogés : ');
$out = array_merge($out, $nodes);
$out[] = ('URI: ' . $uri);
$out[] = _('URI: ' . $uri);
if (isset($queryParams)) {
$out[] = ('Paramètres de la requête : ');
$out[] = _('Paramètres de la requête : ');
$out[] = '<pre>'. print_r($queryParams, true) . '<pre>';
}
// $this->decease($out);
throw new Exception(implode("\n", $out));
$this->decease($out);
}
return $json;

View File

@ -1,64 +0,0 @@
<?php
class ErrorsHandler {
public function __construct () {
}
static public function kaput ($errorMsgs) {
ob_get_clean(); // to prevent error message to display inside an HTML container (case of error generated by get method calls)
if (!is_array($errorMsgs)) {
$errorMsgs = explode("\n", $errorMsgs);
}
echo '<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Erreur critique</title>
<style>
div {
overflow: auto;
word-wrap: break-word;
background-color: hsl(0, 100%, 69%);
color: hsl(0, 100%, 19%);
margin: 1em;
padding: 1em;
border-radius: 1em;
position: fixed;
top: 0;
left: 0;
width: calc(100% - 4em);
max-height: calc(100vh - 4em);
}
</style>
</head>
<body>
<div>';
foreach ($errorMsgs as $msg) {
echo '<pre>' . print_r($msg, true) . '</pre>';
}
echo '
</div>
</body>
</html>';
die;
}
}

View File

@ -1,84 +1,39 @@
<?php
class Fred {
private $gatewayProtocol = 'http';
private $gatewayDomain = 'libra.copylaradio.com';
// private $gatewayDomain = 'aries.copylaradio.com';
// private $gatewayDomain = 'astroport.localhost';
private $gatewayPort = '1234';
private $gatewayDelay = 3;
private $gatewayMaxRounds = 20;
public function __construct () {
}
public function donneMoiLAdresseIPDuServeurQuiHebergeMonTiddlyWiki ($salt, $pepper) {
}
public function donneMoiLaPutainDeClefIPNS ($prenomNom, $nomDuChienSuivieDeLaDateDeNaissanceDeJohnnyHallyday) {
$salt = $prenomNom;
$pepper = $nomDuChienSuivieDeLaDateDeNaissanceDeJohnnyHallyday;
$query = 'salt='. urlencode($salt) .'&pepper='. urlencode($pepper) . '&getipns=on';
$page1 = file_get_contents($this->gatewayProtocol . '://'. $this->gatewayDomain .':' . $this->gatewayPort . '/?' . $query);
if (empty($page1)) {
throw new Exception("J'ai pas pû récupérer la putain de première page.");
}
$query = 'salt='. $salt .'&pepper='. $pepper;
$page1 = @file_get_contents($this->gatewayProtocol . '://'. $this->gatewayDomain .':' . $this->gatewayPort . '/?' . $query)
or die('<p>On a fait du sale.</p>');
preg_match("`url='([^']+)'`isU", $page1, $matches);
$url = $matches[1];
$url .= '/?'. $query;
// die($url);
$opts2 = array(
'http'=>array(
'method'=>"GET",
'header'=>"Accept-language: fr\r\n",
'follow_location' => 0
)
);
// echo 'fred 2';
$context2 = stream_context_create($opts2);
$page2 = false;
$rounds = 0;
while (($page2 === false) and $rounds < $this->gatewayMaxRounds) {
sleep($this->gatewayDelay);
// echo "\n\n\nround n°" . $rounds . "\n";
$page2 = @file_get_contents($url, false, $context2);
// echo '<pre>'. print_r(htmlspecialchars($page2), true) . '</pre>';
$rounds++;
}
if ($page2 === false) {
sleep($this->gatewayDelay);
throw new Exception("J'ai pas pû me connecter à ". $url ." pour récupérer la putain de deuxième page.");
} else if (empty($page2)) {
$page2 = @file_get_contents($url)
or die('</p>On a chié dans la colle.</p>');
throw new Exception("J'ai pas pû récupérer la putain de deuxième page.");
}
preg_match("`/ipns/(.+)`is", $page2, $matches);
preg_match("`url='.*/ipns/([^']+)'`isU", $page2, $matches);
$ipnsKey = $matches[1];
@ -97,12 +52,8 @@ class Fred {
// echo '<pre>'; var_dump(htmlspecialchars($url)); echo '</pre>';
$page1 = file_get_contents($url);
if (empty($page1)) {
throw new Exception("J'ai pas pû récupérer la putain de première page.");
}
$page1 = file_get_contents($url)
or die('<p>On a fait du sale.</p>');
// echo '<pre>'; var_dump(htmlspecialchars($page1)); echo '</pre>';
@ -113,19 +64,11 @@ class Fred {
// echo '<pre>'; var_dump($url); echo '</pre>';
$page2 = '';
$rounds = 0;
while (empty($page2) and $rounds < $this->gatewayMaxRounds) {
while (empty($page2)) {
sleep($this->gatewayDelay);
$page2 = file_get_contents($url);
$rounds++;
}
if (empty($page2)) {
throw new Exception("J'ai pas pû récupérer la putain de deuxième page.");
$page2 = @file_get_contents($url);
}
// echo '<pre>'; var_dump(htmlspecialchars($page2)); echo '</pre>';
@ -135,76 +78,41 @@ class Fred {
return json_decode($json);
}
public function donneMoiSaPutaindeG1Pub ($prenomNom, $nomDuChienSuivieDeLaDateDeNaissanceDeJohnnyHallyday) {
$salt = $prenomNom;
$pepper = $nomDuChienSuivieDeLaDateDeNaissanceDeJohnnyHallyday;
$query = 'salt='. urlencode($salt) .'&pepper='. urlencode($pepper) . '&g1pub=on';
$query = 'salt='. $salt .'&pepper='. $pepper . '&g1pub=on';
$url = $this->gatewayProtocol . '://'. $this->gatewayDomain .':' . $this->gatewayPort . '/?' . $query;
// echo '<pre>'; var_dump(htmlspecialchars($url)); echo '</pre>';
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=>"Accept-language: fr\r\n",
'follow_location' => 0
)
);
$context = stream_context_create($opts);
$page1 = file_get_contents($url, false, $context);
if (empty($page1)) {
throw new Exception("J'ai pas pû récupérer la putain de première page.");
}
$page1 = file_get_contents($url)
or die('<p>On a fait du sale.</p>');
// die('<pre>' . htmlspecialchars($page1) . '</pre>');
preg_match("`url='([^']+)'`isU", $page1, $matches);
// die(
// '<pre>' . htmlspecialchars($page1) . '</pre>' .
// '<pre>' . print_r($matches, true) . '</pre>'
// '<pre>' . htmlspecialchars($page1) . '</pre>' .
// '<pre>' . print_r($matches, true) . '</pre>'
// );
$url = $matches[1];
// die('<pre>' . var_dump($url, true) . '</pre>');
$opts2 = array(
'http'=>array(
'method'=>"GET",
'header'=>"Accept-language: fr\r\n",
'follow_location' => 0
)
);
$context2 = stream_context_create($opts2);
$page2 = '';
$rounds = 0;
while (empty($page2) and $rounds < $this->gatewayMaxRounds) {
while (empty($page2)) {
sleep($this->gatewayDelay);
$page2 = file_get_contents($url, false, $context2);
$rounds++;
}
if (empty($page2)) {
throw new Exception("J'ai pas pû récupérer la putain de deuxième page.");
$page2 = @file_get_contents($url);
}
preg_match("`url='.*/user/([^']+)/'`isU", $page2, $matches);
@ -212,5 +120,6 @@ class Fred {
$gchangeId = $matches[1];
return $gchangeId;
}
}

View File

@ -7,7 +7,6 @@ require_once('DAO.class.php');
require_once('GchangeUser.class.php');
require_once('GchangeRecord.class.php');
require_once('GchangeRating.class.php');
require_once('ErrorsHandler.class.php');
class Gchange {
@ -19,13 +18,9 @@ class Gchange {
private $cacheLongevity = array(
'placesNearby' => 604800, // 3 jours
'placeDetails' => 2116800, // 7 jours
'placeVisitors' => 2116800, // 7 jours
'usersNearby' => 43200, // 12 heures
'users' => 2116800, // 12 heures
'userRecords' => 900 // 15 min
'users' => 43200, // 12 heures
'records' => 900 // 15 min
);
public function __construct () {
@ -33,21 +28,71 @@ class Gchange {
$this->dao = DAO::getInstance();
}
public function fetchJson ($uri, $queryParams = null) {
public function getRecordsByIssuer ($issuer) {
try {
$json = $this->dao->fetchJson($uri, 'gchange', $queryParams);
$recordsCacheDir = 'records/user/';
$recordsCacheFile = $issuer . '.json';
} catch (Exception $errorMsgs) {
$json = $this->getJsonFromCache($recordsCacheDir, $recordsCacheFile, $this->cacheLongevity['records']);
throw $errorMsgs;
if (empty($json)) {
$n = 20;
$queryParams = [
'size' => $n,
'query' => [
'bool' => [
'filter' => [
'term' => [
'issuer' => $issuer
]
/*
, 'range' => [
'stock' => [
'gte' => 1
]
]
*/
]
/*
, 'filter' => [
]
*/
, 'must_not' => [
[ "term" => ["stock" => 0] ]
]
]
],
'sort' => [
['time' => 'desc']
]
];
$json = $this->dao->fetchJson('/market/record/_search', 'gchange', $queryParams);
$this->cacheJson($recordsCacheDir, $recordsCacheFile, $json);
}
return $json;
$result = json_decode($json);
$records = [];
foreach ($result->hits->hits as $hit) {
$records[] = new GchangeRecord($hit);
}
return $records;
}
private function getJsonFromCache ($dir, $file, $cacheLongevity = null) {
private function getJsonFromCache ($dir, $file, $cacheLongevity) {
if (!$this->isActivatedCache) {
@ -58,30 +103,13 @@ class Gchange {
$json = null;
$jsonFullPath = $this->cacheDir . $dir . $file;
if (!file_exists($jsonFullPath)) {
throw new Exception("Le fichier de cache suivant n'existe pas : " . $jsonFullPath);
}
if ($cacheLongevity !== null and (time() - filemtime($jsonFullPath) > $cacheLongevity)) {
throw new Exception("Le fichier de cache est expiré.");
}
try {
if (file_exists($jsonFullPath) and ((time() - filemtime($jsonFullPath)) < $cacheLongevity)) {
$json = file_get_contents($jsonFullPath);
} catch (Exception $errorMsgs) {
throw new Exception($jsonFullPath . " n'a pas été trouvé");
} finally {
return $json;
}
return $json;
}
private function cacheJson ($dir, $file, $json) {
@ -108,30 +136,13 @@ class Gchange {
$usersCacheDir = 'users/';
$usersCacheFile = $pubkey . '.json';
try {
$json = $this->getJsonFromCache($usersCacheDir, $usersCacheFile, $this->cacheLongevity['users']);
$json = $this->getJsonFromCache($usersCacheDir, $usersCacheFile, $this->cacheLongevity['users']);
if (empty($json)) {
} catch (Exception $errorMsgs) {
try {
$json = $this->fetchJson('/user/profile/'. $pubkey);
$this->cacheJson($usersCacheDir, $usersCacheFile, $json);
} catch (Exception $errorMsgs) {
try {
$json = $this->getJsonFromCache($usersCacheDir, $usersCacheFile, null);
} catch (Exception $errorMsgs) {
throw new Exception("L'utilisateur " . $pubkey . " n'a été trouvé nulle part.");
}
}
$json = $this->dao->fetchJson(('/user/profile/'. $pubkey), 'gchange');
$this->cacheJson($usersCacheDir, $usersCacheFile, $json);
}
$result = json_decode($json);
@ -139,50 +150,43 @@ class Gchange {
return new GchangeUser($result);
}
public function getNearbyUsers ($lat, $lon, $maxDistance, $minDistance = NULL) {
public function getPlacesNearUser ($user, $radius) {
return $this->getNearbyPlaces($user->getLat(), $user->getLon(), $radius);
/*
$placesCacheDir = 'places-nearby/user/';
$placesCacheFile = $user->getUserGchangeId() . '.json';
$json = $this->getJsonFromCache($placesCacheDir, $placesCacheFile, $this->cacheLongevity['placesNearby']);
if (empty($json)) {
$json = $this->getNearbyPlacesJson($user->getLat(), $user->getLon(), $radius);
$this->cacheJson($placesCacheDir, $placesCacheFile, $json);
}
$result = json_decode($json);
$nearbyUsersCacheDir = 'users-nearby/geopoint/' . $maxDistance . 'km/';
$nearbyUsersCacheFile = $lat . ',' . $lon . '.json';
return $result->hits->hits;
try {
*/
}
$json = $this->getJsonFromCache($nearbyUsersCacheDir, $nearbyUsersCacheFile, $this->cacheLongevity['usersNearby']);
public function getNearbyPlaces ($lat, $lon, $maxDistance, $minDistance = NULL) {
$placesCacheDir = 'places-nearby/geopoint/';
$placesCacheFile = $lat . ',' . $lon . '.json';
} catch (Exception $errorMsgs) {
$json = $this->getJsonFromCache($placesCacheDir, $placesCacheFile, $this->cacheLongevity['placesNearby']);
$n = 20;
if (empty($json)) {
$queryParams = [
'size' => $n,
'query' => [
'bool' => [
'filter' => [
[
'geo_distance' => [
"distance" => $maxDistance . 'km',
"geoPoint"=> [
"lat" => $lat,
"lon" => $lon
]
]
]
]
]
]
];
$json = $this->getNearbyPlacesJson($lat, $lon, $maxDistance, $minDistance);
try {
$json = $this->fetchJson('/users/record/_search', $queryParams);
$this->cacheJson($nearbyUsersCacheDir, $nearbyUsersCacheFile, $json);
} catch (Exception $errorMsgs) {
$json = $this->getJsonFromCache($nearbyUsersCacheDir, $nearbyUsersCacheFile, null);
}
$this->cacheJson($placesCacheDir, $placesCacheFile, $json);
}
@ -191,216 +195,45 @@ class Gchange {
return $result->hits->hits;
}
public function getPlacesNearUser ($user, $radius, $maxPlacesNb) {
public function getNearbyUsers ($lat, $lon, $maxDistance, $minDistance = NULL) {
return $this->getNearbyPlaces($user->getLat(), $user->getLon(), $radius, null, $maxPlacesNb);
}
public function getNearbyPlaces ($lat, $lon, $maxDistance, $minDistance = NULL, $maxPlacesNb = 15) {
$placesCacheDir = 'places-nearby/geopoint/' . $maxDistance . 'km/';
$placesCacheDir = 'users-nearby/geopoint/';
$placesCacheFile = $lat . ',' . $lon . '.json';
$placeDetailsCacheDir = 'place/details/';
$json = $this->getJsonFromCache($placesCacheDir, $placesCacheFile, $this->cacheLongevity['usersNearby']);
$nearbyPlaces = [];
if (empty($json)) {
$json = $this->getNearbyPlacesJson($lat, $lon, $maxDistance, $minDistance);
$this->cacheJson($placesCacheDir, $placesCacheFile, $json);
try {
$json = $this->getJsonFromCache($placesCacheDir, $placesCacheFile, $this->cacheLongevity['placesNearby']);
$places = json_decode($json);
foreach ($places->hits->hits as $place) {
try {
$p = $this->getPlaceDetails($place->_id);
$nearbyPlaces[] = $p;
} catch (Exception $errorMsgs) {
// place not found
}
}
} catch (Exception $errorMsgs) {
try {
$n = (string) $maxPlacesNb;
$queryParams = [
'size' => $n,
'query' => [
'bool' => [
'filter' => [
[
'geo_distance' => [
"distance" => $maxDistance . 'km',
"geoPoint"=> [
"lat" => $lat,
"lon" => $lon
]
]
]
]
]
]
];
$json = $this->fetchJson('/page/record/_search', $queryParams);
$result = json_decode($json);
$resultClone = $this->filterIds($result);
// cache nearby places index
$this->cacheJson($placesCacheDir, $placesCacheFile, json_encode($resultClone));
// cache each nearby place details
// ob_get_clean();
// echo '<pre>'; print_r($resultClone); echo '</pre>';
// echo '<pre>'; print_r($result); echo '</pre>';
foreach ($result->hits->hits as $place) {
$nearbyPlaces[] = $place;
$placeDetailsCacheFile = $place->_id . '.json';
$this->cacheJson($placeDetailsCacheDir, $placeDetailsCacheFile, json_encode($place));
}
} catch (Exception $errorMsgs) {
try {
$json = $this->getJsonFromCache($placesCacheDir, $placesCacheFile, null);
$result = json_decode($json);
foreach ($result->hits->hits as $place) {
try {
$p = $this->getPlaceDetails($place->_id);
$nearbyPlaces[] = $p;
} catch (Exception $errorMsgs) {
// place not found
}
}
} catch (Exception $errorMsgs) {
throw new Exception('Pas pu récupérer la liste des lieux : ' . $errorMsgs);
}
}
}
return $nearbyPlaces;
}
private function filterIds ($r) {
// $result = clone $r;
$result = new stdClass;
$result->took = $r->took;
$result->timed_out = $r->timed_out;
$result->_shards = new stdClass;
$result->_shards->total = $r->_shards->total;
$result->_shards->successful = $r->_shards->successful;
$result->_shards->failed = $r->_shards->failed;
$result->hits = new stdClass;
$result->hits->total = $r->hits->total;
$result->hits->max_score = $r->hits->max_score;
$result->hits->hits = array();
$rHitsNb = count($r->hits->hits);
for ($i = 0; $i < $rHitsNb; $i++) {
$result->hits->hits[$i] = new stdClass;
$result->hits->hits[$i]->_id = $r->hits->hits[$i]->_id;
}
return $result;
}
/*
private function filterIds (&$item) {
$result = json_decode($json);
$itemId = $item->_id;
$item = new stdClass;
$item->_id = $itemId;
return $result->hits->hits;
}
*/
public function getPlaceDetails ($placeId) {
$placeDetailsCacheDir = 'place/details/';
$placeDetailsCacheFile = $placeId . '.json';
try {
$json = $this->getJsonFromCache($placeDetailsCacheDir, $placeDetailsCacheFile, $this->cacheLongevity['placeDetails']);
} catch (Exception $errorMsgs) {
try {
$json = $this->fetchJson('/page/record/' + $placeId);
$this->cacheJson($placeDetailsCacheDir, $placeDetailsCacheFile, $json);
} catch (Exception $errorMsgs) {
try {
$json = $this->getJsonFromCache($placeDetailsCacheDir, $placeDetailsCacheFile, null);
} catch (Exception $errorMsgs) {
throw new Exception('Pas pu trouver les détails pour la page ' . $placeId);
}
}
}
return json_decode($json);
}
/*
public function getNearbyRecords ($lat, $lon, $maxDistance, $minDistance = NULL) {
public function getImmaterialRecords () {
$n = 20;
$queryParams = [
'size' => $n,
'query' => [
'bool' => [
'must' => [
[
'geo_distance' => [
"distance" => $maxDistance . 'km',
"geoPoint"=> [
"lat" => $lat,
"lon" => $lon
]
]
], [
'range' => [
'stock' => [
'gte' => 1
]
'nested' => [
'path' => 'category',
'query' => [
'bool' => [
'should' => [
[ 'term' => [ 'category.parent' => 'cat31' ] ],
[ 'term' => [ 'category.id' => 'cat31' ] ],
[ 'term' => [ 'category.parent' => 'cat74' ] ],
[ 'term' => [ 'category.id' => 'cat74' ] ]
],
'must_not' => [
[ "term" => ["category.id" => "cat65"] ]
]
]
]
@ -408,7 +241,7 @@ class Gchange {
]
];
$json = $this->fetchJson('/market/record/_search?pretty', $queryParams);
$json = $this->dao->fetchJson('/market/record/_search?pretty', 'gchange', $queryParams);
$result = json_decode($json);
@ -421,190 +254,42 @@ class Gchange {
return $records;
}
*/
public function getUsersInDaPlace ($placeId) {
$users = [];
$cacheDir = 'place/visitors/';
$cacheFile = $placeId . '.json';
$usersCacheDir = 'users/';
try {
$json = $this->getJsonFromCache($cacheDir, $cacheFile, $this->cacheLongevity['placeVisitors']);
$result = json_decode($json);
foreach ($result->hits->hits as $hit) {
$user = null;
try {
$user = null;
$user = $this->getUser($hit->_id);
$users[] = $user;
} catch (Exception $errorMsgs) {
// Utilisateur non trouvé
}
}
$n = 20;
} catch (Exception $errorMsgs) {
try {
$n = 20;
$queryParams = [
'size' => $n
// ,'fields' => ['_id']
,'query' => [
'nested' => [
'path' => 'socials',
'query' => [
'bool' => [
'filter' => [
'term' => [
'socials.url' => 'https://www.gchange.fr/#/app/page/view/'. $placeId .'/'
]
]
]
]
]
]
];
$json = $this->fetchJson('/user/profile/_search', $queryParams);
$result = json_decode($json);
foreach ($result->hits->hits as $hit) {
$user = new GchangeUser($hit);
$users[] = $user;
$this->cacheJson($usersCacheDir, $hit->_id . '.json', $user->jsonify());
}
} catch (Exception $errorMsgs) {
try {
$json = $this->getJsonFromCache($cacheDir, $cacheFile, null);
$result = json_decode($json);
foreach ($result->hits->hits as $hit) {
$user = null;
try {
$user = null;
$user = $this->getUser($hit->_id);
$users[] = $user;
} catch (Exception $errorMsgs) {
// Utilisateur non trouvé
}
}
} catch (Exception $errorMsgs) {
throw new Exception('Visiteurs trouvés nulle part.');
}
}
}
return $users;
}
public function getRecordsByIssuer ($issuer) {
$recordsCacheDir = 'records/user/';
$recordsCacheFile = $issuer . '.json';
try {
$json = $this->getJsonFromCache($recordsCacheDir, $recordsCacheFile, $this->cacheLongevity['userRecords']);
} catch (Exception $errorMsgs) {
try {
$n = 20;
$queryParams = [
'size' => $n,
$queryParams = [
'size' => $n,
'query' => [
'nested' => [
'path' => 'socials',
'query' => [
'bool' => [
'filter' => [
'term' => [
'issuer' => $issuer
'socials.url' => 'https://www.gchange.fr/#/app/page/view/'. $placeId .'/'
]
/*
, 'range' => [
'stock' => [
'gte' => 1
]
]
*/
]
/*
, 'filter' => [
]
*/
, 'must_not' => [
[ "term" => ["stock" => 0] ]
]
]
],
'sort' => [
['time' => 'desc']
]
];
$json = $this->fetchJson('/market/record/_search', $queryParams);
$this->cacheJson($recordsCacheDir, $recordsCacheFile, $json);
]
]
];
} catch (Exception $errorMsgs) {
try {
$json = $this->getJsonFromCache($recordsCacheDir, $recordsCacheFile, null);
} catch (Exception $errorMsgs) {
throw new Exception ("Aucune annonce trouvée pour l'utilisateur " . $issuer);
}
}
}
$json = $this->dao->fetchJson('/user/profile/_search', 'gchange', $queryParams);
$result = json_decode($json);
$records = [];
$users = [];
foreach ($result->hits->hits as $hit) {
$records[] = new GchangeRecord($hit);
$users[] = new GchangeUser($hit);
}
return $records;
return $users;
}
public function getRatingsSentBy ($issuer) {
@ -625,7 +310,7 @@ class Gchange {
]
];
$json = $this->fetchJson('/like/record/_search', $queryParams);
$json = $this->dao->fetchJson('/like/record/_search', 'gchange', $queryParams);
$result = json_decode($json);
@ -657,7 +342,7 @@ class Gchange {
]
];
$json = $this->fetchJson('/like/record/_search', $queryParams);
$json = $this->dao->fetchJson('/like/record/_search', 'gchange', $queryParams);
$result = json_decode($json);
@ -670,6 +355,79 @@ class Gchange {
return $ratings;
}
public function getNearbyPlacesJson ($lat, $lon, $maxDistance, $minDistance = NULL) {
$n = 20;
$queryParams = [
'size' => $n,
'query' => [
'bool' => [
'filter' => [
[
'geo_distance' => [
"distance" => $maxDistance . 'km',
"geoPoint"=> [
"lat" => $lat,
"lon" => $lon
]
]
]
]
]
]
];
$json = $this->dao->fetchJson('/page/record/_search', 'gchange', $queryParams);
return $json;
}
public function getNearbyRecords ($lat, $lon, $maxDistance, $minDistance = NULL) {
$n = 20;
$queryParams = [
'size' => $n,
'query' => [
'bool' => [
'must' => [
[
'geo_distance' => [
"distance" => $maxDistance . 'km',
"geoPoint"=> [
"lat" => $lat,
"lon" => $lon
]
]
], [
'range' => [
'stock' => [
'gte' => 1
]
]
]
]
]
]
];
$json = $this->dao->fetchJson('/market/record/_search?pretty', 'gchange', $queryParams);
$result = json_decode($json);
$records = [];
foreach ($result->hits->hits as $hit) {
$records[] = new GchangeRecord($hit);
}
return $records;
}
public function getShippable () {
@ -684,47 +442,7 @@ class Gchange {
]
];
$json = $this->fetchJson('/market/record/_search?pretty', $queryParams);
$result = json_decode($json);
$records = [];
foreach ($result->hits->hits as $hit) {
$records[] = new GchangeRecord($hit);
}
return $records;
}
public function getImmaterialRecords () {
$n = 20;
$queryParams = [
'size' => $n,
'query' => [
'nested' => [
'path' => 'category',
'query' => [
'bool' => [
'should' => [
[ 'term' => [ 'category.parent' => 'cat31' ] ],
[ 'term' => [ 'category.id' => 'cat31' ] ],
[ 'term' => [ 'category.parent' => 'cat74' ] ],
[ 'term' => [ 'category.id' => 'cat74' ] ]
],
'must_not' => [
[ "term" => ["category.id" => "cat65"] ]
]
]
]
]
]
];
$json = $this->fetchJson('/market/record/_search?pretty', $queryParams);
$json = $this->dao->fetchJson('/market/record/_search?pretty', 'gchange', $queryParams);
$result = json_decode($json);
@ -741,5 +459,10 @@ class Gchange {
public function getHousingOffers () {
}
public function getShippableOffers () {
}
}

View File

@ -1,29 +0,0 @@
<?php
trait Locatable {
private $lat = null;
private $lon = null;
public function getLat () {
return $this->lat;
}
public function getLon () {
return $this->lon;
}
}
trait Avatarable {
private $avatarImgSrc = null;
public function getAvatarImgSrc () {
return $this->avatarImgSrc;
}
}

View File

@ -2,8 +2,6 @@
class GchangeRecord {
use Locatable, Avatarable;
private $gchangeId;
private $title;
@ -12,6 +10,8 @@ class GchangeRecord {
private $type;
private $imgSrc = null;
public function __construct ($gchangeObject) {
@ -26,7 +26,7 @@ class GchangeRecord {
if (isset($gchangeObject->_source->avatar->_content) and
!empty($gchangeObject->_source->avatar->_content)) {
$this->avatarImgSrc = 'data:'. $gchangeObject->_source->avatar->_content_type .';base64,' . $gchangeObject->_source->avatar->_content;
$this->imgSrc = 'data:'. $gchangeObject->_source->avatar->_content_type .';base64,' . $gchangeObject->_source->avatar->_content;
}
}
@ -52,6 +52,6 @@ class GchangeRecord {
public function getImgSrc () {
return $this->getAvatarImgSrc();
return $this->imgSrc;
}
}

View File

@ -1,20 +1,20 @@
<?php
require_once('Gchange.traits.php');
class GchangeUser {
use Locatable, Avatarable;
private $userGchangeId;
public $userGchangeId;
private $userName;
public $userName;
private $lat = null;
private $lon = null;
private $avatarImgSrc = null;
public function __construct ($gchangeObject) {
$this->gchangeObject = $gchangeObject;
$this->userGchangeId = $gchangeObject->_id;
if (isset($gchangeObject->found) and $gchangeObject->found == false) {
@ -30,7 +30,7 @@ class GchangeUser {
}
if (isset($gchangeObject->_source->geoPoint->lat, $gchangeObject->_source->geoPoint->lon)) {
$this->lat = $gchangeObject->_source->geoPoint->lat;
$this->lon = $gchangeObject->_source->geoPoint->lon;
}
@ -54,8 +54,18 @@ class GchangeUser {
return $this->userName;
}
public function jsonify () {
public function getLat () {
return $this->gchangeObject;
return $this->lat;
}
public function getLon () {
return $this->lon;
}
public function getAvatarImgSrc () {
return $this->avatarImgSrc;
}
}

View File

@ -7,8 +7,6 @@ class Jaklis {
private $mode;
private $jaklisPath = __DIR__ . '/../vendors/jaklis/jaklis';
// private $jaklisPath = 'jaklis'; // if you use Docker
private $nodes = [
@ -17,14 +15,12 @@ class Jaklis {
private $msgLimit = 15;
private $pubsecDir = __DIR__ .'/../cache/pubsec/';
private $userPubsecPath;
public function __construct ($userPubkey, $mode = 'local') {
$this->userPubsecPath = $this->pubsecDir . $userPubkey .'.dunikey';
$this->userPubsecPath = __DIR__ .'/../cache/pubsec/'. $userPubkey .'.dunikey';
if ($this->mode != 'local') {
@ -36,17 +32,11 @@ class Jaklis {
if ($this->mode = 'local') {
try {
return [
$msg_in = $this->getInboundMessages();
$msg_out = $this->getOutboundMessages();
} catch (Exception $errMsg) {
throw new Exception($errMsg);
}
return [$msg_in, $msg_out];
$this->getInboundMessages(),
$this->getOutboundMessages()
];
} else {
@ -67,11 +57,6 @@ class Jaklis {
$result_code=null;
exec($cmd, $output, $result_code);
if (empty($output)) {
throw new Exception('Jaklis marche pô pour les messages entrants.');
}
$json = implode("\n", $output);
// echo '<p>' . $cmd . '</p>';
@ -98,11 +83,6 @@ class Jaklis {
$result_code=null;
exec($cmd, $output, $result_code);
if (empty($output)) {
throw new Exception('Jaklis marche pô pour les messages sortants.');
}
$json = implode("\n", $output);
// echo '<p>' . $cmd . '</p>';

View File

@ -2,100 +2,9 @@
class Keygen {
private $keygenPath = __DIR__ . '/../vendors/keygen/keygen';
// private $keygenPath = 'keygen'; // if you use Docker
private $pubsecDir = __DIR__ .'/../cache/pubsec/';
private $userPubsecPath;
public function __construct () {
}
public function getG1Pub ($salt, $pepper) {
$salt = str_replace('"', '\"', $salt);
$pepper = str_replace('"', '\"', $pepper);
$cmd = $this->keygenPath;
$cmd .= ' -f pubsec';
$cmd .= ' -t duniter';
$cmd .= ' "'. $salt .'"';
$cmd .= ' -p "'. $pepper .'"';
$output=null;
$result_code=null;
exec($cmd, $output, $result_code);
// die($cmd . '<br />'. print_r($output, true) . '<br />'. print_r($result_code, true));
if (empty($output) or empty($output[0])) {
throw new Exception('Keygen me calcule pas (la G1 pub)');
}
return $output[0];
}
public function getIPNSPub ($salt, $pepper) {
$salt = str_replace('"', '\"', $salt);
$pepper = str_replace('"', '\"', $pepper);
$cmd = $this->keygenPath;
$cmd .= ' -t b36mf';
$cmd .= ' "'. $salt .'"';
$cmd .= ' -p "'. $pepper .'"';
$output=null;
$result_code=null;
exec($cmd, $output, $result_code);
// die($cmd . '<br />'. print_r($output, true) . '<br />'. print_r($result_code, true));
if (empty($output) or empty($output[0])) {
throw new Exception('Keygen me calcule pas (la pub IPNS) :<br />' . $cmd . '<br />');
}
return $output[0];
}
public function generatePubsec ($salt, $pepper) {
$salt = str_replace('"', '\"', $salt);
$pepper = str_replace('"', '\"', $pepper);
$userPubkey = $this->getG1Pub($salt, $pepper);
if (!file_exists($this->pubsecDir)) {
mkdir($this->pubsecDir, 0777, true);
}
if (!file_exists($this->pubsecDir . $userPubkey . '.dunikey')) {
$cmd = $this->keygenPath;
$cmd .= ' -f pubsec';
$cmd .= ' -t duniter';
$cmd .= ' "'. $salt .'"';
$cmd .= ' -p "'. $pepper .'"';
$cmd .= ' -o '. $this->pubsecDir . $userPubkey . '.dunikey';
$output=null;
$result_code=null;
exec($cmd, $output, $result_code);
// die($cmd . '<br />'. print_r($result_code, true));
if ($result_code != 0) {
throw new Exception('Keygen me calcule pas (la dunikey)');
}
}
}
}

View File

@ -1,313 +0,0 @@
const nodes = {
gchange: [
'https://data.gchange.fr'
]
}
let gameId = 'spationaute'
async function fetchShippable (n) {
// var uri = '/market/record/_search?size='+ n +'&_source=title,description&q=description:envoi+possible%20type=offer'
var uri = '/market/record/_search'
var query = {
size: n
, _source: [
'title'
, 'description'
, 'id'
, 'picturesCount'
, 'pictures'
]
, query: {
bool: {
must: [
{
match: {
'description': {
query: 'envoi possible',
operator: 'and'
}
}
}
]
, must_not : [
{term : {stock: 0} }
]
, filter: [
{term: {type: 'offer'}}
]
}
}
, sort: [
{ 'time': 'desc'}
]
}
var fetchOpts = {
method: 'POST',
headers: {
'Accept': 'application/json'
},
body: JSON.stringify(query)
}
const r = await fetch(nodes['gchange'][0] + uri, fetchOpts)
if (r.ok === true) {
return r.json()
}
throw new Error(r.status)
}
async function fetchImmaterial (n) {
// var uri = '/market/record/_search?size='+ n +'&_source=title,description&q=description:envoi+possible%20type=offer'
var uri = '/market/record/_search'
var query = {
size: n
, _source: [
'title'
, 'description'
, 'id'
, 'picturesCount'
, 'pictures'
]
, query: {
nested: {
path: 'category',
query: {
bool: {
should: [
{term: {'category.parent': 'cat31'}}
, {term: {'category.id': 'cat31'}}
, {term: {'category.parent': 'cat74'}}
, {term: {'category.id': 'cat74'}}
]
,
must_not: [
{term: {'category.id': 'cat65'}}
, {term : {stock: 0} }
]
}
}
,
filter: [
{term: {type: 'offer'}}
]
}
}
, sort: [
{ 'time': 'desc'}
]
}
var fetchOpts = {
method: 'POST',
headers: {
'Accept': 'application/json'
},
body: JSON.stringify(query)
}
const r = await fetch(nodes['gchange'][0] + uri, fetchOpts)
if (r.ok === true) {
var obj = r.json()
// storeAtFreds(obj)
return obj
}
throw new Error(r.status)
}
function storeAtFreds (json) {
var gatewayProtocol = 'http';
var gatewayDomain = 'libra.copylaradio.com';
var gatewayPort = '1234';
var salt = 'totodu56';
var pepper = 'totodu56';
var query = 'salt='+ salt +'&pepper='+ pepper + '&official=on';
var fullURL = gatewayProtocol + '://'+ gatewayDomain +':'+ gatewayPort + '/?' + query;
console.log(fullURL)
const controller = new AbortController()
const timeoutId = setTimeout( () => {
controller.abort()
}, 15000)
var fetchOpts = {
method: 'GET',
headers: {
'Accept': 'text/html'
// ,'Content-Type': 'text/html'
// // ,'Access-Control-Allow-Origin': '*',
// ,'Origin': 'la-bureautique'
// ,'Referrer-Policy': 'unsafe-url'
// ,'Redirect': 'manual'
},
signal: controller.signal
}
fetch(fullURL, fetchOpts)
.then(reponse => {
return reponse.text()
})
.then(html => {
// console.log(html)
var regex = /url='([^']+)/i;
var redirectURL = html.match(regex)[1]
return redirectURL
})
.then(url => {
console.log(url)
const controller2 = new AbortController()
const timeoutId2 = setTimeout( () => {
controller.abort()
}, 15000)
var fetchOpts2 = {
method: 'GET',
headers: {
'Accept': 'text/html'
,'Content-Type': 'text/html'
// ,'Access-Control-Allow-Origin': '*',
,'Origin': 'la-bureautique'
,'Referrer-Policy': 'unsafe-url'
,'Redirect': 'manual'
},
mode: 'cors',
redirect: 'manual',
signal: controller2.signal
}
fetch(url, fetchOpts2)
.then(html => {
console.log(html)
/*
var regex = /url='.*\/ipns\/([^']+)/isU;
var ipnsKey = html.match(regex)[1]
return ipnsKey
*/
}).catch(err => {
console.error(err)
})
})
// JSON.stringify(json)
}
function displayShippable (records) {
let offersElt = document.getElementById('shippable-offers');
for (record of records) {
offerLi = document.createElement('li')
offerLink = document.createElement('a')
offerSpan = document.createElement('span')
offerImg = document.createElement('img')
if (record._source.picturesCount > 0) {
offerImg.src = 'data:' + (record._source.pictures[0].file._content_type) + ';base64,' + (record._source.pictures[0].file._content)
} else {
offerImg.src = 'themes/' + gameId + '/default-shippable.256.png'
}
offerImg.alt = record._source.title
offerImg.title = record._source.title
// offerLink.innerHTML = record._source.title
offerLink.href = 'https://www.gchange.fr/#/app/market/view/' + record._id + '/'
offerSpan.append(offerImg)
offerLink.append(offerSpan)
offerLi.append(offerLink)
offersElt.append(offerLi)
}
}
function displayImmaterial (records) {
let offersElt = document.getElementById('immaterial-offers');
for (record of records) {
offerLi = document.createElement('li')
offerLink = document.createElement('a')
offerSpan = document.createElement('span')
offerImg = document.createElement('img')
if (record._source.picturesCount > 0) {
offerImg.src = 'data:' + (record._source.pictures[0].file._content_type) + ';base64,' + (record._source.pictures[0].file._content)
} else {
offerImg.src = 'themes/' + gameId + '/default-immaterial.256.png'
}
offerImg.alt = record._source.title
offerImg.title = record._source.title
// offerLink.innerHTML = record._source.title
offerLink.href = 'https://www.gchange.fr/#/app/market/view/' + record._id + '/'
offerSpan.append(offerImg)
offerLink.append(offerSpan)
offerLi.append(offerLink)
offersElt.append(offerLi)
}
}
fetchImmaterial(18)
.then(records => {
displayImmaterial(records.hits.hits)
})
.catch(error => {
if (error == 'Error: 400')
console.error('Mauvaise requête')
else
console.error(error)
})
fetchShippable(18)
.then(records => {
displayShippable(records.hits.hits)
})
.catch(error => {
if (error == 'Error: 400')
console.error('Mauvaise requête')
else
console.error(error)
})

View File

@ -3,39 +3,25 @@ require_once('config.php');
require_once('lib/Gchange.class.php');
require_once('lib/Fred.class.php');
require_once('lib/Keygen.class.php');
require_once('lib/ErrorsHandler.class.php');
$toto = 'QP1VkfaFUMdHZmHgPMi7q5wJJHaQhZcEqs5A86NigKr';
$boris = '25zB1gSC7Qhwnx463cuDLDCKLRVieLAgFiPbYq6jVHG9';
$playerG1Id = null;
if (isset($_POST['salt'], $_POST['pepper'])) {
try {
$fred = new Fred();
$keygen = new Keygen();
$playerG1Id = $fred->donneMoiSaPutaindeG1Pub($_POST['salt'], $_POST['pepper']);
$keygen = new Keygen();
$_SESSION['player_pubkey'] = $playerG1Id;
$gchange = new Gchange();
$user = $gchange->getUser($_SESSION['player_pubkey']);
$playerG1Id = $keygen->getG1Pub($_POST['salt'], $_POST['pepper']);
$keygen->generatePubsec($_POST['salt'], $_POST['pepper']);
} catch (Exception $errMsg) {
try {
$fred = new Fred();
$playerG1Id = $fred->donneMoiSaPutainDeG1Pub($_POST['salt'], $_POST['pepper']);
} catch (Exception $errMsg) {
ErrorsHandler::kaput($errMsg);
}
}
$_SESSION['player_lat'] = $user->_source->geoPoint->lat;
$_SESSION['player_lon'] = $user->_source->geoPoint->lon;
$_SESSION['radius'] = DEFAULT_RADIUS;
$_SESSION['salt'] = $_POST['salt'];
$_SESSION['pepper'] = $_POST['pepper'];
$_SESSION['player_pubkey'] = $playerG1Id;
header('Location:home.php');
@ -76,4 +62,4 @@ if (isset($_POST['salt'], $_POST['pepper'])) {
include_once('footer.php');
}
}

102
map.php
View File

@ -3,7 +3,6 @@
require_once('config.php');
require_once('lib/Gchange.class.php');
require_once('lib/Location.class.php');
require_once('lib/ErrorsHandler.class.php');
if (!isset($_SESSION['player_pubkey'])) {
@ -12,27 +11,16 @@ if (!isset($_SESSION['player_pubkey'])) {
if (isset($_GET['r']) and in_array($_GET['r'], $radiuses)) {
$_SESSION['searchRadius'] = $_GET['r'];
} else if (!isset($_SESSION['searchRadius'])) {
$_SESSION['searchRadius'] = DEFAULT_SEARCH_RADIUS;
$_SESSION['radius'] = $_GET['r'];
}
function getThemeScriptsFullPath ($themeScript) {
return GAME_JS_DIR . '/' . $themeScript;
}
$gameScripts = array_map('getThemeScriptsFullPath', array_slice(scandir(GAME_JS_DIR), 2));
$javascripts['footer'] = array_merge($javascripts['footer'], $gameScripts);
$bodyIds = 'sonar';
include_once('header.php');
$gchange = new Gchange();
$player = $gchange->getUser($_SESSION['player_pubkey']);
// die('<pre>' . print_r($player, true) . '</pre>');
@ -49,7 +37,7 @@ echo '
<nav id="go-back-home">
<a href="home.php">
<span>
Retour au tableau de bord
'. dgettext($_SESSION['gameId'], _('Retour au tableau de bord')) . '
</span>
</a>
</nav>
@ -82,7 +70,7 @@ echo '
id="map"
data-orig-lat="'. $origLat .'"
data-orig-lon="'. $origLon .'"
data-radius="'. $_SESSION['searchRadius'] .'"
data-radius="'. $_SESSION['radius'] .'"
>
<div id="map-deco"></div>
';
@ -104,8 +92,8 @@ echo '
';
*/
$places = $gchange->getPlacesNearUser($player, $_SESSION['searchRadius'], MAX_NEARBY_PLACES);
$places = $gchange->getPlacesNearUser($player, $_SESSION['radius']);
$selectedPlace = NULL;
foreach ($places as $place) {
@ -217,73 +205,43 @@ if (isset($selectedPlace)) {
';
$visitors = $gchange->getUsersInDaPlace($place->_id);
$records_visitors = [];
$records_placeCreator = [];
try {
if (!empty($visitors)) {
$records_placeCreator = $gchange->getRecordsByIssuer($place->_source->issuer);
echo '
<h4>Visiteurs</h4>
<ul class="visitors">';
} catch (Exception $errorMsgs) {
foreach ($visitors as $visitor) {
// Pas d'annonce pour le créateur du lieu
}
try {
$visitors = $gchange->getUsersInDaPlace($place->_id);
if (!empty($visitors)) {
$records_visitors = array_merge($records_visitors, $gchange->getRecordsByIssuer($visitor->getUserGchangeId()));
echo '
<h4>Visiteurs</h4>
<ul class="visitors">';
<li class="visitor">';
foreach ($visitors as $visitor) {
$avatarSrc = $visitor->getAvatarImgSrc();
$src = !empty($avatarSrc) ? $avatarSrc : $games[$_SESSION['gameId']]['default_avatar'];
try {
$records_visitor = $gchange->getRecordsByIssuer($visitor->getUserGchangeId());
$records_visitors = array_merge($records_visitors, $records_visitor);
echo '
<li class="visitor">';
$avatarSrc = $visitor->getAvatarImgSrc();
$src = !empty($avatarSrc) ? $avatarSrc : $games[$_SESSION['gameId']]['default_avatar'];
echo '
<img src="'. $src . '"
alt="'. $visitor->getUserName() .'"
title="'. $visitor->getUserName() .'"
width="64"
height="64" />
</li>';
} catch (Exception $errorMsgs) {
// Pas d'annonce pour cet utilisateur
}
}
echo '
</ul>';
echo '
<img src="'. $src . '"
alt="'. $visitor->getUserName() .'"
title="'. $visitor->getUserName() .'"
width="64"
height="64" />
</li>';
}
} catch (Exception $errorMsgs) {
// Visiteurs trouvés nulle part
echo '
</ul>';
}
$records_placeCreator = $gchange->getRecordsByIssuer($place->_source->issuer);
$records = array_merge($records_placeCreator, $records_visitors);
$offers = [];
$needs = [];
$crowdfundings = [];

View File

@ -5,9 +5,6 @@ require_once('lib/Fred.class.php');
require_once('lib/Messenger.class.php');
require_once('lib/Gchange.class.php');
require_once('lib/Jaklis.class.php');
require_once('lib/ErrorsHandler.class.php');
$javascripts['header'][] = 'lib/js/messenger.js';
$gchange = new Gchange();
$messenger = new Messenger($gchange);
@ -27,15 +24,7 @@ if (isset($_POST['message'], $_POST['to'])) {
}
// $msgIn = $jaklis->getInboundMessages('QP1VkfaFUMdHZmHgPMi7q5wJJHaQhZcEqs5A86NigKr');
try {
list($msgIn, $msgOut) = $jaklis->getMessages();
} catch (Exception $errMsg) {
ErrorsHandler::kaput($errMsg);
}
list($msgIn, $msgOut) = $jaklis->getMessages();
// list($msgIn, $msgOut) = $fred->donneMoiSesPutainDeMessagesGchange($_SESSION['salt'], $_SESSION['pepper']);
// echo '<pre>'; var_dump($msgIn); echo '</pre>';
@ -148,16 +137,14 @@ if (isset($_GET['penpal'])) {
echo '
<form method="post" action="">
<label for="message">'. 'Message' .'</label>
<label for="message">'. _('Message') .'</label>
<textarea name="message" rows="1" cols="30"></textarea>
<input type="hidden" name="to" value="'. htmlspecialchars($_GET['penpal']) .'" />
<input type="hidden" name="title" value="'. htmlspecialchars($displayedConv->getConvTitle()) .'" />
<p class="submit-button-wrapper">
<input type="submit" value="'. 'Envoyer' .'" />
</p>
<input type="submit" value="'. _('Envoyer') .'" />
</form>
';
}

View File

@ -1,393 +0,0 @@
async function getCrafts() {
const res = await fetch("./data/crafts.json");
const data = await res.json();
return data;
};
async function getCollections() {
const res = await fetch("./data/collections.json");
const data = await res.json();
return data;
};
function updateSelectedCollection (selected = 0) {
var previouslySelectedCollection = document.querySelector('#collections nav ul li.selected');
if (previouslySelectedCollection != null) {
previouslySelectedCollection.classList.remove('selected');
}
var collections = document.querySelectorAll('#collections nav ul li');
console.log(collections);
var newlySelectedCollection = collections[selected];
console.log(newlySelectedCollection);
newlySelectedCollection.classList.add('selected');
}
async function printCollections (crafts, collections) {
var collectionsElt = document.getElementById('collections');
var collectionsNavElt = collectionsElt.querySelector('nav ul');
collectionsNavElt.innerHTML = '';
var cssClass = '';
collections.forEach(function (collection, index) {
if (collection.items != undefined) {
cssClass = '';
collectionsNavElt.innerHTML +=
'<li' + cssClass + '>' +
'<a href="#" ' +
'title="' + collection.name + '" ' +
'>' +
'<img src="data/img/' + collection.img + '" ' +
'alt="' + collection.name + '" ' +
'/>' +
'</a>' +
'</li>';
}
});
displayCollection(crafts, collections);
collectionsElt.querySelectorAll('li').forEach(function (elt, index) {
elt.addEventListener('click', function () {
console.log(index);
displayCollection(crafts, collections, index);
});
});
}
async function displayCollection (crafts, collections, collectionId = 0) {
updateSelectedCollection(collectionId);
itemsListElt = document.querySelector('#collections .items-list');
itemsListElt.innerHTML = '';
collections[collectionId].items.forEach(function (itemId){
itemsListElt.innerHTML +=
'<li>' +
'<a href="#" ' +
'onclick="displayRecipe('+ itemId + ', 0)" ' +
'title="' + crafts[itemId].name + '" ' +
'>' +
'<img src="data/img/' + crafts[itemId].img + '" ' +
'alt="' + crafts[itemId].name + '" ' +
'/>' +
'</a>' +
'</li>';
});
}
async function printItemsList () {
crafts = await getCrafts();
itemsListElt = document.getElementById('items-list');
crafts.forEach(function (item, index) {
if (item.recipes != undefined) {
itemsListElt.innerHTML +=
'<li>' +
'<a href="#" ' +
'onclick="displayRecipe('+ index + ', 0)" ' +
'title="' + item.name + '" ' +
'>' +
'<img src="data/img/' + item.img + '" ' +
'alt="' + item.name + '" ' +
'/>' +
'</a>' +
'</li>';
}
});
}
function padIngredient (nbIngredients, str) {
if (nbIngredients <= 1 ||
nbIngredients == 4 ||
nbIngredients == 9 ||
nbIngredients == 16) {
return '';
} else if (nbIngredients < 4) {
return str.repeat(4 - nbIngredients);
} else if (nbIngredients < 9) {
return str.repeat(9 - nbIngredients);
} else if (nbIngredients < 16) {
return str.repeat(16 - nbIngredients);
} else if (nbIngredients < 25) {
return str.repeat(25 - nbIngredients);
}
}
async function displayRecipe (itemId, recipeId = 0, elementId = 'recipe-main', bc_item = null, bc_recipe = null) {
crafts = await getCrafts();
recipeElt = document.getElementById(elementId);
ingredientsElt = recipeElt.querySelector('.ingredients');
actionElt = recipeElt.querySelector('.action');
resultElt = recipeElt.querySelector('.result');
itemNameElt = recipeElt.querySelector('.item-name');
otherRecipesElt = recipeElt.querySelector('.other-recipes ul');
detailsElt = recipeElt.querySelector('.recipe-details');
detailsContentElt = detailsElt.querySelector('div');
actionElt.innerHTML = '<a href="#">&nbsp;</a>';
resultElt.innerHTML = "&nbsp;";
otherRecipesElt.innerHTML = "";
detailsContentElt.innerHTML = "";
recipeElt.style.visibility = 'visible';
detailsElt.style.visibility = 'hidden';
itemNameElt.innerHTML = '' + crafts[itemId].name + '';
resultElt_content =
'<img src="data/img/' + crafts[itemId].img + '" ' +
'alt="' + crafts[itemId].name + '" ' +
'title="' + crafts[itemId].name + '" ' +
'/>';
if (elementId == 'recipe-aux' && bc_item != null) {
resultElt_content =
'<a href="#" ' +
'onclick="displayRecipe(' + bc_item + ', ' + bc_recipe +', \'recipe-aux\')" ' +
'>' +
resultElt_content +
'</a>';
}
resultElt.innerHTML = resultElt_content;
blackHoleStr = '<li class="ingredient"><img src="data/img/black-hole.png" /></li>';
if (crafts[itemId].recipes == undefined) {
ingredientsElt.innerHTML = blackHoleStr;
} else {
recipes = crafts[itemId].recipes;
ingredients = recipes[recipeId].ingredients;
if (ingredients == undefined) {
ingredientsElt.innerHTML = blackHoleStr;
} else {
ingredientsElt.innerHTML = '';
nbIngredients = ingredients.length;
ingredientsElt.className = 'ingredients ';
if (nbIngredients > 16) {
ingredientsElt.className += "grid-25";
} else if (nbIngredients > 9) {
ingredientsElt.className += "grid-16";
} else if (nbIngredients > 4) {
ingredientsElt.className += "grid-9";
} else if (nbIngredients > 1) {
ingredientsElt.className += "grid-4";
} else {
ingredientsElt.className += "";
}
var i = 1;
console.log(ingredients);
ingredients.forEach (function (ingredient) {
unit = (ingredient.unit != undefined) ? (' ' + ingredient.unit) : '';
qty = (ingredient.qty == undefined) ? '' : '<span class="qty">' + ingredient.qty + '</span>';
title =
(ingredient.qty == undefined) ?
crafts[ingredient.ref].name : (
(ingredient.unit == undefined) ?
ingredient.qty + ' ' + crafts[ingredient.ref].name :
ingredient.qty + ' ' + ingredient.unit + ' de ' + crafts[ingredient.ref].name
);
// displayOn = (elementId == 'recipe-main') ? 'recipe-aux' : 'recipe-main';
displayOn = 'recipe-aux';
if (elementId == 'recipe-aux') {
bc_item = itemId;
bc_recipe = recipeId;
} else {
bc_item = null;
bc_recipe = null;
}
ingredientsElt.innerHTML +=
'<li class="ingredient">' +
qty +
'<a href="#" ' +
'onclick="displayRecipe('+ ingredient.ref + ', 0, \'' + displayOn + '\', '+ bc_item +', '+ bc_recipe + ')"' +
'title="' + title + '"' +
'>' +
'<img src="data/img/' + crafts[ingredient.ref].img + '" ' +
'alt="' + crafts[ingredient.ref].name + '" ' +
'/>' +
'</a>' +
'</li>';
i++;
});
ingredientsElt.innerHTML += padIngredient(nbIngredients, '<li class="ingredient"></li>');
}
action = (recipes[recipeId].action == undefined) ? '' : recipes[recipeId].action;
if (recipes[recipeId].details != undefined) {
actionElt.className += ' has-details';
}
actionElt.innerHTML =
'<a href="#" ' +
'onclick="showDetails(\'' + elementId + '\', \'' + recipeId + '\')" ' +
'>'+
action +
'</a>';
if ((details = crafts[itemId].recipes[recipeId].details) != undefined) {
detailsContentElt.innerHTML = details;
}
nbRecipes = recipes.length;
if (nbRecipes == 1) {
if (recipes[0].name != undefined) {
otherRecipesElt.innerHTML +=
'<li>' +
'<strong>' +
recipes[0].name +
'</strong>' +
'</li>';
}
} else if (nbRecipes > 1) {
for (i = 0; i < nbRecipes; i++) {
otherRecipeName = (recipes[i].name != undefined) ?
recipes[i].name :
"recette n°" + (i + 1);
if (i == recipeId) {
otherRecipesElt.innerHTML +=
'<li>' +
'<strong>' +
otherRecipeName +
'</strong>' +
'</li>';
} else {
otherRecipesElt.innerHTML +=
'<li>' +
'<a href="#" ' +
'onclick="displayRecipe(' + itemId + ', ' + i + ', \''+ elementId + '\')">' +
otherRecipeName +
'</a>'
'</li>';
}
}
}
}
}
showDetails = function (elementId) {
detailsElt = document.querySelector('#' + elementId + ' .recipe-details');
detailsElt.style.visibility = "visible";
}
// printItemsList();
window.addEventListener('load', async function () {
const crafts = await getCrafts();
const collections = await getCollections();
printCollections(crafts, collections);
});

View File

@ -1,93 +0,0 @@
Copyright 2014 The Comic Neue Project Authors (https://github.com/crozynski/comicneue)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@ -1,93 +0,0 @@
Copyright (c) 2010, Kimberly Geswein (kimberlygeswein.com)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@ -1,93 +0,0 @@
Copyright (c) 2010-2012 Patrick Wagesreiter (mail@patrickwagesreiter.at)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@ -1,499 +0,0 @@
:root {
--item-size: 32px;
--marron: hsl(350, 20%, 25%);
--marron-medium: hsl(30, 50%, 50%);
--marron-clair: hsl(30, 70%, 66%);
--marron-transparent: hsla(350, 20%, 25%, 0.80);
--blanc: hsl(0, 100%, 100%);
--noir: hsl(0, 100%, 0%);
--vert-pomme: hsl(100, 70%, 90%);
}
@font-face {
font-family: 'Comic Neue';
src: url("../../fonts/Comic_Neue/ComicNeue-Regular.ttf") format('truetype');
}
@font-face {
font-family: 'Comic Neue';
src: url("../../fonts/Comic_Neue/ComicNeue-Bold.ttf") format('truetype');
font-weight: 700;
}
@font-face {
font-family: 'Patrick Hand';
src: url("../../fonts/Patrick_Hand/PatrickHand-Regular.ttf") format('truetype');
}
@font-face {
font-family: 'MinecraftFifty';
src: url("../../fonts/MinecraftFifty-Solid.otf") format('opentype');
}
body {
font-family: 'Comic Neue', fantasy;
}
h1 {
font-family: 'MinecraftFifty', 'Comic Neue', fantasy;
}
#usp {
font-family: 'Patrick Hand', fantasy;
}
q:after {
content: " »";
}
q:before {
content: "« ";
}
body > footer {
margin-top: 10rem;
display: flex;
justify-content: center;
}
body > footer blockquote {
font-family: cursive;
font-size: 1.5rem;
color: hsl(30, 15%, 90%);
}
body > footer blockquote cite {
display: block;
text-align: right;
margin-top: 0.5rem;
}
body > footer blockquote cite:before {
content: "― ";
}
iframe {
max-width: 100%;
}
.recipe-name:before {
content: "« ";
}
.recipe-name:after {
content: " »";
}
main {
display: flex;
width: 100%;
flex-wrap: wrap;
}
#recipe-main,
#recipe-aux {
visibility: hidden;
}
@media screen and (max-width: 39.999rem) {
main {
flex-direction: column;
}
#recipe-main {
order: 1;
}
#recipe-aux {
order: 2;
}
#collections {
order: 3;
}
}
@media screen and (min-width: 40rem) {
.recipe {
width: 48%;
padding: 0% 2% 0% 0%;
}
#collections {
width: 100%;
padding: 0% 0% 0% 2%;
}
}
@media screen and (min-width: 60rem) {
.recipe {
width: 31.333%;
padding: 0% 2% 0% 0%;
}
#collections {
width: 31.334%;
padding: 0% 0% 0% 2%;
}
}
.recipe > .recipe-signature {
display: flex;
align-items: center;
}
@keyframes blinking {
0% {
text-shadow: 0 0 0px transparent;
}
50% {
text-shadow: 0 0 5px var(--vert-pomme),
0 0 10px var(--vert-pomme),
0 0 15px var(--vert-pomme),
0 0 20px var(--vert-pomme),
0 0 25px var(--vert-pomme);
}
100% {
text-shadow: 0 0 0px transparent;
}
}
.recipe .action {
padding: 0 2rem;
text-align: center;
}
.recipe .action a,
.recipe .action a:visited {
text-decoration: none;
color: var(--noir);
background-color: var(--blanc);
transition: text-shadow 0.666s;
}
.recipe .action.has-details a,
.recipe .action.has-details a:visited {
animation: blinking 3s infinite;
}
.recipe .action:hover a,
.recipe .action:hover a:before {
}
.recipe .action *:before {
content: "⇒";
display: block;
font-size: 2rem;
font-weight: bolder;
}
.recipe .ingredients {
list-style-type: none;
padding: 0;
margin: 0;
display: grid;
grid-gap: 0;
border: 2px solid var(--marron);
}
.recipe .ingredients.grid-4 {
grid-template-columns: 50% 50%;
max-width: calc(2 * (var(--item-size) + 24px + 4px * 2));
}
.recipe .ingredients.grid-9 {
grid-template-columns: 33.333% 33.333% 33.333%;
max-width: calc(3 * (var(--item-size) + 24px + 4px * 2));
}
.recipe .ingredients.grid-16 {
grid-template-columns: 25% 25% 25% 25%;
max-width: calc(4 * (var(--item-size) + 24px + 4px * 2));
}
.recipe .ingredients.grid-25 {
grid-template-columns: 20% 20% 20% 20% 20%;
max-width: calc(5 * (var(--item-size) + 24px + 4px * 2));
}
.result {
border: 4px solid var(--marron);
}
#items-list,
.items-list,
#collections nav ul {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
flex-wrap: wrap;
}
#collections nav {
display: flex;
}
#collections nav ul {
margin-bottom: 1rem;
border: 0.25rem solid var(--marron);
border-radius: 1rem;
overflow: hidden;
}
#collections nav ul li.selected {
background-color: var(--marron-clair);
}
/*
#collections nav ul li {
border-left: 0.5rem solid var(--marron);
border-right: 0.5rem solid var(--marron);
margin: 0;
padding: 0;
}
#collections nav ul li:first-child {
border-left: 0;
}
#collections nav ul li:last-child {
border-right: 0;
}
*/
.recipe .ingredients .ingredient,
#items-list li,
.items-list li {
border: 2px solid var(--marron);
margin: 0;
padding: 0;
}
#items-list li,
.items-list li,
#collections nav ul li {
height: 48px;
width: 48px;
}
.recipe .ingredients .ingredient a,
#items-list li a,
.items-list li a,
#collections nav ul li a {
z-index: 10;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.recipe .ingredients .ingredient:hover a,
#items-list li:hover a,
.items-list li:hover a,
#collections nav ul li:hover a {
background-color: var(--marron-clair);
}
.recipe .ingredients .ingredient:hover a {
border: 2px solid var(--marron-medium);
}
.recipe .ingredients .ingredient,
.recipe .result,
#items-list li,
#collections nav ul li {
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.recipe .ingredients .ingredient {
}
.recipe .ingredients .ingredient img {
flex-basis: var(--item-size);
flex-grow: 0;
}
.recipe .ingredients .ingredient .qty {
position: absolute;
right: 0;
bottom: 0;
z-index: 100;
font-weight: bold;
font-size: 1.25rem;
background-color: var(--marron-transparent);
color: var(--blanc);
padding-left: 0.375rem;
padding-right: 0.125rem;
padding-top: 0.25rem;
border-top-left-radius: 0.33em;
}
.recipe .ingredients .ingredient,
.recipe .result {
height: 64px;
width: 64px;
}
.other-recipes ul {
list-style: none;
padding: 0;
padding-top: 0px;
margin: 0;
display: flex;
}
.other-recipes ul {
list-style: none;
padding: 0;
margin: 0;
display: flex;
height: 2.5rem;
padding-top: 1rem;
width: auto;
width: auto;
overflow-y: hidden;
overflow-x: visible;
flex-wrap: nowrap;
}
.other-recipes li {
margin: 0;
margin-right: 0.5rem;
padding: 0;
display: inline;
flex-basis: auto;
flex-shrink: 0;
}
.other-recipes li > * {
width: 2rem;
text-align: center;
height: 2rem;
display: inline;
padding: 0.25rem 0.5em;
border-radius: 1rem;
text-decoration: none;
border-width: 2px;
border-style: solid;
border-color: var(--marron);
background-color: var(--blanc);
color: var(--marron);
}
.other-recipes li *:not(a) {
border-color: var(--marron);
color: var(--blanc);
background-color: var(--marron);
}
.recipe-details {
visibility: hidden;
}

View File

@ -1,75 +0,0 @@
[
{
"name": "habitat",
"img": "carpenter.png",
"items": [
4,
0,
1,
12,
7,
11,
13,
58
]
}
,{
"name": "culture",
"img": "farmer.png",
"items": [
28,
36,
57,
56,
42,
43,
3,
59,
35,
49,
86
]
}
,{
"name": "cuisine",
"img": "chef.png",
"items": [
33,
17,
44,
87
]
}
,{
"name": "vêtement",
"img": "sewing.png",
"items": [
54
]
}
,{
"name": "soin",
"img": "arm-plaster.png",
"items": [
101,
83,
67,
68,
69,
70,
71,
72,
73,
74,
75,
77,
100
]
}
]

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 675 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 965 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 870 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Some files were not shown because too many files have changed in this diff Show More