Added photo voting
This commit is contained in:
parent
4ba6085a06
commit
52bc3105fd
103
results-gallery.php
Normal file
103
results-gallery.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
/** require autoloading to manage namespaces */
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
use PhotoPrismUpload\API\PhotoPrism;
|
||||
use PhotoPrismUpload\Entities\Album;
|
||||
use PhotoPrismUpload\Entities\Photo;
|
||||
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<title>Collagen Abstimmung</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<link href="vote.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<?php
|
||||
|
||||
$footer = '</body></html>';
|
||||
|
||||
/** @var array $config configuration options */
|
||||
$config = require(__DIR__ . '/config.php');
|
||||
|
||||
/** @var PhotoPrism $api API object to interface with PhotoPrism */
|
||||
$api = new PhotoPrism($config);
|
||||
|
||||
/** @var Album[] $albums List of PhotoPrism albums */
|
||||
$albums = [];
|
||||
try {
|
||||
$api->login();
|
||||
} catch (\Exception $e) {
|
||||
die('Fehler: ' . $e->getMessage().$footer.'</body></html>');
|
||||
}
|
||||
|
||||
/** @var string $token Tokens for which album(s) are visible in the dropdown */
|
||||
$token = $_GET['token'];
|
||||
|
||||
/** @var int $page Page number of photos to load */
|
||||
$page = 1;
|
||||
|
||||
/** @var int $count Number of pictures to load */
|
||||
$count = 200;
|
||||
|
||||
/** @var int $offset Tokens for which album(s) are visible in the dropdown */
|
||||
$offset = ($page - 1) * $count;
|
||||
|
||||
/** @var string $album_url URL path to the selected album */
|
||||
$album_url = '/';
|
||||
|
||||
$votes_file = 'votes.json';
|
||||
|
||||
$contents = file_get_contents($votes_file);
|
||||
if ($contents === false) {
|
||||
$contents = '{}';
|
||||
}
|
||||
$contents = json_decode($contents, true);
|
||||
|
||||
$vote_counts = [];
|
||||
foreach ($contents as $votes) {
|
||||
foreach ($votes as $photo_uid => $vote_value) {
|
||||
if (!array_key_exists($photo_uid, $vote_counts)) {
|
||||
$vote_counts[$photo_uid] = 0;
|
||||
}
|
||||
$vote_counts[$photo_uid] += intval($vote_value);
|
||||
}
|
||||
}
|
||||
|
||||
$page_sizes = array_values(array_unique([10, 20, 50, 100, $count]));
|
||||
sort($page_sizes);
|
||||
$link_class = $page === 1 ? 'pageLink disabled' : 'pageLink';
|
||||
|
||||
try {
|
||||
$album = $api->getAlbumByToken($token);
|
||||
if ($album === null) {
|
||||
die('Album nicht gefunden' . $footer . '</body></html>');
|
||||
}
|
||||
$photos = $api->getAlbumPhotos($album, $count, $offset);
|
||||
$photos = array_filter($photos, function (Photo $a) use ($vote_counts) {
|
||||
$vote_a = $vote_counts[$a->uid] ?? 0;
|
||||
return $vote_a >= 0;
|
||||
});
|
||||
usort($photos, function (Photo $a, Photo $b) use ($vote_counts) {
|
||||
$vote_a = $vote_counts[$a->uid] ?? 0;
|
||||
$vote_b = $vote_counts[$b->uid] ?? 0;
|
||||
return $vote_b - $vote_a;
|
||||
});
|
||||
?>
|
||||
<?php
|
||||
foreach ($photos as $photo) {
|
||||
$thumb = $photo->getThumbnailUrl();?>
|
||||
<div class="photowrapper">
|
||||
<img src="<?= $api->api_url.$thumb?>" id="<?= $photo->uid?>">
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
die('Fehler: ' . $footer . $e->getMessage() . '</body></html>');
|
||||
}
|
||||
?>
|
@ -33,7 +33,6 @@ class LoggerFactory
|
||||
{
|
||||
$l = new Logger($name);
|
||||
$l->setHandlers(self::$handlers);
|
||||
$l->info('Initialized');
|
||||
return $l;
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ use Psr\Log\LoggerInterface;
|
||||
use PhotoPrismUpload\Exceptions\NetworkException;
|
||||
use PhotoPrismUpload\Exceptions\AuthenticationException;
|
||||
use PhotoPrismUpload\Entities\Album;
|
||||
use PhotoPrismUpload\Entities\Photo;
|
||||
|
||||
/**
|
||||
* The main API class to interface with PhotoPrism
|
||||
@ -18,11 +19,17 @@ class PhotoPrism
|
||||
public string $base_url = 'https://photos.phlaym.net';
|
||||
|
||||
/** @var string $api_url API URL of the PhotoPrism instance */
|
||||
protected string $api_url = '';
|
||||
public string $api_url = '';
|
||||
|
||||
/** @var string|null $session_id Session id of the currently logged in user */
|
||||
protected ?string $session_id = null;
|
||||
|
||||
/** @var string|null $download_token Token for downloading files */
|
||||
protected ?string $download_token = null;
|
||||
|
||||
/** @var string|null $preview_token Token for thumbnails files */
|
||||
protected ?string $preview_token = null;
|
||||
|
||||
/** @var array $config Configuration options */
|
||||
protected array $config;
|
||||
|
||||
@ -51,6 +58,8 @@ class PhotoPrism
|
||||
$this->logger = LoggerFactory::create('PhotoPrismUpload');
|
||||
if (isset($_SESSION['pp_sessionid'])) {
|
||||
$this->session_id = $_SESSION['pp_sessionid'];
|
||||
$this->preview_token = $_SESSION['pp_preview_token'];
|
||||
$this->download_token = $_SESSION['pp_download_token'];
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,6 +76,10 @@ class PhotoPrism
|
||||
private function parseHeaders(string $response): array
|
||||
{
|
||||
$response = explode("\r\n\r\n", $response, 2);
|
||||
if (count($response) === 3) {
|
||||
$dropped = array_shift($response);
|
||||
$this->logger->warning('Dropping start of response:' . $dropped);
|
||||
}
|
||||
$headers = $response[0];
|
||||
if ($headers === 'HTTP/1.1 100 Continue') {
|
||||
$response = explode("\r\n\r\n", $response[1], 2);
|
||||
@ -150,6 +163,7 @@ class PhotoPrism
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
if ($method !== 'get' && !empty($query_data)) {
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $query_data);
|
||||
}
|
||||
@ -209,8 +223,12 @@ class PhotoPrism
|
||||
throw new AuthenticationException($response['error']);
|
||||
}
|
||||
$this->session_id = $response['id'];
|
||||
$this->download_token = $response['config']['downloadToken'];
|
||||
$this->preview_token = $response['config']['previewToken'];
|
||||
$_SESSION['pp_sessionid'] = $this->session_id;
|
||||
$this->logger->debug('Session ID: ' . $this->session_id);
|
||||
$_SESSION['pp_preview_token'] = $this->preview_token;
|
||||
$_SESSION['pp_download_token'] = $this->download_token;
|
||||
$this->logger->debug('Session ID: ' . $this->session_id . ', preview token: ' . $this->preview_token);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -248,7 +266,7 @@ class PhotoPrism
|
||||
* Fetches albums from PhotoPrism which can be viewed with the provided tokens
|
||||
|
||||
* @throws NetworkException on failure
|
||||
* @param string[] $tokens -A list of tokens by which the albms are filtered
|
||||
* @param string[] $tokens -A list of tokens by which the albums are filtered
|
||||
* @param int $count -Maximum amount of albums to fetch
|
||||
* @param int $offset -Number of albums to skip
|
||||
* @return Album[]
|
||||
@ -272,6 +290,25 @@ class PhotoPrism
|
||||
return $visibleAlbums;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches an album from PhotoPrism which can be viewed with the provided token
|
||||
|
||||
* @throws NetworkException on failure
|
||||
* @param string $token -A token by which the albums are filtered
|
||||
* @return Album|null
|
||||
*/
|
||||
public function getAlbumByToken(string $token): ?Album
|
||||
{
|
||||
$this->logger->debug('getAlbumByToken');
|
||||
$albums = $this->getAlbumsByTokens([$token]);
|
||||
if (empty($albums)) {
|
||||
$this->logger->debug('Could not find album for token' . $token);
|
||||
return null;
|
||||
}
|
||||
$this->logger->debug('getAlbumByToken done');
|
||||
return $albums[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the secret token of an album
|
||||
|
||||
@ -326,4 +363,48 @@ class PhotoPrism
|
||||
$res = $this->makeRequest('POST', $import_url, $import_data);
|
||||
$this->logger->info('Import result: ' . $res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the photos of an album
|
||||
|
||||
* @throws NetworkException on failure
|
||||
* @param Album $album - The album to which the photos should be loaded
|
||||
* @param int $count - How many photos should be loaded
|
||||
* @param int $offset - Offset for paging
|
||||
* @return Photo[] - Photos in the album
|
||||
*/
|
||||
public function getAlbumPhotos(Album $album, int $count = 60, int $offset = 0): array
|
||||
{
|
||||
$this->logger->debug('getAlbumPhotos');
|
||||
$data = [
|
||||
'album' => $album->uid,
|
||||
'count' => $count,
|
||||
'offset' => $offset
|
||||
];
|
||||
$res = $this->makeRequest('GET', '/photos', $data, 'text/plain');
|
||||
$response = json_decode($res, true);
|
||||
if (!empty($response['error'])) {
|
||||
throw new NetworkException($response['error']);
|
||||
}
|
||||
$this->logger->debug('getAlbumPhotos response');
|
||||
$photos = array_map(
|
||||
function ($entry) {
|
||||
$photo = new Photo($entry);
|
||||
$photo->thumbnail_token = $this->preview_token;
|
||||
return $photo;
|
||||
},
|
||||
$response
|
||||
);
|
||||
$this->logger->info('Got photos:' . json_encode($photos));
|
||||
$photos = array_filter($photos, function ($obj) {
|
||||
static $idList = array();
|
||||
if (in_array($obj->uid, $idList)) {
|
||||
return false;
|
||||
}
|
||||
$idList []= $obj->uid;
|
||||
return true;
|
||||
});
|
||||
$this->logger->info('unique photos:' . json_encode($photos));
|
||||
return $photos;
|
||||
}
|
||||
}
|
||||
|
63
src/Entities/Photo.php
Normal file
63
src/Entities/Photo.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
namespace PhotoPrismUpload\Entities;
|
||||
|
||||
use PhotoPrismUpload\API\LoggerFactory;
|
||||
|
||||
/** A PhotoPrism Photo */
|
||||
class Photo
|
||||
{
|
||||
|
||||
/** @var string $thumbnail_token Token for fetching the thumbnail*/
|
||||
public string $thumbnail_token = '';
|
||||
|
||||
/** @var string $uid Unique Id of the photo */
|
||||
public string $uid = '';
|
||||
|
||||
/** @var string $id Id of the photo */
|
||||
public int $id = 0;
|
||||
|
||||
/** @var string $type Type of the photo (image, video, etc) */
|
||||
public string $type = '';
|
||||
|
||||
public string $fileUID;
|
||||
public string $fileRoot;
|
||||
public string $fileName;
|
||||
public string $hash;
|
||||
public int $width;
|
||||
public int $height;
|
||||
|
||||
public array $files;
|
||||
|
||||
/**
|
||||
* Creates a new photo from the api response
|
||||
*
|
||||
* @param array $response Photoprism API response containing a photo object
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
array $response
|
||||
) {
|
||||
$this->uid = $response['UID'];
|
||||
$this->id = intval($response['ID']);
|
||||
$this->type = $response['Type'];
|
||||
$this->fileUID = $response['FileUID'];
|
||||
$this->fileRoot = $response['FileRoot'];
|
||||
$this->fileName = $response['FileName'];
|
||||
$this->hash = $response['Hash'];
|
||||
$this->width = intval($response['Width']);
|
||||
$this->height = intval($response['Height']);
|
||||
$this->logger = LoggerFactory::create('PhotoPrismUpload.Photo');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the thumbnail URL path for this image.
|
||||
* Starts with a leading /
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getThumbnailUrl(string $size = 'tile_500'): string
|
||||
{
|
||||
return "/t/{$this->hash}/{$this->thumbnail_token}/{$size}";
|
||||
}
|
||||
}
|
110
vote-gallery.php
Normal file
110
vote-gallery.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
/** require autoloading to manage namespaces */
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
use PhotoPrismUpload\API\PhotoPrism;
|
||||
use PhotoPrismUpload\Entities\Album;
|
||||
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<title>Collagen Abstimmung</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<script src="vote.js"></script>
|
||||
<link href="vote.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<?php
|
||||
|
||||
$footer = '</body></html><footer style="position: fixed;bottom: 0;left: 0;">'
|
||||
.'<a href="/git/phlaym/photoprismupload">Ich bin Open Source</a></footer>';
|
||||
|
||||
/** @var array $config configuration options */
|
||||
$config = require(__DIR__ . '/config.php');
|
||||
|
||||
/** @var PhotoPrism $api API object to interface with PhotoPrism */
|
||||
$api = new PhotoPrism($config);
|
||||
|
||||
/** @var Album[] $albums List of PhotoPrism albums */
|
||||
$albums = [];
|
||||
try {
|
||||
$api->login();
|
||||
} catch (\Exception $e) {
|
||||
die('Fehler: ' . $e->getMessage().$footer.'</body></html>');
|
||||
}
|
||||
|
||||
/** @var string $token Tokens for which album(s) are visible in the dropdown */
|
||||
$token = $_GET['token'];
|
||||
|
||||
/** @var int $page Page number of photos to load */
|
||||
$page = intval($_GET['page'] ?? 1);
|
||||
|
||||
/** @var int $count Number of pictures to load */
|
||||
$count = intval($_GET['count'] ?? 50);
|
||||
|
||||
/** @var int $offset Tokens for which album(s) are visible in the dropdown */
|
||||
$offset = ($page - 1) * $count;
|
||||
|
||||
/** @var string $album_url URL path to the selected album */
|
||||
$album_url = '/';
|
||||
|
||||
$page_sizes = array_values(array_unique([10, 20, 50, 100, $count]));
|
||||
sort($page_sizes);
|
||||
$link_class = $page === 1 ? 'pageLink disabled' : 'pageLink';
|
||||
|
||||
try {
|
||||
$album = $api->getAlbumByToken($token);
|
||||
if ($album === null) {
|
||||
die('Album nicht gefunden' . $footer . '</body></html>');
|
||||
}
|
||||
$photos = $api->getAlbumPhotos($album, $count, $offset);
|
||||
?>
|
||||
<div>
|
||||
<input type="text" placeholder="Name" name="name" id="nameInput" style="margin: 0 0 0 8px">
|
||||
<button onclick="loadVotes()">OK</button>
|
||||
<a class="<?=$link_class?>" href="vote-gallery.php?token=<?=$token?>&count=<?=$count?>&page=1"><<</a>
|
||||
<a class="<?=$link_class?>" href="vote-gallery.php?token=<?=$token?>&count=<?=$count?>&page=<?=$page-1?>"><</a>
|
||||
Seite <?=$page?>
|
||||
<a class="pageLink" href="vote-gallery.php?token=<?=$token?>&count=<?=$count?>&page=<?=$page+1?>">></a>
|
||||
<select>
|
||||
<?php
|
||||
foreach ($page_sizes as $current_page_size) {
|
||||
$selected_string = $current_page_size === $count ? 'selected' : '';
|
||||
echo '<option '.$selected_string.'>'.$current_page_size.'</option>';
|
||||
}
|
||||
?>
|
||||
</select> pro Seite
|
||||
</div>
|
||||
<?php
|
||||
foreach ($photos as $photo) {
|
||||
$thumb = $photo->getThumbnailUrl();?>
|
||||
<div class="photowrapper">
|
||||
<img src="<?= $api->api_url.$thumb?>" id="<?= $photo->uid?>">
|
||||
<div class="votewrapper">
|
||||
<button value="1" onclick="vote(this)" class="voteButton" data-uid="<?= $photo->uid?>" disabled>
|
||||
👍 Dafür
|
||||
</button>
|
||||
<button value="0" onclick="vote(this)" class="voteButton" data-uid="<?= $photo->uid?>" disabled>
|
||||
😶 Neutral
|
||||
</button>
|
||||
<button value="-1" onclick="vote(this)" class="voteButton" data-uid="<?= $photo->uid?>" disabled>
|
||||
👎 Dagegen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
die('Fehler: ' . $footer . $e->getMessage() . '</body></html>');
|
||||
}
|
||||
?>
|
||||
<div>
|
||||
<a class="<?=$link_class?>" href="vote-gallery.php?token=<?=$token?>&count=<?=$count?>&page=1"><<</a>
|
||||
<a class="<?=$link_class?>" href="vote-gallery.php?token=<?=$token?>&count=<?=$count?>&page=<?=$page-1?>"><</a>
|
||||
Seite <?=$page?>
|
||||
<a class="pageLink" href="vote-gallery.php?token=<?=$token?>&count=<?=$count?>&page=<?=$page+1?>">></a>
|
||||
</div>
|
52
vote.css
Normal file
52
vote.css
Normal file
@ -0,0 +1,52 @@
|
||||
:root {
|
||||
--main-bg-color: white;
|
||||
--main-text-color: #333333;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--main-bg-color: #333333;
|
||||
--main-text-color: white;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--main-bg-color);
|
||||
color: var(--main-text-color);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Oxygen-Sans, Ubuntu,
|
||||
Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", Arial, sans-serif;
|
||||
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.photowrapper {
|
||||
margin: 8px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.votewrapper {
|
||||
margin: auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
a.disabled, a.disabled:visited {
|
||||
pointer-events: none;
|
||||
color: rgb(163, 163, 163);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.pageLink {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.pageLink:visited {
|
||||
color: rgb(195, 0, 255);
|
||||
}
|
41
vote.js
Normal file
41
vote.js
Normal file
@ -0,0 +1,41 @@
|
||||
async function vote(button) {
|
||||
console.log(button);
|
||||
const name = document.getElementById('nameInput').value;
|
||||
const data = new FormData();
|
||||
data.append("name", name);
|
||||
data.append("vote", button.value);
|
||||
data.append("uid", button.dataset.uid);
|
||||
const response = await fetch('vote.php', { method: "POST", body: data });
|
||||
button.disabled = true;
|
||||
button.parentElement
|
||||
.querySelectorAll('.voteButton')
|
||||
.forEach(b => {
|
||||
b.disabled = b.value === button.value;
|
||||
});
|
||||
}
|
||||
|
||||
async function loadVotes() {
|
||||
const name = document.getElementById('nameInput').value;
|
||||
localStorage.setItem('name', name);
|
||||
const response = await fetch('vote.php?' + new URLSearchParams({
|
||||
name: name
|
||||
}));
|
||||
const result = await response.json();
|
||||
console.log(result);
|
||||
document
|
||||
.querySelectorAll('.voteButton')
|
||||
.forEach(b => {
|
||||
b.disabled = b.dataset.uid in result && b.value == result[b.dataset.uid];
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', async (event) => {
|
||||
console.log('DOMContentLoaded');
|
||||
const loadedName = localStorage.getItem('name');
|
||||
console.log(loadedName);
|
||||
if (loadedName) {
|
||||
const nameInput = document.getElementById('nameInput');
|
||||
nameInput.value = loadedName;
|
||||
await loadVotes();
|
||||
}
|
||||
});
|
30
vote.php
Normal file
30
vote.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
$votes_file = 'votes.json';
|
||||
|
||||
if (isset($_GET['name'])) {
|
||||
$name = $_GET['name'];
|
||||
$contents = file_get_contents($votes_file);
|
||||
if ($contents === false) {
|
||||
$contents = '{}';
|
||||
}
|
||||
$contents = json_decode($contents, true);
|
||||
$data = $contents[$name] ?? [];
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
die(json_encode($data));
|
||||
} elseif (isset($_POST['name']) && isset($_POST['uid']) && isset($_POST['vote'])) {
|
||||
$name = $_POST['name'];
|
||||
$contents = file_get_contents($votes_file);
|
||||
if ($contents === false) {
|
||||
$contents = '{}';
|
||||
}
|
||||
$contents = json_decode($contents, true);
|
||||
$data = $contents[$name] ?? [];
|
||||
$data[$_POST['uid']] = $_POST['vote'];
|
||||
$contents[$name] = $data;
|
||||
file_put_contents($votes_file, json_encode($contents));
|
||||
header('HTTP/1.1 204 No Content');
|
||||
die();
|
||||
} else {
|
||||
header('HTTP/1.1 400 Bad Request');
|
||||
die();
|
||||
}
|
1
votes.json
Normal file
1
votes.json
Normal file
@ -0,0 +1 @@
|
||||
{"":{"pra15px12nephjox":"1"},"Max":{"pra15px12nephjox":"1","pra15pf3bal4owcz":"-1","pra15oq302x3jkuz":"1","pra15nj2z2ludgom":"1","pr354wv3w00i7czq":"1","pr354x42wpbkkg7m":"1","pr354z62mo0pncoz":"1","pr9mmge3mws6j0rw":"1","pr354yv3323z8b3z":"1","pr354wnz5nl70u4v":"1","pr354we11aqlpp4w":"1","pr354v03myo2bo7b":"1","pr354v63s8rslcv9":"1","pr354vp2ac5w1475":"1","pr354vs27id73evj":"1","pr354vwa8rws201t":"1","pra15okcu3t5ob18":"-1","pra15no38usadrog":"1","pr354x99sy2hweha":"-1","pr354wz2t3pdxu96":"1"},"Tanja":{"pra15px12nephjox":"-1","pra15pu3vm33tk8q":"-1","pra15pn12aqtap4o":"0","pra15pf3bal4owcz":"-1","pra15p92aj8kop1p":"0","pra15p43fyu1terq":"1","pra15ox3hmtsdz3l":"-1","pra15oq302x3jkuz":"1","pra15okcu3t5ob18":"0","pra15od10vgdxzrb":"1","pra15o6zv5tgetvk":"-1","pra15nz2zm6knku7":"-1","pra15nuvxk0zmeh9":"-1","pra15no38usadrog":"-1","pra15nj2z2ludgom":"1","pra15nd3ov8vazx7":"1","pra15n3y8fe0petq":"-1","pra15mw24h20rl1a":"1","pr9mmge3mws6j0rw":"1","pr354z62mo0pncoz":"-1","pr354z11al5w7r7g":"-1","pr354yv3323z8b3z":"-1","pr354yn28trvqtyy":"-1","pr354yi4avhp502d":"-1","pr354yc26ml4vbae":"-1","pr354y8edf9t34mj":"1","pr354y14maa7029f":"1","pr354xy2bhnte2gq":"-1","pr354xvtxuexra59":"1","pr354xl3gvk4amup":"-1","pr354xc1yyqjiciw":"-1","pr354x99sy2hweha":"-1","pr354x42wpbkkg7m":"1","pr354wz2t3pdxu96":"1","pr354wv3w00i7czq":"1","pr354wr25rtuux68":"1","pr354wnz5nl70u4v":"1","pr354wj2ph8qjcwg":"1","pr354we11aqlpp4w":"-1","pr354w93pprqutov":"-1","pr354w62c5g8t1po":"1","pr354vz2dnwjdm1r":"1","pr354vwa8rws201t":"-1","pr354vs27id73evj":"-1","pr354vp2ac5w1475":"1","pr354v63s8rslcv9":"0","pr354v03myo2bo7b":"0","pr354uovlc3coazv":"-1"},"Colin":{"pra15px12nephjox":"1","pra15pu3vm33tk8q":"-1","pra15pn12aqtap4o":"1","pra15pf3bal4owcz":"1","pra15p92aj8kop1p":"1","pra15p43fyu1terq":"0","pra15ox3hmtsdz3l":"0","pra15oq302x3jkuz":"1","pra15okcu3t5ob18":"0","pra15od10vgdxzrb":"1","pra15o6zv5tgetvk":"0","pra15nz2zm6knku7":"1","pra15nuvxk0zmeh9":"-1","pra15no38usadrog":"0","pra15nj2z2ludgom":"1","pra15nd3ov8vazx7":"1","pra15n3y8fe0petq":"-1","pra15mw24h20rl1a":"1","pr9mmge3mws6j0rw":"0","pr354z62mo0pncoz":"1","pr354z11al5w7r7g":"1","pr354yv3323z8b3z":"1","pr354yn28trvqtyy":"1","pr354yi4avhp502d":"1","pr354yc26ml4vbae":"1","pr354y8edf9t34mj":"1","pr354y14maa7029f":"1","pr354xy2bhnte2gq":"-1","pr354xvtxuexra59":"1","pr354xl3gvk4amup":"-1","pr354xc1yyqjiciw":"-1","pr354x99sy2hweha":"-1","pr354x42wpbkkg7m":"1","pr354wz2t3pdxu96":"0","pr354wv3w00i7czq":"1","pr354wr25rtuux68":"1","pr354wnz5nl70u4v":"0","pr354wj2ph8qjcwg":"0","pr354we11aqlpp4w":"-1","pr354w93pprqutov":"-1","pr354w62c5g8t1po":"0","pr354vz2dnwjdm1r":"1","pr354vwa8rws201t":"0","pr354vs27id73evj":"1","pr354vp2ac5w1475":"1","pr354v63s8rslcv9":"1","pr354v03myo2bo7b":"1","pr354uovlc3coazv":"1"},"Claraaa":{"pra15px12nephjox":"1","pra15pu3vm33tk8q":"0","pra15pn12aqtap4o":"1","pra15pf3bal4owcz":"1","pra15p92aj8kop1p":"1","pra15p43fyu1terq":"1","pra15ox3hmtsdz3l":"1","pra15oq302x3jkuz":"1","pra15okcu3t5ob18":"0","pra15od10vgdxzrb":"1","pra15o6zv5tgetvk":"-1","pra15nz2zm6knku7":"1","pra15nuvxk0zmeh9":"0","pra15no38usadrog":"0","pra15nj2z2ludgom":"1","pra15nd3ov8vazx7":"1","pra15n3y8fe0petq":"-1","pra15mw24h20rl1a":"0","pr9mmge3mws6j0rw":"0","pr354z62mo0pncoz":"1","pr354z11al5w7r7g":"1","pr354yv3323z8b3z":"1","pr354yn28trvqtyy":"0","pr354yi4avhp502d":"0","pr354yc26ml4vbae":"1","pr354y8edf9t34mj":"0","pr354y14maa7029f":"1","pr354xy2bhnte2gq":"0","pr354xvtxuexra59":"1","pr354xl3gvk4amup":"0","pr354xc1yyqjiciw":"0","pr354x99sy2hweha":"0","pr354x42wpbkkg7m":"1","pr354wv3w00i7czq":"1","pr354wz2t3pdxu96":"1","pr354wr25rtuux68":"1","pr354wnz5nl70u4v":"1"}}
|
Loading…
Reference in New Issue
Block a user