Merge pull request #126 from shikorism/develop

Release 20190307.2250
This commit is contained in:
shibafu 2019-03-07 22:51:27 +09:00 committed by GitHub
commit 03fcc424d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
89 changed files with 6455 additions and 9286 deletions

67
.circleci/config.yml Normal file
View File

@ -0,0 +1,67 @@
version: 2
jobs:
build:
docker:
- image: circleci/php:7.1-node-browsers
environment:
APP_DEBUG: true
APP_ENV: testing
APP_KEY: base64:f2tcw34GKT8EOtb5myZxJ8QLdgNivmyPhoQIPY2YfK8=
DB_CONNECTION: pgsql
DB_DATABASE: tissue
DB_USERNAME: tissue
DB_PASSWORD: tissue
- image: circleci/postgres:10-alpine
environment:
POSTGRES_DB: tissue
POSTGRES_USER: tissue
POSTGRES_PASSWORD: tissue
steps:
- checkout
- run: sudo apt update
- run: sudo apt install -y libpq-dev
- run: sudo docker-php-ext-install zip
- run: sudo docker-php-ext-install pdo_pgsql
- restore_cache:
keys:
- v1-dependencies-{{ checksum "composer.json" }}
- v1-dependencies-
- run: composer install -n --prefer-dist
- save_cache:
key: v1-dependencies-{{ checksum "composer.json" }}
paths:
- ./vendor
- restore_cache:
keys:
- v1-dependencies-{{ checksum "package.json" }}
- v1-dependencies-
- run: yarn install
- save_cache:
key: v1-dependencies-{{ checksum "package.json" }}
paths:
- ./node_modules
- ~/.yarn
- run: php artisan migrate
- run: yarn run prod
# Run linter
- run:
command: |
mkdir -p /tmp/php-cs-fixer
./vendor/bin/php-cs-fixer fix --dry-run --diff --format=junit > /tmp/php-cs-fixer/php-cs-fixer.xml
when: always
- store_test_results:
path: /tmp/php-cs-fixer
# Run unit test
- run:
command: |
mkdir -p /tmp/phpunit
./vendor/bin/phpunit --log-junit /tmp/phpunit/phpunit.xml
when: always
- store_test_results:
path: /tmp/phpunit

8
.gitignore vendored
View File

@ -1,6 +1,10 @@
/node_modules /node_modules
/public/css
/public/fonts
/public/js
/public/hot /public/hot
/public/storage /public/storage
/public/mix-manifest.json
/storage/*.key /storage/*.key
/vendor /vendor
/.idea /.idea
@ -12,4 +16,6 @@ yarn-error.log
.env .env
*.iml *.iml
.php_cs .php_cs
.php_cs.cache .php_cs.cache
.phpstorm.meta.php
_ide_helper*.php

View File

@ -0,0 +1,53 @@
<?php
namespace App\Http\Controllers\Api;
use App\Metadata;
use App\MetadataResolver\MetadataResolver;
use App\Utilities\Formatter;
use Illuminate\Http\Request;
class CardController
{
/**
* @var MetadataResolver
*/
private $resolver;
/**
* @var Formatter
*/
private $formatter;
public function __construct(MetadataResolver $resolver, Formatter $formatter)
{
$this->resolver = $resolver;
$this->formatter = $formatter;
}
public function show(Request $request)
{
$request->validate([
'url:required|url'
]);
$url = $this->formatter->normalizeUrl($request->input('url'));
$metadata = Metadata::find($url);
if ($metadata === null || ($metadata->expires_at !== null && $metadata->expires_at < now())) {
$resolved = $this->resolver->resolve($url);
$metadata = Metadata::updateOrCreate(['url' => $url], [
'title' => $resolved->title,
'description' => $resolved->description,
'image' => $resolved->image,
'expires_at' => $resolved->expires_at
]);
}
$response = response($metadata);
if (!config('app.debug')) {
$response = $response->setCache(['public' => true, 'max_age' => 86400]);
}
return $response;
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Http\Controllers;
use App\Ejaculation;
use Illuminate\Http\Request;
class TimelineController extends Controller
{
public function showPublic()
{
$ejaculations = Ejaculation::join('users', 'users.id', '=', 'ejaculations.user_id')
->where('users.is_protected', false)
->where('ejaculations.is_private', false)
->where('ejaculations.link', '<>', '')
->orderBy('ejaculations.ejaculated_date', 'desc')
->select('ejaculations.*')
->with('user', 'tags')
->paginate(21);
return view('timeline.public')->with(compact('ejaculations'));
}
}

View File

@ -11,7 +11,10 @@ use Illuminate\Support\Facades\DB;
class UserController extends Controller class UserController extends Controller
{ {
// public function redirectMypage()
{
return redirect()->route('user.profile', ['name' => auth()->user()->name]);
}
public function profile($name) public function profile($name)
{ {
@ -124,8 +127,19 @@ SQL
$hour = (int)$data->hour; $hour = (int)$data->hour;
$hourlySum[$hour] += $data->count; $hourlySum[$hour] += $data->count;
} }
$graphData = [
'dailySum' => $dailySum,
'dowSum' => $dowSum,
'monthlyKey' => array_keys($monthlySum),
'monthlySum' => array_values($monthlySum),
'yearlyKey' => array_keys($yearlySum),
'yearlySum' => array_values($yearlySum),
'hourlyKey' => array_keys($hourlySum),
'hourlySum' => array_values($hourlySum),
];
return view('user.stats')->with(compact('user', 'dailySum', 'monthlySum', 'yearlySum', 'dowSum', 'hourlySum')); return view('user.stats')->with(compact('user', 'graphData'));
} }
public function okazu($name) public function okazu($name)

View File

@ -18,6 +18,7 @@ class Kernel extends HttpKernel
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class, \App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
]; ];
/** /**

View File

@ -0,0 +1,29 @@
<?php
namespace App\Http\Middleware;
use Fideloper\Proxy\TrustProxies as Middleware;
use Illuminate\Http\Request;
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* @var array
*/
protected $proxies = '**';
/**
* The current proxy header mappings.
*
* @var array
*/
protected $headers = [
Request::HEADER_FORWARDED => 'FORWARDED',
Request::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR',
Request::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST',
Request::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT',
Request::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO',
];
}

View File

@ -21,7 +21,8 @@ class LinkCollector
/** /**
* Create the event listener. * Create the event listener.
* *
* @return void * @param Formatter $formatter
* @param MetadataResolver $metadataResolver
*/ */
public function __construct(Formatter $formatter, MetadataResolver $metadataResolver) public function __construct(Formatter $formatter, MetadataResolver $metadataResolver)
{ {

View File

@ -2,9 +2,9 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Exception\TransferException; use GuzzleHttp\Exception\TransferException;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Psr\Http\Message\ResponseInterface;
class ActivityPubResolver implements Resolver, Parser class ActivityPubResolver implements Resolver, Parser
{ {
@ -40,7 +40,7 @@ class ActivityPubResolver implements Resolver, Parser
$metadata = new Metadata(); $metadata = new Metadata();
$metadata->title = isset($object['attributedTo']) ? $this->getTitleFromActor($object['attributedTo']) : ''; $metadata->title = isset($object['attributedTo']) ? $this->getTitleFromActor($object['attributedTo']) : '';
$metadata->description .= isset($object['summary']) ? $object['summary'] . " | " : ''; $metadata->description .= isset($object['summary']) ? $object['summary'] . ' | ' : '';
$metadata->description .= isset($object['content']) ? $this->html2text($object['content']) : ''; $metadata->description .= isset($object['content']) ? $this->html2text($object['content']) : '';
$metadata->image = $object['attachment'][0]['url'] ?? ''; $metadata->image = $object['attachment'][0]['url'] ?? '';
@ -53,6 +53,7 @@ class ActivityPubResolver implements Resolver, Parser
$res = $this->activityClient->get($url); $res = $this->activityClient->get($url);
if ($res->getStatusCode() !== 200) { if ($res->getStatusCode() !== 200) {
Log::info(self::class . ': Actorの取得に失敗 URL=' . $url); Log::info(self::class . ': Actorの取得に失敗 URL=' . $url);
return ''; return '';
} }
@ -65,6 +66,7 @@ class ActivityPubResolver implements Resolver, Parser
return $title; return $title;
} catch (TransferException $e) { } catch (TransferException $e) {
Log::info(self::class . ': Actorの取得に失敗 URL=' . $url); Log::info(self::class . ': Actorの取得に失敗 URL=' . $url);
return ''; return '';
} }
} }
@ -75,6 +77,7 @@ class ActivityPubResolver implements Resolver, Parser
$html = preg_replace('~<br\s*/?\s*>|</p>\s*<p[^>]*>~i', "\n", $html); $html = preg_replace('~<br\s*/?\s*>|</p>\s*<p[^>]*>~i', "\n", $html);
$dom = new \DOMDocument(); $dom = new \DOMDocument();
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); $dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
return $dom->textContent; return $dom->textContent;
} }
} }

View File

