@@ -5,8 +5,8 @@ FROM php:7.3-apache
 | 
			
		||||
ENV APACHE_DOCUMENT_ROOT /var/www/html/public
 | 
			
		||||
 | 
			
		||||
RUN apt-get update \
 | 
			
		||||
    && apt-get install -y git libpq-dev unzip \
 | 
			
		||||
    && docker-php-ext-install pdo_pgsql \
 | 
			
		||||
    && apt-get install -y git libpq-dev unzip libicu-dev \
 | 
			
		||||
    && docker-php-ext-install pdo_pgsql intl \
 | 
			
		||||
    && pecl install xdebug \
 | 
			
		||||
    && curl -sS https://getcomposer.org/installer | php \
 | 
			
		||||
    && mv composer.phar /usr/local/bin/composer \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										61
									
								
								app/Console/Commands/NormalizeTags.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								app/Console/Commands/NormalizeTags.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\Console\Commands;
 | 
			
		||||
 | 
			
		||||
use App\Tag;
 | 
			
		||||
use App\Utilities\Formatter;
 | 
			
		||||
use DB;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
class NormalizeTags extends Command
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * The name and signature of the console command.
 | 
			
		||||
     *
 | 
			
		||||
     * @var string
 | 
			
		||||
     */
 | 
			
		||||
    protected $signature = 'tissue:tag:normalize';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The console command description.
 | 
			
		||||
     *
 | 
			
		||||
     * @var string
 | 
			
		||||
     */
 | 
			
		||||
    protected $description = 'Normalize tags';
 | 
			
		||||
 | 
			
		||||
    private $formatter;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a new command instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(Formatter $formatter)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct();
 | 
			
		||||
        $this->formatter = $formatter;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
     *
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    public function handle()
 | 
			
		||||
    {
 | 
			
		||||
        $start = hrtime(true);
 | 
			
		||||
 | 
			
		||||
        DB::transaction(function () {
 | 
			
		||||
            /** @var Tag $tag */
 | 
			
		||||
            foreach (Tag::query()->cursor() as $tag) {
 | 
			
		||||
                $normalizedName = $this->formatter->normalizeTagName($tag->name);
 | 
			
		||||
                $this->line("{$tag->name} : {$normalizedName}");
 | 
			
		||||
                $tag->normalized_name = $normalizedName;
 | 
			
		||||
                $tag->save();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $elapsed = (hrtime(true) - $start) / 1e+9;
 | 
			
		||||
        $this->info("Done! ({$elapsed} sec)");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
 | 
			
		||||
namespace App\Http\Controllers\Api;
 | 
			
		||||
 | 
			
		||||
use App\MetadataResolver\DeniedHostException;
 | 
			
		||||
use App\Services\MetadataResolveService;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
 | 
			
		||||
@@ -13,7 +14,11 @@ class CardController
 | 
			
		||||
            'url:required|url'
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        $metadata = $service->execute($request->input('url'));
 | 
			
		||||
        try {
 | 
			
		||||
            $metadata = $service->execute($request->input('url'));
 | 
			
		||||
        } catch (DeniedHostException $e) {
 | 
			
		||||
            abort(403, $e->getMessage());
 | 
			
		||||
        }
 | 
			
		||||
        $metadata->load('tags');
 | 
			
		||||
 | 
			
		||||
        $response = response($metadata);
 | 
			
		||||
 
 | 
			
		||||
@@ -4,20 +4,30 @@ namespace App\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use App\Ejaculation;
 | 
			
		||||
use App\Tag;
 | 
			
		||||
use App\Utilities\Formatter;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Support\Facades\Auth;
 | 
			
		||||
 | 
			
		||||
class SearchController extends Controller
 | 
			
		||||
{
 | 
			
		||||
    /** @var Formatter */
 | 
			
		||||
    private $formatter;
 | 
			
		||||
 | 
			
		||||
    public function __construct(Formatter $formatter)
 | 
			
		||||
    {
 | 
			
		||||
        $this->formatter = $formatter;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function index(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $inputs = $request->validate([
 | 
			
		||||
            'q' => 'required'
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        $q = $this->normalizeQuery($inputs['q']);
 | 
			
		||||
        $results = Ejaculation::query()
 | 
			
		||||
            ->whereHas('tags', function ($query) use ($inputs) {
 | 
			
		||||
                $query->where('name', 'like', "%{$inputs['q']}%");
 | 
			
		||||
            ->whereHas('tags', function ($query) use ($q) {
 | 
			
		||||
                $query->where('normalized_name', 'like', "%{$q}%");
 | 
			
		||||
            })
 | 
			
		||||
            ->whereHas('user', function ($query) {
 | 
			
		||||
                $query->where('is_protected', false);
 | 
			
		||||
@@ -41,11 +51,17 @@ class SearchController extends Controller
 | 
			
		||||
            'q' => 'required'
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        $q = $this->normalizeQuery($inputs['q']);
 | 
			
		||||
        $results = Tag::query()
 | 
			
		||||
            ->where('name', 'like', "%{$inputs['q']}%")
 | 
			
		||||
            ->where('normalized_name', 'like', "%{$q}%")
 | 
			
		||||
            ->paginate(50)
 | 
			
		||||
            ->appends($inputs);
 | 
			
		||||
 | 
			
		||||
        return view('search.relatedTag')->with(compact('inputs', 'results'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function normalizeQuery(string $query): string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->formatter->normalizeTagName($query);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
namespace App\Listeners;
 | 
			
		||||
 | 
			
		||||
use App\Events\LinkDiscovered;
 | 
			
		||||
use App\MetadataResolver\DeniedHostException;
 | 
			
		||||
use App\Services\MetadataResolveService;
 | 
			
		||||
use Illuminate\Contracts\Queue\ShouldQueue;
 | 
			
		||||
use Illuminate\Queue\InteractsWithQueue;
 | 
			
		||||
@@ -32,6 +33,8 @@ class LinkCollector
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            $this->metadataResolveService->execute($event->url);
 | 
			
		||||
        } catch (DeniedHostException $e) {
 | 
			
		||||
            // ignored
 | 
			
		||||
        } catch (\Exception $e) {
 | 
			
		||||
            // 今のところこのイベントは同期実行されるので、上流をクラッシュさせないために雑catchする
 | 
			
		||||
            report($e);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								app/MetadataResolver/DeniedHostException.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								app/MetadataResolver/DeniedHostException.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\MetadataResolver;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use Throwable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * メタデータの解決を禁止しているホストに対して取得を試み、ブロックされたことを表します。
 | 
			
		||||
 */
 | 
			
		||||
class DeniedHostException extends Exception
 | 
			
		||||
{
 | 
			
		||||
    private $url;
 | 
			
		||||
 | 
			
		||||
    public function __construct(string $url, Throwable $previous = null)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct("Access denied by system policy: $url", 0, $previous);
 | 
			
		||||
        $this->url = $url;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getUrl(): string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->url;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getHost(): string
 | 
			
		||||
    {
 | 
			
		||||
        return parse_url($this->url, PHP_URL_HOST);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -3,10 +3,12 @@
 | 
			
		||||
namespace App\Services;
 | 
			
		||||
 | 
			
		||||
use App\Metadata;
 | 
			
		||||
use App\MetadataResolver\DeniedHostException;
 | 
			
		||||
use App\MetadataResolver\MetadataResolver;
 | 
			
		||||
use App\Tag;
 | 
			
		||||
use App\Utilities\Formatter;
 | 
			
		||||
use GuzzleHttp\Exception\TransferException;
 | 
			
		||||
use Illuminate\Support\Facades\DB;
 | 
			
		||||
use Illuminate\Support\Facades\Log;
 | 
			
		||||
 | 
			
		||||
class MetadataResolveService
 | 
			
		||||
@@ -27,32 +29,39 @@ class MetadataResolveService
 | 
			
		||||
        // URLの正規化
 | 
			
		||||
        $url = $this->formatter->normalizeUrl($url);
 | 
			
		||||
 | 
			
		||||
        // 無かったら取得
 | 
			
		||||
        // TODO: ある程度古かったら再取得とかありだと思う
 | 
			
		||||
        $metadata = Metadata::find($url);
 | 
			
		||||
        if ($metadata == null || ($metadata->expires_at !== null && $metadata->expires_at < now())) {
 | 
			
		||||
            try {
 | 
			
		||||
                $resolved = $this->resolver->resolve($url);
 | 
			
		||||
                $metadata = Metadata::updateOrCreate(['url' => $url], [
 | 
			
		||||
                    'title' => $resolved->title,
 | 
			
		||||
                    'description' => $resolved->description,
 | 
			
		||||
                    'image' => $resolved->image,
 | 
			
		||||
                    'expires_at' => $resolved->expires_at
 | 
			
		||||
                ]);
 | 
			
		||||
 | 
			
		||||
                $tagIds = [];
 | 
			
		||||
                foreach ($resolved->normalizedTags() as $tagName) {
 | 
			
		||||
                    $tag = Tag::firstOrCreate(['name' => $tagName]);
 | 
			
		||||
                    $tagIds[] = $tag->id;
 | 
			
		||||
                }
 | 
			
		||||
                $metadata->tags()->sync($tagIds);
 | 
			
		||||
            } catch (TransferException $e) {
 | 
			
		||||
                // 何らかの通信エラーによってメタデータの取得に失敗した時、とりあえずエラーログにURLを残す
 | 
			
		||||
                Log::error(self::class . ': メタデータの取得に失敗 URL=' . $url);
 | 
			
		||||
                throw $e;
 | 
			
		||||
            }
 | 
			
		||||
        // 自分自身は解決しない
 | 
			
		||||
        if (parse_url($url, PHP_URL_HOST) === parse_url(config('app.url'), PHP_URL_HOST)) {
 | 
			
		||||
            throw new DeniedHostException($url);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $metadata;
 | 
			
		||||
        return DB::transaction(function () use ($url) {
 | 
			
		||||
            // 無かったら取得
 | 
			
		||||
            // TODO: ある程度古かったら再取得とかありだと思う
 | 
			
		||||
            $metadata = Metadata::find($url);
 | 
			
		||||
            if ($metadata == null || ($metadata->expires_at !== null && $metadata->expires_at < now())) {
 | 
			
		||||
                try {
 | 
			
		||||
                    $resolved = $this->resolver->resolve($url);
 | 
			
		||||
                    $metadata = Metadata::updateOrCreate(['url' => $url], [
 | 
			
		||||
                        'title' => $resolved->title,
 | 
			
		||||
                        'description' => $resolved->description,
 | 
			
		||||
                        'image' => $resolved->image,
 | 
			
		||||
                        'expires_at' => $resolved->expires_at
 | 
			
		||||
                    ]);
 | 
			
		||||
 | 
			
		||||
                    $tagIds = [];
 | 
			
		||||
                    foreach ($resolved->normalizedTags() as $tagName) {
 | 
			
		||||
                        $tag = Tag::firstOrCreate(['name' => $tagName]);
 | 
			
		||||
                        $tagIds[] = $tag->id;
 | 
			
		||||
                    }
 | 
			
		||||
                    $metadata->tags()->sync($tagIds);
 | 
			
		||||
                } catch (TransferException $e) {
 | 
			
		||||
                    // 何らかの通信エラーによってメタデータの取得に失敗した時、とりあえずエラーログにURLを残す
 | 
			
		||||
                    Log::error(self::class . ': メタデータの取得に失敗 URL=' . $url);
 | 
			
		||||
                    throw $e;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return $metadata;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								app/Tag.php
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								app/Tag.php
									
									
									
									
									
								
							@@ -2,6 +2,7 @@
 | 
			
		||||
 | 
			
		||||
namespace App;
 | 
			
		||||
 | 
			
		||||
use App\Utilities\Formatter;
 | 
			
		||||
use Illuminate\Database\Eloquent\Model;
 | 
			
		||||
 | 
			
		||||
class Tag extends Model
 | 
			
		||||
@@ -15,6 +16,15 @@ class Tag extends Model
 | 
			
		||||
        'name'
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    protected static function boot()
 | 
			
		||||
    {
 | 
			
		||||
        parent::boot();
 | 
			
		||||
 | 
			
		||||
        self::creating(function (Tag $tag) {
 | 
			
		||||
            $tag->normalized_name = app(Formatter::class)->normalizeTagName($tag->name);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function ejaculations()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->belongsToMany('App\Ejaculation')->withTimestamps();
 | 
			
		||||
 
 | 
			
		||||
@@ -132,4 +132,12 @@ class Formatter
 | 
			
		||||
 | 
			
		||||
        return $bytes . 'B';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function normalizeTagName(string $name)
 | 
			
		||||
    {
 | 
			
		||||
        $name = \Normalizer::normalize($name, \Normalizer::FORM_KC);
 | 
			
		||||
        $name = mb_strtolower($name);
 | 
			
		||||
 | 
			
		||||
        return $name;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,12 @@
 | 
			
		||||
    ],
 | 
			
		||||
    "require": {
 | 
			
		||||
        "php": "^7.2",
 | 
			
		||||
        "ext-dom": "*",
 | 
			
		||||
        "ext-intl": "*",
 | 
			
		||||
        "ext-json": "*",
 | 
			
		||||
        "ext-libxml": "*",
 | 
			
		||||
        "ext-mbstring": "*",
 | 
			
		||||
        "ext-pdo": "*",
 | 
			
		||||
        "anhskohbo/no-captcha": "^3.0",
 | 
			
		||||
        "doctrine/dbal": "^2.9",
 | 
			
		||||
        "erusev/parsedown": "^1.7",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										432
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										432
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							@@ -4,7 +4,7 @@
 | 
			
		||||
        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
 | 
			
		||||
        "This file is @generated automatically"
 | 
			
		||||
    ],
 | 
			
		||||
    "content-hash": "2c0bd951a595d4856079c5a13a72e651",
 | 
			
		||||
    "content-hash": "1bba68b609be6a0dcdaf05d72e8eb759",
 | 
			
		||||
    "packages": [
 | 
			
		||||
        {
 | 
			
		||||
            "name": "anhskohbo/no-captcha",
 | 
			
		||||
@@ -547,6 +547,20 @@
 | 
			
		||||
                "uppercase",
 | 
			
		||||
                "words"
 | 
			
		||||
            ],
 | 
			
		||||
            "funding": [
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://www.doctrine-project.org/sponsorship.html",
 | 
			
		||||
                    "type": "custom"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://www.patreon.com/phpdoctrine",
 | 
			
		||||
                    "type": "patreon"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector",
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-05-29T15:13:26+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
@@ -609,6 +623,20 @@
 | 
			
		||||
                "parser",
 | 
			
		||||
                "php"
 | 
			
		||||
            ],
 | 
			
		||||
            "funding": [
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://www.doctrine-project.org/sponsorship.html",
 | 
			
		||||
                    "type": "custom"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://www.patreon.com/phpdoctrine",
 | 
			
		||||
                    "type": "patreon"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer",
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-05-25T17:44:05+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
@@ -1148,16 +1176,16 @@
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "laravel/framework",
 | 
			
		||||
            "version": "v6.18.25",
 | 
			
		||||
            "version": "v6.18.26",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/laravel/framework.git",
 | 
			
		||||
                "reference": "fd4c42cb49b8777473d1161ef15d1104b2a33d6c"
 | 
			
		||||
                "reference": "d11b6168c65251ffa81ae0dfaf017ad2f30013da"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/laravel/framework/zipball/fd4c42cb49b8777473d1161ef15d1104b2a33d6c",
 | 
			
		||||
                "reference": "fd4c42cb49b8777473d1161ef15d1104b2a33d6c",
 | 
			
		||||
                "url": "https://api.github.com/repos/laravel/framework/zipball/d11b6168c65251ffa81ae0dfaf017ad2f30013da",
 | 
			
		||||
                "reference": "d11b6168c65251ffa81ae0dfaf017ad2f30013da",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
@@ -1292,7 +1320,7 @@
 | 
			
		||||
                "framework",
 | 
			
		||||
                "laravel"
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-07-10T16:41:03+00:00"
 | 
			
		||||
            "time": "2020-07-21T14:25:39+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "laravel/helpers",
 | 
			
		||||
@@ -1413,16 +1441,16 @@
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "league/commonmark",
 | 
			
		||||
            "version": "1.5.1",
 | 
			
		||||
            "version": "1.5.3",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/thephpleague/commonmark.git",
 | 
			
		||||
                "reference": "6d74caf6abeed5fd85d6ec20da23d7269cd0b46f"
 | 
			
		||||
                "reference": "2574454b97e4103dc4e36917bd783b25624aefcd"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/6d74caf6abeed5fd85d6ec20da23d7269cd0b46f",
 | 
			
		||||
                "reference": "6d74caf6abeed5fd85d6ec20da23d7269cd0b46f",
 | 
			
		||||
                "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/2574454b97e4103dc4e36917bd783b25624aefcd",
 | 
			
		||||
                "reference": "2574454b97e4103dc4e36917bd783b25624aefcd",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
@@ -1441,7 +1469,7 @@
 | 
			
		||||
                "michelf/php-markdown": "~1.4",
 | 
			
		||||
                "mikehaertl/php-shellcommand": "^1.4",
 | 
			
		||||
                "phpstan/phpstan": "^0.12",
 | 
			
		||||
                "phpunit/phpunit": "^7.5",
 | 
			
		||||
                "phpunit/phpunit": "^7.5 || ^8.5 || ^9.2",
 | 
			
		||||
                "scrutinizer/ocular": "^1.5",
 | 
			
		||||
                "symfony/finder": "^4.2"
 | 
			
		||||
            },
 | 
			
		||||
@@ -1504,7 +1532,7 @@
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-06-27T12:50:08+00:00"
 | 
			
		||||
            "time": "2020-07-19T22:47:30+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "league/csv",
 | 
			
		||||
@@ -2509,24 +2537,24 @@
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "phpoption/phpoption",
 | 
			
		||||
            "version": "1.7.4",
 | 
			
		||||
            "version": "1.7.5",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/schmittjoh/php-option.git",
 | 
			
		||||
                "reference": "b2ada2ad5d8a32b89088b8adc31ecd2e3a13baf3"
 | 
			
		||||
                "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/b2ada2ad5d8a32b89088b8adc31ecd2e3a13baf3",
 | 
			
		||||
                "reference": "b2ada2ad5d8a32b89088b8adc31ecd2e3a13baf3",
 | 
			
		||||
                "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/994ecccd8f3283ecf5ac33254543eb0ac946d525",
 | 
			
		||||
                "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "php": "^5.5.9 || ^7.0 || ^8.0"
 | 
			
		||||
            },
 | 
			
		||||
            "require-dev": {
 | 
			
		||||
                "bamarni/composer-bin-plugin": "^1.3",
 | 
			
		||||
                "phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0 || ^7.0"
 | 
			
		||||
                "bamarni/composer-bin-plugin": "^1.4.1",
 | 
			
		||||
                "phpunit/phpunit": "^4.8.35 || ^5.7.27 || ^6.5.6 || ^7.0 || ^8.0 || ^9.0"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
@@ -2570,7 +2598,7 @@
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-06-07T10:40:07+00:00"
 | 
			
		||||
            "time": "2020-07-20T17:29:33+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "psr/container",
 | 
			
		||||
@@ -4359,16 +4387,16 @@
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/polyfill-ctype",
 | 
			
		||||
            "version": "v1.17.1",
 | 
			
		||||
            "version": "v1.18.0",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/polyfill-ctype.git",
 | 
			
		||||
                "reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d"
 | 
			
		||||
                "reference": "1c302646f6efc070cd46856e600e5e0684d6b454"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d",
 | 
			
		||||
                "reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454",
 | 
			
		||||
                "reference": "1c302646f6efc070cd46856e600e5e0684d6b454",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
@@ -4380,7 +4408,7 @@
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "1.17-dev"
 | 
			
		||||
                    "dev-master": "1.18-dev"
 | 
			
		||||
                },
 | 
			
		||||
                "thanks": {
 | 
			
		||||
                    "name": "symfony/polyfill",
 | 
			
		||||
@@ -4431,20 +4459,20 @@
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-06-06T08:46:27+00:00"
 | 
			
		||||
            "time": "2020-07-14T12:35:20+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/polyfill-iconv",
 | 
			
		||||
            "version": "v1.17.1",
 | 
			
		||||
            "version": "v1.18.0",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/polyfill-iconv.git",
 | 
			
		||||
                "reference": "ba6c9c18db36235b859cc29b8372d1c01298c035"
 | 
			
		||||
                "reference": "6c2f78eb8f5ab8eaea98f6d414a5915f2e0fce36"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/ba6c9c18db36235b859cc29b8372d1c01298c035",
 | 
			
		||||
                "reference": "ba6c9c18db36235b859cc29b8372d1c01298c035",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/6c2f78eb8f5ab8eaea98f6d414a5915f2e0fce36",
 | 
			
		||||
                "reference": "6c2f78eb8f5ab8eaea98f6d414a5915f2e0fce36",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
@@ -4456,7 +4484,7 @@
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "1.17-dev"
 | 
			
		||||
                    "dev-master": "1.18-dev"
 | 
			
		||||
                },
 | 
			
		||||
                "thanks": {
 | 
			
		||||
                    "name": "symfony/polyfill",
 | 
			
		||||
@@ -4508,25 +4536,26 @@
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-06-06T08:46:27+00:00"
 | 
			
		||||
            "time": "2020-07-14T12:35:20+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/polyfill-intl-idn",
 | 
			
		||||
            "version": "v1.17.1",
 | 
			
		||||
            "version": "v1.18.0",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/polyfill-intl-idn.git",
 | 
			
		||||
                "reference": "a57f8161502549a742a63c09f0a604997bf47027"
 | 
			
		||||
                "reference": "bc6549d068d0160e0f10f7a5a23c7d1406b95ebe"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a57f8161502549a742a63c09f0a604997bf47027",
 | 
			
		||||
                "reference": "a57f8161502549a742a63c09f0a604997bf47027",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/bc6549d068d0160e0f10f7a5a23c7d1406b95ebe",
 | 
			
		||||
                "reference": "bc6549d068d0160e0f10f7a5a23c7d1406b95ebe",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "php": ">=5.3.3",
 | 
			
		||||
                "symfony/polyfill-mbstring": "^1.3",
 | 
			
		||||
                "symfony/polyfill-intl-normalizer": "^1.10",
 | 
			
		||||
                "symfony/polyfill-php70": "^1.10",
 | 
			
		||||
                "symfony/polyfill-php72": "^1.10"
 | 
			
		||||
            },
 | 
			
		||||
            "suggest": {
 | 
			
		||||
@@ -4535,7 +4564,7 @@
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "1.17-dev"
 | 
			
		||||
                    "dev-master": "1.18-dev"
 | 
			
		||||
                },
 | 
			
		||||
                "thanks": {
 | 
			
		||||
                    "name": "symfony/polyfill",
 | 
			
		||||
@@ -4559,6 +4588,10 @@
 | 
			
		||||
                    "name": "Laurent Bassin",
 | 
			
		||||
                    "email": "laurent@bassin.info"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Trevor Rowbotham",
 | 
			
		||||
                    "email": "trevor.rowbotham@pm.me"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Symfony Community",
 | 
			
		||||
                    "homepage": "https://symfony.com/contributors"
 | 
			
		||||
@@ -4588,20 +4621,101 @@
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-06-06T08:46:27+00:00"
 | 
			
		||||
            "time": "2020-07-14T12:35:20+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/polyfill-mbstring",
 | 
			
		||||
            "version": "v1.17.1",
 | 
			
		||||
            "name": "symfony/polyfill-intl-normalizer",
 | 
			
		||||
            "version": "v1.18.0",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/polyfill-mbstring.git",
 | 
			
		||||
                "reference": "7110338d81ce1cbc3e273136e4574663627037a7"
 | 
			
		||||
                "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
 | 
			
		||||
                "reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7110338d81ce1cbc3e273136e4574663627037a7",
 | 
			
		||||
                "reference": "7110338d81ce1cbc3e273136e4574663627037a7",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e",
 | 
			
		||||
                "reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "php": ">=5.3.3"
 | 
			
		||||
            },
 | 
			
		||||
            "suggest": {
 | 
			
		||||
                "ext-intl": "For best performance"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "1.18-dev"
 | 
			
		||||
                },
 | 
			
		||||
                "thanks": {
 | 
			
		||||
                    "name": "symfony/polyfill",
 | 
			
		||||
                    "url": "https://github.com/symfony/polyfill"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "psr-4": {
 | 
			
		||||
                    "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
 | 
			
		||||
                },
 | 
			
		||||
                "files": [
 | 
			
		||||
                    "bootstrap.php"
 | 
			
		||||
                ],
 | 
			
		||||
                "classmap": [
 | 
			
		||||
                    "Resources/stubs"
 | 
			
		||||
                ]
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "MIT"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Nicolas Grekas",
 | 
			
		||||
                    "email": "p@tchwork.com"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Symfony Community",
 | 
			
		||||
                    "homepage": "https://symfony.com/contributors"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "Symfony polyfill for intl's Normalizer class and related functions",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "keywords": [
 | 
			
		||||
                "compatibility",
 | 
			
		||||
                "intl",
 | 
			
		||||
                "normalizer",
 | 
			
		||||
                "polyfill",
 | 
			
		||||
                "portable",
 | 
			
		||||
                "shim"
 | 
			
		||||
            ],
 | 
			
		||||
            "funding": [
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://symfony.com/sponsor",
 | 
			
		||||
                    "type": "custom"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://github.com/fabpot",
 | 
			
		||||
                    "type": "github"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-07-14T12:35:20+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/polyfill-mbstring",
 | 
			
		||||
            "version": "v1.18.0",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/polyfill-mbstring.git",
 | 
			
		||||
                "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/a6977d63bf9a0ad4c65cd352709e230876f9904a",
 | 
			
		||||
                "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
@@ -4613,7 +4727,7 @@
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "1.17-dev"
 | 
			
		||||
                    "dev-master": "1.18-dev"
 | 
			
		||||
                },
 | 
			
		||||
                "thanks": {
 | 
			
		||||
                    "name": "symfony/polyfill",
 | 
			
		||||
@@ -4665,20 +4779,97 @@
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-07-14T12:35:20+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/polyfill-php70",
 | 
			
		||||
            "version": "v1.17.1",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/polyfill-php70.git",
 | 
			
		||||
                "reference": "471b096aede7025bace8eb356b9ac801aaba7e2d"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/471b096aede7025bace8eb356b9ac801aaba7e2d",
 | 
			
		||||
                "reference": "471b096aede7025bace8eb356b9ac801aaba7e2d",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "paragonie/random_compat": "~1.0|~2.0|~9.99",
 | 
			
		||||
                "php": ">=5.3.3"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "1.17-dev"
 | 
			
		||||
                },
 | 
			
		||||
                "thanks": {
 | 
			
		||||
                    "name": "symfony/polyfill",
 | 
			
		||||
                    "url": "https://github.com/symfony/polyfill"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "psr-4": {
 | 
			
		||||
                    "Symfony\\Polyfill\\Php70\\": ""
 | 
			
		||||
                },
 | 
			
		||||
                "files": [
 | 
			
		||||
                    "bootstrap.php"
 | 
			
		||||
                ],
 | 
			
		||||
                "classmap": [
 | 
			
		||||
                    "Resources/stubs"
 | 
			
		||||
                ]
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "MIT"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Nicolas Grekas",
 | 
			
		||||
                    "email": "p@tchwork.com"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Symfony Community",
 | 
			
		||||
                    "homepage": "https://symfony.com/contributors"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "keywords": [
 | 
			
		||||
                "compatibility",
 | 
			
		||||
                "polyfill",
 | 
			
		||||
                "portable",
 | 
			
		||||
                "shim"
 | 
			
		||||
            ],
 | 
			
		||||
            "funding": [
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://symfony.com/sponsor",
 | 
			
		||||
                    "type": "custom"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://github.com/fabpot",
 | 
			
		||||
                    "type": "github"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-06-06T08:46:27+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/polyfill-php72",
 | 
			
		||||
            "version": "v1.17.0",
 | 
			
		||||
            "version": "v1.18.0",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/polyfill-php72.git",
 | 
			
		||||
                "reference": "f048e612a3905f34931127360bdd2def19a5e582"
 | 
			
		||||
                "reference": "639447d008615574653fb3bc60d1986d7172eaae"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/f048e612a3905f34931127360bdd2def19a5e582",
 | 
			
		||||
                "reference": "f048e612a3905f34931127360bdd2def19a5e582",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/639447d008615574653fb3bc60d1986d7172eaae",
 | 
			
		||||
                "reference": "639447d008615574653fb3bc60d1986d7172eaae",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
@@ -4687,7 +4878,11 @@
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "1.17-dev"
 | 
			
		||||
                    "dev-master": "1.18-dev"
 | 
			
		||||
                },
 | 
			
		||||
                "thanks": {
 | 
			
		||||
                    "name": "symfony/polyfill",
 | 
			
		||||
                    "url": "https://github.com/symfony/polyfill"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "autoload": {
 | 
			
		||||
@@ -4720,20 +4915,34 @@
 | 
			
		||||
                "portable",
 | 
			
		||||
                "shim"
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-05-12T16:47:27+00:00"
 | 
			
		||||
            "funding": [
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://symfony.com/sponsor",
 | 
			
		||||
                    "type": "custom"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://github.com/fabpot",
 | 
			
		||||
                    "type": "github"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-07-14T12:35:20+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/polyfill-php73",
 | 
			
		||||
            "version": "v1.17.1",
 | 
			
		||||
            "version": "v1.18.0",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/polyfill-php73.git",
 | 
			
		||||
                "reference": "fa0837fe02d617d31fbb25f990655861bb27bd1a"
 | 
			
		||||
                "reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fa0837fe02d617d31fbb25f990655861bb27bd1a",
 | 
			
		||||
                "reference": "fa0837fe02d617d31fbb25f990655861bb27bd1a",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fffa1a52a023e782cdcc221d781fe1ec8f87fcca",
 | 
			
		||||
                "reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
@@ -4742,7 +4951,7 @@
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "1.17-dev"
 | 
			
		||||
                    "dev-master": "1.18-dev"
 | 
			
		||||
                },
 | 
			
		||||
                "thanks": {
 | 
			
		||||
                    "name": "symfony/polyfill",
 | 
			
		||||
@@ -4796,20 +5005,20 @@
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-06-06T08:46:27+00:00"
 | 
			
		||||
            "time": "2020-07-14T12:35:20+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/polyfill-php80",
 | 
			
		||||
            "version": "v1.17.1",
 | 
			
		||||
            "version": "v1.18.0",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/polyfill-php80.git",
 | 
			
		||||
                "reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2"
 | 
			
		||||
                "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4a5b6bba3259902e386eb80dd1956181ee90b5b2",
 | 
			
		||||
                "reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/d87d5766cbf48d72388a9f6b85f280c8ad51f981",
 | 
			
		||||
                "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
@@ -4818,7 +5027,7 @@
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "1.17-dev"
 | 
			
		||||
                    "dev-master": "1.18-dev"
 | 
			
		||||
                },
 | 
			
		||||
                "thanks": {
 | 
			
		||||
                    "name": "symfony/polyfill",
 | 
			
		||||
@@ -4876,7 +5085,7 @@
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-06-06T08:46:27+00:00"
 | 
			
		||||
            "time": "2020-07-14T12:35:20+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/polyfill-uuid",
 | 
			
		||||
@@ -5491,22 +5700,22 @@
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "vlucas/phpdotenv",
 | 
			
		||||
            "version": "v3.6.6",
 | 
			
		||||
            "version": "v3.6.7",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/vlucas/phpdotenv.git",
 | 
			
		||||
                "reference": "4669484ccbc38fe7c4e0c50456778f2010566aad"
 | 
			
		||||
                "reference": "2065beda6cbe75e2603686907b2e45f6f3a5ad82"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/4669484ccbc38fe7c4e0c50456778f2010566aad",
 | 
			
		||||
                "reference": "4669484ccbc38fe7c4e0c50456778f2010566aad",
 | 
			
		||||
                "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2065beda6cbe75e2603686907b2e45f6f3a5ad82",
 | 
			
		||||
                "reference": "2065beda6cbe75e2603686907b2e45f6f3a5ad82",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "php": "^5.4 || ^7.0 || ^8.0",
 | 
			
		||||
                "phpoption/phpoption": "^1.5.2",
 | 
			
		||||
                "symfony/polyfill-ctype": "^1.16"
 | 
			
		||||
                "symfony/polyfill-ctype": "^1.17"
 | 
			
		||||
            },
 | 
			
		||||
            "require-dev": {
 | 
			
		||||
                "ext-filter": "*",
 | 
			
		||||
@@ -5560,7 +5769,7 @@
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-06-02T14:08:54+00:00"
 | 
			
		||||
            "time": "2020-07-14T19:04:52+00:00"
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "packages-dev": [
 | 
			
		||||
@@ -8579,83 +8788,6 @@
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-05-30T20:35:19+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/polyfill-php70",
 | 
			
		||||
            "version": "v1.17.1",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/polyfill-php70.git",
 | 
			
		||||
                "reference": "471b096aede7025bace8eb356b9ac801aaba7e2d"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/471b096aede7025bace8eb356b9ac801aaba7e2d",
 | 
			
		||||
                "reference": "471b096aede7025bace8eb356b9ac801aaba7e2d",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "paragonie/random_compat": "~1.0|~2.0|~9.99",
 | 
			
		||||
                "php": ">=5.3.3"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "1.17-dev"
 | 
			
		||||
                },
 | 
			
		||||
                "thanks": {
 | 
			
		||||
                    "name": "symfony/polyfill",
 | 
			
		||||
                    "url": "https://github.com/symfony/polyfill"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "psr-4": {
 | 
			
		||||
                    "Symfony\\Polyfill\\Php70\\": ""
 | 
			
		||||
                },
 | 
			
		||||
                "files": [
 | 
			
		||||
                    "bootstrap.php"
 | 
			
		||||
                ],
 | 
			
		||||
                "classmap": [
 | 
			
		||||
                    "Resources/stubs"
 | 
			
		||||
                ]
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "MIT"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Nicolas Grekas",
 | 
			
		||||
                    "email": "p@tchwork.com"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Symfony Community",
 | 
			
		||||
                    "homepage": "https://symfony.com/contributors"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "keywords": [
 | 
			
		||||
                "compatibility",
 | 
			
		||||
                "polyfill",
 | 
			
		||||
                "portable",
 | 
			
		||||
                "shim"
 | 
			
		||||
            ],
 | 
			
		||||
            "funding": [
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://symfony.com/sponsor",
 | 
			
		||||
                    "type": "custom"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://github.com/fabpot",
 | 
			
		||||
                    "type": "github"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2020-06-06T08:46:27+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/stopwatch",
 | 
			
		||||
            "version": "v5.1.2",
 | 
			
		||||
@@ -8875,7 +9007,13 @@
 | 
			
		||||
    "prefer-stable": true,
 | 
			
		||||
    "prefer-lowest": false,
 | 
			
		||||
    "platform": {
 | 
			
		||||
        "php": "^7.2"
 | 
			
		||||
        "php": "^7.2",
 | 
			
		||||
        "ext-dom": "*",
 | 
			
		||||
        "ext-intl": "*",
 | 
			
		||||
        "ext-json": "*",
 | 
			
		||||
        "ext-libxml": "*",
 | 
			
		||||
        "ext-mbstring": "*",
 | 
			
		||||
        "ext-pdo": "*"
 | 
			
		||||
    },
 | 
			
		||||
    "platform-dev": [],
 | 
			
		||||
    "plugin-api-version": "1.1.0"
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
use Illuminate\Database\Migrations\Migration;
 | 
			
		||||
use Illuminate\Database\Schema\Blueprint;
 | 
			
		||||
use Illuminate\Support\Facades\Schema;
 | 
			
		||||
 | 
			
		||||
class AddNormalizedNameToTags extends Migration
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Run the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function up()
 | 
			
		||||
    {
 | 
			
		||||
        Schema::table('tags', function (Blueprint $table) {
 | 
			
		||||
            $table->string('normalized_name')->nullable();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reverse the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function down()
 | 
			
		||||
    {
 | 
			
		||||
        Schema::table('tags', function (Blueprint $table) {
 | 
			
		||||
            $table->dropColumn('normalized_name');
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,2 +1,2 @@
 | 
			
		||||
User-agent: *
 | 
			
		||||
Disallow:
 | 
			
		||||
Disallow: /search/
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ export default class TagInput extends Vue {
 | 
			
		||||
                case 'Enter':
 | 
			
		||||
                case ' ':
 | 
			
		||||
                    if ((event as any).isComposing !== true) {
 | 
			
		||||
                        this.tags.push(this.buffer.trim());
 | 
			
		||||
                        this.tags.push(this.buffer.trim().replace(/\s+/g, '_'));
 | 
			
		||||
                        this.buffer = '';
 | 
			
		||||
                    }
 | 
			
		||||
                    event.preventDefault();
 | 
			
		||||
@@ -49,7 +49,7 @@ export default class TagInput extends Vue {
 | 
			
		||||
                case 'Unidentified':
 | 
			
		||||
                    // 実際にテキストボックスに入力されている文字を見に行く (フォールバック処理)
 | 
			
		||||
                    if (event.srcElement && (event.srcElement as HTMLInputElement).value.slice(-1) == ' ') {
 | 
			
		||||
                        this.tags.push(this.buffer.trim());
 | 
			
		||||
                        this.tags.push(this.buffer.trim().replace(/\s+/g, '_'));
 | 
			
		||||
                        this.buffer = '';
 | 
			
		||||
                        event.preventDefault();
 | 
			
		||||
                    }
 | 
			
		||||
 
 | 
			
		||||
@@ -70,4 +70,30 @@ class FormatterTest extends TestCase
 | 
			
		||||
            $formatter->profileImageSrcSet($profileImageProvider, 128, 2)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dataProvider provideNormalizeTagName
 | 
			
		||||
     */
 | 
			
		||||
    public function testNormalizeTagName($input, $expected)
 | 
			
		||||
    {
 | 
			
		||||
        $formatter = new Formatter();
 | 
			
		||||
 | 
			
		||||
        $normalized = $formatter->normalizeTagName($input);
 | 
			
		||||
        $this->assertSame($expected, $normalized);
 | 
			
		||||
        $this->assertSame($expected, $formatter->normalizeTagName($normalized));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function provideNormalizeTagName()
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            'LowerCase' => ['example', 'example'],
 | 
			
		||||
            'UpperCase' => ['EXAMPLE', 'example'],
 | 
			
		||||
            'HalfWidthKana' => ['ティッシュ', 'ティッシュ'],
 | 
			
		||||
            'FullWidthAlphabet' => ['Tissue', 'tissue'],
 | 
			
		||||
            '組み文字1' => ['13㎝', '13cm'],
 | 
			
		||||
            '組み文字2' => ['13㌢㍍', '13センチメートル'],
 | 
			
		||||
            'Script' => ['ℬ𝒶𝒷𝓊𝓂𝒾', 'babumi'],
 | 
			
		||||
            'NFD' => ['オカズ', 'オカズ'],
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								yarn.lock
									
									
									
									
									
								
							@@ -1496,9 +1496,9 @@ bluebird@^3.1.1, bluebird@^3.5.5:
 | 
			
		||||
  integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
 | 
			
		||||
 | 
			
		||||
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
 | 
			
		||||
  version "4.11.8"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
 | 
			
		||||
  integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==
 | 
			
		||||
  version "4.11.9"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828"
 | 
			
		||||
  integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==
 | 
			
		||||
 | 
			
		||||
body-parser@1.19.0:
 | 
			
		||||
  version "1.19.0"
 | 
			
		||||
@@ -2865,9 +2865,9 @@ elegant-spinner@^1.0.1:
 | 
			
		||||
  integrity sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=
 | 
			
		||||
 | 
			
		||||
elliptic@^6.0.0:
 | 
			
		||||
  version "6.5.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762"
 | 
			
		||||
  integrity sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==
 | 
			
		||||
  version "6.5.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6"
 | 
			
		||||
  integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    bn.js "^4.4.0"
 | 
			
		||||
    brorand "^1.0.1"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user