@ -3,16 +3,30 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use Carbon\Carbon; use Carbon\Carbon;
use GuzzleHttp\Client;
class CienResolver extends MetadataResolver class CienResolver extends MetadataResolver
{ {
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata public function resolve(string $url): Metadata
{ {
$client = new \GuzzleHttp\Client(); $res = $this->client->get($url);
$res = $client->get($url);
if ($res->getStatusCode() === 200) { if ($res->getStatusCode() === 200) {
$ogpResolver = new OGPResolver(); $metadata = $this->ogpResolver->parse($res->getBody());
$metadata = $ogpResolver->parse($res->getBody());
// 画像URLから有効期限の起点を拾う // 画像URLから有効期限の起点を拾う
parse_str(parse_url($metadata->image, PHP_URL_QUERY), $params); parse_str(parse_url($metadata->image, PHP_URL_QUERY), $params);

View File

@ -2,16 +2,31 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use GuzzleHttp\Client;
class DLsiteResolver implements Resolver class DLsiteResolver implements Resolver
{ {
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata public function resolve(string $url): Metadata
{ {
$client = new \GuzzleHttp\Client(); $res = $this->client->get($url);
$res = $client->get($url);
if ($res->getStatusCode() === 200) { if ($res->getStatusCode() === 200) {
$ogpResolver = new OGPResolver(); $metadata = $this->ogpResolver->parse($res->getBody());
$metadata = $ogpResolver->parse($res->getBody()); $metadata->image = str_replace('img_sam.jpg', 'img_main.jpg', $metadata->image);
$metadata->image = str_replace('img_sam.jpg', 'img_main.jpg', $metadata->image);
return $metadata; return $metadata;
} else { } else {

View File

@ -2,15 +2,30 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use GuzzleHttp\Client;
class DeviantArtResolver implements Resolver class DeviantArtResolver implements Resolver
{ {
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata public function resolve(string $url): Metadata
{ {
$client = new \GuzzleHttp\Client(); $res = $this->client->get($url);
$res = $client->get($url);
if ($res->getStatusCode() === 200) { if ($res->getStatusCode() === 200) {
$ogpResolver = new OGPResolver(); $metadata = $this->ogpResolver->parse($res->getBody());
$metadata = $ogpResolver->parse($res->getBody());
$dom = new \DOMDocument(); $dom = new \DOMDocument();
@$dom->loadHTML(mb_convert_encoding($res->getBody(), 'HTML-ENTITIES', 'UTF-8')); @$dom->loadHTML(mb_convert_encoding($res->getBody(), 'HTML-ENTITIES', 'UTF-8'));

View File

@ -2,20 +2,34 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
class FantiaResolver implements Resolver class FantiaResolver implements Resolver
{ {
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata public function resolve(string $url): Metadata
{ {
preg_match("~\d+~", $url, $match); preg_match("~\d+~", $url, $match);
$postId = $match[0]; $postId = $match[0];
$client = new \GuzzleHttp\Client(); $res = $this->client->get($url);
$res = $client->get($url);
if ($res->getStatusCode() === 200) { if ($res->getStatusCode() === 200) {
$ogpResolver = new OGPResolver(); $metadata = $this->ogpResolver->parse($res->getBody());
$metadata = $ogpResolver->parse($res->getBody());
$dom = new \DOMDocument(); $dom = new \DOMDocument();
@$dom->loadHTML(mb_convert_encoding($res->getBody(), 'HTML-ENTITIES', 'UTF-8')); @$dom->loadHTML(mb_convert_encoding($res->getBody(), 'HTML-ENTITIES', 'UTF-8'));

View File

@ -2,16 +2,31 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use GuzzleHttp\Client;
class FanzaResolver implements Resolver class FanzaResolver implements Resolver
{ {
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata public function resolve(string $url): Metadata
{ {
$client = new \GuzzleHttp\Client(); $res = $this->client->get($url);
$res = $client->get($url);
if ($res->getStatusCode() === 200) { if ($res->getStatusCode() === 200) {
$ogpResolver = new OGPResolver(); $metadata = $this->ogpResolver->parse($res->getBody());
$metadata = $ogpResolver->parse($res->getBody()); $metadata->image = preg_replace("~(pr|ps)\.jpg$~", 'pl.jpg', $metadata->image);
$metadata->image = preg_replace("~(pr|ps)\.jpg$~", 'pl.jpg', $metadata->image);
return $metadata; return $metadata;
} else { } else {

View File

@ -2,12 +2,24 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use GuzzleHttp\Client;
class IwaraResolver implements Resolver class IwaraResolver implements Resolver
{ {
/**
* @var Client
*/
private $client;
public function __construct(Client $client)
{
$this->client = $client;
}
public function resolve(string $url): Metadata public function resolve(string $url): Metadata
{ {
$client = new \GuzzleHttp\Client(); $res = $this->client->get($url);
$res = $client->get($url);
if ($res->getStatusCode() === 200) { if ($res->getStatusCode() === 200) {
$dom = new \DOMDocument(); $dom = new \DOMDocument();
@$dom->loadHTML(mb_convert_encoding($res->getBody(), 'HTML-ENTITIES', 'UTF-8')); @$dom->loadHTML(mb_convert_encoding($res->getBody(), 'HTML-ENTITIES', 'UTF-8'));

View File

@ -2,8 +2,20 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use GuzzleHttp\Client;
class KomifloResolver implements Resolver class KomifloResolver implements Resolver
{ {
/**
* @var Client
*/
private $client;
public function __construct(Client $client)
{
$this->client = $client;
}
public function resolve(string $url): Metadata public function resolve(string $url): Metadata
{ {
if (preg_match('~komiflo\.com(?:/#!)?/comics/(\\d+)~', $url, $matches) !== 1) { if (preg_match('~komiflo\.com(?:/#!)?/comics/(\\d+)~', $url, $matches) !== 1) {
@ -11,8 +23,7 @@ class KomifloResolver implements Resolver
} }
$id = $matches[1]; $id = $matches[1];
$client = new \GuzzleHttp\Client(); $res = $this->client->get('https://api.komiflo.com/content/id/' . $id);
$res = $client->get('https://api.komiflo.com/content/id/' . $id);
if ($res->getStatusCode() === 200) { if ($res->getStatusCode() === 200) {
$json = json_decode($res->getBody()->getContents(), true); $json = json_decode($res->getBody()->getContents(), true);
$metadata = new Metadata(); $metadata = new Metadata();
@ -21,6 +32,7 @@ class KomifloResolver implements Resolver
$metadata->description = ($json['content']['attributes']['artists']['children'][0]['data']['name'] ?? '?') . $metadata->description = ($json['content']['attributes']['artists']['children'][0]['data']['name'] ?? '?') .
' - ' . ' - ' .
($json['content']['parents'][0]['data']['title'] ?? '?'); ($json['content']['parents'][0]['data']['title'] ?? '?');
$metadata->image = 'https://t.komiflo.com/564_mobile_large_3x/' . $json['content']['named_imgs']['cover']['filename'];
return $metadata; return $metadata;
} else { } else {

View File

@ -2,19 +2,33 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar; use GuzzleHttp\Cookie\CookieJar;
class MelonbooksResolver implements Resolver class MelonbooksResolver implements Resolver
{ {
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata public function resolve(string $url): Metadata
{ {
$cookieJar = CookieJar::fromArray(['AUTH_ADULT' => '1'], 'www.melonbooks.co.jp'); $cookieJar = CookieJar::fromArray(['AUTH_ADULT' => '1'], 'www.melonbooks.co.jp');
$client = new \GuzzleHttp\Client(); $res = $this->client->get($url, ['cookies' => $cookieJar]);
$res = $client->get($url, ['cookies' => $cookieJar]);
if ($res->getStatusCode() === 200) { if ($res->getStatusCode() === 200) {
$ogpResolver = new OGPResolver(); $metadata = $this->ogpResolver->parse($res->getBody());
$metadata = $ogpResolver->parse($res->getBody());
// censoredフラグの除去 // censoredフラグの除去
if (mb_strpos($metadata->image, '&c=1') !== false) { if (mb_strpos($metadata->image, '&c=1') !== false) {

View File

@ -2,6 +2,7 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException; use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ServerException; use GuzzleHttp\Exception\ServerException;
@ -37,7 +38,8 @@ class MetadataResolver implements Resolver
{ {
foreach ($this->rules as $pattern => $class) { foreach ($this->rules as $pattern => $class) {
if (preg_match($pattern, $url) === 1) { if (preg_match($pattern, $url) === 1) {
$resolver = new $class(); /** @var Resolver $resolver */
$resolver = app($class);
return $resolver->resolve($url); return $resolver->resolve($url);
} }
@ -49,13 +51,15 @@ class MetadataResolver implements Resolver
} }
if (isset($this->defaultResolver)) { if (isset($this->defaultResolver)) {
$resolver = new $this->defaultResolver(); /** @var Resolver $resolver */
$resolver = app($this->defaultResolver);
return $resolver->resolve($url); return $resolver->resolve($url);
} }
throw new \UnexpectedValueException('URL not matched.'); throw new \UnexpectedValueException('URL not matched.');
} }
public function resolveWithAcceptHeader(string $url): ?Metadata public function resolveWithAcceptHeader(string $url): ?Metadata
{ {
try { try {
@ -65,7 +69,7 @@ class MetadataResolver implements Resolver
// Acceptヘッダには */* を足さないことにする。 // Acceptヘッダには */* を足さないことにする。
$acceptTypes = array_diff(array_keys($this->mimeTypes), ['*/*']); $acceptTypes = array_diff(array_keys($this->mimeTypes), ['*/*']);
$client = new \GuzzleHttp\Client(); $client = app(Client::class);
$res = $client->request('GET', $url, [ $res = $client->request('GET', $url, [
'headers' => [ 'headers' => [
'Accept' => implode(', ', $acceptTypes) 'Accept' => implode(', ', $acceptTypes)
@ -78,14 +82,14 @@ class MetadataResolver implements Resolver
if (isset($this->mimeTypes[$mimeType])) { if (isset($this->mimeTypes[$mimeType])) {
$class = $this->mimeTypes[$mimeType]; $class = $this->mimeTypes[$mimeType];
$parser = new $class(); $parser = app($class);
return $parser->parse($res->getBody()); return $parser->parse($res->getBody());
} }
if (isset($this->mimeTypes['*/*'])) { if (isset($this->mimeTypes['*/*'])) {
$class = $this->mimeTypes['*/*']; $class = $this->mimeTypes['*/*'];
$parser = new $class(); $parser = app($class);
return $parser->parse($res->getBody()); return $parser->parse($res->getBody());
} }

View File

@ -2,19 +2,33 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar; use GuzzleHttp\Cookie\CookieJar;
class NarouResolver implements Resolver class NarouResolver implements Resolver
{ {
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata public function resolve(string $url): Metadata
{ {
$cookieJar = CookieJar::fromArray(['over18' => 'yes'], '.syosetu.com'); $cookieJar = CookieJar::fromArray(['over18' => 'yes'], '.syosetu.com');
$client = new \GuzzleHttp\Client(); $res = $this->client->get($url, ['cookies' => $cookieJar]);
$res = $client->get($url, ['cookies' => $cookieJar]);
if ($res->getStatusCode() === 200) { if ($res->getStatusCode() === 200) {
$ogpResolver = new OGPResolver(); $metadata = $this->ogpResolver->parse($res->getBody());
$metadata = $ogpResolver->parse($res->getBody());
$metadata->description = ''; $metadata->description = '';
$dom = new \DOMDocument(); $dom = new \DOMDocument();

View File

@ -2,15 +2,30 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use GuzzleHttp\Client;
class NicoSeigaResolver implements Resolver class NicoSeigaResolver implements Resolver
{ {
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata public function resolve(string $url): Metadata
{ {
$client = new \GuzzleHttp\Client(); $res = $this->client->get($url);
$res = $client->get($url);
if ($res->getStatusCode() === 200) { if ($res->getStatusCode() === 200) {
$ogpResolver = new OGPResolver(); $metadata = $this->ogpResolver->parse($res->getBody());
$metadata = $ogpResolver->parse($res->getBody());
// ページURLからサムネイルURLに変換 // ページURLからサムネイルURLに変換
preg_match('~http://(?:(?:sp\\.)?seiga\\.nicovideo\\.jp/seiga(?:/#!)?|nico\\.ms)/im(\\d+)~', $url, $matches); preg_match('~http://(?:(?:sp\\.)?seiga\\.nicovideo\\.jp/seiga(?:/#!)?|nico\\.ms)/im(\\d+)~', $url, $matches);

View File

@ -2,8 +2,25 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use GuzzleHttp\Client;
class NijieResolver implements Resolver class NijieResolver implements Resolver
{ {
/**
* @var Client
*/
protected $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata public function resolve(string $url): Metadata
{ {
if (mb_strpos($url, '//sp.nijie.info') !== false) { if (mb_strpos($url, '//sp.nijie.info') !== false) {
@ -13,11 +30,10 @@ class NijieResolver implements Resolver
$url = preg_replace('~view_popup\.php~', 'view.php', $url); $url = preg_replace('~view_popup\.php~', 'view.php', $url);
} }
$client = new \GuzzleHttp\Client(); $client = $this->client;
$res = $client->get($url); $res = $client->get($url);
if ($res->getStatusCode() === 200) { if ($res->getStatusCode() === 200) {
$ogpResolver = new OGPResolver(); $metadata = $this->ogpResolver->parse($res->getBody());
$metadata = $ogpResolver->parse($res->getBody());
$dom = new \DOMDocument(); $dom = new \DOMDocument();
@$dom->loadHTML(mb_convert_encoding($res->getBody(), 'HTML-ENTITIES', 'UTF-8')); @$dom->loadHTML(mb_convert_encoding($res->getBody(), 'HTML-ENTITIES', 'UTF-8'));

View File

@ -2,12 +2,23 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use GuzzleHttp\Client;
class OGPResolver implements Resolver, Parser class OGPResolver implements Resolver, Parser
{ {
/**
* @var Client
*/
private $client;
public function __construct(Client $client)
{
$this->client = $client;
}
public function resolve(string $url): Metadata public function resolve(string $url): Metadata
{ {
$client = new \GuzzleHttp\Client(); $res = $this->client->get($url);
$res = $client->get($url);
if ($res->getStatusCode() === 200) { if ($res->getStatusCode() === 200) {
return $this->parse($res->getBody()); return $this->parse($res->getBody());
} else { } else {

View File

@ -5,4 +5,4 @@ namespace App\MetadataResolver;
interface Parser interface Parser
{ {
public function parse(string $body): Metadata; public function parse(string $body): Metadata;
} }

View File

@ -3,19 +3,33 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use Carbon\Carbon; use Carbon\Carbon;
use GuzzleHttp\Client;
class PatreonResolver implements Resolver class PatreonResolver implements Resolver
{ {
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata public function resolve(string $url): Metadata
{ {
$client = new \GuzzleHttp\Client(); $res = $this->client->get($url);
$res = $client->get($url);
if ($res->getStatusCode() === 200) { if ($res->getStatusCode() === 200) {
$ogpResolver = new OGPResolver(); $metadata = $this->ogpResolver->parse($res->getBody());
$metadata = $ogpResolver->parse($res->getBody());
parse_str(parse_url($metadata->image, PHP_URL_QUERY), $temp); parse_str(parse_url($metadata->image, PHP_URL_QUERY), $temp);
$expires_at_unixtime = $temp["token-time"]; $expires_at_unixtime = $temp['token-time'];
$expires_at = Carbon::createFromTimestamp($expires_at_unixtime); $expires_at = Carbon::createFromTimestamp($expires_at_unixtime);
$metadata->expires_at = $expires_at; $metadata->expires_at = $expires_at;

View File

@ -2,8 +2,25 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use GuzzleHttp\Client;
class PixivResolver implements Resolver class PixivResolver implements Resolver
{ {
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
/** /**
* サムネイル画像 URL から最大長辺 1200px の画像 URL に変換する * サムネイル画像 URL から最大長辺 1200px の画像 URL に変換する
* *
@ -36,6 +53,7 @@ class PixivResolver implements Resolver
{ {
parse_str(parse_url($url, PHP_URL_QUERY), $params); parse_str(parse_url($url, PHP_URL_QUERY), $params);
$illustId = $params['illust_id']; $illustId = $params['illust_id'];
$page = 0;
// 漫画ページページ数はmanga_bigならあるかも // 漫画ページページ数はmanga_bigならあるかも
if ($params['mode'] === 'manga_big' || $params['mode'] === 'manga') { if ($params['mode'] === 'manga_big' || $params['mode'] === 'manga') {
@ -45,15 +63,17 @@ class PixivResolver implements Resolver
$url = preg_replace('~mode=manga(_big)?~', 'mode=medium', $url); $url = preg_replace('~mode=manga(_big)?~', 'mode=medium', $url);
} }
$client = new \GuzzleHttp\Client(); $res = $this->client->get($url);
$res = $client->get($url);
if ($res->getStatusCode() === 200) { if ($res->getStatusCode() === 200) {
$ogpResolver = new OGPResolver(); $metadata = $this->ogpResolver->parse($res->getBody());
$metadata = $ogpResolver->parse($res->getBody());
preg_match("~https://i\.pximg\.net/c/128x128/img-master/img/\d{4}/\d{2}/\d{2}/\d{2}/\d{2}/\d{2}/{$illustId}(_p0)?_square1200\.jpg~", $res->getBody(), $match); preg_match("~https://i\.pximg\.net/c/128x128/img-master/img/\d{4}/\d{2}/\d{2}/\d{2}/\d{2}/\d{2}/{$illustId}(_p0)?_square1200\.jpg~", $res->getBody(), $match);
$illustThumbnailUrl = $match[0]; $illustThumbnailUrl = $match[0];
if ($page != 0) {
$illustThumbnailUrl = str_replace('_p0', '_p'.$page, $illustThumbnailUrl);
}
$illustUrl = $this->thumbnailToMasterUrl($illustThumbnailUrl); $illustUrl = $this->thumbnailToMasterUrl($illustThumbnailUrl);
$metadata->image = $this->proxize($illustUrl); $metadata->image = $this->proxize($illustUrl);

View File

@ -2,20 +2,33 @@
namespace App\MetadataResolver; namespace App\MetadataResolver;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar; use GuzzleHttp\Cookie\CookieJar;
class ToranoanaResolver implements Resolver class ToranoanaResolver implements Resolver
{ {
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
public function resolve(string $url): Metadata public function resolve(string $url): Metadata
{ {
$cookieJar = CookieJar::fromArray(['adflg' => '0'], 'ec.toranoana.jp'); $cookieJar = CookieJar::fromArray(['adflg' => '0'], 'ec.toranoana.jp');
$client = new \GuzzleHttp\Client(); $res = $this->client->get($url, ['cookies' => $cookieJar]);
$res = $client->get($url, ['cookies' => $cookieJar]);
if ($res->getStatusCode() === 200) { if ($res->getStatusCode() === 200) {
$ogpResolver = new OGPResolver(); return $this->ogpResolver->parse($res->getBody());
return $ogpResolver->parse($res->getBody());
} else { } else {
throw new \RuntimeException("{$res->getStatusCode()}: $url"); throw new \RuntimeException("{$res->getStatusCode()}: $url");
} }

View File

@ -16,6 +16,7 @@
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-debugbar": "^3.1", "barryvdh/laravel-debugbar": "^3.1",
"barryvdh/laravel-ide-helper": "^2.5",
"filp/whoops": "~2.0", "filp/whoops": "~2.0",
"friendsofphp/php-cs-fixer": "^2.14", "friendsofphp/php-cs-fixer": "^2.14",
"fzaninotto/faker": "~1.4", "fzaninotto/faker": "~1.4",

485
composer.lock generated
View File

@ -1,10 +1,10 @@
{ {
"_readme": [ "_readme": [
"This file locks the dependencies of your project to a known state", "This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "9a0efd1b396f7a748eee3b98cbd7b6a6", "content-hash": "79423bebbfa31e28aab2d06ba7e19828",
"packages": [ "packages": [
{ {
"name": "anhskohbo/no-captcha", "name": "anhskohbo/no-captcha",
@ -3045,6 +3045,265 @@
], ],
"time": "2018-11-09T08:37:55+00:00" "time": "2018-11-09T08:37:55+00:00"
}, },
{
"name": "barryvdh/laravel-ide-helper",
"version": "v2.5.3",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-ide-helper.git",
"reference": "3d7f1240896a075aa23b13f82dfcbe165dadeef2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/3d7f1240896a075aa23b13f82dfcbe165dadeef2",
"reference": "3d7f1240896a075aa23b13f82dfcbe165dadeef2",
"shasum": ""
},
"require": {
"barryvdh/reflection-docblock": "^2.0.6",
"composer/composer": "^1.6",
"illuminate/console": "^5.5,<5.8",
"illuminate/filesystem": "^5.5,<5.8",
"illuminate/support": "^5.5,<5.8",
"php": ">=7"
},
"require-dev": {
"doctrine/dbal": "~2.3",
"illuminate/config": "^5.1,<5.8",
"illuminate/view": "^5.1,<5.8",
"phpro/grumphp": "^0.14",
"phpunit/phpunit": "4.*",
"scrutinizer/ocular": "~1.1",
"squizlabs/php_codesniffer": "^3"
},
"suggest": {
"doctrine/dbal": "Load information from the database about models for phpdocs (~2.3)"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.5-dev"
},
"laravel": {
"providers": [
"Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Barryvdh\\LaravelIdeHelper\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "Laravel IDE Helper, generates correct PHPDocs for all Facade classes, to improve auto-completion.",
"keywords": [
"autocomplete",
"codeintel",
"helper",
"ide",
"laravel",
"netbeans",
"phpdoc",
"phpstorm",
"sublime"
],
"time": "2018-12-19T12:12:05+00:00"
},
{
"name": "barryvdh/reflection-docblock",
"version": "v2.0.6",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/ReflectionDocBlock.git",
"reference": "6b69015d83d3daf9004a71a89f26e27d27ef6a16"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/6b69015d83d3daf9004a71a89f26e27d27ef6a16",
"reference": "6b69015d83d3daf9004a71a89f26e27d27ef6a16",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.0,<4.5"
},
"suggest": {
"dflydev/markdown": "~1.0",
"erusev/parsedown": "~1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Barryvdh": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mike van Riel",
"email": "mike.vanriel@naenius.com"
}
],
"time": "2018-12-13T10:34:14+00:00"
},
{
"name": "composer/ca-bundle",
"version": "1.1.4",
"source": {
"type": "git",
"url": "https://github.com/composer/ca-bundle.git",
"reference": "558f321c52faeb4828c03e7dc0cfe39a09e09a2d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/558f321c52faeb4828c03e7dc0cfe39a09e09a2d",
"reference": "558f321c52faeb4828c03e7dc0cfe39a09e09a2d",
"shasum": ""
},
"require": {
"ext-openssl": "*",
"ext-pcre": "*",
"php": "^5.3.2 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5",
"psr/log": "^1.0",
"symfony/process": "^2.5 || ^3.0 || ^4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\CaBundle\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.",
"keywords": [
"cabundle",
"cacert",
"certificate",
"ssl",
"tls"
],
"time": "2019-01-28T09:30:10+00:00"
},
{
"name": "composer/composer",
"version": "1.8.4",
"source": {
"type": "git",
"url": "https://github.com/composer/composer.git",
"reference": "bc364c2480c17941e2135cfc568fa41794392534"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/composer/zipball/bc364c2480c17941e2135cfc568fa41794392534",
"reference": "bc364c2480c17941e2135cfc568fa41794392534",
"shasum": ""
},
"require": {
"composer/ca-bundle": "^1.0",
"composer/semver": "^1.0",
"composer/spdx-licenses": "^1.2",
"composer/xdebug-handler": "^1.1",
"justinrainbow/json-schema": "^3.0 || ^4.0 || ^5.0",
"php": "^5.3.2 || ^7.0",
"psr/log": "^1.0",
"seld/jsonlint": "^1.4",
"seld/phar-utils": "^1.0",
"symfony/console": "^2.7 || ^3.0 || ^4.0",
"symfony/filesystem": "^2.7 || ^3.0 || ^4.0",
"symfony/finder": "^2.7 || ^3.0 || ^4.0",
"symfony/process": "^2.7 || ^3.0 || ^4.0"
},
"conflict": {
"symfony/console": "2.8.38"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7",
"phpunit/phpunit-mock-objects": "^2.3 || ^3.0"
},
"suggest": {
"ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages",
"ext-zip": "Enabling the zip extension allows you to unzip archives",
"ext-zlib": "Allow gzip compression of HTTP requests"
},
"bin": [
"bin/composer"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\": "src/Composer"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nils Adermann",
"email": "naderman@naderman.de",
"homepage": "http://www.naderman.de"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "Composer helps you declare, manage and install dependencies of PHP projects, ensuring you have the right stack everywhere.",
"homepage": "https://getcomposer.org/",
"keywords": [
"autoload",
"dependency",
"package"
],
"time": "2019-02-11T09:52:10+00:00"
},
{ {
"name": "composer/semver", "name": "composer/semver",
"version": "1.4.2", "version": "1.4.2",
@ -3107,6 +3366,67 @@
], ],
"time": "2016-08-30T16:08:34+00:00" "time": "2016-08-30T16:08:34+00:00"
}, },
{
"name": "composer/spdx-licenses",
"version": "1.5.0",
"source": {
"type": "git",
"url": "https://github.com/composer/spdx-licenses.git",
"reference": "7a9556b22bd9d4df7cad89876b00af58ef20d3a2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/spdx-licenses/zipball/7a9556b22bd9d4df7cad89876b00af58ef20d3a2",
"reference": "7a9556b22bd9d4df7cad89876b00af58ef20d3a2",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5",
"phpunit/phpunit-mock-objects": "2.3.0 || ^3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\Spdx\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nils Adermann",
"email": "naderman@naderman.de",
"homepage": "http://www.naderman.de"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
},
{
"name": "Rob Bast",
"email": "rob.bast@gmail.com",
"homepage": "http://robbast.nl"
}
],
"description": "SPDX licenses list and validation library.",
"keywords": [
"license",
"spdx",
"validator"
],
"time": "2018-11-01T09:45:54+00:00"
},
{ {
"name": "composer/xdebug-handler", "name": "composer/xdebug-handler",
"version": "1.3.1", "version": "1.3.1",
@ -3528,6 +3848,72 @@
], ],
"time": "2016-01-20T08:20:44+00:00" "time": "2016-01-20T08:20:44+00:00"
}, },
{
"name": "justinrainbow/json-schema",
"version": "5.2.8",
"source": {
"type": "git",
"url": "https://github.com/justinrainbow/json-schema.git",
"reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/dcb6e1006bb5fd1e392b4daa68932880f37550d4",
"reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2.2.20",
"json-schema/json-schema-test-suite": "1.2.0",
"phpunit/phpunit": "^4.8.35"
},
"bin": [
"bin/validate-json"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0.x-dev"
}
},
"autoload": {
"psr-4": {
"JsonSchema\\": "src/JsonSchema/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Bruno Prieto Reis",
"email": "bruno.p.reis@gmail.com"
},
{
"name": "Justin Rainbow",
"email": "justin.rainbow@gmail.com"
},
{
"name": "Igor Wiedler",
"email": "igor@wiedler.ch"
},
{
"name": "Robert Schönthal",
"email": "seroscho@googlemail.com"
}
],
"description": "A library to validate a json schema.",
"homepage": "https://github.com/justinrainbow/json-schema",
"keywords": [
"json",
"schema"
],
"time": "2019-01-14T23:55:14+00:00"
},
{ {
"name": "maximebf/debugbar", "name": "maximebf/debugbar",
"version": "v1.15.0", "version": "v1.15.0",
@ -5021,6 +5407,99 @@
"homepage": "https://github.com/sebastianbergmann/version", "homepage": "https://github.com/sebastianbergmann/version",
"time": "2016-10-03T07:35:21+00:00" "time": "2016-10-03T07:35:21+00:00"
}, },
{
"name": "seld/jsonlint",
"version": "1.7.1",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/jsonlint.git",
"reference": "d15f59a67ff805a44c50ea0516d2341740f81a38"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/d15f59a67ff805a44c50ea0516d2341740f81a38",
"reference": "d15f59a67ff805a44c50ea0516d2341740f81a38",
"shasum": ""
},
"require": {
"php": "^5.3 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
},
"bin": [
"bin/jsonlint"
],
"type": "library",
"autoload": {
"psr-4": {
"Seld\\JsonLint\\": "src/Seld/JsonLint/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "JSON Linter",
"keywords": [
"json",
"linter",
"parser",
"validator"
],
"time": "2018-01-24T12:46:19+00:00"
},
{
"name": "seld/phar-utils",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/phar-utils.git",
"reference": "7009b5139491975ef6486545a39f3e6dad5ac30a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/7009b5139491975ef6486545a39f3e6dad5ac30a",
"reference": "7009b5139491975ef6486545a39f3e6dad5ac30a",
"shasum": ""
},
"require": {
"php": ">=5.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Seld\\PharUtils\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be"
}
],
"description": "PHAR file format utilities, for when PHP phars you up",
"keywords": [
"phra"
],
"time": "2015-10-13T18:44:15+00:00"
},
{ {
"name": "symfony/filesystem", "name": "symfony/filesystem",
"version": "v4.2.2", "version": "v4.2.2",
@ -5370,7 +5849,7 @@
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
"php": ">=7.0.0" "php": ">=7.1.0"
}, },
"platform-dev": [] "platform-dev": []
} }

View File

@ -1,8 +1,8 @@
<?php <?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddBioAndUrlToUsers extends Migration class AddBioAndUrlToUsers extends Migration
{ {

View File

@ -0,0 +1,10 @@
version: "3"
services:
mailcatcher:
image: schickling/mailcatcher
ports:
- 1080:1080
networks:
- backend

View File

@ -10,12 +10,18 @@
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
}, },
"devDependencies": { "devDependencies": {
"axios": "^0.16.2", "bootstrap": "^4.2.1",
"bootstrap-sass": "^3.3.7", "cal-heatmap": "^3.3.10",
"cross-env": "^5.0.1", "chart.js": "^2.7.1",
"jquery": "^3.1.1", "cross-env": "^5.2.0",
"laravel-mix": "^1.0", "jquery": "^3.2.1",
"lodash": "^4.17.4", "js-cookie": "^2.2.0",
"vue": "^2.1.10" "laravel-mix": "^4.0.0",
"open-iconic": "^1.1.1",
"popper.js": "^1.14.7",
"resolve-url-loader": "^2.3.1",
"sass": "^1.17.0",
"sass-loader": "^7.1.0",
"vue-template-compiler": "^2.6.6"
} }
} }

BIN
public/apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

5
public/css/app.css vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,8 +0,0 @@
/*!
* Bootstrap Reboot v4.1.1 (https://getbootstrap.com/)
* Copyright 2011-2018 The Bootstrap Authors
* Copyright 2011-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.min.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 0 B

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

Binary file not shown.

View File

@ -1,543 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<!--
2014-7-1: Created.
-->
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>
Created by FontForge 20120731 at Tue Jul 1 20:39:22 2014
By P.J. Onori
Created by P.J. Onori with FontForge 2.0 (http://fontforge.sf.net)
</metadata>
<defs>
<font id="open-iconic" horiz-adv-x="800" >
<font-face
font-family="Icons"
font-weight="400"
font-stretch="normal"
units-per-em="800"
panose-1="2 0 5 3 0 0 0 0 0 0"
ascent="800"
descent="0"
bbox="-0.5 -101 802 800.126"
underline-thickness="50"
underline-position="-100"
unicode-range="U+E000-E0DE"
/>
<missing-glyph />
<glyph glyph-name="" unicode="&#xe000;"
d="M300 700h500v-700h-500v100h400v500h-400v100zM400 500l200 -150l-200 -150v100h-400v100h400v100z" />
<glyph glyph-name="1" unicode="&#xe001;"
d="M300 700h500v-700h-500v100h400v500h-400v100zM200 500v-100h400v-100h-400v-100l-200 150z" />
<glyph glyph-name="2" unicode="&#xe002;"
d="M350 700c193 0 350 -157 350 -350v-50h100l-200 -200l-200 200h100v50c0 138 -112 250 -250 250s-250 -112 -250 -250c0 193 157 350 350 350z" />
<glyph glyph-name="3" unicode="&#xe003;"
d="M450 700c193 0 350 -157 350 -350c0 138 -112 250 -250 250s-250 -112 -250 -250v-50h100l-200 -200l-200 200h100v50c0 193 157 350 350 350z" />
<glyph glyph-name="4" unicode="&#xe004;"
d="M0 700h800v-100h-800v100zM100 500h600v-100h-600v100zM0 300h800v-100h-800v100zM100 100h600v-100h-600v100z" />
<glyph glyph-name="5" unicode="&#xe005;"
d="M0 700h800v-100h-800v100zM0 500h600v-100h-600v100zM0 300h800v-100h-800v100zM0 100h600v-100h-600v100z" />
<glyph glyph-name="6" unicode="&#xe006;"
d="M0 700h800v-100h-800v100zM200 500h600v-100h-600v100zM0 300h800v-100h-800v100zM200 100h600v-100h-600v100z" />
<glyph glyph-name="7" unicode="&#xe007;"
d="M400 700c75 0 146 -23 206 -59l-75 -225l-322 234c57 31 122 50 191 50zM125 588l191 -138l-310 -222c-4 24 -6 47 -6 72c0 114 49 215 125 288zM688 575c69 -72 112 -168 112 -275c0 -35 -8 -68 -16 -100h-218zM216 253l112 -347c-128 23 -232 109 -287 222zM372 100
h372c-64 -109 -177 -185 -310 -197z" />
<glyph glyph-name="8" unicode="&#xe008;" horiz-adv-x="600"
d="M200 800h100v-500h200l-247 -300l-253 300h200v500z" />
<glyph glyph-name="9" unicode="&#xe009;"
d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM300 700v-300h-200l300 -300l300 300h-200v300h-200z" />
<glyph glyph-name="a" unicode="&#xe00a;"
d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM400 700l-300 -300l300 -300v200h300v200h-300v200z" />
<glyph glyph-name="b" unicode="&#xe00b;"
d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM400 700v-200h-300v-200h300v-200l300 300z" />
<glyph glyph-name="c" unicode="&#xe00c;"
d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM400 700l-300 -300h200v-300h200v300h200z" />
<glyph glyph-name="d" unicode="&#xe00d;"
d="M300 600v-200h500v-100h-500v-200l-300 247z" />
<glyph glyph-name="e" unicode="&#xe00e;"
d="M500 600l300 -247l-300 -253v200h-500v100h500v200z" />
<glyph glyph-name="f" unicode="&#xe00f;" horiz-adv-x="600"
d="M200 800h200v-500h200l-297 -300l-303 300h200v500z" />
<glyph glyph-name="10" unicode="&#xe010;"
d="M300 700v-200h500v-200h-500v-200l-300 297z" />
<glyph glyph-name="11" unicode="&#xe011;"
d="M500 700l300 -297l-300 -303v200h-500v200h500v200z" />
<glyph glyph-name="12" unicode="&#xe012;" horiz-adv-x="600"
d="M297 800l303 -300h-200v-500h-200v500h-200z" />
<glyph glyph-name="13" unicode="&#xe013;" horiz-adv-x="600"
d="M247 800l253 -300h-200v-500h-100v500h-200z" />
<glyph glyph-name="14" unicode="&#xe014;"
d="M400 800h100v-800h-100v800zM200 700h100v-600h-100v600zM600 600h100v-400h-100v400zM0 500h100v-200h-100v200z" />
<glyph glyph-name="15" unicode="&#xe015;"
d="M116 600l72 -72c-54 -54 -88 -126 -88 -209s34 -159 88 -213l-72 -72c-72 72 -116 175 -116 285s44 209 116 281zM684 600c72 -72 116 -171 116 -281s-44 -213 -116 -285l-72 72c54 54 88 130 88 213s-34 155 -88 209zM259 460l69 -72c-18 -18 -28 -41 -28 -69
s10 -54 28 -72l-69 -72c-36 36 -59 89 -59 144s23 105 59 141zM541 459c36 -36 59 -85 59 -140s-23 -108 -59 -144l-69 72c18 18 28 44 28 72s-10 51 -28 69z" />
<glyph glyph-name="16" unicode="&#xe016;" horiz-adv-x="400"
d="M200 800c110 0 200 -90 200 -200s-90 -200 -200 -200s-200 90 -200 200s90 200 200 200zM100 319c31 -11 65 -19 100 -19s68 8 100 19v-319l-100 100l-100 -100v319z" />
<glyph glyph-name="17" unicode="&#xe017;"
d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700c-166 0 -300 -134 -300 -300c0 -66 21 -126 56 -175l419 419c-49 35 -109 56 -175 56zM644 575l-419 -419c49 -35 109 -56 175 -56c166 0 300 134 300 300
c0 66 -21 126 -56 175z" />
<glyph glyph-name="18" unicode="&#xe018;"
d="M0 700h100v-600h700v-100h-800v700zM500 700h200v-500h-200v500zM200 500h200v-300h-200v300z" />
<glyph glyph-name="19" unicode="&#xe019;"
d="M397 800c13 1 23 -4 34 -13c2 -2 214 -254 241 -287h128v-100h-100v-366c0 -18 -16 -34 -34 -34h-532c-18 0 -34 16 -34 34v366h-100v100h128l234 281c9 11 22 18 35 19zM400 672l-144 -172h288zM250 300c-28 0 -50 -22 -50 -50v-100c0 -28 22 -50 50 -50s50 22 50 50
v100c0 28 -22 50 -50 50zM550 300c-28 0 -50 -22 -50 -50v-100c0 -28 22 -50 50 -50s50 22 50 50v100c0 28 -22 50 -50 50z" />
<glyph glyph-name="1a" unicode="&#xe01a;"
d="M9 700h682c6 0 9 -4 9 -10v-190h100v-200h-100v-191c0 -6 -3 -9 -9 -9h-682c-6 0 -9 3 -9 9v582c0 6 3 9 9 9zM100 600v-400h500v400h-500z" />
<glyph glyph-name="1b" unicode="&#xe01b;"
d="M9 700h682c6 0 9 -4 9 -10v-190h100v-200h-100v-191c0 -6 -3 -9 -9 -9h-682c-6 0 -9 3 -9 9v582c0 6 3 9 9 9z" />
<glyph glyph-name="1c" unicode="&#xe01c;"
d="M92 650c0 23 19 50 45 50h3h5h5h500c28 0 50 -22 50 -50s-22 -50 -50 -50h-50v-141c9 -17 120 -231 166 -309c16 -26 34 -61 34 -106c0 -39 -15 -77 -41 -103h-3c-26 -25 -62 -41 -100 -41h-512c-39 0 -77 15 -103 41s-41 64 -41 103c0 46 18 80 34 106
c46 78 157 292 166 309v141h-50c-2 0 -6 -1 -8 -1c-28 0 -50 23 -50 51zM500 600h-200v-162l-6 -10s-63 -123 -119 -228h450c-56 105 -119 228 -119 228l-6 10v162z" />
<glyph glyph-name="1d" unicode="&#xe01d;"
d="M400 800c110 0 200 -90 200 -200c0 -104 52 -198 134 -266c41 -34 66 -82 66 -134h-800c0 52 25 100 66 134c82 68 134 162 134 266c0 110 90 200 200 200zM300 100h200c0 -55 -45 -100 -100 -100s-100 45 -100 100z" />
<glyph glyph-name="1e" unicode="&#xe01e;" horiz-adv-x="600"
d="M150 800h50l350 -250l-225 -147l225 -153l-350 -250h-50v250l-75 -75l-75 75l150 150l-150 150l75 75l75 -75v250zM250 650v-200l150 100zM250 350v-200l150 100z" />
<glyph glyph-name="1f" unicode="&#xe01f;"
d="M0 800h500c110 0 200 -90 200 -200c0 -47 -17 -91 -44 -125c85 -40 144 -125 144 -225c0 -138 -112 -250 -250 -250h-550v100c55 0 100 45 100 100v400c0 55 -45 100 -100 100v100zM300 700v-200h100c55 0 100 45 100 100s-45 100 -100 100h-100zM300 400v-300h150
c83 0 150 67 150 150s-67 150 -150 150h-150z" />
<glyph glyph-name="20" unicode="&#xe020;" horiz-adv-x="600"
d="M300 800v-300h200l-300 -500v300h-200z" />
<glyph glyph-name="21" unicode="&#xe021;"
d="M100 800h300v-300l100 100l100 -100v300h50c28 0 50 -22 50 -50v-550h-550c-28 0 -50 -22 -50 -50s22 -50 50 -50h550v-100h-550c-83 0 -150 67 -150 150v550l3 19c8 39 39 70 78 78z" />
<glyph glyph-name="22" unicode="&#xe022;" horiz-adv-x="400"
d="M0 800h400v-800l-200 200l-200 -200v800z" />
<glyph glyph-name="23" unicode="&#xe023;"
d="M0 800h800v-100h-800v100zM0 600h300v-103h203v103h297v-591c0 -6 -3 -9 -9 -9h-782c-6 0 -9 3 -9 9v591z" />
<glyph glyph-name="24" unicode="&#xe024;"
d="M300 800h200c55 0 100 -45 100 -100v-100h191c6 0 9 -3 9 -9v-241c0 -28 -22 -50 -50 -50h-700c-28 0 -50 22 -50 50v241c0 6 3 9 9 9h191v100c0 55 45 100 100 100zM300 700v-100h200v100h-200zM0 209c16 -6 32 -9 50 -9h700c18 0 34 3 50 9v-200c0 -6 -3 -9 -9 -9h-782
c-6 0 -9 3 -9 9v200z" />
<glyph glyph-name="25" unicode="&#xe025;" horiz-adv-x="600"
d="M300 800c58 0 110 -16 147 -53s53 -89 53 -147h-100c0 39 -11 61 -25 75s-36 25 -75 25c-35 0 -55 -10 -72 -31s-28 -55 -28 -94c0 -51 20 -107 28 -175h172v-100h-178c-14 -60 -49 -127 -113 -200h491v-100h-600v122l16 12c69 69 95 121 106 166h-122v100h125
c-8 50 -25 106 -25 175c0 58 16 114 50 156c34 43 88 69 150 69z" />
<glyph glyph-name="26" unicode="&#xe026;"
d="M34 700h4h3h4h5h700c28 0 50 -22 50 -50v-700c0 -28 -22 -50 -50 -50h-700c-28 0 -50 22 -50 50v700v2c0 20 15 42 34 48zM150 600c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50zM350 600c-28 0 -50 -22 -50 -50s22 -50 50 -50h300c28 0 50 22 50 50
s-22 50 -50 50h-300zM100 400v-400h600v400h-600z" />
<glyph glyph-name="27" unicode="&#xe027;"
d="M744 797l6 -3l44 -44c4 -4 3 -8 0 -12l-266 -375l-15 -13l-25 -12c-23 72 -78 127 -150 150l12 25l13 15l375 266zM266 400c74 0 134 -60 134 -134c0 -147 -119 -266 -266 -266c-48 0 -95 12 -134 34c80 46 134 133 134 232c0 74 58 134 132 134z" />
<glyph glyph-name="28" unicode="&#xe028;"
d="M9 451c0 23 19 50 46 50c8 0 19 -3 26 -7l131 -66l29 22c-79 81 -1 250 118 250s197 -167 119 -250l28 -22l131 66c6 4 12 7 21 7c28 0 50 -22 50 -50c0 -17 -12 -37 -27 -45l-115 -56c9 -16 19 -33 25 -50h68c28 0 50 -22 50 -50s-22 -50 -50 -50h-50
c0 -23 -2 -45 -6 -66l78 -40c21 -5 37 -28 37 -49c0 -28 -22 -50 -50 -50c-10 0 -23 5 -31 11l-65 35c-24 -46 -62 -86 -103 -110c-35 19 -60 45 -60 72v135v4v5v6v5v5v87c0 28 -22 50 -50 50c-24 0 -45 -17 -50 -40c1 -3 1 -8 1 -11s0 -8 -1 -11v-82v-4v-5v-144
c0 -28 -24 -53 -59 -72c-41 25 -79 64 -103 110l-66 -35c-8 -6 -21 -11 -31 -11c-28 0 -50 22 -50 50c0 21 16 44 37 49l78 40c-4 21 -6 43 -6 66h-50h-5c-28 0 -50 22 -50 50c0 26 22 50 50 50h5h69c6 17 16 34 25 50l-116 56c-16 7 -28 27 -28 45z" />
<glyph glyph-name="29" unicode="&#xe029;"
d="M600 700h91c6 0 9 -3 9 -9v-582c0 -6 -3 -9 -9 -9h-91v600zM210 503l290 147v-500l-250 125v-3c-15 0 -25 -8 -28 -22l75 -178c11 -25 0 -58 -25 -69s-58 0 -69 25l-103 272h-91c-6 0 -9 3 -9 9v182c0 6 3 9 9 9h182z" />
<glyph glyph-name="2a" unicode="&#xe02a;"
d="M9 800h682c6 0 9 -3 9 -9v-782c0 -6 -3 -9 -9 -9h-682c-6 0 -9 3 -9 9v782c0 6 3 9 9 9zM100 700v-200h500v200h-500zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400v-300h100v300h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100z" />
<glyph glyph-name="2b" unicode="&#xe02b;"
d="M0 800h700v-200h-700v200zM0 500h700v-491c0 -6 -3 -9 -9 -9h-682c-6 0 -9 3 -9 9v491zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100z" />
<glyph glyph-name="2c" unicode="&#xe02c;"
d="M409 800h182c6 0 10 -4 12 -9l94 -182c2 -5 6 -9 12 -9h82c6 0 9 -3 9 -9v-582c0 -6 -3 -9 -9 -9h-782c-6 0 -9 3 -9 9v441c0 83 67 150 150 150h141c6 0 10 4 12 9l94 182c2 5 6 9 12 9zM150 500c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50z
M500 500c-110 0 -200 -90 -200 -200s90 -200 200 -200s200 90 200 200s-90 200 -200 200zM500 400c55 0 100 -45 100 -100s-45 -100 -100 -100s-100 45 -100 100s45 100 100 100z" />
<glyph glyph-name="2d" unicode="&#xe02d;"
d="M0 600h800l-400 -400z" />
<glyph glyph-name="2e" unicode="&#xe02e;" horiz-adv-x="400"
d="M400 800v-800l-400 400z" />
<glyph glyph-name="2f" unicode="&#xe02f;" horiz-adv-x="400"
d="M0 800l400 -400l-400 -400v800z" />
<glyph glyph-name="30" unicode="&#xe030;"
d="M400 600l400 -400h-800z" />
<glyph glyph-name="31" unicode="&#xe031;"
d="M0 550c0 23 20 50 46 50h3h5h4h200c17 0 37 -13 44 -28l38 -72h444c14 0 19 -12 15 -25l-81 -250c-4 -13 -21 -25 -35 -25h-350c-14 0 -30 12 -34 25c-27 83 -54 167 -81 250l-10 25h-150c-2 0 -5 -1 -7 -1c-28 0 -51 23 -51 51zM358 100c28 0 50 -22 50 -50
s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM658 100c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50z" />
<glyph glyph-name="32" unicode="&#xe032;"
d="M0 700h500v-100h-300v-300h-100l-100 -100v500zM300 500h500v-500l-100 100h-400v400z" />
<glyph glyph-name="33" unicode="&#xe033;"
d="M641 700l143 -141l-493 -493c-71 76 -146 148 -219 222l-72 71l141 141c50 -51 101 -101 153 -150c116 117 234 231 347 350z" />
<glyph glyph-name="34" unicode="&#xe034;"
d="M150 600l250 -250l250 250l150 -150l-400 -400l-400 400z" />
<glyph glyph-name="35" unicode="&#xe035;" horiz-adv-x="600"
d="M400 800l150 -150l-250 -250l250 -250l-150 -150l-400 400z" />
<glyph glyph-name="36" unicode="&#xe036;" horiz-adv-x="600"
d="M150 800l400 -400l-400 -400l-150 150l250 250l-250 250z" />
<glyph glyph-name="37" unicode="&#xe037;"
d="M400 600l400 -400l-150 -150l-250 250l-250 -250l-150 150z" />
<glyph glyph-name="38" unicode="&#xe038;"
d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM600 622l-250 -250l-100 100l-72 -72l172 -172l322 322z" />
<glyph glyph-name="39" unicode="&#xe039;"
d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM250 622l-72 -72l150 -150l-150 -150l72 -72l150 150l150 -150l72 72l-150 150l150 150l-72 72l-150 -150z" />
<glyph glyph-name="3a" unicode="&#xe03a;"
d="M350 800c28 0 50 -22 50 -50v-50h75c14 0 25 -11 25 -25v-75h-300v75c0 14 11 25 25 25h75v50c0 28 22 50 50 50zM25 700h75v-200h500v200h75c14 0 25 -11 25 -25v-650c0 -14 -11 -25 -25 -25h-650c-14 0 -25 11 -25 25v650c0 14 11 25 25 25z" />
<glyph glyph-name="3b" unicode="&#xe03b;"
d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700c-166 0 -300 -134 -300 -300s134 -300 300 -300s300 134 300 300s-134 300 -300 300zM350 600h100v-181c23 -24 47 -47 72 -69l-72 -72c-27 30 -55 59 -84 88l-16 12
v222z" />
<glyph glyph-name="3c" unicode="&#xe03c;"
d="M450 800c138 0 250 -112 250 -250v-50c58 -21 100 -85 100 -150c0 -18 -3 -34 -9 -50h-191v50c0 83 -67 150 -150 150s-150 -67 -150 -150v-50h-272c-17 30 -28 63 -28 100c0 110 90 200 200 200c23 114 129 200 250 200zM434 400h3h4c3 0 6 1 9 1c28 0 50 -22 50 -50v-1
v-150h150l-200 -200l-200 200h150v150v2c0 20 15 42 34 48z" />
<glyph glyph-name="3d" unicode="&#xe03d;"
d="M450 800c138 0 250 -112 250 -250v-50c58 -21 100 -85 100 -150c0 -18 -3 -34 -9 -50h-141l-200 200l-200 -200h-222c-17 30 -28 63 -28 100c0 110 90 200 200 200c23 114 129 200 250 200zM450 350l250 -250h-200v-50c0 -28 -22 -50 -50 -50s-50 22 -50 50v50h-200z" />
<glyph glyph-name="3e" unicode="&#xe03e;"
d="M450 700c138 0 250 -112 250 -250v-50c58 -21 100 -85 100 -150c0 -83 -67 -150 -150 -150h-450c-110 0 -200 90 -200 200s90 200 200 200c23 114 129 200 250 200z" />
<glyph glyph-name="3f" unicode="&#xe03f;"
d="M250 800c82 0 154 -40 200 -100c-143 0 -270 -85 -325 -209c-36 -10 -70 -25 -100 -47c-16 33 -25 67 -25 106c0 138 112 250 250 250zM450 600c138 0 250 -112 250 -250v-50c58 -21 100 -85 100 -150c0 -83 -67 -150 -150 -150h-450c-110 0 -200 90 -200 200
s90 200 200 200c23 114 129 200 250 200z" />
<glyph glyph-name="40" unicode="&#xe040;"
d="M500 700h100l-300 -600h-100zM100 600h100l-100 -200l100 -200h-100l-100 200zM600 600h100l100 -200l-100 -200h-100l100 200z" />
<glyph glyph-name="41" unicode="&#xe041;"
d="M350 800h100l50 -119l28 -12l119 50l72 -72l-50 -119l12 -28l119 -50v-100l-119 -50l-12 -28l50 -119l-72 -72l-119 50l-28 -12l-50 -119h-100l-50 119l-28 12l-119 -50l-72 72l50 119l-12 28l-119 50v100l119 50l12 28l-50 119l72 72l119 -50l28 12zM400 550
c-83 0 -150 -67 -150 -150s67 -150 150 -150s150 67 150 150s-67 150 -150 150z" />
<glyph glyph-name="42" unicode="&#xe042;"
d="M0 800h800v-200h-800v200zM200 500h400l-200 -200zM0 100h800v-100h-800v100z" />
<glyph glyph-name="43" unicode="&#xe043;"
d="M0 800h100v-800h-100v800zM600 800h200v-800h-200v800zM500 600v-400l-200 200z" />
<glyph glyph-name="44" unicode="&#xe044;"
d="M0 800h200v-800h-200v800zM700 800h100v-800h-100v800zM300 600l200 -200l-200 -200v400z" />
<glyph glyph-name="45" unicode="&#xe045;"
d="M0 800h800v-100h-800v100zM400 500l200 -200h-400zM0 200h800v-200h-800v200z" />
<glyph glyph-name="46" unicode="&#xe046;"
d="M150 700c83 0 150 -67 150 -150v-50h100v50c0 83 67 150 150 150s150 -67 150 -150s-67 -150 -150 -150h-50v-100h50c83 0 150 -67 150 -150s-67 -150 -150 -150s-150 67 -150 150v50h-100v-50c0 -83 -67 -150 -150 -150s-150 67 -150 150s67 150 150 150h50v100h-50
c-83 0 -150 67 -150 150s67 150 150 150zM150 600c-28 0 -50 -22 -50 -50s22 -50 50 -50h50v50c0 28 -22 50 -50 50zM550 600c-28 0 -50 -22 -50 -50v-50h50c28 0 50 22 50 50s-22 50 -50 50zM300 400v-100h100v100h-100zM150 200c-28 0 -50 -22 -50 -50s22 -50 50 -50
s50 22 50 50v50h-50zM500 200v-50c0 -28 22 -50 50 -50s50 22 50 50s-22 50 -50 50h-50z" />
<glyph glyph-name="47" unicode="&#xe047;"
d="M0 791c0 5 4 9 9 9h782c6 0 9 -4 9 -10v-790l-200 200h-591c-6 0 -9 3 -9 9v582z" />
<glyph glyph-name="48" unicode="&#xe048;"
d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700c-166 0 -300 -134 -300 -300s134 -300 300 -300s300 134 300 300s-134 300 -300 300zM600 600l-100 -300l-300 -100l100 300zM400 450c-28 0 -50 -22 -50 -50
s22 -50 50 -50s50 22 50 50s-22 50 -50 50z" />
<glyph glyph-name="49" unicode="&#xe049;"
d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700v-600c166 0 300 134 300 300s-134 300 -300 300z" />
<glyph glyph-name="4a" unicode="&#xe04a;"
d="M0 800h800v-100h-800v100zM0 600h500v-100h-500v100zM0 300h800v-100h-800v100zM0 100h600v-100h-600v100zM750 100c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50z" />
<glyph glyph-name="4b" unicode="&#xe04b;"
d="M25 700h750c14 0 25 -11 25 -25v-75h-800v75c0 14 11 25 25 25zM0 500h800v-375c0 -14 -11 -25 -25 -25h-750c-14 0 -25 11 -25 25v375zM100 300v-100h100v100h-100zM300 300v-100h100v100h-100z" />
<glyph glyph-name="4c" unicode="&#xe04c;"
d="M100 800h100v-100h450l100 100l50 -50l-100 -100v-450h100v-100h-100v-100h-100v100h-500v500h-100v100h100v100zM200 600v-350l350 350h-350zM600 550l-350 -350h350v350z" />
<glyph glyph-name="4d" unicode="&#xe04d;"
d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700c-166 0 -300 -134 -300 -300s134 -300 300 -300s300 134 300 300s-134 300 -300 300zM400 600c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50z
M200 452c0 20 15 42 34 48h3h3h8c12 0 28 -7 36 -16l91 -90l25 6c55 0 100 -45 100 -100s-45 -100 -100 -100s-100 45 -100 100l6 25l-90 91c-9 8 -16 24 -16 36zM550 500c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50z" />
<glyph glyph-name="4e" unicode="&#xe04e;"
d="M300 800h200v-300h200l-300 -300l-300 300h200v300zM0 100h800v-100h-800v100z" />
<glyph glyph-name="4f" unicode="&#xe04f;"
d="M0 800h800v-100h-800v100zM400 600l300 -300h-200v-300h-200v300h-200z" />
<glyph glyph-name="50" unicode="&#xe050;"
d="M200 700h600v-600h-600l-200 300zM350 622l-72 -72l150 -150l-150 -150l72 -72l150 150l150 -150l72 72l-150 150l150 150l-72 72l-150 -150z" />
<glyph glyph-name="51" unicode="&#xe051;"
d="M400 700c220 0 400 -180 400 -400h-100c0 166 -134 300 -300 300s-300 -134 -300 -300h-100c0 220 180 400 400 400zM341 491l59 -88l59 88c81 -25 141 -101 141 -191c0 -110 -90 -200 -200 -200s-200 90 -200 200c0 90 60 166 141 191z" />
<glyph glyph-name="52" unicode="&#xe052;"
d="M0 800h300v-400h400v-400h-700v800zM400 800l300 -300h-300v300zM100 600v-100h100v100h-100zM100 400v-100h100v100h-100zM100 200v-100h400v100h-400z" />
<glyph glyph-name="53" unicode="&#xe053;" horiz-adv-x="600"
d="M200 700h100v-100h75c30 0 58 -6 81 -22s44 -44 44 -78v-100h-100v94c-4 3 -13 6 -25 6h-250c-14 0 -25 -11 -25 -25v-50c0 -15 20 -40 34 -44l257 -65c66 -16 109 -73 109 -141v-50c0 -68 -57 -125 -125 -125h-75v-100h-100v100h-75c-30 0 -58 6 -81 22s-44 44 -44 78
v100h100v-94c4 -3 13 -6 25 -6h250c14 0 25 11 25 25v50c0 15 -20 40 -34 44l-257 65c-66 16 -109 73 -109 141v50c0 68 57 125 125 125h75v100z" />
<glyph glyph-name="54" unicode="&#xe054;"
d="M0 700h300v-300l-300 -300v600zM500 700h300v-300l-300 -300v600z" />
<glyph glyph-name="55" unicode="&#xe055;"
d="M300 700v-600h-300v300zM800 700v-600h-300v300z" />
<glyph glyph-name="56" unicode="&#xe056;"
d="M300 700v-100c-111 0 -200 -89 -200 -200h200v-300h-300v300c0 165 135 300 300 300zM800 700v-100c-111 0 -200 -89 -200 -200h200v-300h-300v300c0 165 135 300 300 300z" />
<glyph glyph-name="57" unicode="&#xe057;"
d="M0 700h300v-300c0 -165 -135 -300 -300 -300v100c111 0 200 89 200 200h-200v300zM500 700h300v-300c0 -165 -135 -300 -300 -300v100c111 0 200 89 200 200h-200v300z" />
<glyph glyph-name="58" unicode="&#xe058;" horiz-adv-x="600"
d="M300 800l34 -34c11 -11 266 -270 266 -488c0 -165 -135 -300 -300 -300s-300 135 -300 300c0 218 255 477 266 488zM150 328c-28 0 -50 -22 -50 -50c0 -110 90 -200 200 -200c28 0 50 22 50 50s-22 50 -50 50c-55 0 -100 45 -100 100c0 28 -22 50 -50 50z" />
<glyph glyph-name="59" unicode="&#xe059;"
d="M400 800l400 -500h-800zM0 200h800v-200h-800v200z" />
<glyph glyph-name="5a" unicode="&#xe05a;" horiz-adv-x="600"
d="M300 800l300 -300h-600zM0 300h600l-300 -300z" />
<glyph glyph-name="5b" unicode="&#xe05b;"
d="M0 500h200v-200h-200v200zM300 500h200v-200h-200v200zM600 500h200v-200h-200v200z" />
<glyph glyph-name="5c" unicode="&#xe05c;"
d="M0 700h800v-100l-400 -200l-400 200v100zM0 500l400 -200l400 200v-400h-800v400z" />
<glyph glyph-name="5d" unicode="&#xe05d;"
d="M400 800l400 -200v-600h-800v600zM400 688l-300 -150v-188l300 -150l300 150v188zM200 500h400v-100l-200 -100l-200 100v100z" />
<glyph glyph-name="5e" unicode="&#xe05e;"
d="M600 700c69 0 134 -19 191 -50l-16 -106c-49 35 -109 56 -175 56c-131 0 -240 -84 -281 -200h331l-16 -100h-334c0 -36 8 -68 19 -100h297l-16 -100h-222c55 -61 133 -100 222 -100c78 0 147 30 200 78v-122c-59 -35 -127 -56 -200 -56c-147 0 -274 82 -344 200h-256
l19 100h197c-8 32 -16 66 -16 100h-200l25 100h191c45 172 198 300 384 300z" />
<glyph glyph-name="5f" unicode="&#xe05f;"
d="M0 700h700v-100h-700v100zM0 500h500v-100h-500v100zM0 300h800v-100h-800v100zM0 100h100v-100h-100v100zM200 100h100v-100h-100v100zM400 100h100v-100h-100v100z" />
<glyph glyph-name="60" unicode="&#xe060;"
d="M0 800h800v-100h-800v100zM200 600h400l-200 -200zM0 200h800v-200h-800v200z" />
<glyph glyph-name="61" unicode="&#xe061;"
d="M0 800h100v-800h-100v800zM600 800h200v-800h-200v800zM200 600l200 -200l-200 -200v400z" />
<glyph glyph-name="62" unicode="&#xe062;"
d="M0 800h200v-800h-200v800zM700 800h100v-800h-100v800zM600 600v-400l-200 200z" />
<glyph glyph-name="63" unicode="&#xe063;"
d="M0 800h800v-200h-800v200zM400 400l200 -200h-400zM0 100h800v-100h-800v100z" />
<glyph glyph-name="64" unicode="&#xe064;"
d="M0 800h200v-100h-100v-600h600v100h100v-200h-800v800zM400 800h400v-400l-150 150l-250 -250l-100 100l250 250z" />
<glyph glyph-name="65" unicode="&#xe065;"
d="M403 700c247 0 397 -300 397 -300s-150 -300 -397 -300c-253 0 -403 300 -403 300s150 300 403 300zM400 600c-110 0 -200 -90 -200 -200s90 -200 200 -200s200 90 200 200s-90 200 -200 200zM400 500c10 0 19 -3 28 -6c-16 -8 -28 -24 -28 -44c0 -28 22 -50 50 -50
c20 0 36 12 44 28c3 -9 6 -18 6 -28c0 -55 -45 -100 -100 -100s-100 45 -100 100s45 100 100 100z" />
<glyph glyph-name="66" unicode="&#xe066;" horiz-adv-x="900"
d="M331 700h3h3c3 1 7 1 10 1c12 0 29 -8 37 -17l94 -93l66 65c57 57 155 57 212 0c58 -58 58 -154 0 -212l-65 -66l93 -94c10 -8 18 -25 18 -38c0 -28 -22 -50 -50 -50c-13 0 -32 9 -40 20l-62 65l-381 -381h-269v272l375 381l-63 63c-9 8 -16 24 -16 36c0 20 16 42 35 48z
M447 481l-313 -315l128 -132l316 316z" />
<glyph glyph-name="67" unicode="&#xe067;"
d="M0 800h300v-400h400v-400h-700v800zM400 800l300 -300h-300v300z" />
<glyph glyph-name="68" unicode="&#xe068;"
d="M200 800c0 0 200 -100 200 -300s-298 -302 -200 -500c0 0 -200 100 -200 300s300 300 200 500zM500 500c0 0 200 -100 200 -300c0 -150 -60 -200 -100 -200h-300c0 200 300 300 200 500z" />
<glyph glyph-name="69" unicode="&#xe069;"
d="M0 800h100v-800h-100v800zM200 800h300v-100h300l-200 -203l200 -197h-400v100h-200v400z" />
<glyph glyph-name="6a" unicode="&#xe06a;" horiz-adv-x="400"
d="M150 800h150l-100 -200h200l-150 -300h150l-300 -300l-100 300h134l66 200h-200z" />
<glyph glyph-name="6b" unicode="&#xe06b;"
d="M0 800h300v-100h500v-100h-800v200zM0 500h800v-450c0 -28 -22 -50 -50 -50h-700c-28 0 -50 22 -50 50v450z" />
<glyph glyph-name="6c" unicode="&#xe06c;"
d="M150 800c83 0 150 -67 150 -150c0 -66 -41 -121 -100 -141v-118c15 5 33 9 50 9h200c28 0 50 22 50 50v59c-59 20 -100 75 -100 141c0 83 67 150 150 150s150 -67 150 -150c0 -66 -41 -121 -100 -141v-59c0 -82 -68 -150 -150 -150h-200c-14 0 -25 -7 -34 -16
c50 -24 84 -74 84 -134c0 -83 -67 -150 -150 -150s-150 67 -150 150c0 66 41 121 100 141v218c-59 20 -100 75 -100 141c0 83 67 150 150 150z" />
<glyph glyph-name="6d" unicode="&#xe06d;"
d="M0 800h400l-150 -150l150 -150l-100 -100l-150 150l-150 -150v400zM500 400l150 -150l150 150v-400h-400l150 150l-150 150z" />
<glyph glyph-name="6e" unicode="&#xe06e;"
d="M100 800l150 -150l150 150v-400h-400l150 150l-150 150zM400 400h400l-150 -150l150 -150l-100 -100l-150 150l-150 -150v400z" />
<glyph glyph-name="6f" unicode="&#xe06f;"
d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM400 700c-56 0 -108 -17 -153 -44l22 -19c33 -18 13 -48 -13 -59c-30 -13 -77 10 -65 -41c13 -55 -27 -3 -47 -15c-42 -26 49 -152 31 -156l-59 34c-8 0 -13 -5 -16 -10
c1 -30 10 -57 19 -84c28 -11 77 -2 100 -25c47 -28 97 -115 75 -159c34 -13 68 -22 106 -22c101 0 193 48 247 125c3 24 -8 44 -50 44c-69 0 -156 13 -153 97c2 46 101 108 66 143c-30 30 12 39 12 66c0 37 -65 32 -69 50s20 36 41 56c-30 10 -60 19 -94 19zM631 591
c-38 -11 -94 -35 -87 -53c6 -15 52 -1 65 -13c11 -10 16 -59 44 -31l22 22v3c-11 26 -26 50 -44 72z" />
<glyph glyph-name="70" unicode="&#xe070;"
d="M703 800l97 -100l-400 -400l-100 100l-200 -203l-100 100l300 303l100 -100zM0 100h800v-100h-800v100z" />
<glyph glyph-name="71" unicode="&#xe071;"
d="M0 700h100v-100h-100v100zM200 700h100v-100h-100v100zM400 700h100v-100h-100v100zM600 700h100v-100h-100v100zM0 500h100v-100h-100v100zM200 500h100v-100h-100v100zM400 500h100v-100h-100v100zM600 500h100v-100h-100v100zM0 300h100v-100h-100v100zM200 300h100
v-100h-100v100zM400 300h100v-100h-100v100zM600 300h100v-100h-100v100zM0 100h100v-100h-100v100zM200 100h100v-100h-100v100zM400 100h100v-100h-100v100zM600 100h100v-100h-100v100z" />
<glyph glyph-name="72" unicode="&#xe072;"
d="M0 800h200v-200h-200v200zM300 800h200v-200h-200v200zM600 800h200v-200h-200v200zM0 500h200v-200h-200v200zM300 500h200v-200h-200v200zM600 500h200v-200h-200v200zM0 200h200v-200h-200v200zM300 200h200v-200h-200v200zM600 200h200v-200h-200v200z" />
<glyph glyph-name="73" unicode="&#xe073;"
d="M0 800h300v-300h-300v300zM500 800h300v-300h-300v300zM0 300h300v-300h-300v300zM500 300h300v-300h-300v300z" />
<glyph glyph-name="74" unicode="&#xe074;"
d="M19 800h662c11 0 19 -8 19 -19v-331c0 -28 -22 -50 -50 -50h-600c-28 0 -50 22 -50 50v331c0 11 8 19 19 19zM0 309c16 -6 32 -9 50 -9h600c18 0 34 3 50 9v-290c0 -11 -8 -19 -19 -19h-662c-11 0 -19 8 -19 19v290zM550 200c-28 0 -50 -22 -50 -50s22 -50 50 -50
s50 22 50 50s-22 50 -50 50z" />
<glyph glyph-name="75" unicode="&#xe075;"
d="M0 700h300v-100h-50c-28 0 -50 -22 -50 -50v-150h300v150c0 28 -22 50 -50 50h-50v100h300v-100h-50c-28 0 -50 -22 -50 -50v-400c0 -28 22 -50 50 -50h50v-100h-300v100h50c28 0 50 22 50 50v150h-300v-150c0 -28 22 -50 50 -50h50v-100h-300v100h50c28 0 50 22 50 50
v400c0 28 -22 50 -50 50h-50v100z" />
<glyph glyph-name="76" unicode="&#xe076;"
d="M400 700c165 0 300 -135 300 -300v-100h50c28 0 50 -22 50 -50v-200c0 -28 -22 -50 -50 -50h-100c-28 0 -50 22 -50 50v350c0 111 -89 200 -200 200s-200 -89 -200 -200v-350c0 -28 -22 -50 -50 -50h-100c-28 0 -50 22 -50 50v200c0 28 22 50 50 50h50v100
c0 165 135 300 300 300z" />
<glyph glyph-name="77" unicode="&#xe077;"
d="M0 500c0 109 91 200 200 200s200 -91 200 -200c0 109 91 200 200 200s200 -91 200 -200c0 -55 -23 -105 -59 -141l-341 -340l-341 340c-36 36 -59 86 -59 141z" />
<glyph glyph-name="78" unicode="&#xe078;"
d="M400 700l400 -300l-100 3v-403h-200v200h-200v-200h-200v400h-100z" />
<glyph glyph-name="79" unicode="&#xe079;"
d="M0 800h800v-800h-800v800zM100 700v-300l100 100l400 -400h100v100l-200 200l100 100l100 -100v300h-600z" />
<glyph glyph-name="7a" unicode="&#xe07a;"
d="M19 800h762c11 0 19 -8 19 -19v-762c0 -11 -8 -19 -19 -19h-762c-11 0 -19 8 -19 19v762c0 11 8 19 19 19zM100 600v-300h100l100 -100h200l100 100h100v300h-600z" />
<glyph glyph-name="7b" unicode="&#xe07b;"
d="M200 600c80 0 142 -56 200 -122c58 66 119 122 200 122c131 0 200 -101 200 -200s-69 -200 -200 -200c-81 0 -142 56 -200 122c-58 -66 -121 -122 -200 -122c-131 0 -200 101 -200 200s69 200 200 200zM200 500c-74 0 -100 -54 -100 -100s26 -100 100 -100
c42 0 88 47 134 100c-46 53 -92 100 -134 100zM600 500c-43 0 -88 -47 -134 -100c46 -53 91 -100 134 -100c74 0 100 54 100 100s-26 100 -100 100z" />
<glyph glyph-name="7c" unicode="&#xe07c;" horiz-adv-x="400"
d="M300 800c55 0 100 -45 100 -100s-45 -100 -100 -100s-100 45 -100 100s45 100 100 100zM150 550c83 0 150 -69 150 -150c0 -66 -100 -214 -100 -250c0 -28 22 -50 50 -50s50 22 50 50h100c0 -83 -67 -150 -150 -150s-150 64 -150 150s100 222 100 250s-22 50 -50 50
s-50 -22 -50 -50h-100c0 83 67 150 150 150z" />
<glyph glyph-name="7d" unicode="&#xe07d;"
d="M200 800h500v-100h-122c-77 -197 -156 -392 -234 -588l-6 -12h162v-100h-500v100h122c77 197 156 392 234 588l7 12h-163v100z" />
<glyph glyph-name="7e" unicode="&#xe07e;"
d="M0 700h800v-100h-800v100zM0 500h800v-100h-800v100zM0 300h800v-100h-800v100zM100 100h600v-100h-600v100z" />
<glyph glyph-name="7f" unicode="&#xe07f;"
d="M0 700h800v-100h-800v100zM0 500h800v-100h-800v100zM0 300h800v-100h-800v100zM0 100h600v-100h-600v100z" />
<glyph glyph-name="80" unicode="&#xe080;"
d="M0 700h800v-100h-800v100zM0 500h800v-100h-800v100zM0 300h800v-100h-800v100zM200 100h600v-100h-600v100z" />
<glyph glyph-name="81" unicode="&#xe081;"
d="M550 800c138 0 250 -112 250 -250s-112 -250 -250 -250c-16 0 -32 0 -47 3l-3 -3v-100h-200v-200h-300v200l303 303c-3 15 -3 31 -3 47c0 138 112 250 250 250zM600 700c-55 0 -100 -45 -100 -100s45 -100 100 -100s100 45 100 100s-45 100 -100 100z" />
<glyph glyph-name="82" unicode="&#xe082;"
d="M134 600h3h4h4h5h500c28 0 50 -22 50 -50v-350h100v-150c0 -28 -22 -50 -50 -50h-700c-28 0 -50 22 -50 50v150h100v350v2c0 20 15 42 34 48zM200 500v-300h100v-100h200v100h100v300h-400z" />
<glyph glyph-name="83" unicode="&#xe083;"
d="M0 800h400v-400h-400v400zM500 600h100v-400h-400v100h300v300zM700 400h100v-400h-400v100h300v300z" />
<glyph glyph-name="84" unicode="&#xe084;" horiz-adv-x="600"
d="M337 694c6 4 12 7 21 7c28 0 50 -22 50 -50c0 -17 -12 -37 -27 -45l-300 -150c-8 -6 -21 -11 -31 -11c-28 0 -50 22 -50 50c0 21 16 44 37 49zM437 544c6 4 12 7 21 7c28 0 50 -22 50 -50c0 -17 -12 -37 -27 -45l-400 -200c-8 -6 -21 -11 -31 -11c-28 0 -50 22 -50 50
c0 21 16 44 37 49zM437 344c6 4 12 7 21 7c28 0 50 -22 50 -50c0 -17 -12 -37 -27 -45l-106 -56c24 -4 43 -26 43 -50c0 -28 -23 -51 -51 -51c-2 0 -6 1 -8 1h-200c-26 1 -48 24 -48 50c0 16 12 36 26 44zM151 -50c0 23 20 50 46 50h3h4h5h100c28 0 50 -22 50 -50
s-22 -50 -50 -50h-100c-2 0 -6 -1 -8 -1c-28 0 -50 23 -50 51z" />
<glyph glyph-name="85" unicode="&#xe085;"
d="M199 800h100v-200h-200v100h100v100zM586 797h1c18 1 38 1 56 -3c36 -8 69 -26 97 -54c78 -78 78 -203 0 -281l-150 -150c-8 -13 -28 -24 -43 -24c-28 0 -50 22 -50 50c0 15 11 35 24 43l150 150c40 40 39 105 0 144c-41 41 -110 34 -144 0l-44 -44
c-8 -13 -27 -24 -42 -24c-28 0 -50 22 -50 50c0 15 11 35 24 43l43 44c32 33 72 53 128 56zM208 490c4 5 14 16 22 16h3c2 0 6 1 8 1c28 0 50 -22 50 -50c0 -11 -6 -27 -14 -35l-150 -150c-40 -40 -39 -105 0 -144c41 -41 110 -34 144 0l44 44c8 13 27 24 42 24
c28 0 50 -22 50 -50c0 -15 -11 -35 -24 -43l-43 -44c-22 -22 -48 -37 -75 -47c-70 -25 -151 -9 -207 47c-78 78 -78 203 0 281zM499 200h200v-100h-100v-100h-100v200z" />
<glyph glyph-name="86" unicode="&#xe086;"
d="M586 797c18 1 39 1 57 -3c36 -8 69 -26 97 -54c78 -78 78 -203 0 -281l-150 -150c-62 -62 -132 -81 -182 -78s-69 17 -84 25s-26 27 -26 44c0 28 22 51 50 51c8 0 19 -3 26 -7c0 0 15 -11 41 -13s62 3 106 47l150 150c40 40 39 105 0 144c-41 41 -110 34 -144 0
c-8 -13 -28 -24 -43 -24c-28 0 -50 22 -50 50c0 15 11 35 24 43c32 33 72 53 128 56zM386 566c50 -2 64 -17 85 -22s37 -28 37 -49c0 -28 -22 -50 -50 -50c-10 0 -23 5 -31 11c0 0 -19 9 -47 10s-63 -4 -103 -44l-150 -150c-40 -40 -39 -105 0 -144c41 -41 110 -34 144 0
c8 13 27 24 42 24c28 0 50 -22 50 -50c0 -15 -10 -35 -23 -43c-22 -22 -48 -37 -75 -47c-70 -25 -151 -9 -207 47c-78 78 -78 203 0 281l150 150c60 60 128 78 178 76z" />
<glyph glyph-name="87" unicode="&#xe087;"
d="M0 700h300v-300h-300v300zM400 700h400v-100h-400v100zM400 500h300v-100h-300v100zM0 300h300v-300h-300v300zM400 300h400v-100h-400v100zM400 100h300v-100h-300v100z" />
<glyph glyph-name="88" unicode="&#xe088;"
d="M50 700c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM200 700h600v-100h-600v100zM50 500c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM200 500h600v-100h-600v100zM50 300c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50
s22 50 50 50zM200 300h600v-100h-600v100zM50 100c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM200 100h600v-100h-600v100z" />
<glyph glyph-name="89" unicode="&#xe089;"
d="M800 800l-400 -800l-100 300l-300 100z" />
<glyph glyph-name="8a" unicode="&#xe08a;" horiz-adv-x="600"
d="M300 700c110 0 200 -90 200 -200v-100h100v-400h-600v400h100v100c0 110 90 200 200 200zM300 600c-56 0 -100 -44 -100 -100v-100h200v100c0 56 -44 100 -100 100z" />
<glyph glyph-name="8b" unicode="&#xe08b;" horiz-adv-x="600"
d="M300 800c110 0 200 -90 200 -200v-200h100v-400h-600v400h400v200c0 56 -44 100 -100 100s-100 -44 -100 -100h-100c0 110 90 200 200 200z" />
<glyph glyph-name="8c" unicode="&#xe08c;"
d="M400 700v-100c-111 0 -200 -89 -200 -200h100l-150 -200l-150 200h100c0 165 135 300 300 300zM650 600l150 -200h-100c0 -165 -135 -300 -300 -300v100c111 0 200 89 200 200h-100z" />
<glyph glyph-name="8d" unicode="&#xe08d;"
d="M100 800h600v-300h100l-150 -250l-150 250h100v200h-400v-100h-100v200zM150 550l150 -250h-100v-200h400v100h100v-200h-600v300h-100z" />
<glyph glyph-name="8e" unicode="&#xe08e;"
d="M600 700l200 -150l-200 -150v100h-500v-100h-100v100c0 55 45 100 100 100h500v100zM200 300v-100h500v100h100v-100c0 -55 -45 -100 -100 -100h-500v-100l-200 150z" />
<glyph glyph-name="8f" unicode="&#xe08f;" horiz-adv-x="900"
d="M350 800c193 0 350 -157 350 -350c0 -60 -17 -117 -44 -166c5 -3 12 -8 16 -12l100 -100c16 -16 30 -49 30 -72c0 -56 -46 -102 -102 -102c-23 0 -56 14 -72 30l-100 100c-4 3 -9 9 -12 13c-49 -26 -107 -41 -166 -41c-193 0 -350 157 -350 350s157 350 350 350zM350 200
c142 0 250 108 250 250c0 139 -111 250 -250 250s-250 -111 -250 -250s111 -250 250 -250z" />
<glyph glyph-name="90" unicode="&#xe090;" horiz-adv-x="600"
d="M300 800c166 0 300 -134 300 -300c0 -200 -300 -500 -300 -500s-300 300 -300 500c0 166 134 300 300 300zM300 700c-110 0 -200 -90 -200 -200s90 -200 200 -200s200 90 200 200s-90 200 -200 200z" />
<glyph glyph-name="91" unicode="&#xe091;" horiz-adv-x="900"
d="M0 800h800v-541c1 -3 1 -8 1 -11s0 -7 -1 -10v-238h-800v800zM495 250c0 26 22 50 50 50h5h150v400h-600v-600h600v100h-150h-5c-28 0 -50 22 -50 50zM350 600c83 0 150 -67 150 -150c0 -100 -150 -250 -150 -250s-150 150 -150 250c0 83 67 150 150 150zM350 500
c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50z" />
<glyph glyph-name="92" unicode="&#xe092;" horiz-adv-x="600"
d="M0 700h200v-600h-200v600zM400 700h200v-600h-200v600z" />
<glyph glyph-name="93" unicode="&#xe093;" horiz-adv-x="600"
d="M0 700l600 -300l-600 -300v600z" />
<glyph glyph-name="94" unicode="&#xe094;" horiz-adv-x="600"
d="M300 700c166 0 300 -134 300 -300s-134 -300 -300 -300s-300 134 -300 300s134 300 300 300z" />
<glyph glyph-name="95" unicode="&#xe095;"
d="M400 700v-600l-400 300zM400 400l400 300v-600z" />
<glyph glyph-name="96" unicode="&#xe096;"
d="M0 700l400 -300l-400 -300v600zM400 100v600l400 -300z" />
<glyph glyph-name="97" unicode="&#xe097;"
d="M0 700h200v-600h-200v600zM200 400l500 300v-600z" />
<glyph glyph-name="98" unicode="&#xe098;"
d="M0 700l500 -300l-500 -300v600zM500 100v600h200v-600h-200z" />
<glyph glyph-name="99" unicode="&#xe099;" horiz-adv-x="600"
d="M0 700h600v-600h-600v600z" />
<glyph glyph-name="9a" unicode="&#xe09a;"
d="M200 800h400v-200h200v-400h-200v-200h-400v200h-200v400h200v200z" />
<glyph glyph-name="9b" unicode="&#xe09b;"
d="M0 700h800v-100h-800v100zM0 403h800v-100h-800v100zM0 103h800v-100h-800v100z" />
<glyph glyph-name="9c" unicode="&#xe09c;" horiz-adv-x="600"
d="M278 700c7 2 13 4 22 4c55 0 100 -45 100 -100v-4v-200c0 -55 -45 -100 -100 -100s-100 45 -100 100v200v2c0 44 35 88 78 98zM34 500h4h3c3 0 6 1 9 1c28 0 50 -22 50 -50v-1v-50c0 -111 89 -200 200 -200s200 89 200 200v50c0 28 22 50 50 50s50 -22 50 -50v-50
c0 -148 -109 -270 -250 -294v-106h50c55 0 100 -45 100 -100h-400c0 55 45 100 100 100h50v106c-141 24 -250 146 -250 294v50v2c0 20 15 42 34 48z" />
<glyph glyph-name="9d" unicode="&#xe09d;"
d="M0 500h800v-200h-800v200z" />
<glyph glyph-name="9e" unicode="&#xe09e;"
d="M34 700h4h3h4h5h700c28 0 50 -22 50 -50v-500c0 -28 -22 -50 -50 -50h-250v-100h100c55 0 100 -45 100 -100h-600c0 55 45 100 100 100h100v100h-250c-28 0 -50 22 -50 50v500v2c0 20 15 42 34 48zM100 600v-400h600v400h-600z" />
<glyph glyph-name="9f" unicode="&#xe09f;"
d="M272 700c-14 -40 -22 -83 -22 -128c0 -221 179 -400 400 -400c45 0 88 8 128 22c-53 -158 -202 -272 -378 -272c-221 0 -400 179 -400 400c0 176 114 325 272 378z" />
<glyph glyph-name="a0" unicode="&#xe0a0;"
d="M350 700l150 -150h-100v-150h150v100l150 -150l-150 -150v100h-150v-150h100l-150 -150l-150 150h100v150h-150v-100l-150 150l150 150v-100h150v150h-100z" />
<glyph glyph-name="a1" unicode="&#xe0a1;"
d="M800 800v-550c0 -83 -67 -150 -150 -150s-150 67 -150 150s67 150 150 150c17 0 35 -4 50 -9v206c-201 -6 -327 -27 -400 -50v-397c0 -83 -67 -150 -150 -150s-150 67 -150 150s67 150 150 150c17 0 35 -4 50 -9v409s100 100 600 100z" />
<glyph glyph-name="a2" unicode="&#xe0a2;" horiz-adv-x="700"
d="M499 700c51 0 102 -20 141 -59c78 -78 78 -203 0 -281l-250 -244c-48 -48 -127 -48 -175 0s-48 127 0 175l96 97l69 -69l-90 -94l-7 -3c-10 -10 -10 -28 0 -38s28 -10 38 0l250 247c37 40 39 102 0 141s-104 40 -144 0l-278 -275c-66 -69 -68 -179 0 -247
c69 -69 181 -69 250 0l9 12l116 113l69 -69l-125 -125c-107 -107 -281 -107 -388 0s-107 281 0 388l278 272c39 39 90 59 141 59z" />
<glyph glyph-name="a3" unicode="&#xe0a3;"
d="M600 800l200 -200l-100 -100l-200 200zM400 600l200 -200l-400 -400h-200v200z" />
<glyph glyph-name="a4" unicode="&#xe0a4;"
d="M550 800c83 0 150 -90 150 -200s-67 -200 -150 -200c-22 0 -40 8 -59 19c6 26 9 52 9 81c0 84 -27 158 -72 212c27 52 71 88 122 88zM250 700c83 0 150 -90 150 -200s-67 -200 -150 -200s-150 90 -150 200s67 200 150 200zM725 384c44 -22 75 -66 75 -118v-166h-200v66
c0 50 -17 96 -44 134c66 2 126 33 169 84zM75 284c45 -53 106 -84 175 -84s130 31 175 84c44 -22 75 -66 75 -118v-166h-500v166c0 52 31 96 75 118z" />
<glyph glyph-name="a5" unicode="&#xe0a5;"
d="M400 800c110 0 200 -112 200 -250s-90 -250 -200 -250s-200 112 -200 250s90 250 200 250zM191 300c54 -61 128 -100 209 -100s155 39 209 100c106 -5 191 -92 191 -200v-100h-800v100c0 108 85 195 191 200z" />
<glyph glyph-name="a6" unicode="&#xe0a6;" horiz-adv-x="600"
d="M19 800h462c11 0 19 -8 19 -19v-762c0 -11 -8 -19 -19 -19h-462c-11 0 -19 8 -19 19v762c0 11 8 19 19 19zM100 700v-500h300v500h-300zM250 150c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50z" />
<glyph glyph-name="a7" unicode="&#xe0a7;"
d="M350 800c17 0 34 -1 50 -3v-397l-297 297c63 64 150 103 247 103zM500 694c169 -25 300 -168 300 -344c0 -193 -157 -350 -350 -350c-85 0 -161 31 -222 81l272 272v341zM91 562l237 -234l-212 -212c-70 55 -116 138 -116 234c0 84 35 158 91 212z" />
<glyph glyph-name="a8" unicode="&#xe0a8;"
d="M92 650c0 23 20 50 46 50h3h4h5h400c28 0 50 -22 50 -50s-22 -50 -50 -50h-50v-200h100c55 0 100 -45 100 -100h-300v-300l-56 -100l-44 100v300h-300c0 55 45 100 100 100h100v200h-50c-2 0 -6 -1 -8 -1c-28 0 -50 23 -50 51z" />
<glyph glyph-name="a9" unicode="&#xe0a9;"
d="M400 800c221 0 400 -179 400 -400s-179 -400 -400 -400s-400 179 -400 400s179 400 400 400zM300 600v-400l300 200z" />
<glyph glyph-name="aa" unicode="&#xe0aa;"
d="M300 800h200v-300h300v-200h-300v-300h-200v300h-300v200h300v300z" />
<glyph glyph-name="ab" unicode="&#xe0ab;"
d="M300 800h100v-400h-100v400zM172 656l62 -78l-40 -31c-58 -46 -94 -117 -94 -197c0 -139 111 -250 250 -250s250 111 250 250c0 80 -39 151 -97 197l-37 31l62 78l38 -31c82 -64 134 -164 134 -275c0 -193 -157 -350 -350 -350s-350 157 -350 350c0 111 53 211 134 275z
" />
<glyph glyph-name="ac" unicode="&#xe0ac;"
d="M200 800h400v-200h-400v200zM9 500h782c6 0 9 -3 9 -9v-282c0 -6 -3 -9 -9 -9h-91v200h-600v-200h-91c-6 0 -9 3 -9 9v282c0 6 3 9 9 9zM200 300h400v-300h-400v300z" />
<glyph glyph-name="ad" unicode="&#xe0ad;"
d="M0 700h100v-700h-100v700zM700 700h100v-700h-100v700zM200 600h200v-100h-200v100zM300 400h200v-100h-200v100zM400 200h200v-100h-200v100z" />
<glyph glyph-name="ae" unicode="&#xe0ae;"
d="M325 700c42 -141 87 -280 131 -419c29 74 59 148 88 222c30 -57 58 -114 87 -172h169v-100h-231l-13 28c-37 -92 -74 -184 -112 -275c-38 129 -79 257 -119 385c-42 -133 -83 -267 -125 -400c-28 88 -56 175 -84 262h-116v100h188l9 -34l3 -6c42 137 83 273 125 409z" />
<glyph glyph-name="af" unicode="&#xe0af;"
d="M200 600c0 57 43 100 100 100s100 -43 100 -100c0 -28 -18 -48 -28 -72c-3 -6 -3 -16 -3 -28h231v-231c12 0 22 0 28 3c24 10 44 28 72 28c57 0 100 -43 100 -100s-43 -100 -100 -100c-28 0 -48 18 -72 28c-6 3 -16 3 -28 3v-231h-231c0 12 0 22 3 28c10 24 28 44 28 72
c0 57 -43 100 -100 100s-100 -43 -100 -100c0 -28 18 -48 28 -72c3 -6 3 -16 3 -28h-231v600h231c0 12 0 22 -3 28c-10 24 -28 44 -28 72z" />
<glyph glyph-name="b0" unicode="&#xe0b0;" horiz-adv-x="500"
d="M247 700c84 0 148 -20 191 -59s59 -93 59 -141c0 -117 -69 -181 -119 -225s-81 -67 -81 -150v-25h-100v25c0 117 65 181 115 225s85 67 85 150c0 25 -8 48 -28 66s-56 34 -122 34s-97 -18 -116 -37s-27 -43 -31 -69l-100 12c5 38 19 88 59 128s103 66 188 66zM197 0h100
v-100h-100v100z" />
<glyph glyph-name="b1" unicode="&#xe0b1;"
d="M450 800c138 0 250 -112 250 -250v-50c58 -21 100 -85 100 -150c0 -69 -48 -127 -112 -144c-22 55 -75 94 -138 94c-20 0 -39 -5 -56 -12c-17 64 -75 112 -144 112s-127 -48 -144 -112c-17 7 -36 12 -56 12c-37 0 -71 -12 -97 -34c-33 36 -53 82 -53 134
c0 110 90 200 200 200c23 114 129 200 250 200zM334 300h4h3c3 0 6 1 9 1c28 0 50 -22 50 -50v-1v-200c0 -28 -22 -50 -50 -50s-50 22 -50 50v200v2c0 20 15 42 34 48zM134 200h4h3c3 0 6 1 9 1c28 0 50 -22 50 -50v-1v-100c0 -28 -22 -50 -50 -50s-50 22 -50 50v100v2
c0 20 15 42 34 48zM534 200h3h4c3 0 6 1 9 1c28 0 50 -22 50 -50v-1v-100c0 -28 -22 -50 -50 -50s-50 22 -50 50v100v2c0 20 15 42 34 48z" />
<glyph glyph-name="b2" unicode="&#xe0b2;"
d="M600 800l200 -150l-200 -150v100h-50l-153 -191l175 -206l6 -3h22v100l200 -150l-200 -150v100h-25c-35 0 -56 12 -78 38l-166 190l-153 -190c-22 -27 -43 -38 -78 -38h-100v100h100l166 206l-163 191l-3 3h-100v100h100c34 0 56 -12 78 -38l153 -178l141 178
c22 27 43 38 78 38h50v100z" />
<glyph glyph-name="b3" unicode="&#xe0b3;"
d="M400 800c110 0 209 -47 281 -119l119 119v-300h-300l109 109c-54 55 -126 91 -209 91c-166 0 -300 -134 -300 -300s134 -300 300 -300c83 0 158 34 212 88l72 -72c-72 -72 -174 -116 -284 -116c-220 0 -400 180 -400 400s180 400 400 400z" />
<glyph glyph-name="b4" unicode="&#xe0b4;"
d="M400 800h400v-400l-166 166l-400 -400l166 -166h-400v400l166 -166l400 400z" />
<glyph glyph-name="b5" unicode="&#xe0b5;" horiz-adv-x="600"
d="M250 800l250 -300h-200v-200h200l-250 -300l-250 300h200v200h-200z" />
<glyph glyph-name="b6" unicode="&#xe0b6;"
d="M300 600v-200h200v200l300 -250l-300 -250v200h-200v-200l-300 250z" />
<glyph glyph-name="b7" unicode="&#xe0b7;"
d="M0 800c441 0 800 -359 800 -800h-200c0 333 -267 600 -600 600v200zM0 500c275 0 500 -225 500 -500h-200c0 167 -133 300 -300 300v200zM0 200c110 0 200 -90 200 -200h-200v200z" />
<glyph glyph-name="b8" unicode="&#xe0b8;"
d="M100 800c386 0 700 -314 700 -700h-100c0 332 -268 600 -600 600v100zM100 600c276 0 500 -224 500 -500h-100c0 222 -178 400 -400 400v100zM100 400c165 0 300 -135 300 -300h-100c0 111 -89 200 -200 200v100zM100 200c55 0 100 -45 100 -100s-45 -100 -100 -100
s-100 45 -100 100s45 100 100 100z" />
<glyph glyph-name="b9" unicode="&#xe0b9;"
d="M300 800h400c55 0 100 -45 100 -100v-200h-400v150c0 28 -22 50 -50 50s-50 -22 -50 -50v-250h400v-300c0 -55 -45 -100 -100 -100h-500c-55 0 -100 45 -100 100v200h100v-150c0 -28 22 -50 50 -50s50 22 50 50v550c0 55 45 100 100 100z" />
<glyph glyph-name="ba" unicode="&#xe0ba;"
d="M75 700h225v-100h-200v-500h400v100h100v-125c0 -41 -34 -75 -75 -75h-450c-41 0 -75 34 -75 75v550c0 41 34 75 75 75zM600 700l200 -200l-200 -200v100h-200c-94 0 -173 -65 -194 -153c23 199 189 353 394 353v100z" />
<glyph glyph-name="bb" unicode="&#xe0bb;"
d="M500 700l300 -284l-300 -316v200h-100c-200 0 -348 -102 -400 -300c0 295 100 500 500 500v200z" />
<glyph glyph-name="bc" unicode="&#xe0bc;"
d="M381 791l19 9l19 -9c127 -53 253 -108 381 -160v-31c0 -166 -67 -313 -147 -419c-40 -53 -83 -97 -125 -128s-82 -53 -128 -53s-86 22 -128 53s-85 75 -125 128c-80 107 -147 253 -147 419v31c128 52 254 107 381 160zM400 100v591l-294 -122c8 -126 58 -243 122 -328
c35 -46 73 -86 106 -110s62 -31 66 -31z" />
<glyph glyph-name="bd" unicode="&#xe0bd;"
d="M600 800h100v-800h-100v800zM400 700h100v-700h-100v700zM200 500h100v-500h-100v500zM0 300h100v-300h-100v300z" />
<glyph glyph-name="be" unicode="&#xe0be;"
d="M300 800h100v-200h200l100 -100l-100 -100h-200v-400h-100v500h-200l-100 100l100 100h200v100z" />
<glyph glyph-name="bf" unicode="&#xe0bf;"
d="M200 800h100v-600h200l-250 -200l-250 200h200v600zM400 800h200v-100h-200v100zM400 600h300v-100h-300v100zM400 400h400v-100h-400v100z" />
<glyph glyph-name="c0" unicode="&#xe0c0;"
d="M200 800h100v-600h200l-250 -200l-250 200h200v600zM400 800h400v-100h-400v100zM400 600h300v-100h-300v100zM400 400h200v-100h-200v100z" />
<glyph glyph-name="c1" unicode="&#xe0c1;"
d="M75 700h650c41 0 75 -34 75 -75v-550c0 -41 -34 -75 -75 -75h-650c-41 0 -75 34 -75 75v550c0 41 34 75 75 75zM100 600v-100h100v100h-100zM300 600v-100h400v100h-400zM100 400v-100h100v100h-100zM300 400v-100h400v100h-400zM100 200v-100h100v100h-100zM300 200
v-100h400v100h-400z" />
<glyph glyph-name="c2" unicode="&#xe0c2;"
d="M400 800l100 -300h300l-250 -200l100 -300l-250 200l-250 -200l100 300l-250 200h300z" />
<glyph glyph-name="c3" unicode="&#xe0c3;"
d="M400 800c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM150 700c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM650 700c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM400 600c110 0 200 -90 200 -200
s-90 -200 -200 -200s-200 90 -200 200s90 200 200 200zM50 450c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM750 450c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM150 200c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50
s22 50 50 50zM650 200c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50zM400 100c28 0 50 -22 50 -50s-22 -50 -50 -50s-50 22 -50 50s22 50 50 50z" />
<glyph glyph-name="c4" unicode="&#xe0c4;"
d="M34 800h632c18 0 34 -16 34 -34v-732c0 -18 -16 -34 -34 -34h-632c-18 0 -34 16 -34 34v732c0 18 16 34 34 34zM100 700v-500h500v500h-500zM350 150c-38 0 -63 -42 -44 -75s69 -33 88 0s-6 75 -44 75z" />
<glyph glyph-name="c5" unicode="&#xe0c5;"
d="M0 800h300l500 -500l-300 -300l-500 500v300zM200 700c-55 0 -100 -45 -100 -100s45 -100 100 -100s100 45 100 100s-45 100 -100 100z" />
<glyph glyph-name="c6" unicode="&#xe0c6;"
d="M0 600h200l300 -300l-200 -200l-300 300v200zM340 600h160l300 -300l-200 -200l-78 78l119 122zM150 500c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50z" />
<glyph glyph-name="c7" unicode="&#xe0c7;"
d="M400 800c220 0 400 -180 400 -400s-180 -400 -400 -400s-400 180 -400 400s180 400 400 400zM400 700c-166 0 -300 -134 -300 -300s134 -300 300 -300s300 134 300 300s-134 300 -300 300zM400 600c110 0 200 -90 200 -200s-90 -200 -200 -200s-200 90 -200 200
s90 200 200 200zM400 500c-56 0 -100 -44 -100 -100s44 -100 100 -100s100 44 100 100s-44 100 -100 100z" />
<glyph glyph-name="c8" unicode="&#xe0c8;"
d="M0 700h559l-100 -100h-359v-500h500v159l100 100v-359h-700v700zM700 700l100 -100l-400 -400l-200 200l100 100l100 -100z" />
<glyph glyph-name="c9" unicode="&#xe0c9;"
d="M9 800h782c6 0 9 -3 9 -9v-782c0 -6 -3 -9 -9 -9h-782c-6 0 -9 3 -9 9v782c0 6 3 9 9 9zM150 722l-72 -72l100 -100l-100 -100l72 -72l172 172zM400 500v-100h300v100h-300z" />
<glyph glyph-name="ca" unicode="&#xe0ca;"
d="M0 800h800v-200h-50c0 55 -45 100 -100 100h-150v-550c0 -28 22 -50 50 -50h50v-100h-400v100h50c28 0 50 22 50 50v550h-150c-55 0 -100 -45 -100 -100h-50v200z" />
<glyph glyph-name="cb" unicode="&#xe0cb;"
d="M0 700h100v-400h-100v400zM200 700h350c21 0 39 -13 47 -31c0 0 103 -291 103 -319s-22 -50 -50 -50h-150c-28 0 -50 -25 -50 -50s39 -158 47 -184s-5 -55 -31 -63s-52 5 -66 31s-109 219 -128 238s-44 28 -72 28v400z" />
<glyph glyph-name="cc" unicode="&#xe0cc;"
d="M400 666c10 19 28 32 47 34l19 -3c26 -8 39 -37 31 -63s-47 -159 -47 -184s22 -50 50 -50h150c28 0 50 -22 50 -50s-103 -319 -103 -319c-8 -18 -26 -31 -47 -31h-350v400c28 0 53 9 72 28s114 212 128 238zM0 400h100v-400h-100v400z" />
<glyph glyph-name="cd" unicode="&#xe0cd;"
d="M200 700h300v-100h-100v-6c25 -4 50 -8 72 -16l-34 -94c-28 11 -58 16 -88 16c-139 0 -250 -111 -250 -250s111 -250 250 -250s250 111 250 250c0 31 -5 60 -16 88l91 37c14 -38 25 -81 25 -125c0 -193 -157 -350 -350 -350s-350 157 -350 350c0 176 130 323 300 347v3
h-100v100zM700 584c0 0 -296 -348 -316 -368s-48 -20 -68 0s-20 48 0 68s384 300 384 300z" />
<glyph glyph-name="ce" unicode="&#xe0ce;"
d="M600 700l200 -150l-200 -150v100h-600v100h600v100zM200 300v-100h600v-100h-600v-100l-200 150z" />
<glyph glyph-name="cf" unicode="&#xe0cf;"
d="M300 800h100c55 0 100 -45 100 -100h100c55 0 100 -45 100 -100h-700c0 55 45 100 100 100h100c0 55 45 100 100 100zM100 500h100v-350c0 -28 22 -50 50 -50s50 22 50 50v350h100v-350c0 -28 22 -50 50 -50s50 22 50 50v350h100v-481c0 -11 -8 -19 -19 -19h-462
c-11 0 -19 8 -19 19v481z" />
<glyph glyph-name="d0" unicode="&#xe0d0;"
d="M100 800h200v-400c0 -55 45 -100 100 -100s100 45 100 100v400h100v-400c0 -110 -90 -200 -200 -200h-50c-138 0 -250 90 -250 200v400zM0 100h700v-100h-700v100z" />
<glyph glyph-name="d1" unicode="&#xe0d1;"
d="M9 700h182c6 0 9 -3 9 -9v-482c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v482c0 6 3 9 9 9zM609 700h182c6 0 9 -3 9 -9v-482c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v482c0 6 3 9 9 9zM309 500h182c6 0 9 -3 9 -9v-282c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v282
c0 6 3 9 9 9zM0 100h800v-100h-800v100z" />
<glyph glyph-name="d2" unicode="&#xe0d2;"
d="M10 700h181c6 0 9 -3 9 -9v-191h-200v191c0 6 4 9 10 9zM610 700h181c6 0 9 -3 9 -9v-191h-200v191c0 6 5 9 10 9zM310 600h181c6 0 9 -3 9 -9v-91h-200v91c0 6 4 9 10 9zM0 400h800v-100h-800v100zM0 200h200v-191c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v191zM300 200
h200v-91c0 -6 -3 -9 -9 -9h-181c-6 0 -10 3 -10 9v91zM600 200h200v-191c0 -6 -3 -9 -9 -9h-181c-6 0 -10 3 -10 9v191z" />
<glyph glyph-name="d3" unicode="&#xe0d3;"
d="M0 700h800v-100h-800v100zM9 500h182c6 0 9 -3 9 -9v-482c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v482c0 6 3 9 9 9zM309 500h182c6 0 9 -3 9 -9v-282c0 -6 -3 -9 -9 -9h-182c-6 0 -9 3 -9 9v282c0 6 3 9 9 9zM609 500h182c6 0 9 -3 9 -9v-482c0 -6 -3 -9 -9 -9h-182
c-6 0 -9 3 -9 9v482c0 6 3 9 9 9z" />
<glyph glyph-name="d4" unicode="&#xe0d4;"
d="M50 600h500c28 0 50 -22 50 -50v-150l100 100h100v-300h-100l-100 100v-150c0 -28 -22 -50 -50 -50h-500c-28 0 -50 22 -50 50v400c0 28 22 50 50 50z" />
<glyph glyph-name="d5" unicode="&#xe0d5;"
d="M334 800h66v-800h-66l-134 200h-200v400h200zM500 600v100c26 0 52 -4 75 -10c130 -33 225 -150 225 -290s-95 -258 -225 -291h-3c-23 -6 -47 -9 -72 -9v100c17 0 34 2 50 6c86 22 150 100 150 194s-64 172 -150 194c-16 4 -33 6 -50 6zM500 500l25 -3
c44 -11 75 -51 75 -97s-32 -86 -75 -97l-25 -3v200z" />
<glyph glyph-name="d6" unicode="&#xe0d6;" horiz-adv-x="600"
d="M334 800h66v-800h-66l-134 200h-200v400h200zM500 500l25 -3c44 -11 75 -51 75 -97s-32 -86 -75 -97l-25 -3v200z" />
<glyph glyph-name="d7" unicode="&#xe0d7;" horiz-adv-x="400"
d="M334 800h66v-800h-66l-134 200h-200v400h200z" />
<glyph glyph-name="d8" unicode="&#xe0d8;"
d="M309 800h82c6 0 10 -4 12 -9l294 -682l3 -19v-81c0 -6 -3 -9 -9 -9h-682c-6 0 -9 3 -9 9v81l3 19l294 682c2 5 6 9 12 9zM300 500v-200h100v200h-100zM300 200v-100h100v100h-100z" />
<glyph glyph-name="d9" unicode="&#xe0d9;"
d="M375 800c138 0 269 -39 378 -109l-53 -82c-93 60 -205 91 -325 91c-119 0 -229 -32 -322 -91l-53 82c109 70 237 109 375 109zM375 500c78 0 154 -23 216 -62l-53 -85c-46 30 -104 47 -163 47c-60 0 -112 -17 -159 -47l-54 85c62 40 134 62 213 62zM375 200
c55 0 100 -45 100 -100s-45 -100 -100 -100s-100 45 -100 100s45 100 100 100z" />
<glyph glyph-name="da" unicode="&#xe0da;" horiz-adv-x="900"
d="M551 800c16 0 32 0 47 -3l-97 -97v-200h200l97 97c3 -15 3 -31 3 -47c0 -138 -112 -250 -250 -250c-32 0 -62 8 -90 19l-288 -291c-20 -20 -46 -28 -72 -28s-52 8 -72 28c-39 39 -39 105 0 144l291 287c-11 28 -19 59 -19 91c0 138 112 250 250 250zM101 150
c-28 0 -50 -22 -50 -50s22 -50 50 -50s50 22 50 50s-22 50 -50 50z" />
<glyph glyph-name="db" unicode="&#xe0db;"
d="M141 700c84 -84 169 -167 253 -250c82 83 167 165 247 250l143 -141l-253 -253c84 -82 167 -166 253 -247l-143 -143c-81 86 -165 169 -247 253l-253 -253l-141 143c85 80 167 164 250 247c-83 84 -166 169 -250 253z" />
<glyph glyph-name="dc" unicode="&#xe0dc;"
d="M0 800h100l231 -300h38l231 300h100l-225 -300h225v-100h-300v-100h300v-100h-300v-200h-100v200h-300v100h300v100h-300v100h225z" />
<glyph glyph-name="dd" unicode="&#xe0dd;" horiz-adv-x="900"
d="M350 800c193 0 350 -157 350 -350c0 -61 -17 -119 -44 -169c4 -2 10 -6 13 -9l103 -100c16 -16 30 -49 30 -72c0 -56 -46 -102 -102 -102c-23 0 -56 14 -72 30l-100 103c-3 3 -7 9 -9 13c-50 -28 -108 -44 -169 -44c-193 0 -350 157 -350 350s157 350 350 350zM350 700
c-139 0 -250 -111 -250 -250s111 -250 250 -250c62 0 119 23 163 60c7 11 19 25 31 31l3 3c34 43 53 97 53 156c0 139 -111 250 -250 250zM300 600h100v-100h100v-100h-100v-100h-100v100h-100v100h100v100z" />
<glyph glyph-name="de" unicode="&#xe0de;" horiz-adv-x="900"
d="M350 800c193 0 350 -157 350 -350c0 -61 -17 -119 -44 -169c4 -2 10 -6 13 -9l103 -100c16 -16 30 -49 30 -72c0 -56 -46 -102 -102 -102c-23 0 -56 14 -72 30l-100 103c-3 3 -7 9 -9 13c-50 -28 -108 -44 -169 -44c-193 0 -350 157 -350 350s157 350 350 350zM350 700
c-139 0 -250 -111 -250 -250s111 -250 250 -250c62 0 119 23 163 60c7 11 19 25 31 31l3 3c34 43 53 97 53 156c0 139 -111 250 -250 250zM200 500h300v-100h-300v100z" />
</font>
</defs></svg>

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Binary file not shown.

34
public/js/app.js vendored

File diff suppressed because one or more lines are too long

3927
public/js/bootstrap.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

30
public/manifest.json Normal file
View File

@ -0,0 +1,30 @@
{
"name": "Tissue",
"short_name": "Tissue",
"description": "気持ちよくティッシュを使った、そのあとの感想戦。",
"display": "minimal-ui",
"start_url": "/",
"share_target": {
"action": "/checkin",
"method": "GET",
"enctype": "application/x-www-form-urlencoded",
"url_template": "/checkin?link={url}",
"params": {
"title": "",
"text": "link",
"url": "link"
}
},
"icons": [
{
"src": "apple-touch-icon.png",
"type": "image/png",
"sizes": "180x180"
},
{
"src": "chrome-touch-icon-192x192.png",
"type": "image/png",
"sizes": "192x192"
}
]
}

1
public/sw.js vendored Normal file
View File

@ -0,0 +1 @@
self.addEventListener('fetch', function() {});

View File

@ -1,22 +1,32 @@
import Cookies from 'js-cookie';
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap'); require('./bootstrap');
window.Vue = require('vue'); $(() => {
if (Cookies.get('agechecked')) {
$('body').removeClass('tis-need-agecheck');
} else {
$('#ageCheckModal')
.modal({backdrop: 'static'})
.on('hide.bs.modal', function () {
$('body').removeClass('tis-need-agecheck');
Cookies.set('agechecked', '1', {expires: 365});
});
}
/** if (navigator.serviceWorker) {
* Next, we will create a fresh Vue application instance and attach it to navigator.serviceWorker.register('/sw.js');
* the page. Then, you may begin adding components to this application }
* or customize the JavaScript scaffolding to fit your unique needs. $('[data-toggle="tooltip"]').tooltip();
*/ $('.alert').alert();
$('.tis-page-selector').pageSelector();
Vue.component('example', require('./components/Example.vue')); if (document.getElementById('status')) {
setTimeout(function () {
$('#status').alert('close');
}, 5000);
}
const app = new Vue({ $('.link-card').linkCard();
el: '#app' $('#deleteCheckinModal').deleteCheckinModal();
}); });

View File

@ -1,53 +1,17 @@
// jQuery
import './tissue';
window._ = require('lodash'); // Setup global request header
const token = document.head.querySelector('meta[name="csrf-token"]');
/** if (!token) {
* We'll load jQuery and the Bootstrap jQuery plugin which provides support
* for JavaScript based Bootstrap features such as modals and tabs. This
* code may be modified to fit the specific needs of your application.
*/
try {
window.$ = window.jQuery = require('jquery');
require('bootstrap-sass');
} catch (e) {}
/**
* We'll load the axios HTTP library which allows us to easily issue requests
* to our Laravel back-end. This library automatically handles sending the
* CSRF token as a header based on the value of the "XSRF" token cookie.
*/
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
/**
* Next we will register the CSRF Token as a common header with Axios so that
* all outgoing HTTP requests automatically have it attached. This is just
* a simple convenience so we don't have to attach every token manually.
*/
let token = document.head.querySelector('meta[name="csrf-token"]');
if (token) {
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token'); console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
} }
/** $.ajaxSetup({
* Echo exposes an expressive API for subscribing to channels and listening headers: {
* for events that are broadcast by Laravel. Echo and event broadcasting 'X-CSRF-TOKEN': token.content
* allows your team to easily build robust real-time web applications. }
*/ });
// import Echo from 'laravel-echo' // Bootstrap
import 'bootstrap';
// window.Pusher = require('pusher-js');
// window.Echo = new Echo({
// broadcaster: 'pusher',
// key: 'your-pusher-key'
// });

51
resources/assets/js/checkin.js vendored Normal file
View File

@ -0,0 +1,51 @@
function updateTags() {
$('input[name=tags]').val(
$('#tags')
.find('li')
.map(function () {
return $(this).data('value');
})
.get()
.join(' ')
);
}
function insertTag(value) {
$('#tags').append('<li class="list-inline-item badge badge-primary" style="cursor: pointer;" data-value="' + value + '"><span class="oi oi-tag"></span> ' + value + ' | x</li>');
}
var initTags = $('input[name=tags]').val();
if (initTags.trim() !== '') {
initTags.split(' ').forEach(function (value) {
insertTag(value);
});
}
$('#tagInput').on('keydown', function (ev) {
var $this = $(this);
if ($this.val().trim() !== '') {
switch (ev.key) {
case 'Tab':
case 'Enter':
case ' ':
insertTag($this.val().trim());
$this.val('');
updateTags();
ev.preventDefault();
break;
}
} else if (ev.key === 'Enter') {
// 誤爆防止
ev.preventDefault();
}
});
$('#tags')
.on('click', 'li', function (ev) {
$(this).remove();
updateTags();
})
.parent()
.on('click', function (ev) {
$('#tagInput').focus();
});

View File

@ -1,23 +0,0 @@
<template>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Example Component</div>
<div class="panel-body">
I'm an example component!
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>

38
resources/assets/js/home.js vendored Normal file
View File

@ -0,0 +1,38 @@
import Chart from 'chart.js';
const graph = document.getElementById('global-count-graph');
const labels = JSON.parse(document.getElementById('global-count-labels').textContent);
const data = JSON.parse(document.getElementById('global-count-data').textContent);
new Chart(graph.getContext('2d'), {
type: 'bar',
data: {
labels,
datasets: [{
data,
backgroundColor: 'rgba(0, 0, 0, .1)',
borderColor: 'rgba(0, 0, 0, .25)',
borderWidth: 1
}]
},
options: {
maintainAspectRatio: false,
legend: {
display: false
},
elements: {
line: {}
},
scales: {
xAxes: [{
display: false
}],
yAxes: [{
display: false,
ticks: {
beginAtZero: true
}
}]
}
}
});

View File

@ -0,0 +1,5 @@
$('#protected').on('change', function () {
if (!$(this).prop('checked')) {
alert('チェックイン履歴を公開に切り替えると、個別に非公開設定されているものを除いた全てのチェックインが誰でも閲覧できるようになります。\nご注意ください。');
}
});

View File

@ -1,5 +1,3 @@
// app.jsの名はモジュールバンドラーを投入する日まで予約しておく。CSSも同じ。
(function ($) { (function ($) {
$.fn.linkCard = function (options) { $.fn.linkCard = function (options) {
@ -17,9 +15,11 @@
url: $this.find('a').attr('href') url: $this.find('a').attr('href')
} }
}).then(function (data) { }).then(function (data) {
var $metaColumn = $this.find('.col-12:last-of-type');
var $imageColumn = $this.find('.col-12:first-of-type');
var $title = $this.find('.card-title'); var $title = $this.find('.card-title');
var $desc = $this.find('.card-text'); var $desc = $this.find('.card-text');
var $image = $this.find('img'); var $image = $imageColumn.find('img');
if (data.title === '') { if (data.title === '') {
$title.hide(); $title.hide();
@ -34,7 +34,8 @@
} }
if (data.image === '') { if (data.image === '') {
$image.hide(); $imageColumn.hide();
$metaColumn.removeClass('col-md-6');
} else { } else {
$image.attr('src', data.image); $image.attr('src', data.image);
} }
@ -46,4 +47,26 @@
}); });
}; };
$.fn.pageSelector = function () {
return this.on('change', function () {
location.href = $(this).find(':selected').data('href');
});
};
$.fn.deleteCheckinModal = function () {
return this.each(function () {
$(this).on('show.bs.modal', function (event) {
var target = $(event.relatedTarget);
var modal = $(this);
modal.find('.modal-body .date-label').text(target.data('date'));
modal.data('id', target.data('id'));
}).find('.btn-danger').on('click', function (event) {
var modal = $('#deleteCheckinModal');
var form = modal.find('form');
form.attr('action', form.attr('action').replace('@', modal.data('id')));
form.submit();
})
});
};
})(jQuery); })(jQuery);

82
resources/assets/js/user/stats.js vendored Normal file
View File

@ -0,0 +1,82 @@
import CalHeatMap from 'cal-heatmap';
import Chart from 'chart.js';
function createLineGraph(id, labels, data) {
const context = document.getElementById(id).getContext('2d');
new Chart(context, {
type: 'line',
data: {
labels: labels,
datasets: [{
data: data,
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255, 99, 132, 1)',
borderWidth: 1
}]
},
options: {
legend: {
display: false
},
elements: {
line: {
tension: 0
}
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
function createBarGraph(id, labels, data) {
const context = document.getElementById(id).getContext('2d');
new Chart(context, {
type: 'bar',
data: {
labels: labels,
datasets: [{
data: data,
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255, 99, 132, 1)',
borderWidth: 1
}]
},
options: {
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
const graphData = JSON.parse(document.getElementById('graph-data').textContent);
new CalHeatMap().init({
itemSelector: '#cal-heatmap',
domain: 'month',
subDomain: 'day',
domainLabelFormat: '%Y/%m',
weekStartOnMonday: false,
start: new Date().setMonth(new Date().getMonth() - 9),
range: 10,
data: graphData.dailySum,
legend: [1, 2, 3, 4]
});
createLineGraph('monthly-graph', graphData.monthlyKey, graphData.monthlySum);
createLineGraph('yearly-graph', graphData.yearlyKey, graphData.yearlySum);
createBarGraph('hourly-graph', graphData.hourlyKey, graphData.hourlySum);
createBarGraph('dow-graph', ['日', '月', '火', '水', '木', '金', '土'], graphData.dowSum);

View File

@ -1,38 +0,0 @@
// Body
$body-bg: #f5f8fa;
// Borders
$laravel-border-color: darken($body-bg, 10%);
$list-group-border: $laravel-border-color;
$navbar-default-border: $laravel-border-color;
$panel-default-border: $laravel-border-color;
$panel-inner-border: $laravel-border-color;
// Brands
$brand-primary: #3097D1;
$brand-info: #8eb4cb;
$brand-success: #2ab27b;
$brand-warning: #cbb956;
$brand-danger: #bf5329;
// Typography
$icon-font-path: "~bootstrap-sass/assets/fonts/bootstrap/";
$font-family-sans-serif: "Raleway", sans-serif;
$font-size-base: 14px;
$line-height-base: 1.6;
$text-color: #636b6f;
// Navbar
$navbar-default-bg: #fff;
// Buttons
$btn-default-color: $text-color;
// Inputs
$input-border: lighten($text-color, 40%);
$input-border-focus: lighten($brand-primary, 25%);
$input-color-placeholder: lighten($text-color, 30%);
// Panels
$panel-default-heading-bg: #fff;

View File

@ -1,9 +1,8 @@
// Fonts
@import url("https://fonts.googleapis.com/css?family=Raleway:300,400,600");
// Variables
@import "variables";
// Bootstrap // Bootstrap
@import "node_modules/bootstrap-sass/assets/stylesheets/bootstrap"; @import "~bootstrap/scss/bootstrap";
// Open Iconic
@import "~open-iconic/font/css/open-iconic-bootstrap";
// Legacy app styles
@import "tissue.css";

View File

@ -21,7 +21,7 @@
} }
.container { .container {
transition: filter .15s liner; transition: filter .15s linear;
} }
.list-group-item.no-side-border { .list-group-item.no-side-border {
@ -53,8 +53,47 @@
border-bottom: 1px solid rgba(0, 0, 0, .125); border-bottom: 1px solid rgba(0, 0, 0, .125);
} }
.tis-page-selector {
margin-left: -1px;
width: calc(100% + 2px);
height: 100%;
border: 1px solid #dee2e6;
border-radius: 0;
line-height: 1.25;
}
@media (min-width: 992px) { @media (min-width: 992px) {
.tis-sidebar-info { .tis-sidebar-info {
font-size: small; font-size: small;
} }
}
#navbarNav > .d-lg-none > .row > div:first-of-type {
padding-left: 15px;
padding-right: 7.5px;
}
#navbarNav > .d-lg-none > .row > div {
padding-left: 7.5px;
padding-right: 15px;
}
#navbarNav > .d-lg-none > .row > .col .btn {
width: 100%;
}
#navbarAccountDropdownSp {
max-width: calc(100vw - 5em);
}
.card-img-left {
width: 100%;
border-top-left-radius: calc(.25rem - 1px);
border-bottom-left-radius: calc(.25rem - 1px);
}
.card-img-right {
width: 100%;
border-top-right-radius: calc(.25rem - 1px);
border-bottom-right-radius: calc(.25rem - 1px);
} }

View File

@ -0,0 +1,15 @@
<div class="card link-card mb-2 px-0 col-12 d-none" style="font-size: small;">
<a class="text-dark card-link" href="{{ $link }}" target="_blank" rel="noopener">
<div class="row no-gutters">
<div class="col-12 col-md-6">
<img src="" alt="Thumbnail" class="card-img-left bg-secondary">
</div>
<div class="col-12 col-md-6">
<div class="card-body">
<h6 class="card-title font-weight-bold">タイトル</h6>
<p class="card-text">コンテンツの説明文</p>
</div>
</div>
</div>
</a>
</div>

View File

@ -12,4 +12,4 @@
<p class="card-text mb-0">最長記録: {{ Formatter::formatInterval($summary[0]->longest) }}</p> <p class="card-text mb-0">最長記録: {{ Formatter::formatInterval($summary[0]->longest) }}</p>
<p class="card-text mb-0">最短記録: {{ Formatter::formatInterval($summary[0]->shortest) }}</p> <p class="card-text mb-0">最短記録: {{ Formatter::formatInterval($summary[0]->shortest) }}</p>
<p class="card-text mb-0">合計時間: {{ Formatter::formatInterval($summary[0]->total_times) }}</p> <p class="card-text mb-0">合計時間: {{ Formatter::formatInterval($summary[0]->total_times) }}</p>
<p class="card-text">通算回数: {{ $summary[0]->total_checkins }}</p> <p class="card-text">通算回数: {{ number_format($summary[0]->total_checkins) }}</p>

View File

@ -99,54 +99,5 @@
@endsection @endsection
@push('script') @push('script')
<script> <script src="{{ mix('js/checkin.js') }}"></script>
function updateTags() {
$('input[name=tags]').val(
$('#tags')
.find('li')
.map(function () {
return $(this).data('value');
})
.get()
.join(' ')
);
}
function insertTag(value) {
$('#tags').append('<li class="list-inline-item badge badge-primary" style="cursor: pointer;" data-value="' + value + '"><span class="oi oi-tag"></span> ' + value + ' | x</li>');
}
var initTags = $('input[name=tags]').val();
if (initTags.trim() !== '') {
initTags.split(' ').forEach(function (value) {
insertTag(value);
});
}
$('#tagInput').on('keydown', function (ev) {
var $this = $(this);
if ($this.val().trim() !== '') {
switch (ev.key) {
case 'Tab':
case 'Enter':
case ' ':
insertTag($this.val().trim());
$this.val('');
updateTags();
ev.preventDefault();
break;
}
} else if (ev.key === 'Enter') {
// 誤爆防止
ev.preventDefault();
}
});
$('#tags')
.on('click', 'li', function (ev) {
$(this).remove();
updateTags();
})
.parent()
.on('click', function (ev) {
$('#tagInput').focus();
});
</script>
@endpush @endpush

View File

@ -100,54 +100,5 @@
@endsection @endsection
@push('script') @push('script')
<script> <script src="{{ mix('js/checkin.js') }}"></script>
function updateTags() {
$('input[name=tags]').val(
$('#tags')
.find('li')
.map(function () {
return $(this).data('value');
})
.get()
.join(' ')
);
}
function insertTag(value) {
$('#tags').append('<li class="list-inline-item badge badge-primary" style="cursor: pointer;" data-value="' + value + '"><span class="oi oi-tag"></span> ' + value + ' | x</li>');
}
var initTags = $('input[name=tags]').val();
if (initTags.trim() !== '') {
initTags.split(' ').forEach(function (value) {
insertTag(value);
});
}
$('#tagInput').on('keydown', function (ev) {
var $this = $(this);
if ($this.val().trim() !== '') {
switch (ev.key) {
case 'Tab':
case 'Enter':
case ' ':
insertTag($this.val().trim());
$this.val('');
updateTags();
ev.preventDefault();
break;
}
} else if (ev.key === 'Enter') {
// 誤爆防止
ev.preventDefault();
}
});
$('#tags')
.on('click', 'li', function (ev) {
$(this).remove();
updateTags();
})
.parent()
.on('click', function (ev) {
$('#tagInput').focus();
});
</script>
@endpush @endpush

View File

@ -54,15 +54,8 @@
<!-- okazu link --> <!-- okazu link -->
@if (!empty($ejaculation->link)) @if (!empty($ejaculation->link))
<div class="row mx-0"> <div class="row mx-0">
<div class="card link-card mb-2 px-0 col-12 col-md-6 d-none" style="font-size: small;"> @component('components.link-card', ['link' => $ejaculation->link])
<a class="text-dark card-link" href="{{ $ejaculation->link }}" target="_blank" rel="noopener"> @endcomponent
<img src="" alt="Thumbnail" class="card-img-top bg-secondary">
<div class="card-body">
<h6 class="card-title font-weight-bold">タイトル</h6>
<p class="card-text">コンテンツの説明文</p>
</div>
</a>
</div>
<p class="d-flex align-items-baseline mb-2 col-12 px-0"> <p class="d-flex align-items-baseline mb-2 col-12 px-0">
<span class="oi oi-link-intact mr-1"></span><a class="overflow-hidden" href="{{ $ejaculation->link }}" target="_blank" rel="noopener">{{ $ejaculation->link }}</a> <span class="oi oi-link-intact mr-1"></span><a class="overflow-hidden" href="{{ $ejaculation->link }}" target="_blank" rel="noopener">{{ $ejaculation->link }}</a>
</p> </p>
@ -96,24 +89,3 @@
@endslot @endslot
@endcomponent @endcomponent
@endsection @endsection
@push('script')
<script type="text/javascript" src="//cdn.jsdelivr.net/npm/holderjs@2.9.4/holder.min.js"></script>
<script>
$('#deleteCheckinModal').on('show.bs.modal', function (event) {
var target = $(event.relatedTarget);
var modal = $(this);
modal.find('.modal-body .date-label').text(target.data('date'));
modal.data('id', target.data('id'));
}).find('.btn-danger').on('click', function (event) {
var modal = $('#deleteCheckinModal');
var form = modal.find('form');
form.attr('action', form.attr('action').replace('@', modal.data('id')));
form.submit();
});
$('.link-card').linkCard({
endpoint: '{{ url('/api/checkin/card') }}'
});
</script>
@endpush

View File

@ -76,15 +76,8 @@
<!-- okazu link --> <!-- okazu link -->
@if (!empty($ejaculation->link)) @if (!empty($ejaculation->link))
<div class="row mx-0"> <div class="row mx-0">
<div class="card link-card mb-2 px-0 col-12 col-md-6 d-none" style="font-size: small;"> @component('components.link-card', ['link' => $ejaculation->link])
<a class="text-dark card-link" href="{{ $ejaculation->link }}" target="_blank" rel="noopener"> @endcomponent
<img src="" alt="Thumbnail" class="card-img-top bg-secondary">
<div class="card-body">
<h6 class="card-title font-weight-bold">タイトル</h6>
<p class="card-text">コンテンツの説明文</p>
</div>
</a>
</div>
<p class="d-flex align-items-baseline mb-2 col-12 px-0"> <p class="d-flex align-items-baseline mb-2 col-12 px-0">
<span class="oi oi-link-intact mr-1"></span><a class="overflow-hidden" href="{{ $ejaculation->link }}" target="_blank" rel="noopener">{{ $ejaculation->link }}</a> <span class="oi oi-link-intact mr-1"></span><a class="overflow-hidden" href="{{ $ejaculation->link }}" target="_blank" rel="noopener">{{ $ejaculation->link }}</a>
</p> </p>
@ -98,6 +91,9 @@
@endif @endif
</li> </li>
@endforeach @endforeach
<li class="list-group-item no-side-border text-right">
<a href="{{ route('timeline.public') }}">もっと見る &raquo;</a>
</li>
</ul> </ul>
@endif @endif
</div> </div>
@ -106,43 +102,7 @@
@endsection @endsection
@push('script') @push('script')
<script type="text/javascript" src="//cdn.jsdelivr.net/npm/chart.js@2.7.1/dist/Chart.min.js"></script> <script id="global-count-labels" type="application/json">@json(array_keys($globalEjaculationCounts))</script>
<script> <script id="global-count-data" type="application/json">@json(array_values($globalEjaculationCounts))</script>
$('.link-card').linkCard({ <script src="{{ mix('js/home.js') }}"></script>
endpoint: '{{ url('/api/checkin/card') }}'
});
new Chart(document.getElementById('global-count-graph').getContext('2d'), {
type: 'bar',
data: {
labels: @json(array_keys($globalEjaculationCounts)),
datasets: [{
data: @json(array_values($globalEjaculationCounts)),
backgroundColor: 'rgba(0, 0, 0, .1)',
borderColor: 'rgba(0, 0, 0, .25)',
borderWidth: 1
}]
},
options: {
maintainAspectRatio: false,
legend: {
display: false
},
elements: {
line: {}
},
scales: {
xAxes: [{
display: false
}],
yAxes: [{
display: false,
ticks: {
beginAtZero: true
}
}]
}
}
});
</script>
@endpush @endpush

View File

@ -16,22 +16,6 @@
</a> </a>
@endforeach @endforeach
</div> </div>
<ul class="pagination mt-4 justify-content-center"> {{ $informations->links(null, ['className' => 'mt-4 justify-content-center']) }}
<li class="page-item {{ $informations->currentPage() === 1 ? 'disabled' : '' }}">
<a class="page-link" href="{{ $informations->previousPageUrl() }}" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
<span class="sr-only">Previous</span>
</a>
</li>
@for ($i = 1; $i <= $informations->lastPage(); $i++)
<li class="page-item {{ $i === $informations->currentPage() ? 'active' : '' }}"><a href="{{ $informations->url($i) }}" class="page-link">{{ $i }}</a></li>
@endfor
<li class="page-item {{ $informations->currentPage() === $informations->lastPage() ? 'disabled' : '' }}">
<a class="page-link" href="{{ $informations->nextPageUrl() }}" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
<span class="sr-only">Next</span>
</a>
</li>
</ul>
</div> </div>
@endsection @endsection

View File

@ -12,9 +12,8 @@
<title>{{ config('app.name', 'Tissue') }}</title> <title>{{ config('app.name', 'Tissue') }}</title>
@endif @endif
<link href="{{ asset('css/bootstrap.min.css') }}" rel="stylesheet"> <link href="{{ asset('manifest.json') }}" rel="manifest">
<link href="{{ asset('css/open-iconic-bootstrap.min.css') }}" rel="stylesheet"> <link href="{{ mix('css/app.css') }}" rel="stylesheet">
<link href="{{ asset('css/tissue.css') }}" rel="stylesheet">
@stack('head') @stack('head')
</head> </head>
@ -36,68 +35,146 @@
</form> </form>
<div class="container"> <div class="container">
<a href="{{ route('home') }}" class="navbar-brand">{{ config('app.name', 'Tissue') }}</a> <a href="{{ route('home') }}" class="navbar-brand mr-auto">{{ config('app.name', 'Tissue') }}</a>
@auth
<div class="d-lg-none navbar-nav">
<div class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle p-2" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img src="{{ Auth::user()->getProfileImageUrl(30) }}" width="30" height="30" class="rounded d-inline-block align-top">
</a>
<div class="dropdown-menu dropdown-menu-right position-absolute" aria-labelledby="navbarDropdownMenuLink" id="navbarAccountDropdownSp">
<a href="{{ route('user.profile', ['name' => Auth::user()->name]) }}" class="dropdown-item text-truncate">
<strong>{{ Auth::user()->display_name }}</strong>
<p class="mb-0 text-muted">
<span>&commat;{{ Auth::user()->name }}</span>
</p>
</a>
<div class="dropdown-divider"></div>
<a href="{{ route('setting') }}" class="dropdown-item">設定</a>
<a href="{{ route('logout') }}" class="dropdown-item" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">ログアウト</a>
</div>
</div>
</div>
@endauth
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
<div class="collapse navbar-collapse" id="navbarNav"> <div class="collapse navbar-collapse" id="navbarNav">
@auth @auth
<ul class="navbar-nav mr-auto"> <!-- PC navbar -->
<li class="nav-item {{ stripos(Route::currentRouteName(), 'home') === 0 ? 'active' : ''}}"> <div class="d-none d-lg-flex navbar-collapse ml-3">
<a class="nav-link" href="{{ route('home') }}">ホーム</a> <ul class="navbar-nav mr-auto">
</li> <li class="nav-item {{ stripos(Route::currentRouteName(), 'home') === 0 ? 'active' : ''}}">
<li class="nav-item {{ stripos(Route::currentRouteName(), 'user.profile') === 0 ? 'active' : ''}}"> <a class="nav-link" href="{{ route('home') }}">ホーム</a>
<a class="nav-link" href="{{ route('user.profile', ['name' => Auth::user()->name]) }}">タイムライン</a> </li>
</li> <li class="nav-item {{ stripos(Route::currentRouteName(), 'user.profile') === 0 ? 'active' : ''}}">
<li class="nav-item {{ stripos(Route::currentRouteName(), 'user.stats') === 0 ? 'active' : ''}}"> <a class="nav-link" href="{{ route('user.profile', ['name' => Auth::user()->name]) }}">タイムライン</a>
<a class="nav-link" href="{{ route('user.stats', ['name' => Auth::user()->name]) }}">グラフ</a> </li>
</li> <li class="nav-item {{ stripos(Route::currentRouteName(), 'user.stats') === 0 ? 'active' : ''}}">
<li class="nav-item {{ stripos(Route::currentRouteName(), 'user.okazu') === 0 ? 'active' : ''}}"> <a class="nav-link" href="{{ route('user.stats', ['name' => Auth::user()->name]) }}">グラフ</a>
<a class="nav-link" href="{{ route('user.okazu', ['name' => Auth::user()->name]) }}">オカズ</a> </li>
</li> <li class="nav-item {{ stripos(Route::currentRouteName(), 'user.okazu') === 0 ? 'active' : ''}}">
{{--<li class="nav-item"> <a class="nav-link" href="{{ route('user.okazu', ['name' => Auth::user()->name]) }}">オカズ</a>
<a class="nav-link" href="{{ route('ranking') }}">ランキング</a> </li>
</li>--}} {{--<li class="nav-item">
</ul> <a class="nav-link" href="{{ route('ranking') }}">ランキング</a>
<form action="{{ stripos(Route::currentRouteName(), 'search') === 0 ? route(Route::currentRouteName()) : route('search') }}" class="form-inline mr-2"> </li>--}}
<div class="input-group"> </ul>
<input type="search" name="q" class="form-control" placeholder="検索..." value="{{ stripos(Route::currentRouteName(), 'search') === 0 ? $inputs['q'] : '' }}" required> <form action="{{ stripos(Route::currentRouteName(), 'search') === 0 ? route(Route::currentRouteName()) : route('search') }}" class="form-inline mr-2">
<div class="input-group-append"> <div class="input-group">
<button class="btn btn-outline-secondary" type="submit"><span class="oi oi-magnifying-glass" aria-hidden="true"></span><span class="sr-only">検索</span></button> <input type="search" name="q" class="form-control" placeholder="検索..." value="{{ stripos(Route::currentRouteName(), 'search') === 0 ? $inputs['q'] : '' }}" required>
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="submit"><span class="oi oi-magnifying-glass" aria-hidden="true"></span><span class="sr-only">検索</span></button>
</div>
</div>
</form>
<form class="form-inline mr-2">
<a href="{{ route('checkin') }}" class="btn btn-outline-success">チェックイン</a>
</form>
<ul class="navbar-nav">
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img src="{{ Auth::user()->getProfileImageUrl(30) }}" width="30" height="30" class="rounded d-inline-block align-top">
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdownMenuLink">
<a href="{{ route('user.profile', ['name' => Auth::user()->name]) }}" class="dropdown-item">
<strong>{{ Auth::user()->display_name }}</strong>
<p class="mb-0 text-muted">
<span>&commat;{{ Auth::user()->name }}</span>
</p>
</a>
<div class="dropdown-divider"></div>
<a href="{{ route('setting') }}" class="dropdown-item">設定</a>
<a href="{{ route('logout') }}" class="dropdown-item" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">ログアウト</a>
</div>
</li>
</ul>
</div>
<!-- SP navbar -->
<div class="d-lg-none">
<div class="row mt-2">
<div class="col">
<a class="btn btn-outline-{{ stripos(Route::currentRouteName(), 'home') === 0 ? 'primary' : 'secondary'}}" href="{{ route('home') }}" role="button">ホーム</a>
</div>
<div class="col">
<a class="btn btn-outline-{{ stripos(Route::currentRouteName(), 'user.profile') === 0 ? 'primary' : 'secondary'}}" href="{{ route('user.profile', ['name' => Auth::user()->name]) }}" role="button">タイムライン</a>
</div> </div>
</div> </div>
</form> <div class="row mt-2">
<form class="form-inline mr-2"> <div class="col">
<a href="{{ route('checkin') }}" class="btn btn-outline-success">チェックイン</a> <a class="btn btn-outline-{{ stripos(Route::currentRouteName(), 'user.stats') === 0 ? 'primary' : 'secondary'}}" href="{{ route('user.stats', ['name' => Auth::user()->name]) }}" role="button">グラフ</a>
</form>
<ul class="navbar-nav">
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img src="{{ Auth::user()->getProfileImageUrl(30) }}" width="30" height="30" class="rounded d-inline-block align-top">
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdownMenuLink">
<a href="{{ route('user.profile', ['name' => Auth::user()->name]) }}" class="dropdown-item">
<strong>{{ Auth::user()->display_name }}</strong>
<p class="mb-0 text-muted">
<span>&commat;{{ Auth::user()->name }}</span>
</p>
</a>
<div class="dropdown-divider"></div>
<a href="{{ route('setting') }}" class="dropdown-item">設定</a>
<a href="{{ route('logout') }}" class="dropdown-item" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">ログアウト</a>
</div> </div>
</li> <div class="col">
</ul> <a class="btn btn-outline-{{ stripos(Route::currentRouteName(), 'user.okazu') === 0 ? 'primary' : 'secondary'}}" href="{{ route('user.okazu', ['name' => Auth::user()->name]) }}" role="button">オカズ</a>
</div>
</div>
{{-- <div class="row mt-2">
<div class="col">
<a class="btn btn-outline-secondary" href="{{ route('ranking') }}">ランキング</a>
</div>
</div> --}}
<div class="row mt-2">
<form action="{{ stripos(Route::currentRouteName(), 'search') === 0 ? route(Route::currentRouteName()) : route('search') }}" class="col">
<div class="input-group">
<input type="search" name="q" class="form-control" placeholder="検索..." value="{{ stripos(Route::currentRouteName(), 'search') === 0 ? $inputs['q'] : '' }}" required>
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="submit"><span class="oi oi-magnifying-glass" aria-hidden="true"></span><span class="sr-only">検索</span></button>
</div>
</div>
</form>
</div>
<div class="row mt-2">
<form class="form-inline col">
<a class="btn btn-outline-success" href="{{ route('checkin') }}">チェックイン</a>
</form>
</div>
</div>
@endauth @endauth
@guest @guest
<ul class="navbar-nav ml-auto mr-2"> <!-- PC navbar -->
<li class="nav-item"> <div class="d-none d-lg-flex navbar-collapse">
<a href="{{ route('register') }}" class="nav-link">会員登録</a> <ul class="navbar-nav ml-auto mr-2">
</li> <li class="nav-item">
</ul> <a href="{{ route('register') }}" class="nav-link">会員登録</a>
<form class="form-inline"> </li>
<a href="{{ route('login') }}" class="btn btn-outline-secondary">ログイン</a> </ul>
</form> <form class="form-inline">
<a href="{{ route('login') }}" class="btn btn-outline-secondary">ログイン</a>
</form>
</div>
<!-- SP navbar -->
<div class="d-lg-none">
<div class="row mt-2">
<div class="col">
<a class="btn btn-outline-secondary" href="{{ route('register') }}" role="button">会員登録</a>
</div>
<div class="col">
<form class="form-inline">
<a class="btn btn-outline-secondary" href="{{ route('login') }}">ログイン</a>
</form>
</div>
</div>
</div>
@endguest @endguest
</div> </div>
</div> </div>
@ -140,33 +217,7 @@
</div> </div>
</div> </div>
@endguest @endguest
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <script src="{{ mix('js/app.js') }}"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-cookie/2.2.0/js.cookie.js"></script>
<script type="text/javascript" src="{{ asset('js/bootstrap.min.js') }}"></script>
<script type="text/javascript" src="{{ asset('js/tissue.js') }}"></script>
<script>
$(function(){
@guest
if (Cookies.get('agechecked')) {
$('body').removeClass('tis-need-agecheck');
} else {
$('#ageCheckModal').modal({ backdrop: 'static' })
.on('hide.bs.modal', function() {
$('body').removeClass('tis-need-agecheck');
Cookies.set('agechecked', '1', { expires: 365 });
});
}
@endguest
$('[data-toggle="tooltip"]').tooltip();
$('.alert').alert();
@if (session('status'))
setTimeout(function () {
$('#status').alert('close');
}, 5000);
@endif
});
</script>
@stack('script') @stack('script')
</body> </body>
</html> </html>

View File

@ -35,15 +35,8 @@
<!-- okazu link --> <!-- okazu link -->
@if (!empty($ejaculation->link)) @if (!empty($ejaculation->link))
<div class="row mx-0"> <div class="row mx-0">
<div class="card link-card mb-2 px-0 col-12 col-md-6 d-none" style="font-size: small;"> @component('components.link-card', ['link' => $ejaculation->link])
<a class="text-dark card-link" href="{{ $ejaculation->link }}" target="_blank" rel="noopener"> @endcomponent
<img src="" alt="Thumbnail" class="card-img-top bg-secondary">
<div class="card-body">
<h6 class="card-title font-weight-bold">タイトル</h6>
<p class="card-text">コンテンツの説明文</p>
</div>
</a>
</div>
<p class="d-flex align-items-baseline mb-2 col-12 px-0"> <p class="d-flex align-items-baseline mb-2 col-12 px-0">
<span class="oi oi-link-intact mr-1"></span><a class="overflow-hidden" href="{{ $ejaculation->link }}" target="_blank" rel="noopener">{{ $ejaculation->link }}</a> <span class="oi oi-link-intact mr-1"></span><a class="overflow-hidden" href="{{ $ejaculation->link }}" target="_blank" rel="noopener">{{ $ejaculation->link }}</a>
</p> </p>
@ -58,30 +51,6 @@
</li> </li>
@endforeach @endforeach
</ul> </ul>
<ul class="pagination mt-4 justify-content-center"> {{ $results->links(null, ['className' => 'mt-4 justify-content-center']) }}
<li class="page-item {{ $results->currentPage() === 1 ? 'disabled' : '' }}">
<a class="page-link" href="{{ $results->previousPageUrl() }}" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
<span class="sr-only">Previous</span>
</a>
</li>
@for ($i = 1; $i <= $results->lastPage(); $i++)
<li class="page-item {{ $i === $results->currentPage() ? 'active' : '' }}"><a href="{{ $results->url($i) }}" class="page-link">{{ $i }}</a></li>
@endfor
<li class="page-item {{ $results->currentPage() === $results->lastPage() ? 'disabled' : '' }}">
<a class="page-link" href="{{ $results->nextPageUrl() }}" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
<span class="sr-only">Next</span>
</a>
</li>
</ul>
@endif @endif
@endsection @endsection
@push('script')
<script>
$('.link-card').linkCard({
endpoint: '{{ url('/api/checkin/card') }}'
});
</script>
@endpush

View File

@ -23,11 +23,5 @@
@endsection @endsection
@push('script') @push('script')
<script> <script src="{{ mix('js/setting/privacy.js') }}"></script>
$('#protected').on('change', function () {
if (!$(this).prop('checked')) {
alert('チェックイン履歴を公開に切り替えると、個別に非公開設定されているものを除いた全てのチェックインが誰でも閲覧できるようになります。\nご注意ください。');
}
});
</script>
@endpush @endpush

View File

@ -0,0 +1,56 @@
@extends('layouts.base')
@section('title', 'お惣菜コーナー')
@section('content')
<div class="container pb-1">
<h2 class="mb-3">お惣菜コーナー</h2>
<p class="text-secondary">公開チェックインから、オカズリンク付きのものを表示しています。</p>
</div>
<div class="container-fluid">
<div class="row mx-1">
@foreach($ejaculations as $ejaculation)
<div class="col-12 col-lg-6 col-xl-4 py-3 tis-word-wrap border-top">
<!-- span -->
<div class="d-flex justify-content-between">
<h5>
<a href="{{ route('user.profile', ['id' => $ejaculation->user->name]) }}" class="text-dark"><img src="{{ $ejaculation->user->getProfileImageUrl(30) }}" width="30" height="30" class="rounded d-inline-block align-bottom"> {{ $ejaculation->user->display_name }}</a>
<a href="{{ route('checkin.show', ['id' => $ejaculation->id]) }}" class="text-muted"><small>{{ $ejaculation->ejaculated_date->format('Y/m/d H:i') }}</small></a>
</h5>
<div>
<a class="text-secondary timeline-action-item" href="{{ route('checkin', ['link' => $ejaculation->link, 'tags' => $ejaculation->textTags()]) }}"><span class="oi oi-reload" data-toggle="tooltip" data-placement="bottom" title="同じオカズでチェックイン"></span></a>
</div>
</div>
<!-- tags -->
@if ($ejaculation->is_private || $ejaculation->tags->isNotEmpty())
<p class="mb-2">
@if ($ejaculation->is_private)
<span class="badge badge-warning"><span class="oi oi-lock-locked"></span> 非公開</span>
@endif
@foreach ($ejaculation->tags as $tag)
<a class="badge badge-secondary" href="{{ route('search', ['q' => $tag->name]) }}"><span class="oi oi-tag"></span> {{ $tag->name }}</a>
@endforeach
</p>
@endif
<!-- okazu link -->
@if (!empty($ejaculation->link))
<div class="row mx-0">
@component('components.link-card', ['link' => $ejaculation->link])
@endcomponent
<p class="d-flex align-items-baseline mb-2 col-12 px-0">
<span class="oi oi-link-intact mr-1"></span><a class="overflow-hidden" href="{{ $ejaculation->link }}" target="_blank" rel="noopener">{{ $ejaculation->link }}</a>
</p>
</div>
@endif
<!-- note -->
@if (!empty($ejaculation->note))
<p class="mb-0 tis-word-wrap">
{!! Formatter::linkify(nl2br(e($ejaculation->note))) !!}
</p>
@endif
</div>
@endforeach
</div>
{{ $ejaculations->links(null, ['className' => 'mt-4 justify-content-center']) }}
</div>
@endsection

View File

@ -60,15 +60,8 @@
<!-- okazu link --> <!-- okazu link -->
@if (!empty($ejaculation->link)) @if (!empty($ejaculation->link))
<div class="row mx-0"> <div class="row mx-0">
<div class="card link-card mb-2 px-0 col-12 col-md-6 d-none" style="font-size: small;"> @component('components.link-card', ['link' => $ejaculation->link])
<a class="text-dark card-link" href="{{ $ejaculation->link }}" target="_blank" rel="noopener"> @endcomponent
<img src="" alt="Thumbnail" class="card-img-top bg-secondary">
<div class="card-body">
<h6 class="card-title font-weight-bold">タイトル</h6>
<p class="card-text">コンテンツの説明文</p>
</div>
</a>
</div>
<p class="d-flex align-items-baseline mb-2 col-12 px-0"> <p class="d-flex align-items-baseline mb-2 col-12 px-0">
<span class="oi oi-link-intact mr-1"></span><a class="overflow-hidden" href="{{ $ejaculation->link }}" target="_blank" rel="noopener">{{ $ejaculation->link }}</a> <span class="oi oi-link-intact mr-1"></span><a class="overflow-hidden" href="{{ $ejaculation->link }}" target="_blank" rel="noopener">{{ $ejaculation->link }}</a>
</p> </p>
@ -87,23 +80,7 @@
</li> </li>
@endforelse @endforelse
</ul> </ul>
<ul class="pagination mt-4 justify-content-center"> {{ $ejaculations->links(null, ['className' => 'mt-4 justify-content-center']) }}
<li class="page-item {{ $ejaculations->currentPage() === 1 ? 'disabled' : '' }}">
<a class="page-link" href="{{ $ejaculations->previousPageUrl() }}" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
<span class="sr-only">Previous</span>
</a>
</li>
@for ($i = 1; $i <= $ejaculations->lastPage(); $i++)
<li class="page-item {{ $i === $ejaculations->currentPage() ? 'active' : '' }}"><a href="{{ $ejaculations->url($i) }}" class="page-link">{{ $i }}</a></li>
@endfor
<li class="page-item {{ $ejaculations->currentPage() === $ejaculations->lastPage() ? 'disabled' : '' }}">
<a class="page-link" href="{{ $ejaculations->nextPageUrl() }}" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
<span class="sr-only">Next</span>
</a>
</li>
</ul>
@endif @endif
@component('components.modal', ['id' => 'deleteCheckinModal']) @component('components.modal', ['id' => 'deleteCheckinModal'])
@ -121,23 +98,3 @@
@endslot @endslot
@endcomponent @endcomponent
@endsection @endsection
@push('script')
<script>
$('#deleteCheckinModal').on('show.bs.modal', function (event) {
var target = $(event.relatedTarget);
var modal = $(this);
modal.find('.modal-body .date-label').text(target.data('date'));
modal.data('id', target.data('id'));
}).find('.btn-danger').on('click', function (event) {
var modal = $('#deleteCheckinModal');
var form = modal.find('form');
form.attr('action', form.attr('action').replace('@', modal.data('id')));
form.submit();
});
$('.link-card').linkCard({
endpoint: '{{ url('/api/checkin/card') }}'
});
</script>
@endpush

View File

@ -30,87 +30,6 @@
@endsection @endsection
@push('script') @push('script')
<script type="text/javascript" src="//cdn.jsdelivr.net/npm/chart.js@2.7.1/dist/Chart.min.js"></script> <script id="graph-data" type="application/javascript">@json($graphData)</script>
<script type="text/javascript" src="//d3js.org/d3.v3.min.js"></script> <script src="{{ mix('js/user/stats.js') }}"></script>
<script type="text/javascript" src="//cdn.jsdelivr.net/cal-heatmap/3.3.10/cal-heatmap.min.js"></script>
<script>
var cal = new CalHeatMap();
cal.init({
itemSelector: '#cal-heatmap',
domain: 'month',
subDomain: 'day',
domainLabelFormat: '%Y/%m',
weekStartOnMonday: false,
start: new Date({{ \Carbon\Carbon::now()->addMonths(-9)->timestamp * 1000 }}),
range: 10,
data: @json($dailySum),
legend: [1, 2, 3, 4]
});
function createLineGraph(id, labels, data) {
var context = document.getElementById(id).getContext('2d');
var chart = new Chart(context, {
type: 'line',
data: {
labels: labels,
datasets: [{
data: data,
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255, 99, 132, 1)',
borderWidth: 1
}]
},
options: {
legend: {
display: false
},
elements: {
line: {
tension: 0
}
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
function createBarGraph(id, labels, data) {
var context = document.getElementById(id).getContext('2d');
var chart = new Chart(context, {
type: 'bar',
data: {
labels: labels,
datasets: [{
data: data,
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255, 99, 132, 1)',
borderWidth: 1
}]
},
options: {
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
createLineGraph('monthly-graph', @json(array_keys($monthlySum)), @json(array_values($monthlySum)));
createLineGraph('yearly-graph', @json(array_keys($yearlySum)), @json(array_values($yearlySum)));
createBarGraph('hourly-graph', @json(array_keys($hourlySum)), @json(array_values($hourlySum)));
createBarGraph('dow-graph', ['日', '月', '火', '水', '木', '金', '土'], @json($dowSum));
</script>
@endpush @endpush

View File

@ -0,0 +1,59 @@
@if ($paginator->hasPages())
{{-- for PC : >= lg --}}
<ul class="pagination d-none d-lg-flex {{ $className ?? '' }}">
{{-- Previous Page Link --}}
@if ($paginator->onFirstPage())
<li class="page-item disabled"><span class="page-link">&laquo;</span></li>
@else
<li class="page-item"><a class="page-link" href="{{ $paginator->previousPageUrl() }}" rel="prev">&laquo;</a></li>
@endif
{{-- Pagination Elements --}}
@foreach ($elements as $element)
{{-- "Three Dots" Separator --}}
@if (is_string($element))
<li class="page-item disabled"><span class="page-link">{{ $element }}</span></li>
@endif
{{-- Array Of Links --}}
@if (is_array($element))
@foreach ($element as $page => $url)
@if ($page == $paginator->currentPage())
<li class="page-item active"><span class="page-link">{{ $page }}</span></li>
@else
<li class="page-item"><a class="page-link" href="{{ $url }}">{{ $page }}</a></li>
@endif
@endforeach
@endif
@endforeach
{{-- Next Page Link --}}
@if ($paginator->hasMorePages())
<li class="page-item"><a class="page-link" href="{{ $paginator->nextPageUrl() }}" rel="next">&raquo;</a></li>
@else
<li class="page-item disabled"><span class="page-link">&raquo;</span></li>
@endif
</ul>
{{-- for Phone : <= md --}}
<ul class="pagination d-flex d-lg-none {{ $className ?? '' }}">
@if ($paginator->onFirstPage())
<li class="page-item w-25 text-center disabled"><span class="page-link">&laquo;</span></li>
@else
<li class="page-item w-25 text-center"><a class="page-link" href="{{ $paginator->previousPageUrl() }}" rel="prev">&laquo;</a></li>
@endif
<li class="page-item w-25 text-center">
<select class="custom-select tis-page-selector" aria-label="Page">
@for ($i = 1; $i <= $paginator->lastPage(); $i++)
<option value="{{ $i }}" {{ $i === $paginator->currentPage() ? 'selected' : '' }} data-href="{{ $paginator->url($i) }}">{{ $i }}</option>
@endfor
</select>
</li>
@if ($paginator->hasMorePages())
<li class="page-item w-25 text-center"><a class="page-link" href="{{ $paginator->nextPageUrl() }}" rel="next">&raquo;</a></li>
@else
<li class="page-item w-25 text-center disabled"><span class="page-link">&raquo;</span></li>
@endif
</ul>
@endif

View File

@ -1,9 +1,5 @@
<?php <?php
use App\MetadataResolver\MetadataResolver;
use App\Utilities\Formatter;
use Illuminate\Http\Request;
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| API Routes | API Routes
@ -15,31 +11,8 @@ use Illuminate\Http\Request;
| |
*/ */
Route::middleware('auth:api')->get('/user', function (Request $request) { //Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user(); // return $request->user();
}); //});
Route::get('/checkin/card', function (Request $request, MetadataResolver $resolver, Formatter $formatter) { Route::get('/checkin/card', 'Api\\CardController@show');
$request->validate([
'url:required|url'
]);
$url = $formatter->normalizeUrl($request->input('url'));
$metadata = App\Metadata::find($url);
if ($metadata == null || ($metadata->expires_at !== null && $metadata->expires_at < now())) {
$resolved = $resolver->resolve($url);
$metadata = App\Metadata::updateOrCreate(['url' => $url], [
'title' => $resolved->title,
'description' => $resolved->description,
'image' => $resolved->image,
'expires_at' => $resolved->expires_at
]);
}
$response = response()->json($metadata);
if (!config('app.debug')) {
$response = $response->setCache(['public' => true, 'max_age' => 86400]);
}
return $response;
});

View File

@ -15,9 +15,7 @@ Auth::routes();
Route::get('/', 'HomeController@index')->name('home'); Route::get('/', 'HomeController@index')->name('home');
Route::get('/user', function () { Route::get('/user', 'UserController@redirectMypage')->middleware('auth');
return redirect()->route('user.profile', ['name' => Auth::user()->name]);
})->middleware('auth')->name('user.profile');
Route::get('/user/{name?}', 'UserController@profile')->name('user.profile'); Route::get('/user/{name?}', 'UserController@profile')->name('user.profile');
Route::get('/user/{name}/stats', 'UserController@stats')->name('user.stats'); Route::get('/user/{name}/stats', 'UserController@stats')->name('user.stats');
Route::get('/user/{name}/okazu', 'UserController@okazu')->name('user.okazu'); Route::get('/user/{name}/okazu', 'UserController@okazu')->name('user.okazu');
@ -30,6 +28,8 @@ Route::middleware('auth')->group(function () {
Route::put('/checkin/{id}', 'EjaculationController@update')->name('checkin.update'); Route::put('/checkin/{id}', 'EjaculationController@update')->name('checkin.update');
Route::delete('/checkin/{id}', 'EjaculationController@destroy')->name('checkin.destroy'); Route::delete('/checkin/{id}', 'EjaculationController@destroy')->name('checkin.destroy');
Route::get('/timeline/public', 'TimelineController@showPublic')->name('timeline.public');
Route::redirect('/setting', '/setting/profile', 301); Route::redirect('/setting', '/setting/profile', 301);
Route::get('/setting/profile', 'SettingController@profile')->name('setting'); Route::get('/setting/profile', 'SettingController@profile')->name('setting');
Route::post('/setting/profile', 'SettingController@updateProfile')->name('setting.profile.update'); Route::post('/setting/profile', 'SettingController@updateProfile')->name('setting.profile.update');

View File

@ -0,0 +1,54 @@
<?php
namespace Tests\Unit\MetadataResolver;
use App\MetadataResolver\Resolver;
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\Psr7\Response;
use Monolog\Handler\AbstractHandler;
trait CreateMockedResolver
{
/**
* @var Resolver
*/
protected $resolver;
/**
* @var AbstractHandler
*/
protected $handler;
/**
* @param string $resolverClass
* @param string $responseText
* @param array $headers
* @param int $status
* @return Resolver
*/
protected function createResolver(string $resolverClass, string $responseText, array $headers = [], int $status = 200)
{
if (!$this->shouldUseMock()) {
$this->resolver = app()->make($resolverClass);
return $this->resolver;
}
$headers += [
'content-type' => 'text/html',
];
$mockResponse = new Response($status, $headers, $responseText);
$this->handler = new MockHandler([$mockResponse]);
$client = new Client(['handler' => $this->handler]);
$this->resolver = app()->make($resolverClass, ['client' => $client]);
return $this->resolver;
}
protected function shouldUseMock(): bool
{
return (bool)env('TEST_USE_HTTP_MOCK', true);
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace Tests\Unit\MetadataResolver;
use App\MetadataResolver\DLsiteResolver;
use Tests\TestCase;
class DLsiteResolverTest extends TestCase
{
use CreateMockedResolver;
public function setUp()
{
parent::setUp();
if (!$this->shouldUseMock()) {
sleep(1);
}
}
public function testProduct()
{
$responseText = file_get_contents(__DIR__.'/../../fixture/DLsite/testProduct.html');
$this->createResolver(DLsiteResolver::class, $responseText);
$metadata = $this->resolver->resolve('https://www.dlsite.com/maniax/work/=/product_id/RJ171695.html');
$this->assertEquals('【骨伝導風】道草屋 たびらこ-一緒にはみがき【耳かき&はみがき】 [桃色CODE] | DLsite', $metadata->title);
$this->assertStringStartsWith('少しお母さんっぽい店員さんに、歯磨きからおやすみまでお世話されます。はみがきで興奮しちゃった旦那様のも、しっかりお世話してくれます。歯磨き音は特殊なマイクを使用、骨伝導風ハイレゾバイノーラル音声です。', $metadata->description);
$this->assertEquals('https://img.dlsite.jp/modpub/images2/work/doujin/RJ172000/RJ171695_img_main.jpg', $metadata->image);
if ($this->shouldUseMock()) {
$this->assertSame('https://www.dlsite.com/maniax/work/=/product_id/RJ171695.html', (string) $this->handler->getLastRequest()->getUri());
}
}
public function testProductSP()
{
$responseText = file_get_contents(__DIR__.'/../../fixture/DLsite/testProductSP.html');
$this->createResolver(DLsiteResolver::class, $responseText);
$metadata = $this->resolver->resolve('https://www.dlsite.com/home/work/=/product_id/RJ234446.html');
$this->assertEquals('【大人向け耳かき】道草屋 はこべら5 時計修理のはこべらさん。他【汗の匂い】 [桃色CODE] | DLsite', $metadata->title);
$this->assertStringStartsWith('夏の終わり、二人で遠くの花火を眺めます。耳かきの他、クラシックシェービング、氷を含んだあまがみ、冷紅茶、ジャズ、時計の修理、それから大人向けの汗の匂い。色々な事のある、二泊三日の田舎宿音声です。', $metadata->description);
$this->assertEquals('https://img.dlsite.jp/modpub/images2/work/doujin/RJ235000/RJ234446_img_main.jpg', $metadata->image);
if ($this->shouldUseMock()) {
$this->assertSame('https://www.dlsite.com/home/work/=/product_id/RJ234446.html', (string) $this->handler->getLastRequest()->getUri());
}
}
}

View File

@ -7,95 +7,139 @@ use Tests\TestCase;
class NijieResolverTest extends TestCase class NijieResolverTest extends TestCase
{ {
use CreateMockedResolver;
public function setUp()
{
parent::setUp();
if (!$this->shouldUseMock()) {
sleep(1);
}
}
public function testStandardPicture() public function testStandardPicture()
{ {
sleep(1); $responseText = file_get_contents(__DIR__ . '/../../fixture/Nijie/testStandardPictureResponse.html');
$resolver = new NijieResolver();
$metadata = $resolver->resolve('https://nijie.info/view.php?id=66384'); $this->createResolver(NijieResolver::class, $responseText);
$metadata = $this->resolver->resolve('https://nijie.info/view.php?id=66384');
$this->assertEquals('チンポップくんの日常ep.1「チンポップくんと釣り」 | ニジエ運営', $metadata->title); $this->assertEquals('チンポップくんの日常ep.1「チンポップくんと釣り」 | ニジエ運営', $metadata->title);
$this->assertEquals("メールマガジン漫画のバックナンバー第一話です!\r\n最新話はメールマガジンより配信中です。", $metadata->description); $this->assertEquals("メールマガジン漫画のバックナンバー第一話です!\r\n最新話はメールマガジンより配信中です。", $metadata->description);
$this->assertRegExp('/pic\d+\.nijie\.info/', $metadata->image); $this->assertRegExp('/pic\d+\.nijie\.info/', $metadata->image);
$this->assertNotRegExp('~/diff/main/~', $metadata->image); $this->assertNotRegExp('~/diff/main/~', $metadata->image);
if ($this->shouldUseMock()) {
$this->assertSame('https://nijie.info/view.php?id=66384', (string)$this->handler->getLastRequest()->getUri());
}
} }
public function testMultiplePicture() public function testMultiplePicture()
{ {
sleep(1); $responseText = file_get_contents(__DIR__ . '/../../fixture/Nijie/testMultiplePictureResponse.html');
$resolver = new NijieResolver();
$metadata = $resolver->resolve('https://nijie.info/view.php?id=202707'); $this->createResolver(NijieResolver::class, $responseText);
$metadata = $this->resolver->resolve('https://nijie.info/view.php?id=202707');
$this->assertEquals('ニジエ壁紙 | ニジエ運営', $metadata->title); $this->assertEquals('ニジエ壁紙 | ニジエ運営', $metadata->title);
$this->assertEquals("ニジエのPCとiphone用(4.7inch推奨)の壁紙です。\r\n保存してご自由にお使いくださいませ。", $metadata->description); $this->assertEquals("ニジエのPCとiphone用(4.7inch推奨)の壁紙です。\r\n保存してご自由にお使いくださいませ。", $metadata->description);
$this->assertRegExp('/pic\d+\.nijie\.info/', $metadata->image); $this->assertRegExp('/pic\d+\.nijie\.info/', $metadata->image);
$this->assertNotRegExp('~/diff/main/~', $metadata->image); $this->assertNotRegExp('~/diff/main/~', $metadata->image);
if ($this->shouldUseMock()) {
$this->assertSame('https://nijie.info/view.php?id=202707', (string)$this->handler->getLastRequest()->getUri());
}
} }
public function testAnimationGif() public function testAnimationGif()
{ {
sleep(1); $responseText = file_get_contents(__DIR__ . '/../../fixture/Nijie/testAnimationGifResponse.html');
$resolver = new NijieResolver();
$metadata = $resolver->resolve('https://nijie.info/view.php?id=9537'); $this->createResolver(NijieResolver::class, $responseText);
$metadata = $this->resolver->resolve('https://nijie.info/view.php?id=9537');
$this->assertEquals('ニジエがgifに対応したんだってね 奥さん | 黒末アプコ', $metadata->title); $this->assertEquals('ニジエがgifに対応したんだってね 奥さん | 黒末アプコ', $metadata->title);
$this->assertEquals('アニメgifとか専門外なのでよくわかりませんでした', $metadata->description); $this->assertEquals('アニメgifとか専門外なのでよくわかりませんでした', $metadata->description);
$this->assertRegExp('~/nijie\.info/pic/logo~', $metadata->image); $this->assertRegExp('~/nijie\.info/pic/logo~', $metadata->image);
if ($this->shouldUseMock()) {
$this->assertSame('https://nijie.info/view.php?id=9537', (string)$this->handler->getLastRequest()->getUri());
}
} }
public function testMp4Movie() public function testMp4Movie()
{ {
sleep(1); $responseText = file_get_contents(__DIR__ . '/../../fixture/Nijie/testMp4MovieResponse.html');
$resolver = new NijieResolver();
$metadata = $resolver->resolve('https://nijie.info/view.php?id=256283'); $this->createResolver(NijieResolver::class, $responseText);
$metadata = $this->resolver->resolve('https://nijie.info/view.php?id=256283');
$this->assertEquals('てすと | ニジエ運営', $metadata->title); $this->assertEquals('てすと | ニジエ運営', $metadata->title);
$this->assertEquals("H264動画てすと あとで消します\r\n\r\n今の所、H264コーデックのみ、出力時に音声なしにしないと投稿できません\r\n動画は勝手にループします", $metadata->description); $this->assertEquals("H264動画てすと あとで消します\r\n\r\n今の所、H264コーデックのみ、出力時に音声なしにしないと投稿できません\r\n動画は勝手にループします", $metadata->description);
$this->assertRegExp('~/nijie\.info/pic/logo~', $metadata->image); $this->assertRegExp('~/nijie\.info/pic/logo~', $metadata->image);
if ($this->shouldUseMock()) {
$this->assertSame('https://nijie.info/view.php?id=256283', (string)$this->handler->getLastRequest()->getUri());
}
} }
public function testStandardPictureSp() public function testStandardPictureSp()
{ {
sleep(1); $responseText = file_get_contents(__DIR__ . '/../../fixture/Nijie/testStandardPictureResponse.html');
$resolver = new NijieResolver();
$metadata = $resolver->resolve('https://sp.nijie.info/view.php?id=66384'); $this->createResolver(NijieResolver::class, $responseText);
$metadata = $this->resolver->resolve('https://sp.nijie.info/view.php?id=66384');
$this->assertEquals('チンポップくんの日常ep.1「チンポップくんと釣り」 | ニジエ運営', $metadata->title); $this->assertEquals('チンポップくんの日常ep.1「チンポップくんと釣り」 | ニジエ運営', $metadata->title);
$this->assertEquals("メールマガジン漫画のバックナンバー第一話です!\r\n最新話はメールマガジンより配信中です。", $metadata->description); $this->assertEquals("メールマガジン漫画のバックナンバー第一話です!\r\n最新話はメールマガジンより配信中です。", $metadata->description);
$this->assertRegExp('/pic\d+\.nijie\.info/', $metadata->image); $this->assertRegExp('/pic\d+\.nijie\.info/', $metadata->image);
$this->assertNotRegExp('~/diff/main/~', $metadata->image); $this->assertNotRegExp('~/diff/main/~', $metadata->image);
if ($this->shouldUseMock()) {
$this->assertSame('https://nijie.info/view.php?id=66384', (string)$this->handler->getLastRequest()->getUri());
}
} }
public function testMultiplePictureSp() public function testMultiplePictureSp()
{ {
sleep(1); $responseText = file_get_contents(__DIR__ . '/../../fixture/Nijie/testMultiplePictureResponse.html');
$resolver = new NijieResolver();
$metadata = $resolver->resolve('https://sp.nijie.info/view.php?id=202707'); $this->createResolver(NijieResolver::class, $responseText);
$metadata = $this->resolver->resolve('https://sp.nijie.info/view.php?id=202707');
$this->assertEquals('ニジエ壁紙 | ニジエ運営', $metadata->title); $this->assertEquals('ニジエ壁紙 | ニジエ運営', $metadata->title);
$this->assertEquals("ニジエのPCとiphone用(4.7inch推奨)の壁紙です。\r\n保存してご自由にお使いくださいませ。", $metadata->description); $this->assertEquals("ニジエのPCとiphone用(4.7inch推奨)の壁紙です。\r\n保存してご自由にお使いくださいませ。", $metadata->description);
$this->assertRegExp('/pic\d+\.nijie\.info/', $metadata->image); $this->assertRegExp('/pic\d+\.nijie\.info/', $metadata->image);
$this->assertNotRegExp('~/diff/main/~', $metadata->image); $this->assertNotRegExp('~/diff/main/~', $metadata->image);
if ($this->shouldUseMock()) {
$this->assertSame('https://nijie.info/view.php?id=202707', (string)$this->handler->getLastRequest()->getUri());
}
} }
public function testAnimationGifSp() public function testAnimationGifSp()
{ {
sleep(1); $responseText = file_get_contents(__DIR__ . '/../../fixture/Nijie/testAnimationGifResponse.html');
$resolver = new NijieResolver();
$metadata = $resolver->resolve('https://nijie.info/view.php?id=9537'); $this->createResolver(NijieResolver::class, $responseText);
$metadata = $this->resolver->resolve('https://nijie.info/view.php?id=9537');
$this->assertEquals('ニジエがgifに対応したんだってね 奥さん | 黒末アプコ', $metadata->title); $this->assertEquals('ニジエがgifに対応したんだってね 奥さん | 黒末アプコ', $metadata->title);
$this->assertEquals('アニメgifとか専門外なのでよくわかりませんでした', $metadata->description); $this->assertEquals('アニメgifとか専門外なのでよくわかりませんでした', $metadata->description);
$this->assertRegExp('~/nijie\.info/pic/logo~', $metadata->image); $this->assertRegExp('~/nijie\.info/pic/logo~', $metadata->image);
if ($this->shouldUseMock()) {
$this->assertSame('https://nijie.info/view.php?id=9537', (string)$this->handler->getLastRequest()->getUri());
}
} }
public function testMp4MovieSp() public function testMp4MovieSp()
{ {
sleep(1); $responseText = file_get_contents(__DIR__ . '/../../fixture/Nijie/testMp4MovieResponse.html');
$resolver = new NijieResolver();
$metadata = $resolver->resolve('https://sp.nijie.info/view.php?id=256283'); $this->createResolver(NijieResolver::class, $responseText);
$metadata = $this->resolver->resolve('https://sp.nijie.info/view.php?id=256283');
$this->assertEquals('てすと | ニジエ運営', $metadata->title); $this->assertEquals('てすと | ニジエ運営', $metadata->title);
$this->assertEquals("H264動画てすと あとで消します\r\n\r\n今の所、H264コーデックのみ、出力時に音声なしにしないと投稿できません\r\n動画は勝手にループします", $metadata->description); $this->assertEquals("H264動画てすと あとで消します\r\n\r\n今の所、H264コーデックのみ、出力時に音声なしにしないと投稿できません\r\n動画は勝手にループします", $metadata->description);
$this->assertRegExp('~/nijie\.info/pic/logo~', $metadata->image); $this->assertRegExp('~/nijie\.info/pic/logo~', $metadata->image);
if ($this->shouldUseMock()) {
$this->assertSame('https://nijie.info/view.php?id=256283', (string)$this->handler->getLastRequest()->getUri());
}
} }
} }

View File

@ -8,18 +8,45 @@ use Tests\TestCase;
class OGPResolverTest extends TestCase class OGPResolverTest extends TestCase
{ {
use CreateMockedResolver;
public function testMissingUrl() public function testMissingUrl()
{ {
$resolver = new OGPResolver(); $this->createResolver(OGPResolver::class, '', [], 404);
$this->expectException(ClientException::class); $this->expectException(\RuntimeException::class);
$resolver->resolve('http://example.com/404'); $this->resolver->resolve('http://example.com/404');
} }
public function testResolve() public function testResolve()
{ {
$resolver = new OGPResolver(); $response = <<< 'HTML'
<!DOCTYPE html>
<html>
<head prefix="og: http://ogp.me/ns#">
<meta charset="utf-8">
<title>The Open Graph protocol</title>
<meta name="description" content="The Open Graph protocol enables any web page to become a rich object in a social graph.">
<link rel="stylesheet" href="base.css" type="text/css">
<meta property="og:title" content="Open Graph protocol">
<meta property="og:type" content="website">
<meta property="og:url" content="http://ogp.me/">
<meta property="og:image" content="http://ogp.me/logo.png">
<meta property="og:image:type" content="image/png">
<meta property="og:image:width" content="300">
<meta property="og:image:height" content="300">
<meta property="og:image:alt" content="The Open Graph logo">
<meta property="og:description" content="The Open Graph protocol enables any web page to become a rich object in a social graph.">
<meta prefix="fb: http://ogp.me/ns/fb#" property="fb:app_id" content="115190258555800">
<link rel="alternate" type="application/rdf+xml" href="http://ogp.me/ns/ogp.me.rdf">
<link rel="alternate" type="text/turtle" href="http://ogp.me/ns/ogp.me.ttl">
</head>
<body></body>
</html>
HTML;
$this->createResolver(OGPResolver::class, $response);
$resolver = $this->createResolver(OGPResolver::class, $response);
$metadata = $resolver->resolve('http://ogp.me'); $metadata = $resolver->resolve('http://ogp.me');
$this->assertEquals('Open Graph protocol', $metadata->title); $this->assertEquals('Open Graph protocol', $metadata->title);
$this->assertEquals('The Open Graph protocol enables any web page to become a rich object in a social graph.', $metadata->description); $this->assertEquals('The Open Graph protocol enables any web page to become a rich object in a social graph.', $metadata->description);
@ -28,9 +55,22 @@ class OGPResolverTest extends TestCase
public function testResolveTitleOnly() public function testResolveTitleOnly()
{ {
$resolver = new OGPResolver(); $response = <<< 'HTML'
<!doctype html>
<html>
<head>
<title>Example Domain</title>
$metadata = $resolver->resolve('http://example.com'); <meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body></body>
</html>
HTML;
$this->createResolver(OGPResolver::class, $response);
$metadata = $this->resolver->resolve('http://example.com');
$this->assertEquals('Example Domain', $metadata->title); $this->assertEquals('Example Domain', $metadata->title);
$this->assertEmpty($metadata->description); $this->assertEmpty($metadata->description);
$this->assertEmpty($metadata->image); $this->assertEmpty($metadata->image);
@ -38,7 +78,7 @@ class OGPResolverTest extends TestCase
public function testResolveTitleAndDescription() public function testResolveTitleAndDescription()
{ {
$resolver = new OGPResolver(); $resolver = $this->app->make(OGPResolver::class);
$html = <<<EOF $html = <<<EOF
<title>Welcome to my homepage</title> <title>Welcome to my homepage</title>

1
tests/fixture/.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* -text

View File

@ -0,0 +1,44 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:og="http://ogp.me/ns#" xmlns:mixi="http://mixi-platform.com/ns#" xmlns:fb="http://www.facebook.com/2008/fbml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=991">
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<meta name="google-site-verification" content="S2Jzwn_Dm4hGoyTfPnxEUSKnbHSuT73N6SZbTanWbEM" />
<link rel="apple-touch-icon" href="/images/web/common/apple_touch_icon_57x57.png">
<link rel="apple-touch-icon" sizes="72x72" href="/images/web/common/apple_touch_icon_72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/images/web/common/apple_touch_icon_76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/images/web/common/apple_touch_icon_114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/images/web/common/apple_touch_icon_120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/images/web/common/apple_touch_icon_144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/images/web/common/apple_touch_icon_152x152.png">
<meta name="msapplication-config" content="/browserconfig.xml" />
<link rel="shortcut icon" href="/images/web/common/favicon.ico">
<link rel="canonical" href="https://www.dlsite.com/maniax/work/=/product_id/RJ171695.html" />
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://www.dlsite.com/maniax-touch/work/=/product_id/RJ171695.html" class="alternate_smartphone" />
<link rel="alternate" hreflang="ja" href="https://www.dlsite.com/maniax/work/=/product_id/RJ171695.html" />
<link rel="alternate" hreflang="en" href="https://www.dlsite.com/ecchi-eng/work/=/product_id/RE171695.html" /> <meta name="description" content="少しお母さんっぽい店員さんに、歯磨きからおやすみまでお世話されます。はみがきで興奮しちゃった旦那様のも、しっかりお世話してくれます。歯磨き音は特殊なマイクを使用、骨伝導風ハイレゾバイーラル音声です。「DLsite 同人 - R18」は同人誌・同人ゲーム・同人音声のダウンロードショップ。お気に入りの作品をすぐダウンロードできてすぐ楽しめる毎日更新しているのであなたが探している作品にきっと出会えます。国内最大級の二次元総合ダウンロードショップ「DLsite」">
<title>【骨伝導風】道草屋 たびらこ-一緒にはみがき【耳かき&amp;はみがき】 [桃色CODE] | DLsite 同人 - R18</title>
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@DLsiteManiax">
<meta name="twitter:image:src" content="https://img.dlsite.jp/modpub/images2/work/doujin/RJ172000/RJ171695_img_main.jpg" />
<meta property="og:title" content="【骨伝導風】道草屋 たびらこ-一緒にはみがき【耳かき&amp;はみがき】 [桃色CODE] | DLsite" />
<meta property="og:type" content="website" />
<meta property="og:description" content="少しお母さんっぽい店員さんに、歯磨きからおやすみまでお世話されます。はみがきで興奮しちゃった旦那様のも、しっかりお世話してくれます。歯磨き音は特殊なマイクを使用、骨伝導風ハイレゾバイーラル音声です。「DLsite 同人 - R18」は同人誌・同人ゲーム・同人音声のダウンロードショップ。お気に入りの作品をすぐダウンロードできてすぐ楽しめる毎日更新しているのであなたが探している作品にきっと出会えます。国内最大級の二次元総合ダウンロードショップ「DLsite」" />
<meta property="og:url" content="https://www.dlsite.com/maniax/work/=/product_id/RJ171695.html" />
<meta property="og:image" content="https://img.dlsite.jp/modpub/images2/work/doujin/RJ172000/RJ171695_img_sam.jpg" />
<meta property="og:site_name" content="DLsite" />
<meta property="fb:app_id" content="226115600829997" />
<meta property="mixi:content-rating" content="1" />
<meta property="mixi:device-smartphone" content="https://www.dlsite.com/maniax-touch/work/=/product_id/RJ171695.html" />
</head>
<body></body>
</html>

View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="ja" xmlns="http://www.w3.org/1999/xhtml" xmlns:og="http://ogp.me/ns#" xmlns:mixi="http://mixi-platform.com/ns#" xmlns:fb="http://www.facebook.com/2008/fbml" >
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<meta name="format-detection" content="telephone=no">
<meta http-equiv="Content-Style-Type" content="text/css">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<meta name="google-site-verification" content="S2Jzwn_Dm4hGoyTfPnxEUSKnbHSuT73N6SZbTanWbEM">
<link rel="apple-touch-icon" href="/images/web/common/apple_touch_icon_57x57.png">
<link rel="apple-touch-icon" sizes="72x72" href="/images/web/common/apple_touch_icon_72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/images/web/common/apple_touch_icon_76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/images/web/common/apple_touch_icon_114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/images/web/common/apple_touch_icon_120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/images/web/common/apple_touch_icon_144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/images/web/common/apple_touch_icon_152x152.png">
<meta name="msapplication-config" content="/browserconfig.xml" />
<link rel="shortcut icon" href="/images/web/common/favicon.ico">
<link rel="canonical" href="https://www.dlsite.com/maniax/work/=/product_id/RJ234446.html" />
<link rel="alternate" hreflang="ja" href="https://www.dlsite.com/maniax/work/=/product_id/RJ234446.html" />
<link rel="alternate" hreflang="en" href="https://www.dlsite.com/ecchi-eng/work/=/product_id/RE234446.html" /> <meta name="description" content="夏の終わり、二人で遠くの花火を眺めます。耳かきの他、クラシックシェービング、氷を含んだあまがみ、冷紅茶、ジャズ、時計の修理、それから大人向けの汗の匂い。色々な事のある、二泊三日の田舎宿音声です。「DLsite 同人 - R18」は同人誌・同人ゲーム・同人音声のダウンロードショップ。お気に入りの作品をすぐダウンロードできてすぐ楽しめる毎日更新しているのであなたが探している作品にきっと出会えます。国内最大級の二次元総合ダウンロードショップ「DLsite」">
<title>【大人向け耳かき】道草屋 はこべら5 時計修理のはこべらさん。他【汗の匂い】 [桃色CODE] | DLsite 同人 - R18</title>
<meta property="og:title" content="【大人向け耳かき】道草屋 はこべら5 時計修理のはこべらさん。他【汗の匂い】 [桃色CODE] | DLsite" />
<meta property="og:type" content="website" />
<meta property="og:description" content="夏の終わり、二人で遠くの花火を眺めます。耳かきの他、クラシックシェービング、氷を含んだあまがみ、冷紅茶、ジャズ、時計の修理、それから大人向けの汗の匂い。色々な事のある、二泊三日の田舎宿音声です。「DLsite 同人 - R18」は同人誌・同人ゲーム・同人音声のダウンロードショップ。お気に入りの作品をすぐダウンロードできてすぐ楽しめる毎日更新しているのであなたが探している作品にきっと出会えます。国内最大級の二次元総合ダウンロードショップ「DLsite」" />
<meta property="og:url" content="https://www.dlsite.com/maniax-touch/work/=/product_id/RJ234446.html" />
<meta property="og:image" content="https://img.dlsite.jp/modpub/images2/work/doujin/RJ235000/RJ234446_img_sam.jpg" />
<meta property="og:site_name" content="DLsite" />
<meta property="fb:app_id" content="226115600829997" />
<meta property="mixi:content-rating" content="1" />
</head>
<body></body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja"><head><link rel="alternate" media="handheld" href="http://mb.nijie.info/view.php?id=9537" /><link rel="alternate" media="only screen and (max-width: 640px)" href="https://sp.nijie.info/view.php?id=9537" /><link rel="canonical" href="https://nijie.info/view.php?id=9537" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=970" /><meta name="format-detection" content="telephone=no" /><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><meta http-equiv="Content-Style-Type" content="text/css; charset=utf-8" /><meta http-equiv="Content-Script-Type" content="text/javascript" /><meta http-equiv="Content-Language" content="ja" /><meta name="description" content="ニジエに投稿された、黒末アプコのイラスト「ニジエがgifに対応したんだってね 奥さん」です。この画像はニジエがgifに対応したんだってね 奥さん,黒末アプコ,おっぱい,陥没乳首,眼鏡,GIFアニメ,ぶるんぶるん,アニメgif,に関連があります。「アニメgifとか専門外なのでよくわかりませんでした」" /><meta name="keywords" content="ニジエがgifに対応したんだってね 奥さん,黒末アプコ,おっぱい,陥没乳首,眼鏡,GIFアニメ,ぶるんぶるん,アニメgif," /><meta property="og:title" content="ニジエがgifに対応したんだってね 奥さん | 黒末アプコ" /><meta property="og:type" content="article" /><meta property="og:description" content="アニメgifとか専門外なのでよくわかりませんでした" /><meta property="og:url" content="https://nijie.info/view.php?id=9537" /><meta property="og:image" content="https://nijie.info/pic/logo/nijie_logo_og.png?201902161557" /><meta property="og:site_name" content="ニジエがgifに対応したんだってね 奥さん | 黒末アプコ | ニジエ" /><meta property="og:email" content="info@nijie.co.jp" /><link rel="alternate" href="https://nijie.info/view.php?id=9537" hreflang="x-default" /><link rel="shortcut icon" href="https://nijie.info/icon/favicon.ico?201902161557" /><link rel="shortcut icon" type="image/vnd.microsoft.icon" href="https://nijie.info/pic/icon/nijie.png?201902161557" /><title>ニジエがgifに対応したんだってね 奥さん | 黒末アプコ | ニジエ</title></head>
<body>
<!-- pickup some json -->
<script type="application/ld+json">{"@context": "http://schema.org","@type": "ImageObject","name": "ニジエがgifに対応したんだってね 奥さん","description": "アニメgifとか専門外なのでよくわかりませんでした","text": "アニメgifとか専門外なのでよくわかりませんでした","interactionCount": "10862 UserPlays, 6 UserComments","datePublished": "Sun Apr 8 06:59:48 2012","uploadDate": "Sun Apr 8 06:59:48 2012","dateModified": "Mon Apr 9 17:09:30 2012","copyrightYear": "2012","genre":"Image","contentLocation":"Japan","width":160,"height":90,"thumbnailUrl": "https://pic01.nijie.info/__rs_l160x160/nijie_picture/201204080659341943.gif","author": {"@type": "Person","name": "黒末アプコ","description": "判子エロ絵師とはわたしのことです","sameAs": "https://nijie.info/members.php?id=1943","image": "https://pic04.nijie.info/members_picture/thumbnail/1943_1542569693.gif"},"creator": {"@type": "Person","name": "黒末アプコ","description": "判子エロ絵師とはわたしのことです","sameAs": "https://nijie.info/members.php?id=1943","image": "https://pic04.nijie.info/members_picture/thumbnail/1943_1542569693.gif"},"editor": {"@type": "Person","name": "黒末アプコ","description": "判子エロ絵師とはわたしのことです","sameAs": "https://nijie.info/members.php?id=1943","image": "https://pic04.nijie.info/members_picture/thumbnail/1943_1542569693.gif"},"copyrightHolder": {"@type": "Person","name": "黒末アプコ","description": "判子エロ絵師とはわたしのことです","sameAs": "https://nijie.info/members.php?id=1943","image": "https://pic04.nijie.info/members_picture/thumbnail/1943_1542569693.gif"}}</script>
<script type="application/ld+json">{"@context": "http://schema.org","@type": "Review","reviewBody": "ティッシュ","author": {"@type": "Person","name": "黒末アプコ","description": "判子エロ絵師とはわたしのことです","sameAs": "https://nijie.info/members.php?id=1943","image": "http://pic04.nijie.info/members_picture/thumbnail/1943_1542569693.gif"},"datePublished": "Wed Nov 19 12:57:57 2014","contentLocation": "Japan","itemReviewed": {"@type" : "ImageObject","name" : "ニジエがgifに対応したんだってね 奥さん","sameAs": "https://nijie.info/view.php?id=9537"}}</script>
<script type="application/ld+json">{"@context": "http://schema.org","@type": "Review","reviewBody": "ひっ さくや様! ガタガタガタ  ","author": {"@type": "Person","name": "黒末アプコ","description": "判子エロ絵師とはわたしのことです","sameAs": "https://nijie.info/members.php?id=1943","image": "http://pic04.nijie.info/members_picture/thumbnail/1943_1542569693.gif"},"datePublished": "Thu Apr 19 20:48:02 2012","contentLocation": "Japan","itemReviewed": {"@type" : "ImageObject","name" : "ニジエがgifに対応したんだってね 奥さん","sameAs": "https://nijie.info/view.php?id=9537"}}</script>
<script type="application/ld+json">{"@context": "http://schema.org","@type": "Review","reviewBody": "さっ、最高です!!","author": {"@type": "Person","name": "黒末アプコ","description": "判子エロ絵師とはわたしのことです","sameAs": "https://nijie.info/members.php?id=1943","image": "http://pic04.nijie.info/members_picture/thumbnail/1943_1542569693.gif"},"datePublished": "Thu Apr 19 20:35:19 2012","contentLocation": "Japan","itemReviewed": {"@type" : "ImageObject","name" : "ニジエがgifに対応したんだってね 奥さん","sameAs": "https://nijie.info/view.php?id=9537"}}</script>
<script type="application/ld+json">{"@context": "http://schema.org","@type": "Review","reviewBody": "ぎょっ 新着コメントがtopに表示されないバグ  しこっていただけてさいわいです","author": {"@type": "Person","name": "黒末アプコ","description": "判子エロ絵師とはわたしのことです","sameAs": "https://nijie.info/members.php?id=1943","image": "http://pic04.nijie.info/members_picture/thumbnail/1943_1542569693.gif"},"datePublished": "Sun Apr 8 14:04:52 2012","contentLocation": "Japan","itemReviewed": {"@type" : "ImageObject","name" : "ニジエがgifに対応したんだってね 奥さん","sameAs": "https://nijie.info/view.php?id=9537"}}</script>
<script type="application/ld+json">{"@context": "http://schema.org","@type": "BreadcrumbList","itemListElement":[{"@type": "ListItem","position": 1,"item":{"@id": "https://nijie.info/members.php?id=1943","name": "黒末アプコ"}},{"@type": "ListItem","position": 2,"item":{"@id": "https://nijie.info/members_illust.php?id=1943","name": "黒末アプコさんのイラスト一覧"}},{"@type": "ListItem","position": 3,"item":{"@id": "https://nijie.info/view.php?id=9537","name": "ニジエがgifに対応したんだってね 奥さん"}}]}</script>
</body></html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,12 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja"><head><link rel="alternate" media="handheld" href="http://mb.nijie.info/view.php?id=202707" /><link rel="alternate" media="only screen and (max-width: 640px)" href="https://sp.nijie.info/view.php?id=202707" /><link rel="canonical" href="https://nijie.info/view.php?id=202707" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=970" /><meta name="format-detection" content="telephone=no" /><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><meta http-equiv="Content-Style-Type" content="text/css; charset=utf-8" /><meta http-equiv="Content-Script-Type" content="text/javascript" /><meta http-equiv="Content-Language" content="ja" /><meta name="description" content="ニジエに投稿された、ニジエ運営のイラスト「ニジエ壁紙」です。この画像はニジエ壁紙,ニジエ運営,ニジエたん,壁紙,に関連があります。「ニジエのPCとiphone用(4.7inch推奨)の壁紙です。
保存してご自由にお使いくださいませ。」" /><meta name="keywords" content="ニジエ壁紙,ニジエ運営,ニジエたん,壁紙," />
<meta property="og:title" content="ニジエ壁紙 | ニジエ運営" /><meta property="og:type" content="article" /><meta property="og:description" content="ニジエのPCとiphone用(4.7inch推奨)の壁紙です。
保存してご自由にお使いくださいませ。" /><meta property="og:url" content="https://nijie.info/view.php?id=202707" /><meta property="og:image" content="https://nijie.info/pic/logo/nijie_logo_og.png?201902161557" /><meta property="og:site_name" content="ニジエ壁紙 | ニジエ運営 | ニジエ" /><meta property="og:email" content="info@nijie.co.jp" /><link rel="alternate" href="https://nijie.info/view.php?id=202707" hreflang="x-default" /><link rel="shortcut icon" href="https://nijie.info/icon/favicon.ico?201902161557" /><link rel="shortcut icon" type="image/vnd.microsoft.icon" href="https://nijie.info/pic/icon/nijie.png?201902161557" /><title>ニジエ壁紙 | ニジエ運営 | ニジエ</title></head>
<body>
<!-- pickup some JSON-LD -->
<script type="application/ld+json">{"@context": "http://schema.org","@type": "ImageObject","name": "","description": "PCiphone(4.7inch)
保存してご自由にお使いくださいませ。","text": "ニジエのPCとiphone用(4.7inch推奨)の壁紙です。
保存してご自由にお使いくださいませ。","interactionCount": "2301 UserPlays, 4 UserComments","datePublished": "Thu Feb 9 18:58:03 2017","uploadDate": "Thu Feb 9 18:58:03 2017","dateModified": "Thu Feb 9 18:58:03 2017","copyrightYear": "2017","genre":"Image","contentLocation":"Japan","width":160,"height":90,"thumbnailUrl": "https://pic03.nijie.info/__rs_l160x160/nijie_picture/38_20170209185801_0.png","author": {"@type": "Person","name": "ニジエ運営","description": "ニジエンジョイ!","sameAs": "https://nijie.info/members.php?id=38","image": "https://pic04.nijie.info/members_picture/thumbnail/38_1511696698.png"},"creator": {"@type": "Person","name": "ニジエ運営","description": "ニジエンジョイ!","sameAs": "https://nijie.info/members.php?id=38","image": "https://pic04.nijie.info/members_picture/thumbnail/38_1511696698.png"},"editor": {"@type": "Person","name": "ニジエ運営","description": "ニジエンジョイ!","sameAs": "https://nijie.info/members.php?id=38","image": "https://pic04.nijie.info/members_picture/thumbnail/38_1511696698.png"},"copyrightHolder": {"@type": "Person","name": "ニジエ運営","description": "ニジエンジョイ!","sameAs": "https://nijie.info/members.php?id=38","image": "https://pic04.nijie.info/members_picture/thumbnail/38_1511696698.png"}}</script>
<script type="application/ld+json">{"@context": "http://schema.org","@type": "Review","reviewBody": "やったぜ!","author": {"@type": "Person","name": "ニジエ運営","description": "ニジエンジョイ!","sameAs": "https://nijie.info/members.php?id=38","image": "http://pic04.nijie.info/members_picture/thumbnail/38_1511696698.png"},"datePublished": "Fri Feb 17 01:31:00 2017","contentLocation": "Japan","itemReviewed": {"@type" : "ImageObject","name" : "ニジエ壁紙","sameAs": "https://nijie.info/view.php?id=202707"}}</script>
<script type="application/ld+json">{"@context": "http://schema.org","@type": "Review","reviewBody": "ぺろぺろしたいです","author": {"@type": "Person","name": "ニジエ運営","description": "ニジエンジョイ!","sameAs": "https://nijie.info/members.php?id=38","image": "http://pic04.nijie.info/members_picture/thumbnail/38_1511696698.png"},"datePublished": "Fri Feb 17 01:30:54 2017","contentLocation": "Japan","itemReviewed": {"@type" : "ImageObject","name" : "ニジエ壁紙","sameAs": "https://nijie.info/view.php?id=202707"}}</script>
</body></html>

View File

@ -0,0 +1,16 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja"><head><link rel="alternate" media="handheld" href="http://mb.nijie.info/view.php?id=66384" /><link rel="alternate" media="only screen and (max-width: 640px)" href="https://sp.nijie.info/view.php?id=66384" /><link rel="canonical" href="https://nijie.info/view.php?id=66384" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=970" /><meta name="format-detection" content="telephone=no" /><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><meta http-equiv="Content-Style-Type" content="text/css; charset=utf-8" /><meta http-equiv="Content-Script-Type" content="text/javascript" /><meta http-equiv="Content-Language" content="ja" /><meta name="description" content="ニジエに投稿された、ニジエ運営のイラスト「チンポップくんの日常ep.1「チンポップくんと釣り」」です。この画像はチンポップくんの日常ep.1「チンポップくんと釣り」,ニジエ運営,ニジエたん,釣り,チンポップ君の日常,公式漫画,に関連があります。「メールマガジン漫画のバックナンバー第一話です!
最新話はメールマガジンより配信中です。」" /><meta name="keywords" content="チンポップくんの日常ep.1「チンポップくんと釣り」,ニジエ運営,ニジエたん,釣り,チンポップ君の日常,公式漫画," /><meta property="og:title" content="チンポップくんの日常ep.1「チンポップくんと釣り」 | ニジエ運営" /><meta property="og:type" content="article" /><meta property="og:description" content="メールマガジン漫画のバックナンバー第一話です!
最新話はメールマガジンより配信中です。" /><meta property="og:url" content="https://nijie.info/view.php?id=66384" /><meta property="og:image" content="https://nijie.info/pic/logo/nijie_logo_og.png?201902161557" /><meta property="og:site_name" content="チンポップくんの日常ep.1「チンポップくんと釣り」 | ニジエ運営 | ニジエ" /><meta property="og:email" content="info@nijie.co.jp" /><link rel="alternate" href="https://nijie.info/view.php?id=66384" hreflang="x-default" /><link rel="shortcut icon" href="https://nijie.info/icon/favicon.ico?201902161557" /><link rel="shortcut icon" type="image/vnd.microsoft.icon" href="https://nijie.info/pic/icon/nijie.png?201902161557" /><title>チンポップくんの日常ep.1「チンポップくんと釣り」 | ニジエ運営 | ニジエ</title></head>
<body>
<!-- pickup only json -->
<script type="application/ld+json">{"@context": "http://schema.org","@type": "ImageObject","name": "ep.1","description": "
最新話はメールマガジンより配信中です。","text": "メールマガジン漫画のバックナンバー第一話です!
最新話はメールマガジンより配信中です。","interactionCount": "13634 UserPlays, 24 UserComments","datePublished": "Sat Nov 30 15:56:26 2013","uploadDate": "Sat Nov 30 15:56:26 2013","dateModified": "Sat Nov 30 15:56:26 2013","copyrightYear": "2013","genre":"Image","contentLocation":"Japan","width":160,"height":90,"thumbnailUrl": "https://pic04.nijie.info/__rs_l160x160/nijie_picture/38_20131130155623.png","author": {"@type": "Person","name": "ニジエ運営","description": "ニジエンジョイ!","sameAs": "https://nijie.info/members.php?id=38","image": "https://pic04.nijie.info/members_picture/thumbnail/38_1511696698.png"},"creator": {"@type": "Person","name": "ニジエ運営","description": "ニジエンジョイ!","sameAs": "https://nijie.info/members.php?id=38","image": "https://pic04.nijie.info/members_picture/thumbnail/38_1511696698.png"},"editor": {"@type": "Person","name": "ニジエ運営","description": "ニジエンジョイ!","sameAs": "https://nijie.info/members.php?id=38","image": "https://pic04.nijie.info/members_picture/thumbnail/38_1511696698.png"},"copyrightHolder": {"@type": "Person","name": "ニジエ運営","description": "ニジエンジョイ!","sameAs": "https://nijie.info/members.php?id=38","image": "https://pic04.nijie.info/members_picture/thumbnail/38_1511696698.png"}}</script>
<script type="application/ld+json">{"@context": "http://schema.org","@type": "Review","reviewBody": "ミルコ字幕","author": {"@type": "Person","name": "ニジエ運営","description": "ニジエンジョイ!","sameAs": "https://nijie.info/members.php?id=38","image": "http://pic04.nijie.info/members_picture/thumbnail/38_1511696698.png"},"datePublished": "Tue Jan 27 08:58:02 2015","contentLocation": "Japan","itemReviewed": {"@type" : "ImageObject","name" : "チンポップくんの日常ep.1「チンポップくんと釣り」","sameAs": "https://nijie.info/view.php?id=66384"}}</script>
<script type="application/ld+json">{"@context": "http://schema.org","@type": "Review","reviewBody": "ティッシュ","author": {"@type": "Person","name": "ニジエ運営","description": "ニジエンジョイ!","sameAs": "https://nijie.info/members.php?id=38","image": "http://pic04.nijie.info/members_picture/thumbnail/38_1511696698.png"},"datePublished": "Tue Aug 26 17:56:41 2014","contentLocation": "Japan","itemReviewed": {"@type" : "ImageObject","name" : "チンポップくんの日常ep.1「チンポップくんと釣り」","sameAs": "https://nijie.info/view.php?id=66384"}}</script>
<script type="application/ld+json">{"@context": "http://schema.org","@type": "Review","reviewBody": "ヨダレもの","author": {"@type": "Person","name": "ニジエ運営","description": "ニジエンジョイ!","sameAs": "https://nijie.info/members.php?id=38","image": "http://pic04.nijie.info/members_picture/thumbnail/38_1511696698.png"},"datePublished": "Mon Jun 23 10:17:29 2014","contentLocation": "Japan","itemReviewed": {"@type" : "ImageObject","name" : "チンポップくんの日常ep.1「チンポップくんと釣り」","sameAs": "https://nijie.info/view.php?id=66384"}}</script>
<script type="application/ld+json">{"@context": "http://schema.org","@type": "Review","reviewBody": "おまわりさんこっちです","author": {"@type": "Person","name": "ニジエ運営","description": "ニジエンジョイ!","sameAs": "https://nijie.info/members.php?id=38","image": "http://pic04.nijie.info/members_picture/thumbnail/38_1511696698.png"},"datePublished": "Thu Mar 27 10:49:56 2014","contentLocation": "Japan","itemReviewed": {"@type" : "ImageObject","name" : "チンポップくんの日常ep.1「チンポップくんと釣り」","sameAs": "https://nijie.info/view.php?id=66384"}}</script>
<script type="application/ld+json">{"@context": "http://schema.org","@type": "Review","reviewBody": "めちゃシコ","author": {"@type": "Person","name": "ニジエ運営","description": "ニジエンジョイ!","sameAs": "https://nijie.info/members.php?id=38","image": "http://pic04.nijie.info/members_picture/thumbnail/38_1511696698.png"},"datePublished": "Sat Feb 15 18:47:22 2014","contentLocation": "Japan","itemReviewed": {"@type" : "ImageObject","name" : "チンポップくんの日常ep.1「チンポップくんと釣り」","sameAs": "https://nijie.info/view.php?id=66384"}}</script>
</body>
</html>

9
webpack.mix.js vendored
View File

@ -12,4 +12,11 @@ let mix = require('laravel-mix');
*/ */
mix.js('resources/assets/js/app.js', 'public/js') mix.js('resources/assets/js/app.js', 'public/js')
.sass('resources/assets/sass/app.scss', 'public/css'); .js('resources/assets/js/home.js', 'public/js')
.js('resources/assets/js/checkin.js', 'public/js')
.js('resources/assets/js/user/stats.js', 'public/js/user')
.js('resources/assets/js/setting/privacy.js', 'public/js/setting')
.sass('resources/assets/sass/app.scss', 'public/css')
.autoload({
'jquery': ['$', 'jQuery', 'window.jQuery']
});

8482
yarn.lock

File diff suppressed because it is too large Load Diff