From 0895b412d2a4ebca1676fb1837558364424a563e Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sat, 8 Feb 2020 15:14:46 +0100 Subject: [PATCH 01/77] #38 - Display only unique destinations --- resources/components/picker/stop.html | 4 ++-- resources/ts/components/picker.ts | 8 ++++++-- resources/ts/utils.ts | 20 ++++++++++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/resources/components/picker/stop.html b/resources/components/picker/stop.html index 49eea23..f40e869 100644 --- a/resources/components/picker/stop.html +++ b/resources/components/picker/stop.html @@ -3,10 +3,10 @@ <slot name="primary-action" /> <div class="overflow-hidden align-self-center"> <stop :stop="stop" class="my-1"/> - <div class="stop__destinations" v-if="stop.destinations && stop.destinations.length > 0"> + <div class="stop__destinations" v-if="destinations && destinations.length > 0"> <fa :icon="['far', 'chevron-right']" /> <ul class="ml-1"> - <li class="stop__destination" v-for="destination in stop.destinations" :key="destination.id">{{ destination.name }}</li> + <li class="stop__destination" v-for="destination in destinations" :key="destination.id">{{ destination.name }}</li> </ul> </div> </div> diff --git a/resources/ts/components/picker.ts b/resources/ts/components/picker.ts index 6ca0faa..f74e41a 100644 --- a/resources/ts/components/picker.ts +++ b/resources/ts/components/picker.ts @@ -2,7 +2,7 @@ import Component from "vue-class-component"; import Vue from "vue"; import { Stop, StopGroup, StopGroups } from "../model"; import { Prop, Watch } from "vue-property-decorator"; -import { ensureArray, FetchingState, filter, map, time } from "../utils"; +import { FetchingState, filter, map, unique } from "../utils"; import { debounce } from "../decorators"; import urls from '../urls'; @@ -18,6 +18,10 @@ export class PickerStopComponent extends Vue { get showMap() { return this.inMap || this.map; } + + get destinations() { + return unique(this.stop.destinations, stop => stop.name); + } } @Component({ @@ -38,7 +42,7 @@ export class FinderComponent extends Vue { get filtered(): StopGroups { const groups = map( this.found, - (group: StopGroup, name: string) => + (group: StopGroup) => group.filter(stop => !this.blacklist.some(blacklisted => blacklisted.id === stop.id)) ) as StopGroups; diff --git a/resources/ts/utils.ts b/resources/ts/utils.ts index 2601a47..ecb4a18 100644 --- a/resources/ts/utils.ts +++ b/resources/ts/utils.ts @@ -75,3 +75,23 @@ export function time<T>(action: () => T, name?: string) { return result; } + +export const identity = a => a; + +export function unique<T, U>(array: T[], criterion: (item: T) => U = identity) { + const result: T[] = []; + const known = new Set<U>(); + + const entries = array.map(item => [ criterion(item), item ]) as [ U, T ][]; + + for (const [ key, item ] of entries) { + if (known.has(key)) { + continue; + } + + known.add(key); + result.push(item); + } + + return result; +} -- 2.45.2 From f2f7b19380e56f7d68c4b0d250a12d1bf9ec6ce0 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sat, 8 Feb 2020 18:16:04 +0100 Subject: [PATCH 02/77] #38 - Add lines to destinations This is useful when we have few different stops, with same destinations and different lines. --- resources/components/line.html | 22 ++++---- resources/components/picker/stop.html | 12 +++-- resources/styles/_stop.scss | 10 ++++ resources/styles/main.scss | 7 +++ resources/ts/components/line.ts | 5 +- resources/ts/components/picker.ts | 28 ++++++++-- resources/ts/components/utils.ts | 7 ++- resources/ts/model/stop.ts | 9 +++- resources/ts/utils.ts | 19 +++++++ src/Controller/Api/v1/TripController.php | 2 +- src/Model/Destination.php | 52 +++++++++++++++++++ src/Model/Stop.php | 4 +- .../Database/GenericStopRepository.php | 22 ++++++-- 13 files changed, 173 insertions(+), 26 deletions(-) create mode 100644 src/Model/Destination.php diff --git a/resources/components/line.html b/resources/components/line.html index e8565f2..91f1ef2 100644 --- a/resources/components/line.html +++ b/resources/components/line.html @@ -1,12 +1,16 @@ <span class="line__symbol flex" :class="{ [`line--${line.type}`]: true, 'line--night': line.night, 'line--fast': line.fast }"> <span class="flex align-items-stretch"> - <span class="icon"> - <fa :icon="['fac', line.type]" fixed-width/> - </span> - <span class="badge badge-dark flex"> - <fa :icon="['fas', 'walking']" fixed-width v-if="line.fast"/> - <fa :icon="['fal', 'moon']" fixed-width v-if="line.night"/> - {{ line.symbol }} - </span> + <slot name="icon" v-if="!simple"> + <span class="icon"> + <fa :icon="['fac', line.type]" fixed-width/> + </span> + </slot> + <slot name="badge"> + <span class="badge badge-dark flex"> + <fa :icon="['fal', 'moon']" fixed-width v-if="line.night && !simple"/> + {{ line.symbol }} + <fa :icon="['fas', 'walking']" v-if="line.fast"/> + </span> + </slot> </span> -</span> \ No newline at end of file +</span> diff --git a/resources/components/picker/stop.html b/resources/components/picker/stop.html index f40e869..1fa2830 100644 --- a/resources/components/picker/stop.html +++ b/resources/components/picker/stop.html @@ -2,11 +2,17 @@ <div class="d-flex"> <slot name="primary-action" /> <div class="overflow-hidden align-self-center"> - <stop :stop="stop" class="my-1"/> + <stop :stop="stop" /> <div class="stop__destinations" v-if="destinations && destinations.length > 0"> - <fa :icon="['far', 'chevron-right']" /> <ul class="ml-1"> - <li class="stop__destination" v-for="destination in destinations" :key="destination.id">{{ destination.name }}</li> + <li class="stop__destination destination" v-for="destination in destinations" :key="destination.stop.id"> + <ul class="destination__lines"> + <li v-for="line in destination.lines"> + <line-symbol :line="line" :key="line.symbol" simple/> + </li> + </ul> + <span class="destination__name ml-1">{{ destination.stop.name }}</span> + </li> </ul> </div> </div> diff --git a/resources/styles/_stop.scss b/resources/styles/_stop.scss index 3ac0d0c..e72315f 100644 --- a/resources/styles/_stop.scss +++ b/resources/styles/_stop.scss @@ -53,6 +53,16 @@ .stop__destination { @extend .favourite__stop; + align-items: center; +} + +.destination__line { + @extend .line__symbol; +} + +.destination__lines li { + display: inline-block; + @include spacing; } .finder__stop { diff --git a/resources/styles/main.scss b/resources/styles/main.scss index 9038407..73afad3 100644 --- a/resources/styles/main.scss +++ b/resources/styles/main.scss @@ -43,6 +43,13 @@ $grid-gutter-width: $spacer * 2; } } +@mixin spacing($spacing: .25em) { + margin-left: $spacing; + &:first-child { + margin-left: 0; + } +} + @mixin no-scrollbars { scrollbar-width: none; /* Firefox */ -ms-overflow-style: none; /* Internet Explorer 10+ */ diff --git a/resources/ts/components/line.ts b/resources/ts/components/line.ts index bce6353..86ca509 100644 --- a/resources/ts/components/line.ts +++ b/resources/ts/components/line.ts @@ -6,6 +6,9 @@ import { Line } from "../model"; export class LineComponent extends Vue { @Prop(Object) public line: Line; + + @Prop(Boolean) + public simple: boolean; } -Vue.component('LineSymbol', LineComponent); \ No newline at end of file +Vue.component('LineSymbol', LineComponent); diff --git a/resources/ts/components/picker.ts b/resources/ts/components/picker.ts index f74e41a..f8a8f61 100644 --- a/resources/ts/components/picker.ts +++ b/resources/ts/components/picker.ts @@ -1,8 +1,8 @@ import Component from "vue-class-component"; import Vue from "vue"; -import { Stop, StopGroup, StopGroups } from "../model"; +import { Destination, Line, Stop, StopGroup, StopGroups } from "../model"; import { Prop, Watch } from "vue-property-decorator"; -import { FetchingState, filter, map, unique } from "../utils"; +import { FetchingState, filter, map, match, unique } from "../utils"; import { debounce } from "../decorators"; import urls from '../urls'; @@ -20,7 +20,29 @@ export class PickerStopComponent extends Vue { } get destinations() { - return unique(this.stop.destinations, stop => stop.name); + const compactLines = destination => ({ + ...destination, + lines: Object.entries(groupLinesByType(destination.lines || [])).map(([type, lines]) => ({ + type: type, + symbol: joinedSymbol(lines), + night: lines.every(line => line.night), + fast: lines.every(line => line.fast), + })), + all: destination.lines + }); + + const groupLinesByType = (lines: Line[]) => lines.reduce<{ [kind: string]: Line[]}>((groups, line) => ({ + ...groups, + [line.type]: [ ...(groups[line.type] || []), line ] + }), {}); + + const joinedSymbol = match<string, [Line[]]>( + [lines => lines.length === 1, lines => lines[0].symbol], + [lines => lines.length === 2, ([first, second]) => `${first.symbol}, ${second.symbol}`], + [lines => lines.length > 2, ([first]) => `${first.symbol}…`], + ); + + return unique(this.stop.destinations || [], destination => destination.stop.name).map(compactLines); } } diff --git a/resources/ts/components/utils.ts b/resources/ts/components/utils.ts index 200e083..9dc6837 100644 --- a/resources/ts/components/utils.ts +++ b/resources/ts/components/utils.ts @@ -1,7 +1,6 @@ import Vue from 'vue'; import { Component, Prop, Watch } from "vue-property-decorator"; import Popper, { Placement } from "popper.js"; -import { Portal } from "portal-vue"; import vueRemovedHookMixin from "vue-removed-hook-mixin"; @Component({ @@ -155,3 +154,9 @@ export class LazyComponent extends Vue { Vue.component('Popper', PopperComponent); Vue.component('Fold', FoldComponent); Vue.component('Lazy', LazyComponent); + +// https://github.com/vuejs/vue/issues/7829 +Vue.component('Empty', { + functional: true, + render: (h, { data }) => h('template', data, '') +}); diff --git a/resources/ts/model/stop.ts b/resources/ts/model/stop.ts index fa6bc33..40e0e6b 100644 --- a/resources/ts/model/stop.ts +++ b/resources/ts/model/stop.ts @@ -1,3 +1,5 @@ +import { Line } from "./line"; + export interface Stop { id: any; name: string; @@ -8,7 +10,12 @@ export interface Stop { }; onDemand?: boolean; variant?: string; - destinations?: Stop[]; + destinations?: Destination[]; +} + +export type Destination = { + stop: Stop; + lines: Line[] } export type StopGroup = Stop[]; diff --git a/resources/ts/utils.ts b/resources/ts/utils.ts index ecb4a18..d7d6a22 100644 --- a/resources/ts/utils.ts +++ b/resources/ts/utils.ts @@ -95,3 +95,22 @@ export function unique<T, U>(array: T[], criterion: (item: T) => U = identity) { return result; } + +type Pattern<TResult, TArgs extends any[]> = [ + (...args: TArgs) => boolean, + ((...args: TArgs) => TResult) | TResult, +] + +export function match<TResult, TArgs extends any[]>(...patterns: Pattern<TResult, TArgs>[]): (...args: TArgs) => TResult { + return (...args: TArgs) => { + for (let [pattern, action] of patterns) { + if (pattern(...args)) { + return typeof action === "function" ? (action as (...args: TArgs) => TResult)(...args) : action; + } + } + + throw new Error(`No pattern matches args: ${JSON.stringify(args)}`); + } +} + +match.default = (...args: any[]) => true; diff --git a/src/Controller/Api/v1/TripController.php b/src/Controller/Api/v1/TripController.php index 9f1583e..87b87cd 100644 --- a/src/Controller/Api/v1/TripController.php +++ b/src/Controller/Api/v1/TripController.php @@ -14,7 +14,7 @@ use Symfony\Component\Routing\Annotation\Route; class TripController extends Controller { /** - * @Route("/{id}") + * @Route("/{id}", methods={"GET"}) */ public function one($id, TripRepository $repository) { diff --git a/src/Model/Destination.php b/src/Model/Destination.php new file mode 100644 index 0000000..45d22c1 --- /dev/null +++ b/src/Model/Destination.php @@ -0,0 +1,52 @@ +<?php + +namespace App\Model; + +use JMS\Serializer\Annotation as Serializer; +use Nelmio\ApiDocBundle\Annotation\Model; +use Swagger\Annotations as SWG; +use Tightenco\Collect\Support\Collection; + +class Destination implements Fillable +{ + use FillTrait; + + /** + * Stop associated with destination. + * @Serializer\Type(Stop::class) + * @var Stop + */ + private $stop; + + /** + * @Serializer\Type("Collection") + * @SWG\Property(type="array", @SWG\Items(ref=@Model(type=Line::class, groups={"Default"}))) + * @var Line[]|Collection<Line> + */ + private $lines; + + public function __construct() + { + $this->lines = collect(); + } + + public function getStop(): Stop + { + return $this->stop; + } + + public function setStop(Stop $stop): void + { + $this->stop = $stop; + } + + public function getLines(): Collection + { + return $this->lines; + } + + public function setLines(iterable $lines): void + { + $this->lines = collect($lines); + } +} diff --git a/src/Model/Stop.php b/src/Model/Stop.php index a37764a..0d294db 100644 --- a/src/Model/Stop.php +++ b/src/Model/Stop.php @@ -73,9 +73,9 @@ class Stop implements Referable, Fillable * * @Serializer\Groups({"WithDestinations"}) * @Serializer\Type("Collection") - * @SWG\Property(type="array", @SWG\Items(ref=@Model(type=Stop::class, groups={"Default"}))) + * @SWG\Property(type="array", @SWG\Items(ref=@Model(type=Destination::class, groups={"Default"}))) * - * @var Collection<Stop> + * @var Collection<Destination> */ private $destinations; diff --git a/src/Provider/Database/GenericStopRepository.php b/src/Provider/Database/GenericStopRepository.php index 737b11f..8dc1972 100644 --- a/src/Provider/Database/GenericStopRepository.php +++ b/src/Provider/Database/GenericStopRepository.php @@ -4,11 +4,12 @@ namespace App\Provider\Database; use App\Entity\StopEntity; use App\Entity\TrackEntity; +use App\Model\Destination; use App\Model\Stop; use App\Provider\StopRepository; -use Tightenco\Collect\Support\Collection; use Kadet\Functional as f; use Kadet\Functional\Transforms as t; +use Tightenco\Collect\Support\Collection; class GenericStopRepository extends DatabaseRepository implements StopRepository { @@ -46,9 +47,10 @@ class GenericStopRepository extends DatabaseRepository implements StopRepository $stops = collect($query->execute([':name' => "%$name%"])); $destinations = collect($this->em->createQueryBuilder() - ->select('t', 'f', 'fs', 'ts') + ->select('t', 'tl', 'f', 'fs', 'ts') ->from(TrackEntity::class, 't') ->join('t.stopsInTrack', 'ts') + ->join('t.line', 'tl') ->where('ts.stop IN (:stops)') ->join('t.final', 'f') ->join('f.stop', 'fs') @@ -62,9 +64,19 @@ class GenericStopRepository extends DatabaseRepository implements StopRepository return $grouped; }, collect()) ->map(function (Collection $tracks) { - return $tracks->map(function (TrackEntity $track) { - return $this->convert($track->getFinal()->getStop()); - })->unique()->values(); + return $tracks + ->groupBy(function (TrackEntity $track) { + return $track->getFinal()->getStop()->getId(); + })->map(function (Collection $tracks, $id) { + return Destination::createFromArray([ + 'stop' => $this->convert($tracks->first()->getFinal()->getStop()), + 'lines' => $tracks + ->map(t\property('line')) + ->unique(t\property('id')) + ->map(f\ref([$this, 'convert'])) + ->values(), + ]); + })->values(); }); return collect($stops)->map(f\ref([$this, 'convert']))->each(function (Stop $stop) use ($destinations) { -- 2.45.2 From 449efd7536f4d2365cf61e5e9dfdccbfc372a30a Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sat, 8 Feb 2020 21:50:20 +0100 Subject: [PATCH 03/77] Fixed build errors --- resources/ts/components/picker.ts | 2 +- resources/ts/model/stop.ts | 3 +++ tsconfig.json | 5 +++-- webpack.config.js | 1 - 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/resources/ts/components/picker.ts b/resources/ts/components/picker.ts index f8a8f61..476d07a 100644 --- a/resources/ts/components/picker.ts +++ b/resources/ts/components/picker.ts @@ -1,6 +1,6 @@ import Component from "vue-class-component"; import Vue from "vue"; -import { Destination, Line, Stop, StopGroup, StopGroups } from "../model"; +import { Destination, Line, StopWithDestinations as Stop, StopGroup, StopGroups } from "../model"; import { Prop, Watch } from "vue-property-decorator"; import { FetchingState, filter, map, match, unique } from "../utils"; import { debounce } from "../decorators"; diff --git a/resources/ts/model/stop.ts b/resources/ts/model/stop.ts index 40e0e6b..d7bbd13 100644 --- a/resources/ts/model/stop.ts +++ b/resources/ts/model/stop.ts @@ -10,6 +10,9 @@ export interface Stop { }; onDemand?: boolean; variant?: string; +} + +export interface StopWithDestinations extends Stop{ destinations?: Destination[]; } diff --git a/tsconfig.json b/tsconfig.json index 9f6d92c..3d3c4a9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,5 +9,6 @@ "moduleResolution": "node", "downlevelIteration": true }, - "files": ["resources/ts/app.ts"] -} \ No newline at end of file + "files": ["resources/ts/app.ts"], + "include": ["resources/ts/**/*.ts"] +} diff --git a/webpack.config.js b/webpack.config.js index 439c13d..367d75b 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,6 +1,5 @@ const path = require('path'); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const BabelMinifyPlugin = require('babel-minify-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const ImageminPlugin = require('imagemin-webpack-plugin').default; -- 2.45.2 From 493c3852d819c1d33fedc90d3f36fa2b9eef8d1d Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 9 Feb 2020 13:56:22 +0100 Subject: [PATCH 04/77] #32 - Switch instead of checkbox --- resources/components/ui/switch.html | 4 + resources/styles/ui/_switch.scss | 48 ++ resources/ts/components/index.ts | 1 + resources/ts/components/ui/index.ts | 1 + resources/ts/components/ui/switch.ts | 24 + webpack.config.js | 3 +- yarn.lock | 905 ++++++++------------------- 7 files changed, 338 insertions(+), 648 deletions(-) create mode 100644 resources/components/ui/switch.html create mode 100644 resources/styles/ui/_switch.scss create mode 100644 resources/ts/components/ui/index.ts create mode 100644 resources/ts/components/ui/switch.ts diff --git a/resources/components/ui/switch.html b/resources/components/ui/switch.html new file mode 100644 index 0000000..6111e23 --- /dev/null +++ b/resources/components/ui/switch.html @@ -0,0 +1,4 @@ +<div class="ui-switch" :class="[ value && 'ui-switch--checked' ]" v-bind="$attrs" @click="update"> + <div class="ui-switch__track"><div class="ui-switch__thumb"></div></div> + <input type="checkbox" class="ui-switch__checkbox" :id="id" :checked="value" @input="update"/> +</div> diff --git a/resources/styles/ui/_switch.scss b/resources/styles/ui/_switch.scss new file mode 100644 index 0000000..7392263 --- /dev/null +++ b/resources/styles/ui/_switch.scss @@ -0,0 +1,48 @@ +$ui-switch-marker-size: .7rem; +$ui-switch-spacing: 1px; +$ui-switch-duration: 150ms; +$ui-switch-width-factor: 2.25; + +.ui-switch { + padding: 3px; +} + +.ui-switch__checkbox { + display: none; +} + +.ui-switch__track { + border: 1px solid $dark; + border-radius: $ui-switch-marker-size; + padding: $ui-switch-spacing; + width: $ui-switch-width-factor * $ui-switch-marker-size; + height: $ui-switch-marker-size; + position: relative; + box-sizing: content-box; + background: white; + transition: background-color $ui-switch-duration ease-in-out; + cursor: pointer; +} + +.ui-switch__thumb { + border-radius: 100%; + width: $ui-switch-marker-size; + height: $ui-switch-marker-size; + background: $dark; + position: absolute; + transition: all $ui-switch-duration ease-in-out; + transition-property: background-color, left; + margin-left: $ui-switch-spacing; + left: 0; +} + +.ui-switch--checked { + .ui-switch__thumb { + background: white; + left: ($ui-switch-width-factor - 1) * $ui-switch-marker-size; + } + + .ui-switch__track { + background: $dark; + } +} diff --git a/resources/ts/components/index.ts b/resources/ts/components/index.ts index 78d820a..cda0742 100644 --- a/resources/ts/components/index.ts +++ b/resources/ts/components/index.ts @@ -9,3 +9,4 @@ export * from './map' export * from './app' export * from './favourites' export * from './trip' +export * from './ui' diff --git a/resources/ts/components/ui/index.ts b/resources/ts/components/ui/index.ts new file mode 100644 index 0000000..4dd2256 --- /dev/null +++ b/resources/ts/components/ui/index.ts @@ -0,0 +1 @@ +export * from './switch'; diff --git a/resources/ts/components/ui/switch.ts b/resources/ts/components/ui/switch.ts new file mode 100644 index 0000000..46756a3 --- /dev/null +++ b/resources/ts/components/ui/switch.ts @@ -0,0 +1,24 @@ +import Vue from 'vue' +import { Component, Prop } from 'vue-property-decorator' +import * as uuid from "uuid"; + +@Component({ + template: require('@templates/ui/switch.html'), + inheritAttrs: false +}) +export class UiSwitch extends Vue { + @Prop({ + type: String, + default: () => `uuid-${uuid.v4()}` + }) + id: string; + + @Prop(Boolean) + value: boolean; + + update(ev) { + this.$emit('input', !this.value); + } +} + +Vue.component('UiSwitch', UiSwitch); diff --git a/webpack.config.js b/webpack.config.js index 367d75b..2b357ce 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -20,7 +20,8 @@ const config = { extensions: ['.tsx', '.ts', '.js'], alias: { 'vue$': 'vue/dist/vue.esm.js', - 'mapbox-gl$': 'mapbox-gl/dist/mapbox-gl-unminified' + 'mapbox-gl$': 'mapbox-gl/dist/mapbox-gl-unminified', + '@templates': path.resolve(__dirname, './resources/components/'), } }, module: { diff --git a/yarn.lock b/yarn.lock index 016780d..cc66e4d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,49 +3,49 @@ "@babel/runtime@^7.0.0", "@babel/runtime@^7.3.4": - version "7.7.6" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.6.tgz#d18c511121aff1b4f2cd1d452f1bac9601dd830f" - integrity sha512-BWAJxpNVa0QlE5gZdWjSxXtemZyZ9RmrmVozxt3NUXeZhVIJ5ANyqmMc0JDrivBZyxUuQvFxlvH4OWWOogGfUw== + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.4.tgz#d79f5a2040f7caa24d53e563aad49cbc05581308" + integrity sha512-neAp3zt80trRVBI1x0azq6c57aNBqYZH8KhMm3TaB7wEI5Q4A2SHfBHE8w9gOhI/lrqxtEbXZgQIrHP+wvSGwQ== dependencies: regenerator-runtime "^0.13.2" -"@fortawesome/fontawesome-common-types@^0.2.25": - version "0.2.25" - resolved "https://npm.fontawesome.com/@fortawesome/fontawesome-common-types/-/0.2.25/fontawesome-common-types-0.2.25.tgz#6df015905081f2762e5cfddeb7a20d2e9b16c786" - integrity sha512-3RuZPDuuPELd7RXtUqTCfed14fcny9UiPOkdr2i+cYxBoTOfQgxcDoq77fHiiHcgWuo1LoBUpvGxFF1H/y7s3Q== +"@fortawesome/fontawesome-common-types@^0.2.27": + version "0.2.27" + resolved "https://npm.fontawesome.com/@fortawesome/fontawesome-common-types/-/0.2.27/fontawesome-common-types-0.2.27.tgz#19706345859fc46adf3684ed01d11b40903b87e9" + integrity sha512-97GaByGaXDGMkzcJX7VmR/jRJd8h1mfhtA7RsxDBN61GnWE/PPCZhOdwG/8OZYktiRUF0CvFOr+VgRkJrt6TWg== "@fortawesome/fontawesome-svg-core@^1.2.4": - version "1.2.25" - resolved "https://npm.fontawesome.com/@fortawesome/fontawesome-svg-core/-/1.2.25/fontawesome-svg-core-1.2.25.tgz#24b03391d14f0c6171e8cad7057c687b74049790" - integrity sha512-MotKnn53JKqbkLQiwcZSBJVYtTgIKFbh7B8+kd05TSnfKYPFmjKKI59o2fpz5t0Hzl35vVGU6+N4twoOpZUrqA== + version "1.2.27" + resolved "https://npm.fontawesome.com/@fortawesome/fontawesome-svg-core/-/1.2.27/fontawesome-svg-core-1.2.27.tgz#e4db8e3be81a40988213507c3e3d0c158a6641a3" + integrity sha512-sOD3DKynocnHYpuw2sLPnTunDj7rLk91LYhi2axUYwuGe9cPCw7Bsu9EWtVdNJP+IYgTCZIbyARKXuy5K/nv+Q== dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.25" + "@fortawesome/fontawesome-common-types" "^0.2.27" "@fortawesome/pro-light-svg-icons@^5.3.1": - version "5.11.2" - resolved "https://npm.fontawesome.com/@fortawesome/pro-light-svg-icons/-/5.11.2/pro-light-svg-icons-5.11.2.tgz#61543170feb34e04f4d4bd1843b08bbde6682833" - integrity sha512-NzN0K+hnKQ8fw4PLsr7WjLgtlnH1QjD4/N26YVUEMzLZiTgYBiqE7NDlRL6q/xJ9ittCj6PDPNY/IQ0T8XPLiA== + version "5.12.1" + resolved "https://npm.fontawesome.com/@fortawesome/pro-light-svg-icons/-/5.12.1/pro-light-svg-icons-5.12.1.tgz#802f8aac0204c41c7a138c5c9547d3cadbeec39a" + integrity sha512-vCT7qkoJINQuNEW7N+i1ioZQ7FHp5UiRPAHxuRS5qFPOXlVxtK8+Yf8DZ+KOpPQiwXoDX0tKFuS6Jc1HOB1qIg== dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.25" + "@fortawesome/fontawesome-common-types" "^0.2.27" "@fortawesome/pro-regular-svg-icons@^5.3.1": - version "5.11.2" - resolved "https://npm.fontawesome.com/@fortawesome/pro-regular-svg-icons/-/5.11.2/pro-regular-svg-icons-5.11.2.tgz#e9185f15555a16748612044211444463c005d97f" - integrity sha512-y1WLNjf/AMN+Mh+CojlOoKfk9miKPDB3P3r7cj3WP7yjxmDX09YyYHkxSWP2HOK9xJulmVN36CbNcMVS8Mrqpg== + version "5.12.1" + resolved "https://npm.fontawesome.com/@fortawesome/pro-regular-svg-icons/-/5.12.1/pro-regular-svg-icons-5.12.1.tgz#852f782eb2f50ee56784f6bb05d62d249b1c0794" + integrity sha512-IHwJ1Jj8zfNwC3Bj2m+YD21L1et9Ocxu6RCSLVqpTYgz2BT7CwUzHy83hUL+4JDEuA41sYyZjdsAXDgg5+DKZg== dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.25" + "@fortawesome/fontawesome-common-types" "^0.2.27" "@fortawesome/pro-solid-svg-icons@^5.3.1": - version "5.11.2" - resolved "https://npm.fontawesome.com/@fortawesome/pro-solid-svg-icons/-/5.11.2/pro-solid-svg-icons-5.11.2.tgz#5d72c801b3413191a81841c606d8cc7926014b76" - integrity sha512-YYrEFhda4KIUweXed1s+RQko53O7rXGK1jEbdlGXZlHnNTX7OyrkvJDQYqhQ7H+H62HV0BxF/xtDXvSJRlyO1Q== + version "5.12.1" + resolved "https://npm.fontawesome.com/@fortawesome/pro-solid-svg-icons/-/5.12.1/pro-solid-svg-icons-5.12.1.tgz#1de223a184a81f40c1ab575880168c82c7afc773" + integrity sha512-7xhIu8QuBBK9/grUVx28rs9MNJaMQppt/rrhY2LMiYuETVKrYzHuTDvjS+UXaKsgHN31JTM/vVMVro/daTB/uw== dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.25" + "@fortawesome/fontawesome-common-types" "^0.2.27" "@fortawesome/vue-fontawesome@^0.1.1": - version "0.1.8" - resolved "https://npm.fontawesome.com/@fortawesome/vue-fontawesome/-/0.1.8/vue-fontawesome-0.1.8.tgz#615347c56d285eb634315f59fe4f4156e4eee8b4" - integrity sha512-SdFiUD+vFDA/xKuEbnQTVrK8FDxoV0eyQaiHxmCcjAc0+vQe0Kf6oGm28opNPIt8MTgKWR3+Yg3xXP455Ae4tQ== + version "0.1.9" + resolved "https://npm.fontawesome.com/@fortawesome/vue-fontawesome/-/0.1.9/vue-fontawesome-0.1.9.tgz#d3af6d4e50f337327de90447fe35fa1e117a2fbe" + integrity sha512-h/emhmZz+DfB2zOGLWawNwXq82UYhn9waTfUjLLmeaIqtnIyNt6kYlpQT/vzJjLZRDRvY2IEJAh1di5qKpKVpA== "@hapi/address@2.x.x": version "2.1.4" @@ -58,9 +58,9 @@ integrity sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA== "@hapi/hoek@8.x.x", "@hapi/hoek@^8.3.0": - version "8.5.0" - resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.5.0.tgz#2f9ce301c8898e1c3248b0a8564696b24d1a9a5a" - integrity sha512-7XYT10CZfPsH7j9F1Jmg1+d0ezOux2oM2GfArAzLwWe4mE2Dr3hVjsAL6+TFY49RRJlCdJDMw3nJsLFroTc8Kw== + version "8.5.1" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.5.1.tgz#fde96064ca446dec8c55a8c2f130957b070c6e06" + integrity sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow== "@hapi/joi@^15.0.0": version "15.1.1" @@ -161,7 +161,7 @@ resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== -"@types/bootstrap@^4.1.2": +"@types/bootstrap@^4.3.1": version "4.3.1" resolved "https://registry.yarnpkg.com/@types/bootstrap/-/bootstrap-4.3.1.tgz#15fa89a4d275b114a4eceb90909d4eb8b90d43f5" integrity sha512-n7Zv7Y+C98Yv4oqbyqGn3alCvNRCya2xMYzOdVEnmnFlu04MXQk1ntVrBhXzDkiwhZZYNkNfBZn2yhTnEh/mHQ== @@ -225,26 +225,19 @@ "@types/node" "*" "@types/jquery@*", "@types/jquery@^3.3.6": - version "3.3.31" - resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.31.tgz#27c706e4bf488474e1cb54a71d8303f37c93451b" - integrity sha512-Lz4BAJihoFw5nRzKvg4nawXPzutkv7wmfQ5121avptaSIXlDNJCUuxZxX/G+9EVidZGuO0UBlk+YjKbwRKJigg== + version "3.3.32" + resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.32.tgz#93e27fdc45dd38ee07f2f0acf34b59c1ccee036f" + integrity sha512-UKoof2mnV/X1/Ix2g+V2Ny5sgHjV8nK/UJbiYxuo4zPwzGyFlZ/mp4KaePb2VqQrqJctmcDQNA57buU84/2uIw== dependencies: "@types/sizzle" "*" -"@types/leaflet@*": +"@types/leaflet@*", "@types/leaflet@^1.2.11": version "1.5.8" resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.5.8.tgz#1c550803672fc5866b8b2c38512009f2b5d4205d" integrity sha512-qpi5n4LmwenUFZ+VZ7ytRgHK+ZAclIvloL2zoKCmmj244WD2hBcLbUZ6Szvajfe3sIkSYEJ8WZ1p9VYl8tRsMA== dependencies: "@types/geojson" "*" -"@types/leaflet@^1.2.11": - version "1.5.6" - resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.5.6.tgz#cdad1f32328331b32ee4f63c24c59cba055c9b0c" - integrity sha512-a9gVDwmNNalKrsU124kS7Lv9eo0z95CCMJu1Fp7l+A+EQ7Vv0UJ7LFkjaxu176ebUOBDEqvjn7A2vrlq5kLtkw== - dependencies: - "@types/geojson" "*" - "@types/mapbox-gl-leaflet@^0.0.1": version "0.0.1" resolved "https://registry.yarnpkg.com/@types/mapbox-gl-leaflet/-/mapbox-gl-leaflet-0.0.1.tgz#2e091ec398ac1e7ed1e52cce7c4dfaa60e25c4a5" @@ -265,9 +258,9 @@ moment "*" "@types/node@*": - version "12.12.14" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.14.tgz#1c1d6e3c75dba466e0326948d56e8bd72a1903d2" - integrity sha512-u/SJDyXwuihpwjXy7hOOghagLEV1KdAST6syfnOk6QZAMzZuWZqXy5aYYZbh8Jdpd4escVFP0MvftHNDb9pruA== + version "13.7.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.0.tgz#b417deda18cf8400f278733499ad5547ed1abec4" + integrity sha512-GnZbirvmqZUzMgkFn70c74OQpTTUcCzlhQliTzYjQMqg+hVKcDnxdL19Ne3UdYzdMA/+W3eb646FWn/ZaT1NfQ== "@types/popper.js@^1.11.0": version "1.11.0" @@ -297,9 +290,9 @@ integrity sha512-3MkYdqVF0yQFEUMbusfaVvQRQoC6yhOSdUU87/ZSvlJrI+E49s3XanUtJZtLThrvnqACnUryt2lC2ezpV9O/2Q== "@types/tapable@*": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370" - integrity sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ== + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.5.tgz#9adbc12950582aa65ead76bffdf39fe0c27a3c02" + integrity sha512-/gG2M/Imw7cQFp8PGvz/SwocNrmKFjFsm5Pb8HdbHkZ1K8pmuPzOX4VeVoiEecFCVf4CsN1r3/BRvx+6sNqwtQ== "@types/uglify-js@*": version "3.0.4" @@ -309,37 +302,23 @@ source-map "^0.6.1" "@types/uuid@^3.4.6": - version "3.4.6" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.6.tgz#d2c4c48eb85a757bf2927f75f939942d521e3016" - integrity sha512-cCdlC/1kGEZdEglzOieLDYBxHsvEOIg7kp/2FYyVR9Pxakq+Qf/inL3RKQ+PA8gOlI/NnL+fXmQH12nwcGzsHw== - dependencies: - "@types/node" "*" + version "3.4.7" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.7.tgz#51d42247473bc00e38cc8dfaf70d936842a36c03" + integrity sha512-C2j2FWgQkF1ru12SjZJyMaTPxs/f6n90+5G5qNakBxKXjTBc/YTSelHh4Pz1HUDwxFXD9WvpQhOGCDC+/Y4mIQ== "@types/webpack-sources@*": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.5.tgz#be47c10f783d3d6efe1471ff7f042611bd464a92" - integrity sha512-zfvjpp7jiafSmrzJ2/i3LqOyTYTuJ7u1KOXlKgDlvsj9Rr0x7ZiYu5lZbXwobL7lmsRNtPXlBfmaUD8eU2Hu8w== + version "0.1.6" + resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.6.tgz#3d21dfc2ec0ad0c77758e79362426a9ba7d7cbcb" + integrity sha512-FtAWR7wR5ocJ9+nP137DV81tveD/ZgB1sadnJ/axUGM3BUVfRPx8oQNMtv3JNfTeHx3VP7cXiyfR/jmtEsVHsQ== dependencies: "@types/node" "*" "@types/source-list-map" "*" source-map "^0.6.1" -"@types/webpack@^4.4.24": - version "4.41.0" - resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.0.tgz#b813a044d8b0dec7dfcd7622fdbe327bde06eb9a" - integrity sha512-tWkdf9nO0zFgAY/EumUKwrDUhraHKDqCPhwfFR/R8l0qnPdgb9le0Gzhvb7uzVpouuDGBgiE//ZdY+5jcZy2TA== - dependencies: - "@types/anymatch" "*" - "@types/node" "*" - "@types/tapable" "*" - "@types/uglify-js" "*" - "@types/webpack-sources" "*" - source-map "^0.6.0" - -"@types/webpack@^4.4.31": - version "4.41.2" - resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.2.tgz#c6faf0111de27afdffe1158dac559e447c273516" - integrity sha512-DNMQOfEvwzWRRyp6Wy9QVCgJ3gkelZsuBE2KUD318dg95s9DKGiT5CszmmV58hq8jk89I9NClre48AEy1MWAJA== +"@types/webpack@^4.4.24", "@types/webpack@^4.4.31": + version "4.41.6" + resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.6.tgz#c76afbdef59159d12e3e1332dc264b75574722a2" + integrity sha512-iWRpV5Ej+8uKrgxp6jXz3v7ZTjgtuMXY+rsxQjFNU0hYCnHkpA7vtiNffgxjuxX4feFHBbz0IF76OzX2OqDYPw== dependencies: "@types/anymatch" "*" "@types/node" "*" @@ -530,11 +509,11 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== ajv@^6.1.0, ajv@^6.10.2, ajv@^6.5.5: - version "6.10.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" - integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== + version "6.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.11.0.tgz#c3607cbc8ae392d8a5a536f25b21f8e5f3f87fe9" + integrity sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA== dependencies: - fast-deep-equal "^2.0.1" + fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" uri-js "^4.2.2" @@ -712,7 +691,7 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= -atob@^2.1.1: +atob@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== @@ -723,9 +702,9 @@ aws-sign2@~0.7.0: integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= aws4@^1.8.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.0.tgz#24390e6ad61386b0a747265754d2a17219de862c" - integrity sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A== + version "1.9.1" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e" + integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug== babel-code-frame@^6.26.0: version "6.26.0" @@ -736,31 +715,6 @@ babel-code-frame@^6.26.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-core@^6.26.0: - version "6.26.3" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" - integrity sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA== - dependencies: - babel-code-frame "^6.26.0" - babel-generator "^6.26.0" - babel-helpers "^6.24.1" - babel-messages "^6.23.0" - babel-register "^6.26.0" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - convert-source-map "^1.5.1" - debug "^2.6.9" - json5 "^0.5.1" - lodash "^4.17.4" - minimatch "^3.0.4" - path-is-absolute "^1.0.1" - private "^0.1.8" - slash "^1.0.0" - source-map "^0.5.7" - babel-extract-comments@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz#0a2aedf81417ed391b85e18b4614e693a0351a21" @@ -768,180 +722,11 @@ babel-extract-comments@^1.0.0: dependencies: babylon "^6.18.0" -babel-generator@^6.26.0: - version "6.26.1" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" - integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== - dependencies: - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - detect-indent "^4.0.0" - jsesc "^1.3.0" - lodash "^4.17.4" - source-map "^0.5.7" - trim-right "^1.0.1" - -babel-helper-evaluate-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.3.0.tgz#2439545e0b6eae5b7f49b790acbebd6b9a73df20" - integrity sha512-dRFlMTqUJRGzx5a2smKxmptDdNCXKSkPcXWzKLwAV72hvIZumrd/0z9RcewHkr7PmAEq+ETtpD1GK6wZ6ZUXzw== - -babel-helper-flip-expressions@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.3.0.tgz#f5b6394bd5219b43cf8f7b201535ed540c6e7fa2" - integrity sha512-kNGohWmtAG3b7tN1xocRQ5rsKkH/hpvZsMiGOJ1VwGJKhnwzR5KlB3rvKBaBPl5/IGHcopB2JN+r1SUEX1iMAw== - -babel-helper-is-nodes-equiv@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz#34e9b300b1479ddd98ec77ea0bbe9342dfe39684" - integrity sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ= - -babel-helper-is-void-0@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-helper-is-void-0/-/babel-helper-is-void-0-0.3.0.tgz#95570d20bd27b2206f68083ae9980ee7003d8fe7" - integrity sha512-JVqdX8y7Rf/x4NwbqtUI7mdQjL9HWoDnoAEQ8Gv8oxzjvbJv+n75f7l36m9Y8C7sCUltX3V5edndrp7Hp1oSXQ== - -babel-helper-mark-eval-scopes@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.3.0.tgz#b4731314fdd7a89091271a5213b4e12d236e29e8" - integrity sha512-nrho5Dg4vl0VUgURVpGpEGiwbst5JX7efIyDHFxmkCx/ocQFnrPt8ze9Kxl6TKjR29bJ7D/XKY1NMlSxOQJRbQ== - -babel-helper-remove-or-void@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.3.0.tgz#f43c86147c8fcc395a9528cbb31e7ff49d7e16e3" - integrity sha512-D68W1M3ibCcbg0ysh3ww4/O0g10X1CXK720oOuR8kpfY7w0yP4tVcpK7zDmI1JecynycTQYAZ1rhLJo9aVtIKQ== - -babel-helper-to-multiple-sequence-expressions@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.3.0.tgz#8da2275ccc26995566118f7213abfd9af7214427" - integrity sha512-1uCrBD+EAaMnAYh7hc944n8Ga19y3daEnoXWPYDvFVsxMCc1l8aDjksApaCEaNSSuewq8BEcff47Cy1PbLg2Gw== - -babel-helpers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" - integrity sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI= - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-messages@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4= - dependencies: - babel-runtime "^6.22.0" - -babel-minify-webpack-plugin@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-minify-webpack-plugin/-/babel-minify-webpack-plugin-0.3.1.tgz#292aa240af190e2dcadf4f684d6d84d179b6d5a4" - integrity sha512-Johg6Ju0Gxevk2R55eutMqnyXwlyUzCtwunBpiyNzoxGnKum+x5nfNuYZYHGd5Bmc1gmhjwzb7GkxHWOtYWmtQ== - dependencies: - babel-core "^6.26.0" - babel-preset-minify "^0.3.0" - webpack-sources "^1.0.1" - -babel-plugin-minify-builtins@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.3.0.tgz#4740117a6a784063aaf8f092989cf9e4bd484860" - integrity sha512-MqhSHlxkmgURqj3144qPksbZ/qof1JWdumcbucc4tysFcf3P3V3z3munTevQgKEFNMd8F5/ECGnwb63xogLjAg== - dependencies: - babel-helper-evaluate-path "^0.3.0" - -babel-plugin-minify-constant-folding@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.3.0.tgz#687e40336bd4ddd921e0e197f0006235ac184bb9" - integrity sha512-1XeRpx+aY1BuNY6QU/cm6P+FtEi3ar3XceYbmC+4q4W+2Ewq5pL7V68oHg1hKXkBIE0Z4/FjSoHz6vosZLOe/A== - dependencies: - babel-helper-evaluate-path "^0.3.0" - -babel-plugin-minify-dead-code-elimination@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.3.0.tgz#a323f686c404b824186ba5583cf7996cac81719e" - integrity sha512-SjM2Fzg85YZz+q/PNJ/HU4O3W98FKFOiP9K5z3sfonlamGOzvZw3Eup2OTiEBsbbqTeY8yzNCAv3qpJRYCgGmw== - dependencies: - babel-helper-evaluate-path "^0.3.0" - babel-helper-mark-eval-scopes "^0.3.0" - babel-helper-remove-or-void "^0.3.0" - lodash.some "^4.6.0" - -babel-plugin-minify-flip-comparisons@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.3.0.tgz#6627893a409c9f30ef7f2c89e0c6eea7ee97ddc4" - integrity sha512-B8lK+ekcpSNVH7PZpWDe5nC5zxjRiiT4nTsa6h3QkF3Kk6y9qooIFLemdGlqBq6j0zALEnebvCpw8v7gAdpgnw== - dependencies: - babel-helper-is-void-0 "^0.3.0" - -babel-plugin-minify-guarded-expressions@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.3.0.tgz#2552d96189ef45d9a463f1a6b5e4fa110703ac8d" - integrity sha512-O+6CvF5/Ttsth3LMg4/BhyvVZ82GImeKMXGdVRQGK/8jFiP15EjRpdgFlxv3cnqRjqdYxLCS6r28VfLpb9C/kA== - dependencies: - babel-helper-flip-expressions "^0.3.0" - -babel-plugin-minify-infinity@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.3.0.tgz#c5ec0edd433517cf31b3af17077c202beb48bbe7" - integrity sha512-Sj8ia3/w9158DWieUxU6/VvnYVy59geeFEkVgLZYBE8EBP+sN48tHtBM/jSgz0ejEdBlcfqJ6TnvPmVXTzR2BQ== - -babel-plugin-minify-mangle-names@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.3.0.tgz#f28561bad0dd2f0380816816bb946e219b3b6135" - integrity sha512-PYTonhFWURsfAN8achDwvR5Xgy6EeTClLz+fSgGRqjAIXb0OyFm3/xfccbQviVi1qDXmlSnt6oJhBg8KE4Fn7Q== - dependencies: - babel-helper-mark-eval-scopes "^0.3.0" - -babel-plugin-minify-numeric-literals@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.3.0.tgz#b57734a612e8a592005407323c321119f27d4b40" - integrity sha512-TgZj6ay8zDw74AS3yiIfoQ8vRSNJisYO/Du60S8nPV7EW7JM6fDMx5Sar6yVHlVuuwNgvDUBh191K33bVrAhpg== - -babel-plugin-minify-replace@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.3.0.tgz#980125bbf7cbb5a637439de9d0b1b030a4693893" - integrity sha512-VR6tTg2Lt0TicHIOw04fsUtpPw7RaRP8PC8YzSFwEixnzvguZjZJoL7TgG7ZyEWQD1cJ96UezswECmFNa815bg== - -babel-plugin-minify-simplify@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.3.0.tgz#14574cc74d21c81d3060fafa041010028189f11b" - integrity sha512-2M16ytQOCqBi7bYMu4DCWn8e6KyFCA108F6+tVrBJxOmm5u2sOmTFEa8s94tR9RHRRNYmcUf+rgidfnzL3ik9Q== - dependencies: - babel-helper-flip-expressions "^0.3.0" - babel-helper-is-nodes-equiv "^0.0.1" - babel-helper-to-multiple-sequence-expressions "^0.3.0" - -babel-plugin-minify-type-constructors@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.3.0.tgz#7f5a86ef322c4746364e3c591b8514eeafea6ad4" - integrity sha512-XRXpvsUCPeVw9YEUw+9vSiugcSZfow81oIJT0yR9s8H4W7yJ6FHbImi5DJHoL8KcDUjYnL9wYASXk/fOkbyR6Q== - dependencies: - babel-helper-is-void-0 "^0.3.0" - babel-plugin-syntax-object-rest-spread@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" integrity sha1-/WU28rzhODb/o6VFjEkDpZe7O/U= -babel-plugin-transform-inline-consecutive-adds@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.3.0.tgz#f07d93689c0002ed2b2b62969bdd99f734e03f57" - integrity sha512-iZsYAIjYLLfLK0yN5WVT7Xf7Y3wQ9Z75j9A8q/0IglQSpUt2ppTdHlwl/GeaXnxdaSmsxBu861klbTBbv2n+RA== - -babel-plugin-transform-member-expression-literals@^6.9.0: - version "6.9.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz#37039c9a0c3313a39495faac2ff3a6b5b9d038bf" - integrity sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8= - -babel-plugin-transform-merge-sibling-variables@^6.9.0: - version "6.9.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz#85b422fc3377b449c9d1cde44087203532401dae" - integrity sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4= - -babel-plugin-transform-minify-booleans@^6.9.0: - version "6.9.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz#acbb3e56a3555dd23928e4b582d285162dd2b198" - integrity sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg= - babel-plugin-transform-object-rest-spread@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" @@ -950,88 +735,7 @@ babel-plugin-transform-object-rest-spread@^6.26.0: babel-plugin-syntax-object-rest-spread "^6.8.0" babel-runtime "^6.26.0" -babel-plugin-transform-property-literals@^6.9.0: - version "6.9.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz#98c1d21e255736573f93ece54459f6ce24985d39" - integrity sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk= - dependencies: - esutils "^2.0.2" - -babel-plugin-transform-regexp-constructors@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.3.0.tgz#9bb2c8dd082271a5cb1b3a441a7c52e8fd07e0f5" - integrity sha512-h92YHzyl042rb0naKO8frTHntpRFwRgKkfWD8602kFHoQingjJNtbvZzvxqHncJ6XmKVyYvfrBpDOSkCTDIIxw== - -babel-plugin-transform-remove-console@^6.9.0: - version "6.9.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz#b980360c067384e24b357a588d807d3c83527780" - integrity sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A= - -babel-plugin-transform-remove-debugger@^6.9.0: - version "6.9.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz#42b727631c97978e1eb2d199a7aec84a18339ef2" - integrity sha1-QrcnYxyXl44estGZp67IShgznvI= - -babel-plugin-transform-remove-undefined@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.3.0.tgz#03f5f0071867781e9beabbc7b77bf8095fd3f3ec" - integrity sha512-TYGQucc8iP3LJwN3kDZLEz5aa/2KuFrqpT+s8f8NnHsBU1sAgR3y8Opns0xhC+smyDYWscqFCKM1gbkWQOhhnw== - dependencies: - babel-helper-evaluate-path "^0.3.0" - -babel-plugin-transform-simplify-comparison-operators@^6.9.0: - version "6.9.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz#f62afe096cab0e1f68a2d753fdf283888471ceb9" - integrity sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk= - -babel-plugin-transform-undefined-to-void@^6.9.0: - version "6.9.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz#be241ca81404030678b748717322b89d0c8fe280" - integrity sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA= - -babel-preset-minify@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-preset-minify/-/babel-preset-minify-0.3.0.tgz#7db64afa75f16f6e06c0aa5f25195f6f36784d77" - integrity sha512-+VV2GWEyak3eDOmzT1DDMuqHrw3VbE9nBNkx2LLVs4pH/Me32ND8DRpVDd8IRvk1xX5p75nygyRPtkMh6GIAbQ== - dependencies: - babel-plugin-minify-builtins "^0.3.0" - babel-plugin-minify-constant-folding "^0.3.0" - babel-plugin-minify-dead-code-elimination "^0.3.0" - babel-plugin-minify-flip-comparisons "^0.3.0" - babel-plugin-minify-guarded-expressions "^0.3.0" - babel-plugin-minify-infinity "^0.3.0" - babel-plugin-minify-mangle-names "^0.3.0" - babel-plugin-minify-numeric-literals "^0.3.0" - babel-plugin-minify-replace "^0.3.0" - babel-plugin-minify-simplify "^0.3.0" - babel-plugin-minify-type-constructors "^0.3.0" - babel-plugin-transform-inline-consecutive-adds "^0.3.0" - babel-plugin-transform-member-expression-literals "^6.9.0" - babel-plugin-transform-merge-sibling-variables "^6.9.0" - babel-plugin-transform-minify-booleans "^6.9.0" - babel-plugin-transform-property-literals "^6.9.0" - babel-plugin-transform-regexp-constructors "^0.3.0" - babel-plugin-transform-remove-console "^6.9.0" - babel-plugin-transform-remove-debugger "^6.9.0" - babel-plugin-transform-remove-undefined "^0.3.0" - babel-plugin-transform-simplify-comparison-operators "^6.9.0" - babel-plugin-transform-undefined-to-void "^6.9.0" - lodash.isplainobject "^4.0.6" - -babel-register@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" - integrity sha1-btAhFz4vy0htestFxgCahW9kcHE= - dependencies: - babel-core "^6.26.0" - babel-runtime "^6.26.0" - core-js "^2.5.0" - home-or-tmp "^2.0.0" - lodash "^4.17.4" - mkdirp "^0.5.1" - source-map-support "^0.4.15" - -babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: +babel-runtime@^6.18.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= @@ -1039,42 +743,6 @@ babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: core-js "^2.4.0" regenerator-runtime "^0.11.0" -babel-template@^6.24.1, babel-template@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" - integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI= - dependencies: - babel-runtime "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - lodash "^4.17.4" - -babel-traverse@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" - integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= - dependencies: - babel-code-frame "^6.26.0" - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - debug "^2.6.8" - globals "^9.18.0" - invariant "^2.2.2" - lodash "^4.17.4" - -babel-types@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= - dependencies: - babel-runtime "^6.26.0" - esutils "^2.0.2" - lodash "^4.17.4" - to-fast-properties "^1.0.3" - babylon@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" @@ -1168,6 +836,13 @@ binary-extensions@^1.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + bl@^1.0.0: version "1.2.2" resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" @@ -1198,7 +873,7 @@ boolbase@^1.0.0, boolbase@~1.0.0: resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= -bootstrap@^4.1.3: +bootstrap@^4.3.1: version "4.4.1" resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.4.1.tgz#8582960eea0c5cd2bede84d8b0baf3789c3e8b01" integrity sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA== @@ -1694,13 +1369,6 @@ content-disposition@^0.5.2: dependencies: safe-buffer "5.1.2" -convert-source-map@^1.5.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== - dependencies: - safe-buffer "~5.1.1" - copy-concurrently@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" @@ -1732,10 +1400,10 @@ copy-webpack-plugin@^4.5.2: p-limit "^1.0.0" serialize-javascript "^1.4.0" -core-js@^2.4.0, core-js@^2.5.0: - version "2.6.10" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.10.tgz#8a5b8391f8cc7013da703411ce5b585706300d7f" - integrity sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA== +core-js@^2.4.0: + version "2.6.11" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" + integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -1909,7 +1577,7 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: +debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -2063,13 +1731,6 @@ detect-file@^1.0.0: resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= -detect-indent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg= - dependencies: - repeating "^2.0.0" - detect-libc@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" @@ -2180,7 +1841,7 @@ duplexify@^3.4.2, duplexify@^3.6.0: readable-stream "^2.0.0" stream-shift "^1.0.0" -earcut@^2.2.0: +earcut@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/earcut/-/earcut-2.2.2.tgz#41b0bc35f63e0fe80da7cddff28511e7e2e80d11" integrity sha512-eZoZPPJcUHnfRZ0PjLvx2qBordSiO8ofC3vt+qACLM95u+4DovnbYNpQtJh0DNsWj8RnxrQytD4WA8gj5cRIaQ== @@ -2260,21 +1921,22 @@ error-ex@^1.2.0: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.12.0, es-abstract@^1.5.1: - version "1.16.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.16.3.tgz#52490d978f96ff9f89ec15b5cf244304a5bca161" - integrity sha512-WtY7Fx5LiOnSYgF5eg/1T+GONaGmpvpPdCpSnYij+U2gDTL0UPfWrhDw7b2IYb+9NQJsYpCA0wOQvZfsd6YwRw== +es-abstract@^1.17.0-next.1, es-abstract@^1.17.2: + version "1.17.4" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.4.tgz#e3aedf19706b20e7c2594c35fc0d57605a79e184" + integrity sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ== dependencies: es-to-primitive "^1.2.1" function-bind "^1.1.1" has "^1.0.3" has-symbols "^1.0.1" - is-callable "^1.1.4" - is-regex "^1.0.4" + is-callable "^1.1.5" + is-regex "^1.0.5" object-inspect "^1.7.0" object-keys "^1.1.1" - string.prototype.trimleft "^2.1.0" - string.prototype.trimright "^2.1.0" + object.assign "^4.1.0" + string.prototype.trimleft "^2.1.1" + string.prototype.trimright "^2.1.1" es-to-primitive@^1.2.1: version "1.2.1" @@ -2326,9 +1988,9 @@ esutils@^2.0.2: integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== events@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" - integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA== + version "3.1.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59" + integrity sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg== evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: version "1.0.3" @@ -2474,10 +2136,10 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= +fast-deep-equal@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" + integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== fast-glob@^2.0.2: version "2.2.7" @@ -2492,9 +2154,9 @@ fast-glob@^2.0.2: micromatch "^3.1.10" fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== fastparse@^1.1.1: version "1.1.2" @@ -2559,6 +2221,11 @@ file-type@^8.1.0: resolved "https://registry.yarnpkg.com/file-type/-/file-type-8.1.0.tgz#244f3b7ef641bbe0cca196c7276e4b332399f68c" integrity sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ== +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + filename-reserved-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" @@ -2724,12 +2391,12 @@ fs.realpath@^1.0.0: integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= fsevents@^1.2.7: - version "1.2.9" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" - integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== + version "1.2.11" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.11.tgz#67bf57f4758f02ede88fb2a1712fef4d15358be3" + integrity sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw== dependencies: + bindings "^1.5.0" nan "^2.12.1" - node-pre-gyp "^0.12.0" fstream@^1.0.0, fstream@^1.0.12: version "1.0.12" @@ -2783,9 +2450,9 @@ get-caller-file@^2.0.1: integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== get-own-enumerable-property-symbols@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.1.tgz#6f7764f88ea11e0b514bd9bd860a132259992ca4" - integrity sha512-09/VS4iek66Dh2bctjRkowueRJbY1JDGR1L/zRxO1Qk8Uxs6PnqaNSqalpizPT+CDjre3hnEsuzvhgomz9qYrA== + version "3.0.2" + resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" + integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== get-proxy@^2.0.0: version "2.1.0" @@ -2907,11 +2574,6 @@ global-prefix@^3.0.0: kind-of "^6.0.2" which "^1.3.1" -globals@^9.18.0: - version "9.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== - globby@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" @@ -2949,9 +2611,9 @@ globby@^8.0.1: slash "^1.0.0" globule@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d" - integrity sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ== + version "1.3.0" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.3.0.tgz#41d0e9fb44afd4b80d93a23263714f90b3dec904" + integrity sha512-YlD4kdMqRCQHrhVdonet4TdRtv1/sZKepvoxNT4Nrhrp5HI8XFfc8kFlGlBn2myBo80aGp8Eft259mbcUJhgSg== dependencies: glob "~7.1.1" lodash "~4.17.10" @@ -3045,7 +2707,7 @@ has-symbol-support-x@^1.4.1: resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== -has-symbols@^1.0.1: +has-symbols@^1.0.0, has-symbols@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== @@ -3093,7 +2755,7 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -has@^1.0.1, has@^1.0.3: +has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== @@ -3125,14 +2787,6 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -home-or-tmp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" - integrity sha1-42w/LSyufXRqhX440Y1fMqeILbg= - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.1" - homedir-polyfill@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" @@ -3367,13 +3021,6 @@ into-stream@^3.1.0: from2 "^2.1.1" p-is-promise "^1.1.0" -invariant@^2.2.2: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" @@ -3415,10 +3062,10 @@ is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-callable@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" - integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== +is-callable@^1.1.4, is-callable@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" + integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== is-data-descriptor@^0.1.4: version "0.1.4" @@ -3435,9 +3082,9 @@ is-data-descriptor@^1.0.0: kind-of "^6.0.0" is-date-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" + integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== is-descriptor@^0.1.0: version "0.1.6" @@ -3475,11 +3122,9 @@ is-extglob@^2.1.0, is-extglob@^2.1.1: integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= is-finite@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= - dependencies: - number-is-nan "^1.0.0" + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" + integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== is-fullwidth-code-point@^1.0.0: version "1.0.0" @@ -3577,12 +3222,12 @@ is-png@^1.0.0: resolved "https://registry.yarnpkg.com/is-png/-/is-png-1.1.0.tgz#d574b12bf275c0350455570b0e5b57ab062077ce" integrity sha1-1XSxK/J1wDUEVVcLDltXqwYgd84= -is-regex@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= +is-regex@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" + integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== dependencies: - has "^1.0.1" + has "^1.0.3" is-regexp@^1.0.0: version "1.0.0" @@ -3687,11 +3332,6 @@ js-base64@^2.1.8: resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121" integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw== -"js-tokens@^3.0.0 || ^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" @@ -3710,11 +3350,6 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= -jsesc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s= - jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" @@ -3752,11 +3387,6 @@ json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= -json5@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= - json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -3818,9 +3448,9 @@ kind-of@^5.0.0: integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== lcid@^1.0.0: version "1.0.0" @@ -3887,11 +3517,6 @@ lodash._reinterpolate@^3.0.0: resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= -lodash.isplainobject@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= - lodash.map@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" @@ -3902,11 +3527,6 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash.some@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" - integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0= - lodash.template@^4.4.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" @@ -3922,7 +3542,7 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "^3.0.0" -lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.4, lodash@~4.17.10: +lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.15, lodash@~4.17.10: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -3940,13 +3560,6 @@ longest@^1.0.0: resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc= -loose-envify@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - loud-rejection@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" @@ -4040,9 +3653,9 @@ mapbox-gl-leaflet@^0.0.11: integrity sha512-3jXZbQaZf/6D3lzv2PBHZsDvlT5wWt7bdm/zDDq6aKJ3n90PGQ+hyBY6Zav0z93Fy0PBHtOsx84Y5MVBA7si5Q== mapbox-gl@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/mapbox-gl/-/mapbox-gl-1.6.1.tgz#bc9beb2d7d6464b0d281a225a3f23bd3a84d9f49" - integrity sha512-qUvu8c/WX0woSLj8M64eK8351th4RI2+grGJ0ZlFb5ELEJNTb4SqMX/4uxRkb5d1euh2U72+AML1QOZjQnUPUw== + version "1.7.0" + resolved "https://registry.yarnpkg.com/mapbox-gl/-/mapbox-gl-1.7.0.tgz#b23a223af61f0c5066c6fa8072f599209b609cc9" + integrity sha512-iVZQUdhZzeVCE8VlELo24GfGqhAzjouiJl1K4rcfk9mtyJLCbWHlzGT6H5Bs61A/3NQXsSx54GdJXAWvebtFFg== dependencies: "@mapbox/geojson-rewind" "^0.4.0" "@mapbox/geojson-types" "^1.0.2" @@ -4054,7 +3667,7 @@ mapbox-gl@^1.6.1: "@mapbox/vector-tile" "^1.3.1" "@mapbox/whoots-js" "^3.1.0" csscolorparser "~1.0.2" - earcut "^2.2.0" + earcut "^2.2.2" geojson-vt "^3.2.1" gl-matrix "^3.0.0" grid-index "^1.1.0" @@ -4155,17 +3768,17 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -mime-db@1.42.0, mime-db@^1.28.0: - version "1.42.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.42.0.tgz#3e252907b4c7adb906597b4b65636272cf9e7bac" - integrity sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ== +mime-db@1.43.0, mime-db@^1.28.0: + version "1.43.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" + integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.25" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.25.tgz#39772d46621f93e2a80a856c53b86a62156a6437" - integrity sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg== + version "2.1.26" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" + integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ== dependencies: - mime-db "1.42.0" + mime-db "1.43.0" mimic-fn@^2.0.0: version "2.1.0" @@ -4335,9 +3948,9 @@ nanomatch@^1.2.9: to-regex "^3.0.1" needle@^2.2.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" - integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== + version "2.3.2" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.2.tgz#3342dea100b7160960a450dc8c22160ac712a528" + integrity sha512-DUzITvPVDUy6vczKKYTnWc/pBZ0EnjMJnQ3y+Jo5zfKFimJs7S3HFCxCRZYB9FUZcrzUQr3WsmvZgddMEIZv6w== dependencies: debug "^3.2.6" iconv-lite "^0.4.4" @@ -4400,10 +4013,10 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" -node-pre-gyp@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" - integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== +node-pre-gyp@*: + version "0.14.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83" + integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA== dependencies: detect-libc "^1.0.2" mkdirp "^0.5.1" @@ -4414,12 +4027,12 @@ node-pre-gyp@^0.12.0: rc "^1.2.7" rimraf "^2.6.1" semver "^5.3.0" - tar "^4" + tar "^4.4.2" node-sass@^4.9.3: - version "4.13.0" - resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.13.0.tgz#b647288babdd6a1cb726de4545516b31f90da066" - integrity sha512-W1XBrvoJ1dy7VsvTAS5q1V45lREbTlZQqFbiHb3R3OTTCma0XBtuG6xZ6Z4506nR4lmHPTqVRwxT6KgtWC97CA== + version "4.13.1" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.13.1.tgz#9db5689696bb2eec2c32b98bfea4c7a2e992d0a3" + integrity sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw== dependencies: async-foreach "^0.1.3" chalk "^1.1.1" @@ -4486,9 +4099,11 @@ normalize-url@2.0.1: sort-keys "^2.0.0" npm-bundled@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.0.tgz#2e8fdb7e69eff2df963937b696243316537c284b" - integrity sha512-ez6dcKBFNo4FvlMqscBEFUum6M2FTLW5grqm3DyBKB5XOyKVCeeWvAuoZtbmW/5Cv8EM2bQUOA6ufxa/TKVN0g== + version "1.1.1" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" + integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== + dependencies: + npm-normalize-package-bin "^1.0.1" npm-conf@^1.1.0: version "1.1.3" @@ -4498,13 +4113,19 @@ npm-conf@^1.1.0: config-chain "^1.1.11" pify "^3.0.0" +npm-normalize-package-bin@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" + integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== + npm-packlist@^1.1.6: - version "1.4.6" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.6.tgz#53ba3ed11f8523079f1457376dd379ee4ea42ff4" - integrity sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg== + version "1.4.8" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" + integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== dependencies: ignore-walk "^3.0.1" npm-bundled "^1.0.1" + npm-normalize-package-bin "^1.0.1" npm-run-path@^2.0.0: version "2.0.2" @@ -4559,7 +4180,7 @@ object-inspect@^1.7.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== -object-keys@^1.0.12, object-keys@^1.1.1: +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== @@ -4571,13 +4192,23 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.getownpropertydescriptors@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" - integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= +object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== dependencies: define-properties "^1.1.2" - es-abstract "^1.5.1" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.getownpropertydescriptors@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" + integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" object.pick@^1.3.0: version "1.3.0" @@ -4587,12 +4218,12 @@ object.pick@^1.3.0: isobject "^3.0.1" object.values@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.0.tgz#bf6810ef5da3e5325790eaaa2be213ea84624da9" - integrity sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg== + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" + integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== dependencies: define-properties "^1.1.3" - es-abstract "^1.12.0" + es-abstract "^1.17.0-next.1" function-bind "^1.1.1" has "^1.0.3" @@ -4645,7 +4276,7 @@ os-locale@^3.1.0: lcid "^2.0.0" mem "^4.0.0" -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: +os-tmpdir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= @@ -4710,9 +4341,9 @@ p-limit@^1.0.0, p-limit@^1.1.0: p-try "^1.0.0" p-limit@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" - integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== + version "2.2.2" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" + integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== dependencies: p-try "^2.0.0" @@ -4777,9 +4408,9 @@ p-try@^2.0.0: integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== pako@~1.0.5: - version "1.0.10" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732" - integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw== + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== parallel-transform@^1.1.0: version "1.2.0" @@ -4841,7 +4472,7 @@ path-exists@^3.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= -path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: +path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= @@ -4958,9 +4589,9 @@ pngquant-bin@^5.0.0: logalot "^2.0.0" popper.js@*, popper.js@^1.14.1, popper.js@^1.14.4: - version "1.16.0" - resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.0.tgz#2e1816bcbbaa518ea6c2e15a466f4cb9c6e2fbb3" - integrity sha512-+G+EkOPoE5S/zChTpmBSSDYmhXJ5PsW8eMhH8cP/CQHMFPBG/kC9Y5IIw6qNYgdJ+/COf0ddY2li28iHaZRSjw== + version "1.16.1" + resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b" + integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ== portal-vue@^2.1.7: version "2.1.7" @@ -5037,11 +4668,6 @@ pretty-bytes@^5.1.0: resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2" integrity sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg== -private@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== - process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -5078,9 +4704,9 @@ pseudomap@^1.0.2: integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= psl@^1.1.24: - version "1.6.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.6.0.tgz#60557582ee23b6c43719d9890fb4170ecd91e110" - integrity sha512-SYKKmVel98NCOYXpkwUqZqh0ahZeeKfmisiLIcEZdsb+WbLv02g/dI5BUmZnIyOe7RzZtLax81nnb2HbvC2tzA== + version "1.7.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.7.0.tgz#f1c4c47a8ef97167dea5d6bbf4816d736e884a3c" + integrity sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ== public-encrypt@^4.0.0: version "4.0.3" @@ -5216,9 +4842,9 @@ read-pkg@^1.0.0: path-type "^1.0.0" "readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: - version "2.3.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -5397,9 +5023,9 @@ resolve-url@^0.2.1: integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= resolve@^1.10.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.13.1.tgz#be0aa4c06acd53083505abb35f4d66932ab35d16" - integrity sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w== + version "1.15.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" + integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== dependencies: path-parse "^1.0.6" @@ -5554,10 +5180,10 @@ serialize-javascript@^1.4.0: resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.9.1.tgz#cfc200aef77b600c47da9bb8149c943e798c2fdb" integrity sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A== -serialize-javascript@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.1.tgz#952907a04a3e3a75af7f73d92d15e233862048b2" - integrity sha512-MPLPRpD4FNqWq9tTIjYG5LesFouDhdyH0EPY3gVK4DRD5+g4aDqdNSzLIwceulo3Yj+PL1bPh6laE5+H6LTcrQ== +serialize-javascript@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" + integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" @@ -5682,23 +5308,16 @@ source-list-map@^2.0.0: integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== source-map-resolve@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" - integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== dependencies: - atob "^2.1.1" + atob "^2.1.2" decode-uri-component "^0.2.0" resolve-url "^0.2.1" source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.4.15: - version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" - integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== - dependencies: - source-map "^0.5.6" - source-map-support@~0.5.12: version "0.5.16" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" @@ -5719,7 +5338,7 @@ source-map@^0.4.2: dependencies: amdefine ">=0.0.4" -source-map@^0.5.6, source-map@^0.5.7: +source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -5860,9 +5479,9 @@ stream-http@^2.7.2: xtend "^4.0.0" stream-shift@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" - integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= + version "1.0.1" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" + integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== strict-uri-encode@^1.0.0: version "1.1.0" @@ -5895,18 +5514,18 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string.prototype.trimleft@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" - integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw== +string.prototype.trimleft@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz#9bdb8ac6abd6d602b17a4ed321870d2f8dcefc74" + integrity sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag== dependencies: define-properties "^1.1.3" function-bind "^1.1.1" -string.prototype.trimright@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" - integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg== +string.prototype.trimright@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz#440314b15996c866ce8a0341894d45186200c5d9" + integrity sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g== dependencies: define-properties "^1.1.3" function-bind "^1.1.1" @@ -6081,7 +5700,7 @@ tar@^2.0.0: fstream "^1.0.12" inherits "2" -tar@^4: +tar@^4.4.2: version "4.4.13" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== @@ -6107,25 +5726,25 @@ tempfile@^2.0.0: temp-dir "^1.0.0" uuid "^3.0.1" -terser-webpack-plugin@^1.4.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.2.tgz#e23c0d554587d1f473bd0cf68627720e733890a4" - integrity sha512-fdEb91kR2l+BVgES77N/NTXWZlpX6vX+pYPjnX5grcDYBF2CMnzJiXX4NNlna4l04lvCW39lZ+O/jSvUhHH/ew== +terser-webpack-plugin@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c" + integrity sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA== dependencies: cacache "^12.0.2" find-cache-dir "^2.1.0" is-wsl "^1.1.0" schema-utils "^1.0.0" - serialize-javascript "^2.1.1" + serialize-javascript "^2.1.2" source-map "^0.6.1" terser "^4.1.2" webpack-sources "^1.4.0" worker-farm "^1.7.0" terser@^4.1.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.4.2.tgz#448fffad0245f4c8a277ce89788b458bfd7706e8" - integrity sha512-Uufrsvhj9O1ikwgITGsZ5EZS6qPokUOkCegS7fYOdGTv+OA90vndUbU6PEjr5ePqHfNUbGyMO7xyIZv2MhsALQ== + version "4.6.3" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.3.tgz#e33aa42461ced5238d352d2df2a67f21921f8d87" + integrity sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ== dependencies: commander "^2.20.0" source-map "~0.6.1" @@ -6171,11 +5790,6 @@ to-buffer@^1.1.1: resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== -to-fast-properties@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" - integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= - to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" @@ -6221,11 +5835,6 @@ trim-repeated@^1.0.0: dependencies: escape-string-regexp "^1.0.2" -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= - "true-case-path@^1.0.2": version "1.0.3" resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d" @@ -6272,9 +5881,9 @@ typedarray@^0.0.6: integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= typescript@^3.6: - version "3.7.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.4.tgz#1743a5ec5fef6a1fa9f3e4708e33c81c73876c19" - integrity sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw== + version "3.7.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" + integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== unbzip2-stream@^1.0.9: version "1.3.3" @@ -6381,12 +5990,14 @@ util-deprecate@~1.0.1: integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= util.promisify@^1.0.0, util.promisify@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" - integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== + version "1.0.1" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" + integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== dependencies: - define-properties "^1.1.2" - object.getownpropertydescriptors "^2.0.3" + define-properties "^1.1.3" + es-abstract "^1.17.2" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.0" util@0.10.3: version "0.10.3" @@ -6403,9 +6014,9 @@ util@^0.11.0: inherits "2.0.3" uuid@^3.0.1, uuid@^3.3.2: - version "3.3.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" - integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== v8-compile-cache@2.0.3: version "2.0.3" @@ -6479,9 +6090,9 @@ vue2-leaflet@^1.0.2: leaflet "1.3.1" vue@^2.5.17: - version "2.6.10" - resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637" - integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ== + version "2.6.11" + resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.11.tgz#76594d877d4b12234406e84e35275c6d514125c5" + integrity sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ== vuex-class@^0.3.1: version "0.3.2" @@ -6527,7 +6138,7 @@ webpack-cli@^3.1.0: v8-compile-cache "2.0.3" yargs "13.2.4" -webpack-sources@^1.0.1, webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1: +webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1: version "1.4.3" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== @@ -6536,9 +6147,9 @@ webpack-sources@^1.0.1, webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack- source-map "~0.6.1" webpack@^4.17.0: - version "4.41.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.2.tgz#c34ec76daa3a8468c9b61a50336d8e3303dce74e" - integrity sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A== + version "4.41.5" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.5.tgz#3210f1886bce5310e62bb97204d18c263341b77c" + integrity sha512-wp0Co4vpyumnp3KlkmpM5LWuzvZYayDwM2n17EHFr4qxBBbRokC7DJawPJC7TfSFZ9HZ6GsdH40EBj4UV0nmpw== dependencies: "@webassemblyjs/ast" "1.8.5" "@webassemblyjs/helper-module-context" "1.8.5" @@ -6560,7 +6171,7 @@ webpack@^4.17.0: node-libs-browser "^2.2.1" schema-utils "^1.0.0" tapable "^1.1.3" - terser-webpack-plugin "^1.4.1" + terser-webpack-plugin "^1.4.3" watchpack "^1.6.0" webpack-sources "^1.4.1" @@ -6758,9 +6369,9 @@ wrappy@1: integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= xmldom@^0.1.27: - version "0.1.27" - resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" - integrity sha1-1QH5ezvbQDr4757MIFcxh6rawOk= + version "0.1.31" + resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff" + integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ== xpath@^0.0.27: version "0.0.27" -- 2.45.2 From 0fc0dd07e444b336e4662f9765e7042262faac43 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 9 Feb 2020 14:05:46 +0100 Subject: [PATCH 05/77] #32 - Switch instead of checkbox --- package.json | 4 ++-- resources/styles/_popper.scss | 4 ++++ resources/styles/main.scss | 2 ++ templates/app.html.twig | 40 ++++++++++++++++++++--------------- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index 07a27f5..65e7b89 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,11 @@ "@fortawesome/pro-regular-svg-icons": "^5.3.1", "@fortawesome/pro-solid-svg-icons": "^5.3.1", "@fortawesome/vue-fontawesome": "^0.1.1", - "@types/bootstrap": "^4.1.2", + "@types/bootstrap": "^4.3.1", "@types/jquery": "^3.3.6", "@types/moment": "^2.13.0", "@types/popper.js": "^1.11.0", - "bootstrap": "^4.1.3", + "bootstrap": "^4.3.1", "css-loader": "^1.0.0", "file-loader": "^2.0.0", "jquery": "^3.3.1", diff --git a/resources/styles/_popper.scss b/resources/styles/_popper.scss index 07d5247..7b9ea5b 100644 --- a/resources/styles/_popper.scss +++ b/resources/styles/_popper.scss @@ -88,6 +88,10 @@ font-size: $font-size-sm; font-weight: bold; margin-bottom: .5rem; + + &:last-child { + margin-bottom: 0; + } } @mixin placement($placement) { diff --git a/resources/styles/main.scss b/resources/styles/main.scss index 73afad3..58b6f1b 100644 --- a/resources/styles/main.scss +++ b/resources/styles/main.scss @@ -72,6 +72,8 @@ $grid-gutter-width: $spacer * 2; @import "trip"; @import "dragscroll"; +@import "ui/switch"; + body { min-height: 100vh; display: flex; diff --git a/templates/app.html.twig b/templates/app.html.twig index 464825c..1fb8bfb 100644 --- a/templates/app.html.twig +++ b/templates/app.html.twig @@ -27,19 +27,23 @@ <fa :icon="['fal', sections.messages ? 'chevron-up' : 'chevron-down']" fixed-width/> </button> - <popper reference="settings-messages" v-if="visibility.messages" arrow placement="left-start" @leave="visibility.messages = false"> - <h3 class="popper__heading flex"> - <fa :icon="['far', 'cog']"></fa> - <label class="text" for="messages-auto-refresh">autoodświeżanie</label> - <input type="checkbox" class="flex-space-left" id="messages-auto-refresh" v-model="autorefresh.messages.active"/> - </h3> - <div class="flex" v-show="autorefresh.messages.active"> - <span class="text">co</span> - <label class="sr-only" for="messages-auto-refresh-interval">częstotliwość odświeżania</label> - <input type="text" class="form-control form-control-sm" id="messages-auto-refresh-interval" v-model="autorefresh.messages.interval"/> - <span class="text">s</span> - </div> - </popper> + <portal to="popups"> + <popper reference="settings-messages" v-if="visibility.messages" arrow placement="left-start" @leave="visibility.messages = false"> + <h3 class="popper__heading flex"> + <label class="text" for="messages-auto-refresh"> + <fa :icon="['far', 'sync']" fixed-width></fa> + autoodświeżanie + </label> + <ui-switch id="messages-auto-refresh" v-model="autorefresh.messages.active" class="flex-space-left"></ui-switch> + </h3> + <div class="flex" v-if="autorefresh.messages.active"> + <span class="text">co</span> + <label class="sr-only" for="messages-auto-refresh-interval">częstotliwość odświeżania</label> + <input type="text" class="form-control form-control-sm" id="messages-auto-refresh-interval" v-model="autorefresh.messages.interval"/> + <span class="text">s</span> + </div> + </popper> + </portal> </header> <fold :visible="sections.messages"> <messages></messages> @@ -64,11 +68,13 @@ <portal to="popups"> <popper reference="settings-departures" v-if="visibility.departures" arrow placement="left-start" @leave="visibility.departures = false"> <h3 class="popper__heading flex"> - <fa :icon="['far', 'sync']" fixed-width></fa> - <label class="text" for="messages-auto-refresh">autoodświeżanie</label> - <input type="checkbox" class="flex-space-left" id="messages-auto-refresh" v-model="autorefresh.departures.active"/> + <label class="text" for="messages-auto-refresh"> + <fa :icon="['far', 'sync']" fixed-width></fa> + autoodświeżanie + </label> + <ui-switch id="messages-auto-refresh" v-model="autorefresh.departures.active" class="flex-space-left"></ui-switch> </h3> - <div class="flex" v-show="autorefresh.messages.active"> + <div class="flex" v-if="autorefresh.departures.active"> <span class="text">co</span> <label class="sr-only" for="messages-auto-refresh-interval">częstotliwość odświeżania</label> <input type="text" class="form-control form-control-sm form-control-simple" id="messages-auto-refresh-interval" v-model="autorefresh.departures.interval"/> -- 2.45.2 From 8d5bdc061dc153bf4db936c2d1eec225b0c7d500 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 9 Feb 2020 15:56:29 +0100 Subject: [PATCH 06/77] Restyle inputs --- resources/components/finder.html | 2 +- resources/styles/_common.scss | 5 ----- resources/styles/_form.scss | 32 +++++++++++++++++++++++++++- templates/app.html.twig | 36 +++++++++++++++++++++----------- 4 files changed, 56 insertions(+), 19 deletions(-) diff --git a/resources/components/finder.html b/resources/components/finder.html index ac9798c..6a7d452 100644 --- a/resources/components/finder.html +++ b/resources/components/finder.html @@ -1,5 +1,5 @@ <div class="finder"> - <input class="form-control" :value="filter" @input="filter = $event.target.value" placeholder="Zacznij pisać nazwę aby szukać..."/> + <input class="form-control form-control--framed" :value="filter" @input="filter = $event.target.value" placeholder="Zacznij pisać nazwę aby szukać..."/> <div v-if="filter.length < 3" class="mt-2"> <favourites /> diff --git a/resources/styles/_common.scss b/resources/styles/_common.scss index e58e558..3ea5003 100644 --- a/resources/styles/_common.scss +++ b/resources/styles/_common.scss @@ -38,7 +38,6 @@ transition: height 250ms ease; will-change: height; - box-sizing: padding-box; } .flex { @@ -94,10 +93,6 @@ } } -svg.svg-inline--fa { - //transform: rotate(360deg) -} - .btn-unstyled { padding: 0; margin: 0; diff --git a/resources/styles/_form.scss b/resources/styles/_form.scss index 501fd56..1101da9 100644 --- a/resources/styles/_form.scss +++ b/resources/styles/_form.scss @@ -1,11 +1,41 @@ label { font-weight: bold; - font-size: .8rem; margin-bottom: 0; margin-top: -0.2rem; display: block; } +.label-sm { + font-size: .8rem; +} + .form-group:last-child { margin-bottom: 0; } + +.form-control, .input-group-text { + background: rgba($dark, .06); + border: none; + border-bottom: 2px solid $dark; + + &:focus { + background: rgba($dark, .06); + } +} + +.form-control--framed { + background: transparent; + border: 1px solid $text-muted; + + &:focus { + background-color: transparent; + } +} + +.input-group-append { + margin-left: 0; +} + +.input-group-prepend { + margin-right: 0; +} diff --git a/templates/app.html.twig b/templates/app.html.twig index 1fb8bfb..327f004 100644 --- a/templates/app.html.twig +++ b/templates/app.html.twig @@ -11,7 +11,7 @@ <fa :icon="['fal', 'bullhorn']" fixed-width class="mr-2"></fa> Komunikaty <span class="ml-2 badge badge-pill badge-dark">{{ '{{ messages.count }}' }}</span> </h2> - <button class="btn btn-action flex-space-left" ref="settings-messages" @click="visibility.messages = true"> + <button class="btn btn-action flex-space-left" ref="settings-messages" @click="visibility.messages = !visibility.messages"> <tooltip>ustawienia</tooltip> <fa :icon="['fal', 'cog']" fixed-width></fa> </button> @@ -37,10 +37,16 @@ <ui-switch id="messages-auto-refresh" v-model="autorefresh.messages.active" class="flex-space-left"></ui-switch> </h3> <div class="flex" v-if="autorefresh.messages.active"> - <span class="text">co</span> - <label class="sr-only" for="messages-auto-refresh-interval">częstotliwość odświeżania</label> - <input type="text" class="form-control form-control-sm" id="messages-auto-refresh-interval" v-model="autorefresh.messages.interval"/> - <span class="text">s</span> + <label for="messages-auto-refresh-interval" class="text"> + <span class="sr-only">częstotliwość odświeżania</span> + co + </label> + <div class="input-group input-group-sm"> + <input type="text" class="form-control form-control-sm form-control-simple" id="messages-auto-refresh-interval" v-model="autorefresh.messages.interval"/> + <div class="input-group-append"> + <span class="input-group-text" aria-label="sekund">s</span> + </div> + </div> </div> </popper> </portal> @@ -57,7 +63,7 @@ <span class="text">Odjazdy</span> </h2> - <button class="btn btn-action flex-space-left" ref="settings-departures" @click="visibility.departures = true"> + <button class="btn btn-action flex-space-left" ref="settings-departures" @click="visibility.departures = !visibility.departures"> <tooltip>ustawienia</tooltip> <fa :icon="['fal', 'cog']" fixed-width></fa> </button> @@ -68,17 +74,23 @@ <portal to="popups"> <popper reference="settings-departures" v-if="visibility.departures" arrow placement="left-start" @leave="visibility.departures = false"> <h3 class="popper__heading flex"> - <label class="text" for="messages-auto-refresh"> + <label class="text" for="departures-auto-refresh"> <fa :icon="['far', 'sync']" fixed-width></fa> autoodświeżanie </label> - <ui-switch id="messages-auto-refresh" v-model="autorefresh.departures.active" class="flex-space-left"></ui-switch> + <ui-switch id="departures-auto-refresh" v-model="autorefresh.departures.active" class="flex-space-left"></ui-switch> </h3> <div class="flex" v-if="autorefresh.departures.active"> - <span class="text">co</span> - <label class="sr-only" for="messages-auto-refresh-interval">częstotliwość odświeżania</label> - <input type="text" class="form-control form-control-sm form-control-simple" id="messages-auto-refresh-interval" v-model="autorefresh.departures.interval"/> - <span class="text">s</span> + <label for="departures-auto-refresh-interval" class="text"> + <span class="sr-only">częstotliwość odświeżania</span> + co + </label> + <div class="input-group input-group-sm"> + <input type="text" class="form-control form-control-sm form-control-simple" id="departures-auto-refresh-interval" v-model="autorefresh.departures.interval"/> + <div class="input-group-append"> + <span class="input-group-text" aria-label="sekund">s</span> + </div> + </div> </div> </popper> </portal> -- 2.45.2 From d6850773b6fa7929c083d775098d4d450d133e43 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 9 Feb 2020 21:56:21 +0100 Subject: [PATCH 07/77] #22 - Create icon library --- resources/components/departures.html | 2 +- .../components/departures/departure.html | 13 +- resources/components/favourites.html | 6 +- resources/components/favourites/save.html | 2 +- resources/components/finder.html | 8 +- resources/components/line.html | 6 +- resources/components/messages.html | 4 +- resources/components/picker/stop.html | 4 +- resources/components/stop/details.html | 4 +- resources/components/ui/icon.html | 4 + resources/ts/app.ts | 8 +- resources/ts/components/messages.ts | 6 +- resources/ts/components/ui/icon.ts | 127 ++++++++++++++++++ resources/ts/components/ui/index.ts | 1 + resources/ts/components/ui/switch.ts | 2 +- resources/ts/font-awesome.ts | 16 --- templates/app.html.twig | 36 ++--- templates/choose.html.twig | 4 +- webpack.config.js | 3 +- 19 files changed, 182 insertions(+), 74 deletions(-) create mode 100644 resources/components/ui/icon.html create mode 100644 resources/ts/components/ui/icon.ts delete mode 100644 resources/ts/font-awesome.ts diff --git a/resources/components/departures.html b/resources/components/departures.html index d8f3557..e2f02b8 100644 --- a/resources/components/departures.html +++ b/resources/components/departures.html @@ -3,7 +3,7 @@ <departure :departure="departure" :key="departure.key" v-for="departure in departures"/> </ul> <div class="alert alert-info" v-if="stops.length === 0"> - <fa :icon="['fal', 'info-circle']"/> + <ui-icon icon="info"/> Wybierz przystanki korzystając z wyszukiwarki poniżej, aby zobaczyć listę odjazdów. </div> </div> diff --git a/resources/components/departures/departure.html b/resources/components/departures/departure.html index cef5126..06b56d8 100644 --- a/resources/components/departures/departure.html +++ b/resources/components/departures/departure.html @@ -6,11 +6,10 @@ </div> <div class="departure__time"> - <fa-layers v-if="!departure.estimated" class="mr-1"> + <template v-if="!departure.estimated"> <tooltip placement="top-end">Czas rozkładowy, nieuwzględniający aktualnej sytuacji komunikacyjnej.</tooltip> - <fa :icon="['far', 'clock']"/> - <fa :icon="['fas', 'exclamation-triangle']" transform="shrink-5 down-4 right-6"/> - </fa-layers> + <ui-icon icon="departure-warning"/> + </template> <span :class="[ 'departure__time', 'departure__time--delayed']" v-if="timeDiffers"> {{ departure.scheduled.format('HH:mm') }} @@ -24,13 +23,13 @@ </div> <div class="departure__stop"> - <fa :icon="['fal', 'sign']" fixed-width class="mr-1 flex-shrink-0"/> + <ui-icon icon="stop" fixed-width class="mr-1 flex-shrink-0"/> <stop :stop="departure.stop"/> <div class="stop__actions flex-space-left"> <button class="btn btn-action" @click="showTrip = !showTrip"> <tooltip>pokaż/ukryj trasę</tooltip> - <fa :icon="['far', 'code-commit']" /> + <ui-icon icon="track" /> </button> </div> </div> @@ -38,7 +37,7 @@ <fold :visible="showTrip"> <trip :schedule="trip.schedule" :current="departure.stop" v-if="trip" :class="[ `trip--${departure.line.type}` ]"/> <div v-else class="text-center"> - <fa icon="spinner-third" pulse></fa> + <ui-icon icon="spinner"/> </div> </fold> </li> diff --git a/resources/components/favourites.html b/resources/components/favourites.html index 0e49f25..2e4ce30 100644 --- a/resources/components/favourites.html +++ b/resources/components/favourites.html @@ -3,7 +3,7 @@ <li v-for="favourite in favourites" class="favourite"> <button @click="choose(favourite)" class="favourite__entry"> <div class="icon"> - <fa :icon="['fal', 'star']"/> + <ui-icon icon="favourite"/> </div> <div class="overflow-hidden"> <span class="text flex-grow-1">{{ favourite.name }}</span> @@ -14,12 +14,12 @@ </button> <button class="btn btn-action" @click="remove(favourite)"> <tooltip placement="left">usuń</tooltip> - <fa :icon="['fal', 'trash-alt']"></fa> + <ui-icon icon="delete"/> </button> </li> </ul> <div class="alert alert-info" v-else> - <fa :icon="['fal', 'info-circle']"></fa> + <ui-icon icon="info"/> Brak zapisanych zespołów przystanków </div> </div> diff --git a/resources/components/favourites/save.html b/resources/components/favourites/save.html index f65d937..3f223e3 100644 --- a/resources/components/favourites/save.html +++ b/resources/components/favourites/save.html @@ -6,7 +6,7 @@ :class="{ 'is-invalid': errors.name.length > 0 }" id="favourite_add_name" v-model="name" v-autofocus/> <button class="btn btn-sm btn-dark" type="submit"> - <fa :icon="['fal', 'check']"></fa> + <ui-icon class="add" /> </button> <div v-if="errors.name.length > 0" class="invalid-feedback"> <p v-for="error in errors.name">{{ error }}</p> diff --git a/resources/components/finder.html b/resources/components/finder.html index 6a7d452..7f34e33 100644 --- a/resources/components/finder.html +++ b/resources/components/finder.html @@ -6,7 +6,7 @@ </div> <div v-if="state === 'fetching'" class="text-center p-4"> - <fa icon="spinner-third" pulse/> + <ui-icon icon="spinner"/> </div> <div class="finder__stops" v-else-if="filter.length > 2 && Object.keys(filtered).length > 0"> <div class="stop-group" v-for="(group, name) in filtered"> @@ -16,7 +16,7 @@ <div class="actions flex-space-left"> <button class="btn btn-action" @click="select(group)"> <tooltip>wybierz wszystkie</tooltip> - <fa :icon="['fal', 'check-double']"></fa> + <ui-icon icon="add-all"/> </button> </div> </div> @@ -26,7 +26,7 @@ <template v-slot:primary-action> <button @click="select(stop, $event)" class="btn btn-action"> <tooltip>dodaj przystanek</tooltip> - <fa :icon="['fal', 'check']" /> + <ui-icon icon="add" /> </button> </template> </picker-stop> @@ -35,7 +35,7 @@ </div> </div> <div class="alert alert-warning" v-else-if="filter.length > 2"> - <fa :icon="['far', 'exclamation-triangle']"></fa> + <ui-icon icon="warning"/> Nie znaleziono więcej przystanków, spełniających te kryteria. </div> </div> diff --git a/resources/components/line.html b/resources/components/line.html index 91f1ef2..517545c 100644 --- a/resources/components/line.html +++ b/resources/components/line.html @@ -2,14 +2,14 @@ <span class="flex align-items-stretch"> <slot name="icon" v-if="!simple"> <span class="icon"> - <fa :icon="['fac', line.type]" fixed-width/> + <ui-icon :icon="`line-${line.type}`" fixed-width/> </span> </slot> <slot name="badge"> <span class="badge badge-dark flex"> - <fa :icon="['fal', 'moon']" fixed-width v-if="line.night && !simple"/> + <ui-icon icon="night" fixed-width v-if="line.night && !simple"/> {{ line.symbol }} - <fa :icon="['fas', 'walking']" v-if="line.fast"/> + <ui-icon icon="fast" v-if="line.fast"/> </span> </slot> </span> diff --git a/resources/components/messages.html b/resources/components/messages.html index e1af51a..d6cda3b 100644 --- a/resources/components/messages.html +++ b/resources/components/messages.html @@ -1,6 +1,6 @@ <ul class="messages list-unstyled"> <li class="message alert" :class="`alert-${type(message)}`" v-for="message in messages"> - <fa :icon="icon(message)" fixed-width></fa> + <ui-icon :icon="`message-${type(message)}`" fixed-width /> {{ message.message }} <div class="message__info"> @@ -12,4 +12,4 @@ </small> </div> </li> -</ul> \ No newline at end of file +</ul> diff --git a/resources/components/picker/stop.html b/resources/components/picker/stop.html index 1fa2830..1f42643 100644 --- a/resources/components/picker/stop.html +++ b/resources/components/picker/stop.html @@ -21,11 +21,11 @@ <slot name="actions"> <button class="btn btn-action" ref="action-info" @click="details = !details"> <tooltip>dodatkowe informacje</tooltip> - <fa :icon="['fal', details ? 'chevron-circle-up' : 'info-circle']"/> + <ui-icon :icon="details ? 'info-hide' : 'info'"/> </button> <button class="btn btn-action" ref="action-map" v-hover:map> - <fa :icon="['fal', 'map-marker-alt']"/> + <ui-icon icon="map"/> </button> </slot> </div> diff --git a/resources/components/stop/details.html b/resources/components/stop/details.html index e25f061..e8d0927 100644 --- a/resources/components/stop/details.html +++ b/resources/components/stop/details.html @@ -32,5 +32,5 @@ </section> </div> <div v-else class="text-center"> - <fa icon="spinner-third" pulse></fa> -</div> \ No newline at end of file + <ui-icon icon="spinner"/> +</div> diff --git a/resources/components/ui/icon.html b/resources/components/ui/icon.html new file mode 100644 index 0000000..4fd3d67 --- /dev/null +++ b/resources/components/ui/icon.html @@ -0,0 +1,4 @@ +<fa v-bind="definition" v-if="type === 'simple'"/> +<fa-layers v-else-if="type === 'stacked'"> + <fa :icon="props.icon" v-bind="props" v-for="(props, index) in definition.icons" :key="index"/> +</fa-layers> diff --git a/resources/ts/app.ts b/resources/ts/app.ts index 24d2987..c5cbef0 100644 --- a/resources/ts/app.ts +++ b/resources/ts/app.ts @@ -6,10 +6,6 @@ import "leaflet/dist/leaflet.css"; import Popper from 'popper.js'; import * as $ from "jquery"; - -window['$'] = window['jQuery'] = $; -window['Popper'] = Popper; - // dependencies import Vue from "vue"; import Vuex from 'vuex'; @@ -21,6 +17,9 @@ import { Workbox } from "workbox-window"; import { migrate } from "./store/migrations"; import { Component } from "vue-property-decorator"; +window['$'] = window['jQuery'] = $; +window['Popper'] = Popper; + Vue.use(Vuex); Vue.use(PortalVue); Vue.use(VueDragscroll); @@ -43,7 +42,6 @@ Component.registerHooks(['removed']); const [ components, { default: store } ] = await Promise.all([ import('./components'), import('./store'), - import('./font-awesome'), import('./filters'), import('bootstrap'), ] as const); diff --git a/resources/ts/components/messages.ts b/resources/ts/components/messages.ts index e3b2d89..50b8140 100644 --- a/resources/ts/components/messages.ts +++ b/resources/ts/components/messages.ts @@ -1,7 +1,6 @@ import Vue from 'vue'; import { Component } from "vue-property-decorator"; import { Message } from "../model/message"; -import { faInfoCircle, faExclamationTriangle, faQuestionCircle } from "@fortawesome/pro-light-svg-icons"; import { namespace } from 'vuex-class'; import store from '../store' @@ -13,9 +12,6 @@ export class MessagesComponent extends Vue { public icon(message: Message) { switch (message.type) { - case "breakdown": return faExclamationTriangle; - case "info": return faInfoCircle; - case "unknown": return faQuestionCircle; } } @@ -28,4 +24,4 @@ export class MessagesComponent extends Vue { } } -Vue.component('Messages', MessagesComponent); \ No newline at end of file +Vue.component('Messages', MessagesComponent); diff --git a/resources/ts/components/ui/icon.ts b/resources/ts/components/ui/icon.ts new file mode 100644 index 0000000..0fe37c1 --- /dev/null +++ b/resources/ts/components/ui/icon.ts @@ -0,0 +1,127 @@ +import Vue from 'vue' +import { Component, Prop } from 'vue-property-decorator' +import { IconDefinition, library } from "@fortawesome/fontawesome-svg-core" +import { Dictionary } from "../../utils"; +import { + faBullhorn, + faCheck, + faCheckDouble, + faChevronCircleUp, + faChevronDown, + faChevronUp, + faClock, + faCog, + faExclamationTriangle, + faInfoCircle, + faMapMarkerAlt, + faMoon, + faQuestionCircle, + faSearch, + faSign, + faStar, + faSync, + faTimes, + faTrashAlt +} from "@fortawesome/pro-light-svg-icons"; +import { faClock as faClockBold, faCodeCommit, faSpinnerThird } from "@fortawesome/pro-regular-svg-icons"; +import { faExclamationTriangle as faSolidExclamationTriangle, faWalking } from "@fortawesome/pro-solid-svg-icons"; +import { fac } from "../../icons"; +import { FontAwesomeIcon, FontAwesomeLayers, FontAwesomeLayersText } from "@fortawesome/vue-fontawesome"; + +type IconDescription = { icon: IconDefinition, [prop: string]: any } + +type SimpleIcon = { + type: 'simple', +} & IconDescription; + +type StackedIcon = { + type: 'stacked', + icons: IconDescription[], +} + +export type Icon = SimpleIcon | StackedIcon; + +const simple = (icon: IconDefinition, props: any = {}): SimpleIcon => ({ + icon, ...props, type: "simple" +}); + +const stack = (icons: IconDescription[]): StackedIcon => ({type: "stacked", icons}); + +const lineTypeIcons = Object + .values(fac) + .map<[string, Icon]>(icon => [ `line-${icon.iconName}`, simple(icon) ]) + .reduce((acc, [icon, definition]) => ({ ...acc, [icon]: definition}), {}) + +const messageTypeIcons: Dictionary<Icon> = { + 'message-breakdown': simple(faExclamationTriangle), + 'message-info': simple(faInfoCircle), + 'message-unknown': simple(faQuestionCircle), +}; + +const definitions: Dictionary<Icon> = { + 'favourite': simple(faStar), + 'add': simple(faCheck), + 'add-all': simple(faCheckDouble), + 'remove-stop': simple(faTimes), + 'delete': simple(faTrashAlt), + 'messages': simple(faBullhorn), + 'timetable': simple(faClock), + 'settings': simple(faCog), + 'refresh': simple(faSync), + 'chevron-down': simple(faChevronDown), + 'chevron-up': simple(faChevronUp), + 'search': simple(faSearch), + 'info': simple(faInfoCircle), + 'warning': simple(faExclamationTriangle), + 'night': simple(faMoon), + 'fast': simple(faWalking), + 'track': simple(faCodeCommit), + 'info-hide': simple(faChevronCircleUp), + 'map': simple(faMapMarkerAlt), + 'stop': simple(faSign), + 'spinner': simple(faSpinnerThird, { spin: true }), + 'departure-warning': stack([ + {icon: faClockBold}, + {icon: faSolidExclamationTriangle, transform: "shrink-5 down-4 right-6"} + ]), + ...lineTypeIcons, + ...messageTypeIcons, +}; + +const extractAllIcons = (icons: Icon[]) => icons.map(icon => { + switch (icon.type) { + case "simple": + return [icon.icon]; + case "stacked": + return icon.icons.map(stacked => stacked.icon); + } +}).reduce((acc, cur) => [...acc, ...cur]); + +library.add(...extractAllIcons(Object.values(definitions))); + +@Component({ + template: require('../../../components/ui/icon.html'), + components: { + fa: FontAwesomeIcon, + faLayers: FontAwesomeLayers, + faText: FontAwesomeLayersText, + } +}) +export class UiIcon extends Vue { + @Prop({ + type: [ String, Object ], + validator: value => typeof value === "object" || Object.keys(definitions).includes(value), + required: true, + }) + icon: keyof typeof definitions; + + get definition() { + return {...(typeof this.icon === "string" ? definitions[this.icon] : { icon: this.icon }), ...this.$attrs}; + } + + get type() { + return definitions[this.icon].type; + } +} + +Vue.component('UiIcon', UiIcon); diff --git a/resources/ts/components/ui/index.ts b/resources/ts/components/ui/index.ts index 4dd2256..9647ef5 100644 --- a/resources/ts/components/ui/index.ts +++ b/resources/ts/components/ui/index.ts @@ -1 +1,2 @@ export * from './switch'; +export * from './icon'; diff --git a/resources/ts/components/ui/switch.ts b/resources/ts/components/ui/switch.ts index 46756a3..d8a6dce 100644 --- a/resources/ts/components/ui/switch.ts +++ b/resources/ts/components/ui/switch.ts @@ -3,7 +3,7 @@ import { Component, Prop } from 'vue-property-decorator' import * as uuid from "uuid"; @Component({ - template: require('@templates/ui/switch.html'), + template: require('../../../components/ui/switch.html'), inheritAttrs: false }) export class UiSwitch extends Vue { diff --git a/resources/ts/font-awesome.ts b/resources/ts/font-awesome.ts deleted file mode 100644 index 184cfd6..0000000 --- a/resources/ts/font-awesome.ts +++ /dev/null @@ -1,16 +0,0 @@ -import Vue from 'vue' - -import { library } from '@fortawesome/fontawesome-svg-core' - -import { far } from "@fortawesome/pro-regular-svg-icons"; -import { fas } from "@fortawesome/pro-solid-svg-icons"; -import { fal } from "@fortawesome/pro-light-svg-icons"; -import { fac } from "./icons"; - -import { FontAwesomeIcon, FontAwesomeLayers, FontAwesomeLayersText } from '@fortawesome/vue-fontawesome' - -library.add(far, fas, fal, fac); - -Vue.component('fa', FontAwesomeIcon); -Vue.component('fa-layers', FontAwesomeLayers); -Vue.component('fa-text', FontAwesomeLayersText); diff --git a/templates/app.html.twig b/templates/app.html.twig index 327f004..fb49b83 100644 --- a/templates/app.html.twig +++ b/templates/app.html.twig @@ -8,30 +8,30 @@ <section class="section messages" v-show="messages.count > 0"> <header class="section__title flex"> <h2> - <fa :icon="['fal', 'bullhorn']" fixed-width class="mr-2"></fa> + <ui-icon icon="messages" fixed-width class="mr-2"></ui-icon> Komunikaty <span class="ml-2 badge badge-pill badge-dark">{{ '{{ messages.count }}' }}</span> </h2> <button class="btn btn-action flex-space-left" ref="settings-messages" @click="visibility.messages = !visibility.messages"> <tooltip>ustawienia</tooltip> - <fa :icon="['fal', 'cog']" fixed-width></fa> + <ui-icon icon="settings" fixed-width></ui-icon> </button> <button class="btn btn-action" @click="updateMessages" ref="btn-messages-refresh"> <tooltip>odśwież</tooltip> - <fa :icon="['fal', 'sync']" :spin="messages.state === 'fetching'" fixed-width></fa> + <ui-icon icon="refresh" :spin="messages.state === 'fetching'" fixed-width></ui-icon> </button> <button class="btn btn-action" @click="sections.messages = !sections.messages"> <tooltip> {{ '{{ ' }} sections.messages ? 'zwiń' : 'rozwiń' {{ '}}' }} <span class="sr-only">sekcję komunikatów</span> </tooltip> - <fa :icon="['fal', sections.messages ? 'chevron-up' : 'chevron-down']" fixed-width/> + <ui-icon :icon="sections.messages ? 'chevron-up' : 'chevron-down'" fixed-width></ui-icon> </button> <portal to="popups"> <popper reference="settings-messages" v-if="visibility.messages" arrow placement="left-start" @leave="visibility.messages = false"> <h3 class="popper__heading flex"> <label class="text" for="messages-auto-refresh"> - <fa :icon="['far', 'sync']" fixed-width></fa> + <ui-icon icon="refresh" fixed-width></ui-icon> autoodświeżanie </label> <ui-switch id="messages-auto-refresh" v-model="autorefresh.messages.active" class="flex-space-left"></ui-switch> @@ -59,23 +59,23 @@ <section class="section"> <header class="section__title flex"> <h2> - <fa :icon="['fal', 'clock']" fixed-width></fa> + <ui-icon icon="timetable" fixed-width></ui-icon> <span class="text">Odjazdy</span> </h2> <button class="btn btn-action flex-space-left" ref="settings-departures" @click="visibility.departures = !visibility.departures"> <tooltip>ustawienia</tooltip> - <fa :icon="['fal', 'cog']" fixed-width></fa> + <ui-icon icon="settings" fixed-width></ui-icon> </button> <button class="btn btn-action" @click="updateDepartures({ stops })"> <tooltip>odśwież</tooltip> - <fa :icon="['fal', 'sync']" :spin="departures.state === 'fetching'" fixed-width></fa> + <ui-icon icon="refresh" :spin="departures.state === 'fetching'" fixed-width></ui-icon> </button> <portal to="popups"> <popper reference="settings-departures" v-if="visibility.departures" arrow placement="left-start" @leave="visibility.departures = false"> <h3 class="popper__heading flex"> <label class="text" for="departures-auto-refresh"> - <fa :icon="['far', 'sync']" fixed-width></fa> + <ui-icon icon="refresh" fixed-width></ui-icon> autoodświeżanie </label> <ui-switch id="departures-auto-refresh" v-model="autorefresh.departures.active" class="flex-space-left"></ui-switch> @@ -98,7 +98,7 @@ <departures :stops="stops"></departures> {% if provider.attribution %} <div class="attribution"> - <fa :icon="['fal', 'info-circle']"></fa> + <ui-icon icon="info"></ui-icon> Pochodzenie danych: {{ provider.attribution|raw }} </div> {% endif %} @@ -108,12 +108,12 @@ <section class="section picker" v-if="stops.length > 0"> <header class="section__title flex"> <h2> - <fa :icon="['fal', 'sign']" fixed-width></fa> + <ui-icon icon="stop" fixed-width></ui-icon> <span class="text">Przystanki</span> </h2> <button class="btn btn-action flex-space-left" @click="clear"> <tooltip>usuń wszystkie</tooltip> - <fa :icon="['fal', 'trash-alt']" fixed-width></fa> + <ui-icon icon="delete" fixed-width></ui-icon> </button> </header> @@ -123,7 +123,7 @@ <template v-slot:primary-action> <button @click="remove(stop)" class="btn btn-action"> <tooltip>usuń przystanek</tooltip> - <fa :icon="['fal', 'times']"></fa> + <ui-icon icon="remove-stop"></ui-icon> </button> </template> </picker-stop> @@ -132,7 +132,7 @@ <div class="d-flex mt-2"> <button class="btn btn-action btn-sm flex-space-left" @click="visibility.save = true" ref="save"> - <fa :icon="['fal', 'star']" fixed-width></fa> + <ui-icon icon="favourite" fixed-width></ui-icon> zapisz jako... </button> </div> @@ -145,22 +145,22 @@ <header class="section__title flex"> <template v-if="visibility.picker === 'search'"> <h2 class="flex-grow-1"> - <fa :icon="['fal', 'search']" fixed-width class="mr-1"></fa> + <ui-icon icon="search" fixed-width class="mr-1"></ui-icon> Wybierz przystanki </h2> <button class="btn btn-action" @click="visibility.picker = 'favourites'"> <tooltip>Zapisane</tooltip> - <fa :icon="['fal', 'star']" fixed-witdth></fa> + <ui-icon icon="favourite" fixed-witdth></ui-icon> </button> </template> <template v-else> <h2 class="flex-grow-1"> - <fa :icon="['fal', 'star']" fixed-width class="mr-1"></fa> + <ui-icon icon="favourite" fixed-width class="mr-1"></ui-icon> Zapisane </h2> <button class="btn btn-action" @click="visibility.picker = 'search'"> <tooltip>Wybierz przystanki</tooltip> - <fa :icon="['fal', 'search']" fixed-witdth></fa> + <ui-icon icon="search" fixed-witdth></ui-icon> </button> </template> </header> diff --git a/templates/choose.html.twig b/templates/choose.html.twig index 8d4a044..397e154 100644 --- a/templates/choose.html.twig +++ b/templates/choose.html.twig @@ -2,7 +2,7 @@ {% block body %} <div class="alert alert-primary"> - <fa :icon="['fal', 'info-circle']"></fa> + <ui-icon icon="info-circle"></ui-icon> Wybierz źródło danych </div> <ul class="list-underlined"> @@ -14,4 +14,4 @@ </li> {% endfor %} </ul> -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/webpack.config.js b/webpack.config.js index 2b357ce..367d75b 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -20,8 +20,7 @@ const config = { extensions: ['.tsx', '.ts', '.js'], alias: { 'vue$': 'vue/dist/vue.esm.js', - 'mapbox-gl$': 'mapbox-gl/dist/mapbox-gl-unminified', - '@templates': path.resolve(__dirname, './resources/components/'), + 'mapbox-gl$': 'mapbox-gl/dist/mapbox-gl-unminified' } }, module: { -- 2.45.2 From 749fd773b6559560e2f4c171fdf608f0b37f9a23 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Mon, 10 Feb 2020 22:38:49 +0100 Subject: [PATCH 08/77] #12 - rebrand to 'Co Jedzie' as 'Czy Dojade' is taken --- composer.json | 2 +- config/packages/nelmio_api_doc.yaml | 2 +- package.json | 2 +- public/manifest.json | 6 +- resources/images/logo-branded-hi.png | Bin 26656 -> 0 bytes resources/images/logo-branded.png | Bin 12512 -> 0 bytes resources/images/logo-cojedzie.ai | 1313 ++++++++++++++++++++++++++ resources/images/logo-hi.png | Bin 24726 -> 0 bytes resources/images/logo-superhi.png | Bin 0 -> 109847 bytes resources/images/logo-vector.svg | 1 + resources/images/logo.png | Bin 11596 -> 44483 bytes resources/ts/app.ts | 6 +- ruleset.xml | 4 +- templates/app.html.twig | 4 +- templates/base.html.twig | 6 +- templates/manifest.json.twig | 4 +- 16 files changed, 1332 insertions(+), 18 deletions(-) delete mode 100644 resources/images/logo-branded-hi.png delete mode 100644 resources/images/logo-branded.png create mode 100755 resources/images/logo-cojedzie.ai delete mode 100644 resources/images/logo-hi.png create mode 100755 resources/images/logo-superhi.png create mode 100755 resources/images/logo-vector.svg mode change 100644 => 100755 resources/images/logo.png diff --git a/composer.json b/composer.json index af906e6..87d236f 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "kadet/czydojade", + "name": "kadet/cojedzie", "type": "project", "license": "MIT", "require": { diff --git a/config/packages/nelmio_api_doc.yaml b/config/packages/nelmio_api_doc.yaml index 6235eb6..c449eee 100644 --- a/config/packages/nelmio_api_doc.yaml +++ b/config/packages/nelmio_api_doc.yaml @@ -1,7 +1,7 @@ nelmio_api_doc: documentation: info: - title: Czy Dojadę? + title: Co Jedzie? version: 0.1.0 parameters: provider: diff --git a/package.json b/package.json index 65e7b89..4b43114 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "czydojade", + "name": "co-jedzie", "version": "1.0.0", "author": "Kacper Donat <kadet1090@gmail.com>", "license": "MIT", diff --git a/public/manifest.json b/public/manifest.json index b932719..00ff1f9 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,6 +1,6 @@ { - "name": "Czy Dojadę?", - "short_name": "Czy Dojadę?", + "name": "Co Jedzie?", + "short_name": "Co Jedzie?", "orientation": "portrait", "lang": "pl_PL", "start_url": ".", @@ -27,4 +27,4 @@ "src": "images/icon-96.png", "sizes": "96x96" }] -} \ No newline at end of file +} diff --git a/resources/images/logo-branded-hi.png b/resources/images/logo-branded-hi.png deleted file mode 100644 index 7a7f074385a8f69ad20360d3b8dd9cae3cb679be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26656 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 diff --git a/resources/images/logo-branded.png b/resources/images/logo-branded.png deleted file mode 100644 index dba7f9f34af1700fcc230b346234e95758a94c19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12512 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 diff --git a/resources/images/logo-cojedzie.ai b/resources/images/logo-cojedzie.ai new file mode 100755 index 0000000..2ae4583 --- /dev/null +++ b/resources/images/logo-cojedzie.ai @@ -0,0 +1,1313 @@ +%PDF-1.5 %���� +1 0 obj <</Metadata 2 0 R/OCProperties<</D<</ON[5 0 R 24 0 R 42 0 R]/Order 43 0 R/RBGroups[]>>/OCGs[5 0 R 24 0 R 42 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <</Length 41746/Subtype/XML/Type/Metadata>>stream +<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> +<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c143 79.161356, 2017/09/07-01:11:22 "> + <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> + <rdf:Description rdf:about="" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:xmp="http://ns.adobe.com/xap/1.0/" + xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/" + xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" + xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#" + xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#" + xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/" + xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/" + xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#" + xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/" + xmlns:pdf="http://ns.adobe.com/pdf/1.3/"> + <dc:format>application/pdf</dc:format> + <dc:title> + <rdf:Alt> + <rdf:li xml:lang="x-default">Mobile</rdf:li> + </rdf:Alt> + </dc:title> + <xmp:CreatorTool>Adobe Illustrator CC 22.1 (Windows)</xmp:CreatorTool> + <xmp:CreateDate>2020-02-10T19:02+01:00</xmp:CreateDate> + <xmp:ModifyDate>2020-02-10T20:45:43+01:00</xmp:ModifyDate> + <xmp:MetadataDate>2020-02-10T20:45:43+01:00</xmp:MetadataDate> + <xmp:Thumbnails> + <rdf:Alt> + <rdf:li rdf:parseType="Resource"> + <xmpGImg:width>256</xmpGImg:width> + <xmpGImg:height>120</xmpGImg:height> + <xmpGImg:format>JPEG</xmpGImg:format> + <xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA
AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK
DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f
Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAeAEAAwER
AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA
AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB
UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE
1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ
qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy
obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp
0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo
+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7
FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F
XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX
Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY
q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq
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</xmpGImg:image> + </rdf:li> + </rdf:Alt> + </xmp:Thumbnails> + <xmpMM:OriginalDocumentID>uuid:C1BCCE1871B8DB11993190FCD52B4E9F</xmpMM:OriginalDocumentID> + <xmpMM:DocumentID>xmp.did:d81b3b0d-0e8f-c849-b804-e1e269280e9e</xmpMM:DocumentID> + <xmpMM:InstanceID>uuid:7aa877f2-4af2-431b-9320-eb2b2a4d2bac</xmpMM:InstanceID> + <xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass> + <xmpMM:DerivedFrom rdf:parseType="Resource"> + <stRef:instanceID>uuid:a752ce14-e6d8-4298-87fb-c8da083631b3</stRef:instanceID> + <stRef:documentID>xmp.did:0c3af16f-48bb-7a4d-9f1e-e4defd3f9a11</stRef:documentID> + <stRef:originalDocumentID>uuid:C1BCCE1871B8DB11993190FCD52B4E9F</stRef:originalDocumentID> + <stRef:renditionClass>proof:pdf</stRef:renditionClass> + </xmpMM:DerivedFrom> + <xmpMM:History> + <rdf:Seq> + <rdf:li rdf:parseType="Resource"> + <stEvt:action>saved</stEvt:action> + <stEvt:instanceID>xmp.iid:f9e2fba2-6d27-bc4d-9723-a29fada23bc8</stEvt:instanceID> + <stEvt:when>2018-09-22T13:42:09+02:00</stEvt:when> + <stEvt:softwareAgent>Adobe Illustrator CC 22.1 (Windows)</stEvt:softwareAgent> + <stEvt:changed>/</stEvt:changed> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <stEvt:action>saved</stEvt:action> + <stEvt:instanceID>xmp.iid:d81b3b0d-0e8f-c849-b804-e1e269280e9e</stEvt:instanceID> + <stEvt:when>2020-02-10T19:02+01:00</stEvt:when> + <stEvt:softwareAgent>Adobe Illustrator CC 22.1 (Windows)</stEvt:softwareAgent> + <stEvt:changed>/</stEvt:changed> + </rdf:li> + </rdf:Seq> + </xmpMM:History> + <illustrator:Type>Document</illustrator:Type> + <illustrator:StartupProfile>Mobile</illustrator:StartupProfile> + <xmpTPg:NPages>1</xmpTPg:NPages> + <xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency> + <xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint> + <xmpTPg:MaxPageSize rdf:parseType="Resource"> + <stDim:w>1808.740000</stDim:w> + <stDim:h>576.000000</stDim:h> + <stDim:unit>Pixels</stDim:unit> + </xmpTPg:MaxPageSize> + <xmpTPg:PlateNames> + <rdf:Seq> + <rdf:li>Cyan</rdf:li> + <rdf:li>Magenta</rdf:li> + <rdf:li>Yellow</rdf:li> + <rdf:li>Black</rdf:li> + </rdf:Seq> + </xmpTPg:PlateNames> + <xmpTPg:SwatchGroups> + <rdf:Seq> + <rdf:li rdf:parseType="Resource"> + <xmpG:groupName>Default Swatch Group</xmpG:groupName> + <xmpG:groupType>0</xmpG:groupType> + <xmpG:Colorants> + <rdf:Seq> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>White</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>255</xmpG:red> + <xmpG:green>255</xmpG:green> + <xmpG:blue>255</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>Black</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>0</xmpG:red> + <xmpG:green>0</xmpG:green> + <xmpG:blue>0</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>RGB Red</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>255</xmpG:red> + <xmpG:green>0</xmpG:green> + <xmpG:blue>0</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>RGB Yellow</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>255</xmpG:red> + <xmpG:green>255</xmpG:green> + <xmpG:blue>0</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>RGB Green</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>0</xmpG:red> + <xmpG:green>255</xmpG:green> + <xmpG:blue>0</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>RGB Cyan</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>0</xmpG:red> + <xmpG:green>255</xmpG:green> + <xmpG:blue>255</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>RGB Blue</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>0</xmpG:red> + <xmpG:green>0</xmpG:green> + <xmpG:blue>255</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>RGB Magenta</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>255</xmpG:red> + <xmpG:green>0</xmpG:green> + <xmpG:blue>255</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=193 G=39 B=45</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>193</xmpG:red> + <xmpG:green>39</xmpG:green> + <xmpG:blue>45</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=237 G=28 B=36</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>237</xmpG:red> + <xmpG:green>28</xmpG:green> + <xmpG:blue>36</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=241 G=90 B=36</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>241</xmpG:red> + <xmpG:green>90</xmpG:green> + <xmpG:blue>36</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=247 G=147 B=30</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>247</xmpG:red> + <xmpG:green>147</xmpG:green> + <xmpG:blue>30</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=251 G=176 B=59</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>251</xmpG:red> + <xmpG:green>176</xmpG:green> + <xmpG:blue>59</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=252 G=238 B=33</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>252</xmpG:red> + <xmpG:green>238</xmpG:green> + <xmpG:blue>33</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=217 G=224 B=33</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>217</xmpG:red> + <xmpG:green>224</xmpG:green> + <xmpG:blue>33</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=140 G=198 B=63</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>140</xmpG:red> + <xmpG:green>198</xmpG:green> + <xmpG:blue>63</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=57 G=181 B=74</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>57</xmpG:red> + <xmpG:green>181</xmpG:green> + <xmpG:blue>74</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=0 G=146 B=69</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>0</xmpG:red> + <xmpG:green>146</xmpG:green> + <xmpG:blue>69</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=0 G=104 B=55</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>0</xmpG:red> + <xmpG:green>104</xmpG:green> + <xmpG:blue>55</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=34 G=181 B=115</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>34</xmpG:red> + <xmpG:green>181</xmpG:green> + <xmpG:blue>115</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=0 G=169 B=157</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>0</xmpG:red> + <xmpG:green>169</xmpG:green> + <xmpG:blue>157</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=41 G=171 B=226</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>41</xmpG:red> + <xmpG:green>171</xmpG:green> + <xmpG:blue>226</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=0 G=113 B=188</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>0</xmpG:red> + <xmpG:green>113</xmpG:green> + <xmpG:blue>188</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=46 G=49 B=146</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>46</xmpG:red> + <xmpG:green>49</xmpG:green> + <xmpG:blue>146</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=27 G=20 B=100</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>27</xmpG:red> + <xmpG:green>20</xmpG:green> + <xmpG:blue>100</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=102 G=45 B=145</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>102</xmpG:red> + <xmpG:green>45</xmpG:green> + <xmpG:blue>145</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=147 G=39 B=143</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>147</xmpG:red> + <xmpG:green>39</xmpG:green> + <xmpG:blue>143</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=158 G=0 B=93</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>158</xmpG:red> + <xmpG:green>0</xmpG:green> + <xmpG:blue>93</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=212 G=20 B=90</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>212</xmpG:red> + <xmpG:green>20</xmpG:green> + <xmpG:blue>90</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=237 G=30 B=121</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>237</xmpG:red> + <xmpG:green>30</xmpG:green> + <xmpG:blue>121</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=199 G=178 B=153</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>199</xmpG:red> + <xmpG:green>178</xmpG:green> + <xmpG:blue>153</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=153 G=134 B=117</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>153</xmpG:red> + <xmpG:green>134</xmpG:green> + <xmpG:blue>117</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=115 G=99 B=87</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>115</xmpG:red> + <xmpG:green>99</xmpG:green> + <xmpG:blue>87</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=83 G=71 B=65</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>83</xmpG:red> + <xmpG:green>71</xmpG:green> + <xmpG:blue>65</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=198 G=156 B=109</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>198</xmpG:red> + <xmpG:green>156</xmpG:green> + <xmpG:blue>109</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=166 G=124 B=82</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>166</xmpG:red> + <xmpG:green>124</xmpG:green> + <xmpG:blue>82</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=140 G=98 B=57</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>140</xmpG:red> + <xmpG:green>98</xmpG:green> + <xmpG:blue>57</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=117 G=76 B=36</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>117</xmpG:red> + <xmpG:green>76</xmpG:green> + <xmpG:blue>36</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=96 G=56 B=19</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>96</xmpG:red> + <xmpG:green>56</xmpG:green> + <xmpG:blue>19</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=66 G=33 B=11</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>66</xmpG:red> + <xmpG:green>33</xmpG:green> + <xmpG:blue>11</xmpG:blue> + </rdf:li> + </rdf:Seq> + </xmpG:Colorants> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:groupName>Grays</xmpG:groupName> + <xmpG:groupType>1</xmpG:groupType> + <xmpG:Colorants> + <rdf:Seq> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=0 G=0 B=0</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>0</xmpG:red> + <xmpG:green>0</xmpG:green> + <xmpG:blue>0</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=26 G=26 B=26</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>26</xmpG:red> + <xmpG:green>26</xmpG:green> + <xmpG:blue>26</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=51 G=51 B=51</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>51</xmpG:red> + <xmpG:green>51</xmpG:green> + <xmpG:blue>51</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=77 G=77 B=77</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>77</xmpG:red> + <xmpG:green>77</xmpG:green> + <xmpG:blue>77</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=102 G=102 B=102</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>102</xmpG:red> + <xmpG:green>102</xmpG:green> + <xmpG:blue>102</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=128 G=128 B=128</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>128</xmpG:red> + <xmpG:green>128</xmpG:green> + <xmpG:blue>128</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=153 G=153 B=153</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>153</xmpG:red> + <xmpG:green>153</xmpG:green> + <xmpG:blue>153</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=179 G=179 B=179</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>179</xmpG:red> + <xmpG:green>179</xmpG:green> + <xmpG:blue>179</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=204 G=204 B=204</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>204</xmpG:red> + <xmpG:green>204</xmpG:green> + <xmpG:blue>204</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=230 G=230 B=230</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>230</xmpG:red> + <xmpG:green>230</xmpG:green> + <xmpG:blue>230</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=242 G=242 B=242</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>242</xmpG:red> + <xmpG:green>242</xmpG:green> + <xmpG:blue>242</xmpG:blue> + </rdf:li> + </rdf:Seq> + </xmpG:Colorants> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:groupName>Mobile Color Group</xmpG:groupName> + <xmpG:groupType>1</xmpG:groupType> + <xmpG:Colorants> + <rdf:Seq> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=136 G=168 B=13</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>136</xmpG:red> + <xmpG:green>168</xmpG:green> + <xmpG:blue>13</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=127 G=71 B=221</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>127</xmpG:red> + <xmpG:green>71</xmpG:green> + <xmpG:blue>221</xmpG:blue> + </rdf:li> + <rdf:li rdf:parseType="Resource"> + <xmpG:swatchName>R=251 G=174 B=23</xmpG:swatchName> + <xmpG:mode>RGB</xmpG:mode> + <xmpG:type>PROCESS</xmpG:type> + <xmpG:red>251</xmpG:red> + <xmpG:green>174</xmpG:green> + <xmpG:blue>23</xmpG:blue> + </rdf:li> + </rdf:Seq> + </xmpG:Colorants> + </rdf:li> + </rdf:Seq> + </xmpTPg:SwatchGroups> + <pdf:Producer>Adobe PDF library 15.00</pdf:Producer> + </rdf:Description> + </rdf:RDF> +</x:xmpmeta> + + + + + + + + + + + + + + + + + + + + + +<?xpacket end="w"?> +endstream endobj 3 0 obj <</Count 1/Kids[7 0 R]/Type/Pages>> endobj 7 0 obj <</ArtBox[56.9269 32.0 1751.81 544.0]/BleedBox[0.0 0.0 1808.74 576.0]/Contents 44 0 R/CropBox[0.0 0.0 1808.74 576.0]/LastModified(D:20200210204543+02'00')/MediaBox[0.0 0.0 1808.74 576.0]/Parent 3 0 R/PieceInfo<</Illustrator 45 0 R>>/Resources<</ColorSpace<</CS0 46 0 R>>/ExtGState<</GS0 47 0 R>>/Properties<</MC0 42 0 R>>>>/Thumb 48 0 R/TrimBox[0.0 0.0 1808.74 576.0]/Type/Page>> endobj 44 0 obj <</Filter/FlateDecode/Length 4312>>stream +H�|�I�]� E�wgWV]t��iA�F�a�����M����]�H�Ym~����˟����z�~{ţ�~�g�xK��?^?�����o���qD�w��`�O,����#�b:RK�s�ԐrL�������w ����(�x��r;�9�ُw�a�y|���+�R %fl}�;���o�G_W#i;g]��!g)���`;9�X�-��t"c@҉V��n�#�&�f(�^�Lʡ�~�(=����B3 �5��V���V&4�Zl��j�h)IJ��ΎVBԝ�� TCg�pl=�5/��m��>�p���ݴ֕���p][ �m�������0���N���cBϞ��ձ�e�X�;K��y�$���3X���)�K��C����[�\߳�^)E�l�L��Lo�^Vd +Wd{���`t��!�� d4p����3z�c*�_�}.�C���G��W����^��z˹����S�K����KcJnL��6�:#5�G?/��}�o|�Uo3�^��]Gou�ת>���~�:�V��6}�o\�JŴ,���zޣ� ��aC�Y��Z���}���t��COU��\,��94)*��+�bo���Ђ +�?����@�9�Af'�^J�$w%�Vl����Z̾R�� ��[_���k�N���Z�a*;9��9BR�'���&����=��&fw�be�z�ұ�)�aװ6�Y�(,��BY�Wv�͞��:��82 ʬ��7Se�r�!W{w�XPК9S�"7J�h��nN� l��LOf +�H�:Qԭ ��ҹV^�Am�ۋ�uYX������n1p��?y��z#{u���ζ(Z�;{O��X�ҷ�x��EK(j7�)O~p�#SѬl�v�(z��~(�]'�����ۼ�h%OVV�f!�m�r�c���<�$\}����zeI���6�?��o��P�=-K��qk�x�ۺ�ń�H�'��]b��2�cy���*���m�����դ��E���,���f�m�B�M[�>�"���re_�q�S�NuJr����Gv]a-�G�m�g�x魑DETT]Y������#uºG_:i1� ���>�,}X�uo�#RsʺE!v���O���&��k�ˢ?��������O +�Ӕ��Y��p��x��߂#�C��?.�����S*�sMV�����ȿk�� ��v�G.�|"�$�u��n�^��%i��,֘խ�N-��̭f?�Ş��S+��ءXY�^E(E����W|�~ڜ'�:�ZV�i,�����RC�!}R�;��Х�ɥ��L���$�tK��j��F�^2��|��x��8��kXXS�א�ԬD�����2���G�TS�#�X"�X������a:�t�����s�>bM8f�^��}�۪�x�)��RUQ���@�ëf�F;i�!P�����S����r.���ૌ��N�>��Q"q' e�XVrGN5۾��"Zf��j�e��v��H�!���M�n[0�bWϰD~�N��٢�%"��;���QbR���a�\<����GX=5�����1�@�H@��ғ4eM�k%��I����hl]��C7����V�ۢ�r�K6[�p�_S��F� cJq��:���p�R�#Gw��d01��T[���DG52���S{��&P2�o A>�i*���~H�!�(�q����k3]�wͰ��!$�\/H�*�%<��.�����K�4����nчTQ���-Y���iVʮ8+�q�y�hN7FL�R���xiJV@�\��1Ɣ��"@��P2h3�bY���]���FF���"�9��h���qd��2s��k,�{x]��Y<G���Fq��T}]�;c�|�P)L/ +���X�6�V=\}G��R�$��$S��b�"�T ;&%]�����G>[� +��m<���ƙ}I��ڋ� 7���f۩Y,�l�ߒ�f������}���A)Z��a�c�~ip�<�p���$��*%� +�0����i���{�J���i��h�Z!)� q(4Y�o��m�T��ޤR*Ś���-+�o��a#L��i�{� ��d�^Q�3��Jc�j�)����3�";q�� �+`G �#��#�J�Bihb/K�@wP&����Z��Acy<F�,�i�,�+yh�<���B�e>f�j<���p��i&�H���Ӆ;�I�i�)jh��q\��[� +� ���.E�.7����_L�j����W%Un�mz�[�C*zҵ@��DLg��,HH&�X�ńo$�Q�@vK�.�h��%[o�>���-�J���PQ��QSV!n$�e���H�ddf��h�,Ff��$>^T���b�q"0��I_m�}�2�� ��2��Ղ� ���y������yl�ċŶ�XB�w�!�U�lBI�9U � �7�N5�L�Li'q��)͊���)�6��VŚ��J�(W�����2���b��/)b�B 22�V\�Z2��C1rQ��[�Z4&K�J���X�� +�I�v�rK���TU��A�xjѥ����N1�!5d�^�+j1�z���T2��ڱY��*q��� ��Jm�RRζ�S�p>U7�D�kßDž��b�*��ߧBL��6���+弪���r,�J�!����[T**���n�[QE���v�����P-��� ��E��؟i +�FAڼ +}���,���f����M�$5��s��@K�O{�Xr +����|]U3b@�H����tF�#���ΰq�^-_�T��*�d]:x��V��'��7e��Kp[�t=]��0�ж�s�Kc�����G��eA�KR���d5�]�mQi�8���?�M���{�L.)Ҥ�:m�-�U,6�����5�8!��^����y�gl�V���4�}������V[�[�+��rx�]��m�їK*2��{m�h��C4̰H|U��q3"���l}�dn���+�6�E��Nq�Ӗ�M�m�հnO�qv>�N��+v&�Mf���|�Q�p$Iٲ��[��C(I�$Pj��-D�2s�$�t���e��^Pe����i�S,�� N�.q�A�q��8 +�&���f�Q�`��R�����\suoPa��eY����L���_z�` �KUJ�(Я�1��Y}�����{m4�"Ցs8kmA6�/�h.�T[��PIx�^g��������`�V�c=��W�᱑ڌ����<�5p� ���GU��ˢ��5;B��&Sk�dl%"�h�IZPC���iN�����7r��|�p���jxY[����4%��_ +z��:��B��x��lV�IH� �_�����\������-+L� �@�����BHO�123կ=��{��$�(��E6�5������Rρ�P�F��'0�#��g��{�oa��o�>T�D��o*�nrT���tN�*���HB��x)�3H]�|�oo�=r���!�\��S��(%I��TD�E�V�'S�]��S鉎<���y�����4���� ��mk���5_���:�ip܉ ;��v��([����t[��^�ݑ͔�,��aY���Er�OZVj�]vT���H��9�<�_�����y�}N؊������^@���h�MkCA7,�����{�*��ݞ���Rs��� +�PDRwu{��U2nVM3/������A�U&�<��ZY �OHz_����*4�@Ǭ1�C:�[>��K ���r� �YmӜ�8f�B�reKaH����%8�w����{����C���j�����L%TW��z�T�- rҺD8��" rPCk������O�Gѯq F�p;�P��!*�{�W��5���o��o�x<��c��f�bҁ�̅(��uw�6Ԕ_ˠEaR������]n����O�1-�7|nd���6�� ^_|�s��q�7��8�`=�_c���b�+�o a�d �+���Y�o�$KuM��v)C"2���,��eu�4Ma�ULLt��y����%ipW-�c��q��z���h�#;��&�̢{\ξh�BD�����]�lB��5��n����x�J̀S�X6q��������>M8 ~\0��冏�b#H@R��\�|��%�w�[�)�H���$���Z�]��T�p����������̀>����w`��ϸ`�iŕ��b�#VP֜� �U����s{��p�E�?~�[h�-���Y��f�}�,����*��P�g��*��U(�[��Y��l�� +��B��N��_~z�����X�O +endstream endobj 48 0 obj <</BitsPerComponent 8/ColorSpace 49 0 R/Filter[/ASCII85Decode/FlateDecode]/Height 33/Length 330/Width 106>>stream +8;Yi^=VAS*$q#+9$g'Lo!%kK-ALU1Ur7*X+Sn1"1>5pV*.rKo'gk=A!@d._\/\6cq +FoNs)en\cn=BUh%>31?3d67p7nWPlo87Lf\c>$6K3rp&\b\L(?r8)Jq3=0AUfbBer +%4^j0Q,J$tm\#-&!\7X$EDj]8,8kje$L/5QE2S+^F!fD70p7Wq7PZFFPH'E/Oc<AD +@jF:R4BmJ3,W-/'grWV0@/f9KWBenjO&:.Q4i?R3D_u_He5':a.ma8ki_1TKWXHC- +,*eatGnB\+krmH7a=;@)P8sH/Fs6&++aMRP:nEO<H9EYsT5BmWnifr5*WlD9'!ts~> +endstream endobj 49 0 obj [/Indexed/DeviceRGB 255 50 0 R] endobj 50 0 obj <</Filter[/ASCII85Decode/FlateDecode]/Length 428>>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1 +VNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH< +PO7r\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> +endstream endobj 42 0 obj <</Intent 51 0 R/Name(Layer 1)/Type/OCG/Usage 52 0 R>> endobj 51 0 obj [/View/Design] endobj 52 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 22.1)/Subtype/Artwork>>>> endobj 47 0 obj <</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>> endobj 46 0 obj [/ICCBased 53 0 R] endobj 53 0 obj <</Filter/FlateDecode/Length 2574/N 3>>stream +H���yTSw�oɞ����c [���5la�QIBH�ADED���2�mtFOE�.�c��}���0��8��8G�Ng�����9�w���߽�����'����0��֠�J��b� � + �2y�.-;!���K�Z� ���^�i�"L��0���-�� �@8(��r�;q��7�L��y��&�Q��q�4�j���|�9�� +�V��)g�B�0�i�W��8#�8wթ��8_�٥ʨQ����Q�j@�&�A)/��g�>'K����t�;\�� ӥ$պF�ZUn����(4T�%)뫔�0C&�����Z��i���8��bx��E���B�;�����P���ӓ̹�A�om?�W= +�x������-������[����0����}��y)7ta�����>j���T�7���@���tܛ�`q�2��ʀ��&���6�Z�L�Ą?�_��yxg)˔z���çL�U���*�u�Sk�Se�O4?�c����.�������R� ߁��-��2�5������ ��S�>ӣV����d�`r��n~��Y�&�+`��;�A4�� ���A9��=�-�t��l�`;��~p���� �Gp| ��[`L��`<� "A�YA�+��Cb(��R�,��*�T�2B-� +�ꇆ��n���Q�t�}MA�0�al������S�x ��k�&�^���>�0|>_�'��,�G!"F$H:R��!z��F�Qd?r9�\A&�G���rQ��h������E��]�a�4z�Bg�����E#H �*B=��0H�I��p�p�0MxJ$�D1��D, V���ĭ����KĻ�Y�dE�"E��I2���E�B�G��t�4MzN�����r!YK� ���?%_&�#���(��0J:EAi��Q�(�()ӔWT6U@���P+���!�~��m���D�e�Դ�!��h�Ӧh/��']B/����ҏӿ�?a0n�hF!��X���8����܌k�c&5S�����6�l��Ia�2c�K�M�A�!�E�#��ƒ�d�V��(�k��e���l ����}�}�C�q�9 +N'��)�].�u�J�r� +��w�G� xR^���[�oƜch�g�`>b���$���*~� �:����E���b��~���,m,�-��ݖ,�Y��¬�*�6X�[ݱF�=�3�뭷Y��~dó ���t���i�z�f�6�~`{�v���.�Ng����#{�}�}��������j������c1X6���fm���;'_9 �r�:�8�q�:��˜�O:ϸ8������u��Jq���nv=���M����m����R 4 � +n�3ܣ�k�Gݯz=��[=��=�<�=G</z�^�^j��^�� ޡ�Z�Q�B�0FX'�+������t���<�u�-���{���_�_�ߘ�-G�,�}���/���Hh8�m�W�2p[����AiA��N�#8$X�?�A�KHI�{!7�<q��W�y(!46�-���a�a���a�W�� ��@�@�`l���YĎ��H,�$����(�(Y�h�7��ъ���b<b*b��<�����~�L&Y&9��%�u�M�s�s��NpJP%�M�IJlN<�DHJIڐtCj'�KwKg�C��%�N��d��|�ꙪO=��%�mL���u�v�x:H��oL��!Ȩ��C&13#s$�/Y����������=�Osbs�rn��sO�1��v�=ˏ��ϟ\�h٢���#��¼����oZ<]T�Ut}�`IÒsK��V-���Y,+>TB(�/�S�,]6*�-���W:#��7�*���e��^YDY�}U�j��AyT�`�#�D=���"�b{ų���+�ʯ:�!kJ4G�m��t�}uC�%���K7YV��fF���Y�.�=b��?S��ƕƩ�Ⱥ����y��� چ���k�5%4��m�7�lqlio�Z�lG+�Z�z���mzy��]�����?u�u�w|�"űN���wW&���e֥ﺱ*|����j��5k��yݭ���ǯg��^y�kEk�����l�D_p߶������7Dm����o꿻1m��l�{��Mś� n�L�l�<9��O��[����$�����h�՛B��������d�Ҟ@��������i�ءG���&����v��V�ǥ8��������n��R�ĩ7�������u��\�ЭD���-��������u��`�ֲK�³8���%�������y��h��Y�ѹJ�º;���.���!������ +�����z���p���g���_���X���Q���K���F���Aǿ�=ȼ�:ɹ�8ʷ�6˶�5̵�5͵�6ζ�7ϸ�9к�<Ѿ�?���D���I���N���U���\���d���l���v��ۀ�܊�ݖ�ޢ�)߯�6��D���S���c���s���� ����2��F���[���p������(��@���X���r������4���P���m��������8���W���w����)���K���m������� +endstream endobj 45 0 obj <</LastModified(D:20200210204543+02'00')/Private 54 0 R>> endobj 54 0 obj <</AIMetaData 55 0 R/AIPrivateData1 56 0 R/AIPrivateData2 57 0 R/AIPrivateData3 58 0 R/ContainerVersion 11/CreatorVersion 22/NumBlock 3/RoundtripStreamType 1/RoundtripVersion 17>> endobj 55 0 obj <</Length 1390>>stream +%!PS-Adobe-3.0 +%%Creator: Adobe Illustrator(R) 17.0 +%%AI8_CreatorVersion: 22.1.0 +%%For: (Kacper Donat) () +%%Title: (logo-cojedzie.ai) +%%CreationDate: 2/10/2020 8:45 PM +%%Canvassize: 16383 +%%BoundingBox: -2 -1262 1752 -460 +%%HiResBoundingBox: -1.11095703125011 -1262 1751.81311523438 -460.7744140625 +%%DocumentProcessColors: Cyan Magenta Yellow Black +%AI5_FileFormat 13.0 +%AI12_BuildNumber: 312 +%AI3_ColorUsage: Color +%AI7_ImageSettings: 0 +%%RGBProcessColor: 0 0 0 ([Registration]) +%AI3_Cropmarks: 0 -1294 1808.74 -718 +%AI3_TemplateBox: 1241.3885546875 -544.5 1241.3885546875 -544.5 +%AI3_TileBox: 516.76999961853 -1303.60000038147 1291.96997558594 -708.400024414063 +%AI3_DocumentPreview: None +%AI5_ArtSize: 14400 14400 +%AI5_RulerUnits: 6 +%AI9_ColorModel: 1 +%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 +%AI5_TargetResolution: 800 +%AI5_NumLayers: 1 +%AI17_Begin_Content_if_version_gt:17 1 +%AI9_OpenToView: -32.1114453125001 -240 0.9 1678 1348 18 1 0 124 87 0 0 0 0 1 0 1 1 0 1 +%AI17_Alternate_Content +%AI9_OpenToView: -32.1114453125001 -240 0.9 1678 1348 18 1 0 124 87 0 0 0 0 1 0 1 1 0 1 +%AI17_End_Versioned_Content +%AI5_OpenViewLayers: 7 +%%PageOrigin:1152.8885546875 -648 +%AI7_GridSettings: 16 4 16 4 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 +%AI9_Flatten: 1 +%AI12_CMSettings: 00.MS +%%EndComments + +endstream endobj 56 0 obj <</Length 5834>>stream +%%BoundingBox: -2 -1262 1752 -460 +%%HiResBoundingBox: -1.11095703125011 -1262 1751.81311523438 -460.7744140625 +%AI7_Thumbnail: 128 60 8 +%%BeginData: 5655 Hex Bytes +%0000330000660000990000CC0033000033330033660033990033CC0033FF +%0066000066330066660066990066CC0066FF009900009933009966009999 +%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 +%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 +%3333663333993333CC3333FF3366003366333366663366993366CC3366FF +%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 +%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 +%6600666600996600CC6600FF6633006633336633666633996633CC6633FF +%6666006666336666666666996666CC6666FF669900669933669966669999 +%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 +%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF +%9933009933339933669933999933CC9933FF996600996633996666996699 +%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 +%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF +%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 +%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 +%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF +%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC +%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 +%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 +%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 +%000011111111220000002200000022222222440000004400000044444444 +%550000005500000055555555770000007700000077777777880000008800 +%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB +%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF +%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF +%524C45FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF +%FDFCFFFDFCFFFD10FFA8A852522727F827F8F8F8FD04277D7DA8A8FD6AFF +%A87D2727FD11F827277DA8FD65FF7D27FD06F82727FD04527D5252275227 +%FD07F827A8FD62FF52FD04F8277DA8FD0FFF7D5227FD04F8A8FD60FF52F8 +%F8F87DA8FD15FF7D52F8F8F8A8FD5FFFF8F827FD1AFFA8F8F827FD5EFFA8 +%F8F87DFFFFA8FFFFFFA8FFFFFFA8FD05FFA8FFA8FFFFFFA8FD04FF52F827 +%FD5FFFF8F8F8FD0A27A8FD04FFA87DF8FD0927F8F827FD4CFFA8FD11FFA8 +%FD0BF852FD08FFA8FD0BF852FD0BFF7D5227527DFD12FFA87D7D7DFD16FF +%A8527D7DFD0BFF27F87DFD0FFF7D52F8F8277D527D527D527D7DFFFFA852 +%5227527DFFFFA8527D527D527D527DF8F8F852A8FD07FF7DFD07F852FD10 +%FF52F8F8F87DFD15FF27F8F827FD0AFF52F8F8F8A8FD0DFF7DFD04F87DFD +%08FFA852FD06F827FD0AFF52F8F8F827FD06FF52FD09F87DFD0FFF7DF8F8 +%F8A8FD15FF52F8F827FD0AFFA8F8F827FD0EFF7DFD04F87DFD09FFFD08F8 +%7DFD09FF27FD04F8FD05FF7DFD05F827FD04F8A8FD0FFF52F8F8F87DFD15 +%FF52F8F827FD0BFFA852FD0FFF52FD04F87DFD09FFA8F827527DF8F8F827 +%FD09FF27FD04F8FD05FFFD04F852FFFFFF5227A8FD04FFA85252527DA8FD +%06FF7DF8F8F8A8FD04FF5252527DA8FD07FF7D5252527D52F8F827FFA8A8 +%7DA8A8A87DA8A8FFA8A8A8FD04FF7D525252A8FD05FF7DFD04F87DFD0EFF +%27F8F8F8FD09FF27FD04F8FD04FF52F8F8F852FD05FFA8FFFFFFA827FD06 +%F852FD05FF52F8F8F87DFFFF7DFD06F827FD04FFA8FD09F827A827FD07F8 +%7D7DF8F8F8A8FF7D27FD05F827A8FFFFFF52FD04F87DFD0DFF7DF8F8F852 +%FD09FF52FD04F8FD04FF52F8F8F8FD09FFA8FD09F852FD04FF7DF8F8F8A8 +%FF7DFD08F827FFFFA8FD0AF827A8FD07F827FFA8F8F8F8FFA8FD08F827A8 +%FFFF7DFD04F87DFD0CFF7DFD04F8A8FD09FF27FD04F8FD04FF27F8F852FD +%09FF27F8F8F8275252FD04F87DFFFFFF52F8F8F8A8A8F8F8F827527D27F8 +%F8F87DFFFD04F8277D27FD04F8277D525252FD04F87DFF7DF8F827A827F8 +%F8F8525252F8F8F852FFFF52FD04F87DFD0BFF7DFD04F87DFD0AFF52FD04 +%F8FD04FF27F8F827FD08FFA8F8F8F852FFFFFFA8F8F8F852FFFFFF7DF8F8 +%F8A852F8F8F8277D5252F8F8F8527DF8F8F852FFFFFF7DF8F8F827FFFFFF +%A8F8F8F827FFFF7DF8F8F87DF8F8F827527D5227F8F8F8FFFF7DFD04F87D +%FD0BFF52F8F827A8FD0BFF27FD04F8FD04FF27F8F827A8FD07FF52F8F8F8 +%A8FD04FF52F8F8F8FFFFFF52F8F8F87D52FD0BF852F8F8F8FD05FF27F8F8 +%27FFFFFF27F8F8F8A8FFFF7DF8F82752FD0BF87DFFFF52F8F8F8527DA87D +%A87DA87DA87DFFFF52F8F852FFA8A87DA87DA87DA87DA87D27F8F8F87DFD +%04FF7DF8F8F87DFD07FF7DF8F8F8FD05FF52F8F827FFFFFF7DF8F8F8A852 +%F8F8277D7D527D7D7D52A852F8F827FD05FF52F8F827FFFFA8F8F8F852FF +%FFFFA8F8F8277DF8F8F87D7D7D527D527D52FD05FFFD0CF87DFFA87D52A8 +%FF7DFD0CF827FD06FFA8FD04F87DFFFFFF7DF8FF7DF8F8F852FFFFFFA827 +%F8F827FFFFFF52F8F8F87D52F8F8F8FD08FF7DF8F8F87DFFFFFFA8F8F8F8 +%52FFFFF8F8F827FD04FF7DF8F82752F8F8F8A8FD0BFFA8FD0CF8A8FFFF7D +%A8FFFF7DFD0CF852FD07FF52FD04F8525252F8F827A8FD04F852A87D27F8 +%F8F87DFFFFFF7DF8F8F8A8A8FD04F8A87D2727FFFFFFA827F8F8F87DA87D +%FD04F87DFF52F8F8F827FD04527DF8F8F8FFFD04F852A85227FD07FFA8F8 +%F852A87DA8A8A87DA87DA8FFFF27F8F87DFFFF7DA8A8A87DA8A8A87DA827 +%F827FD08FF27FD09F852A8FD09F852FD04FF52F8F8F87DFF27FD07F852FF +%FFFF7DFD09F827FFA8FD08F8277DF8F8F8FF7DFD07F852FD06FFA8F8F87D +%FD0AFF7DFD04F8FD0CFF52F827FD09FF52FD07F852FFFFA8FD07F852FD05 +%FF7DF8F8F8A8FFFF52FD06F852FD04FF7DFD07F852FFFF27FD08F852A8F8 +%F8F8FFFF7DFD07F8FD07FFF8F87DFFFFFF527DA8FD05FFF8F8F827FD06FF +%7D527DFFFFFF27F827FD0AFFA852272727527DFD05FF5227F827277DFD06 +%FF52F8F8F8A8FFFFFF7D52F827277DFD06FFA852272727527DFFFFA8527D +%527D527D527D52FFA8522752FFFFFFA85227F82752FD07FFA8F8F87DFFFF +%F8F8F827A8FD04FFA82727A8FD05FF7DF8F8F852FFFF52F827FD21FFA8FD +%04F8FD39FFF8F87DFF7DFD04F87DFD0DFF52FD04F8FFFF27F827FD20FF7D +%FD04F87DFD38FFA8F8F87DFF7DFD04F87DFD0DFF27FD04F8FFFF27F852FD +%1FFF27FD04F827FD3AFFF8F87DFFFF52F8F852FD0FFF27F8F8A8FFFF27F8 +%27FD1EFF7DFD04F827A8FD39FFA8F8F87DFFFFFFA8A8FD11FF7DA8FFFFFF +%27F852FD1EFFA8F8F8F87DFD3BFFA8F8F87DFD1BFF27F827FD1EFFA8527D +%FD3DFFA8F8F8275252275252522752525227525252275252522752525227 +%5252522727F827FD5FFFFD20F852FD5FFFA827FD04F82727F8F8272727F8 +%272727F8272727FD04F82727F8F8F82752FD62FF27F852FFFFFF27F852FD +%0BFF27F852FFFFFFF8F87DFD63FF27F852FFFFA827F87DFD0BFF27F87DFF +%FFA8F8F87DFD63FF27F8F8272727F8F852FD0BFF27F8F8272727F8F87DFD +%63FF7DFD07F8A8FD0BFF7DFD07F8FD65FFA8FD0552A8FD0DFF7DFD0552FD +%85FFFF +%%EndData + +endstream endobj 57 0 obj <</Length 65536>>stream +%AI12_CompressedDatax��i�Ǖ���f�w>����L�o���1˵F=�Ŵt�����R$Z ��Ej����y�#nܛ7P�Hu5�"ED���p?~������������>Kg���O��._�ݾ����/�~�����o^q�'���.Գ�^�?�>�=��ݫ���_�l�Yhwo��O��ۧ_߽�]ݿ�}���O~ʝ�=��N�^�q�����v��>�;�}����z�����O��$q�M?�e��_���˿ܾ~���CӔ�xq����/����?�}w��8F ��?���?�s���_8a�KR�ea��p6�B�)�ɏ8�5琇1�vu���Ww/�����ӻׯ/�_ܿz����7�/w���Bwnw�{�������O�������7��/�������ݳ�g�����|~��ŝ����7��<��?���_<��ۯ�x�Y���z�ܣ��k G#�}�~��t�wo�h&�O�o��b�-�������Ͻ�Z�����ɯ����՟�5�6�]�����g5L�������Vҳbgi�J��T��Yy����}�\�xV�Y�0��W�!���r�s�p6�K-e*3��x��Ƕn�?s�rwy~�ן�~y��O���7�m������~�7o_ܽ����,��ks��_�?�{�_�q��������=~w�ꋻ7"��o�x�L�[���r������Z��z��7������_�v���7?���?���w/w���I�%mĠ�S� ʎY#8��e�$�����aivS��m# �����_��{�|�������>�L����[���;�y�P�Eпz�\�3v�ٴ!�1O������g{��.�1����$60�a��^�������\��'2y��ZW:~~��ͦ�~�[>Msqy��ڜj�N��w��==��ן~�o�~��'�������z⋻�<>����_�4�ӓ뷯�(æ�o_�=��(���v���5���_�~��?yv��w��������_i;�����x"N������o_>{�ۧ���_>�B|��~q��7O~u�Uڳ������n_�Y_��_ڭ?���7O�^>�}�哻��o��1=���a��^�~|��ٽD�D�.����=�{�/~�{���ۧ��1?y��ի��O��_�'|u�绗����d��������g�z������|�R?�������/��<��{�䕹�~���W�O��U���k S����'o�z���&����'o�|uw������7wO�z� ���ڳ�Z?��ݳ�/^��I��/4��n_?}��#�&n����������j��_�D�O�Mz�y{��f5�����_�<9�~rه���?r��)כ�_���y������o��|�s���'����_�����W�����W��z����_|��W�_@�_>���ǿ�������n����W��;Iӗ"��Onۋo��������v}ȭ������e:��������?֣���=o���^�7�x����t�l/�o��1�o~p��{��/Ϲ�&�m�������y���v��'��������>��k ̍�LM$]�|z�.����{=�@e��'�;O6��������&�<k��Wo�~��@n�Oo�����w�/�����_�x��������?���O?�I�W��=�n�|W������z�����ϟ���U))�_��=����<������wy��{* ZJdzݯ������~����B_�|�%V^-߯������������Ю^�����7n�>䉿~q����:i�*I��V��$����=S<�kM��r�(�����A��}�xI�����_�#�kڵy��$�v��_>��x�������߿X�~�����=��D��|����_��f{�ע��O_���I�[U��W/����ï��?@ +r�ͷ����W�ޤ��+�E�3s���������oYYڅ�#��}~��[q�y���lT��O�_>Ӹ��������k���~y���w����G�0���g�h!�.^n���+t��o~&�-WS����O��{�ל�.��v�l�g%NsL��y��ƹ�D��8�R�L�)�%�yL�X��.�e�b*2�C�c��0OC�c(ㄑ�w���ū��>~���~�/�=x����w�Y�Ȇƀ����8���?����Ǜ��~�����������='Z��#��o_}���?�~����w���+�LeR�˜���3�RC(CNal�u�S�y�S��<��}uR�Tc���ѻz�U�6v��Cm�7����������tσ�0_�]��,�<2�Y�iާ��j��tc��8i��Po���'u�����+� x�yL��i�0�F��\�]�5��L�����b�*!ߨ]�K5 5�Y��#rR�y�C�I�jW�RM���4�դ�I��OH��4��k��x�v�v��q�U�A��GGM����nµڕڅ&�B����U�1��~�p�v=\�]�\mv��F7-to����O�o���7��!�}�5,��z��?�P���R��T;���?��������e�HjL �Q�V�T���|�@9Y�L;���F�J�s�FG�Dda +����7jW��K����ğ��'��q*,��K��M���^�K��B�>W��ϤW��B8���/�u��x��'��k�F�����t���g��B��g��y�)�D������<QM�2kI�� �Ey�Z�D����: ��i�LW"'�,~�����e(If��*����������F3��o'���2hW�Z�s�Ѝ�+i��8�լ��J'��$J�<�:��DQL����E{A[0k��w��������I���3]�_]\]]��N麸��U������J�����b�,���Hg��ش���]yu/D�ρ� �,�*�4}�� �;�A�W&G�=����ɶ@'�����|�ɸ0�_�]ް��>��C6S��*/�N��E��+m�O��y��҅��[o�F�x�7煷*���-��eç>��R+�f���4��Ӯv}ysy����i�Z�K�B���\1�W���������zyX M�ebP��b���`�*n�.���'�Ɵ�l�S-l���� �����SĀ�����"b21�L5'Aq�MzeZ��p�� ��f�ou�|�ǘ�Pf�f���CAH����b~\�p`<��Ѕ���ӵ?�Qޖ�D}bn��m����4�P���p�D3VS�hrK��W��+Enir��-]v�\VG�p)�8�#ٰ��5�z��hM]�X.Ee�z��O5�Y� ,l1]���&Z�l�,T��6ʹ�Im⤫!���%䲫!�����H5[�sM�d�Q4��c�Z��a�ph�a�H��08���Ƹ*(���uWLλZ2Z-�~UP�PI�D�VI���d+$�)$R5PH.�:�2R�*��4����Վ�U��U�+mw�)��90ʎ��ݑ�{�::6w�8�荻j�c&ُ4�f��//A�K�qg`D�I��|A��\�;�F6��$Y9���gyc�Ċ��f����?������[�\������g�/�%h���u=�,�ע�EiWE<�Ұ��?:֥dZV����U�VM�̅6������_�Ē���qE�,Յ$nF��g��ea#Q���-�����zQ^��奩.�ڲUY��tA� �y��U@�1u!����DMT4a��E]��^l,.Z�f���"J��������lZ8�D��AK'[~���f!�Xm��'>vo�ۚ����iz��������X�A<%�f[�ʵ���8K��B��m�Us�K)7b�I��h#�""��\&٦�V��(w��x�:|a5����q�b�3��Xѕ��(�����}�J�Ū�6u�)��*�QcmH�G]tE�joLuEvQeSWe�\j��.mި��]��]��j����5+��j�� ���^�-���V4sG{�k��۴oz��-���'��Ƿm����'~��}<�}e�O&�9�<Ba��\��HG?)�"'mAIk���A�J��2Yk��6���� ?�A�)�яs���l�ʹ�e7����JZ�Js�� \�4[�r���+oiܥi@{�͞ˬ��8J=0��U?Z��Cs�i8Nӣ��!�9�@'�����J�� ��r�w��y������>>�z����Jr˶�Fs����e%�qg���m�s��іKiL��ɢ��4��]�zS���8zӢ9�2����ul�� �K�whPl��F�������ZY� �Ixcנ�(>����f�������-V[�rc?�=��s5���ڝ��O�B������1�=������%���lm�&������r�Z@��˱v��#M�?W'��鶏K�lѱ�m�C���A��>���'~p�����p������ �zSn�M��������E[0\�\]�Dp(�W�*ڑ|uya�h�q����l�z���1�b�Ÿ�������il.�� ����pwK�X\������s��O�u��xq7'qs7Gqs7g�E�aOv�4n���b��Q��C�i/Q��پ�3�����=��:֝;�!Ҥ�9 ���&��ek-n���,*մ6�v�~����)߷�i�� ��'���ni��lW�W�.?����w։�'~p��}�xs�|�(9�G��}=�#G��Q>r����{b�(+8����4£j�Ny�u�l@���4�`��P�������C��ګ�9�i".4�B�����4��)��?Ҩ� +����.$��x�:���_h��3R�"�]�gc�`;���� U.QC�R��'w�?��c������!�]�bu#-2s��B�������`j���ј���W6����o����j}R ��}��j�S b���`�$`]�B�ڈ7UQ���#$������z������eD PT#p�i��F#%e�s�ԏ٣�Ks(�U�G3 ڟY:F��x4M��Fc�s_��F��ӏ�j�hT�=0��O3+]?bVЭ��+�D�������h�j����0A��zih����A88`�q L�nà�!��W�uzȳ���+�V����C�2 ����U;P���;r7��_;~�aǯq�2�`OeE�7�xs�߬(�?Ĉ�� į�J��o8�)�:R��->��B���?�4����\j]��N�嵕��0�mz�f=�aη� �p�]�h���x���c�1�d^_��b����}��������� l9u~���0Z�r4���F��B1t�����`�أ}� ��3&��WYެ�ұs���+�|������p����UV�i�oh`��t��<xN���j� +��0:�㼇,�E\�,�bL��=T��(����*��DWH�-�f��Mms<���\.�Fq�%/fɍY�c��8`YseZ�ֶ�|t�����ϖ����sn9hX��ڧ�\�-?��{ڨ'���67=���w���MO��^ߦ��~Ⓒ6|ߎ��CG�so.�ѩ���ߖm���\�<�}��sl��Y6�c�wS�M +��>��2�|�5�攋r�l�7�=)}��Ay�\����<tL>pJ�o�.�S���۱r�~�:�n��܌G��m�[��\~�`��|��ģ+a��VO5��[O7��}�����B"�����x�� =���f�v��7׃T�+g�ز�l����oZ���3��V������~� ��f�J��K����Ji��)�)7��=]���K��q��dX+cP���?�����u���EGVΝ��"Ր���Z����2Ʌbτ��:lm1��a�h����V�� .vڴ�i�Q+G��=1�h����̱?�����}�ɇ�����MO��^ߦ�{~��q��� i��FNOڤ�9d�,d��f�������l���@�T<[-�C!��T��qm~u��f,�;�y��Z��<:���-$�@�[��V��i���sW�u����g�5�a�&�l����/nX��ZZ-�}�Z�c-ر�=���T�����w�[�۷�T�Cp�A��u��t�S�t���&�Ş�����!mIl �oѮ������yg�:nz�k߭}|�i�&(�8�d�4cH��P&�R2�����K�K*�@s^�C�"�����&7?9�_z��TLTW�Pd|$1[�wDZ����9����5����QR�65�"6��kb�ar�a�В�x�&4o��.������d�ɈkbPX������^�����*.��xb�i��t>�f[��I��t��>+��Ha\/���ѥȺ�o���>��k�(�KQ�k��:�FO٧�=�����Ǥ��Vt�yʣ=A����T)�A +��s��`�K ���ݛ]���_�P]�+iV�͵l�I��� �S�7�`z�!pԦ�>h���x�<xh ��0���"6���Z�\w5�{`/�2����B��W�����J!Rc�n��ԋ݄U l*��|W��W���8��xM�[Թ�Uy;��֔�5�p��,���>Dž}Z��R�g^�������%\8n���R7��R�n�T/%u��[�qsk����C��x�զp!���yM�TԥCo7�DT+5>�f@F��rm�aNc�τY�w +����m�9��AG�>Nq���eՏS>,,���m�Xu��0�� �@K�Q�-�,Ҿ����4�Wf�es�j@=�z�p���Z�#����F��H��XY��>�t�pӃ�W{� "_ôa��7�c8��5(��ge��� +��~�V�b��-�V�bk�-��)�mo�m�9./7�[��k���$�^(4�S�o��co��F7}�z�t]��Q��?�"uӺV�����)ɶ��Hk[��M+���m�)��30�dK�|G��/���ߡ�'�0��}MtVo�\tp�t�hl�v��/�n��fӍg���a�ᇽ������e9����5�)�;u�+��6�$�e��F�| ]�r���iU�Z�f���:�*�9�"͢��YCCGùJ���j�:(�Z�֖�Ɇ�t�҆����O��~���R�ds�6��t�k��le>@�\���{٠�x")�Wk���tЬݡMMB�IP�)T]��ܕ7{�M+�W�l���M�}-�L��^d����ºWK�L�Ыf�B K�|φ_��v�l�m͇54�ZI3�i��Q��rDj�C����q�-_?����q�I���H�2#�� {_��XsEه�;��Y�&�}'��<Һ=�=��č�kV�$r�#����ƛ�������[�|��B��O?�ۢ����_�hY��_4��/��v�b��t�Vk��}���go�k�KӦ�S�^C��V{��m1D���P�A��8�vh�?�-�����~y0]��T�=�����{ݸ�⇷(au�}�譇���wh<qX�O�-�p�.}܃7켁�OԆ��M]ʥ6ܸ�6���z��}�����t��PiE;��R��A���R=,�}��8.��U:.�}���N�q1�<x\P�$��v>(���M7�i��Z��G���&����m�x[]�]4[��ނ�oP5���������!�P5����~�~T��X�(�����vX�������rcpX��é�:������ �#��mH�rӶQ�ퟭ.��xXo�R�a��C{\��~�j��n�m; +{���@I:p�j�*��n�����?�*p��p�ook��.���u����x�Q��e�]��+?\I�[��G <���}���_�f��`:_7G���S=��>,���2��/#|�b�������X����4��n�|�������=�g!�<��|k���WF�l��p.8^���Pf��������o_Ia=�;�����C�Pa�z~I"Wf6��K̓�v�#;����U����]<�[�����b<:��#|A��i�/��y�M�V^p��j�`/1�m��6�.[�����ta��yp(h��-i��AaÖ/t�1l��{n�$O�^�{���s/̶�e��7�X����{��@V�ր{ �7���4r��� xy������_q��[N�Q�"ΞR��C��p�YT�2ʲ�r�b;�@��A��0�ƕ�n���d�i���DN���vxH��B %��W�{�c��<�{�����3;�63|��7�B�K��ц�]�O: pJ>x"o�ONJ�c��J�H��&2����Ђn~,&���x̘XL�n2�F�blK�#a1���?� +t��Z��!����K�IZ��#��"J ك��b�)5Tϕ���E�`(`�^�y8�g� qD`�"ؔ@����=���P�A\�R���ށ�yW������%C���o�}�ki_����F�$`mӯ��6g5nOk\ҭ�D+������U����j����)QK�Ӓ���,���H���hA;���S/ۮ�!C>�E?�Ɏ����$p��vu��v�y����^7��>�d�����3�竟�f-1PNXQCپ���3�Gⅎ�B�!�8\l�{��m�m�7=q<h��6��m�z���q���;�&cXO�<a9_%�˽%|XG~���l��_� 娧{K��m�_�����-�j���r|��W��i]S�4��xǽQzc?���B=Q�=���W�Ƈ�ZH�STK#I��&\��'��u���)Q��8*�O��|���*N�:�L�"1Og��ǭA��|M�'�LMa-I�-ՙ0�ؐ������Q��r�r��1J����1 ��.�( +�s/Z3�Kk�b���ʽ����+7cȳ���á��g�,{`���m_:��V1sY�Sl5} +tT$8��^tz^�@�7s- ������j��I%{D�������封��#�v��*?8h��1��1�6���o�t�蘋} �M���8@'֖7��������*�VIث E��ON�閳H��oZX�<8}��\������9�{L���y����k���G�AAKe�����Qq��o�cݖ��z�[?K���x��&�����@��:�c�X;�l��l�F�.y�I�Ѽe���[}�f�W��fؽZ�� ���6Ļ�nü����yHI��o7J�^�ܟp{�=���� +V{ݘ�ɶ�#{O��X�������-UR���Z�?N�T�P֞�64��D?6d��3�F�E?$iP��(�0��M�=8{{ �o���W�����:me���j����+�L&�r\dXwy[��Y׳�Yv��AP~k(l���:\���%H����/ZV`�_.η� _.Ɔ�k�>!{��902n�n���A'�y�(�8p����}=\'���;��s����u9N��=O�H������C�:@��ǡ����VK�JzM�M�y�O:}/��a��r�u��gi4��Ե9Bv�)��ڒ"[.̖7k8��u1R��*���H�ڄ&�<�ao��k�z���fFsL��u�������۳����O��f��ko���;~�ko���Χk[�g�{B`o���si��l��س�bs�t����pf1l�{��F�罋�=@ >��{��A4�R�!�ߖ"�7��+�]��*n�q��۵ܮ&n���n��vM7�z�˷뺮��hج�v}��~߮�v�����Yʰf�^��s��>]��1Ȅk�Hv,��]���o�~����]�V�k��-<��R�]�����=l)bO���\c�#*�<g�k-�&Q��o��A�FI�in��YT-Y i=��hE��+�[b�B&MɔC�f� Y�pf9��0����0=���<�;;Ng%���ۡ� �!M�m��ڋ_�P���E�զ�yG�_w�CZ�'��C�1o�1;����u���A\OiL��e�H�+��� ���F���F�ݪ�S/�z�粍l?��f�Y\GW֓$k�68���خ������c���7���yW��NZߑF��~t���G��I��z����:��^7r�D��ñmGw8��jO�v��~�syC���qnGz8ְd�>����\%s1��,�9)�7�:j&Z���N ep��u��c��4�g9 t���`N�Y|p;Ŋ��]yi=�J��KXy��]8�!�ju%���؇is{�ܡKn�;,�L����3���o2,N�w��"���.Q3gIi��8k���)�6��G|���n��F�8eq�^l\��f�ٗohdaԃb���Ϋ�օ����O�=��]$��i��R�z9Qx# rv�.������27���.\��uL3����rs��9G�9�~�I��:m��h�X����=e��|��t����6[g���V&��&�n)�']��T�������m�;p��n�ߒ&N27\� 2����K�e�r�?��/(b +:��u���P��i�ؑ����-]�&ƞ��X`h8���q|P���p< ������q��?l�hbO7[�9�_ҁ�؟����h��@S��ԭ'^q���͓g��r�^Q������Q�G�\����X�vFzr�7�_�<t�B��R�����Gl��O0��'eu��[F�gd��ށ{T����с�с��G��Hi�#M��&�}9p<���I�5dG<�|��;��v�`Z��l�������_�ɏL֭ѲʮJ�7jJˁ�҉�=}е�?�>���]_����W����=_������տ�k�/����:'�I��g�ho����j�kn�s�"�`��Ku @��<�t��Q�������|�����]��}�g����?�E?�E?�E?�E?�E?�E?�E?�E?�E?�;>��>��G��H����~Q]����/����7�_~��g[��Χ���k�K�ޯo�{��g��\�������8��܅XΨ}/�I�초gy�@�"�<�r���L����+y��?��zj��Ծ��߿����������ֿ~�������MW��i��b�o�u�=�Կ��O;��w_�������n��_N����~�K����՛��O�<�y�����ihO.��_�~r��0�_?{������O�����w�_�}����o~�������_'&���?�mO�j�I<�Y*�SĀ��4̣�夭]��g1Kѝ�x�$%t)2W��� L�7.jN�Y��ʸ��uH��䙩4%���Y�gQlH�J�S7�h�8�b!e'�t&;~��tp��n����0Ly��Ӏ�<V��{��0hي�a-U�@t!E}?g1�N�O#�'���Sԗ$�A�<��K��i��0es%4�Y�5�Q�}���Ut�8�<gͣa�9�v�LK)׃��F9��g�*�3�g���ɜ�c<�DH�Q��ܜ��7z���ګĵ�b��8D=p7�3q��??˲'-��v���,�������I��n5���x�d[�!Z���қ��.kg7�g�ܧR���$鴛*lp�K'�{�Q��4j�2OI��Zv̪��j^��{I��gc�b0Y+_��n�ъ�gc��i��!n�i����6pS��MI~�FHl,)UB���o�Cuy�� +��,�ݙ���R>�B Z!��R"�ꓢrC�����_C�U�.�Q(J�$8�-��<���Z���N@ +C�vI�ξS�=�)��Fm�ʃ$��8�0�����(>Uʎ�N��dT4VO�Ht +�(�EE�d*�uC�7h@5�}�~N�����u��6��njz��!���=��� ��<i{�9ML� ��F�˩a� |����<��ֈҔ"o*z#e�Ρ��q�^^���t�ѵn�U����@� :��zq:�@-�F����cL�Ц�˛�69� ���܍���v�>��g�1�C9�������Y�u*��z�����.rw��Y^f[�':�'~���r�M�Ko+�$'��6�@%�֭�pʹv=���O�P =�� ڱ��\P�O�'��C#~*�@Ռ�Sd�k����i�;��Y�� � �#�+�K�J�1ŕ*�Hʬȶ.%,X��i�HQԍ</7�u��D��6aY�?rm7Wg���`b��!�g��!�è�ٚ�1m���^���$��v��'&7����L���E�eq��e���d\��%Ҕ��Ϛ'����'>7&�[�X��XB�]uy�v�� #a�ˮ���uьD�. +̍�t7�cEJ���36y����fv��dZ�G�hވ� �M��ͯ�Јz̈�1�A8�3�D[��"%^%2��2��=Dbg<$�8L�,�N +qD� !U4�@RH���J�讈f^5o�J<uI����l=d���Z��=�}����ԫ����z��`����,������D�#[W�����h�����m��8c�/�غnj�4���Czq�*��Rń*����n�>� ��2i�������,ViA�l�IU�O��j����s=t�8U���ָ-���覭o7y����=~��b�!37�El��e���w�a�-D�C���!������mР��G������|ܥ8AZM�hEN�r�=ٙ�����l�x�(-��@� ���*h��.H6Tz�a���8�i����cE�Pe���)"�= ���d�v���*����7�6�A���V��U Oi�"C�=t�FR�o���]1Q�Y���K�*���ї�BH)9�U���BL�aI���*�����lEz<#H2��^��sS� ��4��) �ϕ��ڑ"4J�D�h���&&����4���h�4P����o�f�%,\I{CK�n%ɦڅ�bQ^�Y��������Ҿl�����S��P`Fϰ���ݰy���4T�S7��|3SaIѴ�=D��Ac����^�>�=��Y��/?w��tM�Ĩ�<�y������ Z�� 3�¡Ҙ�/��j�DNV�����P7HЕxĎ�a�hR��hЂzd���az RR$ȱ��h�qDO��#�%N�'G�*��*Iu�q�<���b�UOX���3}��2�>�}�O�m܊���$Ɩ7h?5��n0ұQ��dJ��U;����o�q�jt�T�e*J�zT�̲A����H�}��˪��i R����/��FS7��d�aa�f���-%�r%N��%���%��"e�V�����N��ړ�)�o�zI�C�ԓ��;uh3CٔeG�FrF�q��v�b,��R��dsR�˞,$rX҈����>�52�� ���U�*R� +��T�(=�ѫI-�#k�Ȏ�SC�v#K���'X���hz�Z <ir�Wj��Uz|����5@y#������I~^�B:�Q}~Lu�$���엄b,Φ�`�Hw�#��m�gȀ��(�rr�8�Avy���������I^�M� �C�����@�`�n����&I�Ÿ�1<�P�U1.Z�� mOM�������[Ц��|�̙`b��5Qe|�Ғ4���z/��2K*����6���n�)=��#%Ʀ�Η�{A=���=��(��4,:�X�?�W�Pу4Ą��� ����"̻DNe��BK��@<�vZ���g�E�p41�Wi�E� �`�����<����ڭ����)`g&O�D&F�P�8�5�)?��L�$��Y�:j���+�g�ŀ��@2�̜�(/�@�$������ݴ �N,h�jjfGVӮ4����$�j��"Ҕ�y!V�-W̠�2e���;��a��fw��Q�+���>�G+�N��ϕ�0#Y���5B�sF��o(}V":���,~�W���&�o�߀!(�]o@w���ey�������eeR�3aN�C�HU�G�!P�!12�ϣTĬ�����جð�Ų�����0�����׆*~�t��~��Հ���n=��ф3۱�h�"]2��W�6�H���Tr�_'�����C>��d�_�h9����A�� ++��-7c3��sc�:��٬�P��H�崊r:�/����L��/� �C�̡�=]&Nz�V��S)�c�<ѕ��Oj!���K��A���0�#*T�T��b��vC�DC�&g� �� +�nO +�7��e��e��Դ)�z�/to4��<5��Ȟ���!�k��&<�䱡`�Gb��G�^P��F��������4�)͝�d��z>bGq6#��n>HL�X��1���0�jJā�&���Kͤ�a1B��<"e��y����B�-��5�`�W|���u�N0 ��s��L֛���Q"���;b�Og�����2z�=��J�H�G�W�I����.�>��$�"&�N���uu_VXnϟ+��<�\�*Oc{<G'� �����J�Hp�B�VA5��)w�y��P��e�I����<e��1��c�!���ï���������ab������O��-��0L}e&�h,�ũ\�M�3-[�2�M�כ�'�o��� %XN����k|\�$�织�\�P=DI�x4���5�^R(m�2��HU�!i<C�����+��0�b�SҍKN�=Xs}�h�=�n�5�F� !��>,����Nw���������E/���iۏ6vG;��b�1R�p"�#�(v�u&�#�s��~��7��>�S�/��.-ud�qӣ0�����-|��d�7�qsc]fX��T�(���G��[�@#��@���6�1�����X��'���D;!�t��o^=���'�O����7�on��0�w�f�BI+B�Zd�.�����`:}�%�p/�u��Z�6J�P�N��X��_���6�G<�����f��hah�W/{<�8������}l�¹��CG�R���n�h�]�uQ�d�Y�����w�G������~�p�?� N���BG�����`��OLv`����W�M���If��A���m��Ωy�$��v5-��k��/����KL�B���^JB���Ñ�-�řA���>��V1�>��c�Pv���i�>e;1%ܦ%l�ڂ�P/�bHo7"�>�N��<���1\ ��1QL���5��p�6%Q������,b�M ��}�⊯ ۳�f-�1� +sq�Uϐ��#���#���t.%@�T�x�~/n�4pnı��XG��:q�E"G'��e*�Yb0ęZ���\��NN��*��������?q�)�b}��� 3O�^LMˏ��c+�KE��g��|P���V�O#_��e���� Vq���S�c;��ޡ���>��Aܶ��}�����v�{�&�M +��Nv�(���]�����F�&�!����>)�t���j���f�Y�D�I�C��&�E&�Н@a��D��~c�7�>�XZ^����d�8:�*���NjEvj � a�-��׀���d'�-F�����D$���jJ��'o���ņ�r2��p �/֘0�q��3R��> �Xma��c���꾄��ϱ��20d��a�`6o�`��nH�c9J���9����7��z����:װۜ��o�,u#�&3X:�Z�Ee��wTT6�ݡج`�b�5Œ�����nĈ妍%���nRセ%�<u�O~P���*��! $�C��z��F��(BǴ��[�|Ĝ�&B�,����,�W�H(��$�����Wv����~�f��� �2$۲�^� ��0�Ϫ��(�����3�l������6��V�#�F��f�J ��RK\: �3�'� +���;)Q Id/ پ��,%��E/d���Ӥ����p�V�������)`ϋ&eO�&-x�GIx��lJ1,���h�q +��\J��#"y2=D[��oÌ!��{2�4y�,� �t�V2�'�T�%���[�f0�[,�D�o�h�,��j��tr ����"N�X�[C��<HZ ��L<�g�(\q�X1�>J���{d��E7��v�0`����)0*�>X�[�F��r�)��D�D\4>M8O�/b[��l����U�,P-0ެ��W�(��F\�C�F�iQVYDi���Q�;p��p;S���`�ca&`��/�p��Q��M����x5&[���MD��(n ˔��Oq'��p y�K���әY�&P����ܭ�n��qD�����Z�{���1Ȇ��u�E�"���ݢec����_��.�wXJ���������'廥�>��\fɼh@a`�F,d�N�g���N�h�M�j\X,R�1��.�-0�<ܳ2�w܀�O8x��yD���纇v�f"��{P3��:-h��j��7��k�(D( � �J ���@�8�uI�+���ih�[ �����v��z4w��t�d�Ǫ֨ +d�z5/��n��M�ܭ��t�8&46g��~������#����W-61;8��������vY&s��70 ���v9�FP D:�������:����r@T��KG����D�34=��`����ЖANg�� g��ONj�B��hr���% �O�8O�(� �V�H�k�B/6��,.�p4c�C/���QMb�b$_��y��߱`4�œ�p��V��gB���9�U�'��e�Y�B���*D�Fi��j�c�y�"�̟�%���i\�@!���zh!*0�T黩 �M��r�{j�Ɯ ��J�C���)4fm�Bh8&u�H��(���ӂ�N�9�� c����Q��C�R����� +��yFJ�ʱZ�I`U���,���B���������h���J^�:͛Dp�~�ˤ:"YS��fwyN �B�h=DB^�1�C�it�Ȃ�hR뀻�5V7�T�3���ü /�u!�Yp3�+��&��M�Nz��U/�8�Ѕ��� OS�r�Q������$6����� E��p�%7U�)�CZp�e�m��2�}U5���GrD'�D +A��}2�2����Jiv#�c���'٥���X�x�F�v��#"�#�X���6 ���\���{ΰ+8�FPc��Z&���SLBɇ�G�I9b�k�J:�kwS�}�qь�@��.��c�4� ��?f&�Wӈ�k���R��S��������������y/�����վ@S_ ��=��?g� ��nd� f�m���K�I�>˄����0C�! f$�b��3������C�S����* ���3G8��8�d�c����N QL����2hCG����X^V��B���S^V�d�Դ;ML]=p������#�"+� �>9���G4p{��V胣x%w|>:&�`�H�>�f�(��PB���kS�dF��\ބ�>��d*�������Ox4���Dh4����(�Z��Xe��8�j�^�ǟ&����DI��ꩩ�# /��f�� +bM"�F6��0\ �?t ��.SXB��5��@�M�����s4MX�cA�ҡ�[�Ϯ�٢J�_ �!��f� ��!x������7{�8��%[��J*����3@Y`�⻝I S�����^�O��'���6Tb6�ĩ�����"h�)�(_��Fc�VLF/>��GL�0,Nq�Y�H��55���1&X�_5�W-� ��h�'�*��X����������V�>��`�>q�$}��� �G<H��"w�-cC�(�آ���=d?Q�0�h��i��\Tb�}��0�,�*�e���5_|Gpj�l�?`���3fѭ�Տ��e��`(�#���A�!���H�c�[{�s�ᠦ�NT����#��BL$K�Ž���h\��Ȭ(C7�k�"#<���h� ������z�K���7�i"�1��6E�H�]�@M/�Ku�����ѓ���)3=�/�'@?m�RzL�بcΨS����nlX�r� +�����C�G�|�@��|!�����L{�C����CTKe�Z�sʕ�wԜ�H@�.&�?��;� Ql�Yb�D'6Q�a +� +�☩�%���x���I>z����� ��Z����CI2�17l�&nDGw�d�� �V��7�h�@"�J��<�n#�'�S�Pg�"��Pd1~eHhb����6V�*������ڣ���ZȞpsG�����`��P�W'�f�L�p2�'�t���G��e,��Q���E$,�@��]r^i�;� +�2�Xb0���K5�IZ�>`Z;�(5 �y�_rjQ�j 1 �%S�M�Y�AK���\;����E�j��2���H��v���<G4��R�K�с>��8E�pi1G�� �m �tǫ�� +���5�qK�"Y�XH��dT��f��A���a��#���u|.AQ-�-�Ԅ����W��K��l����`�ɈSQ���dj0��A ���?��L>~Ugz��� /'cجT�̘Z��Z���r�z��7b=��������p����ǔ���hcʯ��,��a88��i����z }Aa�~���3��Ęݣ�sL'���k���ɻ��ѝ�CC�<DGĜ�l4"�5i��qh�78�P�y|6�3�����Y%���me��.�R�z�������iL��٧`1�)�:49�5�µC�GZ΄+\fn^���sk"3dF'$FlɌv��H#'�L�fA�OI�|IF���q���>��G`�2O*���!��c�=�e�d�w-��1xst���Y�.e�w�ᘭ�pB��Jr�\��L����U�H�w�S�Jj�.����c�B�n�E�������ԌQH�ڵ8Q��()%�xܚ<,�M��U%��D�v���@;��$�������A��6)�|�CV��u��~�6�v�dGS�(xa�V3�'mG�ց�W���wpqN���y�#榗�w� �tCFBrF�10�y�hX_r%���!��ib�>y�$PIa����i~�\T ϯ�DͶ{H��IJC��3<�:�%��YQ���#@��z`�͜��6{�*����$X�48��j�f�$+"h�]}��-_����3"�����c���g&ژLл͕>��J7�Ӄ3<����J���;��Q4�r�QA�r�I�h� ��: ��/��)�Ό#��ڳ�_E$/��u��9���Lj!=��Ra������O�UdB��_�@����%�#hBGYW{�#�k�}��#3��V��9��]�6Ȋa���'gT��+}�<��GQ6��S���G[Ӏ5��:�Z�s&5p�6(����X�����sB`!K�}qM�OD}Q�� moȌ}E�yp��J�B�P!�*�#������I1,��t���$���H���ێ���M��)8�/�G�bV��v�SUc������d^M��l��6�gϣn� ���a�S����.�������e1F�:����dH09�d�Rr���H,��ZV��+�RTC�o�K-��pA��4��٩����.������+����Ț���ؠ.6Rqc�K�� q�g�%=Z&(����X�YM��zX�5ҸҺ� +�a �����H:�ħ��4:���%�|d�9�5,�u��!�-�ƕ%X[d�O�O����*�������d%BD�~�Di���PX(q�ԑ#B h����VL�jj1~m_�ۛ'���!��.lI�a��O� H�WY�Y�{K�SuPt)R�i�q[���dT�ev��)�pj��-]�RPy�j�6R=�4��I⨘8N� �o�G���R���2 E +:D[�������+uU��� 5�n8�w�+�u6�]���Q G�A1z}�����]�B3�����-�vH3��8 +M���Zb����� +Sn�.�Js˦��s���1�.��tH�J�H�"��l�����J�ԋ��-�]�]<C�}2S��쏩 [�<�L*�c,"�?s�2�s?]\�N~���np�>߹cv�Cg�Q�3V���[�Oe�D; �r��p����2�5�U�6�sjA��C�HK1��� >gj�hb(���3?CwA��/}bX*�0�� v�e����ܡ�'�A��! ��R d���R>��켼����5Bo��Q�`3�5��S#�b�t�z<���6�B `!A��ả���+� + +'4r[Ă5ׯxJ��%�C_<��/-�32��&'�F���$�n�{ҏ�Tc�847�q\n�x����y��9<�-�6c0� {�] �6Ɍm,a�����[���z,!�f�I����_֢w�آ�6|��pU�X�-� ��m;��Jf�V�f�0�@n8�7�_���o���7��Q��Y�w��}�v�4xI�R*n�@,���W[�?L@��j3Ao���(�Ѱ.�'�{Tj�Tj��#�G&m\u2�x\���R�,P��������ܠ��E&����u5�ndVs �:�lT� qހ���g��G[��i��1?ZDK�Q%{�+�o�SZ�}�����t��"�;�L1�F,Y糣����,��q(M��7`G�6�Oj��;�(�6�BS�ȡԦQ� �2=�q�ˏ ��>@$h�bK�)��4�3��z��-�����gzbL-�M{�IU6�Uh�����2�~6BG�0#�*P��TH�I�(�p���O���p0���V�h��E��sȦ�� I:�1�E�nnQ �g�ގF�����|9�f�ejF�$�EH���?,#�ٟL��EY�(�QJ�o��S����)�O�P-lZ̢��'�G��YԗsZݔG���W1�:���z ��������{��3�^�v�9�Z2.�{���&�����,v���&�91߁A[��"^�#nE85��Z��D�*����"�L�*�wr)�� �Q�WL���u@8+��xY�����^�}�~ȣ}2F D#l�X��Ԭ!���QS,�i�H��8b�{��d�@���u�q�/LF,��)��e�L² C��[}RJ[����Y"���gtl�F�6�,�]k�����q�bb(4�Ed�Y�&�uu;7�cl�����p�3b/�Y_�����{�ʊ�W�d����L� +�\ +R$�-� �X��"��&)�.uRѸ�LA�h�HCDI?p�����`4�u�Ic�bo�&�%^b��p��=O`]-����ɑ�+IQ�#�w>�MفܿF9�=j�Ǧ��]P�G�|OV��Њ���*^�m:;$4�L�S���?�[���˩k×Į^Dl��1H������Z� �Y��5��B�w �jl)2Zd�4��[�q�$=��)\rε֏{\{����o0����l̔v&@z�A&�$Z]�����d�y͑v��B�$�� ��n�J n*�&��a��%����,)�t�-��!ekkD��yɣhi|����E�4��_ �:0�2�1�V�1���v���X�����=�������4F2�����~�e>0"��I��lL���㇖�/E��^Yi�ʚ8Kq�t+W���V��ܵ��H�"��6 Q�s�a�$������g77=�zd˧�|v;+f�p�A艘,��+d��F���H�_oҦ�)d +A�y������'t���C1���j�촯������.�K-�4�{DF:�i,+�q�fwf_�"�z��f�9cC�Qߊ�A�s�)� ��xU�H��U$9��?���ju��M0NLũEe�s����\�q��Zj� �� ��q����y�^d��ivh����j �z����J�"�nҺ�GCAPc)�q�.��l���ęFcp�x�3C_��\.�4�$��NQr!P\H��bk����N�ᄮ�P#f�p^T4M���O؇��"�ܐ�I�QJF>{_4q�\�<~�3���f�V�sI�n���Wˊ�Y+���^H!���Ŏ�V����0I �#j�ю<v� ���4����'��ʬMH�"/`u��oo�����͘&�r�EQ��Z2���j��F!���\}������hy�k�4�z\1���$?�sVQj�O�d��{������H���x��{�� ?��'��Q��������wŗ��:���w*S&����A�ǺR�5���mA�Wњ�C����a�-�z�C���'Z��]Ռ�2��h��,�L��oo��_(2+�P, #�� �f�GG��Ʀ�R�Ø�Ԍ�I�p�MP�����r����p��jKr��! ��"�/�-&{IJ������r�����2$�a��ګLҧ�b�Έ�N�0�9�9�3�0�r�l��+5`&��̭�S~���<vi�xU�_Lv�gj3�����C���,��E=�W�3eY�T�!a���s&<�VFD:h����� �?���G��Y6s�A4����.�]{�Iݙ8Kj"/B˙iR���� ��Y�C�Z�H65�B!�/�k��X]D�oN��:�Ѳ@�`�`���R�w��H�VD9���r�žjJ����Z g�I"}�� k"7���Lf�2L�;H� �L�9͖�ϼz��볰Г]}R�(�ŜdR�'^,�b�oP�oX�819І�awE���Ow�urq����0�ɇ��-�:Q���+�e�K�-��'y�����L��3v�7�٤���u��.���O>NdXK:�F�HK +�v}��"�>-�� ��{���X87�s�&!$����:�Om�,0%35�AS�p�<�&�ȅ�y���C+��k5�l�<4(Pgm�}����V��ȭ["�?q&H,i���-� �Z=Fi�l�����=�^�(��~ҟ�t�S1w�%l�z:h5�HD��[X��]h���.��P�"I���H�/Ҝ��!�5��6o'tQa���{�`w�##���ۄU�ֱ�i��"�Bb&�:�Fi��L��>v���ύ�u�����$8Ʌ�F�T#�Z�������D�h���S�5:� I�O=�BBR(Ĩn=���\Ӎ����$�PڍSk�%�k���J�9S;�A��^�j�Q�.fhzo&��o����(D��{�D#��K�J�w��3���/ ��%~�B� ^���I]ʐ�H�`��]N�[��lu�ĸ��9�W=P��왩�R�i�T�B[�P5EOČ�o�z䉓{��A"0�o���q�����I���3Q#�>�z���a����ɥ��K�0 sm�z��9����&]v!��@�{����ʑB��v���R��<� ��*�hU��ɵ��Q|�҉��}s����<��Lؙ�dU�3V|s�O�����ё�'��ꚙ�wH��j���8�� )�~�n��A&��(��&��WE�%�i�R��S�5�v#�b�2RG)���s*8�M[!d�9�&l�����G����c«�hGm��ϥ����$m�8{�j�@�J����%[S�B3��,��n�|�b��e����i�nۦıB�,�����] +܌�jr각> ������sCpֱ�rIT�Y��Q�;��5Mw���5�����Z��9v�=\8Xt�ܣ݂\w����=8x.�m��(R,<&�|k�Y$I +��ե��S��8:�#mۓ��D�u4.�5�հ��S*j��ւ��!L�_��U��E����?��J �A10� ���\�Lی�P�M���ɕAJ�aI����#��^\*BC�ǧ\��/����JBh���Դ�HAt(TiP(t +v�c��¾3��UѢSˬo2�� � ��� �P���7"�P���R�ø��:7�� +��Zy������1�/=�Z\Ψx���!d���%:�{9�]���2�����u�[������&-A�z��Q�K�"��y�t0�y����x2pO��z�z�8�:LHעK�RAA��F�O�%��:��nR�\ț�,�>k?����R�c&kxi����Д�z�������Ծݖb���05Y��g�@B%Sy�J��Sz=��W���[6zDKA��f3N��9��[>&�z��||�����x�H�*�l�`.����Z�`����#����� +�s+�`��z��X��#ƈ�%Gr�Os]^O�9��f�!:V�����g�er�7 6�@��^.]Lf����N/�u�ڧ���� +�j�[RڝX��Z�FS����7&�� Q��w����N�z�������|F�8�F��ҍ�6�k�JP7$�l(��S���"��`h�Бp ���1 �z$�hͷ;B�%c�`S���`�\�9B��H���>��w|>2�U�깳wXh������w��R�yhT��*�G�\;0�ߐ +�!� �(����T�:8?��K&�p��8��}�b�i)�͇`���x65�V�@fF�6�`�Qs�]�0����� +47O�����0�A��r/L����B���!��JX��3��3:��N�n�7��+���?�邔sԊ*'&�:��Wbn@��}�6$C�P \ ����D)iTFX�TV֪$T�$&��)�ݍ-�aب�4���Lʲ��L�y"����:�e ���l�W.,a\�1$b��w}�F�(<�^f�c�5..�N�� �� 9���a%�{r�� �����gm1Z�A�]���z T�[�H{����0)�c1Qo� N<�s�v���ź�t8��v���\�2��@l����j�t\;z���D^�7*�p��X��Ch�x�C�>����2�4��J�S+Kj���QJ|l'K��q���ew�e7r������ �y�A��T"[�Um�-n8�;6�������@eԞ.: +�P�(� +�O�r�%�S�0�T���Re��uH�ZZ^:ّ� &u�\�s6�tW����\{�8U��� Jk\�!ts�aR�V5��I"��~U��»i���[Ò�uq������5�p�/��%�*���� �Y��y̸54�ar ���e��,�U��>��@� ���8P��2���S��:�n&%jE��"��@7Q] f���р�N �g�����m�J��2�c������4� y� ��4� �y�Zg�Z��ƣ���.�Kn��57�`�9�\�[Z�O� ��R t<�N�uL7# +�Q,��0�O�ܔAP,��*:J��Dm}v���4��h��^7[�E�6n 8Wt���;'JeC+]%�8y�V�l�n�H���&ҧZL�G����4��o��73f����q��G{&�p���m���������A5Tj���2@�)��q��AD,�c��t�>���<L!�+P��;ལ�Y�"����-�3������×�����h.�[�������o_�b�邭�����'�F�2��"8�\�A���L7\`�<[��� ��LL���=3��ɱ�±>G=�25�'�p*�ʯ�����.�WW[�ϐݣ�Ӧ�M�CM�e��UY�D�B�<?�|8κ���>d�NG*�a�fN6������"�����O������>0�'<���O��j��?D~� u4Nc�),]�=C�L�s�m ��h)�+�M�LU�H�+x-G+�� ��#D9w�&� ,�VmB\;��q.J���|E��)����Js�ĩ��O�T� e�����-�,4�^C��9�7Q"з��w@l `R��zJ&"PY42nL�#���[9 �4�#l<��u��-��O� +���=��T���翹�����ݳ������q�����_����|��?��������O~������ڿ�T�C�rNB Q�����m�v� ɰ�r�L�)���d����մc�(}J�/��ʋ�C�8���T# ԕ\���h�4?��I����9YjW]^��(M�*�k*�V�|y��#'�R���n�D��w��"sRm{e\�����⯖� ����h�d���i?���kp&�� +�%�N-��Z�\��P�Zׇ�qB�4�' � X*@�8������<�a]+��W��6�x$��/��%�|r�)Z��oj�9�m��WQ�g�e(O�j��ر�>e8 +��!�KgO4'0рE}�J�C-8և8�s���r�aϾKF�Yz�KʶA#c׳N-�A|�!0E:�ըg-�αq��ܼ�#t�p��((�y��&����Z�ct�������;��t�q�>O4��ɛhZ�=&���,K�h�q�-�=�t��ع!IF����,����lo���ם%n���j E6�D}Y�1���`6�n�5�҂@-��f8B�>�7(Ko��RT|yB�4�����W-���jP���z�% +�3�GwhU�k��8��5�r;qs��<��,�%Gc1I�&���K=��(�h=�r�NQt������K#��U���`L~���ęZ�Z«�Lt,VSq2�m@Һ|��Z�g1ޥA�l��<��&�����U�)����٘v�����ݢ�� gSZ�\�gB�S19h�~NL�1����R�����91-I1��N�A]����9Ji&Q�Bc��]C�:[���6��l�2�.! p��ϓO�1p���y�a)�K���9��a��]�M���]�}f*�D$���0����L�� +Z�&��ŪA#�,$5q+ Ȗ1%ңA�����a�a���[Y�̛ju��X:��r�H�"�=���RގLbg&Kj%��%�R3����,A�ǥ�D�%�a�K���c����-t�c N��G���6,� 5���$m����Y�i���!l�d-�$;�$p������D�eV�m��;�bʅ8��Z0�R\�f;d����Kx+E����N@z�h��4 t!��������������}��G�ы� xx��pw +}VB�,�`i"��$���}�Kӧ�h���r|���Af�f�3��*���R����)����=����d7|dFH���ߚ|�F?�T9���0|:m� I"Z�qWsR�O^��o95_���ԣy���{�}N�wqQg +���� K j�ְ��ӓ�2�0Z�;=���+^��b��$�-O��s���� �gs�Zn=Z�F�y}@��Þ�ЉO��-�p-gk�5� ơ{���I�Շ�:翷���r�6{v�ٕl���_����M���q(Y��r$���v|�DV5=𬢈9h�6@n=���%j�=%Uj�Z���0W8kjO�Ʃ"J��zB$߄V�e�\`�R� �(llp��k�c� "D#�TV]�4��R��8hX��%J?��9Vh�\�a�&J��7G�����!�2�p@�D���TZ� v��;��$��qW���<!2�]����v��7�0�}@� �_���baDž©��Z0���I�hgcg��.��lJ�:,ъ�~�:�>�X�8���x9e�� �� +�T�J$�q�0��)j#ŲH�qMz� �t�{�kZ�[�/D#����O-�ߐ}��<�`�H��')�+W��t$�H�U@� ����>��^N���*}V��O=�_�!x.�4:�Hޮ+\�%`�rCB�Dq����3I�d���V�*D�f���1���K��� ^<!%�����us3��4�r���4o��́~ �klZaD7��V�N�x��`C��p=�2���������ޯ�����i��J��AG�\�O�V�v<�C��~r��U��znm�%��>��٩�<H��f�P:���Dp� �~����aP,`>�x�c�B� +�R��9�x/tI��,&��w�Iu���B�����_>O��' ��O[`5� y?��H�UX��}#�}�Ш�����"T8E0�<gU֊��6+bĿ�U +�o������1D5�h�c�'8A@� �`+���tUJ) >�N�s3��D�RA�Q�u�^�֠�d�?X�p�Ϲ�*8�Wx1gg�$��Pv$mOh�hD �@m����>"٩��k +�Q~�Ţ'$�s��Жh�;k ����cK֎xiXz�߁��e�3B>h�l-�x��Q��S���ng�T�� �A=�;���Q/ ������= C���Э'������0�͏�{� ��秗���Eq�0l��wSl� �<����0�m�(_x�w���V0�����|�����L�������*��v&��g~���,!eW�{ ܬ��� �Su5 "`'�<���C���� H`j�a�NP���@��?#Æ4���\��Y����T�Y)�(t�a�!�@[@����b��O�^];Lo�U{z��Giʾ�K����yB��B�<��ã�xJ���܌I�Ӥ�i���V������a\��M�۩����J5�������<�iD�%�c�<�/E�@Z4����P �<K�������_`*�w��c�b�92��� ��&�"t%��C������'��b���Ϗ�9������@��� �cv�F]�e� � w�yF�<�G���(�t�@����99��h]9*�mnM#����&k�-Qీ���z�����6Ks�B���&U�1�j^Z�(�+q���K���DyF5t��\�V,�S�����du����6o�g��@Hr�Am�w�SD3ej���Z�8]X������.`$[�y��LB���E�f�_{_V��EL~� iG����ٚ�$4��]��V-/ +k߲s��lǖظ)���i%cC��������?��,lTF!��sr�/�w��U��KQv��u�������W���[HK�h�����-A�{��E%�j|PU�!�#.���~e���q��k�ŏ�,���:U>��WTo2�џO���&�v����g�4�������0����������?�����'�rΙ8�K���j�JCy嶕9�@Q$��5��%��`�'�K4��Z�M�T��j�q~��p�Q�q|�/�")���H��@��㻢���r|���<�� vK�Mpv�<;+᳁�E�ԅe�>�l�-=i�,�lp���<z�*�Ų��F7�;P��E]��<˯��i�`^�B�"�=�ݠH�h���I�"���s��&�Q�S�䌐ݧ���Hü,���+7���n,?�\���L�x�ɧ�SW����ۆ�c�+aq�����%����� Q�SE*��b� +l�u�i�OӔaJ��<�Z������L2=���Ct��l���F�] +Ƥ@V��������0RD��gT:*˖gQ�#��;��3qR��� YL+�ET�ϲ�o��:��f��!19��ƚI�<���kӒ�%����KA����x1����yf2ÿ�2�O�3�(wTk�6�����5jL"[B��}7��>8� ���p��V��B=r��9�|�052���j�}Q^�, o�LG�Ъ�-�� ��3�\�;�fM� +^>�S��F�k@G��C������()>~��\0��5�,_b/�j�]��e�_�]����U�Y�則KP�b1���/|����t&B5`�3�����9'D�v����u�T+\��r(W&��W�U�;W�R�!3�a-� +sy]G[} ui� +��$�0m_¼��@!d.9�h�=���b0�_*uy�<�(�/�>)� +Ҙ�B���Y'�<F�D�6�5&�7]�O,=��jYW�0��g~�H�H�s艈�e��������^S��1g�d+��.��r����xPK�Xh��*�{��{���)^??�kʅ��E˧�W��:���:��m�|P����"��Qԉ�ҩcQ�\���X�N���D��R����cw��������."ϵuAs͗���7Gk��p��� +-�!s��L��\fk����u"_�*�9BL���%��Eu����%w�a�X�8�JX�ŝ�o���1�*�\��Qԙ��o�\r7lo�kV�GÖv���K���[�BJ�����x��Q]���.�\=7��z/�ݬ{*:[�) + [0w��E�k���:A*�E�N�}/��A��aS��~~y�HK�}�p�zjlG �w�����aXo���ې�˿��0{��TB�M��&�iᡣ���'4j�Ҕ#�/x=�) �'Ʀ�I�#�*! ��B��q����wX�������#yIs�� �k�?T����N�F�y��b��*��XFύ��V�{t�y]=#`K�.���64�����.W�;��+7�wJ����Fc��⼚���ԮA��鉥�����g&� +������wLh?� +�������;�qד�]���%~V��"�t +��Y��b/�����>W�${�g���nuv�:���2��^|���|6L�Ǚ��beg��9�.����<�NH2/wE�W�ݑ�$��������s�����_V��ѐ�F�o�!���mW��\?�dd��i��z"M}cqT�Jb?��lT]I��b�8�ƃW��V�2�ڱ��.Rg��@��@�툀����W��Z�w����1��J]�)�K����а� +��7�qe��� ���F�Y)Z� 6��k�)��ۉ�f0����!�Ů[���݅���#Z���M��y�x�R�BzV`74�g�.�]�^RP�$�e'����f�@�!C:�Vu���g�(d#�Z��g�˽u��U�C _���Y����N����GӠ������l��u�up��c��<�wz��SaXB�W ���6r]Ѵ�e�����k[z!�>"g������ �XԞ�l���ˏj'xP��f�~A�3���Ϡ �#��[B)ƭ����x�cXFD�6V����BAW��|��XG��؝MB`:(F�%B?`��EC� �3��_��iw%�"x ���q��u�L'nA�L�)�+�K�m��+�W0���Z<�_�c��e<��ıD�@&��&���ȋLw`��<j�2�7G4}d����(vLv=�X�X��x��W4��Tl-U�p�j���b�ze�O��ÿ�m��XGE��Q<������7�(c���&sѐ{fD�:���e� He C^L��w[�I�>��Ԝ���>�����ORI�w�s(�����!��\ӟf����;���BѲ�W`:Z��)Ѐ����fW)V����)l�aԅ4L��ɀ�3e`IF4��夏�g�[С�m���N���BYR�2�O�o1@h�����̟�u�V4R�'`�ECG^T�����{���(��GEȂ�Y�(S!��fئ|!>u��(��`����+�.�M��So�ʣ���g�Z�NPm�k������q�К�V8��\g�|��i�ww#H�:8�!�E�1R$N���7i +Ě�k��5����00-����Pܿz=�dE�\�pUU�IE<Tp��3W�]�4�5�m>+�M}^��-��fx�2B�+t�� h�E��U�Y���^���ȷ�MV����jx +�� +�$Bi�^O�V������`��$�#[M���"�~�yִA�c3�#�Ç�C�f'/\�{ +)�E'p=q���L�m拀��Q�<$Vn�lCGDy���H���P�q����"'���t�,?v$��v_�Z��R� /��3�@A�vF�&g��N�iH\�}��C�f�yV���n+���w��D�Y�O�A�'��l���lS^Ěv�Ԅ� ��L # + +����1Q���@�qF])#p����I�!.�-� ��sm�g �2b �wf����q� �s)�ň$z�9�Խ�-�,�V���sx3v=�w@j����嚭��R�� �m��zwZ���VT�So,����b`NQ��{�C�Q2@�вE���ϩ��g�U�AU�m\i����t��c!JH�*:�����4�8N��Q���j��s<��a�J4=�$��/l��9����S��I��%kM��{�|�9E<L�&+��/���p�L*�)?BP����~�~|��{�I�Y.UL�����QTo �+$�!�Dd`F�d>�A�������� �K�_�1e"�o���{V-0������ȪD�-Uo�E�A��~�>HlΑ��.��=�^h�!���$�o�}���bQ��4��oK[�I�姆!A�ƍX��?�� ffi��;'I�d����![��#��4��ZT�����n�ER�7<D).�(���B�bk�w�?������6-9�T �yi��#Y`�R�����;�5#����^��'���&���&����2�D3�-�1(�O�0{4�'4(Z�PK��cD�{J�?g ��I{��?�z|}��3'<�h;�hK��� ~�|$ N8����fe�uԵ*Ю�0`W��������3yK_�N�\��h�3�~�TG�ev���Z� S��_��N,��yE#%���%�[{MQۋ�� h� ��nD�"��$���1:��O���JZ��;R�I� �$�P�=�uޝ��E��p�6�� �4�Xx�@�Ii��������i�eF����V0�8 ����?#�9��ٟe�d/-Н)�m�T��`"�U�����Nfg��_��l��&�S����@5�g ���E%�M�����e�Zf*�PCfj��֑�`-@�T���L �9�j ��"��D_���Yўc��n����踀�C}W���k�� +�z�?�C�ӝz57��c�M(���h���X���-D��F��oK���ᔳ�ι�y(B �0x7xܸ3�?6.�x�+���&��8��X�q^h����J�$w���V��!n�g�r�e*�jLZ��]G�G!�'��yӔp��<ÎI +�Y���?����-�_: ��g��NgW��)�,��=�"�/�+�m�ژ��iaUl3̗���EYM ��5���X/T�^}����+��.-n�˦�i5 �yA�"ƅ����p����f��T�FΔިޫ����#Z�ӝXQ 7\I��!�]�Z;!_b5�ݜ�vO8-����d4aϧiZkKW ����L�Ay��M%l�y��I��e ����@�#v��p�(�U��l(�-T��a�Ԣ2�1�k���������V��(_�0��;�E� + �$����5��fhB�Q�߰R_��٤ +0od|�������ս �VP��_~�/Gh���ư� ���h)]��<D��C����7���t�x�d7��m105Wzv�af���<99���{���4+��>����XK�\�KQQ�+V�}s�;C�ܝET<���3��W�(�����WҢ����Q�BK���p��\"��X(QAQ0 1P^|��Z��F��ld��v�����C�^2���&㰋��c���Ȏ7e K��㤊�)�]�q`,�BA�L��,W|�Х�Z}#�T���/D��{�K��k*����"�x\�Im�0��A�0�(>���A,MY�Z0 �~� b�6����zŤ�#&(t�(��ڥS Q�Ne�U��>�'*g����D�v�,�em����z#�˕�@�u� ��<c�E�^w.ֳ^�)�R�E��#@�U��~��D�t��˟$���$��I��9dd2����[K�z�9>�W�,���ʢ3N��$��z��N���KlA�9�8=�bT���{V%��� +P����|7�f�m�I��L^��� Ig�<t�����V3Дx+�S��쬸� ��Rn-(���� C�^C��O +���1 "ʘ�� ����2V0ʺ�����A�Z�'f���YΈ���3�5`Ra���Y�v%��^v�7��uMC�F����-�Ub%�U�����bY� ���̍⾊(�\���$�SY`ш9�jHu�|�o��y����� %�ޞb�*��;,��aD��z+@��H"�!#�d��I�i!ا���%b��?�frA��� ቮ�]3���u���V{#J��5������^�^jh#�V�*��L^d����P�A���I�w1�v��~�-�P�69N �^Р�43���c�*\Df�?��_�߫�3���0!���g�s��:a| /�97;� +pƢ��� ����6��_M�ϔ� n��yr5�?9x�aw��K�l���c;B����?��+���W��u[�Ǿ�.�}����QyĐt�S� Y�W'��sA�t��|I�=8�s�5����U��1��L��j��(��J�j�At|��\<�k�=8o��W`��¤=8��z�y<qȈ��� ���J}$�/F�����+Lg�L0�� �U���B�Dp��Zc���6�1�Kf5y� ��k�]?W�u0/�ƭ�6��ޱ��M+����;!���~��r�x�55BX�2�Qҷ܁COV��#�[V��%^~�(������(��G�B�:,��/�*+&� �W|�����-�D +���u~\Xs�uQ���FG���t���X1�K�{��zԁi�2� ���Vg�q�_�DW���R(Բ����Dq{-Yϒj!fp�\�6�B��K()9���G�D��wd�[]�ɊpL +����S�]:l�`���- ��4��L�Eҗ42���o�A�OkS�����R�#kar���ѿU����{eȮ6$TGc�ͩ��>4$��@�6�� ����#���`�9K�֭�U��!��d�Ʌ��pk�Ǽ]1,�g�Lw���+̄�5e �C��j� �'w=�7Q�o!��{*�7i��_�)��[c^�s ��D�L.IE�nj�Ni*��\fd����*��=���b�)Ηo)W������u@1P�㠞@�.(�g�'���L��.;sx�_J��<ksl�I +�9����Z���5�88EP��*5��T�_w�M� ɏ���� +�f*�t���\�W�ux�8��u�P���N����̙�v�߹�B����� �ԭ��hp�eǥ��KwWC]ͭ̎��s�����l��@�'M��I�/�bn�V��5Nf;L[T������N����b�����A�S~�u�7��=����L'U�۷݀�ѫ�wYg�\���p��t�|ʽ���� ���O#�f])N\���G�wa��e>R�I��f$~�=���Q]E*[�j��?1�'�r��}]��~���, ���W�(w�Mt��D�y�^a���Kx�����{(4~!�&�,� +|��L����w)R�����^L���Ki�����A�����{���x�rw���KwU(��V�M|}�4r�g�.��lo�� ߄��7�w<%[\ +QIFE�8���fؼ����z�ǖ�x�M���] Rc�k��H1�r�Q�!46�މW�6����y&��Z�h�:�|�!L�0��8d�1qW�4|<�̴ ��)C��L�Le(pɀ��xfv{�#l� �q�d)����ФϨ�D�3�G�Jt:b_�M�-@>'(�z���~�-�Yϑe�MQ&�N��y,HF_�����E��iG��+�����_�x�Bx&�������� �6��!���� ӆ�#����DݡPrt/�Wڑ�Ҏ��Yp���l\���������)n%]!6]$�7|0��(���d�')M�3u��U��(��]pƫ�D�y3ha���rL3̈́d�*Fm �3���Z?&�T!4]�ڒ#�-��Iqר��u̜�J� -��-�@]��a����n�6��5A�CF�-�q�)�؍O"Q�X�8t�a#�a',��D�ww&p+���4�`�S����ԙ�K����2Q�Ta��xJ}�F�c�����#h71�" d�e�X�nr�Ĉ3BR�#�_��њn2>#OW�7���G�ls� +�b�ɬ�L�����!��59�P��E������ǘ�p��jP��\����/@���xi�)d��t����m�j"5�D��~��BQ�T�š�%D��T����n�\I�$����� ����A��Y�9��I��;Q�)B�ѯ��Т�x���/L��S-7n�L)(�~~��߰&�Q��O-0�j����|v��>%�=���MLc�!Q�œk�Kn��_c�g�Q��@��C�╇9�l����2L�� �<C�Zl l4,������m��-�[,�{H~�Ū#N 3���R(��'�T�Q��jߞ����y��5bQ�xs��<*��ة����u�*�Q��7���|m��>�c��vl��؞�+����BRB�v���mťB9}��VG�W�3h�#�gXS\�-h��]��{�,��e�" t�ZP�l�p� � +\J��(��hTu��w�M�����!I:�'� ��:���{�@SƠ|�=fDI2�����q)q�$�[zTn���M_}L{�̶^�h�T�;�9�JYQ�\��gcb`�C�7p�*�e%K�����p�X �|ã�i�} +�#ۻ�r���1'�Ś="�U�����4��W�w�jV~%�#��{E�gS���>�;��A�G�l���9���#@71J�ց��r�a��K_����b����Rpp>f߉d����lX +p�zw�c�(e��!u:-;�k��6'ˀ]�[��\ԲQ���4�S� +]�xY�`��-J�8�MMm�7U�F�D���$h|����qfZ?���h��_��F �� +xf�9�� )��su����ݝ��X��(,E�)�J�r��`��<K�B�7�O}�rR�1���uP���Bn�����!/,��y�bt� ���U�f��6�[�X�҈�G�C��6lO�=�v}͘��ݎS�6M84����a!�:�D��$5 U��u+���:��/"��u +b0�G&��oz�"�PSy�B��G�k���Y��Ώ6�#�EL�x�����7!�����Be��� �`���P&�q�"�0c�ݨ�)���Mp�b�������*��H4/�� #«�}|p����h/�a\B�|�ˠ�O��B$W�>xA����� +�t@�h˷���a�OQm^b癬Q| 5m�RQvJ����Y.M�������;q�Z:U���^�.<tr��%��X�W9�=�y�u�K���_���俿v�\#��� R��-��A���-\ �FK�}�zᰶ9zX���J�1�@=�C�(uD�ȁ�Q���v��>�O�匌��bHvӷm':i0�iԸ?p�u j�����q��;1}��� ��d,�P<MV� {K���O7��*DF��$��Ō.��M�)����"34���?R�ډaҧa�i���J��RO*X v[�ϼ��4}�4Q�3�]6�H9�.?�Q��k@�<+�4�roŔT��(�$x�%|�����^Jo� v�%���x-�h0���#Lkp[�;с%��SJ >�������#� �,W�{����d���w)z4.�"����������-��,�/�rSqD+F�P�i�n!=��R�&����%�6G��,�w��e��e�Y� X����S�^$c�� +G*���4{�+v{q%$������Ҽ +p����@��*��p@Ϯ�tR�G�� - S +ϠZ�i�EG��<�T�M̨���v���rpP���/�P�GU)��M�� ��,�A��ρ;����V���'AIּ�,���х���G�t���f�9���n 5�Bu<a��g�GR㾈���E5_ԗ4����p)?�\o�t�%mR�c��Z�`��.�k�M��.Џ�z9��x�,\N�}}�Ag�,��Ɯ�$`���Q��@~����J"����Q�a���2��]<J�S�/CY���tXW\G� V��CL�ar�P���)2���}�`f�����x���ů䅫]n(s��ZB��Ԉh�*5DX������B�Mk�� S�]h]� �L#h�.�`'cу�-�7�UK�F��I$�������+��w0 �e0�f�u���yc�$� K�'�����#q�e�(s4�b���f�E)Ȱ�B1�c�z��:ʸoR�ps��P�<k{1��Ж�_��K���#�uҀN��Abd�xnOpuJ�}+�َv(_� U�6����G�.k��s�����w+;��B^�(��y:19��%�����PZxG�E��~�_�2����#���J����am,.H ��` f��@� <hv�glN�ȍ����r�����̾�y�k�}f �`�t��^���=%�թ�P����t�n��Q��Li�YH�F�9��ۃ�Ŵ�L̐u5�N*���6Qb�L��#�n�5DŽ�_�auVB=�}��v%X��/n�V����]/4��5�T�OVc��B�h��eV�>(7�;�� �έ��9۪��S}��h��LC��_��_��H�P3q�y߲�@^c�5�6���[Iɟ��F�0�����>"�㸺��[�hEص�9G�N��տ=������ �a#@}���94G��m�MP�{ ͚��i��2\V]X�I����nF^R�1�'O�<�F��F�ج��H�ϼ[WK�����;�#�ђ��3�5�3MAc �̡π��%onG D�ѐ�s�nƪG��J(�����Wd +�Kyٳ� �ݠ;]x�½W>��_�-����u������S5ZWr�A��_m����&Qt<i� +Z�8o� +۽�0�`�vʝc 9cۅ8�<#��p��8���U�O�=������*� 4��;������9��=Lŷ]��j�S<��Ok�f��1\Zx�����z{]��ƾ����|�H1?ϋ��9�*1BL����ȸRAkq�"/����:�5�(G���v��� ���20$���^��s[��͂����`����r��h��4��84%�����J '��� SH96�X(�BZB�PN�8�3t`�ݖ҄�IS�h��Pd�瀦_�X@2ZbʉO�ϸtP��^������'"�/�-4Z{���µ�p�J<�*u-W��h�B��aO�\돈�sj�ۆ]5��y�Z�;�ҕ��)�2�����p ��͎�dU�s�P�@j�_�3Av�9\�� g3��<�)Y�G +M�41s�s��b�y�䢌��������`P={r �{x@JhP���&�)#���]%S��������%5���pD)�a��J:c +I�|��x�F�Oa�P��]� ������:-�����R` ��'�.������f�B]��7|���h��bP����U����P�SA�b�Z�Ф1�2��E��B,��W�ܨ,�8(���p?`�����L��hHZ�C#�5�4 Q�$�}��e��6�PX9��^Ӭ��L�I���zԁ9�PƘg+�!钭�ϸu���m{��(�M�[v�Hy@@I���t�`Z^�(�izP����%�lXV��zv8�Wr�e��E�)Cq�OI��A���������h�a�Z�U�lAi�Y(���F'D�ݭ�ݭ��σqͨku��J�I�'�+��%�q���v;�i�ˬ�1��~�r���S��Hѡ��b'/F������qp�&�>_�¼�e���aB�h{ێB��]dH.�o�Y�@�a�f���� +�{�����~�^�Ѓ6U���q�ŐX3�O��}��~��?��N���(VA����u��f=�"y/��C��I�k�H�O�@l�;ܸ,P��`�"-)I\�$j���{��S=�q�U�;7��;8�x������P�o��`��{�b���^0�/�\�[��i+��6����@�d�-���Fm������������|wt���Ԥ���#lE�:������O��Bx�b���+�R8�/�����H��3�!�oA~���A*�HP�X�~N.��*�+� + ���3��S�PE�_�t4VH�� �+0��"���?\�y,�!� +��l�\�iŵCQ�#i�֧>GU���-�w�,�B]�;���.2�E2���yOֳ'ž˸ƣAs2����4. +��zZθz��I�����g�L83��Р�����.r�B����F���ܩk��s��yd��F=Qÿ'�\�w�@r.��CQ�XY��� @��iI1�N�Ͽ���O?�1\�S�D� +ᛃl &p֊�;���W�!9GCVkR�4έS��yz8R�B��(;[����Yx���T�O�;]�$B�� +Q�jP0;K���CX�x�#T�E��#� +lq����;ST�6�*욠�����2j��f�"��nρ��R�D��X�2L���ىM�`��C���T�r�@�4Mg R�p�3��'���l6t���9B��4�K��c���"v�ohn�Vg��1�.R����B��M4a�S�=?{Fn2e�ncF���{'b)�< +G��0�.�f4GK 獁(�h~�x�{��gE9t1ϧ#�!2�D�ME��X���(xG�P�5.�Ar���!W���<q�Z��4͡AS�/�G!J�lAY+Pq�"�k�Ks��A����1Um �]:w��^����.�I�[P�$�tr��f���r$�u_ɦ���`�����|�X�D���dǃ}���� "s3���f��؞����aL'�p������O֎2�y(-��q@��� +�{�P�] +�x"���]5@4�J�w_��sP�D�o�����^2�2��_��_^��� �Jδ���D�S@J���֖QBD�z5��|��jo�Oa��Rv� T�-�3�������'l��Pi����,=\��N�CI��?Ŋs���Y����/4�8^j�O ��p�����K�)��K`?� ��R�g����eؑhPo<5JNL�/�(�(L��8�O#�l�N�"��5ơ\�]�P��xWH�����:-3a�gi��S���%C�|3�TO�^¦%�J�wY��/,�AI�.>?���R�*-�ll%�'5ʾ$��\1N�qW�|U��;�.n����-���"�Ĉ^� ./��� ���UAj����`��ؽ��#�JOT�j7���z�,� +P���b�ܦyG�1��ci�Z{��=�E��A�*a�ݺ|J�)/�!���/r��C�E"E���| ���z@$+��Yh��8`3�w%u��<+}:����Z��H�@���9`P�$��H���Y��H�3[��S��L�s��~�5�*���h���#�Z*��"V� +�t�ie����WR#�P`:����K��ҜQ�����C����Q����]�J Y�:a%�pLd�aB� ����`���P>翸&��;;�M�/ +�9��t���"`�-�t!�9��^[����#試م +�{7<)��U"�d�.|�Uj��)9&���}c��Ѱ�D� ��CT�Lh5~gK��W�� +4<@� M��|��$ː��3�$��,¿���M���Ð�����GⳔW8����ET�+�\ +,��B�QlqD<��/�[}�K�.��ppW*a�*�� o�m�s4�����w�O}uUB3��+�g�TR��$ ��J�s⮽�5�A��;6���C���!��*^=�5ꬵ��ĄN 2�^�C�_��xP�Ӱ���2�����t\Z�<��v�=;��<��:Ob��+�5�~�����Y���KU6/D��e�1N���Ѕ:__�r�������?�NL��1���'@�:���x��r� +�|a� I5`_T�D%��z�،^x�QU�{���ww��2'�}�����)�s;�Q��E� �B��mC*��;��i�qN����2Rŕ��X(htp�W���c��&�Ҧ'1I�?�g�S=��%����S��k?xKRGH�'I rr +9��x�bs�h���H���a�8�c�� ������R�S%6��E��,�����ʸ�C�&zn�T��?���O�b:�W�X��i1�P'�`�Ӝ:�`aEL��:��כqS�$���*.S��f�T�>8}�f��(�j�"��:�tj#�$���A)�)gX� iT�F`0!�U_�z��-Ҁl�k͓���]ό�@�5E����^���'��h��d�a���Bze�mf��]�4r�S>��̈$�Vb�QrCRV�9\�E�������!���9��%Փ��z����㋺�=�jPW"Y�)�5E�(�ሆ[/�"�}F�b���ӎ@�:8#h��=MׂEB��U�i]�3�{�5�E��$�[�.��y���ސ� ¡����: + ���ɺ�/0��_r�� �,Юc�ћ2+_�@�7��XrKh�V��,O�T�"� +#��[��f�jv��i�P�뷆�o ���M̠�'.��sZ��T6��@����>��}���V�Y�)Q� �y{�;V���@��0c�3� �@�U +�*}DwGP_ܒ`�$g���Fr"t��_��hYC��b��(㞴o B�# �V`"7ڷ�S��A��H@+��:1���H���&�)G�]'z���������m���l9\p�P;L����gG7�����_�>��>B�E�hE��?�wX\��x��$�g�A��Ӝ +�&� :�� +���)�Urvha���1��(���.\Ik��:M�a���б�B>3^�b���t*�=<�%��`$h�T��X��!����$����1�>s�ɝ�j03��.1lb�) l�( +oͻ*����y�i� �&ן��@�<r�����C�s�j�Z(�,�Jʄ ? �>`*��F����n�+Kh�! +�=�Ib�F����'��C����q6�z��Z̘v����ֻЫ&c+��i��L#t�.�v��^��<#��b�v0::� +��HT�~�s����f��rJ��K�e�Tղ�a�k�i8@��L�b�ӌ�:�q�w��0%�,N�[���g����5˫t��4�YE2{��̸O���֠�ͺ��2��:�w��T�θ�e�u��;�q t�U�������t�j��a�>�J�\}u��S��1fJR�J4�a!D�^�����j9^c�*���&���$f��<Ω��P����w���xp*Lg\{Pg��I*Έ"�� +Z��.SL���\�����à��G^H5x�9�g���D��f�oY=�]_ڦm�����a� �a�������]�sb��U `��rR�(`0��l��� +�Z_�~&����ܛ�p�.��a�Vt���\�� ��N���'�������ش��ϖ����4y�b��ffg;EIBƈ#*,dh�� �j��p̈́u_��.�@��������S���0!_�wM7��qP�����!>O;Bq�hQ��_��_F�eͭ4��'����� ���s�hZ�i�-#�~���a��23��\�X7�#��? ��`JUe)6�D!�ę�q!��Z��wi��k{�6�8�@�fD(2����$��l�B���' A�C;�Ũ����X�V��Ļ#4��틽W +c� +�d��?(�굆Z�݁jh�&��;_��c�n�<%����y��~`E.A��:y��q��k":��.I/k��J�@k-�G����,Nx2V82!�`K�� ��l�Dc�W:oD��������p��B�'~��nn��L���������-S�ft\`4@Pp������6��������m�q,���׀�s�h�A������Կ�-S, +�������k�����7����� �w%�T�߽�o�����lH��iE��qY��sk���M���_�j�yf ��(5X���oQg�Ҧ�Xտ9�c��S'pam�u�B��Jމ�[�oV����{6��Q +��H&�XDA�T��n��H�Io�މ��i��\������Q����m)���\�$�E#BA���D�)�u[��6?��{�#]_Z + ���� +Y�Q�>����&�`�@��$EzVp�0�:#�\ť"S���Y|n�nT�+�9��~&!��D���9G� D�Cg�|b�1j�Q�`z��f$��� ��R Y�O�P�q- �3�����������Df=���o�-�Lc���-�E-p��7Hs�W ��\���ݰl��9O ����6aj�� ������� R�@�H?Bo�3�k���n��^� �� ��%��1��Ic��J7Bh!�}v:�0+�:|�(i2<$]|�2�2])2�pN,t���Pc���L����la�Q"-��3�_F �Zw�%����<�d��2�q�Aw/�/P�O�����ޕ֏��]����Z�{I}�5��ζֶ8{�lv�Qړ�W.�T� ������,P�q3�M�֊����<��\[xcb�'|��LΒ(�`���X�C���)��O�z���J������H�"V�ОE�/b/� ��Fyd�#@k��"�K��t��MD�AQ$��˽Tj^�z����M�/��֢���`�l�B�4B8�Š�p%�Qʱ�C �� ��>��K���?����2����:lrtI9�4f�M,�#T<(�@�t���p�<,bK^���J��IO�j��X��{����G"�x� .R��ݪT�X��R#�F� w(�B��Uu�,{��� (� �ň��X��=o(�����%�e���?���Y_M|�Yt��B)l������釚��(6T�&�sh�ޜG�kˡ�b9���I9�x���j>�U{֪�v��S휰���р\ӈ]X�'�G !��|)�Eh�S�?��:?m�W�&~�0���p���Y�W���{XiG̻�{X���s +�� �&/sN('�B�p�, B8ĕ}[���`�1��M�O*%��a|�|(�,V`�t 8����� })���5hߙ)�Ru���Uo��ʝ�{��]-�;I��l�Iɀd����j7�*r�j&���,Q{}W�gw�����^�����7#PKNb̦#�ٌDOG�k���w6$1_gkv-�z���.��rlD_<��AU�ؗ�>��xߦ���Cg��v����`]�G��h'K�WeI�d[��vOT�@G��A�=�� �Ւs�ea�xG� 2��[�K�>r�����T +dY��#�Kq|��<y�o�� VN�i�b�dq�;Q�@��M��R��Xo�>��J��=厨1B�����Y�U�iBK! �w�x��+�6�iK�o��؞X�gY��1K���9m�"c�a���? +7o�"��%�K�ݨ�¶�ج��yS��w9�B�'N"�a~-=��+���_`�m`P]��Tlu��d��{ajNy�L��6��ŕ���p���.�E���X,~� +z��U�'��X�V���)A��4z@L���9��}��gˑor�,�)�O4W�~��y�L4���Oؚ�(�kr�7�Fk�)m�O�☦@��$�E����^.��z�0��eԬe�^���맑]����Sk�D���r�n�����ϢoCa���S�j1C?#[�����σ����̪�"��*�� ��[���hθ����N��D3�NU]�E +�E���|��_Tq;�!�<�(Z��3�:H���P��*܆�Vz�tb�y��兊'��'$�>��ئ� +��t�̚\�����7|l��A�,�&��v/����fp��Z!15�͠��Ϧ�n6wbF!�'t|9X7,� �b^̍��`۱��q��A���q���`C���G��0nӆ&"�|qs�g�cJ��[�'� J�����aP/��Q�R�t� ]�?�� �nx��F��Q6`���P�����ǰcC�*��-����N��W� a��]��(/-�� � ��r3�Lx_���j7v^_K�����Os���s[DqX]��'ve~�ʄC2��m� >%Z�}F%��ֺ��,F��C�{(��i�`�O,u ��l�S�����p�ʖ���7D�^�1:-�!J�+�*�Φ���q�+����%�z}s�},~�m�C�s�����A{t�e�3��K�g+��-�@�_|�r<MgҼ>;������0��q�BVX�< +�gѢ�P����iA���߂(YT}�3>�R�7�@�OM�Q���mt�< ����a����v��Úbћdq��ѠYp9P���r^���x���̒�eĩ��_P�[�.[�������H��;g�T���e�L9�vN��Ip�Æ'&��y�߅b%{q��7'�CC����d�}����4�O�4'����)ܙ�q���8q +���0�����wdBβ����I���bFu裡0Z(� ��8���t�E0G"������j؉�=�P�jGp$�ֵ](��X���%;�jH�2��S�f�f]�T��t�/""����'}>�&al�x +� �Fr_u�,�w��7��PM@)N#Aׅc�a������;Au�s3D?姴����r�`uWK�ov�3'V�2��8I��P�ip�j���vY'�r ���~�^4�9�I�U�D{����1�� ����v�'�(/{#�`��K������M��o�dA$l��K�̚����\�T��x�_F���T �^�����0�9�y������~���l���y���G˖��/nb� +�.o����U��qa�8|��WX�O��q�zV� ����>5�B/{sM����֊7����#���Q}�<��d@��hd���f�ko�E�LG ��CA/.��~� -����K!,0)�$�3���y�#�Y�n�fz�x���{I�E���9Ut��w�"�/�?hr�����dO:o�Zo[^�x`F(��P�@3H^� �y�D][���-� m������� �W���2�#�K��Ħ�>9��c�d�،���X9w|�cb�ƃ�* |�>�8q�=BH�b +(��X�bD��9��]F�J]�K�Y�R�R�g %�}�)�7Æ���+�$!�=����\�q��vq�����ӡ!a��OUz�:�x�,4uQ�;}J'�d4m�HD~(����h>Ln���+�e$������ܪ]���� �h�j��C���N:�ф�����)!<�#����UJ��T��%_�ˮ6����Hexy����{ �q�/���I|�B�%{��[�ФS��tW1����-I��k��������s��H��Ş�����-6���}�0Z2+�çp��� +�����(%�S�f4���|���k��>���D7tqҎ茱T�u%�Ǎ� �i�1��l�&�l3[<��y,oaT�^���8�#�Y4���<v�D��ri�C j�9O�Xԩc\E�\b���a����l�@y���:��}��߀�L��0�J����}�ܓJ�'kB���D)�>"pf_8�hJ��G�jD���Qc�6�:�,1U�OK���a$��1��?�X&+Or'>�����OG�N�~�ׯW&�E�3̀��-�7MߤF�N��-Ɋ�(DV`�)@}�_�&yyċ{}oeݷB��#���z�y�FcX��Aڙ�W2;xLO{��m�U6�|fG�i:���d��)���=F�P�K��#�s7_b#�P�B�<.݀����9x��Iz�ؗ W @E�lY���n-"j�0�����b��$�X��e���-aǵ�,-�$������[�ya�$v��z:����,��#;m�3A�� �h�B�� i�R�1�d'��d�x����q�r#KB�k�c��g_�І4��L�ũ��)���p��p��L$ƊY�H����j�����yt��}�1TD� +�O �mW���4 �X#Qx�c�ݍ����@�ۖ�״*C]�su�� ��J��/��5n���1;�p���M7��P��3Y~��x�g�����d��T����Ҋ�Fގs�xF^�#�#�ݞ�3N�C �����ߠ��rQ(���"Fm*�"�_��6�e6�t�z�z�60`+�-'��i}vT,��~���'�� +FU�* +�pjK�o\+�j���r0���^`�@�Z*����f���|�Ǻ$��o�AsA��L��6� ��Ģ����e��w�����_fhq.Y=)DPax��c� D�z��o�Т�ۉ����J���r���@MÄ�����b�^��&�%�'�tTZB�84�.�Ң.r��:=���#�P�S� *y�0��� ��I��QR��P�l���CR��A����E��/�'��}o�]���ЦF� +<zFCk���9����9"z>h�>� +j.Iq#m�o����T#�D���k���@� ɉ��6�܌���5�냅�w&�[M��c����fJ{����o�q:�MQ��>�x�u��xc#�nm<�M�e������0���yy���)?���d؝0�����S��G�����4� �T�hA�u��n�P�V�n�Q�nH$��B"|0��B%�4��Ϥ�=p��Y���� l��㢓���8�̠K��x��}S��T������ +BBӹ�U�<H��yo={ �bض�_\,�"��@}֪�g�ym�;�<�@2�։���M4��\�Uɥ��D&Y(�p�5J�����h-ଈ���:���F�\G��s����%)�g������t���������N�&���|��G ?��/�[H +a�B�'�������~�����)�3Y�;]�8�V���l�TH�L@R=�Ή�3�@�"d.R�$6����G.���Kݝ5�ɖx^�_K7�����1��a�Ě�P��P1���X?�)~j�?�.� +RK��G��E��ۅW�눬�<7` ~�*�s���^��c���v�f�����R��8V�ݴhv_�}RL̳�`�$a��Ѷ�\�S�w6�M&L����5�F��(="�q����E�=p��:�����JR�n���lC���qB�9 +�%\O�l��A�4��ؾ��c�%w��ޞϖ�#��٘�n���ПF��D4�J +Xz������R�#Y��̠D�mPu�@���R��v�����D��ҫ^���V�����O�|_�+��t"�{�;%�J�+H�l� o>jJ'���hfn�N�W����xW���9"}F<V���#�=��95ק�U��6����T��l���-���Q�Z�e�c[��R��4�=����T��Z�f��g�Z���5KG��J߬2�;�(*�y|ޑ$K��.5��gX���VM!\�U�_�|� �XmӃy��'jv*��f��L�p�J�"l��L1Be�3�T��������d0�3��3Uφ��K�; a�*_�� �tX#�;K��d��#cycYI��5��V��%��#ZM�[憻-��9�em"�PH��� f��V%�w��Qn3��vTl9k�����|�ktG�/<l���M�EA��umw���ݰh�}1 ��M��Qu`Nn\/�H@�%5��c;@��;ҽ����ϕ�VgS�Y��� �HCy.'��b�)�f����s �16(����8�HD��ێ�gA�aF�AoBؿ����ST���A�m�2D�vо�:��̙��R��Y��`�Q��*�&��;K��GE��4�'����:��1lij�3t]��� ���d�]����a���S�nY�#�R����؉��ǎ�Sf0:�ݔPLvB]H��B~nqZy=S��a�C�������dQ鼵$)q��8%v��k��+���"��j.f��RU�rr����O��MEd�:�$�Q� ��4�8B�N�/R1�eV��?�un�����X��u�������!�"+�����b��~������ z3�Q���1�������淪֣�1ճ��![G��&d���VU�<kgd�&6�R%�(�D�G���������hG]/���)2.�� ɿ^z��dDgtw�3`�NW��U>wo��Α���B�E���!�R�*����a�4Ϥ��a��%�wDVF�X���&m?;���?b*��hK²]Vo�|�����ҟ +R��|-@�� +2 �tDEC��sIRU;�/#!���Ov���G{hw�a ��4M�z��FG���ᗃg� ��a��k7F��=�=����Ī�#-��M�u�RcF��fF,�9<RIΐ�����3z��v�Q�@ќ�N~@]� �3%��+w��ё�SL��T^㤃I� e��:�_�.{̄C�F�eD���=g��^Q/=d��b7��c���w8���D�@���Ab�\���H\��^�]6lT�%ɨ�JY>+ ;��-F�|ZVK�:����&G}Dν��i� �z�m�V���SJ��x!�Q8����5�3�**j'K�����$a����r<*=�M��zn 8ȳ���uG"�6a~�оKz���m/�㉢��@a�oJQ_���:8[= &[��v -�5^k,�B)���TVA@����uA�^yG(r�ޮ�p�A�]x���8���Ӡ {�Dab�xՂBڎ]q*X�����{Mމ>I~ �N"�I�)T{.N���Iy���|K��"��.�E���EY*>�w@��)�P�/��?�QZ���% �n���}X� ��I����C��B�� �Y�H_����B�8�PH7`�ǁZ�7E��)���*�.@x5���-A@j���qs�t����f��4"��3j<v�4e��A���0����Q�lӵ�%�Dh�G�J 5p���� +��X3`��5q|meGh4�%oCn�BH�H�4�X�;Hi$#]������"��W��.��W��2d��X�����g�)hB#hB��ϣ*Q���^K� �=�-�/ѽ)I|���d��� +m�(&C���$`���MW�0��;��+j�@M��x��ojJ�.�;Q2� J�s���E���Hk@�b)LGX�Wc�yۢ?Ou<���$�bD� +��e�C4?��g�x��Τ������K�Q���R(�U��|k'�'/GU��]��)�6��Ԁ�Ӄ鏛�U��lo��j�l�Ů: h��n�:� �sN;"�=�S����·1��6��9�ʅ�\ ��rv�א��qO�Ihgf�;����b���I�m��H�OY�šWa��i�v��R܌�>��p%� +�v�Q�+��l4��W�z��jU�BK���AR 6��� �JY:ˬAǞ�ʆ���s��-@ �P���[���ON�$�0��2.��[h���Z@��4kE)$-�����c!U�E�`��Y1%T8��s���y7��;JPQ��Fz��6��8x){�vU�PWAZ��� f/�eX�Y�N�9+�Є�34a��@���)_u�)����ł�v�)/h��M8N~^l���#�ރ��ypϦ�t3�pC�n�i������i�Uvd��2�K�{`�Ш3�H�e�a\gb�Z.���p%��e�N�09�Cٙvj�:ne,���R��&����}�J�j]���j���w#��Q��]A���?NJ|Ҭ;��P���� �V����GL�N:���Q��h�V�z�gv��'q%�"K��L�#��V("!3,��m�?I�N�F� +��m��>_م��d +������J��MJ)]�t��W[� +l�=˻�A��R�J+�"���,�nj��%lt��L�s7,�I�t��� g#6ǀ$,M�2��5�J���HT�P�WA��1��é�Q� +�-</�C�R��=wժ���ɉ��D&��P�3BN��mx�0B Xc��Cf�����s�8�j>�ThV�>�Eԃ�>��3N�҈���}uQ�&���!?������ޑ����bH/�7�K���\��7H +.�)�h�"����A�w���>d�Zub��)U>����`Z�ZJB��DȨO]��#�1hlv0�%�Y�"���������F�؝-����X<,�bl��b��'�Z� �f��w��N�[��x���F�h�4���e8"�PCɒ����O��>QeMiZ9�x�>��� � �L��� +?���ji���9Ҋ�H�O�4�|g.����G�� �L��X6ň� ���R�<k��'\�yζ�bp��FK�O��[�����A��"���i��w���ʛ@t����Vt�ck�Yx��y��\;PnKuY#; ��V�{�C4Ʈ�>@�)b���q�-,Q�=O�S�5a*�I�]5���6��|��o�3�} xE��eZ��������f̝��/W��9� ���tM��G�qE23�飙�C����S�9,'��`���(\0j�\��<�wg��9�V�k������?J�s����"��R��� +l<���v��ı�� �{��H����z&�n�c��\l嚆�Z�O�`�A��o���%�>k�"Is���x��Y��hgK��4U�zlj$�H�3���ٕ��$��ɖz�}Bm�`�3�Eð:��<ּ�=w �5���6p�]#���y|e����0�Dz�� �#��e�$����W����s�T��YuZ�M��I0[(��|t�t�@� �:��uђ����0������C�9�^�34DC�0���;�M91�)�B������0�Np����2��D�0p�*�������Jx�Z�cs����FPG[�R9*PQ���{Ja����P�����z8_η�r�3ϸW�Mh]}Ĵ5�Ea[d�xh���(M������7��{#X�3�=3������bߨ��F��ih�E#f�Q�B����+z��=t�ǣ��\"�^SڧJ���ϕf�㊮���ᛆ�8e����1����N�k�{nѻX$��P���_�H?ޠ"~3zY2Q�!4�߳�I�j��C���v* +9�#�H�7Û4k$j�Vv�h���jh�gD� 04�O� +X�l�~�9;�����1@9�3�o�Ay���ىo���{�Į�a��Z��s0�#�ٜ)�d��Xvf��A��{)ᇮ��C�3 +mPF%��)y�2�)m}H��qR�)���,���c� +��_^5�ATy���{��t;�#� �N��w���w�m��5gI��H�^���0�aC�mZ�(����d�F����:��A�,�9���EG�k��'������*o�F����T[���{��s+~���`���w�m�+��鸶���v�g9��p���j��kJ���%{jA��t�ӹ =fzY���1��e;���w��$��2 �����},;�-�Uy'��:p����� zvjR/����h�.W�]�!�-��;�l��l��1����%3�*�\V�(f� ���{Rh[��"d�2�'�FH������1�����Ģw#X�;1�7���^6t?�}�H�s�:F�>�6���pn^�tn/�{�W^O��y����9!5-/D��C�]�f<���>B="2UE/�v@c9|��f��! +�m(ZM�C$X�_��0U��WT'�bP��Rp�w���S�U����LL����rS�5`F� �4FV�!�%L �|N>��`�!W�V��l���{+ؗ�0��mVKAm�C0�c��³��PK��;�Fh�Lx;^�:��ؑF(cqpN��:N����'<��B��LkXS?YSj|���F�����/b{G@>��i���#Τၩ䙙��:�P�b���8��8�����2,CZ�gj~dIJY�k��a��� ��!���]��%� ,*,wT=�qS�o�Wz����^ 1X�b�����x�>�� +]Bc�^����=�Gpp�;P��3ڀ'��z�#h��o | +�� �?0�6z��Z��MW��������bۑ�B\vB\͊p�e�e��-��x5�I�3b�zFh��W ���Y�'bn�g�Q���z'��V����,���(x5��#8[�~�D��|Ц��#�cD�OW0��̤�{��Q���t���i�!@�(=��L)��p��PZ N +�,oV-�çt}�P��=��F�T�r0cK38!U�;2F���ޯ�]W���ur�g`�#^�1-��<�O���{+9��6`S���|TX�)�m�Ø��xy�\�`����8X�E��d���HBg�:�8=�eG�x�Y���To�W�Z��[���j�U^��RP-`�j�� 7�a#(�7�o�����q6M��4i��������/���W�r���5p�<�?)�,���0�p�Md��Df��4����_�T)��� |`�~I}�����̃��w����0��9�,�i`���u���!����җ�P-w��ns�l�T8$e�995w��"�B��ۆ���9���F���5u�v@*Y 3:�4��?1���:2V�Y�(�S���~~��B�Q��A��!�,Q c��W�%�@s9�8�ɭ���OXe��aȆ���P���Vj����P^=F(xZ�"��H�Ȩ#Tz>vG����С�b�%�ފ�Z�(�hJ�TR��MUZ�#��%��Tqf��W�`�<0"'o/���4wc�F�Z��ֱ�$`c����� \�u���>$�[�x��243g�d� x"����&X��t�*4M"0���W�)}�!,�P�[�0����'�K� z�:RA�� ��R,wy&�ޚ�y9�Bu�":�TAПz6�D�'bTZF�[��L�iU�� p`\�[4�ԑ����E%jKt*�\=̪���^�S���0�O�n�C�1� I�ND.�Z��I��1;�`B0Vl�x�Ā��O��TU74K|���8Es(�@��aa��������g�|�f�����#���J&L$5o�U����ϥ6Ic�@d��{SJ�D��6�,^���H�ٟ0�vX�B��RE"��+h�T �fQ����h�P���jv0�!��ߤ�~=�;���8��*����0������륇��O��6���ta�F�H诫z�Y5�ۢLv++*2Ű���o��Is%�"�� �g�!����X��3c4Y�K�D�J ?ƆE��+���SE�b�e�`$�71?8��Ψgynh����&��:5�(�j�gz�E��P<O�uw�Af#�p?9�*/j�R�H�`��ӳ����z:L/���S`E��0 r���^(� z-�'!�����6$�!I#[�sq����+ـ�F�k� +��OVV�8�w (fS���)d���G���V`5ۦ"�,;,W� �{e8~����&����[�yp��UZG^�\�Y�S�ު�@ӫ�� +�nF����F�;��j��4u���ɾ.�մ�U������3������R_���A�������O7{A�I��+Z8j��.�^��M�r�B<������k�u�ء���T��aQF̶�$�_m��X[�!@��aH'2l�m����Eg �(4���`�i!�En�R��NIg1�R�<�aߺgvjq�;��F�hA낊T�Խ�� ����F%=����&V���u3� +!l�~ĸu�4��۳���F5���$7쁾;4ܢ ++RF�gv�G��H���8b1&}z�~�]?��_�J+T ����g��!��ۀ��#s�q�t:�t�%1yh�LF�m:㕐��P��ԍ��M#�Y�%���=�Iѷ�>��he���9�����{�8�X +Q�#��Re���^A���O]4�fp*T 4X6hF^d�YWU����^�-ԨNNӾ���h��v��/4C��w�Q^1y�v�B5��I�����ϟ�C�י&�PԹh��xg7�������z�և}Ɠo��Pd� ��t�U+�:��gB2�� +�EK�P'�͍A���u]����?���mG�D:-�d�t(d��>�g�xT�$q��K����4�zZ�0��DtR���IEݔ��3%����M7��-+�>�g#ps�!ﴬ@�PD������Q_@C7�ٟg9=��ܢUK��[�=%b�.k���pB8,�;���аNk��<��G��7���N|�--����#�j®�K��f�4w�S��?�|��] +��C��Ԋ� ++aEB}�G\���0�,݂q�_�XI�@���Q=��Z���ZR~h5�4�wGJ�ޯU�5���f�ݖ#9�,�{��p#������1�bQ��J�/JӒ���@Hb��(�(����[�#2q*dQ$*F�,d���#��k�����/5����v@5� +-�1]�z >kM��6�Y�jmY�ܧF}*�1�Զ�� �)y��k� +����U[�y��Т�%eq��D��'�Hi\�JU��p�F����Ma�a�`�i��Pޤ ���$���ٳ��#\�i��:��8���{��v�������2�� +�Xv���I����q�� /kF�g,F8�B*�H�J���J�@YT���\R�'��)bo�m]5��S%@܁�����A:Crbj���96̌�5��jvȣLe�'M@X6V0��1,��gG��>(�+���%j��u�b�+^n�Dm�`�W��R@����^�1b��0�lj���ˆ� +��e˿�3c"f�M�FI�=h\I� +�_�W(�^�I�]J;��⻍>��:�ų���U4d��8\.j��OM��ɨ�H&�Ѥ�ap�./ۜ�NZXr: � M����d����R��g�U����$�N��C���?H���%�J���w���0|���MH��M�����\PB5�>�`Q�7[7��|x�JI�6�c�� � �|Ȗg�Dڮ��4Ћ"U���͜�H�Ғ�- +��7��:�=�N_�gA�b�b=OAV��4�a�Ɔ���IH����F^�n�ā�1QW��V�G�ك�bP�:a��k0��l�p� �(Uf�L��0�o�4������͚VZ'z���ظ�!փ@*���V�u�8 +��p�F�@l�T�-�r"���� + �5�͌~3�*�l�I6S���N���Fx�fCl'�Ñ ��h��+: +}{����l��#�f_�՚���k�x + ũa�H(�c5�@�;p �~�����ьc��Zۅ��HD\�I�B�$��Ҭ[�{�pq$�'��:x�A�ݤV�����`jױ�n�F�S"5+i��TO� ��^�r�����T&`� ��-N��=2�Oq驤 ��$���5&�8�\K����, +UV�T��b��B��Pt6b���r��z�Ygp���)m�� ��.����78�r��`H�� �C8��<(4p�~�&@ ����w�)�f-T�"�V� ��X���Q��o��䡃�s�d2�!�AhE_�2�̜�a�"5�H�f�O��D�u +d�\M�Ji�~�dV��f��+���Y���P3k���]Xq�"U�����T'z���[�@`$�,��A?ȤO�Úd]3���Q-�t��;�I .e5��/���be �h'�З.��7\��x�� ����l�����%30�t���w��J��WZp3�I��w��jS'�o������ې�1(�n�I(�g�K �Iɇ���L-�>�a� �|^�cB�O.�5$)WQ�3�#F�T���֣�(|Y�|-� I���tP��(8�d"�����ECr���-E�%�`�ju�!Ax���BJK�Ls��Ry��B��xT���T��Q`Ϯ��7*/IZ$�j�k��΅Q~��Mi����l�����h׀�0~�ǁQV�b{���b�D��}_YJ��4m$BH����=A�^K:Ie�_Q��+���61 ]8x�TԢw�uOfF^S|�'��d ���Ncޭ�.�o��T��v +��a�N���s��xB/�<�C��Ij�����G�X%b!�w����-��ۉ%�E<Ռ~Ҍ�t��u�A��j_��B?���ƭ�>O�yp��狸�+>v������Ѻ�2I(��ƮU +�}_G����z��"��S�w�4�dG����8�<+��D�Bʼn��z��%����0`����뵥;�7�}�I����A�(�ʂ�G3e�,���rhj^��2�T�I��� �TQ�$���`��~*�*<����ƀ����Z��m�No������J�� �E�(B�� 3�+� ��Ё�9�/<^DU7RR���Bp�s�uʆj��0�Q�x��~2���F8 +d���IJƵwE� :X���:�dD�����#Z7Ք��b����{�Ea�!����PF��5� Ұ7.�? F��״��Ht�(;/� @a�W��~���=��a�(3?�$�����D�y���xҨ����牝En��V�9�*���RT*N�`��;��;v���%���/np�2GtZFD���`^Ȋ�'S��h.`�����Ӝt�Eƻx�}#,�Q�Ⱥ�d.b�f��b�pV-P����RD��Rv�>j�c�����t�_�#Oڑ�|�H�Кw�� +wp��I��p�0C�8�X� +l�TN�0~���ZL1���x���8a +�a�G:���q�%�A;?�`�k�RQNU��P���M��뭍"W�M�"���c���Y���#ʫ�F�Jp����EokpD�/����,�-5씴�"���U�p�*�����e�ړ��� �%�Bz��7�<�ܷ�h���"�/��2�Ũ�,y��LB2��M�T�)`�,N,ˀ�i!�R�7�<+�& T��Wٓ]� �2���J��;D�)jFCODJiL����Z��J������P+��`e���Ԣ�@ +�3�AN\h[�o� @�y(ApL3�dTt��FQ�<X���ڧ=�X�X}�)R�#�ᶰk1TD>i� +�a��Z'���~8U4e��4��d���1f@�'��C[�`e��WӉ7R�/0��n�/F�J�0MՊ��� �@%O�[Čv��֢<���cV�~�,8N��\��d(7T��u!qs_Ui�W��<�m��@�/B@�M���!JƉ1S�7��G~@t�ܭ����=UI�.63%>U�4*��ʘ!}�B"RY�P�z��8�مI��e�P��P�V�A���;��X3�%��K{�3K{�[ �O)�T�)� �B�5�:��uBÀ��A2�Ў0�7�"K ,�d ���t��1��A٦�� ��e[��j��F[~�UŖt~�%>�B!��$��i�>�j">5ETvB %�n������h�g��$�y)�e&)�n +���[�j��x��w���ϔ��6w�^7�l�Ź(����W���af!�A2��7��m�ʡ�OX�����Rϒ��BE�ۼtZa�Ȑ\̡B ��&h�r����x��+��KUW�$I� +:�T�y�pEq�1��H��>Lt`b���Z�����r�K6I�+��9�ZR"Af5ܨJ,g�Ty�;a����X,}��1�b.���\*6��{AET�~O���!IJQ;���q�a���&Y�TV���%�hf/�Re\н`���R%ڪ��^��U��Wv�Br����el"ѣK�D��"ez~�\*�בSm%|��Иh�(���f��h6*�D8�i�gj�*�Z��D4 �)�}��Uc���)�"�e��`'�(�(��I��,�=a֍����S$xM�\�R�n��a�s.^�սR+'�dh�_Gx��t���8c�8�@��1H���**.���IXQ�(�z�B��;�e1���聕� +X(�����*�#3�B1(��5`t� ߑqhc3��g N^� �͚�Qz� �e�����W��8��y�З��0�n{�V��Y�X�:� +cng��$�g`�`��+�zn��NĊ(�$iB��jҙfpȢ7O���@�'פfJPf����I��� ��,�N�5��H�O?8�=��V�)���cS��#d���R�.R�rU$3o�ȤP ]U'HQ�Z"��f�/k�I"жg������/:�1�Аg8 �NTv1#Іg�ݖR��K�Q=�)b/��(�d��p/(*�ڑ�={9���ǴDǽI���"2٣�c���0�*8�F15s#��v6N�<3g[$����i:4�ū)��*��& �ʤ�`�2{�Y��@}Q�MT ٣��8���2-�xGJ�Cn��L��k�̹c�����PI.�vS�lwBR�^�Q�=2[Jg�>����.��L�Pu����0� >y&~�����F�F�uk�c�̽Ћ5�h;;zn5 +4CK�k�WKWdD:�s/��yz�a� �Ңw�k@g)��B��T!Pe]��W� ��l"т���KTq� �&3C�F�~��dU���x�~:�=��q&/k���0K[!� �C+����t[uP����9$LQ�,H�1/�rˀc������B#������&���jT���"���< +�a��aZ�h��d͌+��$� + =��9Ec'>M�ؙƥ�P��-� HURta�����`�c��9H��t;DϬfBZX3(��x��NA&9�.En��A�,��e ,�k�~Ŝ�DI�츭�����b����"�J�%6k�p�7NR�7���(C�"�8Ѩ|P����{�XB���asUQ��̶��RN2)B��bD4���d�Y�����O`�R��$LE&<ur��T��:1�ub�P���Y+�^����!�̐�����ޙ��z)M�C�l�M57���7S���U��@#`+� ��*0&_��Q��IAz�3�Iz ��4�0�6 �Q28�I���(�Ѕ�ᓗ�-Fd�Q~h�2,�SIm���d���B���RVRm +J�ځ�I0\p)�^���R���6;Y�i*(�j�XG�b� ��;���M�q��Z�ܘr+�#�?l���3�� +�^Dh�+Q!�7I�'��?@�ԇV�yQ����:���E��*/3��!�X�&7��C�h,��#���?�w���RS}4�vP��aq�����o�>5�Fx���?����|ޤ����l�&�,3�w)�k��Z�Y���J�jq���N��u"�lh��њ���:qP�#E�H���8 +\����uP����،���\�zV�:s�u�|�z���,� �z�Dq�t��%���#Խ���*a����6��\�~��RkBp��lU��w�8*�(�yPN�ŹS�~�ꀋ�=�T��1��A �A��$�� ����Io�%� /���N�B���t!l�%Ъ�d�U|�4B�!�t2�荑Z߫�C<9����{�(�2K�lB ]�P���E��",f��qZ���.if��q��b�(W�o�t�6�4�s���_su-dI^�ӌz� +e�,�X��u�����CB�Q��#FG{�AD��d='���!o���[d���K���K�-D�c͐����o�K��Fdk:^�g]�dI�ɒ�%}��K�f�7Q���=2�H�Xj����z1�z�����o�#/r��h[�V-X�x<��^�����Db׃`W�MV� `E��>��ڲK%����V�߹beXe��{'�L�&��'��EH�ß�T��<�N5��������J.=41m%��& j*"�HY��8��8��CIJ*�j0ʳ��_u"�y��h0i���ROe����p�ԟXTT 54���X��X Ҏ���~*�����_��:<3���� +Ey���S���dhN��-� +����k��I����3��_!�!8< v?��D(+O�m�P��3�g p�Xܒ���'d�^h��4 .�@8Q����E l[22�����d8�hYQ��d��!n�XS�uTyr�E�X���Y��>�'m�ɣʀBh�.�+��_�m�R�+Ho�+��v��R�-Һ���!`�H����ψ �M�워\���B� l���w�[(������y^*/t%���lq�y����0���[�ʇɾ��4�8XHFBB�2 ��b�`��>����c��K�Zd��d��2��rQٱ������7ŹI� +�l�.ѽR�T�PB'�g��fq���j���$�H� ��H�;���C ����PR��c��^F�z[���y`ި�_�iHs���BMb>�+��P��I'��Mˢ�fd�ȥ"S���*�* �:�:ݎ +hQ�����R������.��@A��i�ų�b�ϢLN�5A�+��d0��r�6B�g��葃�a��7��0��F&D<EŧQ ����E��<A�H_���3�e��V�I6]�ɐ�J���Ή�r�"4�Y�E�)��8� �����t/�R�j��t�~� z�2��D_�e�5�z'l��2�x'-��n�@LU��� ʋ��V�5҇'�<H3P�.<B��I��ӕD}��9��q=�8���:U�]� j���IJ�1A�~^�����Go����]k��ɀ�~��߉y���"��4z�Y[n57#��Z������ +cq�T�cIS�倍X���VY6�ǘ�^���[0��D����SC[����R1Ȣa4BL�܌#D$Y� I7�Xf1s�!�3�N{vo�h��+�=�v���7eֽ��{��Iߙ��@�� r</�}� �Ԉ��� ^3ͥ�BLk���$�Q�K�n����x�_�4 +�½��ļ��a��p �����̬|*��1(�����x7`��T`�d�]��R�If��G)^,�Ma�ztl����!�$��+Z3qw0��s�� [%�=Jo��sN����\��.�����2�!���}A?6����r���ŴD�>פ*�0��ܶ6I >���ه@, +4J��7��z�=ym�Z[�[J�2|B����,ǂjj�µ��)�H��(�b�J�Q"�Yu������讬���|_�A�Am3�@��*�BC��F#��3��j��2���9%B�N���-��(�^������C1h4�FW��-t��j:�E�ө�9c���"�H����&H@a$�,��x��H��y��u�+��4Uh +j��b0�l�!�c�cpY��v��g�$�˶B�d�0�{��DD�y.I�ڶW�!ȓ35=|�Q��p�m�Y)S�~/N y�����)1(����"�%�z�pT��H��/%%���ceX�6W�1����1�Tmݵ���W��؍���l�8U�T�3�B���&���(�T����{�W=P�(�!b�A��$�`S �ۨ�x%i =Q)%�)yF��A��TL����^�!KT��!#/ؗV?����Q�fm�ֱ@R�Z%:�F��j ;AB)�'�ى����T�`<�P\�/xjcSۨ����;wg����7����wɻ���WyC]{A4�0���X�?��N~��X�7Sг�Dɍ�H���/�D���X�Q}�]n%��u����KE'��l��8֜B�Hщ�`W���[@��LD��.%��K����GD�D���E/�(:-b��{RH�7�|��(�~/C�[aV�{q>쩊�b���2����P�$�1�����ړn�̀���C&�Rsʤ�"�T2D�:�p�G/�C�|wP�@l;�%&�B$�jB7�qH3y]zlv�XEf�&�/�� +��~p4�g�H��>";�'dhcUףUQJ�g�bb�b� +?3��Di3E)�N�!�>EG�L:�"G���z���bO�+���$!�rb�赎F�7I��f$�]g��\�^�Q�W,7ڤH�W�Oi5 d Cj{L���ܭ�1(�٭�.�lu.G'+�rv���UL(�]�� DjiD�I�k��@N��UA���c�� p;G` +D�]�\8��l��~���/���2�D���x��Bj�"�E�*9U��T� i~�\� �������E����$6�)�J���0��Y���.�q��;Z�z��U�T)�V0ѻ.5�ɨ �,~�kނ� �������I%�@ǜ�_K�z\# ?ow�Z#m=��D.&�<Ɵ+�5M��b� �Eβ����;TQ��35%B%�t�WPMZ�~�(A�ZF��N����b�Om�,9$ܲ�0�F��$Ht����6�� +NFt]0Q��X%�i��W=0+��v�"� +!�ڻ*|G`!��Ցd u����e+m��QY���YNf�Z;��b�ԨL��%����j�w�g����FK�>-�e�Na)Qnӧ5�4�P�%A���sSK'gS@G���o*�b�0�B���2A� q��J0��a�8�1m��s��-��K��H%��b`��$����X���(6U%+;����P����<�ɑ�'�kK����:�I�R� I��N��$��@��H %%_ռ��%E�V7� 0<�Q��S��^N?�k��y+v% �RA��<H�y�@��R��!Yܥ�*��������a��1n��C��A�a�����|D +I���M?U����M5q|F�Ŭ�3�kBt�����ԃw�K�Mh�0#,�a8R�x�x@Gs�p(��-��`a#����2$����z'�B.K�TG+[�FG҃���A,Pe�؈5�0J$H�C�/�պ�lS�j� ��-�lv�gZ0C���t��r���Q�_#�����+��GH6J��"��CyVUaĢ{�\R������ Р�+*Q3+�v�?��AH��4j�P�5�:WZ���v�!� V�`�zT) +endstream endobj 58 0 obj <</Length 64512>>stream +����o�t�|�>Jj���Z���XE�1�G��x��(6"�r�N��gDFa뛭��բ�|��R�Ҹ�ՠ������X�)�L�/x=�Ҫ�1�.��3P)"�"(�-�G�g����/dK�'� �����jC:�g"�pk�J��kH:1���͔�Bk�u3�5�+�צ��;|��L�|({'x��H���)f���>��ե��ۙ�����Z�(=a����1��:�C�"��U4"�He(���4th��t��@�bѵeF<��j�,v��b`��R�~���J�v��Ç��h'��d��,�ϹH�Ƽ$��Q-<��j�H��:SO(/�Zk�pI������fǺej�� !�ɍ�싎�%�`t�q���17�MʷH�ӥa��--�"�;4"�㛄�סZ���`4�f�k�)JT�� �3�XE�N@�ٜ���۱w��غ\�n���I��NO^ +`A7[I��fa�Z�6J�:��� +铖��e� ��(O��O�!��z\�$�d���]m�� ����#�$�+e�)@foQ�a�|y%��+{MRKJ�-��F{REy�)�zOW�5�Svg ���1��X�ڧ��G�Y���r���w627�Q�NG���*h!KpV3���3�SF=�P�^U@�''_r��MT<��Q#9�ɚ!B����b�(j �h��q��8[�>(���O4^�)��X�m"=�t�� Z`�o�l�dA-����쑒s����Bf�a�_��V��@�%;��0���tb��tb6O]٫���;Y����ޅr��X�d�&D�1BV�$�d�w�qw�^� [���}�yNr��%;p���t��p��)Dx��V�!l�+P��ޅ��]���yݫ�����NJ?A�u�ɦ����_&����O�{�ҐG���(?�:�wcUeO�!�'��I!�Q!��9�!9!T�+�%IA�ޱ�� R��Bi���b�n=��Z��b�CP�l[B3cO~�E���~�Pm嘨 �=>�_Fz ���+%������IK4J��lY����D�;�;���\�a��5,��4���~�*E��A���I"6(F@*Q!Z�<:( A��ӚKb�����j��ڪ_��1P�ep�(e�����p���F�~U�S���o��Q�Dئk�YH�'�y=�$�!͠<�-�#������b���wh�QBb��=���{���#�G�q�{��Ĩ�m`��J �1�D�*�}'��1�y��i|bg�i����DF+a�K�UN �aQ54��H�[LN��b߉wZ8~(��M;�WB����>Ӫ�dj�� �#��sZ�Ʃ���>�(Q���ݗ%%=�4b���15�X�iT�'���J+=d"ԲXw�t��%��2���~�5 +L�؏0q��+������a�Ԕg|zq0�T'�u�9�s�ʙ:���C#>��p��P� +�:���C���)�PѡR6&{� +~m�N�[]�0x]�6W�������+ STȷ������9�-Cw�o�V���RI��ı!�,�[�פfy��z�A�T��g�R�����?<�;hyգ���z�v3W�7*<R]$����0W���bA��A�T ��Y� +0qm�i)kM`�A� [{����K�"��^,Ŵ�������jӡsPY�S�+�EB������:RJ����q���9���ųLzL���2U�S�3�z���dJ`�S���Y%>��q����>���"�uVe������P��t��,��� +�� /8���Ў�a��Y�@z�D���:$ +Oɴ�~���#Pt��'A��k�nO& ��?ra�s��AŸC�������'�l�~%j-�̋)y�PzP��P�� ����{�½���MT�@,�q3"G����8�*�ù���sə,��im�7˱&�A�2K��P� ��櫨}��}G8�U� cTk`]��ka��)|�s�^"� Q�i�b�Ya��Lvd�ĂX�Ad�IQ|a��{T���ږ�Xgq���/�/V�����|�*{JKp���z_�5{@�v�ў�L�b���3�N��� +��I��ː����y)�Ng/����䋋�~D��� ��{�x2�O���GP�� {��䒂o�n#��H��*.�3�H�9�EI`���Q��`# +>F�=-(4���J�e �aÕ���~n����!0Hd��zـi,x�%�?<��ɴ���$�[��.�N���ňd�n�e���� %4�w��Ћӧ�D���]xZ��D ��C.��t����.���mAۖ$�lQG+��@���y���@[�؉wo./(Y�+�J1�t>��#�����`8���`�J�V�z�m8�5��1H��fp[E�I ��7!�5�X�G��Ja��;z-�j����ô��yX��ٌi����.cI�_��!����m-�� P|�����������e�Ց�׃�6�+hgo,!���>iz�ǜƫ�S��-�J6㘊�p���� �@�,,��e!i�ni�>A�F���7Kތ����n�Pr�F�%|� +���;u�� +���'� ++ +��?"�ǐ`��|�8WJD>TÅ��'-T0VEf죪G���<�J-9;��v���,���c�Y�<Z$�>k� r���7M�!d=r�Ѩ�PʙI���N+�`(�AF�Wf��(�19��5���S�SE�%�@�R��0��� 07��U������Hfd��Z�Z%# �V��v�&��y�L�^�73 t�~D�%������D�h��#��%-dMU]Wf`I��6�Wa���*�д�qX�C��'��;�ؕإ�g ؑ +���,�'�^�q�i͜:58Ne�����19~�0:��81M��(E��=hߩ�4 p�q�_� kkP�AT^������ED���p���$��Lu�،U|Q�:�<���� e��7G�j�[�pQ�.�SE Ex8�I�C�2i���icJ,��$[5mf�έ�I��*s�:�dY�brY:�̂��ϕb�l�V�g��^�F��_��;Um�Sd�?1 �$p?�mD���!��)�*7�`�P�H�(>`\LN��Z�)�ks� F�W���!#HP�U��B�v-EQiA��Mq�قx &�Q�� +#E�O��C>J{a�0�"�F +Y�z�<��tB��<ɲDqŠԂ���@tez')�G���*b��}RE�@:E-�G�a�� �>��b�R� +���Y@�*�Aj5�z@ 1~�x; ��S�]QR�ъ�Q�eX��c�r_�,z�@-p~3��`�J��K��M��U�<�6���U���~�j���S�=��Ma ��ޤ�� ���:�:؍[�5�*��E����뭶�EaJ�3���IjϤkh$���m[�j��cř$PoΤĉ������ꭒA���婙�I��A!�*Q��$��z�nZ�]�JI����y2<�*N�(�" +��B�t��X����+O�{U3�q�hX�m.�"V�L�� K�'c�y!�xK����8�ك�� ��fh�'XZ!�S����X�d(@l&Z[<�*�P�B1)+[��� ���+QML0�m�B�6�$��c;>D�<� ��ZB��zQ �p���v�ֶ�}�lo�r +�E�q�j=��%x��d�0�D�Z����j�nk@��_@��ZH�LJ�Ц�\0(X>�Ěζ7u�o�x^�EN�Z�P�_镬@��ᥩ +�x� +�FPM��Lʤ���KcJ���.��C@��D�6b�@숃;�>���a�{�B' +�h���G� +��K�VuV�T�sU���9K�����zcm�b�<��"��� �� z�~�A�2)�`����xbې��[��2��B�\��Y�� ��M�$�0�R_���U�m'��IAlg��G���ɷ7J4���\�$PJ2́f+��,� �W钐u���8�& 6����\���ȭ��̎h��$��G +��� +�!�b � �r�n�#1�1�Fү.eъ�RߑƘLdXT\O���20x�)Pv��Z8j]��,��Q�P�76�tz[k� +B��*�h\�F����Eű�p���H���4�h/�b���7g���&�j��Pd��D�*O-������� E(�2�Ͻ�l���,��.0��-:�5��ܒ�g�T�C�MD��MK�IH�ɣ*�z��N��d����d�'9��G��Z9� hTo�� �+� �n{>��x�E�:�f&(ܒ��$wTt�����g���+�%ۺ���Q��XZ@���*��^�{�f�Q_b��b�\!&��⸀�yʩ�?P����"H� �D������p*�I$(y��D��Q��^ЧØ�A������·�k<�.2�Bl���z��Fg.u{�j����O"^h�����%!�C[{{Jӳs��"�:[(��G�\�.�bhQ���(oB0�v�4`�e_%��#��;� Knͬ�adt�-�,<��d����c������ +r-'�w}O;��5���i�kait��q��B��"�1�7���+�r_j����� D���X�6��m���["zB +�oy>q�ɟ�J�%A����֢#��+�5�zb�(x6�B�*�{�Cj?W_�H�U5~b'#�=�䦗�����(֜CY�G�s�W�z�@7Z��`�D���b�u��;�ݪO�>���ϔZ�i-����.�8�P:���ڛ�Iib�v���.��B欚Gg�ē�,K�|TL��1Q���w +�I���ɋ<(W/�������Rv�H��`i�O����řx���f.��1���K��Y%�5�����UȽɖ%�*�7�N����IR >^��)z����R�չ��p�H�'�&���F�49q�ؔ���1�cR����ix��(�*���%�+Q\ܪ�A�B�3įXH��y�xb�� �$'�UnRr�_ ���[��(G�&W�%����D��f��46Pt���^�(�E4�`Xt8Z&��*w��.�c� +n����蜇=��aI� +���פ�B�0��*�L�wCp,��[1n3W�w��#8(CŖ�>z��d!GsJ!&=�N�V ?E�äĉ<`��Jݩ2Z$*�a�dSl+C�-TC�$���T��*�K>nUk��&ai|yEȄ�D���\�H�Q��/���vE+��=�,9+v �[xd�H8��H�C���]��"�{����Z��E (NoOt{z�f �+�D4�Q*a�~�d�q)�L��H]%\�ɤ��5�~Αy����漈�h�̚T(���dZ�0'ˁin�N�F5P��b�B�]��)�)���?����7�Q06���J���J���DT�(�ͅ��l�"�Wy�{r܇R�0���!IJ��-�2xG���y�@��&�]�����jٽ�::�"�.U� +�H�.vYk�<O�I`e3,��k�G����#��&M��z�0���$�+����;�������*�)�>KF���vR�^���/9F�����F瘖b�z0c�S� 2@�ɀ7��:I��^ד�)���~��!�Ň��b18T/8v�OEj� ���h/H�]�&#�`�P�`�t���Γ`ə@��䋒 +�rD�kP�,�$��_H�(�%�{=Wa:yo��E�>]�I�@��Sp&���O6,b��W���^�^��=卭��U0��:/��2H���v�eO�)F�t�f�_H� +8_����!�]T���7ʔ��rv����t�*��po�FP�T5��@��2Nl�xm�8/J�(�T%KL��hN����A��J]����%�5��rtc�0�/n�46Z@�1�C�,G�ր����X"�]o��?�_ �9�|i�>�! ����HBPNk& at���Ys�2 �g�0�a$�MM�!(zL0z1 + h��3L����3�K�D�sZ�rM-��S��;�:��#�U��p�J妻m�5cw��mj^U�<��sL.{�C +�*|#�Q'���2�5���V5���vt�Z'����J�� +?�dd��(���E.v�*beˈ"V~" +m�f��{�K��U C%��:G��.��A+�t�K�֊+�+� 﨑�<H��ey�L�s�~���e�B <��u^q� +%��E�+ȕ� ��6�5�{���ڞeKqA��le픮vn,l� ��t�f S�D�*TK֙� +"��/��Kf8���"�-=���v�^��މ� �U���N�����5�)k�EN@���xȣ��EqD�[#{k���h��܈��ٿE��$h��W盉>���$��Y-��E�W� U�U���S�����=� +��R����Lk��x-`̈́+ fI��Ke�m��q\�8��"���<l�b���J���!�K�U'x����,�T��[u�̺N����[xj.H #�Z%�_<q����ё+-]�n�u����r�J�U�S^C3�@QO���3#����x@~�~ٛS�J�B� +�e�Z����4�Z�*)H"�� ���K�(b���bG���H�1�D���ve�R$���$���!'K�pA�QջQ��cCCiL�r�(�f;��j�"3gx�}�k��w.��{� f����U�[@�d; �a�2@�:�^� +B�k�1r<Aap�X3 �� +�@{ �� rdM-)Ł�<<�P�T=d�OC���Ê�2P��Z5nr�.�P��Հ5��_iԅ%88!%�j�2Z��$�:�"�Cj��)s�J[y�SUJS�U���פ2}%�̨ u"6�"������:)������N�����xA�|rN!icn��p�D��NjI�ඁ���Z�䜂I,.o%(4y�2�� '�ϲٕD;�����F�@ +��쁎8//T��q�&�16@�J�@0�"��'OQ�P-'�H��$�5��<���Q�fk48P�s"t�`���� �$sz���)����u +Y�m��ʲ���R� ���tCuV|���'�V1�G��E����榜�Ӊ��U\oG)znC.���F�⪩cO��M�<��T[�*�zT�N�b�olv%9:��U-�+�R��e��-s���(��v�A|F��~�Wz�ջ�a��w�e^�� _�*�B]uÀ�'�i���x���TQ0����ٖ�g��o��[V� .�^��Zt���& �x�d/�����V �ح:�-xII�fj��������? + +���;Cu�r��+��X��j�J����6�)]GMrgQ%�FA1n�ȭ�،՜�CT�dC�F���Rj��Et�O>\06�����Q��6ȤHk"���c`�Z�@u�!�9�Pb�W��<WOB|b��t윀��n��v��$�CAD +��OE�z�̑��"���e)N��72�� K�|�x&��U~,�!�2�vM7nĺ�j��NK���KDN�.)��f��MI��f�nM���U����&T\U�Y����)A+8�%�5�2W�Q::'�p�� +�|��}FX�I�u�(���8���~d'��&�2d�{�~�sz�g�Xr�����)tLu�V\x �m��وK$�y���X��T��$���.8 ��m����P&�#q�E������3Lέ�W�%�:g�e�B�@�h����_�tl�[E��EZ�65����S� j!��K/PB����U����{ji�����F2:��죱m�k#s���M�t�pJ�rZ[�$�{hbZ�@4k�B��Ae�>|p��� ɜ.5^d�t� �X&z���9R�T&֊�Y+Vk���V"����2�r|��dВ��^�.�h3��oS��aB(�ֆ7JZ����k�z���R���T�X�l��]4�E�n�;�`Js�%�c�.�ܲ��L�S�Dܩ�N��1���M�V��-}�^���a���Sm��Dp۹���Pz��=V�� HAH�H)�Q���~yVc��#!������%-F&#��N�Nz�,���b�%�D���}vW��D�;skK ^Y��|���zAv�qkKd�5�+��zh^�F�j'cd$ ,/p�6��> +�H�xk\�@x1c�ʦ��F�'��%`��D�����K\M��N�(��(��i��]O$j'�!�F�"p��@�,L��W����'�"-���$V_}f�&�U�Cr�܍ +���k�{h�6���x|�{y�!��[���������_��TT0|獀6F� �[R�{������q���|rz�������]������.oi����?N���;}}w/Z�_���#'ǯ��_�?�����o/��������-�h���n4��*����������/7����:��j�?��ة���8?Z�v w� ���㋣�˵� +�����������ٿw_���e;��(|���Ͼ�Q~i}�}���;{�k�|��~�o���������s����k�����>�$���G���ͧ�Ľ�~��!��ħ�i�?��ǽ��������K;�����}�CD�rF��a������}�_��ʶ�ѯy�ᖫ�g���n +�N��Y$*����0u?P�r(���P$�Al�,|ӭ���,��:ff/����������[��z6�����n?�8\���ۯ���h��U�խ'�~���h��;��~��� +����W?�/mۨ�:~7�q�q�>����ޝG����:q�W�}H��(U����˯ә�x�u��07Ob��SJ��0���H���Ư�� +I��!�������� +;��l˕qMlouZ���p�ݶ_�n;��rQ���#$n����avڼ�~]��;nx� r� �_� ����\WQഺaJK�|�O�n�����pG�<�����k�a2|��_��g��M?���{�OWo�Ư�o����\��7~m'���_;��Q�%��� G=��������?��������W�/��5��^w��x���[>0�{��_��7~���;j����7i�n�L}��|2���-�2u�x�����[�զrzz�lň�����V�y�(�='�w��j�ռ�ސ%��`u}u�5�6�������B;ջ��Z���~C�ea���殶��1�?}�x�f��a�^ktzǠ�W^��n���O?� ����Of����f�"0�o�뭐`V��mT-�p����t�[�u���bO��@mӍ��nou�\��$P��%�uw7Z�yw=�����%�uw�[�zw�xn#um9�憭~�����N�O��?��p��ֱ���߹Y��O�������oON�T�~���o�'��������c�}5��~��/�|uzf?�� ^�|����������z���ON_^{p)5����\N.�������._��9{i�xq�����_�N����Z?���oڑߪO����ۏas�!v�W��G��g���g�?|�uܸ�'/�Bxwu�F�է����������m�w�G�2nڭ��SW�L��N�sG���-B�i��_ET7��S[`/�\|������x�'�o�|�K=J��ƽ:{��G���8�b�X?��f�A(w���ǿ�8��7�·Xg��X]=;�����螕t���՜��/��A��U���ݼ8~��t�%kj��uW��zp�9�n��yåg����:���:9�gA�b�������Ɲ:�������bx��}u�����w�?|r������=������O.��_��f�Xm|����{�Z��'���9]��'���tם�o/ͽ:�������n���{�ys�N�t�N�t�N����x��xj/��q|����/�|N�����<��l=���֎�lۼ���g�K1���s=qw����_���Pmnܯ�X�����={��[��;|�����ً{������G��-�֗���nѣ-������o5�ve)<����Ǘ�O��_*�����"�������7�������<<��e�<�ь��uw���ώߥ��#���X����O�/������Q_1S~:�"Xޚ?VW7�9�~s�����WG�[u��Q�v�b����=���Om�69��������#:�q�N�F�f�lӧ���i�|y~rv��V��{w�U�a�h��.`�Y�1O"��ֵl�O�}{�4�S[@6����m��h�X�o�=���D���(�D��y�WzѓG[�Uĭj��|W6�Ë���__n������!#)�s����}q�eO~�7�Զ�w��������\w���zJ~/�������H��>???}qq|�_�'E�>�m��n�Uc|����y��ۮ������/O�l��N�뽿<9=�"������D/nޣ��V>�io��]�||������OϿ�|�>Բ&�����V�R���{�����=?t��[6�{���e����������Lz���#�w��cs�}���B��;���۵n����<I��y,����ΎO�:>=>��e�y�c���6OӼsoo�X��z��tnY���9[�);{���7�����6�ڎmk�>y������������{[؛��w��x�ύ_���¼����8ݑU�ա�ns��.���l�ܹsK~��Y0?����ʧ�Xn�vd�ga��6z�ܢ�y��Ӣ��f��A'�=9=� +#z�x/{�9������~l��k�=V����6��GGo^���p��k�<V'�=��z�u�/o�X� +�w����{�����鏇?m�9�!./��R�����ű��ͧ�˗'�'��f��G<VOOΎ7�c::<=���%'kG<ڪ��x���w���篶����Q��ó�W��[���n��M�r��;�G���E�v,���ȥm�͎̤g�\ڂ%sw�K�2���]�.=_��]۱=n�.-إ�z�t�K��7��]�fM���348��/vi���ض���K��.m3NwdUy�إ��]ڢk;�`>��6/hGV���t�|�K[tm����B�E(�6/x�E�1_� +�;����z�+��ν��z3O�F�#��g����E6����gO�"h���=5^�������;�V-��;,�uY[�6˲�,�˲�<���\�7����Ǽ�eQ\�eQ�lQ\L��o*.��(.��F��z���-��xm��I<PN|���L{��/3��o�'�̴e��?�J�+�U��i���!�e�}���_�������ß�"�/�'g/��=9�WP� +�����_oC��v�c����W��Q��(Ն���E�q?��U܂�i!�ZȨ2�����?@G�qw��*��_����7�������e?�}����s�ށ��Yk�Yc��;����s��B��:����T�gW +��[�v<q��ۑ������O.������a��\G>���ˋ�����ZC�}4�t�ݓۻң�=��u^�Q|D�e�m�[��7�w��we+>�8������v�.n��{����A(b��� �w{Ệ[*_�l�]�`���X6K��%��d�l���_��K6�.�u��_�w;�����0o����L�%��K�݈-�%���NՒ��4�����S�r�c�ß�OO�ܸ��'�}i ��` �{4�`s����o>����,ȳ-V�>�Ͳ�.���[3R��W�ڍ�tG6�6����m�>%�%���Q�mv�%��S��E�~ -.��%��><�_}wq||�+�f�ef��w��������.�_������>��s|t�-�Dž���՛�{�`�L����u���ڧ�b�k�<r���'rܿ��{h!�9K_4�r�'��C���Gf�]l��y��Y�[w�7���l�w�����3H�qӟS q���ltm�1O��-�K$j�D-��[��D��H��:_"Q�.��N�ja)��H��9�K$�"Q�g�=vv�c��}����`{�u�Ϝr�]�K����?uR��x汌��{�#�3[��!���3��GB:����Ѹ����t�'?�=y!�{�{�B����w�}�I��[�\��%/$p[�ɻ����e/p?�f���<G������_����}����-�O��x.����gA���㍾-z��ڸ���|ڕ����o__2}.�_n�����G��#�U~�+������>X�b����^.��n���x�Q:��/6���#x1�ͻ����m����N��-<�Gt0b�����x+���~ �bx���y&��s ��.x�E�����Y�7���?���S{]K�f �,��]�\n��{�Ȁ�� +rz ��ã���?��lQ��oڽ�bO����ͫ?����6����<V���T^��>�����9>;��v�c�����˓ˣ{��W!4����6���A��գ�#�Ɲ�E����_�BVv�jzD��-Vօ�l�~>��gIU�0z]����.>>�W8�\*��|��|7��o/�_m����F�� ����� +�����7oNm;~�ԅi'k<�quv+��N��K�y�8�=�Z����b� �[�v0�-`p���\p�w���/74w4��9�iwsaI~����M~0-�;�k�N����ӭ���.��⟮�������;�������g�ۜ,ew=����8����8����8����8����m��A�����]n�0<y�t?>?��<[�t���#�6o�#�P������B�r�7��;�cB�υGf!ްG�̓!ٵu�|��] ��qB�������_��oN����=����ã�˟��6��ח?�n�h�kh���v�m�w�e����Y�RK��I����a�m�Ԗ��"���9/��~������1C��Xc���8%xg �7X�ֻz������o��~~����>��+N������^������x��{���O�Nm+B�k���Hx�b���=���Wo�ɓ�<�K��S��ڧ�Rk�<V��=:�����~}��십�}��>�Gk�Ͳ�8��I }{��摏f�m�L7���p~v�.�]�؋ѹ�o�J�)��7��M�3���-ԋ����b�}�쫶�<mA��p��]��e�~r�9�"�����{����mknѣ{�Wz��?ݼG�4�ң��h�=�em@ޙ�������W��������q��'�_���Z��'�'o��/{���ю��[��ٓ���Z��'�/o�s-[��ޒw1L�h���!֜�{I��fvy��[,~76�g��ȓ.�wvww �6%�}��yРŽ��w�_�7�L��Š����xݕ=�ա�nsv�]�gG������J�~���|ګ�s6E?*�]n�����??����]�]���PѷG���V�1��'���lw�T�ʹ���++ +i��?��g�y��+�1n!پ����KܼpwG��s����&��o�/~{r�dB@O�����SH��ߜ��-C�Wz����x�1��\�~����O�� +�{ao��c$�n�Gb\���2_<���3H3�|qx���-�r���x�B�%��$">�d���)Y�K��-�L���NO���zj�������7�n��T�~�ٿ���o�^��z�����8?���"b�������N�����?������W?�����n�����{_{������>�$���G������?� *�ן��?���g���������� {/�|�?v�������tuL�ž�;}��ޑ5��_�7������:ݕ�\�Y�|��'/��>�/��5��_�x/���8|yb��^2f?�CJ{�+C�3ٓ8�!�=��/�w� ��]Lq�}�O�7�ݯc �/��,{}M� ������ܷ�7���/;Y��X��۽�+%��؝v]?�MC���}���6!ԚR��Z��웒K�Ѝ)�:T�k�u�}*��p`�Xk�����[����gƮ�G�����G�9/bo���O���}pL���5ݟ�_?��՟�������o)M#��ݠ��?}G}h�ը�V�����z���Z����S^=���|�w�����'��ח�~R���_���������g�ٯ=���:���tk7��=���^\�Zy�+��j���<��Yo�:͙f�gg�'�����C[)R<��!����XR=����C�^��>�6��~��N�`m퍯���w�dL���v��Օ�[�h��^�� �X��`c}�G�p�W�p��ZUV�,��M'����ܶ����6�b��q_�ޮbg�1��%Jo+EN)$]�v��CI�ϡ6%j<H9ٗ�M�>3[ʁM�ds?�P��8���c�]�ښS��n�lI��_�ҶT��ۉ��K����Ao'�Z��4lz5[�l�1���Q}�AL���~�{q�!���A���ԅ.�U���B:ʘs_�]Q}���0��pe��1�o�5��V����?sl-�v���;{�|�e��2��Z_m�7W�;͓���O�m��5{堷W��@��%[���R�[ !Y�#�M��i۟�W��u�FV/a��:X��A��d�a[�%��:�0p�W��)�����tn���l�Ǟo�%�����x���l��M���e?u�6�=�ݒF�5���t�F���yS���Z��A��kkQ����m-2˧4�� t{_9��mܧT��wT�B?����c�mĮP�a�Ja�3��0�0���x���RWƱ��Z��-�{k�s�/����l�Hl��7�Z6�)��$�W�w61�=�l+��Fk��ۋ훍��c�q���Z��m/�/����_�xy����p�cě��{��?��x����~��w�3�p���f+ħ�v��d��n�r��}����Q�v6���uq<�kW{}dI˚Q� t6�mQ�G����\[Oz��ɶ��&[�凙�v��^g��s�1�vvoܒm;>��M�6��6�����/���G�)�kJ�qm�2����g�>��mol�5Gd��gl;`߅\�>W�Zƃ.[o총�(�sM���.�1ˡ鲍�Pzw�}cK�m����\�щ]s�YtY��=��ܒj�q6�V����g��j��3�ʶq��2��������օR�S���Z�V��ֳ<�tݲ�g���}s^���df���疙[�.�/6�_83��0:���f��R7n����q���w���Gl���>���_��~h�`<�P���y��ǭ���A���ߘ�<�����gF� �={P�7�Y��m,S�bT/�ͷ�.o|�2���������W�\��K_�j�o����(4�ì�9���gGGo^���r��7� ��k��������ʧ������j�p����v�j_�q�p�m��Ι�>�}��ڿ6/ T��m54��L�!뛐1�R���f~e4���8ϻÛ��zE� ��?�Kl���h�x;?��8��o}�u +��w�?��U�����?�#�;~O/0� G���i��mn����p��j:1�Z4���������};ϝ]�{�|q~~*3�|y����/�/�=>�����8<{yz|�e����O�V�q����������R�2��ύ��f����˖~������t�����=���{4.��j ��OLJ�^��WN1~uz���*wq���4����o��s��L��m��h��ے ����h�#,y�%���>To�J<t�����#Ȇ���tB�7M'�2�`S��%;3s=�n�ҞBǜ�.�>X��=��m�)�7�m-���9�]f��{6������� ���v�N0Wy�=�U:�C��Ń��� �3?vȫtBL��ĥ�t��ӧ��>�<�pu���薬��'�Cdl�|��B�%��w��U(�%��7�*��� +�~Y�m�u�0��k�r�Uq1���s�/�Hx�m��c!�3��C(�"�2�݇��n4��)�?a�G�;�-�n8�eİ��j�)�'әW��SN���@]�r +�g/�g�(ة:[��Y�(�HW���ޖR�=�RKJaI),)���R�xv�nJ�7�;Et����c��p�f���z�a���+�G3=r���Ð�n���b�D��k�f�����`���F;���Y�{J�ȯf�� +g[� 2/���YA�:b�"�tJL�싾�Afc�v�A�c��M ��u���G��:���흱����2/!�(�0��mᲝ�WU�nn +1�;�J�M�W̵l*�uXA�]�Xd����>%�F{ +�MR�e:�#�l��{�Wd�����{��bG߳�4��k�/�^��˙�pH6�L�=�r"�c7JŞQ.��[�ޖ>c���̎&�{{�2�;� +�i��3z^E�5�ޓd +<�6��v��6S��`kQ�,���la�YO���������)3G�T��l��l+���JI$�d��lյ�%l��'j�]����]٪��] ���rZ6���l�WW����!ga�(d�J�W����W"P9S�c�u�S4��}�|��Kd�}�kU���W��>��LZ��0�����6�#; +�oG�O��4��,g��g}�iݷ@��avp͵L�\/�(�K!`�7�I�ƶ6���3A��:�NK�-�}�%+tLr�$f��,�gc�f��u_���|2��+ ��XX�b ��I����K���\�S�OI��u��R� �x~���fZX�l���1d�=+V�2�B%:�Y�z^ݑ��54�2���m��,;�5�Z�ۣ�n��eώ��Uw<C[�́�1��-����nL��W���������7�p�U�3�$��� ���%_�䫖|Ւ��@�*����8N�x�&n��9*y�k9��q�j��9�>wcŌ��8�,.�j�p3��ߚ��}['�<N1�+�+%/=��M�~��TsƊY緔��q�������~NQ �u�RT�k/�k��2s�^�OQ D���� ��JQ�?clmx��yi��y��RwΜ[�Ro�;��2S��R�ʹ�?������R�i�x_Zj���#-e}��1���|ȝ��<}c���1w�����f^�Ac~�*15�$-6U��z�& f��8�J�HLu�yb���91��P]>D�^<h�%u�^�j���n�.������k��{�I�d����G���tr�nb�C�<�;Va�;�^�o!ۊ�D��`����m�v��|o�KJ��j�D�¶�+G:���8�Ny�L�k�*���:�=q{Q��)<jfPG�{�t�Մ#VA�ƺe#���#���;u7 +��6��I����Ζ|ٵ���*�u �v����̋��V-%���+Wn����Y�P�vf�$��{7z����~Pv�YKʟ�=�n���Sv�����*�}Σ��{�ڨ#1�Q���Ls�����]ڬ�Ƕ}*\sϮG��ث�^%λ���0ڨJf�f��;�<t�w$x���+���b�]Y4����� �f"y\Ŧ��m�Z�Lo�<��Ԥ����o��|�`61���V�v�t�<3��n����-��<[9#أ&Wydz%�l��w�%�F��ai��R���e��?�!�;��t�w�w�ywc0+H77��7w�Q�_}#�{u� j+�>��h+�䨤\,!�O����r��\.�}+'�'0Лɡ�b�O �kK6ꖅ��V����}Ϙ6�k��k_��j_}�aa��L���A$-c�CoM| +l�'��A��A�����`�y��}�z���5h��j�� in_���- g?���c ��[�"OW��H"�3��֫P�í`�ӏ<�J��,�˴\i�1��� +f��-�-{}�ts��l6-�%y5�����9��,$�ݖ���>�7��Z>��՟׳�|w����3?駞�z�YJ�*�9[a���\}{g�2Q�1�H���^�e+��UzQ����li_O]k�K?,�]Mb�w�kG�_?���%�o����^�mνX��MW�RuD�p��S>�[�v�]I��Vپ�xV^?��ג��^�κ��ar�������w`ջ�Y�Ճ�͕3_K��(��Ǿֱ�����͇�<�;dR�[*��ҥ.�>�Ղs�|�[����?�fY��דF��'���z�u��)���V�L�VM�|��Q�:�2��{�7�y��=�`��f� =�Q�J�'�^YKSzn��mN�>v��Sy����-�*��X��Zv,v��pT���Ζ�D�l��yvH�N�nN���!r%��{��A{F6�Kf��%`��;�!��o��h�]��o�]I�n1ٮfh7�n�%��N�U�v�)����曩�>_K�v�jE�yq�T���y�η�y�z$��B��uJ��RUX�eoc�YU(���ލ����mJ4� �'8��ټߵ'���kۖR���Y�Z�s� ��'Q�� +�ݓuI8%8��~�n.oz5%o� V3C�� +mI�okL��k/�kSY��<�9uK>�.���ۜnI�����8ki�y]Z�4�w��M�j��6��E�����A��IN�I��z� ��J��s�rM�j�I]}Z��5?(��X��6�ퟠ�PKC�`c���Ґ�+��s-�ُ�!�9�ٛK��j��̜N��<mw�|��`}�Ք��A 1es;|N1�ձ�1���`����PR?����\�i7��ε+y�-f������ۍ��=3n���t����n4�e3�-�K�Mto� ���y��a'Z�����\�{+��r[��f."�5 �������RWRd�,$-�H�d�)����e� +&�;�6?�&�H�l}��uZ�|-=S�k�b�L�\HUW<�+�u�Whq���\?%���� +���^�;�����I�Q�ՠ���c���]������/���U���cn~[/���M�0F� �ez�ɕ��/ϗ����k��Z�]�E�h�5Zt�]�E�h�5Zt�?]��-�^K��z}$�F�x��)t�n�t���*XJ�4�B{�aP��f�ZU��FH�J(����T��`䧀 N�����X7/[�N��m��"h��4H������gE��%��+!!�m�?�6W��x�h�����I�l�X-���.���:<��9b\]��;Ud�]I�[$:�w�y�fί[\a�)�Jd �ơ�˔��~���T�l����B�&��#<i�)�����X�?�M������ `�ub&�y4��;����:~/���0�� +��E���C+���L�5Í(V�����cX+�<!ă��x����n�C���Aa>P��"͛?'/�8R1����'�ϱ9���"����7U�8}e�m����2}^]h����t��N���h���X�@{���k#M�1�2X"fP'�jH��D�����S�K������@������lnh�����:�jy�ɖ��[�l�Mq�&�]i4���1Hk=k�&u����M)݀ +!����.%Q�6j�jk����9�7;}^�����k.q���ml�n��?��^쓻c���{m�Y��)��:4so�þYU[C�9�U�5^KoQ�ҝ5���eE��)C�`��������i�w����h����{��fӴ�4��( �F+ov�Z�W����`�%T�N�m��b����Q����8S���^�d�-�h��~�nk+3�iZ�������e���Þ�;=J��.�����,��nP#�N�[j�����E+S�vk����k��?��=��:e_.�<�����¨۱ F�߉�S�e��*�._��2�Nk_�,��3���G���;ͨ(��{�uWoMO��n%{���'��|֏�۶��ѫ��Ĉ���A�1�(SS_�-�����*��8�}��|�eMQ�]��+ݐ��w���/�-����1Q��rh�{l��<f!�66���o�jO#l��*�:��h�b�j�W�M'�o�z��Zw�4�^M���������I8�j�������& *�Eh^��c!�-�}��]��X�&�;϶(=U4ϙ0WgsW��)��γ֯����s�n���ʀ��0_e��SMJ�$�|��絾L_��KE�3�[U7ޯ��&��z��}��|�ޏ+�'�|�����C?=�����I���,D� ��p�q�����#2�3�?����۔>�|��5��0���7���'ݨ�V?>��|o�-�&�R-%�=����0d9�k4�����%灛�\;�O`�D�|���J��v=����/�M.��:���ۋ��D�j�=�̙�u��fn�?~r�aj�n���;�ֳ�wή%u�������_R�o/�{��}j Y����e�I�m܃u/J6���lc� � �j�Q�:��ir�h�n����+�����/PG�Lڪ��C���C��s��Z�#ã�����%w�]���*��- ����B�+,�q���R�8�ߤ +*�UX�m�����^��i�;�=#S�'y���) uG2�D�Fnm�����M��μ����)�w�u��e�������� �u��[{3��8�W�/���"��8�]�Uvşf��]_^}��v-�]Ki�Rڵ;�彥�k)�ZJ��Ү%>�ć�������Rڵ�v-�]�^��V��v����wl�ݜ���1ia��ǵJ� +�=���] * +o��0�T�a�m*n%���FQ���g{>u�7��h�m&���쬲l�Vj�́=�����~Y���5�n�����m"$��D���Bٯ96�<� {l��HO�����C�_�8�J�Ȏ�!r��y1""���Ff��v����TV@���OC�N�w��dn[���~�-.b�8���4�0���A���:R����ډ�Z�Ǎ���T�f6�jm$D�U��Q��6�5^�`��X�o������{��D�%�p��9�X$B@�Ď��@�k�@�b���0_2/�623?1���Jmw��{��m�*3#322��H�E�Yr&�x +?�ZE5}�na��dz�Af���&���y@;�xrxI�S�)�A�`w��x�E� +ps��U�,��#�TQ�g�k����+\ܸ�a�^�f ^�~<r/�˄��D��R���V�U��#�k��+�G��ɼ�a+<�0�"*]��<Yj��xl��-�h>�@�Dk�2x��U�ŋr%�5������x�1�p' =�k�3ęD�o�}�D��8��0:!�s��P�AN!���3�nU�9t�HԶ�0�kS��0����C��� +9���2=�'��G:�� +�8r顂�vp�քG���eLHR2i�9 ��a� +���"�$o����\K���z�3���ÉY� +�p��4e����*�E+�gAp��Wu]P�ga%7� +�,�=m����~�0֞p�SÐ����[�����P(~txQ�"�3���+��P�@r��3���r�\9��ɦW��%��3:����2� �l�j ��O�:}8#��`���j �5^�ͣ4T-���ro�����#�*�[̼�-D\q<9�Ff���[�Ь�R��H��cY�6��@.��,#�<�<'���_�1�:�&��$KfA�*9�fr"��m"�X�%0<� �@�c=�~4Af%�8�eH-`a"9l�sxg��Ƙ:kH-����C�ȐZ85��� �%c0I�.�� r��H-�+P���Сό��� +1���0M�]��!����E:�O�!n�^��QP�u/�pDj ��G��s��7�2}������O�!��;����C��q�b��B�DE�j�\:HL�(9�ΙB���{`�`�K +���2qJ�C4��͢��^���`���Ar +����d�tÅ�W�˖�B���@<�Ȋ��Ez [Qh��^�^*����-} 2��h��:1/��k �X���3�����?y2��+B�����?H���n{������Ewۋ��m/��^t���n{������Ewۋ��m/��^t��������>g4���������~�$���*��B�sҷ���pݱ/�_y���?�d��d���:��8֟�䚸շw�ގ���_|� w��A#?J䇑�/4����۶�}�+���n/.�a����������m��s~Y�tT��t��םn��[�n�/r���Cn��%��j��F�<��oL#C�ෝFLC�t8� �f�����<��� ���Cn<�G�C�<�&K@`B9<�����ul��ǃe��!7,7���|����g�k�r�_DN��Ϻm^H���mgݸg�lo0�� v�m��sg݄/�u�>;���p�,,5^�-4�_��N��i Á�J+aO���u'�"k�K��D�$�= ��ȃA����>�d�KU�SE��B#�`�ix�oH(�x�%Y��#����������LG0<Gfx�љ�.m/��x����n�+�8��pE���=�=��?��˫�}���w�aD�u"�P#}�L�G d�/�#���|�x,�[�����rڿD�����4N���?E� +3�!��gE��~��̭��Q1̑{���ha@�����|��!��1�|��W��C�K�0�Jn=�m� +�C˝����G�p���Y�y�� R�ti���b����*� +�s<�z�ְ��^���.Ʈ����q�"[�fMG{x�F%'� - $�A�$�qRPU��|[ +�*t��2���3"���V�$!L�Ӛ��"k�}IK�ĜҜ*�{t�;�S{���39B��u�Q��Ѱ�427�x�� %��'�d�e?ٔ�i��M�d�2ddx�$�d��g?�fȪ�Y�D<�h��v� ؤ��l�N#4'V�D$��FG�8��<���������c�N���A�a�T����R#~�n�9����-��6Z_<���_�Eإ�쒲�d� oٸ�JRz�Tθ�Ɛ7�-oxS�P��������?��P��Oɼt����G�?�i�G�< %��vX�/�A���<���y�A��d#�!o��ƉR��^�E�F<N6����]0Btκ%�f'@�*���7:�����LR4�})�x"�̆�0�F[⩄ �vqr��l��o�Ѭk0.�`��X*^D�T�l��T��g5D��Z�(�3�0�2��b?�:F���9�+�Ѿ��!���>i�ȑ���vm$Ǯ8s>��m,�D� ���X���c�� 0�K�юz��ds� ,�f<�u9����~��-U(K�Ѫ��m�_mc���SUI�x؛�u�q�m� u/�Ƌ���,^�͆�͆�͆�͆�͆�͆�͆�͆�����P�A�m�x� ��eC�nXb�*�+P�O�M��'�D��fE����5}��e�d#T�2��}0�]��Q7TQ�[��Rf���pɴ* zGVE��e�J ����զ�6�����ae���tzU��vZ��������`�q%#�zHi�O�3�lp���T[$&����"�;�Z)�:Y�^��"�6H���B��'Ysɮd(�����z��na +]Pjq %"I�,3��ʡ�Y6AB��xv�5_���F�uy�ns��a-���S����������+�K��0�5s��"���D;���YY�ƆE��X�ȭ>�=:�&��;,g���p�H#�gL�>���H�3��,��C��pr�(��/�Em<��/�|����#w��0� �FnF���dO�$Q+fB�L�%T�@@�B5@$�����xR�|t�� A\�.���㑐e4i�Ҡ�����hcB�0!�n��8$G�M6�`B[U�XEXI�`�c@�f����}�$��F���U���:/a&c %�Y���oH@JN�SU@5wa�P�0k�y�xB��m�sE��.���y�U�d��D�/�ؑC% +�+]Q�E���@-+9�w�����f��A�ę�L0�ǫ S0{3�{8����E��a�a���|��i�)FBj�L�?��f7C )�Irb�"���2(9��G�: �qB��*�����y� ��^8{d��@���D�fp(�U8*[E�C1ȉy�-�r(��$Q7|B$�dO}��}ܔ��H3.+F�ͥaSl8�{���W�K�_���m�w�݆���/ .��&t��E���e��#�ğ���_>"����_Y�UP�e�:F+H��J`�,�6EGA:�<���1Z�c������4�"I`F��`A����rtt 4#��VnIN�@g��rK�CKס��/(E0u�����:�����W���k�G� +v�#�v嬈�n^;�#�����|��/ſ3拄��c��b��g1_�ĩ`P�Y�ax��,�xtUei?==+��a�]0�(� +S�;�+�HEX����g9���K��\0��U0��u.����+Ɩ��c#1_0�1�-�Fc�<�^�� �n��a)��>�z���|��c�_]\��!_� +��F��v��$O��ʢ�<��/^��,h|�/|1��y���_ ��$�����$�� +���U�&�K.��$�/���6-*xk�BZyiS����yM�����{E̅Ě�F�p/G��4�$S"WW��������z1����h�8�1:b�`�����GDϛ�%�&z�����f�W%���,�Ш��^�V�qu��,7����z6 d�J�� H�$^�"��X�/�Tk��xP�3&�.$��:��"N`�V(�ު@lI\�����'[;��f<�)`��{�:`�gzOf�����"b&X3��=Z���<�K'Y��!�x"�z�uՌ��" �4���4a�j�N!�:`3#g���qdK�L� c�v�~a%�j��2�\ V'C�f �3r&����A`�ۓ�NA"C�@*.:cXr9���2�udS�t3��A�/��#����"GLp�9�Y9?�m�h2Z���r>TƝ� �B�{Ir~����G�B�Uz3��\���_�TsX�]��l�v�i�M���>|��E�f�^�bc��4��5m�ŻFӰ�m��rY�.��| �MU���mj�{��� +���^�Lۘ���MZ�Y1������|���(G�0J��z��>�\a�0[�x�s��s�$�w�ŸH@����_���Sŗ�迧���N��K� +E�D�Kj@������ +d[C��O� \���f �W".S������_(�F\�/o� �A�qǺlY�Z��߿k�\0��������O�����y�� �K���E���M��� y5'>@���Pq ��QT��o .���z����������M#9�e��%����n}�d�b�ӃA�d�Zg�E���~F�T?"םI�itE#թ����F��'im�i8Z�3Y���]�Un�&�4@��&��^oFT��8���]�NT�M4��Zt����\%:�u��)�@��Fi�S��iN/��j��L:�Ս@ �g�?ۙ�z�o���ژ1�0�˿{�Aj��aa� k8�"Y�効��/��1��1T[�(�M�����`�j̍6����tO4��v6NM��gc��m��X?�̓��Yg���7�C����ñ��_M��/���lR�G06�u�Knq3�}6Q��1�V_��h��u�P'��1��Џ��Ւ�F÷���W�~�� +������*���;۶���m�[��V�n��V�m��V��l�훷Wm���/��H���Mf��m+ڶ�m+�~6�F�6����a�9��8� ���e���V�m�V�m��h?x�D�V�m�l�J����!��s���>���j�V +k��j�b�ԟ�Ʀ\<��ӯ�q�l�%Ħ�$�D�U�="�B�r��(.�rn+s}���sP����cdw�@�L��t�1�(��`uLʃ�O�:t�ȹ6$��z�tæ����0i��0��J�~ͩ��2� K8���,/02�{�P��%N`X�3$�4钨(/r���2��Y�I�r�6��{�L�Y8^�����Yݤ�5���� +�Ä�hsl��>�a`��1��@�@����H���*���=�2CHT��VTY&ۀ�UAPE�cT�>���v}�d_y���1�����t���a�����b͵g��͓k��xLG x�s�knؚL�{�|��u�߰���d��+ӌ�Ȓ7�Oc�5�R��i�0n����������,��N��],��;����-��D�ڡ�, ��#�`���?�[w��M��/��?��w�q�3t�5��'�m?��_�&�,}���}p,�'�����]h!��UU0�y���/cx��"��UU�A�^���X���U��$,�?�2����Umk��[���?Jw�3��˘�X�(�;8��W��mԿ��'���7�ތ��H&��6��^�_�1uʼn�������[f�R-������a�u�7�aӘ�s/��5V2�Zd��&W�?# �wZo Ǻ�ZO~"/����������i\��������6��7pF`X��yA0�'ƾX�c��Q�D��� s9�0�,;*��/�L��9Dˉ[��6<���,^�Қ�2�I�QxQ�%�i ] ?&,XyG�z�BS�hvs|珒�6�jF_%�W���m��GD_�dy�gMXV�F^�D�u"2��$S,g��� �r�sj����s���Q��O<� Wo�[ �ͮ+ݛ�s������myAP�eY%�f�U�uE��U��K���L�g2�͋�řG�[�<�@"�Ϣ�56�R�EF����gTb!�x#�*J2+H<IO +��d���8�JH�x�����.�X�̥0�7`����,�=M��Xr�8�-`Ce��[5}��"�Jt���p�����HP)�W�RREaD@��%��X�Y���V�=���wR�p�X���B�Γ�z\�a���*q����� ��+���7h`��㕈uщK���g�Ħ�=q�C웿mB��D��ϔ��Rπp4s�0��&j��.K� ��#���������_NWʏe�?��8qKZ?)i���)�/!��~����[\�^���ON�C���l���B��*��^��}���[+����*�:�s�$װ�M�%,���R�z�t���V��{t��fO����q�?��_��*��oڝ�n~��;�hzXUyN�p�s,u��v��B�u�7��0�p�(�2*��-����'*����Z ����W� ��D�eU�a%��\�w�Q�0���UEd�W�s`Rk��&#���)��G���o�݂������J*C�B cD��@�)f��q���:�@9��X�L������Ga'�� �io�`�Ym��s̋��2Q�`�2�x5#��dE��XGo��8&�Nz�0g6���-���r�ێh��ʻ +q����=���D�G�WE��d O�EF�=��݇���K�� ��8�8��wg'8��|�>g�9g��/L�B�S�_�� OL4�3@)<= @��V�³���A��/�Q�n����#`��*3����$���l&�1�A����l�Ra�5�",B�c��1�m�zK������;����0��^c����94"�*ԗ��N��B��Ĝc�2�Y48��(����8DAf�tb,}����J���W���?d��S��C*� ���QY]�8U���4�d|2�͢1�@�0Kȏ��$�a$^��� ��X@� J<�l�2PF`a +TY�(�]�Z�vnΏb��D��(�x����3YF� <��� r�2�V�aTV��ķ��G�ە�+�@FGDB~ +����J,4z�������r�"���a��q��.E�k8���K��E~d��d���[P�.DP":E���' }ׄ�r�F��d2X��m�&�܃�0���8.ڜ��ު@�ot"@6s'Ix�I���%�_����d���5�β�(a�^`L[12�/�fx��pl +���F��`I ����{i$�(��[�1�7H]�-�@���2d��BQ�t}��t��P�e?��*6������a��A�b�77Z��Xߪ0�s�,�#T��`����*,�8c;��˰�����5rI�����7�(� �g��}��F]��,� +�L �L�*��7�"���t;�@(� +h!r>vm���E��� DчYl��L�K� �P� eX��Z����� �)/�$,[�Ȥ��B+��ɼ�4� ������W�<P�`��ʉ���� �A2�<-�����K�� +�>���Y)���q�~-�,�����2�2���0B��H�r@�D����yC��8����b�E��Z!�s�:#��A�"B��(�O�E2�� b(������Db JΤթ��2����`y�!�c$�$��V)���'��Q�WyB�k+�_P�Y������R�<�����d'Q&(/�MiNS%ol�Y%I!��1�*�= trP��v=Q�G�M�\�(�/܂ �Z���@*H2���}ڴ�Si �|!��I���!Bv�*�d�T�b�<�j裊���E��$(��&A��Á�Rw��XV�%�)ZP��պ3�+ԝqq(���0&������ �� + �"B$^��3ө��X�l�_��$��JXl^A�y"�ʑD��.��^:��Y ̶'��D&#��$����hf�{�<�R�[� +�7w�t�k�L8������ :Q��&��n��&����1y zee��y�+H��$�(H��D +�q�J +�~mX��n�n�S��`)@��rV8�ķ�����Y�d�������Vj��������i�D9v�$ �%O��2'��0h�"'�p�@4���E�:@m&��(6�+u�E���ld�AL&��d+��yR��DA�(���6��ه����d/�!Z>����*N%�0����G��T�K)DAB4�`���_0fTL�v�=+@�Hn _��Z���-Ba<ѼLfn�F#���S9�c�w���k(�5uWm���t�R��� ��6�pe6��fy� ��/4�P�6�Mi%�¦*�/���&x����C��T9Fq��aua�I{�� ���HJ���4$p�d>I�i�(�jD�#�/�1��$��aH��c +�!o�m����&�� +�rJ�Y�D�lEFY�'G�e�i�!"��m��"pY��.E�`�2���R���u&j�d#���3T�T�I8��Ί��ݒ �A��쐲��E�L�A�b/@T���e`��n(�x�(�c`ł�E�"�֟9M�F!eK��`&����1<@8�j���"�~�� +"����-&��1���I�����@��,a�و��Q�D�D�ˁ��nOQ�� jI<:>e�^H֟y�K��@X"�$�+Tn�u���B4��2X�`4��$J���Oߘ]��JJ����%tA��0T�d�F� +����8' + �8�u2�X̕�D�G����� +�{AG��b��,Z$��P������+�բ�Х�}��R��Df�ٮP��eFy��j�r��ˎN�����||�����G���ۼ�lX��tWf����F6cA�F�6�@M �*� ^v-q�a��V�K$iE��$���sC��M���*`"��c��13���!�2�� K*ϒ�����Z���gs }�*(h�H"k� �B��p�U���u���,��=������9�JڎZ1@;,���_�##�H����Rg2��.$Y��{eޅ/����\>���&�yts�0X�~��֯{�����D��ᯮ��"�+����u���g�I�A>i� *-��t8"/z�o� T���0B�U�(0�pl��������\76��~v�Ӭ6���}��/0l���p<yq{V:6�5�c.���i��S�A�ӜPp����|'(�r�v�����y����M��g�o0y�EOb�;p�e�0j��5��Q���d�����p�K�a��7��&���O1�zgЄ�_$�LU����|a���ߓ(�<R��H�*:Z��ie|e��vB�v����l����l�&�a�'`?�D� �{��u�uJ�+�M������ߵ�'�_��p�I����a�!��6֎��/M�o? �F??��~�4IJ���e��)�B'R}x��?���V��}m�ںq���3���3���Y}8E���v�Ƹ\��)��g㆞�c.?�R���G_�jMж�Cg�?�o�p�|����+�G�Ȳ.�;��u8��ި�sn����k:���i��:Mפ� gi� +f�ס��X�u&��&��R�ڤk��%�Hk��lv�9������l:t]j��>���:�����6n�����d�Ӧ����8�,^�/nYۤ���֔aMY_�s����7��Z���<����ku`Mu���>���zv�/;%�����>�Ew���L]�fg��;����J�b�7��m��6���ieK�t��L�ڱJ̌e��p���ʱJ�]$]���I�vU��������Y� +/:@e�L�Z�_�z�xNؙ�H�33?4�D� aF�-��s�eM�TR�V�!�U�/�^mxI�ҎT��b�|fͦF ˂+����^�[b�&����<���ά��a�͌�5C#�b������H���>� +#$4u9�m��FB<�'m�Rt�1� +3W�<����}R����%m�6��tWe8�x�<�^����H�e@��@���xl�mK�,�u�w��f��\�`j���bp|L-��ݹ>eWu6~'.��U�E�З�X�:�FP��� �9{���pLH���&�����H'K����f<Ξ��R�C����ة�kKg�^��XqS��8�E�,���ñy�=���e�R7�6Cv�f�X��f����J���$�]v}тS6|2��Β8���Iq���u��/��/);�ae#vs��:V���d��f�����M��s^,^mh=s` +�$W�����M����uG��p�),'������EuSi������_&jq :I�K��\_�A#�艔u҈l)�V �w�4 2�30�,5BVV�MM`=gڸwʟZ�=>�(���*�N�bv�f�ʖ�@4(��J;K��I����[?@��\���fClvS����3�W'��:��jYUL;.P̵�� 삌� ���@wMȑ�%=~M�)t�a�jEӄ��J6� `�̫�+cIP��3��\1�M�ve<l���qƮ*����檢�.;�~�M����"6}7$�D��Y��b9�G{��o�0�Rs��O9%�&K_74%$����u��_��'�;25�)�?#�F�3����� �Ĭ"۶�\�1Q�B��2ST�[^����z&p�}��7K/d~��,�ե2��y��r��v��# K=��,�Z.�4 +ii����e.�Y\�.,�T\��ta�?Kc�ވK#�0/-�B���Yz#/�ZjYX�%��A+�31������p[��� cVdׁ�x��(��g4OQj�z@`牦M�A#1��Zt&m�SA�(�+�`u�A�pj�o�"���y���Tq���be7A ��V$Z�����J$Ȫm�����@%�t-�/i���8h������T��q�/�Q��!�;��gu�l��u�,��Yj����b��L+���k�B}L+H��= sjEuV����D+���#�<3rm)�C�Z�/��_�;����mI����FO��J��&W�nv�8"X��Iw�E2�5d��rNkp�\�⦲��,�}Q�M�k+a������I٥2K#,�o�V|��-D]M�k� ��4�%<�-V������z�,E����5����EnuI��,�47��u���O0cJ1��S�R���"p���o�5n�'��lа�D��r!c>'�Ϛ�(K���eC��3 +;".��@��9ۀh(11�n���m8����'�Ѡ��W�ڶ��zj� ���Bj�}R�����Fc���aW����˻���RQk�-��78V57��� }B>�q3<�8 >[,����(���M��p��s�W��E�u��#dGw��Q��2��-�'+��:�#k%ln�@�>|�}B�@�a�1��M��voV��>�� ��lCb�Us�}pn�>,��6QTD�W�����7=<vx�<��H�"�x-�ƚ=ܑo��8x�U�͕��oF62����8����6Xlhl�tx�${,F���RS��t�����8�M}�y8c��6=��b�{%�Ս-���6�w�}�lUV�R��|,�7�m��'�{0ؼ����?kr����qdn�� �|�U"v��`�Y7,�N�o��-=�ռ$^����Un$@2����Ee�x�g̿���&�Q���\.�L6�b� ���6�������X>M��%G'~��+9�] �lp���T��1ū��΄�-yKea�����WWw��!�� +5�5:Rf��3h ?+7v$��.����x�i��a��u +�/������;����x_w'=�Bi�'_(<�����p�7��sf�r&���ɬn�Z~���s8�ר��MslcY��'�z���-���P�-�Y�� �q*�+������Ǻ�+�-��k�X�m{~I��)��D7��K6�hzN�Y9!s�g=;l�m�������� +�:)���Ct���`���Y�i���-98�k�)��%�G����۴H��=����R�ngjŠ���X`�Fn��*b�~9g�uúOt�x9`6?YI'�z䈓 Xx �܍U�:�js#���yy�6h��6n���JH�<�Ev�-՚�Ei雁�j_��GvkY,�5*��轊>n�J?#b����?�����T:�no¡1n�?6��Q��شdNyq�u����vD�=��Q�%����_��M�p`������������ʲ�8���<BDN\��[����l��Ǣ�6�����&��H�cNN��)1��D���Q��<���Ŵۃ�W���B�}�O���^���';��qN�F�W�ęp-=�%dz���qg�.+^��d߳o�N2��O�&��)0�X�=6K�L�o��䡠W3�x�� ��ޖ`��w�P��w��}a�}J���TX��n��`B���Ya�&��ۻ0�sR_�ڎ���닇�T-�^�Y.��<�柒�I������B�`��/�Y��t#�{��m��nO3m����ȫ/�`K�ã��tz�y~{�/�G��,��!�}'U y��Zs`�w��k��L[x��vy_0}~�Lf���}���>�c����_�`�UjS�,��qg�5�y>i�{�G{�q�q�*U}8�@2v����~J���~0~����xG�#��7�l�e�&ٓ�5`N����iF;���̞���=ݓ+}:���n2S<���TS�g��7!g������C��{�H���.)!�{qZ��b��J��)d�u�İOlD;�����1����3i�0L�S�C0�?4~��Ni��A��qE��[&�H����[�h�&~k��?�ٴz�Ӣ J�O�.<�]`��K,���Ng_����H���F��}f[�ӏ����������q�%����Te�q��q<�@J~��B��}���hfa���>w�֔^x|lN��0۪��Ю&��:K�2�ɽ���p{�O���+!zvsDfI;c fp� ��ϋ��&���bS�&����l�M3'b�*0�PB����ԓ��Lg��\�M��ٿ��] y�G��ZD��R��~�(�iK���:s�����F��cVO(F,t� +�����a�5�K�4�-�˚��*Տ�i���>�gZ' +Þ֛�L�G8�y(�{R��n\������7�� �����BwWX��lx��.�w�\~L#O]U�1�|'�"(ՙΤ#�z�po��WL�����/Hdg����� ��x_wK���K�����d#��?Oh�K����-y]+j��rq`�L����(w0<��>)z?Ss��τ@JO�l���W^�K]�F��r�1��=A�l�S�wU܊���f��dM��3��;'B�}�Vj�yN$\��/w��@��%���$��s��Q}�ja�;�5�ȋX�;�D\���T� 9�t:M��Բ��ǡ�aN��d4o�Z�v��M�N�0�׃�Pe娳/$���r|v�֟�R�Ͻ��;���)%�W(��3z=z��3Gֻ���D��w��F�!5ɣT-q�5N�[2�.M�J���^r/��9D���Mւ��R�vC�o#iu?aՈ�"؝ +���J���H阱[������l0��E,a�WA%�&Ұ��<BI�~%9��Ic�("o� U�R̡s4�&6��'ca&���d�J�/�q2��y��ɸ�GҔ�`w��Ohb�m��i���j?���<�@X�d�˦�E�5F�_q:V��L���Qc��*�.,Y�c�1�0R-��6�滓�뒯P���n�6a/)��H�X21����PR5F�'�$�~ݎNl$�u$ĥ�xb7$����#�i���KIae�N�5VY������ TS��e����т�HծO�$�vLa��h��Cc�]��_���d�������cS��v:�CSX4��吠�n�J H��xcU0hN��脁����/�S|w�X �C +��(�F΅ZB���Cp�I���A�*U���`)����'�ݑis\l�B(>�>R�L�B4C�����T������@�X��2%?�\fO����H��O������F߮v��IY:aIJ�([�Ex�i�ٮ *�iZ`k�|���f[�j�Sy��:����8�y6[KkM%�㴖lB��QC�6U�g�o^2�w)k�w�@��g-�WY�l�w![m24�j��n + �h�����-�A"� +Q|���^���D:�xԘ�yT͙*]��p���9�rL����^�2�(�4���:�×��n���q �<�� ]U��i���__j�p'��j�qW�۽pl��r&�l�*X����r�f�.EbHP){>�u/9�������WnW�+& �D�Q:I_T�0���������.Ϋ��l�i~�i~�c��^aJ���mI/:'��.�M���������0���t�,��e/�(ze��].�?X&����)��{�/�F� +����@�;�(|<��>L59;���v�7^NU�w����K^�U2d���#���iG�Ɍ̴z,�<k�Fm�{��d�j/�p�qb�k�*�ڕv�=&���;�!�W/�:П��[�膵���e�l�˘�sBn^�'�|ٺ�W?]Ǝ��2~C��*�X>+�s�����r�_�8�-9�q���&(ŹIH'�l��JF��̪I�� cx�C��a'��%M��鑶���(��+d�;���(��t��@�6�����t_Nr�}��a6�!AI;�%����Z���d�6�l��oj�u�C�?<���I�yne�`�O0����>*���!yK��q��ڙdž/_�J5�|G;�f�mղ� ��f)1�z�5*���ex3�v��]U�<��_�j�$�G5���CrRg��e�)�yVZ0�7�87��ʧx覴j��U�%֎,B�}��7w�㨡�p�f)�>z����;�f��j;������R��۰D.v�<����M�^JD�w��He�g�#sEe�b���)m6��E�CYF���gt���e56�S� +�|t���E�L���,��n���x�g��Z�c�@��L'~6IF�t$�2��#Km�Ly#v�b㲒n����?{� L����䨤?槆�lLd��T���Z�7� GG�(I�}�)�bk-}���p��}A"?��#��y���M��v���� +#>�ߧ �\Fia������&z�R���=G2GE�ݒ��2h�DY�����J���L� t�d����AM�܌��j7���d��M^�}f�Y[傆�T 48�Yj�i��n�01�0Q�7`|+���ݽ�IZ��\���/�����Z� �n�̓�й����� :Ha�"��^�ۈ���<��LS�wl�5~z��6���\����_��ܘ���k[t,Y+�A�o�|��m�'�l}����^LJ�To�!>��A��`�<y̞�F��]TC���磩K�9�7~��ϧiiw$f�Zow��*���%2�p���AG��J:<�U��If�?����,عWXI�`��G���?@ P�&?����B��C,�/�Sj��ܛ�VΪ�ݑ�|�FK��{�^��v�l��Sr՛I����a(X K� +�d~�R9~y�y�)�����'�'�)�"����=�X����`��4h�V���4Ѱ>M ��}�i�i�귌���?���ժ���n�I��������@r��'$�Ith)y� �ۇ�MH��~�@�H�K#�#1˘�6��8�tr���Wq��c��_�4�(5[y�iAu�4!ًG/~襪�Q����yK�=ʻC�J�>��i��?���E���ή�e#���~gr,݇.����ٮ�^+(G�ѕ9k�����T4ui�����'�j�����Z���A�Cf[���I��oa�;�}��9��XQ��^`"��?@/�[B�0����m�7�ia�Sr��N��� +��p��~�$����4{���1�Z���TO��)7��&����kK��[C�{�H}������>�d�'�)S|(.,s4��4j����,������x+6�$���vH\��L�dŭ?����tϿ�y0��7��ɾ}V1�\�>0�AI����7Tٛ�HJ)L����v��n=�ӓ���~��'�Z����8�cD��˾�VǺ*X_�����S(���k�=���٘vC�u2�V��A�p��s�Z�&�&�:��bb&��7eYƴ��t��ef���T%9��Mf�yo�$}��e��Ѻ��N�!�9=w�*�,�&)R��_ͣ��RJ(�A�I�p0��ʽ\{=�䳳 o^�����3���@�;j�B�o�쪳Z��B9���'-��&f���(P��6�w���^��G��4����R��)톺\�v�|�4~� ��'���~ �.q\�{��i-�5ط&��,Ɓ���^i|q| +�0�ӏ4��R�.�S��C�Ҍ���:��~��/.�'��-<b��V�H��nI�.4nFJ�������)HM+��O+�U�f��s��>��$�[ +�r���Y)�5�?8��_��������|����[;��1te��V#��~L"�e��}��y�B�6+��h�g6 +��Ѝ��{���q߲����� gO�^� �7��5�M�-�;2^�=>��T��|�Or2���j�,�&�����;� +�OŒ����<(������~�j/1[�Qi�B���\�W(��Na�O����ΛT��s9w(i�ڎ�v3��c +�4���p��Yf'4 "_tg�Y0�0��t������w�o�˒��_���W球ñ˺t��0�km}����u�q��5ѧx����k[�&&�qi�*qi|m�/4}�]W�$�=��oÙkԃJÁKov��?�6��ux�������p0b ��!'�5WO� ӭj�Q�Ӡ�'�F�Wdɱ6� +m��\3�ݰe��L\�Aw0�uތK�;�4�wF��9�v����S �g��\T ��7e��bJ�U{^��ƀ��'l�V+ڛ^�|��,Jr'���Ŭ-[w����+e��dz��1���@�v��m�'� +_~rn�,|��-t���K����+����\��p�d�I�R��m�+���8�Xt9�23ڈ���X�V07�:���x�׳����K�W�&���V��M<�Y�S#����u�g�q�E"�q*V��w��q�æ�C�p���dm�ת3NΙ^L��ə +U����o��g_��Tc<�kӒ��>�t��K���U:���I���0��Vg����M�Z{֯�No�Y!����y�dXC��]Ǣ�D� XK$U��� �c��k��r�n�Ϊ{�|"xL�7�����Qrܚ�M�c���a��1��K�E�Hvh���:o�η K\<�D�(}��&B\λ�6��5g�=Q�J1M1Ts���ʪ�#G_?ňc������C[�f�]���n�E�0��_=�5��,C�Fqm��")�6Cژ�T��Y=�oc�_P�����9��|��8X���¼�s���6����#���gNZX��T���r{��[�T�?4Y�öP�v+cY�����oUz灎�wS`�hc��ǃ��<�f���}u�|�xl��v�fj�$��K$�l�|�����8���μ%>v�v�o�O8�LF�ɩ�ɟ=����fm�+�������k�������F��R�����qs��E��;c|��䧷�ؽ��<J!���G�6��O���Gs��� >��c�WbG�X��k��(>6�cJ��G�����SJ��q|Dwea/�:��},�,�v�y�up��s�Τ�G�U1�M�G�%_�}���W�ʽ&>��C��T1͵�c�HG�B�$�o�gZO�ߥ{i���k�'����|�h�OGB�T�c��ϥ�9���)W߉>�g�t�?�|���3Ly�m.[�ϸ��C�y�f/��7�'�<7�DМ���#�Sx�2�p�{O_:��;^�:�B^buxC�;}��ݎY��)*�����a�M��z����a�����L]6�|�\�+���o��l������������F�ɏ�N�AQv�e�7lف����;�f��|�,I� <�x ��J,�ؐ��R�\�wf���tON���t,�����q�䭉���c"�q89w�ʧI�#r� + +r���Z��Y�89.����,uz�m�|��!���(�xv�ǧ{�n}�x����sq�K�Tu�n�9�UH��U����G>�>;K,N�1��b��� �!�7��=��w�;{#��3n���{�1&,���q�o?��Qu�;�](b�^�>y�����.݄z��$���������n�A�ܽ���]V�/^�MI�(Sp��z�@�:t������'�>�~�v�s��p=pG�:q7ӯ\�ى��y�t��Ϯ$��;<qK�g�̾��J�w�y���r?�c�N�;݉�I�}ts'lН��gݙ�;���xw��.�G^�ih�r�����Q0�������긫�3�}��^��g���� ��c���x{%��/z��ךx�__V���ю��L����6uw}̱���p����q��p�wQ�y����Ǘ��<���'�9b<��9�b�=���=�(�{~O,:x�$��COr|��ɴ/�����)>{���q�Sn� �����s5��y�h�1��x^��O��[�"��\A}���3�(��L��$��:������7Щ�xCU����w�W��A���&���X˛�|��f�O���*���n�qo��B����!�7��}RG�V��^�����s����;�̴�_�m�S>j��d�v�υ�;}��W����c'q:r�d����1� +�oĝ˃I|�&-�<F�+;Z����:;m�t_'��Ѵ�u�fx�c�w{^� ��w�sm�+MS���s_b7ʹ����E{��4ح����gz����~�6�;����kew�j�}�&����_�����E+�/�Iad�W��O}g�݁��;���/ +u��tߛ.>�ٛ�o +���&7��������{����^�t(����^�1q�w����g����t�뗊/{�n���^"���[�_R��?��L��|��<�_T}��G��o��J�^������'����H&X ȥR"p�< +�I��6�'�����}�$j&��S����Gp?�{��KOُ��c���������7ԟ��=�q��yz؟_����S�S�/�ر�̾2���A��9�5�d7�~���Sϥ`�/���/����I�sPnL�wO��������M�3�uC��D0$GC�P���&t�k C��#z}�9u×���� �ga�W�� �^�o�ץÝ�vzu�z� ]^�#J�+F2���H9:�#�W'� G1�Qy�3~�᯼]�H���ɴ�e�߲7L����fw�~��y �ƫ�6[Ԙ3�j(sl����q����8.���\�;�<�q���z��}��{| [�x�3��_��'������Ko��)��a!2�����N��vg*�w;a��L�`w*�7�G,d2��U��7F�8ؗ���������R>�J���T��{҇z��IVMr���|z+_'�����I��Y�F9<>)�����'b�J�4��z�IN��ӊ��]�ԋ\�P}�w`�+�����E4����}�wz{���Y��9� cB���e�{�X-�T�5oN�bS��9d�^�0�y�Vڍ⡦<?Z�����]&��o��Z���9��ND>qP8'���S��t��x�?CH�:#�Q(��%��OG�Q�r���G㑦&#�B$����dտ�N6��Q����M��C'�k�n�nZ��=���;쾧ՋY?}:b���t���A�����L�+%2���$Ӫ��;��fV.�O�'�p8�t�NeG�g�\ė����~ w��N�:�������$���������I� �bHy.����8+|�cF=�g+���m;�8���ފ��D1����Z�f��IB�O����I�ZO���������)�.*0�δ�W�w�����Jս�~�}��~`��g�N:sV��pg���<(���SR���F�������Y>V�>3\��3;(�{��y+ţ�Y�e�<�p?�fJ~�(��]�s� +J�K��\����9��_�T#��Z�\֫������<kJ��V��˵�i�~�߸�^�N�W����ո�^��q����8�n�r�7�tU�07����ͽ����[�������nߺg����|�}���==pʽ[�����}� :�����5�8�ߞ����c �p?fv;����Q����^O��h���Zz�z�I�����ܑ��^�WW�����_���k@(�^3����0mh;���v�����6+V.��J�~ݼ�����ˆr>�#$��}hO�ZS:x{o^4�q��ЅF�+������.[��G�U������$��s|�\���u'Cw���ڕH������1�\\E:��*��R�Q|�>�b���z��u6%w'�#�w��Pzw3V�{n��~���?s����_�����A#�ćrx:<9�o��z�p�1e�R}y ����&ď������>N����/�ra�m����%��!����~��Wb+��1�ܠi���C%oY�%��u����������j?�_���u=�D�g��Q{��/N8���և���j�t�����˸�m1w �+�_Jm0�;�P��c{�]����n������U��*�}(�.T���`�_O��O +ɢ����Y.xV�ɞ�U�k��L�c��V��n��e22y�C�ѧʙ����cG�N��j��l��5���)y �3��7ioT����ߏ��(�/�7�-U��xr��w����.��I�2MP/_ܙ`�;����� s��f=Ʉ�/� W�l����u�v�Y���d<�Mj����"�~'J_��D�O���!XMK�P&�"lw��L�qefL7931��#���T���C}?�=^��Z���h�9`�S��;祵P��iaw5�C�<aw�P\a�_u�wpZUl�����j�B�1xȽ�ܬ.�]��j�+����ӧ�5P%��`�/@%`(�g&�:���Zp�ؓ��J��c����}��J�@�ˣ���ڛ��,QB������=6�P���>������G�R0`Q쿌�A}?��5P��$�wؕP��^q��`���=��z�~�x���j��@�c�_����m�z���b{��>Y^ U��c�*s��'�����e�+�.�zʯ�*yw����:�S8x������(� �I��~�n%��ރ#�]ȿ��s!n`8����A�'iIJr�E��K�=ևҥ���<Zk��^[U���f�ن�`�p�9�RWC-~D����˕P��=~-T�s�Wyf�pBL�%�Y ��X?��WB����Pqn�W���uP����p5��{�O�WAŹ��x��������Zfn�N����%r/�OO*�Y�S�[\��Nl��@}T��I/� +*��x��G����+��R �B�V��5Pﮘ\�B�J[��!�;������♽�/�:XX<����O�r{ �� ��pK��~4���B������N���uz\��Q{���K߱�y�x0�\%�5�̡�!s���Tt�H�{��"�F�x0�_ `~'�9���3k�Be�:N�C��O܋�]|�R�C�&z^@�g��֨�յi�W_���ѵ_�.����W�X۠����Uo#���|�y�3������2��������,�m��گr�}\�U��/_MXY��=ﭭ��|���_K����Ձ4(P/�bk��=���ʱ���jB���>�e�];���b=хW���`���l�;^��f�q[H[U�1������,���>�����!�{ͥ/�V�w��u_������+�9�����A�ZZ������~ͥ�����N�#��z����k���L.�o�:�--��`�brdȄ��^�)�W��r�F�0ͽ��i������T��H�E��(=���_��Mw�\�w�D�C����]�}����_7���@�2����n/^ L!#Lxy\�'}�F�r��ș2�c"���Y���-��H'^�{?�ɍg����uB%��������P��{�i�R�*��wv-Tb���2����̍���P�q@U��UԦ�絡����/`m���V�� 7p�*`8έ�Jl������m������z�a=T� �z��d� ګ��Û������� cP4�BEE�67���_�wvŭC�~?k��Лǽ���K -�B��������ْl˲�f欬Efl����E����'�c�'�wJ���U�����Wv�<�/�T��H�(X�~6�~�q�?F�@{�3gf��Y��/s +��LO�?��?�8z��x�f�><&]��>f���?l3������2 �dx�?�<$�Ln?�P �)Ȋ�3��>>�&�� +p���fi(��'k��%�B�%fU^s��äv�u�|;o�1��J�����,�k�67��!��0�k�Ĝn���9]���}�'�Y���b�@�-Fx����f�鏘>��5+�a4�TV��T��w�{H���@�����^{�|��m�C-D��U���ᶫ@�Jx��*= S�VϞ�)H��_�CZ�IO(��^8����$��&��r��<:_�n�#� wd�l�Y�a��3.TL��� �5�!f�<���Y�X�g�g�<e>�'O���.��]��d���+\�3{��]�8�gusX�"23�Y'&�4Qg]7�ư@��/c��ݒ� P��pId�I�H�QF��c�J�E����G�rpd�C�$�1���:��_cJ�y���Y�j@��THgz��x��/W,�>�@�廣�R�&�I�s:!�8r��=��˛��J���;� X����h����dZ�ܰ��U�܀W/E˜3o^ک���d[&��r�Z%��\H��yFt�J�t���d�:��k�i���&�L� +������M�^�rm ��RA��)���z��(��Ξ�N�9%��Nz&;XG��F���F�E������0Y ����]�0b��}��{v�[V�tE^�Z��9 �V��5Y��s/���ń��I��s���L1?R̲$&]�9�5��2�^8��_��$�[O����zG�GO���i��a�]����a�trzZ)�f^I]ixe4��j�����yaV�2A7��̤�hg�h�4���Y,��\<+3����' +d��5�y��5y:ofS�D����+C���:!�r��}(�l�"���$:B��]$f6u�U4��J�@m����P Τe9�f� +(_�H��8��1���A,��H���N���ݬ0���K��������$��Q0"c6�W��)]8�J�Մ�Ux%���3ݶ�ľ����Es��t��96TG�:<QC����:rL�GnV`}#�/nv�xo�}!��l�e%uG����I���WF�f=���Dw'>��$*�7�M�wPa +���_�%��qId��7U�2�KB��j���fk���rԚ�\��r1vB:��H���XK������f��Xst� �͜@���7A(�@�%�ge`+H�7Yd�=�e���KY�6�j.��H�"��DS��K�9)�օgu0���U��Zoy]��Σ/5$`=�4.Z-����Roy*l̡�x� q�;�uGYcS�ZuGMHQ�K꣎��s�^ +![MY�{K�u�j��d� ���Ѭ&��2b��'�H�N���מ���6�G +���f����H�i)w{��q����`���^,6sO��>:�w;H�[b�u���*�[�E����H�h���0 �r7Ӫ;ꌻe-i�Q�� �(�$�m7�0���Z +�nZ��-�e/GFwydq�#���W����VftQH��Vcc�.�픳ɺ��Etu�_+_��-O��q�T� �Pgt7S���% Ș�����nF�u�YV�ҋ��my�L�,�����}]����Kt���|� +'T��gSͬ�D8��EX�{�95�£��p����� 1���ǯ��ݾr��{�v�P86k�Q ��Z������y/Y�X�mW�QI�E^8j�D2=�=Օ���1 z�� /�I�S�pd<mzTM�*H�JS; +���YҀ��ȴt�H n�5���z��%�G���x�Qza��d�n���8[`���zhQkN�@k��J�*�����Z4ڍ��Ef��pt]�8��|v\ ��B!����^z�ڋ�HU�"��������3@�G�z�袎�{+� �i"��s�I��;�9U�Z�q�%p3���������^~�O����(��<�sCE|�]��O�|�X벜����%N�麜O7jZ��җ.6/�+��k��Ů���k�d�o����%�.vU�W8*��k�.6-�+��kɥ�ݔ�i�%�|q(��r��Z�8 k�����ɪzG�|���J$�ݑ�*�XV���� +3hR�VoZ��\c�h���l�J���j�Ԓ�A\ �"�t)�h��V�pIuH����g|��xo5Y��Fk���9T�T),�<�+��Ҋ��"��+�8�>�S�pNq`�6�+]tӼ~�ۑ�T�k��T� �'_u|6F�)&q����\�k�*��ݼܵ{��3P/����V~I럡��������zd1�.=[T(Wlvgjq+asQ"�c�(]�P�N��%E|R/Ǖ�T�QU�Q\��,cřR�8�r��0�P�P9�u���k�@V9��0�WI�A G��� � +O=(��mP�S��qZ�z����F5�o5 +^��]U��d|\�5r�E8���z��5P4�9]�hiMaE�}�:����*�ȯ]S>W�䠗ęR���5���1�MW���2S��Ъ*v���p�вܭ�2�ڝ���)�D�RJ�J�w꩹9W��h)%��ҽ�|�(��>n��=�}|��-��W�)������V�L*$��DHJ\��`�����..O�(ٓv� ��|�f]CMOiTiW�TB���W&��ɻ����=[Qn��h��/���%ɠ� �R ��֨R����V�>*�,Y���P�7���� ���5��?�ui?������J*�ڪ��1���p�YgZv�:'�E�p��7%sr+��j����&oFe�7F�{s���{�Ǵ��7P�Uf�I�����6�kxo/G���Ir��E=\���U�(l|ޛ�/@�p]{o���&㶫�b�Mqu�6�� ++��Vэ"��RM6�Jc�)�����$IJ�@���F�-�]�X�b��c�0�7=�u=\yV`�*E�ك�b_T ,(�Yx�Y���]U�,��,a>#�6~Ŭ�:?�mZ��u~j��n> KϪ���lV�Wl���2�����J*�`Z�yJ�G\���ʼΒaW�����̓��*��y�@~� ��V��qSu�D����g�^W��؛^T�E +�Ņ�����$�N�L�Q�[�R/�����˭�H5(H���\tRxE�LV�@͎�T���ު�zSP�K��<Ś��i�����z)�#O�둧�J��&=6��Sy#���c�R��c3�VH�Ǐ��� Tu��֦l��/��c�������(/�j�LԜ��/���T����O˦��8��&�./���gv���d�w�Ð�x���d*�Ж��:*��|w5��P�:S����"ٳ��RG=)�����dϞ4�����kVF'��5�Ⱦ�[��$k6 +=Ni��C7X>��?)�+k�-�k5:���<=y��(�'�guQ�b{0خ�����R���hTȖ�㱢1fBx3MO�_��\$5��G�T�U�M���j�3V�x����i6�#������?�r�:��g �Հ�����kuNg�>r:O�tה���I݀b��3;T������bi��my%�;_ٟ�]�k��,����K'+��K'��s�k�����cqq��I�.|y�����, �*��j��Jõ�����p���]ɲW������ �˳�_�C�� +�����ۺQ[���\�_(.����}Y4���QW��,y�Ea�/ɨjٝ{�k�}AڻѲb���|9mvԉ�����'���� +�Ӳb?������a�p�᭛_�%�~7e�~>*u���j!�����{ +�?�t+�g��O�hע;�?���ե{�U���.o'��/������U�2e>����b�v�>e�~谸Hڛ���"Vu��������k�*�`Ռ��]����F��z=��u�;]���Y�g�T㶕��Yr������Ǫ�r�3��݅Wu�J� +�=M�&�VΩ�+u_��]�nVo^k�J�*U}�0=,�K&!U�u�)(��Y �ۮg�}:������O���|�fo +�tY%R&d� +�t1��?��y�,���/ӕ����`� +�tU}�������<���^���Xz���OWէ�^����+]���Z�gtuR�W��ma_սQ=*��ͩ�����>u��+�ً¾b���}��t��.���j���Qa_/�V���к)�S��Q��Ia_��RU_��ҫia�N'}�DU��/�Ua�����O���Mܞ��Ԋo��]a_Q V���m�B�4)�Ӂ�{�{Zا[R&�U���uh#23J65��?��Μ*6�֫��]}��-�-V9:�ů����-~��\��r����H9Z��EhՠZz��6J�@֡�k��[wN +S�N�/�r��^���i5���pNq�7�*��j�M��4km�(&�3=V$6ɺ@�ی���x��7���(��/ZMOsg�������9n4��u����?��[����R)��.��M.�K��e��uQ/��@,J���2��R{���=���YA���n������fy�q��}+�~hpm_V-�(����uv�@fICRuYL�}�̐B��\ _�X��� I��������4�}QK����?_+`��{WN}5S�Z�MR��[-�|�T+tU3��<��q��bv'��� +jvT%[���>)�XG�T��)wH��u֬�������oH�5�>+��|�06Y�i�)�f���I��YVB1���b���^@���ƨ�:�+��k���V NR��b|~W=ް.pPC�o�*�l�ch�G������j�c�;ꨄB�oXG�W�5K�=���UQ��D� GE�9�}��X�Ve�gO��k�Ux=Hو����ׁ��ɽ�0Q����H����<�����/�Ž-~�V�� �SJ��S�M�[�����Ԭ����Z*O;{�Y�/�J�A7]T��=հ�[��c�]�// +1�����t�R�D�gt��:-0�y머2��t��܌Q���3�E�82SH%9�K�qzt2G�ӣ-%Fa/�ǣ2z�_H�5,������w�M����$u�z�U>/t��Z���:�Y̔�v_C��a{���2۳��]<7/�*q?����4Fah�~d%[��� Q-�<����z)����fu���#>%{sܻS��[�LȞ��^���D�j] �.�����Q��Ԏ�Oj�9�/�.���"ڌ�@?�t7�ޭ}�_���_�n6�,�N|����}�ǧ�]^gxt�rm�̼[₈y�%������4�8!u%�/�ǻ�g+{5����qAeޘZ��f$W�M[���+��v����`�7����Ô">:ţ���:�~e�LK�h5��˱��]��2�e$~NFu��K36:{������k�.��͕�龲�Rt�~Z�^T�wQ2��_8*���灓��k�ROuԽ�*��ì�Q�V�[;Ho'�O�$�m�c�V;g��2���������&�^�S��U����$ޣ��%�U"��.q�*���7��(-u}�B�y?>����*�L)�?�gmI�$�.=[l�8<��.��~�M�:s�*.���wZ*�FI����+��5K�*�C�3A[��XU/�:k��ּv�pN��Xj�VQ���S�Qu�(��nJ +g�try� +�Z>�g|K6��{ci��u5���|��/�h�S)6u���-�}��|�������z����^R�G:ͼ�.I��t�Dzf���ƪɟw��lj��MEQ����PW�� �Y�%}�ҫ\�짖tlN�u^E��A7_6f�>�2n��B%%�Ԯ�;*>���I��ĪD��m9����H{Cʏ��;ZcZe>�:�zfZ�E�u�{x;Xy�@��Ī[��tS��R�!Y�[�&��K�4��5�M�2]�����*"�����n]m�=+��\��Ps,/I�k����,I�[�X@�uK�'��G�Δ�K��#b�nJ��#��S{����3u����]�U��Ahi͕%�u��d� R��(��]R�ck�Bx�%�s|���}Ya����ؾV���������/+T�v��e�-vR_Qmc�.+T���e�:��pY�Z��]V�@���yYae��M�/ѫ�t�N�2b�����T��ɩV�u^��Zս�֩V�_xX~�a���k�j�݅�i`/N�*��q�g��0�������Ym^��0#����;/(�QN$�vX����\~�a����U��uv}�a��z'pK�����$�vq�af�r���:�𰜌�?������\xX���o;��7���eyYR�����]w|ᡄH���atԨ*��������^J3�tT�,���R�����Z�9�^xXn�e���..<TI;{ۡ�~(f���)����)綫�����BۡN�Sr���C.���C���J�`��)�hչ��΅���)�����m�J��7���f�Ԓ���e�&Wg�-=*������^x،�u|�a=U����H}�G2L�64q;��P�K��Xkr��]�j��0]_xX���.<,7�[���\Yzۡ0q���\��g?tpᡆeI�v��^xX�K�����{ +{q�ayip.ͅ�MJ�U�z�D��m�,k���<{�a��ux�ayU�� ������}no:��P;�ĺ��יZ݄�^\xX~�a+�����CeN +Z(��/<����v���ux�ay�n���{�ay�n��uy�ahjYm���������fS���r6�.{p�a�m����/<,�-v�@��hkt��2Y�s�K#a�S��ʝɞ{����ѽd�Qe�8XR����G��UN�5����l������S�`�zy~�_~�C�l�O�~4�G�oBU]���3�9z���q��:Ͽ6Vf�~�>��Nݍ�,<-�k??�<�-�0�g���|����k��;O{����i��p{���4����U���������m����O����Ϳ�_��ܥ?���6o��~8z����������O�_?�R�h�]���=]_{�5p�>��L��e��3�_����~�����gd�\Y�\0W���a���{��ߣ����������]��&E���SD���������_���h@�Nb��M����E4���#yrA&]��������`��0 +�D�����gg��t��F/GnvO�g��+ö��m��u�5նnĵ��T�5��~����{V!�?���?d�\���C֛�����(數��}�ƌ?���t�rs��]���w�Z�~7�~��1�~�~� ��.�s����տ�Gg�k~�z9|�;��S⭉ۀj+����o�?�u��=l��o~�z1�|x�F���ݿ�Or��;~f���~����WΗ۞1�F�Ù{��{< �Y92x��#�~�d_!�N��uш��^Y��C��fN,M������[�#���>Ef{&K���_��c��ߗm�>NH�.?�/������l�b=pSpjp�W�Oc`ġ�խw��� ����#y1%�x�6�Y[�M�'�ʜ�5˦�6�ܺ:�=s��y���z�H��<� Ϡ=23J�\� �䇿H}6)������þ�~��Zb��W&��_n��g7-Q{̟��g�o�a̱�д�~Z��ƀ ���h�'0"���!��N���uiJ�Y큗� h�́�i>�v=J�`��|�(s|j'�����������=�v}/��d�i���GB����ɺE�}���;�b/�=�ŧ��s����c���ӣ><����uybP�ȃ}�w�俽x����ǎ~I(pbK3����O<�7!�+i5߿�/��yO�{����?��Z�\���2�$�ؒ����1[p���o�Q���B�a��e�u�ߟz����欄#��ͳ�Pjo:����o+K�����?Y����J��˘\����D� /g���=|�h�u���������c��ma�4��LT�i���4��ՃŅ��ݱ��w�B�n'��.�����wF����ag0�{5�Q�E (X'�=g.Z|u�e�ޘ�|6GO�',Ȓ⋓���G��]���QN��ď�%��.�@��z�w���i�dM����]���drq�*y6)�X�ڛ@��pm����u��nQ���]m�flZ2s\x�#?w�b��&j���l^�_������ �����w�+��ԊE�`���f���}�� +e�R�>� +�6��RV���/h�����д��,J�]�,�S�z�~1ԧ ��� �����n�����n��;��������ټ�_B�� Y�B-v5������I#�ǯ���q���^I�=�����<߸�;|boH�|�����>�2}� ��z8�m���6�ɦB_�ɵ �d�g<ed��<yL~y"e���Db"�&H�����v��AE��;�����ޒ��-������|������k������d��m)ۛ��͉�䏵oƻ?|5+ؘb���(s$H\�̀�;�B�߬T�fW��-�.��tB�xlIs8�>;W�!- �O��c8`:��Ϊ9�e �??'@8��rټ�8N!.?|J�����B�v��˕c�X:$��������ǧ:d �Qnz 0�~�O��ワ'p8*A:�5��V�G��>��cd6�ż��y4��ų��7���z鐴�]8�ؑݳ�B�f�1v����Eyԃ#�ݛ�ʅ�J}�.>=d&��_> &*x�㻴sm������,A�ci�͕ok{*���u�i��.1���IH����KL;��ӎj0��8�]=Wc�I�B~U@S`Z)0nߺC��G��W��>��pAE��}�@�ގ��_���:D������ț\�o].�Y"��y{�h�u'U�j���}���"wpu���TH����S�I(���W��uu��5뼺�P.����Kb�z뗿�x����c����_O���ϙ��/��O����o�j�d&�w�]��Xf&'c�7�)�I���q�������n]��>��+~$����XK{���zsV_����?��� 8�C7�}�����G{���|�bt�V�Լs��nq����@��i�ŋ�j�G>�=q��z�h���@��Ļ| +kÜj�˱�κfq�}=����>r�Ǟ-J1�3�����qf}d=Pr�+��'o�5�p���B���'��l������r}�=�Ԍ�|:��ºR\���0g-�����63,����e����������4sƓK⣽t�o��ERV�<.��;>sj����;�ͩ���bC:����9S���n��<��I1�������O�s�������>³`��c��̎�Z�[ֵ;��ѿ�;�r��N�������x�8������j�ܜ�Bgpz(*���]%w��>s�`�g/Ti�85̍ՏK����]OmZ?�����߫�ԟ���L�0c��(Gf���7oڙ�17n�]gx��h��=_��~N8�ҝ9g�ܭSҗg����-��s�=<w,�I��Y|<�xu��{fgљ��(L2&au��Ǣ�s5>prbf�R�� �dQ��[�����q��ˣ5����Ê`�:�o8�u��W���ӟ����8Ai]t��ڄ�:=:�Y� +������k�u3 �kW�G���.�GbL��0�(Ӂ��B6 ��Ϗ�3[Ҁ���������x,�|tt:~<���έ����4$u�>�0_݊]�;D7�_{��f� ��5b0�܇ZM +�]���zo��v��D���=�<%�\��#ޯ3���Df����I�:&d8�1$��9�w��7eg%C#"h֛��:<����ً.̴?����������)�l>���߳�Cd/����hЏ�$���"D�䫭�d�.A#�=�DZ��<��p�}࿌�O�+��|l{���>�����Q�)Z�=0��������G��$��P��2�m]�n�۟nL�'�0�=X���w��O��ڗ��ޏ�|Xv�H!j!�>������L����!EJ��zڦY�͏�O�g���}��g��2.��?�[�������܇�#w~����� �GE����0#J&1�͂��P�Ɲ (�q�h7�FMĭ����'��S����8��,�̓2txm&����iz�͉�77�)&�A0y("�7������N��3�g"��a�X<��l�)<-z%ֹ)Ǥ!�nN�0�Ϗ���&�؊!1����/��(QoB\�6쥩� �ӈ��Yڍ�P��� +�d"�Co��J;O��SBǚ�3���3 ˲\�s,��|7�k���y�y����}��}����e�_?�<������ץ�ow7��}�}��/��롷t������G���A��S�I�"�e�MH]X�7Z�]��x���y<�*�#��O����P a��c�t���I{�K����$}=�6 [��`����x�`�{ѿ]�ٷ��>l��3�0œs�>�O�G�H�����ڤ�}��+�$�ԸS6E +s��9(,������D#���sP�G�_B{r�J�I^Ȧ�2y$��Ͷ��q�g�B ���8i6̹z0�h3�dmf���h3�&;���9�v@AS�Mq&�Ҥ"z���"��c0��xr����S)H��-�Qf� r�E�?>�~����U1$t�)w�m_��=6;��Q&C6֪�1�ck+�}.?o}L)�{��Y�v��0�_�/�\�Rd�E�Ɛ��s�u��H��ʙ'�A�/_�D���Eb�_�1�5Ю���+�b_���@�����X~�& ����v�$�J:1�OV�$�D-:q䔔��A����]�o��ӊ�N�䔟o�*���\����W�߬�-�����37�q�xF�W�/.M�c++�ۇ� �w����}��$�5'u��6�J|Q�X�~6�~���O�`��K��~����,�FYz�������+����ⷍ�������Զ�y���5Ge�9M�7jN4�No�S���F��0%�Nu>S6$�B�0YAiB/A +�@b��M"Haô�%�f�`�&�f�����&�f�����A +�@8 +�*�<�سD��,�8*ԛD��,�n"v�D����A +�@2��A +;`{ӳD��,�h�I)Dm%b�e"Haٞ�K��VӋD��,�N1M���:N)����JAjcZw� �Y ��pW� 5�jz�R+���D����%�ʔi5 A +�@j���N)�i5 A +�@ʅt�D��I�B�� �Y +��2���<�0�~�k�� ]�D�D��'��Ю#�TS�:J(M�2���n +�2�8�����v�4�)BY�ǥ��4����B�*<��'�텣� ���V�豺g����A?��Υ�_�����OB� a+���j��i����� �Xb�q��=u�J� �s�~�[)l���Ԋ��x-�g���\<-�,����Z��]�n#���F�9 +WW�Fn��֯?��A�#+�Iʵgc/�J�K7��a$���O��:h�:2����1|:�����ܞ��m��ե�vYbso�XS,�>< 6y{��oO��ӹ%�?Gf�f���#�8�w.D����P춼��(1��xN����ף���C���i�Zs��ti�P�r�Fn��7�^W��f��S�W�o�3|���Te��^<'ݾ� +T��Z5�t���Z��8T�?�Uc���2��Z5�L�d�תQ8�j')�y�|-G9�x��ܼ�=�&�������[��{�������L���A�g�a��y���ӭ��?��u�5ַuO��'��E{��u����������7͞mo�/�M���\�7��F13���j��Y/������߾�����k�q���웧?G��ƺi��ƞ���F�F�m�>�w#�5� �"�,�w��eOL��]�#Ϗ�$2-����,Ƿ��1�%u�|�_���O���,�o�����w���=�ɳB#0#ۊ|7���,Ӌ�0��(,L��N��w���M��̃�-# +L?4}�1�$0\� ����-j�����e���z ��(�\7r�l(��g۱Ǵ��5�/,+�#�:r�6�Y虚��{�x���L��|�X���=�庾�&l,30B�tm,Ƕ٤C� ��k`QG�k�����L�7q1A�L�ac���ZP-�0dM<���>�Ɔ�QE�:�k��h�/7�b� ;l���bY����<��ʨ�i8�f�D~�i��B�쑏=m?X&�I[������^�w^nh�*���=c�t-t��6;�L۷m�06�_@����hb�Ū��n�Y6v�5=��>�~�0��x�]��d�~|[�.�Qءu�����E�<�Ѥe���!351�)����u$�i��V<���zVhSE?� +B��ٳ 'p�� M[,��l��S��`M��P���8fD�c��ID4"�=���w��]���(=���-O�ЌL�"�����F�hͶ#߉��4�����|�-�������b�}�D�Xk�b"��K@���ٮ) ��ڸ�H��)�q��S�&6a(f㛁���&���( � �@�O����!7�͆1pI���-X�<h�-"�. >�|�N���ix�ZFH���,sp�u 18&���h[C�u���;L�'Z8���*g��Ba3�,�H +�52)K�B�[$��\\Ǣ�d�-d(h�1B�$�"B,��F��n�� + 8��H#O���B��519Ͽ!���D��E3,p�O3Oz��4}pK�Bٮm�?�陼�7��y�[dnX-<K��-�6h@��_ VG��Pj]~ݎ�?Pםo�[�F]w~X���<ź-��k��4��QT9T�I<�ܛ�"s�r�h�Y�?N%Y�����?������v�9�bK��1�/��6Mb-ӱ٠?��I%�:���V���2��A�$"T K4��B$?N� �q=�_�UپS��n�}aA�(�C0B�2i[x�i���`sȽm>T��cSW�,�����k���li�X~�����Xd����i�7�@�7P� �%;䒎�c6Z����uMK�-֕k��=7 M�J�7�j *d�71<4oԩ@����7��y���Ef��\W�$4M<�o�U�� +fB���#����1<�&��GK�@R���� +<Ev�d�r��_���y����'Z6�X���R&��'GH�< �d���b���O��O�C[1o ��y��ij��v�o*�m�Λ���L�hNઃ1���1z���t/��2��\�� 2�,��|(��uà��D`��1�!U߃r��7L=taV�Pa�q��( ��9����w�Wx��[�a�kF�a��76-�ֶC(�C-�E��j �X���fh�薚� ����B4!k����]�Ё�B>�6�P���3CZ�Xyc���FB2�f'a7�]�{�cOD؊_pț��v��� ,'X�������V7����`�&S����� \�h`F����;���:�� 0"ɔ�"�.�>l���֥�U�0>��Đ���`�l0��[b6� ,�bqs�v-"�]�^�f�W��XN�f@ +�A��S� ��f�a��P{!�}l�p6([B�ry�\��j�VGB�d� r2B�cd�`��ܛ�ģ�Z6��U�8X����@D��}��o�vmr���&��&~���3���M'���Khɥ_y��K{�'a����8�m���@Wt`�CL�&�#8�����v��t�iA��^�o�E8��3�Ơ��%߆�}7�$� "Gp);%Fײ��Q:}A��Ĩ����ӢY�6`i��c1!@aI�)��)� ,���a�,��Ğ3"c-��h3�D�D +xA<������n n�JAak���DZv�c��٩r`u�&z�ܘ~-`�@�X�X��p�?q8s�$��|w�G��A`~�c�� �&fQ�&.�+Hؘ�p��� vD��l�/�7���!����j�\�������4� d���+Zؤ�s�� �Y�$��!8[g��������ys������D�y1�NK/L�� +?��b�?~P����gſ +J~����}UCK���4E4��>�� A H^�'�v\ɵ"�cŁ�L�y>!;pŵ}�v�9��|�����ʣ�?��EA, S��D��0��<�V);V�g!���xXDZ�B�@'��s\�钿8"��ĊuLø�fHd�3�L� ]���c�$0��e�On��g��H��j�(t���PH�,Ƅ���ӤL��������z�����5 ��O!���l9&��!�M�L���gdr'���z��hHR+�"\/y,/"K�}���(�xa��)x�ʢ�@�t��P~]��~{�=pJh6٘Ԉ������݂t���@Q`v�e8� +6]�Y� 8 �(�Kڮ���P ��x�|�Lh�`k&ul2��#`��& U�XgĽ��6&��o@�$ �B�lҲM/�� +�P� h0j�]���G��ǚ��3�!�ajC�� + ՉCZ��P��4H��mwC� +��Rh�j���>kdCb�CB�e,٠/�r�Bʑ���!�`�G��Ԯ�Ql �tI(���[��!QI�T�X�If8#�Wj�U��,F�M�C���ӎ�?��9�%#�]�Z�t��AIwH�� ��)\����r +���VS���7Y�/:A]�����2�h�R�X�Z��`M$Yl#"��� 8H�Ecp/���UA\�H.p��+5�C��Dְ^,��`OĐLA�}@���Ҵi����1'l�͌/��d�v<�4Xa<h�I�ob�9aÆə��VP����rh����� (0 r�&������KM��`��EA!�u�`P"�����d\ +���Z`�!i��e������@( +#�Dn��@M��b�<_ׄ� �� �q��;��`�0����7�X���? ���?1��O���+H�̣5Y6tj��Ġ-���&�#E!"�\���܈2]�_�D�̾$���vpx;�pd�5�,C#`sH����Ќc0 q�������0� +��e�P.�P�Ay!�sv�P�*'̠������"���hB�l(@k�&&��aJ@�!U2ׄk�����$��k�&��!ۋ���,"k����2 �]2�M�Yh�}��(xMDX`Aj�Oa���B2�}�AaRQ8hS̕�b��6ވ���P�,"h��})�H��ԥDh1f�:�o\���xeJ=�&��K�d����L�l���kJ�2�F����.�dAE�@4:���EF��C�]����e�J��a�`GIe��("F;Ęh�$r��OI�3\uH����(p�/Ġ�3&�0�� ����^�Y�94Hsd +��E$ ��e�P}H��DН�(!s��:���F��G�� +�c�Ki¹b밵�[�) 䉧h�|�&Q5�>`��zd�p�>2�S��7#&��j��{2g+TN��d�*�C�5�."��vII�ƥ�c��dL��r��E���bm�%�lks�#a@�n0(�̇��ԅ1f�'��Ƈb���6X��|��C��y��3 Fi �i�$�8 ����ym߄<��Dz� s�,�9ۉ�RΗ�L�E"ݾ�M��W'�5�(��bV7�f�����������M�.��(m�E��@ ��c�[������ԭ�H�68�ki�ǃhr�v�-B���Ϗ 0M��������f�Ds��څM�Pd'n��$�_� L� �C�V�k��pU�W�j%��-��s�o���u���l%0��"��c����� YSxrC�������OH����[����M�����|1�P{��M�@���+���M�e������d���}!�bKhI۟�^�8�}�#1nrb�VP��?XTJA�\79tW���uE��<�IC+��-"``J|���P8(|&�\X��\#�3bL��=)�H�DŽ)t!,C��w���Ch�$bĴ,���?(^;F�g(I�=o���7�G�!FlɃ���}�,d'�?��z����:'�����~4�(/4�&�9$�(�7��2S�e�L1w�H� �$��!b�.T�$��1ș��\r�@N��AH��A�'�J/�'p���2䖱 +�k��B���P\�eG�'{pb^ ;H��?�B�+-P��b4���^1>�ϜTk3��6�H ��"������6���1��\NY���x`,��ʎ>���L@; 1�$L�s��lQύYS��rvsS )�V +n�VD�e��)�Ș�la�l����d���H`��03���ԙ���T� �~ܲԵ?n��*�\9Pre��@O��0uv���$����M�KWBL���$Ll��d81\��j��6a!��l�� �RD�0l�3����S�50##f�4H����{�+/�C���� fALfJ<�Sʣ�B����Qʿ���LL ����exD���� ^� :��&����yl%ӵ���F����C�J�� �X$�!��)�/� +�p;� ��M��c�u� 5 0��פ�A}'�:�L��4��(4Ki��U8��Bn+ǔ�Ө���ξ���y��#8#�2s���6�_#��&OF�������赭C%�i9PI�D�f��5�6!����{�"t-lRpt(K��$!�����%,#ݒ�aZ�y4 +2y-<���'����L�^<MJ������0t"�h~ �#�S9��$t�� i�J��tV��XՉD4�C`��Oyz�%v���9���L"�l6Oj"����DkKjd�ҏ�:D7^�y�ܽԤ.��b��6v�>��y�J�+Ih�0GlT.�Xb� N�pl;��P%R�V���$��E�<J�;b�+Y6d�� Lڷm�2�.��!Ͻ�3�xO��!g��r7�n�83I�B�I]h�I ��"�P"�A��=�_����('#Es�rY�p82|�<Q�eRYM�����#IF�(H�H@���N�J��r���5Ѝ�x���)k� FLJ�)t��%��"��4@�Հ�M�(0�,���&�D��R)���&'\����� ��e�Ǝ���a<�y�vCl�����R�$���������m���i�EO����#i�Y�&�R�R�IY�Ж%2��+˂(s�|T +#��))��!1j�t-țO�T�V�x#ύ"��61������D���nW��a+.!_r���t0Y�1�0�2�&���qTZ�ݖ�N�5/ +UR�:%z�5�6O{O��'�4-W�l�Q֓I)LhAIM���R>���YˡH,KZ�w���Oj䢇db�Ao&���V�xΜ�E+�d����7[$�(߈�����-jDa��KUe�(Չ��|%��^ȏ���۸,D�;8�)�N��i@tKܔ�I��ϊ�^�4 &,���-$?��" /��Ԉ���N(�}y�đK�,rErb$�9�����1L�Ա�0vD�'k�P�N�h���q�G�O��F��2`W���� )�-�Y����y�����Rd5��>��B 7J5�)V�,����,'�����S#V�.�R���t�2�i�������D�b6�e������9�H.'�}�Di���8�m���S�>J�5��_l� +�YI�X�WLf�Z��F2���&T���q�ڕch�tB�!4���m���t"P�S���d���DS���fƽR���f� ��S2W$���&ཞ�R1O�M�0 +�a�2NIr�:I@ãbvWQ�=C��:�Еt��[i�Gu��b7�䑈��G�^�@��3ۂ"?��-E������겗/;��d)��̊h'�+e)?p��m";i�IG�����'o��������M +,jC֦���lKHߧ�q�&�P��.�`���f����+A��ʐ������v¢k�.%����#m��R�n�ĸ�mo�C#J�Ȓ`�rC�'��$���ʾ�~fR�SeY���nO+El�t� a$�dR�v��l:��M�lS��]�,<p���eK(A�G"�)��㒺t-2��ɵ!�)ŵ<Ragy��|M��Q����O�g��DT�K/��ו�$%�����l,7u�A ETvYRn*�Aȵd��4��n��N� +����R���"��*y��&Br�z�5q����A*f=rA�MY y-m5���ׂ'eQ?�"O8��ԧ��'oe줻���O�����JXR��'�����)�Dh4E�2J|����t�K������Y��ِ^Y�sMi6!��2��;z��I9��ޣ�Px����������y�x9����,C�L�܃�A��Y�1��T�F)n����1$?38�xy�r��ar��"ٽ"�B�ٮd�f�H�ѥSs$狲L �Th@E5��͕�]�K�P��S�����?$W_ yh�7���>�̔���R���g%{���<�S"�,�ޏә���-*��2`�#1���g��;���Ш�Er#�:�����CC��:wv@�D��6s�8���fb�W=�O�� l�9���vV����3�� %7u�A���;~Ƌ��3�3��5\A�:��¥#��=K�K�fR,C�,i:�ȗ�Zy��O\~@B7�`��D�ѵ�* �}l �)���@��}� ��B���V�1F.��4~a��l�X&��ux�5��$�1�1y���j���՛�=�l+�d�b�T�J8�zr���s����T �0��.�鞧��{#�M�H�lt�%ئ\]�e��O��'Y^�"��Q�KI̡��E-"�B�X#�:R�R���_�t,������Q�/eYL��QE���Fn�P��)9A i�Y;�(�@�}��r�z���IXK��N�QҰB�q>:;�ε����ɡt��fr�HǴ�S��I���F4H�m@#xD��H���x����3Sp)�MK�ukp(-�qC��CA����yI�z��M��Q��{hۆ�D�Ҡ,еPy���M�ĝP�⒠PZ�1�!�LI����3&L�\��$Ը)��DC�P'�����<�Դg� M1�F�� P��c�2E�+`G�����U���J���]�C�ŷKtȊ[e�U;Y�D/"�#� +�}"��,9?,�,�(I͎�8�'��ʁt� 6�J|d7���u����iiޕ� �Q�L~�,_h*�4�PJ�E%lJ9Y8�x�ܲx�t�!+��8s�7):���p�ڸr��Xt�N�᙮F��Su �f��/ Ԁj�� ��q�<���>V�d���ф��1��>VX�� +:���=��'�{6&���J�.L +�%.S>)� 2����̙�<U0�K�F�z�nFg!gz��3���KY5ʦP���z��d����\�r�U��B3�����r��6}b��MIaHk�ux��$dYR�� P�^RIur�D8�q%�B2� Ģ�J +h�%$KNJ^���l.q�)~��A�`ؒ��c�ڂ㱂��nTLW'�R�v5d���(t^*�j��:��į�f�KY������N��9�5P-߆�5M��M�p]*!��be��-�����A���=�D��0ǻ�B��|ؒ�V#L:��b2eb�-W���2��$Fl�� I҆�('�S,8�F�E9-*ba�� �����W�(���bZi�d�����x��('{��1��{%������"#D���n�g��9�eC�`�;�[�P��MGGņ.ʉ��'��rBC�:�4J.ʉF����-���ğR���'�$ñ� m�����v�KR������gL7�|�I��6��9iJ�.����5�A��\��\2�\i#�('k#��颜����{J���:)����(�+]K&�I'(A�$%-�('w@%�q@I�r��(�L�R��j����XY�vbRD�r�xN�d��VR=��r2h(���r��Agw�<�d�Oh;�o�QN���j�QN���/i�j�S�B�r��(QN6�(�('fJڛ��٘���+��W�����7MIa�F99x�"�����3�A�~L��t^�}�~L2��KޏiQŧ�)?P��@::7Nr�2��j�3��J*��&�R_~ >�����@�b!;�}&�Ɏo�tq]���ke���$w&�71�rQ�R-�T+r�r����g+����˅�� {=5�?�U1�l�A��� :$�N��#c[t�G��磜�ON4�E9��B�P? +H�RoE~�.�`�%-�eB�Ė�MP��4�D@�%�T������e^��_��ÒT�⟗�ŤLk�Z�o�5��qJ��q��K"� ôb��c�G?����.ƙbɮq +5��>RC���2/��[��6],E�J�;����|ssp�@ke_/�n��o��x�������/�v������ߗ/���c�P18;1����B�f�@pk��/�Z��fWM�erC��?o��/����~�\����������כG����|������z�zB?J~04�������r⚬ +endstream endobj 5 0 obj <</Intent 15 0 R/Name(Layer 1)/Type/OCG/Usage 16 0 R>> endobj 24 0 obj <</Intent 33 0 R/Name(Layer 1)/Type/OCG/Usage 34 0 R>> endobj 33 0 obj [/View/Design] endobj 34 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 22.1)/Subtype/Artwork>>>> endobj 15 0 obj [/View/Design] endobj 16 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 22.1)/Subtype/Artwork>>>> endobj 43 0 obj [42 0 R] endobj 59 0 obj <</CreationDate(D:20200210190200+01'00')/Creator(Adobe Illustrator CC 22.1 \(Windows\))/ModDate(D:20200210204543+01'00')/Producer(Adobe PDF library 15.00)/Title(Mobile)>> endobj xref +0 60 +0000000004 65535 f +0000000016 00000 n +0000000173 00000 n +0000041997 00000 n +0000000006 00000 f +0000188597 00000 n +0000000008 00000 f +0000042048 00000 n +0000000009 00000 f +0000000010 00000 f +0000000011 00000 f +0000000012 00000 f +0000000013 00000 f +0000000014 00000 f +0000000017 00000 f +0000188854 00000 n +0000188885 00000 n +0000000018 00000 f +0000000019 00000 f +0000000020 00000 f +0000000021 00000 f +0000000022 00000 f +0000000023 00000 f +0000000000 00000 f +0000188667 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000188738 00000 n +0000188769 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000047861 00000 n +0000188970 00000 n +0000042443 00000 n +0000050845 00000 n +0000048161 00000 n +0000048048 00000 n +0000046826 00000 n +0000047299 00000 n +0000047347 00000 n +0000047932 00000 n +0000047963 00000 n +0000048196 00000 n +0000050919 00000 n +0000051115 00000 n +0000052557 00000 n +0000058443 00000 n +0000124032 00000 n +0000188995 00000 n +trailer +<</Size 60/Root 1 0 R/Info 59 0 R/ID[<F361282BA461F147A1F2B3811D3F3FD3><614117EE489C14408B11F817CB897719>]>> +startxref +189182 +%%EOF diff --git a/resources/images/logo-hi.png b/resources/images/logo-hi.png deleted file mode 100644 index 3359d748eacae4121373616d8eea451d3e1eb072..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24726 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∨n*jTwA^=Mtov7d9TXHn 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 diff --git a/resources/images/logo-superhi.png b/resources/images/logo-superhi.png new file mode 100755 index 0000000000000000000000000000000000000000..066b87c4b178bb01d88af4e1cb3f853a98601986 GIT binary patch literal 109847 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 literal 0 HcmV?d00001 diff --git a/resources/images/logo-vector.svg b/resources/images/logo-vector.svg new file mode 100755 index 0000000..b7b5717 --- /dev/null +++ b/resources/images/logo-vector.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1694.89 512"><title>logo-vector</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M1461.78,309.88a27.83,27.83,0,0,1-2.18,10.92,27,27,0,0,1-6.1,8.85,28.51,28.51,0,0,1-9,5.8,30.63,30.63,0,0,1-22.24,0,27.42,27.42,0,0,1-9-5.83,27.11,27.11,0,0,1-6-8.82,27.49,27.49,0,0,1-2.2-10.92,27,27,0,0,1,2.21-10.86,27.5,27.5,0,0,1,6-8.73,29.22,29.22,0,0,1,31.26-5.88,29.48,29.48,0,0,1,9,5.85,26.8,26.8,0,0,1,8.28,19.62Z"/><circle cx="1566.89" cy="352" r="32"/><circle cx="1310.89" cy="352" r="32"/><path d="M1670.89,128h-8V80c0-44.8-99.2-80-224-80s-224,35.2-224,80v48h-8a24,24,0,0,0-24,24v80a24,24,0,0,0,24,24h8V416a32,32,0,0,0,32,32v32a32,32,0,0,0,32,32h48a32,32,0,0,0,32-32V448h160v32a32,32,0,0,0,32,32h48a32,32,0,0,0,32-32V448a32,32,0,0,0,32-32V256h8a24,24,0,0,0,24-24V152A24,24,0,0,0,1670.89,128Zm-344,352h-48V448h48Zm272,0h-48V448h48Zm32-384h-168a98.81,98.81,0,0,1,11.64,3.06,86.36,86.36,0,0,1,30.24,17,78.69,78.69,0,0,1,11,11.91h115.09l0,128H1488.58l-1,.74-.42.31-3.83,19.15a60.17,60.17,0,0,1,5.57,10c.26.6.49,1.2.72,1.8H1630.9V416h-384V288h130.36c.23-.58.45-1.16.7-1.74a60.19,60.19,0,0,1,7.48-12.67L1383,256H1246.88V128H1354.3l6.2-5.2a132.65,132.65,0,0,1,15.28-11,124.09,124.09,0,0,1,18.25-9.29,117.74,117.74,0,0,1,21.53-6.43l.35-.06H1246.86V80.31C1250.2,67,1314.3,32,1438.89,32s188.69,35,192,48.31Z"/><path d="M1500.26,178.76a53.19,53.19,0,0,1-11.09,34,60.53,60.53,0,0,1-10.45,10.52c-3.56,2.78-7,5.38-10.18,7.75a74.24,74.24,0,0,0-7.89,6.63,11.55,11.55,0,0,0-3.39,5.77l-4.5,22.49h-36.09l-3.51-25.68a23.19,23.19,0,0,1,1.75-14.19,35.8,35.8,0,0,1,7.7-10.28,85,85,0,0,1,10.24-8.14,90.78,90.78,0,0,0,9.68-7.56,40.77,40.77,0,0,0,7.25-8.55,18.9,18.9,0,0,0,2.63-10.27c0-4.39-1.35-7.74-4.14-10.24s-7-3.9-12.35-3.9a38,38,0,0,0-11.06,1.35,45.46,45.46,0,0,0-7.76,3.11c-2.31,1.21-4.33,2.33-6,3.31a14.3,14.3,0,0,1-7.25,2.05,13.47,13.47,0,0,1-12.27-7l-13.21-20.31,2.7-2.27a100.16,100.16,0,0,1,11.6-8.36,92.28,92.28,0,0,1,13.53-6.88,85.71,85.71,0,0,1,15.61-4.64,92.14,92.14,0,0,1,18-1.67,78.67,78.67,0,0,1,24.7,3.66,54.86,54.86,0,0,1,19.16,10.69A47.57,47.57,0,0,1,1496,157,54.12,54.12,0,0,1,1500.26,178.76Z"/><path d="M171.84,306.11a102.57,102.57,0,0,1-21.73,18,93.25,93.25,0,0,1-50,14.16,93.71,93.71,0,0,1-50-14.16,103.57,103.57,0,0,1-36.6-38.45,112.8,112.8,0,0,1,0-106.8A104.67,104.67,0,0,1,50,140.27a93.7,93.7,0,0,1,50-14.15,93.24,93.24,0,0,1,50,14.15A101.31,101.31,0,0,1,171.56,158l-32.74,33.88a56.34,56.34,0,0,0-11.87-11,47.05,47.05,0,0,0-53.75,0,60.94,60.94,0,0,0-19.59,22.3,63.51,63.51,0,0,0-7.15,29.17,62.35,62.35,0,0,0,7.29,29.16,60.91,60.91,0,0,0,19.59,22.31,46.61,46.61,0,0,0,53.47,0,56.38,56.38,0,0,0,12.3-11.58Z"/><path d="M211.88,328.27A80.83,80.83,0,0,1,181,300.11a75.84,75.84,0,0,1-4.86-71.49,77.35,77.35,0,0,1,18.45-25,84.53,84.53,0,0,1,27-16.44,90.51,90.51,0,0,1,63.33,0,81.25,81.25,0,0,1,27,16.3,78.1,78.1,0,0,1,18.44,25.16,76.43,76.43,0,0,1,.15,62.34A78.75,78.75,0,0,1,312,316.26a85,85,0,0,1-27,16.44,88.42,88.42,0,0,1-73.05-4.43Zm14.58-42.18a38.13,38.13,0,0,0,53.61,0q11.43-11,11.44-26.3a34.09,34.09,0,0,0-5.29-18.44,39.12,39.12,0,0,0-14.16-13.44,37.78,37.78,0,0,0-37.6,0,39,39,0,0,0-14.15,13.44A34,34,0,0,0,215,259.79Q215,275.09,226.46,286.09Z"/><path d="M436.91,130.69V326.27h-.29A77.75,77.75,0,0,1,433.33,345q-7.57,24.44-28,42.74a109.74,109.74,0,0,1-47.75,25,123.33,123.33,0,0,1-21.3,3V372.3c2.19-.28,4.29-.62,6.29-1,.57-.09,1.19-.19,1.86-.28H345l.43-.15a61.1,61.1,0,0,0,25.88-13.72,52.85,52.85,0,0,0,15.44-23.3,87.41,87.41,0,0,0,1.86-9.73h.14V130.69Z"/><path d="M606.47,228.77a75,75,0,0,1,6.43,30.88v1.28a10.37,10.37,0,0,1-.14,1.58l-.29,2.43H594.74v.28H496.38A35.77,35.77,0,0,0,506.82,286q11,10.88,25.73,10.87A35.18,35.18,0,0,0,558.29,286l.28-.28.43-.58.43-.42.29-.43,24.59,35.17a85.85,85.85,0,0,1-21.45,13,82.31,82.31,0,0,1-30.31,5.71A80.29,80.29,0,0,1,493,328a77.71,77.71,0,0,1-29.59-28.16,77.69,77.69,0,0,1-4.72-71,77.06,77.06,0,0,1,17.73-24.88,78.54,78.54,0,0,1,25.73-16.44,83.48,83.48,0,0,1,30.45-5.72,82.32,82.32,0,0,1,30.31,5.72,79.32,79.32,0,0,1,25.88,16.3A74.63,74.63,0,0,1,606.47,228.77Zm-73.92-5.72a35.5,35.5,0,0,0-18,4.86,42.49,42.49,0,0,0-10,8.86h56a42.46,42.46,0,0,0-10-8.86A35.53,35.53,0,0,0,532.55,223.05Z"/><path d="M787.75,260.93a71.53,71.53,0,0,1-11.58,39.32,79.82,79.82,0,0,1-30.88,28,88.44,88.44,0,0,1-73.06,4.43,81.72,81.72,0,0,1-27-16.44,79.2,79.2,0,0,1-18.59-25.16,76.07,76.07,0,0,1,.15-62.19,76.5,76.5,0,0,1,18.44-25,83.16,83.16,0,0,1,27-16.44,92.63,92.63,0,0,1,63.33,0l3.29,1.43,3.29,1.43V130l45.61.14Zm-45.61-1a33.32,33.32,0,0,0-5.29-18.3,39.18,39.18,0,0,0-14.15-13.44,37.1,37.1,0,0,0-18.73-5,37.85,37.85,0,0,0-18.87,5,39.21,39.21,0,0,0-14.16,13.44,33.4,33.4,0,0,0-5.29,18.3q0,15.3,11.44,26.31a38.13,38.13,0,0,0,53.61,0Q742.15,275.23,742.14,259.93Z"/><path d="M864.09,292.53h64.19l-11,41.32H787.46l64.62-108.09h-52.9l9.15-38.31H926.28Z"/><path d="M979.75,158.28a24.65,24.65,0,0,1-8.58,8.58,23.73,23.73,0,0,1-23.87.14,24.47,24.47,0,0,1-11.87-20.87,23.54,23.54,0,0,1,3.15-12,25.44,25.44,0,0,1,8.72-8.72,22.81,22.81,0,0,1,11.86-3.14,23.61,23.61,0,0,1,12,3.14,24.32,24.32,0,0,1,8.58,8.72,23.64,23.64,0,0,1,3.14,12A23.34,23.34,0,0,1,979.75,158.28Zm3,29.31V334.13h-45.6V187.73Z"/><path d="M1144.3,228.77a75,75,0,0,1,6.44,30.88v1.28a9.31,9.31,0,0,1-.15,1.58l-.28,2.43h-17.73v.28h-98.36A35.71,35.71,0,0,0,1044.66,286q11,10.88,25.73,10.87A35.14,35.14,0,0,0,1096.12,286l.29-.28.43-.58.43-.42.28-.43,24.59,35.17a85.63,85.63,0,0,1-21.44,13,82.35,82.35,0,0,1-30.31,5.71,80.29,80.29,0,0,1-39.6-10.15,77.81,77.81,0,0,1-29.6-28.16,77.64,77.64,0,0,1-4.71-71,77,77,0,0,1,17.72-24.88,78.69,78.69,0,0,1,25.74-16.44,83.41,83.41,0,0,1,30.45-5.72,82.36,82.36,0,0,1,30.31,5.72,79.43,79.43,0,0,1,25.88,16.3A74.74,74.74,0,0,1,1144.3,228.77Zm-73.91-5.72a35.47,35.47,0,0,0-18,4.86,42.49,42.49,0,0,0-10,8.86h56a42.49,42.49,0,0,0-10-8.86A35.5,35.5,0,0,0,1070.39,223.05Z"/></g></g></svg> \ No newline at end of file diff --git a/resources/images/logo.png b/resources/images/logo.png old mode 100644 new mode 100755 index 2ff153ac92e764badb476a58d8cb0c0cf101fbd1..f7b42bf272a61d7efde56d5bf40cc129a5eff203 GIT binary patch literal 44483 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 literal 11596 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 diff --git a/resources/ts/app.ts b/resources/ts/app.ts index c5cbef0..1d7fc4e 100644 --- a/resources/ts/app.ts +++ b/resources/ts/app.ts @@ -47,15 +47,15 @@ Component.registerHooks(['removed']); ] as const); // here goes "public" API - window['czydojade'] = Object.assign({ + window['app'] = Object.assign({ state: {} - }, window['czydojade'], { + }, window['app'], { components, application: new components.Application({ el: '#app' }) }); store.dispatch('messages/update'); - store.dispatch('load', window['czydojade'].state); + store.dispatch('load', window['app'].state); if ('serviceWorker' in navigator) { const wb = new Workbox("/service-worker.js"); diff --git a/ruleset.xml b/ruleset.xml index 79c2e2d..8b74543 100644 --- a/ruleset.xml +++ b/ruleset.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> -<rulset name="Kadet.CzyDojade"> - <description>Czy Dojadę ruleset</description> +<rulset name="CoJedzie"> + <description>Co Jedzie ruleset</description> <arg name="colors"/> <arg name="parallel" value="75"/> diff --git a/templates/app.html.twig b/templates/app.html.twig index fb49b83..0817d50 100644 --- a/templates/app.html.twig +++ b/templates/app.html.twig @@ -183,7 +183,7 @@ provider: {{ provider.identifier|json_encode|raw }} }; - window.czydojade = {}; - window.czydojade.state = {{ state|json_encode|raw }}; + window.app = {}; + window.app.state = {{ state|json_encode|raw }}; </script> {% endblock %} diff --git a/templates/base.html.twig b/templates/base.html.twig index ed9d198..39b5778 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -15,10 +15,10 @@ <link rel="apple-touch-icon" href="images/ios.png" sizes="512x512"> <link rel="apple-touch-icon" href="images/ios-80.png" sizes="80x80"> <link rel="apple-touch-icon" href="images/ios-192.png" sizes="192x192"> - <meta name="apple-mobile-web-app-title" content="Czy Dojadę?"> + <meta name="apple-mobile-web-app-title" content="Co Jedzie?"> <meta name="apple-mobile-web-app-capable" content="yes"> - <title>{% block title %}Czy dojadę?{% endblock %}</title> + <title>{% block title %}Co Jedzie?{% endblock %}</title> {% if ga_tracking %} <!-- Global site tag (gtag.js) - Google Analytics --> @@ -39,7 +39,7 @@ <footer class="container"> {% block footer %} <span> - <img src="{{ asset('images/logo.png') }}" alt="czydojade logo"/> + <img src="{{ asset('images/logo.png') }}" alt="co jedzie logo"/> v. {{ version() }} • <a href="{{ url('app.swagger_ui') }}">API</a> </span> diff --git a/templates/manifest.json.twig b/templates/manifest.json.twig index 06ade28..0fa40c9 100644 --- a/templates/manifest.json.twig +++ b/templates/manifest.json.twig @@ -1,6 +1,6 @@ { - "name": "Czy Dojadę? - {{ provider.shortName }}", - "short_name": "Czy Dojadę? - {{ provider.shortName }}", + "name": "Co Jedzie? - {{ provider.shortName }}", + "short_name": "Co Jedzie? - {{ provider.shortName }}", "orientation": "portrait", "lang": "pl_PL", "start_url": "{{ path('app', { provider: provider.identifier }) }}", -- 2.45.2 From 8ebf5ac1372b58081b4db7ae754943f739ba79bc Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Tue, 11 Feb 2020 20:12:33 +0100 Subject: [PATCH 09/77] #22 - Fix missing icon in favourites adder --- resources/components/favourites/save.html | 2 +- resources/components/ui/icon.html | 2 +- resources/ts/components/ui/icon.ts | 17 ++++++++++++----- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/resources/components/favourites/save.html b/resources/components/favourites/save.html index 3f223e3..544dc83 100644 --- a/resources/components/favourites/save.html +++ b/resources/components/favourites/save.html @@ -6,7 +6,7 @@ :class="{ 'is-invalid': errors.name.length > 0 }" id="favourite_add_name" v-model="name" v-autofocus/> <button class="btn btn-sm btn-dark" type="submit"> - <ui-icon class="add" /> + <ui-icon icon="add" /> </button> <div v-if="errors.name.length > 0" class="invalid-feedback"> <p v-for="error in errors.name">{{ error }}</p> diff --git a/resources/components/ui/icon.html b/resources/components/ui/icon.html index 4fd3d67..f9f2d25 100644 --- a/resources/components/ui/icon.html +++ b/resources/components/ui/icon.html @@ -1,4 +1,4 @@ -<fa v-bind="definition" v-if="type === 'simple'"/> +<fa v-bind="attrs" v-if="type === 'simple'"/> <fa-layers v-else-if="type === 'stacked'"> <fa :icon="props.icon" v-bind="props" v-for="(props, index) in definition.icons" :key="index"/> </fa-layers> diff --git a/resources/ts/components/ui/icon.ts b/resources/ts/components/ui/icon.ts index 0fe37c1..419db53 100644 --- a/resources/ts/components/ui/icon.ts +++ b/resources/ts/components/ui/icon.ts @@ -15,7 +15,7 @@ import { faInfoCircle, faMapMarkerAlt, faMoon, - faQuestionCircle, + faQuestionCircle, faQuestionSquare, faSearch, faSign, faStar, @@ -60,6 +60,7 @@ const messageTypeIcons: Dictionary<Icon> = { const definitions: Dictionary<Icon> = { 'favourite': simple(faStar), + 'unknown': simple(faQuestionSquare), 'add': simple(faCheck), 'add-all': simple(faCheckDouble), 'remove-stop': simple(faTimes), @@ -113,14 +114,20 @@ export class UiIcon extends Vue { validator: value => typeof value === "object" || Object.keys(definitions).includes(value), required: true, }) - icon: keyof typeof definitions; + icon: string | IconDefinition; - get definition() { - return {...(typeof this.icon === "string" ? definitions[this.icon] : { icon: this.icon }), ...this.$attrs}; + get definition(): Icon { + return typeof this.icon === "string" + ? definitions[this.icon] || definitions['unknown'] + : { icon: this.icon as IconDefinition, type: "simple" }; + } + + get attrs() { + return { ...this.definition, ...this.$attrs }; } get type() { - return definitions[this.icon].type; + return this.definition.type; } } -- 2.45.2 From 16882ee06fb3bff202f0403daaf905775515b747 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Tue, 11 Feb 2020 22:48:30 +0100 Subject: [PATCH 10/77] #35 - fluent repository prototype --- src/Event/HandleDatabaseModifierEvent.php | 34 +++++++++++ src/Event/HandleModifierEvent.php | 35 +++++++++++ src/Exception/InvalidOptionException.php | 13 ++++ .../Database/LimitDatabaseHandler.php | 27 +++++++++ .../Database/WithIdDatabaseHandler.php | 45 ++++++++++++++ src/Handlers/ModifierHandler.php | 10 ++++ src/Modifiers/Limit.php | 30 ++++++++++ src/Modifiers/Modifier.php | 8 +++ src/Modifiers/WithId.php | 31 ++++++++++ .../Database/GenericLineRepository.php | 60 +++++++++++++++---- src/Provider/FluentRepository.php | 11 ++++ src/Provider/LineRepository.php | 4 +- src/Provider/Repository.php | 3 +- 13 files changed, 294 insertions(+), 17 deletions(-) create mode 100644 src/Event/HandleDatabaseModifierEvent.php create mode 100644 src/Event/HandleModifierEvent.php create mode 100644 src/Exception/InvalidOptionException.php create mode 100644 src/Handlers/Database/LimitDatabaseHandler.php create mode 100644 src/Handlers/Database/WithIdDatabaseHandler.php create mode 100644 src/Handlers/ModifierHandler.php create mode 100644 src/Modifiers/Limit.php create mode 100644 src/Modifiers/Modifier.php create mode 100644 src/Modifiers/WithId.php create mode 100644 src/Provider/FluentRepository.php diff --git a/src/Event/HandleDatabaseModifierEvent.php b/src/Event/HandleDatabaseModifierEvent.php new file mode 100644 index 0000000..74bbc81 --- /dev/null +++ b/src/Event/HandleDatabaseModifierEvent.php @@ -0,0 +1,34 @@ +<?php + +namespace App\Event; + +use App\Event\HandleModifierEvent; +use App\Modifiers\Modifier; +use App\Provider\Repository; +use Doctrine\ORM\QueryBuilder; + +class HandleDatabaseModifierEvent extends HandleModifierEvent +{ + private $builder; + + public function __construct( + Modifier $modifier, + Repository $repository, + QueryBuilder $builder, + array $meta = [] + ) { + parent::__construct($modifier, $repository, $meta); + + $this->builder = $builder; + } + + public function getBuilder(): QueryBuilder + { + return $this->builder; + } + + public function replaceBuilder(QueryBuilder $builder): void + { + $this->builder = $builder; + } +} diff --git a/src/Event/HandleModifierEvent.php b/src/Event/HandleModifierEvent.php new file mode 100644 index 0000000..af28988 --- /dev/null +++ b/src/Event/HandleModifierEvent.php @@ -0,0 +1,35 @@ +<?php + +namespace App\Event; + +use App\Modifiers\Modifier; +use App\Provider\Repository; + +class HandleModifierEvent +{ + private $repository; + private $modifier; + private $meta = []; + + public function __construct(Modifier $modifier, Repository $repository, array $meta = []) + { + $this->repository = $repository; + $this->modifier = $modifier; + $this->meta = $meta; + } + + public function getModifier(): Modifier + { + return $this->modifier; + } + + public function getRepository() + { + return $this->repository; + } + + public function getMeta(): array + { + return $this->meta; + } +} diff --git a/src/Exception/InvalidOptionException.php b/src/Exception/InvalidOptionException.php new file mode 100644 index 0000000..b052f10 --- /dev/null +++ b/src/Exception/InvalidOptionException.php @@ -0,0 +1,13 @@ +<?php + +namespace App\Exception; + +class InvalidOptionException extends \InvalidArgumentException +{ + public static function invalidType($parameter, $value, array $expected = []) + { + return new \InvalidArgumentException( + sprintf('Expected %s to be of type: %s. %s given.', $parameter, implode(', ', $expected), gettype($value)) + ); + } +} diff --git a/src/Handlers/Database/LimitDatabaseHandler.php b/src/Handlers/Database/LimitDatabaseHandler.php new file mode 100644 index 0000000..202ddce --- /dev/null +++ b/src/Handlers/Database/LimitDatabaseHandler.php @@ -0,0 +1,27 @@ +<?php + +namespace App\Handlers\Database; + +use App\Event\HandleDatabaseModifierEvent; +use App\Event\HandleModifierEvent; +use App\Handlers\ModifierHandler; +use App\Modifiers\Limit; + +class LimitDatabaseHandler implements ModifierHandler +{ + public function process(HandleModifierEvent $event) + { + if (!$event instanceof HandleDatabaseModifierEvent) { + return; + } + + /** @var Limit $modifier */ + $modifier = $event->getModifier(); + $builder = $event->getBuilder(); + + $builder + ->setFirstResult($modifier->getOffset()) + ->setMaxResults($modifier->getCount()) + ; + } +} diff --git a/src/Handlers/Database/WithIdDatabaseHandler.php b/src/Handlers/Database/WithIdDatabaseHandler.php new file mode 100644 index 0000000..1cbb324 --- /dev/null +++ b/src/Handlers/Database/WithIdDatabaseHandler.php @@ -0,0 +1,45 @@ +<?php + +namespace App\Handlers\Database; + +use App\Handlers\ModifierHandler; +use App\Modifiers\WithId; +use App\Event\HandleDatabaseModifierEvent; +use App\Event\HandleModifierEvent; +use App\Service\IdUtils; +use function Kadet\Functional\apply; +use function Kadet\Functional\ref; + +class WithIdDatabaseHandler implements ModifierHandler +{ + /** + * @var IdUtils + */ + private $id; + + public function __construct(IdUtils $id) + { + $this->id = $id; + } + + public function process(HandleModifierEvent $event) + { + if (!$event instanceof HandleDatabaseModifierEvent) { + return; + } + + /** @var WithId $modifier */ + $modifier = $event->getModifier(); + $builder = $event->getBuilder(); + $alias = $event->getMeta()['alias']; + $provider = $event->getMeta()['provider']; + + $id = $modifier->getId(); + $mapper = apply([$this->id, 'generate'], $provider); + + $builder + ->where($modifier->isMultiple() ? "{$alias} in (:id)" : "{$alias} = :id") + ->setParameter(':id', $modifier->isMultiple() ? array_map($mapper, $id) : $mapper($id)); + ; + } +} diff --git a/src/Handlers/ModifierHandler.php b/src/Handlers/ModifierHandler.php new file mode 100644 index 0000000..b4e015e --- /dev/null +++ b/src/Handlers/ModifierHandler.php @@ -0,0 +1,10 @@ +<?php + +namespace App\Handlers; + +use App\Event\HandleModifierEvent; + +interface ModifierHandler +{ + public function process(HandleModifierEvent $event); +} diff --git a/src/Modifiers/Limit.php b/src/Modifiers/Limit.php new file mode 100644 index 0000000..170ea6e --- /dev/null +++ b/src/Modifiers/Limit.php @@ -0,0 +1,30 @@ +<?php + +namespace App\Modifiers; + +class Limit implements Modifier +{ + private $offset; + private $count; + + public function __construct(int $offset = 0, ?int $count = null) + { + $this->offset = $offset; + $this->count = $count; + } + + public function getOffset() + { + return $this->offset; + } + + public function getCount() + { + return $this->count; + } + + public static function count(int $count) + { + return new static(0, $count); + } +} diff --git a/src/Modifiers/Modifier.php b/src/Modifiers/Modifier.php new file mode 100644 index 0000000..a8ddd7c --- /dev/null +++ b/src/Modifiers/Modifier.php @@ -0,0 +1,8 @@ +<?php + +namespace App\Modifiers; + +interface Modifier +{ + +} diff --git a/src/Modifiers/WithId.php b/src/Modifiers/WithId.php new file mode 100644 index 0000000..883db0f --- /dev/null +++ b/src/Modifiers/WithId.php @@ -0,0 +1,31 @@ +<?php + +namespace App\Modifiers; + +use App\Exception\InvalidOptionException; +use App\Modifiers\Modifier; + +class WithId implements Modifier +{ + /** @var string|array */ + private $id; + + public function __construct($id) + { + if (!is_iterable($id) && !is_string($id)) { + throw InvalidOptionException::invalidType('id', $id, ['string', 'array']); + } + + $this->id = $id instanceof \Traversable ? iterator_to_array($id) : $id; + } + + public function getId() + { + return $this->id; + } + + public function isMultiple() + { + return is_array($this->id); + } +} diff --git a/src/Provider/Database/GenericLineRepository.php b/src/Provider/Database/GenericLineRepository.php index e9bab49..66d3cc0 100644 --- a/src/Provider/Database/GenericLineRepository.php +++ b/src/Provider/Database/GenericLineRepository.php @@ -3,8 +3,15 @@ namespace App\Provider\Database; use App\Entity\LineEntity; +use App\Event\HandleDatabaseModifierEvent; +use App\Handlers\Database\LimitDatabaseHandler; +use App\Handlers\Database\WithIdDatabaseHandler; +use App\Handlers\ModifierHandler; use App\Model\Line; +use App\Modifiers\Limit; +use App\Modifiers\WithId; use App\Provider\LineRepository; +use App\Modifiers\Modifier; use Tightenco\Collect\Support\Collection; use Kadet\Functional as f; @@ -12,25 +19,52 @@ class GenericLineRepository extends DatabaseRepository implements LineRepository { public function getAll(): Collection { - $repository = $this->em->getRepository(LineEntity::class); - $lines = $repository->findAll(); - - return collect($lines)->map(f\ref([$this, 'convert'])); + return $this->all(); } public function getById($id): ?Line { - $repository = $this->em->getRepository(LineEntity::class); - return $this->convert($repository->find($id)); + return $this->first(new WithId($id)); } public function getManyById($ids): Collection { - $ids = collect($ids)->map(f\apply(f\ref([$this->id, 'generate']), $this->provider)); - - $repository = $this->em->getRepository(LineEntity::class); - $lines = $repository->findBy(['id' => $ids->all()]); - - return collect($lines)->map(f\ref([$this, 'convert'])); + return $this->all(new WithId($ids)); } -} \ No newline at end of file + + public function first(Modifier ...$modifiers) + { + return $this->all(Limit::count(1), ...$modifiers)->first(); + } + + public function all(Modifier ...$modifiers) + { + $builder = $this->em + ->createQueryBuilder() + ->from(LineEntity::class, 'line') + ->select('line') + ; + + foreach ($modifiers as $modifier) { + $event = new HandleDatabaseModifierEvent($modifier, $this, $builder, [ + 'alias' => 'line', + 'provider' => $this->provider, + ]); + + $handler = $this->getHandlers()[get_class($modifier)]; + + $handler->process($event); + } + + return collect($builder->getQuery()->execute())->map(f\ref([$this, 'convert'])); + } + + /** @return ModifierHandler[] */ + private function getHandlers() + { + return [ + WithId::class => new WithIdDatabaseHandler($this->id), + Limit::class => new LimitDatabaseHandler(), + ]; + } +} diff --git a/src/Provider/FluentRepository.php b/src/Provider/FluentRepository.php new file mode 100644 index 0000000..e24545d --- /dev/null +++ b/src/Provider/FluentRepository.php @@ -0,0 +1,11 @@ +<?php + +namespace App\Provider; + +use App\Modifiers\Modifier; + +interface FluentRepository extends Repository +{ + public function first(Modifier ...$modifiers); + public function all(Modifier ...$modifiers); +} diff --git a/src/Provider/LineRepository.php b/src/Provider/LineRepository.php index 81a6e3a..80bebbd 100644 --- a/src/Provider/LineRepository.php +++ b/src/Provider/LineRepository.php @@ -7,10 +7,10 @@ namespace App\Provider; use App\Model\Line; use Tightenco\Collect\Support\Collection; -interface LineRepository extends Repository +interface LineRepository extends FluentRepository { public function getAll(): Collection; public function getById($id): ?Line; public function getManyById($ids): Collection; -} \ No newline at end of file +} diff --git a/src/Provider/Repository.php b/src/Provider/Repository.php index 008cc99..75b1ed1 100644 --- a/src/Provider/Repository.php +++ b/src/Provider/Repository.php @@ -6,5 +6,4 @@ namespace App\Provider; interface Repository { - -} \ No newline at end of file +} -- 2.45.2 From d7fb3032b79dd05e7fff506392d1d54bf4d709bf Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Wed, 12 Feb 2020 20:08:56 +0100 Subject: [PATCH 11/77] #35 - Add service subscriber to database repository --- .../UnsupportedModifierException.php | 14 +++++ ...andler.php => IdFilterDatabaseHandler.php} | 7 +-- src/Modifiers/{WithId.php => IdFilter.php} | 2 +- src/Provider/Database/DatabaseRepository.php | 61 +++++++++++++++++-- .../Database/GenericLineRepository.php | 29 ++++----- .../Database/GenericOperatorRepository.php | 7 ++- .../Database/GenericScheduleRepository.php | 5 ++ .../Database/GenericStopRepository.php | 5 ++ .../Database/GenericTrackRepository.php | 7 ++- .../Database/GenericTripRepository.php | 5 ++ 10 files changed, 112 insertions(+), 30 deletions(-) create mode 100644 src/Exception/UnsupportedModifierException.php rename src/Handlers/Database/{WithIdDatabaseHandler.php => IdFilterDatabaseHandler.php} (86%) rename src/Modifiers/{WithId.php => IdFilter.php} (94%) diff --git a/src/Exception/UnsupportedModifierException.php b/src/Exception/UnsupportedModifierException.php new file mode 100644 index 0000000..4dbd2bf --- /dev/null +++ b/src/Exception/UnsupportedModifierException.php @@ -0,0 +1,14 @@ +<?php + +namespace App\Exception; + +use App\Modifiers\Modifier; +use App\Provider\Repository; + +class UnsupportedModifierException extends \Exception +{ + public static function createFromModifier(Modifier $modifier, Repository $repository) + { + return new static(sprintf("Modifier %s is not supported by %s.", get_class($modifier), get_class($repository))); + } +} diff --git a/src/Handlers/Database/WithIdDatabaseHandler.php b/src/Handlers/Database/IdFilterDatabaseHandler.php similarity index 86% rename from src/Handlers/Database/WithIdDatabaseHandler.php rename to src/Handlers/Database/IdFilterDatabaseHandler.php index 1cbb324..58a89db 100644 --- a/src/Handlers/Database/WithIdDatabaseHandler.php +++ b/src/Handlers/Database/IdFilterDatabaseHandler.php @@ -3,14 +3,13 @@ namespace App\Handlers\Database; use App\Handlers\ModifierHandler; -use App\Modifiers\WithId; +use App\Modifiers\IdFilter; use App\Event\HandleDatabaseModifierEvent; use App\Event\HandleModifierEvent; use App\Service\IdUtils; use function Kadet\Functional\apply; -use function Kadet\Functional\ref; -class WithIdDatabaseHandler implements ModifierHandler +class IdFilterDatabaseHandler implements ModifierHandler { /** * @var IdUtils @@ -28,7 +27,7 @@ class WithIdDatabaseHandler implements ModifierHandler return; } - /** @var WithId $modifier */ + /** @var IdFilter $modifier */ $modifier = $event->getModifier(); $builder = $event->getBuilder(); $alias = $event->getMeta()['alias']; diff --git a/src/Modifiers/WithId.php b/src/Modifiers/IdFilter.php similarity index 94% rename from src/Modifiers/WithId.php rename to src/Modifiers/IdFilter.php index 883db0f..e2f570c 100644 --- a/src/Modifiers/WithId.php +++ b/src/Modifiers/IdFilter.php @@ -5,7 +5,7 @@ namespace App\Modifiers; use App\Exception\InvalidOptionException; use App\Modifiers\Modifier; -class WithId implements Modifier +class IdFilter implements Modifier { /** @var string|array */ private $id; diff --git a/src/Provider/Database/DatabaseRepository.php b/src/Provider/Database/DatabaseRepository.php index 3a97eff..4f4dce3 100644 --- a/src/Provider/Database/DatabaseRepository.php +++ b/src/Provider/Database/DatabaseRepository.php @@ -2,15 +2,19 @@ namespace App\Provider\Database; -use App\Entity\Entity; use App\Entity\ProviderEntity; +use App\Event\HandleDatabaseModifierEvent; +use App\Exception\UnsupportedModifierException; use App\Model\Referable; +use App\Provider\Repository; use App\Service\Converter; use App\Service\IdUtils; use Doctrine\ORM\EntityManagerInterface; -use Kadet\Functional as f; +use Doctrine\ORM\QueryBuilder; +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\ServiceSubscriberInterface; -class DatabaseRepository +abstract class DatabaseRepository implements ServiceSubscriberInterface, Repository { /** @var EntityManagerInterface */ protected $em; @@ -24,22 +28,30 @@ class DatabaseRepository /** @var Converter */ protected $converter; + /** @var ContainerInterface */ + protected $handlers; + /** * DatabaseRepository constructor. * * @param EntityManagerInterface $em */ - public function __construct(EntityManagerInterface $em, IdUtils $id, Converter $converter) - { + public function __construct( + EntityManagerInterface $em, + IdUtils $id, + Converter $converter, + ContainerInterface $handlers + ) { $this->em = $em; $this->id = $id; $this->converter = $converter; + $this->handlers = $handlers; } /** @return static */ public function withProvider(ProviderEntity $provider) { - $result = clone $this; + $result = clone $this; $result->provider = $provider; return $result; @@ -56,4 +68,41 @@ class DatabaseRepository return $this->em->getReference($class, $id); } + + protected function processQueryBuilder(QueryBuilder $builder, iterable $modifiers, array $meta = []) + { + foreach ($modifiers as $modifier) { + $event = new HandleDatabaseModifierEvent($modifier, $this, $builder, array_merge([ + 'provider' => $this->provider, + ], $meta)); + + $class = get_class($modifier); + + if (!$this->handlers->has($class)) { + throw UnsupportedModifierException::createFromModifier($modifier, $this); + } + + $handler = $this->handlers->get($class); + + $handler->process($event); + } + } + + /** + * Returns array describing handlers for each modifier type. Syntax is as follows: + * [ IdFilter::class => IdFilterDatabaseHandler::class ] + * + * It is internally used as part of service subscriber. + * + * @return array + */ + protected abstract static function getHandlers(); + + /** + * @inheritDoc + */ + public static function getSubscribedServices() + { + return static::getHandlers(); + } } diff --git a/src/Provider/Database/GenericLineRepository.php b/src/Provider/Database/GenericLineRepository.php index 66d3cc0..6982cb1 100644 --- a/src/Provider/Database/GenericLineRepository.php +++ b/src/Provider/Database/GenericLineRepository.php @@ -5,11 +5,11 @@ namespace App\Provider\Database; use App\Entity\LineEntity; use App\Event\HandleDatabaseModifierEvent; use App\Handlers\Database\LimitDatabaseHandler; -use App\Handlers\Database\WithIdDatabaseHandler; +use App\Handlers\Database\IdFilterDatabaseHandler; use App\Handlers\ModifierHandler; use App\Model\Line; use App\Modifiers\Limit; -use App\Modifiers\WithId; +use App\Modifiers\IdFilter; use App\Provider\LineRepository; use App\Modifiers\Modifier; use Tightenco\Collect\Support\Collection; @@ -24,12 +24,12 @@ class GenericLineRepository extends DatabaseRepository implements LineRepository public function getById($id): ?Line { - return $this->first(new WithId($id)); + return $this->first(new IdFilter($id)); } public function getManyById($ids): Collection { - return $this->all(new WithId($ids)); + return $this->all(new IdFilter($ids)); } public function first(Modifier ...$modifiers) @@ -45,26 +45,21 @@ class GenericLineRepository extends DatabaseRepository implements LineRepository ->select('line') ; - foreach ($modifiers as $modifier) { - $event = new HandleDatabaseModifierEvent($modifier, $this, $builder, [ - 'alias' => 'line', - 'provider' => $this->provider, - ]); - - $handler = $this->getHandlers()[get_class($modifier)]; - - $handler->process($event); - } + $this->processQueryBuilder($builder, $modifiers, [ + 'alias' => 'line', + 'entity' => LineEntity::class, + 'type' => Line::class, + ]); return collect($builder->getQuery()->execute())->map(f\ref([$this, 'convert'])); } /** @return ModifierHandler[] */ - private function getHandlers() + protected static function getHandlers() { return [ - WithId::class => new WithIdDatabaseHandler($this->id), - Limit::class => new LimitDatabaseHandler(), + IdFilter::class => IdFilterDatabaseHandler::class, + Limit::class => LimitDatabaseHandler::class, ]; } } diff --git a/src/Provider/Database/GenericOperatorRepository.php b/src/Provider/Database/GenericOperatorRepository.php index 946eff6..929d994 100644 --- a/src/Provider/Database/GenericOperatorRepository.php +++ b/src/Provider/Database/GenericOperatorRepository.php @@ -30,4 +30,9 @@ class GenericOperatorRepository extends DatabaseRepository implements OperatorRe return collect($operators); } -} \ No newline at end of file + + protected static function getHandlers() + { + return []; + } +} diff --git a/src/Provider/Database/GenericScheduleRepository.php b/src/Provider/Database/GenericScheduleRepository.php index 551c288..e1c2c29 100644 --- a/src/Provider/Database/GenericScheduleRepository.php +++ b/src/Provider/Database/GenericScheduleRepository.php @@ -70,4 +70,9 @@ class GenericScheduleRepository extends DatabaseRepository implements ScheduleRe ]); }); } + + protected static function getHandlers() + { + return []; + } } diff --git a/src/Provider/Database/GenericStopRepository.php b/src/Provider/Database/GenericStopRepository.php index 8dc1972..fe7b017 100644 --- a/src/Provider/Database/GenericStopRepository.php +++ b/src/Provider/Database/GenericStopRepository.php @@ -83,4 +83,9 @@ class GenericStopRepository extends DatabaseRepository implements StopRepository $stop->setDestinations($destinations[$this->id->generate($this->provider, $stop->getId())]); }); } + + protected static function getHandlers() + { + return []; + } } diff --git a/src/Provider/Database/GenericTrackRepository.php b/src/Provider/Database/GenericTrackRepository.php index 9a25d44..53bd235 100644 --- a/src/Provider/Database/GenericTrackRepository.php +++ b/src/Provider/Database/GenericTrackRepository.php @@ -64,4 +64,9 @@ class GenericTrackRepository extends DatabaseRepository implements TrackReposito return collect($tracks)->map(f\ref([$this, 'convert'])); } -} \ No newline at end of file + + protected static function getHandlers() + { + return []; + } +} diff --git a/src/Provider/Database/GenericTripRepository.php b/src/Provider/Database/GenericTripRepository.php index e85f178..3944e18 100644 --- a/src/Provider/Database/GenericTripRepository.php +++ b/src/Provider/Database/GenericTripRepository.php @@ -25,4 +25,9 @@ class GenericTripRepository extends DatabaseRepository implements TripRepository return $this->convert($trip); } + + protected static function getHandlers() + { + return []; + } } -- 2.45.2 From fd4bcc9c7045b3ce76a2d0e7518bfb3864611141 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Wed, 12 Feb 2020 20:16:26 +0100 Subject: [PATCH 12/77] #35 - Remove unnecessary methods from LineRepository --- src/Provider/Database/DatabaseRepository.php | 5 ++++- src/Provider/Database/GenericLineRepository.php | 17 +---------------- src/Provider/FluentRepository.php | 3 ++- src/Provider/LineRepository.php | 8 -------- .../ZtmGdansk/ZtmGdanskDepartureRepository.php | 4 +++- 5 files changed, 10 insertions(+), 27 deletions(-) diff --git a/src/Provider/Database/DatabaseRepository.php b/src/Provider/Database/DatabaseRepository.php index 4f4dce3..bcc596b 100644 --- a/src/Provider/Database/DatabaseRepository.php +++ b/src/Provider/Database/DatabaseRepository.php @@ -96,7 +96,10 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit * * @return array */ - protected abstract static function getHandlers(); + protected static function getHandlers() + { + return []; + } /** * @inheritDoc diff --git a/src/Provider/Database/GenericLineRepository.php b/src/Provider/Database/GenericLineRepository.php index 6982cb1..244b8e0 100644 --- a/src/Provider/Database/GenericLineRepository.php +++ b/src/Provider/Database/GenericLineRepository.php @@ -17,27 +17,12 @@ use Kadet\Functional as f; class GenericLineRepository extends DatabaseRepository implements LineRepository { - public function getAll(): Collection - { - return $this->all(); - } - - public function getById($id): ?Line - { - return $this->first(new IdFilter($id)); - } - - public function getManyById($ids): Collection - { - return $this->all(new IdFilter($ids)); - } - public function first(Modifier ...$modifiers) { return $this->all(Limit::count(1), ...$modifiers)->first(); } - public function all(Modifier ...$modifiers) + public function all(Modifier ...$modifiers): Collection { $builder = $this->em ->createQueryBuilder() diff --git a/src/Provider/FluentRepository.php b/src/Provider/FluentRepository.php index e24545d..d0644fe 100644 --- a/src/Provider/FluentRepository.php +++ b/src/Provider/FluentRepository.php @@ -3,9 +3,10 @@ namespace App\Provider; use App\Modifiers\Modifier; +use Tightenco\Collect\Support\Collection; interface FluentRepository extends Repository { public function first(Modifier ...$modifiers); - public function all(Modifier ...$modifiers); + public function all(Modifier ...$modifiers): Collection; } diff --git a/src/Provider/LineRepository.php b/src/Provider/LineRepository.php index 80bebbd..2ab6884 100644 --- a/src/Provider/LineRepository.php +++ b/src/Provider/LineRepository.php @@ -3,14 +3,6 @@ namespace App\Provider; - -use App\Model\Line; -use Tightenco\Collect\Support\Collection; - interface LineRepository extends FluentRepository { - public function getAll(): Collection; - - public function getById($id): ?Line; - public function getManyById($ids): Collection; } diff --git a/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php b/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php index 0e956bd..165e571 100644 --- a/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php +++ b/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php @@ -6,6 +6,7 @@ use App\Model\Departure; use App\Model\Line; use App\Model\Stop; use App\Model\Vehicle; +use App\Modifiers\IdFilter; use App\Provider\Database\GenericScheduleRepository; use App\Provider\DepartureRepository; use App\Provider\LineRepository; @@ -65,7 +66,8 @@ class ZtmGdanskDepartureRepository implements DepartureRepository $lines = $estimates->map(function ($delay) { return $delay['routeId']; })->unique(); - $lines = $this->lines->getManyById($lines)->keyBy(t\property('id')); + + $lines = $this->lines->all(new IdFilter($lines))->keyBy(t\property('id')); return collect($estimates)->map(function ($delay) use ($stop, $lines) { $scheduled = (new Carbon($delay['theoreticalTime'], 'Europe/Warsaw'))->tz('UTC'); -- 2.45.2 From d72fcf777f220d9a19ca217d84afab20c7789f4e Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 16 Feb 2020 21:07:16 +0100 Subject: [PATCH 13/77] #35 - Make StopRepository more fluent --- config/services.yaml | 2 +- resources/ts/components/picker.ts | 2 +- resources/ts/urls.ts | 6 +- .../Api/v1/DeparturesController.php | 5 +- src/Controller/Api/v1/StopsController.php | 51 +++++++---- src/Event/HandleDatabaseModifierEvent.php | 2 +- src/Event/HandleModifierEvent.php | 2 +- src/Event/PostProcessEvent.php | 27 ++++++ src/Exception/NonExistentServiceException.php | 5 +- src/Exception/NotSupportedException.php | 4 +- .../UnsupportedModifierException.php | 4 +- .../Database/FieldFilterDatabaseHandler.php | 52 +++++++++++ .../Database/IdFilterDatabaseHandler.php | 6 +- .../IncludeDestinationsDatabaseHandler.php | 76 ++++++++++++++++ .../Database/LimitDatabaseHandler.php | 6 +- src/{Handlers => Handler}/ModifierHandler.php | 2 +- src/Handler/PostProcessingHandler.php | 11 +++ src/Modifier/FieldFilter.php | 37 ++++++++ src/{Modifiers => Modifier}/IdFilter.php | 4 +- src/Modifier/IncludeDestinations.php | 7 ++ src/{Modifiers => Modifier}/Limit.php | 2 +- src/{Modifiers => Modifier}/Modifier.php | 2 +- src/Provider/Database/DatabaseRepository.php | 74 ++++++++++++--- .../Database/GenericLineRepository.php | 30 ++----- .../Database/GenericStopRepository.php | 89 ++++--------------- src/Provider/Dummy/DummyStopRepository.php | 11 +++ src/Provider/FluentRepository.php | 2 +- src/Provider/StopRepository.php | 6 +- .../ZtmGdanskDepartureRepository.php | 2 +- src/Service/IdUtils.php | 3 +- 30 files changed, 374 insertions(+), 158 deletions(-) create mode 100644 src/Event/PostProcessEvent.php create mode 100644 src/Handler/Database/FieldFilterDatabaseHandler.php rename src/{Handlers => Handler}/Database/IdFilterDatabaseHandler.php (91%) create mode 100644 src/Handler/Database/IncludeDestinationsDatabaseHandler.php rename src/{Handlers => Handler}/Database/LimitDatabaseHandler.php (85%) rename src/{Handlers => Handler}/ModifierHandler.php (84%) create mode 100644 src/Handler/PostProcessingHandler.php create mode 100644 src/Modifier/FieldFilter.php rename src/{Modifiers => Modifier}/IdFilter.php (91%) create mode 100644 src/Modifier/IncludeDestinations.php rename src/{Modifiers => Modifier}/Limit.php (95%) rename src/{Modifiers => Modifier}/Modifier.php (56%) diff --git a/config/services.yaml b/config/services.yaml index 853ef0a..4337891 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -23,7 +23,7 @@ services: # this creates a service per class whose id is the fully-qualified class name App\: resource: '../src/*' - exclude: '../src/{DependencyInjection,Entity,Model,Migrations,Tests,Functions,Kernel.php}' + exclude: '../src/{DependencyInjection,Exception,Modifiers,Entity,Model,Migrations,Tests,Functions,Kernel.php}' # controllers are imported separately to make sure services can be injected # as action arguments even if you don't extend any base controller class diff --git a/resources/ts/components/picker.ts b/resources/ts/components/picker.ts index 476d07a..93493d1 100644 --- a/resources/ts/components/picker.ts +++ b/resources/ts/components/picker.ts @@ -80,7 +80,7 @@ export class FinderComponent extends Vue { this.state = 'fetching'; - const response = await fetch(urls.prepare(urls.stops.grouped, { name: this.filter })); + const response = await fetch(urls.prepare(urls.stops.grouped, { name: this.filter, 'include-destinations': true })); if (response.ok) { this.found = (await response.json()).reduce((accumulator, { name, stops }) => Object.assign(accumulator, { [name]: stops }), {}); diff --git a/resources/ts/urls.ts b/resources/ts/urls.ts index e3bb5d1..106a0a1 100644 --- a/resources/ts/urls.ts +++ b/resources/ts/urls.ts @@ -8,7 +8,11 @@ export function query(params: UrlParams = { }) { function *simplify(name: string, param: any): IterableIterator<ParamValuePair> { if (typeof param === 'string') { yield [ name, param ]; - } else if (typeof param === 'number') { + } else if (typeof param === 'boolean') { + if (param) { + yield [ name, '1' ]; + } + } else if (typeof param === 'number') { yield [ name, param.toString() ]; } else if (param instanceof Array) { for (let entry of param) { diff --git a/src/Controller/Api/v1/DeparturesController.php b/src/Controller/Api/v1/DeparturesController.php index 410a753..da07d63 100644 --- a/src/Controller/Api/v1/DeparturesController.php +++ b/src/Controller/Api/v1/DeparturesController.php @@ -5,6 +5,7 @@ namespace App\Controller\Api\v1; use App\Controller\Controller; use App\Model\Departure; +use App\Modifier\IdFilter; use App\Provider\DepartureRepository; use App\Provider\StopRepository; use App\Service\SerializerContextFactory; @@ -34,7 +35,7 @@ class DeparturesController extends Controller */ public function stop(DepartureRepository $departures, StopRepository $stops, $stop) { - $stop = $stops->getById($stop); + $stop = $stops->first(new IdFilter($stop)); return $this->json($departures->getForStop($stop)); } @@ -65,7 +66,7 @@ class DeparturesController extends Controller public function stops(DepartureRepository $departures, StopRepository $stops, Request $request) { $stops = $stops - ->getManyById($request->query->get('stop')) + ->all(new IdFilter($request->query->get('stop'))) ->flatMap(ref([ $departures, 'getForStop' ])) ->sortBy(property('departure')); diff --git a/src/Controller/Api/v1/StopsController.php b/src/Controller/Api/v1/StopsController.php index 76c19a1..0fca3e4 100644 --- a/src/Controller/Api/v1/StopsController.php +++ b/src/Controller/Api/v1/StopsController.php @@ -7,6 +7,9 @@ use App\Controller\Controller; use App\Model\Stop; use App\Model\Track; use App\Model\StopGroup; +use App\Modifier\IdFilter; +use App\Modifier\FieldFilter; +use App\Modifier\IncludeDestinations; use App\Provider\StopRepository; use App\Provider\TrackRepository; use App\Service\Proxy\ReferenceFactory; @@ -46,16 +49,9 @@ class StopsController extends Controller */ public function index(Request $request, StopRepository $stops) { - switch (true) { - case $request->query->has('id'): - $result = $stops->getManyById($request->query->get('id')); - break; + $modifiers = $this->getModifiersFromRequest($request); - default: - $result = $stops->getAll(); - } - - return $this->json($result->all()); + return $this->json($stops->all(...$modifiers)->toArray()); } /** @@ -76,16 +72,9 @@ class StopsController extends Controller */ public function groups(Request $request, StopRepository $stops) { - switch (true) { - case $request->query->has('name'): - $result = $stops->findByName($request->query->get('name')); - break; + $modifiers = $this->getModifiersFromRequest($request); - default: - $result = $stops->getAll(); - } - - return $this->json(static::group($result)->all()); + return $this->json(static::group($stops->all(...$modifiers))->toArray()); } /** @@ -106,7 +95,7 @@ class StopsController extends Controller */ public function one(Request $request, StopRepository $stops, $id) { - return $this->json($stops->getById($id)); + return $this->json($stops->first(new IdFilter($id), new IncludeDestinations())); } /** @@ -145,4 +134,28 @@ class StopsController extends Controller return $group; })->values(); } + + /** + * @param Request $request + * + * @return array + */ + private function getModifiersFromRequest(Request $request): array + { + $modifiers = []; + + if ($request->query->has('name')) { + $modifiers[] = FieldFilter::contains('name', $request->query->get('name')); + } + + if ($request->query->has('id')) { + $modifiers[] = new IdFilter($request->query->get('id')); + } + + if ($request->query->has('include-destinations')) { + $modifiers[] = new IncludeDestinations(); + } + + return $modifiers; + } } diff --git a/src/Event/HandleDatabaseModifierEvent.php b/src/Event/HandleDatabaseModifierEvent.php index 74bbc81..c548d59 100644 --- a/src/Event/HandleDatabaseModifierEvent.php +++ b/src/Event/HandleDatabaseModifierEvent.php @@ -3,7 +3,7 @@ namespace App\Event; use App\Event\HandleModifierEvent; -use App\Modifiers\Modifier; +use App\Modifier\Modifier; use App\Provider\Repository; use Doctrine\ORM\QueryBuilder; diff --git a/src/Event/HandleModifierEvent.php b/src/Event/HandleModifierEvent.php index af28988..5544af4 100644 --- a/src/Event/HandleModifierEvent.php +++ b/src/Event/HandleModifierEvent.php @@ -2,7 +2,7 @@ namespace App\Event; -use App\Modifiers\Modifier; +use App\Modifier\Modifier; use App\Provider\Repository; class HandleModifierEvent diff --git a/src/Event/PostProcessEvent.php b/src/Event/PostProcessEvent.php new file mode 100644 index 0000000..5d23040 --- /dev/null +++ b/src/Event/PostProcessEvent.php @@ -0,0 +1,27 @@ +<?php + +namespace App\Event; + +use App\Modifier\Modifier; +use App\Provider\Repository; + +class PostProcessEvent extends HandleModifierEvent +{ + private $data; + + public function __construct($data, Modifier $modifier, Repository $repository, array $meta = []) + { + parent::__construct($modifier, $repository, $meta); + $this->data = $data; + } + + public function getData() + { + return $this->data; + } + + public function setData($data): void + { + $this->data = $data; + } +} diff --git a/src/Exception/NonExistentServiceException.php b/src/Exception/NonExistentServiceException.php index c2c6ba3..b19aef2 100644 --- a/src/Exception/NonExistentServiceException.php +++ b/src/Exception/NonExistentServiceException.php @@ -4,7 +4,6 @@ namespace App\Exception; -class NonExistentServiceException extends \Exception +class NonExistentServiceException extends \LogicException { - -} \ No newline at end of file +} diff --git a/src/Exception/NotSupportedException.php b/src/Exception/NotSupportedException.php index 4ab7b89..1af7250 100644 --- a/src/Exception/NotSupportedException.php +++ b/src/Exception/NotSupportedException.php @@ -2,6 +2,6 @@ namespace App\Exception; -class NotSupportedException extends \RuntimeException +class NotSupportedException extends \LogicException { -} \ No newline at end of file +} diff --git a/src/Exception/UnsupportedModifierException.php b/src/Exception/UnsupportedModifierException.php index 4dbd2bf..f1e7145 100644 --- a/src/Exception/UnsupportedModifierException.php +++ b/src/Exception/UnsupportedModifierException.php @@ -2,10 +2,10 @@ namespace App\Exception; -use App\Modifiers\Modifier; +use App\Modifier\Modifier; use App\Provider\Repository; -class UnsupportedModifierException extends \Exception +class UnsupportedModifierException extends \LogicException { public static function createFromModifier(Modifier $modifier, Repository $repository) { diff --git a/src/Handler/Database/FieldFilterDatabaseHandler.php b/src/Handler/Database/FieldFilterDatabaseHandler.php new file mode 100644 index 0000000..cb77a66 --- /dev/null +++ b/src/Handler/Database/FieldFilterDatabaseHandler.php @@ -0,0 +1,52 @@ +<?php + +namespace App\Handler\Database; + +use App\Event\HandleDatabaseModifierEvent; +use App\Event\HandleModifierEvent; +use App\Handler\ModifierHandler; +use App\Model\Stop; +use App\Modifier\FieldFilter; + +class FieldFilterDatabaseHandler implements ModifierHandler +{ + protected $mapping = [ + Stop::class => [ + 'name' => 'name', + ], + ]; + + public function process(HandleModifierEvent $event) + { + if (!$event instanceof HandleDatabaseModifierEvent) { + return; + } + + /** @var FieldFilter $modifier */ + $modifier = $event->getModifier(); + $builder = $event->getBuilder(); + $alias = $event->getMeta()['alias']; + + $field = $this->mapFieldName($event->getMeta()['type'], $modifier->getField()); + $operator = $modifier->getOperator(); + $value = $modifier->getValue(); + + $parameter = sprintf(":%s_%s", $alias, $field); + + $builder + ->where(sprintf("%s.%s %s %s", $alias, $field, $operator, $parameter)) + ->setParameter($parameter, $value) + ; + } + + protected function mapFieldName(string $class, string $field) + { + if (!isset($this->mapping[$class][$field])) { + throw new \InvalidArgumentException( + sprintf("Unable to map field %s of %s into entity field.", $field, $class) + ); + } + + return $this->mapping[$class][$field]; + } +} diff --git a/src/Handlers/Database/IdFilterDatabaseHandler.php b/src/Handler/Database/IdFilterDatabaseHandler.php similarity index 91% rename from src/Handlers/Database/IdFilterDatabaseHandler.php rename to src/Handler/Database/IdFilterDatabaseHandler.php index 58a89db..10f124c 100644 --- a/src/Handlers/Database/IdFilterDatabaseHandler.php +++ b/src/Handler/Database/IdFilterDatabaseHandler.php @@ -1,9 +1,9 @@ <?php -namespace App\Handlers\Database; +namespace App\Handler\Database; -use App\Handlers\ModifierHandler; -use App\Modifiers\IdFilter; +use App\Handler\ModifierHandler; +use App\Modifier\IdFilter; use App\Event\HandleDatabaseModifierEvent; use App\Event\HandleModifierEvent; use App\Service\IdUtils; diff --git a/src/Handler/Database/IncludeDestinationsDatabaseHandler.php b/src/Handler/Database/IncludeDestinationsDatabaseHandler.php new file mode 100644 index 0000000..4d5e1f2 --- /dev/null +++ b/src/Handler/Database/IncludeDestinationsDatabaseHandler.php @@ -0,0 +1,76 @@ +<?php + +namespace App\Handler\Database; + +use App\Entity\TrackEntity; +use App\Event\PostProcessEvent; +use App\Handler\PostProcessingHandler; +use App\Model\Destination; +use App\Model\Stop; +use App\Service\Converter; +use App\Service\IdUtils; +use Doctrine\ORM\EntityManagerInterface; +use Tightenco\Collect\Support\Collection; +use Kadet\Functional as f; +use Kadet\Functional\Transforms as t; + +class IncludeDestinationsDatabaseHandler implements PostProcessingHandler +{ + private $em; + private $converter; + private $id; + + public function __construct(EntityManagerInterface $entityManager, Converter $converter, IdUtils $id) + { + $this->em = $entityManager; + $this->converter = $converter; + $this->id = $id; + } + + public function process(PostProcessEvent $event) + { + $provider = $event->getMeta()['provider']; + $stops = $event + ->getData() + ->map(t\property('id')) + ->map(f\apply([$this->id, 'generate'], $provider)) + ->all(); + + $destinations = collect($this->em->createQueryBuilder() + ->select('t', 'tl', 'f', 'fs', 'ts') + ->from(TrackEntity::class, 't') + ->join('t.stopsInTrack', 'ts') + ->join('t.line', 'tl') + ->where('ts.stop IN (:stops)') + ->join('t.final', 'f') + ->join('f.stop', 'fs') + ->getQuery() + ->execute(['stops' => $stops])) + ->reduce(function ($grouped, TrackEntity $track) { + foreach ($track->getStopsInTrack()->map(t\property('stop'))->map(t\property('id')) as $stop) { + $grouped[$stop] = ($grouped[$stop] ?? collect())->add($track); + } + + return $grouped; + }, collect()) + ->map(function (Collection $tracks) { + return $tracks + ->groupBy(function (TrackEntity $track) { + return $track->getFinal()->getStop()->getId(); + })->map(function (Collection $tracks, $id) { + return Destination::createFromArray([ + 'stop' => $this->converter->convert($tracks->first()->getFinal()->getStop()), + 'lines' => $tracks + ->map(t\property('line')) + ->unique(t\property('id')) + ->map(f\ref([$this->converter, 'convert'])) + ->values(), + ]); + })->values(); + }); + + $event->getData()->each(function (Stop $stop) use ($provider, $destinations) { + $stop->setDestinations($destinations[$this->id->generate($provider, $stop->getId())]); + }); + } +} diff --git a/src/Handlers/Database/LimitDatabaseHandler.php b/src/Handler/Database/LimitDatabaseHandler.php similarity index 85% rename from src/Handlers/Database/LimitDatabaseHandler.php rename to src/Handler/Database/LimitDatabaseHandler.php index 202ddce..3f445a9 100644 --- a/src/Handlers/Database/LimitDatabaseHandler.php +++ b/src/Handler/Database/LimitDatabaseHandler.php @@ -1,11 +1,11 @@ <?php -namespace App\Handlers\Database; +namespace App\Handler\Database; use App\Event\HandleDatabaseModifierEvent; use App\Event\HandleModifierEvent; -use App\Handlers\ModifierHandler; -use App\Modifiers\Limit; +use App\Handler\ModifierHandler; +use App\Modifier\Limit; class LimitDatabaseHandler implements ModifierHandler { diff --git a/src/Handlers/ModifierHandler.php b/src/Handler/ModifierHandler.php similarity index 84% rename from src/Handlers/ModifierHandler.php rename to src/Handler/ModifierHandler.php index b4e015e..237f87d 100644 --- a/src/Handlers/ModifierHandler.php +++ b/src/Handler/ModifierHandler.php @@ -1,6 +1,6 @@ <?php -namespace App\Handlers; +namespace App\Handler; use App\Event\HandleModifierEvent; diff --git a/src/Handler/PostProcessingHandler.php b/src/Handler/PostProcessingHandler.php new file mode 100644 index 0000000..4da8a89 --- /dev/null +++ b/src/Handler/PostProcessingHandler.php @@ -0,0 +1,11 @@ +<?php + +namespace App\Handler; + +use App\Event\HandleModifierEvent; +use App\Event\PostProcessEvent; + +interface PostProcessingHandler +{ + public function process(PostProcessEvent $event); +} diff --git a/src/Modifier/FieldFilter.php b/src/Modifier/FieldFilter.php new file mode 100644 index 0000000..e813949 --- /dev/null +++ b/src/Modifier/FieldFilter.php @@ -0,0 +1,37 @@ +<?php + +namespace App\Modifier; + +class FieldFilter implements Modifier +{ + private $field; + private $value; + private $operator; + + public function __construct(string $field, $value, string $operator = '=') + { + $this->field = $field; + $this->value = $value; + $this->operator = $operator; + } + + public static function contains(string $field, string $value) + { + return new static($field, "%$value%", 'LIKE'); + } + + public function getField(): string + { + return $this->field; + } + + public function getValue() + { + return $this->value; + } + + public function getOperator(): string + { + return $this->operator; + } +} diff --git a/src/Modifiers/IdFilter.php b/src/Modifier/IdFilter.php similarity index 91% rename from src/Modifiers/IdFilter.php rename to src/Modifier/IdFilter.php index e2f570c..f7b6a13 100644 --- a/src/Modifiers/IdFilter.php +++ b/src/Modifier/IdFilter.php @@ -1,9 +1,9 @@ <?php -namespace App\Modifiers; +namespace App\Modifier; use App\Exception\InvalidOptionException; -use App\Modifiers\Modifier; +use App\Modifier\Modifier; class IdFilter implements Modifier { diff --git a/src/Modifier/IncludeDestinations.php b/src/Modifier/IncludeDestinations.php new file mode 100644 index 0000000..01d74b2 --- /dev/null +++ b/src/Modifier/IncludeDestinations.php @@ -0,0 +1,7 @@ +<?php + +namespace App\Modifier; + +class IncludeDestinations implements Modifier +{ +} diff --git a/src/Modifiers/Limit.php b/src/Modifier/Limit.php similarity index 95% rename from src/Modifiers/Limit.php rename to src/Modifier/Limit.php index 170ea6e..7b73f8d 100644 --- a/src/Modifiers/Limit.php +++ b/src/Modifier/Limit.php @@ -1,6 +1,6 @@ <?php -namespace App\Modifiers; +namespace App\Modifier; class Limit implements Modifier { diff --git a/src/Modifiers/Modifier.php b/src/Modifier/Modifier.php similarity index 56% rename from src/Modifiers/Modifier.php rename to src/Modifier/Modifier.php index a8ddd7c..e1b3e62 100644 --- a/src/Modifiers/Modifier.php +++ b/src/Modifier/Modifier.php @@ -1,6 +1,6 @@ <?php -namespace App\Modifiers; +namespace App\Modifier; interface Modifier { diff --git a/src/Provider/Database/DatabaseRepository.php b/src/Provider/Database/DatabaseRepository.php index bcc596b..e7e7529 100644 --- a/src/Provider/Database/DatabaseRepository.php +++ b/src/Provider/Database/DatabaseRepository.php @@ -4,8 +4,17 @@ namespace App\Provider\Database; use App\Entity\ProviderEntity; use App\Event\HandleDatabaseModifierEvent; +use App\Event\PostProcessEvent; use App\Exception\UnsupportedModifierException; +use App\Handler\Database\IdFilterDatabaseHandler; +use App\Handler\Database\LimitDatabaseHandler; +use App\Handler\Database\FieldFilterDatabaseHandler; +use App\Handler\PostProcessingHandler; use App\Model\Referable; +use App\Modifier\IdFilter; +use App\Modifier\Limit; +use App\Modifier\Modifier; +use App\Modifier\FieldFilter; use App\Provider\Repository; use App\Service\Converter; use App\Service\IdUtils; @@ -71,21 +80,60 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit protected function processQueryBuilder(QueryBuilder $builder, iterable $modifiers, array $meta = []) { + $reducers = []; + foreach ($modifiers as $modifier) { - $event = new HandleDatabaseModifierEvent($modifier, $this, $builder, array_merge([ - 'provider' => $this->provider, - ], $meta)); + $handler = $this->getHandler($modifier); - $class = get_class($modifier); + switch (true) { + case $handler instanceof PostProcessingHandler: + $reducers[] = function ($result) use ($meta, $modifier, $handler) { + $event = new PostProcessEvent($result, $modifier, $this, array_merge([ + 'provider' => $this->provider, + ], $meta)); - if (!$this->handlers->has($class)) { - throw UnsupportedModifierException::createFromModifier($modifier, $this); + $handler->process($event); + + return $event->getData(); + }; + break; + + default: + $event = new HandleDatabaseModifierEvent($modifier, $this, $builder, array_merge([ + 'provider' => $this->provider, + ], $meta)); + + $handler->process($event); + break; } - - $handler = $this->handlers->get($class); - - $handler->process($event); } + + return collect($reducers); + } + + protected function allFromQueryBuilder(QueryBuilder $builder, iterable $modifiers, array $meta = []) + { + $reducers = $this->processQueryBuilder($builder, $modifiers, $meta); + + return $reducers->reduce(function ($result, $reducer) { + return $reducer($result); + }, collect($builder->getQuery()->execute())->map(\Closure::fromCallable([$this, 'convert']))); + } + + public function first(Modifier ...$modifiers) + { + return $this->all(Limit::count(1), ...$modifiers)->first(); + } + + protected function getHandler(Modifier $modifier) + { + $class = get_class($modifier); + + if (!$this->handlers->has($class)) { + throw UnsupportedModifierException::createFromModifier($modifier, $this); + } + + return $this->handlers->get($class); } /** @@ -106,6 +154,10 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit */ public static function getSubscribedServices() { - return static::getHandlers(); + return array_merge([ + IdFilter::class => IdFilterDatabaseHandler::class, + Limit::class => LimitDatabaseHandler::class, + FieldFilter::class => FieldFilterDatabaseHandler::class, + ], static::getHandlers()); } } diff --git a/src/Provider/Database/GenericLineRepository.php b/src/Provider/Database/GenericLineRepository.php index 244b8e0..9ca147d 100644 --- a/src/Provider/Database/GenericLineRepository.php +++ b/src/Provider/Database/GenericLineRepository.php @@ -4,24 +4,19 @@ namespace App\Provider\Database; use App\Entity\LineEntity; use App\Event\HandleDatabaseModifierEvent; -use App\Handlers\Database\LimitDatabaseHandler; -use App\Handlers\Database\IdFilterDatabaseHandler; -use App\Handlers\ModifierHandler; +use App\Handler\Database\LimitDatabaseHandler; +use App\Handler\Database\IdFilterDatabaseHandler; +use App\Handler\ModifierHandler; use App\Model\Line; -use App\Modifiers\Limit; -use App\Modifiers\IdFilter; +use App\Modifier\Limit; +use App\Modifier\IdFilter; use App\Provider\LineRepository; -use App\Modifiers\Modifier; +use App\Modifier\Modifier; use Tightenco\Collect\Support\Collection; use Kadet\Functional as f; class GenericLineRepository extends DatabaseRepository implements LineRepository { - public function first(Modifier ...$modifiers) - { - return $this->all(Limit::count(1), ...$modifiers)->first(); - } - public function all(Modifier ...$modifiers): Collection { $builder = $this->em @@ -30,21 +25,10 @@ class GenericLineRepository extends DatabaseRepository implements LineRepository ->select('line') ; - $this->processQueryBuilder($builder, $modifiers, [ + return $this->allFromQueryBuilder($builder, $modifiers, [ 'alias' => 'line', 'entity' => LineEntity::class, 'type' => Line::class, ]); - - return collect($builder->getQuery()->execute())->map(f\ref([$this, 'convert'])); - } - - /** @return ModifierHandler[] */ - protected static function getHandlers() - { - return [ - IdFilter::class => IdFilterDatabaseHandler::class, - Limit::class => LimitDatabaseHandler::class, - ]; } } diff --git a/src/Provider/Database/GenericStopRepository.php b/src/Provider/Database/GenericStopRepository.php index fe7b017..62a7a90 100644 --- a/src/Provider/Database/GenericStopRepository.php +++ b/src/Provider/Database/GenericStopRepository.php @@ -3,89 +3,34 @@ namespace App\Provider\Database; use App\Entity\StopEntity; -use App\Entity\TrackEntity; -use App\Model\Destination; +use App\Handler\Database\IncludeDestinationsDatabaseHandler; use App\Model\Stop; +use App\Modifier\Modifier; +use App\Modifier\IncludeDestinations; use App\Provider\StopRepository; -use Kadet\Functional as f; -use Kadet\Functional\Transforms as t; use Tightenco\Collect\Support\Collection; class GenericStopRepository extends DatabaseRepository implements StopRepository { - public function getAll(): Collection + public function all(Modifier ...$modifiers): Collection { - $stops = $this->em->getRepository(StopEntity::class)->findAll(); + $builder = $this->em + ->createQueryBuilder() + ->from(StopEntity::class, 'stop') + ->select('stop') + ; - return collect($stops)->map(f\ref([$this, 'convert'])); - } - - public function getById($id): ?Stop - { - $id = $this->id->generate($this->provider, $id); - $stop = $this->em->getRepository(StopEntity::class)->find($id); - - return $this->convert($stop); - } - - public function getManyById($ids): Collection - { - $ids = collect($ids)->map(f\apply(f\ref([$this->id, 'generate']), $this->provider)); - $stops = $this->em->getRepository(StopEntity::class)->findBy(['id' => $ids->all()]); - - return collect($stops)->map(f\ref([$this, 'convert'])); - } - - public function findByName(string $name): Collection - { - $query = $this->em->createQueryBuilder() - ->select('s') - ->from(StopEntity::class, 's') - ->where('s.name LIKE :name') - ->getQuery(); - - $stops = collect($query->execute([':name' => "%$name%"])); - - $destinations = collect($this->em->createQueryBuilder() - ->select('t', 'tl', 'f', 'fs', 'ts') - ->from(TrackEntity::class, 't') - ->join('t.stopsInTrack', 'ts') - ->join('t.line', 'tl') - ->where('ts.stop IN (:stops)') - ->join('t.final', 'f') - ->join('f.stop', 'fs') - ->getQuery() - ->execute(['stops' => $stops->map(t\property('id'))->all()])) - ->reduce(function ($grouped, TrackEntity $track) { - foreach ($track->getStopsInTrack()->map(t\property('stop'))->map(t\property('id')) as $stop) { - $grouped[$stop] = ($grouped[$stop] ?? collect())->add($track); - } - - return $grouped; - }, collect()) - ->map(function (Collection $tracks) { - return $tracks - ->groupBy(function (TrackEntity $track) { - return $track->getFinal()->getStop()->getId(); - })->map(function (Collection $tracks, $id) { - return Destination::createFromArray([ - 'stop' => $this->convert($tracks->first()->getFinal()->getStop()), - 'lines' => $tracks - ->map(t\property('line')) - ->unique(t\property('id')) - ->map(f\ref([$this, 'convert'])) - ->values(), - ]); - })->values(); - }); - - return collect($stops)->map(f\ref([$this, 'convert']))->each(function (Stop $stop) use ($destinations) { - $stop->setDestinations($destinations[$this->id->generate($this->provider, $stop->getId())]); - }); + return $this->allFromQueryBuilder($builder, $modifiers, [ + 'alias' => 'stop', + 'entity' => StopEntity::class, + 'type' => Stop::class, + ]); } protected static function getHandlers() { - return []; + return array_merge(parent::getHandlers(), [ + IncludeDestinations::class => IncludeDestinationsDatabaseHandler::class, + ]); } } diff --git a/src/Provider/Dummy/DummyStopRepository.php b/src/Provider/Dummy/DummyStopRepository.php index caea318..959d5bd 100644 --- a/src/Provider/Dummy/DummyStopRepository.php +++ b/src/Provider/Dummy/DummyStopRepository.php @@ -3,6 +3,7 @@ namespace App\Provider\Dummy; use App\Model\Stop; +use App\Modifier\Modifier; use App\Provider\StopRepository; use App\Service\Proxy\ReferenceFactory; use Tightenco\Collect\Support\Collection; @@ -41,4 +42,14 @@ class DummyStopRepository implements StopRepository { return collect(); } + + public function first(Modifier ...$modifiers) + { + // TODO: Implement first() method. + } + + public function all(Modifier ...$modifiers): Collection + { + // TODO: Implement all() method. + } } diff --git a/src/Provider/FluentRepository.php b/src/Provider/FluentRepository.php index d0644fe..a02831c 100644 --- a/src/Provider/FluentRepository.php +++ b/src/Provider/FluentRepository.php @@ -2,7 +2,7 @@ namespace App\Provider; -use App\Modifiers\Modifier; +use App\Modifier\Modifier; use Tightenco\Collect\Support\Collection; interface FluentRepository extends Repository diff --git a/src/Provider/StopRepository.php b/src/Provider/StopRepository.php index ea87c03..bf6aa3f 100644 --- a/src/Provider/StopRepository.php +++ b/src/Provider/StopRepository.php @@ -7,10 +7,6 @@ namespace App\Provider; use App\Model\Stop; use Tightenco\Collect\Support\Collection; -interface StopRepository extends Repository +interface StopRepository extends FluentRepository { - public function getAll(): Collection; - public function getById($id): ?Stop; - public function getManyById($ids): Collection; - public function findByName(string $name): Collection; } diff --git a/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php b/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php index 165e571..e7f7dc6 100644 --- a/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php +++ b/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php @@ -6,7 +6,7 @@ use App\Model\Departure; use App\Model\Line; use App\Model\Stop; use App\Model\Vehicle; -use App\Modifiers\IdFilter; +use App\Modifier\IdFilter; use App\Provider\Database\GenericScheduleRepository; use App\Provider\DepartureRepository; use App\Provider\LineRepository; diff --git a/src/Service/IdUtils.php b/src/Service/IdUtils.php index 61bc00b..e652ad4 100644 --- a/src/Service/IdUtils.php +++ b/src/Service/IdUtils.php @@ -11,6 +11,7 @@ class IdUtils public function generate(ProviderEntity $provider, $id) { + // todo: use array cache if not fast enough return sprintf('%s%s%s', $provider->getId(), self::DELIMITER, $id); } @@ -23,4 +24,4 @@ class IdUtils { return $this->strip($entity->getId()); } -} \ No newline at end of file +} -- 2.45.2 From c7dc90bfc5b878f8da955e0f1351c90c98c89f58 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 16 Feb 2020 21:59:38 +0100 Subject: [PATCH 14/77] #35 - Move trip and operator repository to fluent pattern --- src/Controller/Api/v1/TripController.php | 3 +- .../Database/GenericOperatorRepository.php | 37 +++++++------------ .../Database/GenericTripRepository.php | 29 ++++++--------- src/Provider/OperatorRepository.php | 7 +--- src/Provider/TripRepository.php | 3 +- 5 files changed, 30 insertions(+), 49 deletions(-) diff --git a/src/Controller/Api/v1/TripController.php b/src/Controller/Api/v1/TripController.php index 87b87cd..031f39a 100644 --- a/src/Controller/Api/v1/TripController.php +++ b/src/Controller/Api/v1/TripController.php @@ -4,6 +4,7 @@ namespace App\Controller\Api\v1; use App\Controller\Controller; use App\Model\Trip; +use App\Modifier\IdFilter; use App\Provider\TripRepository; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; @@ -18,7 +19,7 @@ class TripController extends Controller */ public function one($id, TripRepository $repository) { - $trip = $repository->getById($id); + $trip = $repository->all(new IdFilter($id)); return $this->json($trip, Response::HTTP_OK, [], $this->serializerContextFactory->create(Trip::class)); } diff --git a/src/Provider/Database/GenericOperatorRepository.php b/src/Provider/Database/GenericOperatorRepository.php index 929d994..2af85f7 100644 --- a/src/Provider/Database/GenericOperatorRepository.php +++ b/src/Provider/Database/GenericOperatorRepository.php @@ -2,37 +2,26 @@ namespace App\Provider\Database; +use App\Entity\OperatorEntity; use App\Model\Operator; +use App\Modifier\Modifier; use App\Provider\OperatorRepository; use Tightenco\Collect\Support\Collection; class GenericOperatorRepository extends DatabaseRepository implements OperatorRepository { - public function getAll(): Collection + public function all(Modifier ...$modifiers): Collection { - $repository = $this->em->getRepository(Operator::class); - $operators = $repository->findAll(); + $builder = $this->em + ->createQueryBuilder() + ->from(OperatorEntity::class, 'operator') + ->select('operator') + ; - return collect($operators); - } - - public function getById($id): ?Operator - { - $repository = $this->em->getRepository(Operator::class); - - return $repository->find($id); - } - - public function getManyById($ids): Collection - { - $repository = $this->em->getRepository(Operator::class); - $operators = $repository->findBy(['id' => $ids]); - - return collect($operators); - } - - protected static function getHandlers() - { - return []; + return $this->allFromQueryBuilder($builder, $modifiers, [ + 'alias' => 'operator', + 'entity' => OperatorEntity::class, + 'type' => Operator::class, + ]); } } diff --git a/src/Provider/Database/GenericTripRepository.php b/src/Provider/Database/GenericTripRepository.php index 3944e18..00626ad 100644 --- a/src/Provider/Database/GenericTripRepository.php +++ b/src/Provider/Database/GenericTripRepository.php @@ -4,30 +4,25 @@ namespace App\Provider\Database; use App\Entity\TripEntity; use App\Model\Trip; +use App\Modifier\Modifier; use App\Provider\TripRepository; +use Tightenco\Collect\Support\Collection; class GenericTripRepository extends DatabaseRepository implements TripRepository { - public function getById(string $id): Trip + public function all(Modifier ...$modifiers): Collection { - $id = $this->id->generate($this->provider, $id); - - $trip = $this->em + $builder = $this->em ->createQueryBuilder() - ->from(TripEntity::class, 't') - ->join('t.stops', 'ts') + ->from(TripEntity::class, 'trip') + ->join('trip.stops', 'ts') ->join('ts.stop', 's') - ->select('t', 'ts') - ->where('t.id = :id') - ->getQuery() - ->setParameter('id', $id) - ->getOneOrNullResult(); + ->select('t', 'ts'); - return $this->convert($trip); - } - - protected static function getHandlers() - { - return []; + return $this->allFromQueryBuilder($builder, $modifiers, [ + 'alias' => 'operator', + 'entity' => TripEntity::class, + 'type' => Trip::class, + ]); } } diff --git a/src/Provider/OperatorRepository.php b/src/Provider/OperatorRepository.php index 79f8b20..70d88c7 100644 --- a/src/Provider/OperatorRepository.php +++ b/src/Provider/OperatorRepository.php @@ -7,9 +7,6 @@ namespace App\Provider; use App\Model\Operator; use Tightenco\Collect\Support\Collection; -interface OperatorRepository +interface OperatorRepository extends FluentRepository { - public function getAll(): Collection; - public function getById($id): ?Operator; - public function getManyById($ids): Collection; -} \ No newline at end of file +} diff --git a/src/Provider/TripRepository.php b/src/Provider/TripRepository.php index 4a82521..17459d8 100644 --- a/src/Provider/TripRepository.php +++ b/src/Provider/TripRepository.php @@ -4,7 +4,6 @@ namespace App\Provider; use App\Model\Trip; -interface TripRepository +interface TripRepository extends FluentRepository { - public function getById(string $id): Trip; } -- 2.45.2 From 9d0e4fdb2a3f1682d1837f3305023795138c58b1 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Mon, 17 Feb 2020 21:48:00 +0100 Subject: [PATCH 15/77] #35 - Rewrite Track Repository into fluent pattern --- src/Controller/Api/v1/StopsController.php | 1 + src/Controller/Api/v1/TracksController.php | 11 ++- .../Database/FieldFilterDatabaseHandler.php | 8 +- .../Database/IdFilterDatabaseHandler.php | 2 +- .../IncludeDestinationsDatabaseHandler.php | 2 +- .../RelatedFilterDatabaseGenericHandler.php | 96 +++++++++++++++++++ src/Handler/PostProcessingHandler.php | 3 +- src/Modifier/RelatedFilter.php | 27 ++++++ src/Provider/Database/DatabaseRepository.php | 39 ++++---- .../Database/GenericTrackRepository.php | 49 +++------- .../Database/GenericTripRepository.php | 2 +- src/Provider/TrackRepository.php | 10 +- 12 files changed, 177 insertions(+), 73 deletions(-) create mode 100644 src/Handler/Database/RelatedFilterDatabaseGenericHandler.php create mode 100644 src/Modifier/RelatedFilter.php diff --git a/src/Controller/Api/v1/StopsController.php b/src/Controller/Api/v1/StopsController.php index 0fca3e4..64c4107 100644 --- a/src/Controller/Api/v1/StopsController.php +++ b/src/Controller/Api/v1/StopsController.php @@ -10,6 +10,7 @@ use App\Model\StopGroup; use App\Modifier\IdFilter; use App\Modifier\FieldFilter; use App\Modifier\IncludeDestinations; +use App\Modifier\RelatedFilter; use App\Provider\StopRepository; use App\Provider\TrackRepository; use App\Service\Proxy\ReferenceFactory; diff --git a/src/Controller/Api/v1/TracksController.php b/src/Controller/Api/v1/TracksController.php index 069a338..6f9fbad 100644 --- a/src/Controller/Api/v1/TracksController.php +++ b/src/Controller/Api/v1/TracksController.php @@ -3,8 +3,11 @@ namespace App\Controller\Api\v1; use App\Controller\Controller; +use App\Model\Line; use App\Model\Stop; use App\Model\Track; +use App\Modifier\IdFilter; +use App\Modifier\RelatedFilter; use App\Provider\TrackRepository; use Nelmio\ApiDocBundle\Annotation\Model; use Swagger\Annotations as SWG; @@ -49,7 +52,7 @@ class TracksController extends Controller { $id = encapsulate($request->query->get('id')); - return $this->json($repository->getManyById($id)); + return $this->json($repository->all(new IdFilter($id))); } private function byStop(Request $request, TrackRepository $repository) @@ -63,8 +66,8 @@ class TracksController extends Controller private function byLine(Request $request, TrackRepository $repository) { $line = $request->query->get('line'); - $line = array_map([Stop::class, 'reference'], encapsulate($line)); + $line = Line::reference($line); - return $this->json($repository->getByLine($line)); + return $this->json($repository->all(new RelatedFilter($line))); } -} \ No newline at end of file +} diff --git a/src/Handler/Database/FieldFilterDatabaseHandler.php b/src/Handler/Database/FieldFilterDatabaseHandler.php index cb77a66..0bfc83c 100644 --- a/src/Handler/Database/FieldFilterDatabaseHandler.php +++ b/src/Handler/Database/FieldFilterDatabaseHandler.php @@ -7,6 +7,7 @@ use App\Event\HandleModifierEvent; use App\Handler\ModifierHandler; use App\Model\Stop; use App\Modifier\FieldFilter; +use function App\Functions\encapsulate; class FieldFilterDatabaseHandler implements ModifierHandler { @@ -33,8 +34,13 @@ class FieldFilterDatabaseHandler implements ModifierHandler $parameter = sprintf(":%s_%s", $alias, $field); + if ($operator === 'in' || $operator === 'not in') { + $parameter = "($parameter)"; + $value = encapsulate($value); + } + $builder - ->where(sprintf("%s.%s %s %s", $alias, $field, $operator, $parameter)) + ->andWhere(sprintf("%s.%s %s %s", $alias, $field, $operator, $parameter)) ->setParameter($parameter, $value) ; } diff --git a/src/Handler/Database/IdFilterDatabaseHandler.php b/src/Handler/Database/IdFilterDatabaseHandler.php index 10f124c..9f95d94 100644 --- a/src/Handler/Database/IdFilterDatabaseHandler.php +++ b/src/Handler/Database/IdFilterDatabaseHandler.php @@ -37,7 +37,7 @@ class IdFilterDatabaseHandler implements ModifierHandler $mapper = apply([$this->id, 'generate'], $provider); $builder - ->where($modifier->isMultiple() ? "{$alias} in (:id)" : "{$alias} = :id") + ->andWhere($modifier->isMultiple() ? "{$alias} in (:id)" : "{$alias} = :id") ->setParameter(':id', $modifier->isMultiple() ? array_map($mapper, $id) : $mapper($id)); ; } diff --git a/src/Handler/Database/IncludeDestinationsDatabaseHandler.php b/src/Handler/Database/IncludeDestinationsDatabaseHandler.php index 4d5e1f2..b58287f 100644 --- a/src/Handler/Database/IncludeDestinationsDatabaseHandler.php +++ b/src/Handler/Database/IncludeDestinationsDatabaseHandler.php @@ -27,7 +27,7 @@ class IncludeDestinationsDatabaseHandler implements PostProcessingHandler $this->id = $id; } - public function process(PostProcessEvent $event) + public function postProcess(PostProcessEvent $event) { $provider = $event->getMeta()['provider']; $stops = $event diff --git a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php new file mode 100644 index 0000000..cb4627e --- /dev/null +++ b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php @@ -0,0 +1,96 @@ +<?php + +namespace App\Handler\Database; + +use App\Entity\LineEntity; +use App\Entity\ProviderEntity; +use App\Event\HandleDatabaseModifierEvent; +use App\Event\HandleModifierEvent; +use App\Handler\ModifierHandler; +use App\Model\Line; +use App\Model\Referable; +use App\Model\Track; +use App\Modifier\RelatedFilter; +use App\Service\IdUtils; +use Doctrine\ORM\EntityManagerInterface; +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\ServiceSubscriberInterface; + +class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSubscriberInterface +{ + protected $mapping = [ + Track::class => [ + Line::class => 'line', + ], + ]; + + protected $references = [ + Line::class => LineEntity::class, + ]; + + private $em; + private $inner; + private $id; + + public function __construct(ContainerInterface $inner, EntityManagerInterface $em, IdUtils $idUtils) + { + $this->inner = $inner; + $this->em = $em; + $this->id = $idUtils; + } + + public function process(HandleModifierEvent $event) + { + if (!$event instanceof HandleDatabaseModifierEvent) { + return; + } + + /** @var RelatedFilter $modifier */ + $modifier = $event->getModifier(); + $builder = $event->getBuilder(); + $alias = $event->getMeta()['alias']; + $type = $event->getMeta()['type']; + + if (!array_key_exists($type, $this->mapping)) { + throw new \InvalidArgumentException( + sprintf("Relationship filtering for %s is not supported.", $type) + ); + } + + if (!array_key_exists($modifier->getRelationship(), $this->mapping[$type])) { + throw new \InvalidArgumentException( + sprintf("Relationship %s is not supported for .", $type) + ); + } + + $relationship = $this->mapping[$type][$modifier->getRelationship()]; + + $parameter = sprintf(":%s_%s", $alias, $relationship); + $reference = $this->getEntityReference($modifier->getRelated(), $event->getMeta()['provider']); + + $builder + ->join(sprintf('%s.%s', $alias, $relationship), $relationship) + ->andWhere(sprintf("%s = %s", $relationship, $parameter)) + ->setParameter($parameter, $reference) + ; + } + + // todo: extract that to separate service + private function getEntityReference(Referable $object, ProviderEntity $provider) + { + return $this->em->getReference( + $this->references[get_class($object)], + $this->id->generate($provider, $object->getId()) + ); + } + + /** + * @inheritDoc + */ + public static function getSubscribedServices() + { + return [ + TrackRelatedFilterDatabaseHandler::class, + ]; + } +} diff --git a/src/Handler/PostProcessingHandler.php b/src/Handler/PostProcessingHandler.php index 4da8a89..a18f0d8 100644 --- a/src/Handler/PostProcessingHandler.php +++ b/src/Handler/PostProcessingHandler.php @@ -2,10 +2,9 @@ namespace App\Handler; -use App\Event\HandleModifierEvent; use App\Event\PostProcessEvent; interface PostProcessingHandler { - public function process(PostProcessEvent $event); + public function postProcess(PostProcessEvent $event); } diff --git a/src/Modifier/RelatedFilter.php b/src/Modifier/RelatedFilter.php new file mode 100644 index 0000000..f3e9038 --- /dev/null +++ b/src/Modifier/RelatedFilter.php @@ -0,0 +1,27 @@ +<?php + +namespace App\Modifier; + +use App\Model\Referable; + +class RelatedFilter implements Modifier +{ + private $relationship; + private $object; + + public function __construct(Referable $object, ?string $relation = null) + { + $this->object = $object; + $this->relationship = $relation ?: get_class($object); + } + + public function getRelationship(): string + { + return $this->relationship; + } + + public function getRelated(): Referable + { + return $this->object; + } +} diff --git a/src/Provider/Database/DatabaseRepository.php b/src/Provider/Database/DatabaseRepository.php index e7e7529..60ad5ca 100644 --- a/src/Provider/Database/DatabaseRepository.php +++ b/src/Provider/Database/DatabaseRepository.php @@ -9,12 +9,15 @@ use App\Exception\UnsupportedModifierException; use App\Handler\Database\IdFilterDatabaseHandler; use App\Handler\Database\LimitDatabaseHandler; use App\Handler\Database\FieldFilterDatabaseHandler; +use App\Handler\Database\RelatedFilterDatabaseGenericHandler; +use App\Handler\ModifierHandler; use App\Handler\PostProcessingHandler; use App\Model\Referable; use App\Modifier\IdFilter; use App\Modifier\Limit; use App\Modifier\Modifier; use App\Modifier\FieldFilter; +use App\Modifier\RelatedFilter; use App\Provider\Repository; use App\Service\Converter; use App\Service\IdUtils; @@ -85,27 +88,26 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit foreach ($modifiers as $modifier) { $handler = $this->getHandler($modifier); - switch (true) { - case $handler instanceof PostProcessingHandler: - $reducers[] = function ($result) use ($meta, $modifier, $handler) { - $event = new PostProcessEvent($result, $modifier, $this, array_merge([ - 'provider' => $this->provider, - ], $meta)); + if ($handler instanceof ModifierHandler) { + $event = new HandleDatabaseModifierEvent($modifier, $this, $builder, array_merge([ + 'provider' => $this->provider, + ], $meta)); - $handler->process($event); + $handler->process($event); + } - return $event->getData(); - }; - break; - - default: - $event = new HandleDatabaseModifierEvent($modifier, $this, $builder, array_merge([ + if ($handler instanceof PostProcessingHandler) { + $reducers[] = function ($result) use ($meta, $modifier, $handler) { + $event = new PostProcessEvent($result, $modifier, $this, array_merge([ 'provider' => $this->provider, ], $meta)); - $handler->process($event); - break; + $handler->postProcess($event); + + return $event->getData(); + }; } + } return collect($reducers); @@ -155,9 +157,10 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit public static function getSubscribedServices() { return array_merge([ - IdFilter::class => IdFilterDatabaseHandler::class, - Limit::class => LimitDatabaseHandler::class, - FieldFilter::class => FieldFilterDatabaseHandler::class, + IdFilter::class => IdFilterDatabaseHandler::class, + Limit::class => LimitDatabaseHandler::class, + FieldFilter::class => FieldFilterDatabaseHandler::class, + RelatedFilter::class => RelatedFilterDatabaseGenericHandler::class, ], static::getHandlers()); } } diff --git a/src/Provider/Database/GenericTrackRepository.php b/src/Provider/Database/GenericTrackRepository.php index 53bd235..82699d7 100644 --- a/src/Provider/Database/GenericTrackRepository.php +++ b/src/Provider/Database/GenericTrackRepository.php @@ -2,36 +2,18 @@ namespace App\Provider\Database; -use App\Entity\LineEntity; use App\Entity\StopEntity; use App\Entity\StopInTrack; use App\Entity\TrackEntity; -use function App\Functions\encapsulate; -use App\Model\Stop; +use App\Modifier\Modifier; use App\Model\Track; use App\Provider\TrackRepository; use Tightenco\Collect\Support\Collection; use Kadet\Functional as f; +use function App\Functions\encapsulate; class GenericTrackRepository extends DatabaseRepository implements TrackRepository { - public function getAll(): Collection - { - $tracks = $this->em->getRepository(TrackEntity::class)->findAll(); - - return collect($tracks)->map(f\ref([$this, 'convert'])); - } - - public function getById($id): Track - { - // TODO: Implement getById() method. - } - - public function getManyById($ids): Collection - { - // TODO: Implement getManyById() method. - } - public function getByStop($stop): Collection { $reference = f\apply(f\ref([$this, 'reference']), StopEntity::class); @@ -49,24 +31,17 @@ class GenericTrackRepository extends DatabaseRepository implements TrackReposito }); } - public function getByLine($line): Collection + public function all(Modifier ...$modifiers): Collection { - $reference = f\apply(f\ref([$this, 'reference']), LineEntity::class); + $builder = $this->em + ->createQueryBuilder() + ->from(TrackEntity::class, 'track') + ->select('track'); - $tracks = $this->em->createQueryBuilder() - ->from(StopInTrack::class, 'st') - ->join('st.track', 't') - ->join('t.stops', 's') - ->where('st.line in (:line)') - ->select(['st', 't', 's']) - ->getQuery() - ->execute(['stop' => array_map($reference, encapsulate($line))]); - - return collect($tracks)->map(f\ref([$this, 'convert'])); - } - - protected static function getHandlers() - { - return []; + return $this->allFromQueryBuilder($builder, $modifiers, [ + 'alias' => 'track', + 'entity' => TrackEntity::class, + 'type' => Track::class, + ]); } } diff --git a/src/Provider/Database/GenericTripRepository.php b/src/Provider/Database/GenericTripRepository.php index 00626ad..6ffd652 100644 --- a/src/Provider/Database/GenericTripRepository.php +++ b/src/Provider/Database/GenericTripRepository.php @@ -20,7 +20,7 @@ class GenericTripRepository extends DatabaseRepository implements TripRepository ->select('t', 'ts'); return $this->allFromQueryBuilder($builder, $modifiers, [ - 'alias' => 'operator', + 'alias' => 'trip', 'entity' => TripEntity::class, 'type' => Trip::class, ]); diff --git a/src/Provider/TrackRepository.php b/src/Provider/TrackRepository.php index 708e329..3e70a03 100644 --- a/src/Provider/TrackRepository.php +++ b/src/Provider/TrackRepository.php @@ -5,13 +5,7 @@ namespace App\Provider; use App\Model\Track; use Tightenco\Collect\Support\Collection; -interface TrackRepository +interface TrackRepository extends FluentRepository { - public function getAll(): Collection; - - public function getById($id): Track; - public function getManyById($ids): Collection; - public function getByStop($stop): Collection; - public function getByLine($line): Collection; -} \ No newline at end of file +} -- 2.45.2 From f4e3ee6f556dea810dfa927223c3cc3db2299fb6 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Tue, 18 Feb 2020 22:45:16 +0100 Subject: [PATCH 16/77] #35 - Add stop filter for tracks --- src/Controller/Api/v1/StopsController.php | 21 ++----- src/Controller/Api/v1/TracksController.php | 63 ++++++++----------- .../RelatedFilterDatabaseGenericHandler.php | 40 ++++++------ .../Database/TrackByStopDatabaseHandler.php | 43 +++++++++++++ src/Service/ReferenceFactory.php | 42 +++++++++++++ 5 files changed, 137 insertions(+), 72 deletions(-) create mode 100644 src/Handler/Database/TrackByStopDatabaseHandler.php create mode 100644 src/Service/ReferenceFactory.php diff --git a/src/Controller/Api/v1/StopsController.php b/src/Controller/Api/v1/StopsController.php index 64c4107..669e58f 100644 --- a/src/Controller/Api/v1/StopsController.php +++ b/src/Controller/Api/v1/StopsController.php @@ -1,6 +1,5 @@ <?php - namespace App\Controller\Api\v1; use App\Controller\Controller; @@ -42,7 +41,8 @@ class StopsController extends Controller * name="id", * in="query", * type="array", - * description="Stop identificators to retrieve at once. Can be used to bulk load data. If not specified will return all data.", + * description="Stop identificators to retrieve at once. Can be used to bulk load data. If not specified will + * return all data.", * @SWG\Items(type="string") * ) * @@ -136,27 +136,18 @@ class StopsController extends Controller })->values(); } - /** - * @param Request $request - * - * @return array - */ - private function getModifiersFromRequest(Request $request): array + private function getModifiersFromRequest(Request $request) { - $modifiers = []; - if ($request->query->has('name')) { - $modifiers[] = FieldFilter::contains('name', $request->query->get('name')); + yield FieldFilter::contains('name', $request->query->get('name')); } if ($request->query->has('id')) { - $modifiers[] = new IdFilter($request->query->get('id')); + yield new IdFilter($request->query->get('id')); } if ($request->query->has('include-destinations')) { - $modifiers[] = new IncludeDestinations(); + yield new IncludeDestinations(); } - - return $modifiers; } } diff --git a/src/Controller/Api/v1/TracksController.php b/src/Controller/Api/v1/TracksController.php index 6f9fbad..71b7ae8 100644 --- a/src/Controller/Api/v1/TracksController.php +++ b/src/Controller/Api/v1/TracksController.php @@ -9,6 +9,7 @@ use App\Model\Track; use App\Modifier\IdFilter; use App\Modifier\RelatedFilter; use App\Provider\TrackRepository; +use App\Service\IterableUtils; use Nelmio\ApiDocBundle\Annotation\Model; use Swagger\Annotations as SWG; use Symfony\Component\HttpFoundation\Request; @@ -31,43 +32,31 @@ class TracksController extends Controller */ public function index(Request $request, TrackRepository $repository) { - switch (true) { - case $request->query->has('stop'): - return $this->byStop($request, $repository); - case $request->query->has('line'): - return $this->byLine($request, $repository); - case $request->query->has('id'): - return $this->byId($request, $repository); - default: - throw new BadRequestHttpException( - sprintf( - 'At least one parameter of %s must be set.', - implode(', ', ['stop', 'line', 'id']) - ) - ); + $modifiers = $this->getModifiersFromRequest($request); + + return $this->json($repository->all(...$modifiers)); + } + + private function getModifiersFromRequest(Request $request) + { + if ($request->query->has('stop')) { + $stop = $request->query->get('stop'); + $stop = Stop::reference($stop); + + yield new RelatedFilter($stop); + } + + if ($request->query->has('line')) { + $line = $request->query->get('line'); + $line = Line::reference($line); + + yield new RelatedFilter($line); + } + + if ($request->query->has('id')) { + $id = encapsulate($request->query->get('id')); + + yield new IdFilter($id); } } - - private function byId(Request $request, TrackRepository $repository) - { - $id = encapsulate($request->query->get('id')); - - return $this->json($repository->all(new IdFilter($id))); - } - - private function byStop(Request $request, TrackRepository $repository) - { - $stop = $request->query->get('stop'); - $stop = array_map([Stop::class, 'reference'], encapsulate($stop)); - - return $this->json($repository->getByStop($stop)); - } - - private function byLine(Request $request, TrackRepository $repository) - { - $line = $request->query->get('line'); - $line = Line::reference($line); - - return $this->json($repository->all(new RelatedFilter($line))); - } } diff --git a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php index cb4627e..6a2683d 100644 --- a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php +++ b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php @@ -2,16 +2,15 @@ namespace App\Handler\Database; -use App\Entity\LineEntity; -use App\Entity\ProviderEntity; use App\Event\HandleDatabaseModifierEvent; use App\Event\HandleModifierEvent; use App\Handler\ModifierHandler; use App\Model\Line; -use App\Model\Referable; +use App\Model\Stop; use App\Model\Track; use App\Modifier\RelatedFilter; use App\Service\IdUtils; +use App\Service\ReferenceFactory; use Doctrine\ORM\EntityManagerInterface; use Psr\Container\ContainerInterface; use Symfony\Contracts\Service\ServiceSubscriberInterface; @@ -21,22 +20,25 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub protected $mapping = [ Track::class => [ Line::class => 'line', + Stop::class => TrackByStopDatabaseHandler::class, ], ]; - protected $references = [ - Line::class => LineEntity::class, - ]; - private $em; private $inner; private $id; + private $references; - public function __construct(ContainerInterface $inner, EntityManagerInterface $em, IdUtils $idUtils) - { + public function __construct( + ContainerInterface $inner, + EntityManagerInterface $em, + IdUtils $idUtils, + ReferenceFactory $references + ) { $this->inner = $inner; $this->em = $em; $this->id = $idUtils; + $this->references = $references; } public function process(HandleModifierEvent $event) @@ -65,8 +67,15 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub $relationship = $this->mapping[$type][$modifier->getRelationship()]; + if ($this->inner->has($relationship)) { + /** @var ModifierHandler $inner */ + $inner = $this->inner->get($relationship); + $inner->process($event); + return; + } + $parameter = sprintf(":%s_%s", $alias, $relationship); - $reference = $this->getEntityReference($modifier->getRelated(), $event->getMeta()['provider']); + $reference = $this->references->create($modifier->getRelated(), $event->getMeta()['provider']); $builder ->join(sprintf('%s.%s', $alias, $relationship), $relationship) @@ -75,22 +84,13 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub ; } - // todo: extract that to separate service - private function getEntityReference(Referable $object, ProviderEntity $provider) - { - return $this->em->getReference( - $this->references[get_class($object)], - $this->id->generate($provider, $object->getId()) - ); - } - /** * @inheritDoc */ public static function getSubscribedServices() { return [ - TrackRelatedFilterDatabaseHandler::class, + TrackByStopDatabaseHandler::class, ]; } } diff --git a/src/Handler/Database/TrackByStopDatabaseHandler.php b/src/Handler/Database/TrackByStopDatabaseHandler.php new file mode 100644 index 0000000..12789e5 --- /dev/null +++ b/src/Handler/Database/TrackByStopDatabaseHandler.php @@ -0,0 +1,43 @@ +<?php + +namespace App\Handler\Database; + +use App\Entity\StopInTrack; +use App\Event\HandleDatabaseModifierEvent; +use App\Event\HandleModifierEvent; +use App\Handler\ModifierHandler; +use App\Modifier\RelatedFilter; +use App\Service\ReferenceFactory; + +class TrackByStopDatabaseHandler implements ModifierHandler +{ + private $references; + + public function __construct(ReferenceFactory $references) + { + $this->references = $references; + } + + public function process(HandleModifierEvent $event) + { + if (!$event instanceof HandleDatabaseModifierEvent) { + return; + } + + /** @var RelatedFilter $modifier */ + $modifier = $event->getModifier(); + $builder = $event->getBuilder(); + $alias = $event->getMeta()['alias']; + + $relationship = 'stopsInTrack'; + + $parameter = sprintf(":%s_%s", $alias, $relationship); + $reference = $this->references->create($modifier->getRelated(), $event->getMeta()['provider']); + + $builder + ->join(sprintf("%s.%s", $alias, $relationship), 'stop_in_track') + ->andWhere(sprintf("stop_in_track.stop = %s", $parameter)) + ->setParameter($parameter, $reference) + ; + } +} diff --git a/src/Service/ReferenceFactory.php b/src/Service/ReferenceFactory.php new file mode 100644 index 0000000..3d91cd9 --- /dev/null +++ b/src/Service/ReferenceFactory.php @@ -0,0 +1,42 @@ +<?php + +namespace App\Service; + +use App\Entity\LineEntity; +use App\Entity\ProviderEntity; +use App\Entity\StopEntity; +use App\Model\Line; +use App\Model\Referable; +use App\Model\Stop; +use Doctrine\ORM\EntityManagerInterface; + +final class ReferenceFactory +{ + protected $mapping = [ + Line::class => LineEntity::class, + Stop::class => StopEntity::class, + ]; + + private $em; + private $id; + + public function __construct(EntityManagerInterface $em, IdUtils $id) + { + $this->em = $em; + $this->id = $id; + } + + public function create(Referable $object, ProviderEntity $provider) + { + $class = get_class($object); + + if (!array_key_exists($class, $this->mapping)) { + throw new \InvalidArgumentException(sprintf("Cannot make entity reference of %s.", $class)); + } + + return $this->em->getReference( + $this->mapping[$class], + $this->id->generate($provider, $object->getId()) + ); + } +} -- 2.45.2 From 42ee6e091de8426a28b3ed0662568b7625719db2 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Thu, 20 Feb 2020 17:33:31 +0100 Subject: [PATCH 17/77] #35 - Track stops fluent quering --- src/Controller/Api/v1/StopsController.php | 18 ++---- src/Controller/Api/v1/TracksController.php | 36 +++++++++++- src/Entity/TrackEntity.php | 12 ++-- .../{StopInTrack.php => TrackStopEntity.php} | 2 +- .../RelatedFilterDatabaseGenericHandler.php | 21 ++++--- .../Database/TrackByStopDatabaseHandler.php | 6 +- src/Model/Line.php | 2 +- src/Model/ScheduledStop.php | 36 +----------- src/Model/TrackStop.php | 58 +++++++++++++++++++ src/Provider/Database/DatabaseRepository.php | 4 ++ .../Database/GenericScheduleRepository.php | 2 +- .../Database/GenericTrackRepository.php | 29 ++++------ src/Provider/TrackRepository.php | 3 +- .../ZtmGdanskDataUpdateSubscriber.php | 4 +- ...Factory.php => EntityReferenceFactory.php} | 9 ++- src/Service/ScheduledStopConverter.php | 27 ++++++--- 16 files changed, 169 insertions(+), 100 deletions(-) rename src/Entity/{StopInTrack.php => TrackStopEntity.php} (96%) create mode 100644 src/Model/TrackStop.php rename src/Service/{ReferenceFactory.php => EntityReferenceFactory.php} (80%) diff --git a/src/Controller/Api/v1/StopsController.php b/src/Controller/Api/v1/StopsController.php index 669e58f..dc6ac45 100644 --- a/src/Controller/Api/v1/StopsController.php +++ b/src/Controller/Api/v1/StopsController.php @@ -4,7 +4,7 @@ namespace App\Controller\Api\v1; use App\Controller\Controller; use App\Model\Stop; -use App\Model\Track; +use App\Model\TrackStop; use App\Model\StopGroup; use App\Modifier\IdFilter; use App\Modifier\FieldFilter; @@ -12,7 +12,6 @@ use App\Modifier\IncludeDestinations; use App\Modifier\RelatedFilter; use App\Provider\StopRepository; use App\Provider\TrackRepository; -use App\Service\Proxy\ReferenceFactory; use Nelmio\ApiDocBundle\Annotation\Model; use Swagger\Annotations as SWG; use Symfony\Component\HttpFoundation\Request; @@ -105,21 +104,12 @@ class StopsController extends Controller * @SWG\Response( * response=200, * description="Returns specific stop referenced via identificator.", - * @SWG\Schema(type="object", properties={ - * @SWG\Property(property="track", type="object", ref=@Model(type=Track::class)), - * @SWG\Property(property="order", type="integer", minimum="0") - * }) + * @SWG\Schema(ref=@Model(type=TrackStop::class)) * ) - * - * @SWG\Tag(name="Tracks") */ - public function tracks(ReferenceFactory $reference, TrackRepository $tracks, $id) + public function tracks(TrackRepository $tracks, $id) { - $stop = $reference->get(Stop::class, $id); - - return $this->json($tracks->getByStop($stop)->map(function ($tuple) { - return array_combine(['track', 'order'], $tuple); - })); + return $this->json($tracks->stops(new RelatedFilter(Stop::reference($id)))); } public static function group(Collection $stops) diff --git a/src/Controller/Api/v1/TracksController.php b/src/Controller/Api/v1/TracksController.php index 71b7ae8..71e79c9 100644 --- a/src/Controller/Api/v1/TracksController.php +++ b/src/Controller/Api/v1/TracksController.php @@ -19,6 +19,7 @@ use function App\Functions\encapsulate; /** * @Route("/tracks") + * @SWG\Tag(name="Tracks") */ class TracksController extends Controller { @@ -27,7 +28,6 @@ class TracksController extends Controller * response=200, * description="Returns all tracks for specific provider, e.g. ZTM Gdańsk.", * ) - * @SWG\Tag(name="Tracks") * @Route("/", methods={"GET"}) */ public function index(Request $request, TrackRepository $repository) @@ -37,6 +37,17 @@ class TracksController extends Controller return $this->json($repository->all(...$modifiers)); } + /** + * @Route("/stops", methods={"GET"}) + * @Route("/{track}/stops", methods={"GET"}) + */ + public function stops(Request $request, TrackRepository $repository) + { + $modifiers = $this->getStopsModifiersFromRequest($request); + + return $this->json($repository->stops(...$modifiers)); + } + private function getModifiersFromRequest(Request $request) { if ($request->query->has('stop')) { @@ -59,4 +70,27 @@ class TracksController extends Controller yield new IdFilter($id); } } + + private function getStopsModifiersFromRequest(Request $request) + { + if ($request->query->has('stop')) { + $stop = $request->query->get('stop'); + $stop = Stop::reference($stop); + + yield new RelatedFilter($stop); + } + + if ($request->query->has('track') || $request->attributes->has('track')) { + $track = $request->get('track'); + $track = Track::reference($track); + + yield new RelatedFilter($track); + } + + if ($request->query->has('id')) { + $id = encapsulate($request->query->get('id')); + + yield new IdFilter($id); + } + } } diff --git a/src/Entity/TrackEntity.php b/src/Entity/TrackEntity.php index a0eaa1d..856297b 100644 --- a/src/Entity/TrackEntity.php +++ b/src/Entity/TrackEntity.php @@ -45,16 +45,18 @@ class TrackEntity implements Entity, Fillable /** * Stops in track - * @var StopInTrack[]|Collection - * @ORM\OneToMany(targetEntity=StopInTrack::class, fetch="LAZY", mappedBy="track", cascade={"persist"}) + * + * @var TrackStopEntity[]|Collection + * @ORM\OneToMany(targetEntity=TrackStopEntity::class, fetch="LAZY", mappedBy="track", cascade={"persist"}) * @ORM\OrderBy({"order": "ASC"}) */ private $stopsInTrack; /** * Final stop in this track. - * @var StopInTrack - * @ORM\OneToOne(targetEntity=StopInTrack::class, fetch="LAZY") + * + * @var TrackStopEntity + * @ORM\OneToOne(targetEntity=TrackStopEntity::class, fetch="LAZY") */ private $final; @@ -114,7 +116,7 @@ class TrackEntity implements Entity, Fillable $this->final = $this->stopsInTrack->last(); } - public function getFinal(): StopInTrack + public function getFinal(): TrackStopEntity { return $this->final; } diff --git a/src/Entity/StopInTrack.php b/src/Entity/TrackStopEntity.php similarity index 96% rename from src/Entity/StopInTrack.php rename to src/Entity/TrackStopEntity.php index 26cbd55..b32c84b 100644 --- a/src/Entity/StopInTrack.php +++ b/src/Entity/TrackStopEntity.php @@ -14,7 +14,7 @@ use Doctrine\ORM\Mapping as ORM; * @ORM\UniqueConstraint(name="stop_in_track_idx", columns={"stop_id", "track_id", "sequence"}) * }) */ -class StopInTrack implements Fillable, Referable +class TrackStopEntity implements Fillable, Referable { use FillTrait, ReferableEntityTrait; diff --git a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php index 6a2683d..68d2fc9 100644 --- a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php +++ b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php @@ -8,9 +8,10 @@ use App\Handler\ModifierHandler; use App\Model\Line; use App\Model\Stop; use App\Model\Track; +use App\Model\TrackStop; use App\Modifier\RelatedFilter; use App\Service\IdUtils; -use App\Service\ReferenceFactory; +use App\Service\EntityReferenceFactory; use Doctrine\ORM\EntityManagerInterface; use Psr\Container\ContainerInterface; use Symfony\Contracts\Service\ServiceSubscriberInterface; @@ -18,10 +19,14 @@ use Symfony\Contracts\Service\ServiceSubscriberInterface; class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSubscriberInterface { protected $mapping = [ - Track::class => [ + Track::class => [ Line::class => 'line', Stop::class => TrackByStopDatabaseHandler::class, ], + TrackStop::class => [ + Stop::class => 'stop', + Track::class => 'track', + ], ]; private $em; @@ -33,11 +38,11 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub ContainerInterface $inner, EntityManagerInterface $em, IdUtils $idUtils, - ReferenceFactory $references + EntityReferenceFactory $references ) { - $this->inner = $inner; - $this->em = $em; - $this->id = $idUtils; + $this->inner = $inner; + $this->em = $em; + $this->id = $idUtils; $this->references = $references; } @@ -71,6 +76,7 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub /** @var ModifierHandler $inner */ $inner = $this->inner->get($relationship); $inner->process($event); + return; } @@ -80,8 +86,7 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub $builder ->join(sprintf('%s.%s', $alias, $relationship), $relationship) ->andWhere(sprintf("%s = %s", $relationship, $parameter)) - ->setParameter($parameter, $reference) - ; + ->setParameter($parameter, $reference); } /** diff --git a/src/Handler/Database/TrackByStopDatabaseHandler.php b/src/Handler/Database/TrackByStopDatabaseHandler.php index 12789e5..d5476a7 100644 --- a/src/Handler/Database/TrackByStopDatabaseHandler.php +++ b/src/Handler/Database/TrackByStopDatabaseHandler.php @@ -2,18 +2,18 @@ namespace App\Handler\Database; -use App\Entity\StopInTrack; +use App\Entity\TrackStopEntity; use App\Event\HandleDatabaseModifierEvent; use App\Event\HandleModifierEvent; use App\Handler\ModifierHandler; use App\Modifier\RelatedFilter; -use App\Service\ReferenceFactory; +use App\Service\EntityReferenceFactory; class TrackByStopDatabaseHandler implements ModifierHandler { private $references; - public function __construct(ReferenceFactory $references) + public function __construct(EntityReferenceFactory $references) { $this->references = $references; } diff --git a/src/Model/Line.php b/src/Model/Line.php index b339218..f905b7d 100644 --- a/src/Model/Line.php +++ b/src/Model/Line.php @@ -138,4 +138,4 @@ class Line implements Fillable, Referable { $this->operator = $operator; } -} \ No newline at end of file +} diff --git a/src/Model/ScheduledStop.php b/src/Model/ScheduledStop.php index abfda2d..2ae78f2 100644 --- a/src/Model/ScheduledStop.php +++ b/src/Model/ScheduledStop.php @@ -4,22 +4,8 @@ namespace App\Model; use Carbon\Carbon; -class ScheduledStop implements Fillable +class ScheduledStop extends TrackStop { - use FillTrait; - - /** - * Stop (as a place) related to that scheduled bus stop - * @var Stop - */ - private $stop; - - /** - * Order in trip - * @var int - */ - private $order; - /** * Arrival time * @var Carbon @@ -32,26 +18,6 @@ class ScheduledStop implements Fillable */ private $departure; - public function getStop() - { - return $this->stop; - } - - public function setStop($stop): void - { - $this->stop = $stop; - } - - public function getOrder(): int - { - return $this->order; - } - - public function setOrder(int $order): void - { - $this->order = $order; - } - public function getArrival(): Carbon { return $this->arrival; diff --git a/src/Model/TrackStop.php b/src/Model/TrackStop.php new file mode 100644 index 0000000..283151a --- /dev/null +++ b/src/Model/TrackStop.php @@ -0,0 +1,58 @@ +<?php + +namespace App\Model; + +use JMS\Serializer\Annotation as Serializer; + +class TrackStop implements Fillable +{ + use FillTrait; + + /** + * Order in trip + * @var int + */ + private $order; + + /** + * Stop (as a place) related to that scheduled bus stop + * @var Stop + */ + private $stop; + + /** + * Track that this stop is part of. + * @var Track|null + */ + private $track; + + public function getStop() + { + return $this->stop; + } + + public function setStop($stop): void + { + $this->stop = $stop; + } + + public function getOrder(): int + { + return $this->order; + } + + public function setOrder(int $order): void + { + $this->order = $order; + } + + public function getTrack(): ?Track + { + return $this->track; + } + + public function setTrack(?Track $track): void + { + $this->track = $track; + } +} diff --git a/src/Provider/Database/DatabaseRepository.php b/src/Provider/Database/DatabaseRepository.php index 60ad5ca..8156253 100644 --- a/src/Provider/Database/DatabaseRepository.php +++ b/src/Provider/Database/DatabaseRepository.php @@ -28,6 +28,8 @@ use Symfony\Contracts\Service\ServiceSubscriberInterface; abstract class DatabaseRepository implements ServiceSubscriberInterface, Repository { + const DEFAULT_LIMIT = 100; + /** @var EntityManagerInterface */ protected $em; @@ -115,6 +117,8 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit protected function allFromQueryBuilder(QueryBuilder $builder, iterable $modifiers, array $meta = []) { + $builder->setMaxResults(self::DEFAULT_LIMIT); + $reducers = $this->processQueryBuilder($builder, $modifiers, $meta); return $reducers->reduce(function ($result, $reducer) { diff --git a/src/Provider/Database/GenericScheduleRepository.php b/src/Provider/Database/GenericScheduleRepository.php index e1c2c29..ed7adbe 100644 --- a/src/Provider/Database/GenericScheduleRepository.php +++ b/src/Provider/Database/GenericScheduleRepository.php @@ -3,7 +3,7 @@ namespace App\Provider\Database; use App\Entity\StopEntity; -use App\Entity\StopInTrack; +use App\Entity\TrackStopEntity; use App\Entity\TrackEntity; use App\Entity\TripEntity; use App\Entity\TripStopEntity; diff --git a/src/Provider/Database/GenericTrackRepository.php b/src/Provider/Database/GenericTrackRepository.php index 82699d7..f25d7f2 100644 --- a/src/Provider/Database/GenericTrackRepository.php +++ b/src/Provider/Database/GenericTrackRepository.php @@ -2,33 +2,28 @@ namespace App\Provider\Database; -use App\Entity\StopEntity; -use App\Entity\StopInTrack; +use App\Entity\TrackStopEntity; use App\Entity\TrackEntity; +use App\Model\TrackStop; use App\Modifier\Modifier; use App\Model\Track; use App\Provider\TrackRepository; use Tightenco\Collect\Support\Collection; -use Kadet\Functional as f; -use function App\Functions\encapsulate; class GenericTrackRepository extends DatabaseRepository implements TrackRepository { - public function getByStop($stop): Collection + public function stops(Modifier ...$modifiers): Collection { - $reference = f\apply(f\ref([$this, 'reference']), StopEntity::class); + $builder = $this->em + ->createQueryBuilder() + ->from(TrackStopEntity::class, 'track_stop') + ->select(['track_stop']); - $tracks = $this->em->createQueryBuilder() - ->from(StopInTrack::class, 'st') - ->join('st.track', 't') - ->where('st.stop in (:stop)') - ->select(['st', 't']) - ->getQuery() - ->execute(['stop' => array_map($reference, encapsulate($stop))]); - - return collect($tracks)->map(function (StopInTrack $entity) { - return [ $this->convert($entity->getTrack()), $entity->getOrder() ]; - }); + return $this->allFromQueryBuilder($builder, $modifiers, [ + 'alias' => 'track_stop', + 'entity' => TrackStopEntity::class, + 'type' => TrackStop::class, + ]); } public function all(Modifier ...$modifiers): Collection diff --git a/src/Provider/TrackRepository.php b/src/Provider/TrackRepository.php index 3e70a03..2b66a36 100644 --- a/src/Provider/TrackRepository.php +++ b/src/Provider/TrackRepository.php @@ -3,9 +3,10 @@ namespace App\Provider; use App\Model\Track; +use App\Modifier\Modifier; use Tightenco\Collect\Support\Collection; interface TrackRepository extends FluentRepository { - public function getByStop($stop): Collection; + public function stops(Modifier ...$modifiers): Collection; } diff --git a/src/Provider/ZtmGdansk/ZtmGdanskDataUpdateSubscriber.php b/src/Provider/ZtmGdansk/ZtmGdanskDataUpdateSubscriber.php index 146ef55..38bf725 100644 --- a/src/Provider/ZtmGdansk/ZtmGdanskDataUpdateSubscriber.php +++ b/src/Provider/ZtmGdansk/ZtmGdanskDataUpdateSubscriber.php @@ -6,7 +6,7 @@ use App\Entity\LineEntity; use App\Entity\OperatorEntity; use App\Entity\ProviderEntity; use App\Entity\StopEntity; -use App\Entity\StopInTrack; +use App\Entity\TrackStopEntity; use App\Entity\TrackEntity; use App\Entity\TripEntity; use App\Entity\TripStopEntity; @@ -216,7 +216,7 @@ class ZtmGdanskDataUpdateSubscriber implements EventSubscriberInterface return !in_array($stop['stopId'], $this->stopBlacklist); }) ->map(function ($stop) use ($entity, $provider) { - return StopInTrack::createFromArray([ + return TrackStopEntity::createFromArray([ 'stop' => $this->em->getReference( StopEntity::class, $this->ids->generate($provider, $stop['stopId']) diff --git a/src/Service/ReferenceFactory.php b/src/Service/EntityReferenceFactory.php similarity index 80% rename from src/Service/ReferenceFactory.php rename to src/Service/EntityReferenceFactory.php index 3d91cd9..d68bcc0 100644 --- a/src/Service/ReferenceFactory.php +++ b/src/Service/EntityReferenceFactory.php @@ -5,16 +5,19 @@ namespace App\Service; use App\Entity\LineEntity; use App\Entity\ProviderEntity; use App\Entity\StopEntity; +use App\Entity\TrackEntity; use App\Model\Line; use App\Model\Referable; use App\Model\Stop; +use App\Model\Track; use Doctrine\ORM\EntityManagerInterface; -final class ReferenceFactory +final class EntityReferenceFactory { protected $mapping = [ - Line::class => LineEntity::class, - Stop::class => StopEntity::class, + Line::class => LineEntity::class, + Stop::class => StopEntity::class, + Track::class => TrackEntity::class, ]; private $em; diff --git a/src/Service/ScheduledStopConverter.php b/src/Service/ScheduledStopConverter.php index da20f28..c00faae 100644 --- a/src/Service/ScheduledStopConverter.php +++ b/src/Service/ScheduledStopConverter.php @@ -2,6 +2,7 @@ namespace App\Service; +use App\Entity\TrackStopEntity; use App\Entity\TripStopEntity; use App\Model\ScheduledStop; @@ -11,18 +12,28 @@ class ScheduledStopConverter implements Converter, RecursiveConverter public function convert($entity) { - /** @var ScheduledStop $entity */ - return ScheduledStop::createFromArray([ - 'arrival' => $entity->getArrival(), - 'departure' => $entity->getDeparture(), - 'stop' => $this->parent->convert($entity->getStop()), - 'order' => $entity->getOrder(), - ]); + if ($entity instanceof TrackStopEntity) { + return ScheduledStop::createFromArray([ + 'stop' => $this->parent->convert($entity->getStop()), + 'track' => $this->parent->convert($entity->getTrack()), + 'order' => $entity->getOrder(), + ]); + } + + if ($entity instanceof TripStopEntity) { + return ScheduledStop::createFromArray([ + 'arrival' => $entity->getArrival(), + 'departure' => $entity->getDeparture(), + 'stop' => $this->parent->convert($entity->getStop()), + 'order' => $entity->getOrder(), + ]); + } } public function supports($entity) { - return $entity instanceof TripStopEntity; + return $entity instanceof TripStopEntity + || $entity instanceof TrackStopEntity; } } -- 2.45.2 From e8a31f60d185a2b01a127028da3402d7092c1287 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 23 Feb 2020 15:23:14 +0100 Subject: [PATCH 18/77] Various little fixes and improvements --- docker/php/.env | 1 - docker/php/Dockerfile | 5 ++++- webpack.config.js | 7 +++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docker/php/.env b/docker/php/.env index eb54481..ef3fd93 100644 --- a/docker/php/.env +++ b/docker/php/.env @@ -1,2 +1 @@ -XDEBUG_CONFIG=remote_host=172.17.0.1 remote_port=9001 PHP_IDE_CONFIG=serverName=czydojade diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile index 6142fa0..08a914e 100644 --- a/docker/php/Dockerfile +++ b/docker/php/Dockerfile @@ -1,5 +1,7 @@ FROM php:7.3-fpm +ARG XDEBUG_REMOTE_HOST="172.17.0.1" + RUN apt-get update && \ apt-get install -y --no-install-recommends git zip libzip-dev @@ -7,7 +9,8 @@ RUN docker-php-ext-install zip RUN pecl install xdebug-2.9.0 && docker-php-ext-enable xdebug -RUN echo "xdebug.remote_enable = 1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; +RUN echo "xdebug.remote_enable = 1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \ + echo "xdebug.remote_host = ${XDEBUG_REMOTE_HOST}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; RUN echo "date.timezone = Europe/Warsaw" >> /usr/local/etc/php/conf.d/datetime.ini; RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" diff --git a/webpack.config.js b/webpack.config.js index 367d75b..0382428 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -66,8 +66,11 @@ const config = { new GenerateSW({ navigationPreload: true, runtimeCaching: [{ - urlPattern: ({event}) => event.request.mode === 'navigate', - handler: 'NetworkFirst', + urlPattern: ({ event }) => event.request.mode === 'navigate', + handler: 'NetworkFirst', + }, { + urlPattern: /^https?:\/\/api\.maptiler\.com\//, + handler: 'CacheFirst', }], swDest: '../service-worker.js' }) -- 2.45.2 From 7fa5124577ed20c716dc6b7018d7eee49c138aa3 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 23 Feb 2020 17:12:23 +0100 Subject: [PATCH 19/77] #35 - Add support for multiple related objects filtering --- src/Controller/Api/v1/TracksController.php | 17 +++++++------ ...ption.php => InvalidArgumentException.php} | 4 +-- .../RelatedFilterDatabaseGenericHandler.php | 2 +- .../Database/TrackByStopDatabaseHandler.php | 4 ++- src/Modifier/IdFilter.php | 7 +++--- src/Modifier/RelatedFilter.php | 23 ++++++++++++----- src/Service/EntityReferenceFactory.php | 25 ++++++++++++++++++- 7 files changed, 60 insertions(+), 22 deletions(-) rename src/Exception/{InvalidOptionException.php => InvalidArgumentException.php} (70%) diff --git a/src/Controller/Api/v1/TracksController.php b/src/Controller/Api/v1/TracksController.php index 71e79c9..54cece5 100644 --- a/src/Controller/Api/v1/TracksController.php +++ b/src/Controller/Api/v1/TracksController.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Annotation\Route; use function App\Functions\encapsulate; +use function Kadet\Functional\ref; /** * @Route("/tracks") @@ -51,17 +52,17 @@ class TracksController extends Controller private function getModifiersFromRequest(Request $request) { if ($request->query->has('stop')) { - $stop = $request->query->get('stop'); - $stop = Stop::reference($stop); + $stop = encapsulate($request->query->get('stop')); + $stop = collect($stop)->map([Stop::class, 'reference']); - yield new RelatedFilter($stop); + yield new RelatedFilter($stop, Stop::class); } if ($request->query->has('line')) { - $line = $request->query->get('line'); - $line = Line::reference($line); + $line = encapsulate($request->query->get('line')); + $line = collect($line)->map([Line::class, 'reference']); - yield new RelatedFilter($line); + yield new RelatedFilter($line, Line::class); } if ($request->query->has('id')) { @@ -74,8 +75,8 @@ class TracksController extends Controller private function getStopsModifiersFromRequest(Request $request) { if ($request->query->has('stop')) { - $stop = $request->query->get('stop'); - $stop = Stop::reference($stop); + $stop = encapsulate($request->query->get('stop')); + $stop = collect($stop)->map(ref([Stop::class, 'reference'])); yield new RelatedFilter($stop); } diff --git a/src/Exception/InvalidOptionException.php b/src/Exception/InvalidArgumentException.php similarity index 70% rename from src/Exception/InvalidOptionException.php rename to src/Exception/InvalidArgumentException.php index b052f10..14789e4 100644 --- a/src/Exception/InvalidOptionException.php +++ b/src/Exception/InvalidArgumentException.php @@ -2,11 +2,11 @@ namespace App\Exception; -class InvalidOptionException extends \InvalidArgumentException +class InvalidArgumentException extends \InvalidArgumentException { public static function invalidType($parameter, $value, array $expected = []) { - return new \InvalidArgumentException( + return new static( sprintf('Expected %s to be of type: %s. %s given.', $parameter, implode(', ', $expected), gettype($value)) ); } diff --git a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php index 68d2fc9..315b99f 100644 --- a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php +++ b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php @@ -85,7 +85,7 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub $builder ->join(sprintf('%s.%s', $alias, $relationship), $relationship) - ->andWhere(sprintf("%s = %s", $relationship, $parameter)) + ->andWhere(sprintf($modifier->isMultiple() ? "%s in (%s)" : "%s = %s", $relationship, $parameter)) ->setParameter($parameter, $reference); } diff --git a/src/Handler/Database/TrackByStopDatabaseHandler.php b/src/Handler/Database/TrackByStopDatabaseHandler.php index d5476a7..fe84aa0 100644 --- a/src/Handler/Database/TrackByStopDatabaseHandler.php +++ b/src/Handler/Database/TrackByStopDatabaseHandler.php @@ -34,9 +34,11 @@ class TrackByStopDatabaseHandler implements ModifierHandler $parameter = sprintf(":%s_%s", $alias, $relationship); $reference = $this->references->create($modifier->getRelated(), $event->getMeta()['provider']); + $condition = $modifier->isMultiple() ? 'stop_in_track.stop IN (%s)' : 'stop_in_track.stop = %s'; + $builder ->join(sprintf("%s.%s", $alias, $relationship), 'stop_in_track') - ->andWhere(sprintf("stop_in_track.stop = %s", $parameter)) + ->andWhere(sprintf($condition, $parameter)) ->setParameter($parameter, $reference) ; } diff --git a/src/Modifier/IdFilter.php b/src/Modifier/IdFilter.php index f7b6a13..0e791a4 100644 --- a/src/Modifier/IdFilter.php +++ b/src/Modifier/IdFilter.php @@ -2,8 +2,9 @@ namespace App\Modifier; -use App\Exception\InvalidOptionException; +use App\Exception\InvalidArgumentException; use App\Modifier\Modifier; +use App\Service\IterableUtils; class IdFilter implements Modifier { @@ -13,10 +14,10 @@ class IdFilter implements Modifier public function __construct($id) { if (!is_iterable($id) && !is_string($id)) { - throw InvalidOptionException::invalidType('id', $id, ['string', 'array']); + throw InvalidArgumentException::invalidType('id', $id, ['string', 'array']); } - $this->id = $id instanceof \Traversable ? iterator_to_array($id) : $id; + $this->id = is_iterable($id) ? IterableUtils::toArray($id) : $id; } public function getId() diff --git a/src/Modifier/RelatedFilter.php b/src/Modifier/RelatedFilter.php index f3e9038..3375880 100644 --- a/src/Modifier/RelatedFilter.php +++ b/src/Modifier/RelatedFilter.php @@ -2,17 +2,23 @@ namespace App\Modifier; +use App\Exception\InvalidArgumentException; use App\Model\Referable; +use App\Service\IterableUtils; class RelatedFilter implements Modifier { private $relationship; - private $object; + private $reference; - public function __construct(Referable $object, ?string $relation = null) + public function __construct($reference, ?string $relation = null) { - $this->object = $object; - $this->relationship = $relation ?: get_class($object); + if (!is_iterable($reference) && !$reference instanceof Referable) { + throw InvalidArgumentException::invalidType('object', $reference, [Referable::class, 'iterable']); + } + + $this->reference = is_iterable($reference) ? IterableUtils::toArray($reference) : $reference; + $this->relationship = $relation ?: get_class($reference); } public function getRelationship(): string @@ -20,8 +26,13 @@ class RelatedFilter implements Modifier return $this->relationship; } - public function getRelated(): Referable + public function getRelated() { - return $this->object; + return $this->reference; + } + + public function isMultiple() + { + return is_array($this->reference); } } diff --git a/src/Service/EntityReferenceFactory.php b/src/Service/EntityReferenceFactory.php index d68bcc0..6a5d5fd 100644 --- a/src/Service/EntityReferenceFactory.php +++ b/src/Service/EntityReferenceFactory.php @@ -6,11 +6,16 @@ use App\Entity\LineEntity; use App\Entity\ProviderEntity; use App\Entity\StopEntity; use App\Entity\TrackEntity; +use App\Exception\InvalidArgumentException; use App\Model\Line; use App\Model\Referable; use App\Model\Stop; use App\Model\Track; use Doctrine\ORM\EntityManagerInterface; +use Tightenco\Collect\Support\Collection; +use function Kadet\Functional\partial; +use function Kadet\Functional\ref; +use const Kadet\Functional\_; final class EntityReferenceFactory { @@ -29,7 +34,25 @@ final class EntityReferenceFactory $this->id = $id; } - public function create(Referable $object, ProviderEntity $provider) + public function create($object, ProviderEntity $provider) + { + switch (true) { + case $object instanceof Referable: + return $this->createEntityReference($object, $provider); + case is_array($object): + return array_map(partial(ref([$this, 'createEntityReference']), _, $provider), $object); + case $object instanceof Collection: + return $object->map(partial(ref([$this, 'createEntityReference']), _, $provider)); + default: + throw InvalidArgumentException::invalidType( + 'object', + $object, + [Referable::class, Collection::class, 'array'] + ); + } + } + + private function createEntityReference(Referable $object, ProviderEntity $provider) { $class = get_class($object); -- 2.45.2 From 129a4dc588f2bcef8caa384056500bfdaa5eba50 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sat, 14 Mar 2020 12:36:24 +0100 Subject: [PATCH 20/77] Fix situation when there are multiple first stops on same trip --- src/Entity/TripStopEntity.php | 17 +++++++--- src/Migrations/Version20200314112552.php | 43 ++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 src/Migrations/Version20200314112552.php diff --git a/src/Entity/TripStopEntity.php b/src/Entity/TripStopEntity.php index f90df10..f80b012 100644 --- a/src/Entity/TripStopEntity.php +++ b/src/Entity/TripStopEntity.php @@ -4,6 +4,7 @@ namespace App\Entity; use App\Model\Fillable; use App\Model\FillTrait; +use App\Model\Referable; use App\Model\Trip; use App\Service\IdUtils; use Carbon\Carbon; @@ -14,21 +15,28 @@ use JMS\Serializer\Tests\Fixtures\Discriminator\Car; * @ORM\Entity * @ORM\Table("trip_stop") */ -class TripStopEntity implements Fillable +class TripStopEntity implements Fillable, Referable { - use FillTrait; + use FillTrait, ReferableEntityTrait; + + /** + * Identifier for stop coming from provider + * + * @ORM\Column(type="integer") + * @ORM\Id + * @ORM\GeneratedValue + */ + private $id; /** * @var StopEntity * @ORM\ManyToOne(targetEntity=StopEntity::class, fetch="EAGER") - * @ORM\Id */ private $stop; /** * @var TripEntity * @ORM\ManyToOne(targetEntity=TripEntity::class, fetch="EAGER", inversedBy="stops") - * @ORM\Id */ private $trip; @@ -37,7 +45,6 @@ class TripStopEntity implements Fillable * @var int * * @ORM\Column(name="sequence", type="integer") - * @ORM\Id */ private $order; diff --git a/src/Migrations/Version20200314112552.php b/src/Migrations/Version20200314112552.php new file mode 100644 index 0000000..a16a743 --- /dev/null +++ b/src/Migrations/Version20200314112552.php @@ -0,0 +1,43 @@ +<?php + +declare(strict_types=1); + +namespace DoctrineMigrations; + +use Doctrine\DBAL\Schema\Schema; +use Doctrine\Migrations\AbstractMigration; + +/** + * Auto-generated Migration: Please modify to your needs! + */ +final class Version20200314112552 extends AbstractMigration +{ + public function getDescription() : string + { + return ''; + } + + public function up(Schema $schema) : void + { + // this up() migration is auto-generated, please modify it to your needs + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'sqlite', 'Migration can only be executed safely on \'sqlite\'.'); + + $this->addSql('CREATE TEMPORARY TABLE __temp__trip_stop AS SELECT stop_id, trip_id, sequence, arrival, departure FROM trip_stop'); + $this->addSql('DROP TABLE trip_stop'); + $this->addSql('CREATE TABLE trip_stop (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, sequence INTEGER NOT NULL, arrival DATETIME NOT NULL, departure DATETIME NOT NULL, stop_id VARCHAR(255) DEFAULT NULL, trip_id VARCHAR(255) DEFAULT NULL)'); + $this->addSql('INSERT INTO trip_stop (stop_id, trip_id, sequence, arrival, departure) SELECT stop_id, trip_id, sequence, arrival, departure FROM __temp__trip_stop'); + $this->addSql('DROP TABLE __temp__trip_stop'); + } + + public function down(Schema $schema) : void + { + // this down() migration is auto-generated, please modify it to your needs + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'sqlite', 'Migration can only be executed safely on \'sqlite\'.'); + + $this->addSql('CREATE TEMPORARY TABLE __temp__trip_stop AS SELECT sequence, arrival, departure, stop_id, trip_id FROM trip_stop'); + $this->addSql('DROP TABLE trip_stop'); + $this->addSql('CREATE TABLE trip_stop (sequence INTEGER NOT NULL, stop_id VARCHAR(255) NOT NULL COLLATE BINARY, trip_id VARCHAR(255) NOT NULL COLLATE BINARY, arrival DATETIME NOT NULL, departure DATETIME NOT NULL, PRIMARY KEY(stop_id, trip_id, sequence))'); + $this->addSql('INSERT INTO trip_stop (sequence, arrival, departure, stop_id, trip_id) SELECT sequence, arrival, departure, stop_id, trip_id FROM __temp__trip_stop'); + $this->addSql('DROP TABLE __temp__trip_stop'); + } +} -- 2.45.2 From 5703816498d0aad3533a381cf2bba73270a9ab5d Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sat, 14 Mar 2020 12:36:24 +0100 Subject: [PATCH 21/77] Fix situation when there are multiple first stops on same trip --- src/Entity/TripStopEntity.php | 17 +++++++--- src/Migrations/Version20200314112552.php | 43 ++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 src/Migrations/Version20200314112552.php diff --git a/src/Entity/TripStopEntity.php b/src/Entity/TripStopEntity.php index f90df10..f80b012 100644 --- a/src/Entity/TripStopEntity.php +++ b/src/Entity/TripStopEntity.php @@ -4,6 +4,7 @@ namespace App\Entity; use App\Model\Fillable; use App\Model\FillTrait; +use App\Model\Referable; use App\Model\Trip; use App\Service\IdUtils; use Carbon\Carbon; @@ -14,21 +15,28 @@ use JMS\Serializer\Tests\Fixtures\Discriminator\Car; * @ORM\Entity * @ORM\Table("trip_stop") */ -class TripStopEntity implements Fillable +class TripStopEntity implements Fillable, Referable { - use FillTrait; + use FillTrait, ReferableEntityTrait; + + /** + * Identifier for stop coming from provider + * + * @ORM\Column(type="integer") + * @ORM\Id + * @ORM\GeneratedValue + */ + private $id; /** * @var StopEntity * @ORM\ManyToOne(targetEntity=StopEntity::class, fetch="EAGER") - * @ORM\Id */ private $stop; /** * @var TripEntity * @ORM\ManyToOne(targetEntity=TripEntity::class, fetch="EAGER", inversedBy="stops") - * @ORM\Id */ private $trip; @@ -37,7 +45,6 @@ class TripStopEntity implements Fillable * @var int * * @ORM\Column(name="sequence", type="integer") - * @ORM\Id */ private $order; diff --git a/src/Migrations/Version20200314112552.php b/src/Migrations/Version20200314112552.php new file mode 100644 index 0000000..a16a743 --- /dev/null +++ b/src/Migrations/Version20200314112552.php @@ -0,0 +1,43 @@ +<?php + +declare(strict_types=1); + +namespace DoctrineMigrations; + +use Doctrine\DBAL\Schema\Schema; +use Doctrine\Migrations\AbstractMigration; + +/** + * Auto-generated Migration: Please modify to your needs! + */ +final class Version20200314112552 extends AbstractMigration +{ + public function getDescription() : string + { + return ''; + } + + public function up(Schema $schema) : void + { + // this up() migration is auto-generated, please modify it to your needs + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'sqlite', 'Migration can only be executed safely on \'sqlite\'.'); + + $this->addSql('CREATE TEMPORARY TABLE __temp__trip_stop AS SELECT stop_id, trip_id, sequence, arrival, departure FROM trip_stop'); + $this->addSql('DROP TABLE trip_stop'); + $this->addSql('CREATE TABLE trip_stop (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, sequence INTEGER NOT NULL, arrival DATETIME NOT NULL, departure DATETIME NOT NULL, stop_id VARCHAR(255) DEFAULT NULL, trip_id VARCHAR(255) DEFAULT NULL)'); + $this->addSql('INSERT INTO trip_stop (stop_id, trip_id, sequence, arrival, departure) SELECT stop_id, trip_id, sequence, arrival, departure FROM __temp__trip_stop'); + $this->addSql('DROP TABLE __temp__trip_stop'); + } + + public function down(Schema $schema) : void + { + // this down() migration is auto-generated, please modify it to your needs + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'sqlite', 'Migration can only be executed safely on \'sqlite\'.'); + + $this->addSql('CREATE TEMPORARY TABLE __temp__trip_stop AS SELECT sequence, arrival, departure, stop_id, trip_id FROM trip_stop'); + $this->addSql('DROP TABLE trip_stop'); + $this->addSql('CREATE TABLE trip_stop (sequence INTEGER NOT NULL, stop_id VARCHAR(255) NOT NULL COLLATE BINARY, trip_id VARCHAR(255) NOT NULL COLLATE BINARY, arrival DATETIME NOT NULL, departure DATETIME NOT NULL, PRIMARY KEY(stop_id, trip_id, sequence))'); + $this->addSql('INSERT INTO trip_stop (sequence, arrival, departure, stop_id, trip_id) SELECT sequence, arrival, departure, stop_id, trip_id FROM __temp__trip_stop'); + $this->addSql('DROP TABLE __temp__trip_stop'); + } +} -- 2.45.2 From b609b81ddfb4bfcf28fa143bb5147b07a6067d07 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sat, 14 Mar 2020 17:19:43 +0100 Subject: [PATCH 22/77] #35 - Extract HandlerProvider to own class --- config/services.yaml | 10 +++- src/Controller/Api/v1/StopsController.php | 10 ++-- .../UnsupportedModifierException.php | 5 +- ...hp => WithDestinationsDatabaseHandler.php} | 4 +- src/Modifier/IncludeDestinations.php | 7 --- src/Modifier/With.php | 18 +++++++ src/Provider/Database/DatabaseRepository.php | 50 ++++++------------- .../Database/GenericStopRepository.php | 10 ++-- src/Service/HandlerProvider.php | 44 ++++++++++++++++ 9 files changed, 103 insertions(+), 55 deletions(-) rename src/Handler/Database/{IncludeDestinationsDatabaseHandler.php => WithDestinationsDatabaseHandler.php} (97%) delete mode 100644 src/Modifier/IncludeDestinations.php create mode 100644 src/Modifier/With.php create mode 100644 src/Service/HandlerProvider.php diff --git a/config/services.yaml b/config/services.yaml index 4337891..9fe3e71 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -23,7 +23,7 @@ services: # this creates a service per class whose id is the fully-qualified class name App\: resource: '../src/*' - exclude: '../src/{DependencyInjection,Exception,Modifiers,Entity,Model,Migrations,Tests,Functions,Kernel.php}' + exclude: '../src/{DependencyInjection,Exception,Modifie,Entity,Model,Migrations,Tests,Functions,Handler,Kernel.php}' # controllers are imported separately to make sure services can be injected # as action arguments even if you don't extend any base controller class @@ -35,6 +35,10 @@ services: resource: '../src/Provider' public: true + App\Handler\: + resource: '../src/Handler' + tags: [ app.handler ] + # add more service definitions when explicit configuration is needed # please note that last definitions always *replace* previous ones @@ -90,3 +94,7 @@ services: # other servces App\Service\ProviderResolver: arguments: [!tagged app.provider, '%kernel.debug%'] + + App\Service\HandlerProvider: + arguments: [!tagged_locator app.handler] + shared: false diff --git a/src/Controller/Api/v1/StopsController.php b/src/Controller/Api/v1/StopsController.php index dc6ac45..2b83043 100644 --- a/src/Controller/Api/v1/StopsController.php +++ b/src/Controller/Api/v1/StopsController.php @@ -4,12 +4,12 @@ namespace App\Controller\Api\v1; use App\Controller\Controller; use App\Model\Stop; -use App\Model\TrackStop; use App\Model\StopGroup; -use App\Modifier\IdFilter; +use App\Model\TrackStop; use App\Modifier\FieldFilter; -use App\Modifier\IncludeDestinations; +use App\Modifier\IdFilter; use App\Modifier\RelatedFilter; +use App\Modifier\With; use App\Provider\StopRepository; use App\Provider\TrackRepository; use Nelmio\ApiDocBundle\Annotation\Model; @@ -95,7 +95,7 @@ class StopsController extends Controller */ public function one(Request $request, StopRepository $stops, $id) { - return $this->json($stops->first(new IdFilter($id), new IncludeDestinations())); + return $this->json($stops->first(new IdFilter($id), new With("destinations"))); } /** @@ -137,7 +137,7 @@ class StopsController extends Controller } if ($request->query->has('include-destinations')) { - yield new IncludeDestinations(); + yield new With("destinations"); } } } diff --git a/src/Exception/UnsupportedModifierException.php b/src/Exception/UnsupportedModifierException.php index f1e7145..1a03b80 100644 --- a/src/Exception/UnsupportedModifierException.php +++ b/src/Exception/UnsupportedModifierException.php @@ -3,12 +3,11 @@ namespace App\Exception; use App\Modifier\Modifier; -use App\Provider\Repository; class UnsupportedModifierException extends \LogicException { - public static function createFromModifier(Modifier $modifier, Repository $repository) + public static function createFromModifier(Modifier $modifier) { - return new static(sprintf("Modifier %s is not supported by %s.", get_class($modifier), get_class($repository))); + return new static(sprintf("Modifier %s is not supported.", get_class($modifier))); } } diff --git a/src/Handler/Database/IncludeDestinationsDatabaseHandler.php b/src/Handler/Database/WithDestinationsDatabaseHandler.php similarity index 97% rename from src/Handler/Database/IncludeDestinationsDatabaseHandler.php rename to src/Handler/Database/WithDestinationsDatabaseHandler.php index b58287f..f3f7879 100644 --- a/src/Handler/Database/IncludeDestinationsDatabaseHandler.php +++ b/src/Handler/Database/WithDestinationsDatabaseHandler.php @@ -10,11 +10,11 @@ use App\Model\Stop; use App\Service\Converter; use App\Service\IdUtils; use Doctrine\ORM\EntityManagerInterface; -use Tightenco\Collect\Support\Collection; use Kadet\Functional as f; use Kadet\Functional\Transforms as t; +use Tightenco\Collect\Support\Collection; -class IncludeDestinationsDatabaseHandler implements PostProcessingHandler +class WithDestinationsDatabaseHandler implements PostProcessingHandler { private $em; private $converter; diff --git a/src/Modifier/IncludeDestinations.php b/src/Modifier/IncludeDestinations.php deleted file mode 100644 index 01d74b2..0000000 --- a/src/Modifier/IncludeDestinations.php +++ /dev/null @@ -1,7 +0,0 @@ -<?php - -namespace App\Modifier; - -class IncludeDestinations implements Modifier -{ -} diff --git a/src/Modifier/With.php b/src/Modifier/With.php new file mode 100644 index 0000000..bbbbd67 --- /dev/null +++ b/src/Modifier/With.php @@ -0,0 +1,18 @@ +<?php + +namespace App\Modifier; + +class With implements Modifier +{ + private $relationship; + + public function __construct(string $relationship) + { + $this->relationship = $relationship; + } + + public function getRelationship(): string + { + return $this->relationship; + } +} diff --git a/src/Provider/Database/DatabaseRepository.php b/src/Provider/Database/DatabaseRepository.php index 8156253..e4021ec 100644 --- a/src/Provider/Database/DatabaseRepository.php +++ b/src/Provider/Database/DatabaseRepository.php @@ -5,28 +5,26 @@ namespace App\Provider\Database; use App\Entity\ProviderEntity; use App\Event\HandleDatabaseModifierEvent; use App\Event\PostProcessEvent; -use App\Exception\UnsupportedModifierException; +use App\Handler\Database\FieldFilterDatabaseHandler; use App\Handler\Database\IdFilterDatabaseHandler; use App\Handler\Database\LimitDatabaseHandler; -use App\Handler\Database\FieldFilterDatabaseHandler; use App\Handler\Database\RelatedFilterDatabaseGenericHandler; use App\Handler\ModifierHandler; use App\Handler\PostProcessingHandler; use App\Model\Referable; +use App\Modifier\FieldFilter; use App\Modifier\IdFilter; use App\Modifier\Limit; use App\Modifier\Modifier; -use App\Modifier\FieldFilter; use App\Modifier\RelatedFilter; use App\Provider\Repository; use App\Service\Converter; +use App\Service\HandlerProvider; use App\Service\IdUtils; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\QueryBuilder; -use Psr\Container\ContainerInterface; -use Symfony\Contracts\Service\ServiceSubscriberInterface; -abstract class DatabaseRepository implements ServiceSubscriberInterface, Repository +abstract class DatabaseRepository implements Repository { const DEFAULT_LIMIT = 100; @@ -42,7 +40,7 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit /** @var Converter */ protected $converter; - /** @var ContainerInterface */ + /** @var HandlerProvider */ protected $handlers; /** @@ -54,12 +52,19 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit EntityManagerInterface $em, IdUtils $id, Converter $converter, - ContainerInterface $handlers + HandlerProvider $handlers ) { $this->em = $em; $this->id = $id; $this->converter = $converter; $this->handlers = $handlers; + + $this->handlers->loadConfiguration(array_merge([ + IdFilter::class => IdFilterDatabaseHandler::class, + Limit::class => LimitDatabaseHandler::class, + FieldFilter::class => FieldFilterDatabaseHandler::class, + RelatedFilter::class => RelatedFilterDatabaseGenericHandler::class, + ], static::getHandlers())); } /** @return static */ @@ -88,7 +93,7 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit $reducers = []; foreach ($modifiers as $modifier) { - $handler = $this->getHandler($modifier); + $handler = $this->handlers->get($modifier); if ($handler instanceof ModifierHandler) { $event = new HandleDatabaseModifierEvent($modifier, $this, $builder, array_merge([ @@ -120,10 +125,11 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit $builder->setMaxResults(self::DEFAULT_LIMIT); $reducers = $this->processQueryBuilder($builder, $modifiers, $meta); + $result = collect($builder->getQuery()->execute())->map(\Closure::fromCallable([$this, 'convert'])); return $reducers->reduce(function ($result, $reducer) { return $reducer($result); - }, collect($builder->getQuery()->execute())->map(\Closure::fromCallable([$this, 'convert']))); + }, $result); } public function first(Modifier ...$modifiers) @@ -131,17 +137,6 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit return $this->all(Limit::count(1), ...$modifiers)->first(); } - protected function getHandler(Modifier $modifier) - { - $class = get_class($modifier); - - if (!$this->handlers->has($class)) { - throw UnsupportedModifierException::createFromModifier($modifier, $this); - } - - return $this->handlers->get($class); - } - /** * Returns array describing handlers for each modifier type. Syntax is as follows: * [ IdFilter::class => IdFilterDatabaseHandler::class ] @@ -154,17 +149,4 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit { return []; } - - /** - * @inheritDoc - */ - public static function getSubscribedServices() - { - return array_merge([ - IdFilter::class => IdFilterDatabaseHandler::class, - Limit::class => LimitDatabaseHandler::class, - FieldFilter::class => FieldFilterDatabaseHandler::class, - RelatedFilter::class => RelatedFilterDatabaseGenericHandler::class, - ], static::getHandlers()); - } } diff --git a/src/Provider/Database/GenericStopRepository.php b/src/Provider/Database/GenericStopRepository.php index 62a7a90..82e41e6 100644 --- a/src/Provider/Database/GenericStopRepository.php +++ b/src/Provider/Database/GenericStopRepository.php @@ -3,10 +3,10 @@ namespace App\Provider\Database; use App\Entity\StopEntity; -use App\Handler\Database\IncludeDestinationsDatabaseHandler; +use App\Handler\Database\WithDestinationsDatabaseHandler; use App\Model\Stop; use App\Modifier\Modifier; -use App\Modifier\IncludeDestinations; +use App\Modifier\With; use App\Provider\StopRepository; use Tightenco\Collect\Support\Collection; @@ -30,7 +30,11 @@ class GenericStopRepository extends DatabaseRepository implements StopRepository protected static function getHandlers() { return array_merge(parent::getHandlers(), [ - IncludeDestinations::class => IncludeDestinationsDatabaseHandler::class, + With::class => function (With $modifier) { + return $modifier->getRelationship() === 'destinations' + ? WithDestinationsDatabaseHandler::class + : GenericWithHandler::class; + }, ]); } } diff --git a/src/Service/HandlerProvider.php b/src/Service/HandlerProvider.php new file mode 100644 index 0000000..59d5edb --- /dev/null +++ b/src/Service/HandlerProvider.php @@ -0,0 +1,44 @@ +<?php + +namespace App\Service; + +use App\Exception\UnsupportedModifierException; +use App\Modifier\Modifier; +use Symfony\Component\DependencyInjection\ServiceLocator; + +class HandlerProvider +{ + private $configuration = []; + private $handlerLocator; + + public function __construct(ServiceLocator $handlerLocator) + { + $this->handlerLocator = $handlerLocator; + } + + public function loadConfiguration(array $providers) + { + $this->configuration = $providers; + } + + public function get(Modifier $modifier) + { + $class = get_class($modifier); + + if (!array_key_exists($class, $this->configuration)) { + throw UnsupportedModifierException::createFromModifier($modifier); + } + + $handler = $this->configuration[$class]; + + if (is_callable($handler)) { + $handler = $handler($modifier); + } + + if (is_string($handler)) { + return $this->handlerLocator->get($handler); + } + + return $handler; + } +} -- 2.45.2 From 9506881792d48a13a4ca341b1e527fb8554420b1 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 15 Mar 2020 12:50:38 +0100 Subject: [PATCH 23/77] #35 - WIP - Add scheduled stop repository --- .../Database/FieldFilterDatabaseHandler.php | 5 + .../Database/GenericWithDatabaseHandler.php | 99 +++++++++++++++++++ .../RelatedFilterDatabaseGenericHandler.php | 6 ++ src/Model/ScheduledStop.php | 20 +++- src/Model/Track.php | 20 +++- src/Model/Trip.php | 16 +++ src/Provider/Database/DatabaseRepository.php | 3 + .../Database/GenericScheduleRepository.php | 17 +++- .../Database/GenericStopRepository.php | 3 +- src/Provider/ScheduleRepository.php | 2 +- .../ZtmGdanskDepartureRepository.php | 65 ++++++++++-- src/Service/EntityConverter.php | 7 +- src/Service/ScheduledStopConverter.php | 6 +- 13 files changed, 247 insertions(+), 22 deletions(-) create mode 100644 src/Handler/Database/GenericWithDatabaseHandler.php diff --git a/src/Handler/Database/FieldFilterDatabaseHandler.php b/src/Handler/Database/FieldFilterDatabaseHandler.php index 0bfc83c..e7e8b1a 100644 --- a/src/Handler/Database/FieldFilterDatabaseHandler.php +++ b/src/Handler/Database/FieldFilterDatabaseHandler.php @@ -5,6 +5,7 @@ namespace App\Handler\Database; use App\Event\HandleDatabaseModifierEvent; use App\Event\HandleModifierEvent; use App\Handler\ModifierHandler; +use App\Model\ScheduledStop; use App\Model\Stop; use App\Modifier\FieldFilter; use function App\Functions\encapsulate; @@ -15,6 +16,10 @@ class FieldFilterDatabaseHandler implements ModifierHandler Stop::class => [ 'name' => 'name', ], + ScheduledStop::class => [ + 'departure' => 'departure', + 'arrival' => 'arrival', + ] ]; public function process(HandleModifierEvent $event) diff --git a/src/Handler/Database/GenericWithDatabaseHandler.php b/src/Handler/Database/GenericWithDatabaseHandler.php new file mode 100644 index 0000000..35dc3b9 --- /dev/null +++ b/src/Handler/Database/GenericWithDatabaseHandler.php @@ -0,0 +1,99 @@ +<?php + +namespace App\Handler\Database; + +use App\Event\HandleDatabaseModifierEvent; +use App\Event\HandleModifierEvent; +use App\Handler\ModifierHandler; +use App\Model\ScheduledStop; +use App\Model\Track; +use App\Model\TrackStop; +use App\Modifier\RelatedFilter; +use App\Service\EntityReferenceFactory; +use App\Service\IdUtils; +use Doctrine\ORM\EntityManagerInterface; +use function Kadet\Functional\Transforms\property; + +class GenericWithDatabaseHandler implements ModifierHandler +{ + protected $mapping = [ + Track::class => [ + 'line' => 'line', + 'stops' => 'stopsInTrack', + ], + TrackStop::class => [ + 'track' => 'track', + ], + ScheduledStop::class => [ + 'trip' => 'trip', + 'track' => 'trip.track', + 'destination' => 'trip.track.final', + ], + ]; + + private $em; + private $id; + private $references; + + public function __construct( + EntityManagerInterface $em, + IdUtils $idUtils, + EntityReferenceFactory $references + ) { + $this->em = $em; + $this->id = $idUtils; + $this->references = $references; + } + + public function process(HandleModifierEvent $event) + { + if (!$event instanceof HandleDatabaseModifierEvent) { + return; + } + + /** @var RelatedFilter $modifier */ + $modifier = $event->getModifier(); + $builder = $event->getBuilder(); + $alias = $event->getMeta()['alias']; + $type = $event->getMeta()['type']; + + if (!array_key_exists($modifier->getRelationship(), $this->mapping[$type])) { + throw new \InvalidArgumentException( + sprintf("Relationship %s is not supported for .", $type) + ); + } + + $relationship = $this->mapping[$type][$modifier->getRelationship()]; + + foreach ($this->getRelationships($relationship, $alias) as [$relationshipPath, $relationshipAlias]) { + $selected = collect($builder->getDQLPart('select'))->flatMap(property('parts')); + + if ($selected->contains($relationshipAlias)) { + continue; + } + + $builder + ->join($relationshipPath, $relationshipAlias) + ->addSelect($relationshipAlias); + } + } + + /** + * @inheritDoc + */ + public static function getSubscribedServices() + { + return [ + TrackByStopDatabaseHandler::class, + ]; + } + + private function getRelationships($relationship, $alias) + { + $relationships = explode('.', $relationship); + + foreach ($relationships as $current) { + yield [sprintf("%s.%s", $alias, $current), $alias = sprintf('%s_%s', $alias, $current)]; + } + } +} diff --git a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php index 315b99f..dbaa48d 100644 --- a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php +++ b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php @@ -6,9 +6,11 @@ use App\Event\HandleDatabaseModifierEvent; use App\Event\HandleModifierEvent; use App\Handler\ModifierHandler; use App\Model\Line; +use App\Model\ScheduledStop; use App\Model\Stop; use App\Model\Track; use App\Model\TrackStop; +use App\Model\Trip; use App\Modifier\RelatedFilter; use App\Service\IdUtils; use App\Service\EntityReferenceFactory; @@ -27,6 +29,10 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub Stop::class => 'stop', Track::class => 'track', ], + ScheduledStop::class => [ + Stop::class => 'stop', + Trip::class => 'trip', + ], ]; private $em; diff --git a/src/Model/ScheduledStop.php b/src/Model/ScheduledStop.php index 2ae78f2..5042a49 100644 --- a/src/Model/ScheduledStop.php +++ b/src/Model/ScheduledStop.php @@ -7,17 +7,23 @@ use Carbon\Carbon; class ScheduledStop extends TrackStop { /** - * Arrival time + * Arrival time. * @var Carbon */ private $arrival; /** - * Departure time + * Departure time. * @var Carbon */ private $departure; + /** + * Exact trip that this scheduled stop is part of. + * @var Trip|null + */ + private $trip; + public function getArrival(): Carbon { return $this->arrival; @@ -37,4 +43,14 @@ class ScheduledStop extends TrackStop { $this->departure = $departure; } + + public function getTrip(): ?Trip + { + return $this->trip; + } + + public function setTrip(?Trip $trip): void + { + $this->trip = $trip; + } } diff --git a/src/Model/Track.php b/src/Model/Track.php index bd62451..acb26f0 100644 --- a/src/Model/Track.php +++ b/src/Model/Track.php @@ -42,6 +42,14 @@ class Track implements Referable, Fillable */ private $stops; + /** + * Destination stop of this track + * @var Stop|null + * @Serializer\Type(Stop::class) + * @SWG\Property(ref=@Model(type=Stop::class)) + */ + private $destination; + /** * Track constructor. */ @@ -89,4 +97,14 @@ class Track implements Referable, Fillable { return $this->stops = collect($stops); } -} \ No newline at end of file + + public function getDestination(): ?Stop + { + return $this->destination; + } + + public function setDestination(?Stop $destination): void + { + $this->destination = $destination; + } +} diff --git a/src/Model/Trip.php b/src/Model/Trip.php index eaea219..f9da46f 100644 --- a/src/Model/Trip.php +++ b/src/Model/Trip.php @@ -40,6 +40,12 @@ class Trip implements Referable, Fillable */ private $schedule; + /** + * Destination stop of this trip + * @var Stop|null + */ + private $destination; + /** * Track constructor. */ @@ -87,4 +93,14 @@ class Trip implements Referable, Fillable { return $this->schedule = collect($schedule); } + + public function getDestination(): ?Stop + { + return $this->destination; + } + + public function setDestination(?Stop $destination): void + { + $this->destination = $destination; + } } diff --git a/src/Provider/Database/DatabaseRepository.php b/src/Provider/Database/DatabaseRepository.php index e4021ec..898a431 100644 --- a/src/Provider/Database/DatabaseRepository.php +++ b/src/Provider/Database/DatabaseRepository.php @@ -9,6 +9,7 @@ use App\Handler\Database\FieldFilterDatabaseHandler; use App\Handler\Database\IdFilterDatabaseHandler; use App\Handler\Database\LimitDatabaseHandler; use App\Handler\Database\RelatedFilterDatabaseGenericHandler; +use App\Handler\Database\GenericWithDatabaseHandler; use App\Handler\ModifierHandler; use App\Handler\PostProcessingHandler; use App\Model\Referable; @@ -17,6 +18,7 @@ use App\Modifier\IdFilter; use App\Modifier\Limit; use App\Modifier\Modifier; use App\Modifier\RelatedFilter; +use App\Modifier\With; use App\Provider\Repository; use App\Service\Converter; use App\Service\HandlerProvider; @@ -64,6 +66,7 @@ abstract class DatabaseRepository implements Repository Limit::class => LimitDatabaseHandler::class, FieldFilter::class => FieldFilterDatabaseHandler::class, RelatedFilter::class => RelatedFilterDatabaseGenericHandler::class, + With::class => GenericWithDatabaseHandler::class, ], static::getHandlers())); } diff --git a/src/Provider/Database/GenericScheduleRepository.php b/src/Provider/Database/GenericScheduleRepository.php index ed7adbe..10c4bdd 100644 --- a/src/Provider/Database/GenericScheduleRepository.php +++ b/src/Provider/Database/GenericScheduleRepository.php @@ -9,8 +9,10 @@ use App\Entity\TripEntity; use App\Entity\TripStopEntity; use App\Model\Departure; use App\Model\Line; +use App\Model\ScheduledStop; use App\Model\Stop; use App\Model\Vehicle; +use App\Modifier\Modifier; use App\Provider\ScheduleRepository; use Carbon\Carbon; use Tightenco\Collect\Support\Collection; @@ -71,8 +73,19 @@ class GenericScheduleRepository extends DatabaseRepository implements ScheduleRe }); } - protected static function getHandlers() + public function all(Modifier ...$modifiers): Collection { - return []; + $builder = $this->em + ->createQueryBuilder() + ->select('trip_stop') + ->from(TripStopEntity::class, 'trip_stop') + ->orderBy('trip_stop.departure', 'ASC') + ; + + return $this->allFromQueryBuilder($builder, $modifiers, [ + 'alias' => 'trip_stop', + 'type' => ScheduledStop::class, + 'entity' => TripStopEntity::class, + ]); } } diff --git a/src/Provider/Database/GenericStopRepository.php b/src/Provider/Database/GenericStopRepository.php index 82e41e6..7610402 100644 --- a/src/Provider/Database/GenericStopRepository.php +++ b/src/Provider/Database/GenericStopRepository.php @@ -3,6 +3,7 @@ namespace App\Provider\Database; use App\Entity\StopEntity; +use App\Handler\Database\GenericWithDatabaseHandler; use App\Handler\Database\WithDestinationsDatabaseHandler; use App\Model\Stop; use App\Modifier\Modifier; @@ -33,7 +34,7 @@ class GenericStopRepository extends DatabaseRepository implements StopRepository With::class => function (With $modifier) { return $modifier->getRelationship() === 'destinations' ? WithDestinationsDatabaseHandler::class - : GenericWithHandler::class; + : GenericWithDatabaseHandler::class; }, ]); } diff --git a/src/Provider/ScheduleRepository.php b/src/Provider/ScheduleRepository.php index 951a20f..e650d22 100644 --- a/src/Provider/ScheduleRepository.php +++ b/src/Provider/ScheduleRepository.php @@ -6,7 +6,7 @@ use App\Model\Stop; use Carbon\Carbon; use Tightenco\Collect\Support\Collection; -interface ScheduleRepository +interface ScheduleRepository extends FluentRepository { const DEFAULT_DEPARTURES_COUNT = 16; diff --git a/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php b/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php index e7f7dc6..48fefc2 100644 --- a/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php +++ b/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php @@ -4,9 +4,14 @@ namespace App\Provider\ZtmGdansk; use App\Model\Departure; use App\Model\Line; +use App\Model\ScheduledStop; use App\Model\Stop; use App\Model\Vehicle; +use App\Modifier\FieldFilter; use App\Modifier\IdFilter; +use App\Modifier\Limit; +use App\Modifier\RelatedFilter; +use App\Modifier\With; use App\Provider\Database\GenericScheduleRepository; use App\Provider\DepartureRepository; use App\Provider\LineRepository; @@ -90,13 +95,33 @@ class ZtmGdanskDepartureRepository implements DepartureRepository private function getScheduledDepartures(Stop $stop, Carbon $time) { - return $this->schedule->getDeparturesForStop($stop, $time); + return $this->schedule->all( + new RelatedFilter($stop), + new FieldFilter('departure', $time, '>='), + new With('track'), + new With('destination'), + Limit::count(16) + ); } private function pair(Collection $schedule, Collection $real) { - $key = function (Departure $departure) { - return sprintf("%s::%s", $departure->getLine()->getSymbol(), $departure->getScheduled()->format("H:i")); + $key = function ($departure) { + if ($departure instanceof Departure) { + return sprintf( + "%s::%s", + $departure->getLine()->getId(), + $departure->getScheduled()->format("H:i") + ); + } elseif ($departure instanceof ScheduledStop) { + return sprintf( + "%s::%s", + $departure->getTrack()->getLine()->getId(), + $departure->getDeparture()->format("H:i") + ); + } else { + throw new \Exception(); + } }; $schedule = $schedule->keyBy($key)->all(); @@ -110,21 +135,27 @@ class ZtmGdanskDepartureRepository implements DepartureRepository unset($schedule[$key]); } - return [ $real, $scheduled ]; - })->merge(collect($schedule)->map(function (Departure $scheduled) { - return [ null, $scheduled ]; + return [ + 'estimated' => $real, + 'scheduled' => $scheduled, + ]; + })->merge(collect($schedule)->map(function (ScheduledStop $scheduled) { + return [ + 'estimated' => null, + 'scheduled' => $scheduled, + ]; }))->map(function ($pair) { - return $this->merge(...$pair); + return $this->merge($pair['estimated'], $pair['scheduled']); })->sortBy(function (Departure $departure) { $time = $departure->getEstimated() ?? $departure->getScheduled(); return $time->getTimestamp(); }); } - private function merge(?Departure $real, ?Departure $scheduled) + private function merge(?Departure $real, ?ScheduledStop $scheduled) { if (!$real) { - return $scheduled; + return $this->convertScheduledStopToDeparture($scheduled); } if (!$scheduled) { @@ -132,10 +163,24 @@ class ZtmGdanskDepartureRepository implements DepartureRepository } $departure = clone $real; - $departure->setDisplay($scheduled->getDisplay()); + $departure->setDisplay($real->getDisplay()); $departure->setTrack($scheduled->getTrack()); $departure->setTrip($scheduled->getTrip()); return $departure; } + + private function convertScheduledStopToDeparture(ScheduledStop $stop): Departure + { + $converted = new Departure(); + + $converted->setDisplay($stop->getTrack()->getDestination()->getName()); + $converted->setLine($stop->getTrack()->getLine()); + $converted->setTrack($stop->getTrack()); + $converted->setTrip($stop->getTrip()); + $converted->setScheduled($stop->getDeparture()); + $converted->setStop($stop->getStop()); + + return $converted; + } } diff --git a/src/Service/EntityConverter.php b/src/Service/EntityConverter.php index 222a7c8..3ec6d4b 100644 --- a/src/Service/EntityConverter.php +++ b/src/Service/EntityConverter.php @@ -32,7 +32,7 @@ final class EntityConverter implements Converter, RecursiveConverter */ public function convert($entity, array $cache = []) { - if (array_key_exists($key = get_class($entity).':'.$this->getId($entity), $cache)) { + if (array_key_exists($key = get_class($entity) . ':' . $this->getId($entity), $cache)) { return $cache[$key]; } @@ -78,6 +78,7 @@ final class EntityConverter implements Converter, RecursiveConverter ->map(t\property('stop')) ->map($convert), 'line' => $convert($entity->getLine()), + 'destination' => $convert($entity->getFinal()->getStop()), ]); break; @@ -154,7 +155,7 @@ final class EntityConverter implements Converter, RecursiveConverter private function create(Entity $entity) { - $id = $this->id->of($entity); + $id = $this->id->of($entity); $class = $this->getModelClassForEntity($entity); return $class::createFromArray(['id' => $id]); @@ -162,7 +163,7 @@ final class EntityConverter implements Converter, RecursiveConverter private function reference(Entity $entity) { - $id = $this->id->strip($this->getId($entity)); + $id = $this->id->strip($this->getId($entity)); $class = $this->getModelClassForEntity($entity); return $this->reference->get($class, ['id' => $id]); diff --git a/src/Service/ScheduledStopConverter.php b/src/Service/ScheduledStopConverter.php index c00faae..d4cfc97 100644 --- a/src/Service/ScheduledStopConverter.php +++ b/src/Service/ScheduledStopConverter.php @@ -5,6 +5,7 @@ namespace App\Service; use App\Entity\TrackStopEntity; use App\Entity\TripStopEntity; use App\Model\ScheduledStop; +use App\Model\TrackStop; class ScheduledStopConverter implements Converter, RecursiveConverter { @@ -12,9 +13,8 @@ class ScheduledStopConverter implements Converter, RecursiveConverter public function convert($entity) { - if ($entity instanceof TrackStopEntity) { - return ScheduledStop::createFromArray([ + return TrackStop::createFromArray([ 'stop' => $this->parent->convert($entity->getStop()), 'track' => $this->parent->convert($entity->getTrack()), 'order' => $entity->getOrder(), @@ -27,6 +27,8 @@ class ScheduledStopConverter implements Converter, RecursiveConverter 'departure' => $entity->getDeparture(), 'stop' => $this->parent->convert($entity->getStop()), 'order' => $entity->getOrder(), + 'track' => $this->parent->convert($entity->getTrip()->getTrack()), + 'trip' => $this->parent->convert($entity->getTrip()), ]); } } -- 2.45.2 From f3a6c3e8eb8d640e77fd03e4950dcf46edc3ed38 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 15 Mar 2020 17:30:08 +0100 Subject: [PATCH 24/77] Add blackfire service for profiling --- docker-compose.yml | 10 +++++-- docker/php/Dockerfile | 25 +++++++++++----- src/Functions/helpers.php | 8 ++++- .../ZtmGdanskDepartureRepository.php | 30 +++++++++---------- 4 files changed, 47 insertions(+), 26 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 24c33b1..065e519 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,4 @@ -version: '2' +version: '3.4' services: nginx: @@ -11,9 +11,15 @@ services: php: build: docker/php - mem_limit: 2g env_file: - ./docker/php/.env volumes: - ./:/var/www:cached - ./docker/php/log.conf:/usr/local/etc/php-fpm.d/zz-log.conf + + blackfire: + image: blackfire/blackfire + ports: ["8707"] + environment: + - BLACKFIRE_SERVER_ID + - BLACKFIRE_SERVER_TOKEN diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile index 08a914e..27e1b3a 100644 --- a/docker/php/Dockerfile +++ b/docker/php/Dockerfile @@ -7,19 +7,30 @@ RUN apt-get update && \ RUN docker-php-ext-install zip +# XDebug RUN pecl install xdebug-2.9.0 && docker-php-ext-enable xdebug - RUN echo "xdebug.remote_enable = 1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \ echo "xdebug.remote_host = ${XDEBUG_REMOTE_HOST}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; -RUN echo "date.timezone = Europe/Warsaw" >> /usr/local/etc/php/conf.d/datetime.ini; -RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" -RUN php composer-setup.php -RUN php -r "unlink('composer-setup.php');" +# Blackfire +RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \ + && curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/amd64/$version \ + && mkdir -p /tmp/blackfire \ + && tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \ + && mv /tmp/blackfire/blackfire-*.so $(php -r "echo ini_get ('extension_dir');")/blackfire.so \ + && printf "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8707\n" > $PHP_INI_DIR/conf.d/blackfire.ini \ + && rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz -RUN mv composer.phar /usr/local/bin/composer -RUN chmod +x /usr/local/bin/composer +#Composer +RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ + && php composer-setup.php \ + && php -r "unlink('composer-setup.php');" \ + && mv composer.phar /usr/local/bin/composer \ + && chmod +x /usr/local/bin/composer + +# Timezone RUN ln -snf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime +RUN echo "date.timezone = Europe/Warsaw" >> /usr/local/etc/php/conf.d/datetime.ini; WORKDIR /var/www diff --git a/src/Functions/helpers.php b/src/Functions/helpers.php index 46f1c7a..57e138f 100644 --- a/src/Functions/helpers.php +++ b/src/Functions/helpers.php @@ -12,4 +12,10 @@ function encapsulate($value) default: return [ $value ]; } -} \ No newline at end of file +} + +function setup($value, $callback) +{ + $callback($value); + return $value; +} diff --git a/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php b/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php index 48fefc2..6053ef5 100644 --- a/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php +++ b/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php @@ -21,6 +21,7 @@ use Carbon\Carbon; use JMS\Serializer\Tests\Fixtures\Discriminator\Car; use Tightenco\Collect\Support\Collection; use Kadet\Functional\Transforms as t; +use function App\Functions\setup; class ZtmGdanskDepartureRepository implements DepartureRepository { @@ -162,25 +163,22 @@ class ZtmGdanskDepartureRepository implements DepartureRepository return $real; } - $departure = clone $real; - $departure->setDisplay($real->getDisplay()); - $departure->setTrack($scheduled->getTrack()); - $departure->setTrip($scheduled->getTrip()); - - return $departure; + return setup(clone $real, function (Departure $departure) use ($scheduled, $real) { + $departure->setDisplay($real->getDisplay()); + $departure->setTrack($scheduled->getTrack()); + $departure->setTrip($scheduled->getTrip()); + }); } private function convertScheduledStopToDeparture(ScheduledStop $stop): Departure { - $converted = new Departure(); - - $converted->setDisplay($stop->getTrack()->getDestination()->getName()); - $converted->setLine($stop->getTrack()->getLine()); - $converted->setTrack($stop->getTrack()); - $converted->setTrip($stop->getTrip()); - $converted->setScheduled($stop->getDeparture()); - $converted->setStop($stop->getStop()); - - return $converted; + return setup(new Departure(), function (Departure $converted) use ($stop) { + $converted->setDisplay($stop->getTrack()->getDestination()->getName()); + $converted->setLine($stop->getTrack()->getLine()); + $converted->setTrack($stop->getTrack()); + $converted->setTrip($stop->getTrip()); + $converted->setScheduled($stop->getDeparture()); + $converted->setStop($stop->getStop()); + }); } } -- 2.45.2 From db30d69cdb636f8a0eb4a0e77d0d6c2ebff7fe92 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 15 Mar 2020 22:35:12 +0100 Subject: [PATCH 25/77] #35 - Add Limit support for departure repository --- .../Api/v1/DeparturesController.php | 22 +++++--- .../RelatedFilterDatabaseGenericHandler.php | 2 +- src/Provider/DepartureRepository.php | 5 +- .../Dummy/DummyDepartureRepository.php | 27 +++++----- .../ZtmGdanskDepartureRepository.php | 51 ++++++++++++++++--- src/Service/ModifierUtils.php | 29 +++++++++++ 6 files changed, 106 insertions(+), 30 deletions(-) create mode 100644 src/Service/ModifierUtils.php diff --git a/src/Controller/Api/v1/DeparturesController.php b/src/Controller/Api/v1/DeparturesController.php index da07d63..afa0798 100644 --- a/src/Controller/Api/v1/DeparturesController.php +++ b/src/Controller/Api/v1/DeparturesController.php @@ -5,7 +5,10 @@ namespace App\Controller\Api\v1; use App\Controller\Controller; use App\Model\Departure; +use App\Modifier\FieldFilter; use App\Modifier\IdFilter; +use App\Modifier\Limit; +use App\Modifier\With; use App\Provider\DepartureRepository; use App\Provider\StopRepository; use App\Service\SerializerContextFactory; @@ -33,11 +36,11 @@ class DeparturesController extends Controller * @SWG\Schema(type="array", @SWG\Items(ref=@Model(type=Departure::class))) * ) */ - public function stop(DepartureRepository $departures, StopRepository $stops, $stop) + public function stop(DepartureRepository $departures, StopRepository $stops, $stop, Request $request) { $stop = $stops->first(new IdFilter($stop)); - return $this->json($departures->getForStop($stop)); + return $this->json($departures->current(collect($stop), ...$this->getModifiersFromRequest($request))); } /** @@ -65,16 +68,21 @@ class DeparturesController extends Controller */ public function stops(DepartureRepository $departures, StopRepository $stops, Request $request) { - $stops = $stops - ->all(new IdFilter($request->query->get('stop'))) - ->flatMap(ref([ $departures, 'getForStop' ])) - ->sortBy(property('departure')); + $stops = $stops->all(new IdFilter($request->query->get('stop'))); + $result = $departures->current($stops, ...$this->getModifiersFromRequest($request)); return $this->json( - $stops->values()->slice(0, (int)$request->query->get('limit', 8)), + $result->values()->slice(0, (int)$request->query->get('limit', 8)), 200, [], $this->serializerContextFactory->create(Departure::class, ['Default']) ); } + + private function getModifiersFromRequest(Request $request) + { + if ($request->query->has('limit')) { + yield Limit::count($request->query->getInt('limit')); + } + } } diff --git a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php index dbaa48d..f366e8e 100644 --- a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php +++ b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php @@ -72,7 +72,7 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub if (!array_key_exists($modifier->getRelationship(), $this->mapping[$type])) { throw new \InvalidArgumentException( - sprintf("Relationship %s is not supported for .", $type) + sprintf("Relationship %s is not supported for %s.", $modifier->getRelationship(), $type) ); } diff --git a/src/Provider/DepartureRepository.php b/src/Provider/DepartureRepository.php index 706274c..a6ea1f4 100644 --- a/src/Provider/DepartureRepository.php +++ b/src/Provider/DepartureRepository.php @@ -5,9 +5,10 @@ namespace App\Provider; use App\Model\Stop; +use App\Modifier\Modifier; use Tightenco\Collect\Support\Collection; interface DepartureRepository extends Repository { - public function getForStop(Stop $stop): Collection; -} \ No newline at end of file + public function current(iterable $stops, Modifier ...$modifiers); +} diff --git a/src/Provider/Dummy/DummyDepartureRepository.php b/src/Provider/Dummy/DummyDepartureRepository.php index 5210943..d265ce6 100644 --- a/src/Provider/Dummy/DummyDepartureRepository.php +++ b/src/Provider/Dummy/DummyDepartureRepository.php @@ -6,6 +6,7 @@ use App\Model\Departure; use App\Model\Line; use App\Model\Stop; use App\Model\Vehicle; +use App\Modifier\Modifier; use App\Provider\DepartureRepository; use App\Service\Proxy\ReferenceFactory; use Carbon\Carbon; @@ -25,21 +26,21 @@ class DummyDepartureRepository implements DepartureRepository $this->reference = $reference; } - public function getForStop(Stop $stop): Collection + public function current(iterable $stops, Modifier ...$modifiers) { return collect([ - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], ])->map(function ($departure) use ($stop) { - list($symbol, $type, $display, $vehicle) = $departure; + [$symbol, $type, $display, $vehicle] = $departure; $scheduled = new Carbon(); $estimated = (clone $scheduled)->addSeconds(40); @@ -53,4 +54,4 @@ class DummyDepartureRepository implements DepartureRepository ]); }); } -} \ No newline at end of file +} diff --git a/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php b/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php index 6053ef5..eb7f401 100644 --- a/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php +++ b/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php @@ -10,18 +10,22 @@ use App\Model\Vehicle; use App\Modifier\FieldFilter; use App\Modifier\IdFilter; use App\Modifier\Limit; +use App\Modifier\Modifier; use App\Modifier\RelatedFilter; use App\Modifier\With; use App\Provider\Database\GenericScheduleRepository; use App\Provider\DepartureRepository; use App\Provider\LineRepository; use App\Provider\ScheduleRepository; +use App\Service\IterableUtils; +use App\Service\ModifierUtils; use App\Service\Proxy\ReferenceFactory; use Carbon\Carbon; use JMS\Serializer\Tests\Fixtures\Discriminator\Car; use Tightenco\Collect\Support\Collection; use Kadet\Functional\Transforms as t; use function App\Functions\setup; +use function Kadet\Functional\ref; class ZtmGdanskDepartureRepository implements DepartureRepository { @@ -46,16 +50,22 @@ class ZtmGdanskDepartureRepository implements DepartureRepository $this->schedule = $schedule; } - public function getForStop(Stop $stop): Collection + public function current(iterable $stops, Modifier ...$modifiers) { - $real = $this->getRealDepartures($stop); + $real = IterableUtils::toCollection($stops) + ->flatMap(ref([$this, 'getRealDepartures'])) + ->sortBy(t\property('estimated')) + ; + $now = Carbon::now()->second(0); $first = $real->map(t\getter('scheduled'))->min() ?? $now; - $scheduled = $this->getScheduledDepartures($stop, $first); + $scheduled = $this->getScheduledDepartures($stops, $first, ...$this->extractModifiers($modifiers)); - return $this->pair($scheduled, $real)->filter(function (Departure $departure) use ($now) { + $result = $this->pair($scheduled, $real)->filter(function (Departure $departure) use ($now) { return $departure->getDeparture() > $now; }); + + return $this->processResultWithModifiers($result, $modifiers); } private function getRealDepartures(Stop $stop) @@ -94,14 +104,14 @@ class ZtmGdanskDepartureRepository implements DepartureRepository })->values(); } - private function getScheduledDepartures(Stop $stop, Carbon $time) + private function getScheduledDepartures($stop, Carbon $time, Modifier ...$modifiers) { return $this->schedule->all( - new RelatedFilter($stop), + new RelatedFilter($stop, Stop::class), new FieldFilter('departure', $time, '>='), new With('track'), new With('destination'), - Limit::count(16) + ...$modifiers ); } @@ -181,4 +191,31 @@ class ZtmGdanskDepartureRepository implements DepartureRepository $converted->setStop($stop->getStop()); }); } + + private function extractModifiers(iterable $modifiers) + { + $result = []; + + /** @var Limit $limit */ + if ($limit = ModifierUtils::getOfType($modifiers, Limit::class)) { + $result[] = new Limit($limit->getOffset(), $limit->getCount() * 2); + } else { + $result[] = Limit::count(16); + } + + return $result; + } + + private function processResultWithModifiers(Collection $result, iterable $modifiers) + { + foreach ($modifiers as $modifier) { + switch (true) { + case $modifier instanceof Limit: + $result = $result->slice($modifier->getOffset(), $modifier->getCount()); + break; + } + } + + return $result; + } } diff --git a/src/Service/ModifierUtils.php b/src/Service/ModifierUtils.php new file mode 100644 index 0000000..69f0fb4 --- /dev/null +++ b/src/Service/ModifierUtils.php @@ -0,0 +1,29 @@ +<?php + +namespace App\Service; + +use Kadet\Functional\Predicate; +use function Kadet\Functional\Predicates\instance; + +final class ModifierUtils +{ + public static function get(iterable $modifiers, Predicate $predicate) + { + return collect($modifiers)->first($predicate); + } + + public static function getOfType(iterable $modifiers, $class) + { + return self::get($modifiers, instance($class)); + } + + public static function hasAny(iterable $modifiers, Predicate $predicate) + { + return collect($modifiers)->contains($predicate); + } + + public static function hasAnyOfType(iterable $modifiers, $class) + { + return collect($modifiers)->contains(instance($class)); + } +} -- 2.45.2 From 720327424aa959ac8ba5708b5ed4d84fcd40443b Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Mon, 16 Mar 2020 20:32:15 +0100 Subject: [PATCH 26/77] #35 - Add paginator to properly handle limits --- src/Controller/Api/v1/TripController.php | 3 ++- .../Database/GenericWithDatabaseHandler.php | 4 ++++ src/Provider/Database/DatabaseRepository.php | 6 ++++- .../Database/GenericTripRepository.php | 4 +--- .../ZtmGdanskDepartureRepository.php | 9 +++++-- src/Service/AggregateConverter.php | 10 ++++---- src/Service/CacheableConverter.php | 8 +++++++ src/Service/EntityConverter.php | 24 ++++++++++++------- 8 files changed, 49 insertions(+), 19 deletions(-) create mode 100644 src/Service/CacheableConverter.php diff --git a/src/Controller/Api/v1/TripController.php b/src/Controller/Api/v1/TripController.php index 031f39a..b91c8cb 100644 --- a/src/Controller/Api/v1/TripController.php +++ b/src/Controller/Api/v1/TripController.php @@ -5,6 +5,7 @@ namespace App\Controller\Api\v1; use App\Controller\Controller; use App\Model\Trip; use App\Modifier\IdFilter; +use App\Modifier\With; use App\Provider\TripRepository; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; @@ -19,7 +20,7 @@ class TripController extends Controller */ public function one($id, TripRepository $repository) { - $trip = $repository->all(new IdFilter($id)); + $trip = $repository->first(new IdFilter($id), new With('schedule')); return $this->json($trip, Response::HTTP_OK, [], $this->serializerContextFactory->create(Trip::class)); } diff --git a/src/Handler/Database/GenericWithDatabaseHandler.php b/src/Handler/Database/GenericWithDatabaseHandler.php index 35dc3b9..26445c7 100644 --- a/src/Handler/Database/GenericWithDatabaseHandler.php +++ b/src/Handler/Database/GenericWithDatabaseHandler.php @@ -8,6 +8,7 @@ use App\Handler\ModifierHandler; use App\Model\ScheduledStop; use App\Model\Track; use App\Model\TrackStop; +use App\Model\Trip; use App\Modifier\RelatedFilter; use App\Service\EntityReferenceFactory; use App\Service\IdUtils; @@ -21,6 +22,9 @@ class GenericWithDatabaseHandler implements ModifierHandler 'line' => 'line', 'stops' => 'stopsInTrack', ], + Trip::class => [ + 'schedule' => 'stops.stop', + ], TrackStop::class => [ 'track' => 'track', ], diff --git a/src/Provider/Database/DatabaseRepository.php b/src/Provider/Database/DatabaseRepository.php index 898a431..7e7f86b 100644 --- a/src/Provider/Database/DatabaseRepository.php +++ b/src/Provider/Database/DatabaseRepository.php @@ -25,6 +25,7 @@ use App\Service\HandlerProvider; use App\Service\IdUtils; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\QueryBuilder; +use Doctrine\ORM\Tools\Pagination\Paginator; abstract class DatabaseRepository implements Repository { @@ -128,7 +129,10 @@ abstract class DatabaseRepository implements Repository $builder->setMaxResults(self::DEFAULT_LIMIT); $reducers = $this->processQueryBuilder($builder, $modifiers, $meta); - $result = collect($builder->getQuery()->execute())->map(\Closure::fromCallable([$this, 'convert'])); + $query = $builder->getQuery(); + + $paginator = new Paginator($query); + $result = collect($paginator)->map(\Closure::fromCallable([$this, 'convert'])); return $reducers->reduce(function ($result, $reducer) { return $reducer($result); diff --git a/src/Provider/Database/GenericTripRepository.php b/src/Provider/Database/GenericTripRepository.php index 6ffd652..2a10b33 100644 --- a/src/Provider/Database/GenericTripRepository.php +++ b/src/Provider/Database/GenericTripRepository.php @@ -15,9 +15,7 @@ class GenericTripRepository extends DatabaseRepository implements TripRepository $builder = $this->em ->createQueryBuilder() ->from(TripEntity::class, 'trip') - ->join('trip.stops', 'ts') - ->join('ts.stop', 's') - ->select('t', 'ts'); + ->select('trip'); return $this->allFromQueryBuilder($builder, $modifiers, [ 'alias' => 'trip', diff --git a/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php b/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php index eb7f401..8e8dbc4 100644 --- a/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php +++ b/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php @@ -174,7 +174,7 @@ class ZtmGdanskDepartureRepository implements DepartureRepository } return setup(clone $real, function (Departure $departure) use ($scheduled, $real) { - $departure->setDisplay($real->getDisplay()); + $departure->setDisplay($this->extractDisplayFromScheduledStop($scheduled)); $departure->setTrack($scheduled->getTrack()); $departure->setTrip($scheduled->getTrip()); }); @@ -183,7 +183,7 @@ class ZtmGdanskDepartureRepository implements DepartureRepository private function convertScheduledStopToDeparture(ScheduledStop $stop): Departure { return setup(new Departure(), function (Departure $converted) use ($stop) { - $converted->setDisplay($stop->getTrack()->getDestination()->getName()); + $converted->setDisplay($this->extractDisplayFromScheduledStop($stop)); $converted->setLine($stop->getTrack()->getLine()); $converted->setTrack($stop->getTrack()); $converted->setTrip($stop->getTrip()); @@ -192,6 +192,11 @@ class ZtmGdanskDepartureRepository implements DepartureRepository }); } + private function extractDisplayFromScheduledStop(ScheduledStop $stop) + { + return $stop->getTrack()->getDestination()->getName(); + } + private function extractModifiers(iterable $modifiers) { $result = []; diff --git a/src/Service/AggregateConverter.php b/src/Service/AggregateConverter.php index 45cc308..ef180c7 100644 --- a/src/Service/AggregateConverter.php +++ b/src/Service/AggregateConverter.php @@ -2,10 +2,7 @@ namespace App\Service; -use Hoa\Iterator\Recursive\Recursive; -use Symfony\Component\DependencyInjection\ServiceLocator; -use function Kadet\Functional\Predicates\equals; -use function Kadet\Functional\Predicates\method; +use Tightenco\Collect\Support\Collection; class AggregateConverter implements Converter { @@ -40,4 +37,9 @@ class AggregateConverter implements Converter return $converter->supports($entity); }); } + + public function getConverters(): Collection + { + return clone $this->converters; + } } diff --git a/src/Service/CacheableConverter.php b/src/Service/CacheableConverter.php new file mode 100644 index 0000000..cf590df --- /dev/null +++ b/src/Service/CacheableConverter.php @@ -0,0 +1,8 @@ +<?php + +namespace App\Service; + +interface CacheableConverter extends Converter +{ + public function flushCache(); +} diff --git a/src/Service/EntityConverter.php b/src/Service/EntityConverter.php index 3ec6d4b..1104077 100644 --- a/src/Service/EntityConverter.php +++ b/src/Service/EntityConverter.php @@ -11,17 +11,19 @@ use Kadet\Functional as f; use Kadet\Functional\Transforms as t; use const Kadet\Functional\_; -final class EntityConverter implements Converter, RecursiveConverter +final class EntityConverter implements Converter, RecursiveConverter, CacheableConverter { use RecursiveConverterTrait; private $id; private $reference; + private $cache; public function __construct(IdUtils $id, ReferenceFactory $reference) { $this->id = $id; $this->reference = $reference; + $this->cache = []; } /** @@ -30,21 +32,22 @@ final class EntityConverter implements Converter, RecursiveConverter * * @return Line|Track|Stop|Operator|Trip|ScheduledStop */ - public function convert($entity, array $cache = []) + public function convert($entity) { - if (array_key_exists($key = get_class($entity) . ':' . $this->getId($entity), $cache)) { - return $cache[$key]; + if (array_key_exists($key = get_class($entity) . ':' . $this->getId($entity), $this->cache)) { + return $this->cache[$key]; } if ($entity instanceof Proxy && !$entity->__isInitialized()) { return $this->reference($entity); } - $result = $this->create($entity); - $cache = $cache + [$key => $result]; - $convert = function ($entity) use ($cache) { + $result = $this->create($entity); + $this->cache[$key] = $result; + + $convert = function ($entity) { return $this->supports($entity) - ? $this->convert($entity, $cache) + ? $this->convert($entity) : $this->parent->convert($entity); }; @@ -173,4 +176,9 @@ final class EntityConverter implements Converter, RecursiveConverter { return $entity instanceof Entity; } + + public function flushCache() + { + $this->cache = []; + } } -- 2.45.2 From c781ca3dbcd776976a2e87efe4c4fcddddaabf03 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Wed, 18 Mar 2020 16:33:06 +0100 Subject: [PATCH 27/77] #47 - UI - Add UiNumericInput component --- resources/components/ui/numeric.html | 11 +++++ resources/styles/_form.scss | 8 ++-- resources/styles/main.scss | 2 + resources/ts/components/app.ts | 2 + resources/ts/components/ui/icon.ts | 4 +- resources/ts/components/ui/index.ts | 1 + resources/ts/components/ui/numeric-input.ts | 53 +++++++++++++++++++++ templates/app.html.twig | 41 +++++++++------- 8 files changed, 102 insertions(+), 20 deletions(-) create mode 100644 resources/components/ui/numeric.html create mode 100644 resources/ts/components/ui/numeric-input.ts diff --git a/resources/components/ui/numeric.html b/resources/components/ui/numeric.html new file mode 100644 index 0000000..c2cb1ce --- /dev/null +++ b/resources/components/ui/numeric.html @@ -0,0 +1,11 @@ +<div class="input-group input-group-sm"> + <input type="text" class="form-control form-control-sm" :id="id" inputmode="numeric" v-bind="$attrs" :value="value" @blur="update"/> + <div class="input-group-append"> + <button class="btn btn-addon" type="button" @click="increment" :disabled="!canIncrement"> + <ui-icon icon="increment"/> + </button> + <button class="btn btn-addon" type="button" @click="decrement" :disabled="!canDecrement"> + <ui-icon icon="decrement"/> + </button> + </div> +</div> diff --git a/resources/styles/_form.scss b/resources/styles/_form.scss index 1101da9..7e14acc 100644 --- a/resources/styles/_form.scss +++ b/resources/styles/_form.scss @@ -3,17 +3,18 @@ label { margin-bottom: 0; margin-top: -0.2rem; display: block; + font-size: .8rem; } .label-sm { - font-size: .8rem; + font-size: .6rem; } .form-group:last-child { margin-bottom: 0; } -.form-control, .input-group-text { +.form-control, .input-group-text, .btn-addon { background: rgba($dark, .06); border: none; border-bottom: 2px solid $dark; @@ -32,7 +33,8 @@ label { } } -.input-group-append { +.input-group-append, +.input-group-append .btn + .btn { margin-left: 0; } diff --git a/resources/styles/main.scss b/resources/styles/main.scss index 58b6f1b..6be0b6c 100644 --- a/resources/styles/main.scss +++ b/resources/styles/main.scss @@ -2,9 +2,11 @@ $border-radius: 0; $border-radius-lg: $border-radius; $border-radius-sm: $border-radius; + @import "~bootstrap/scss/functions"; @import "~bootstrap/scss/variables"; +$form-group-margin-bottom: $form-group-margin-bottom / 2; $primary: #005ea8; $custom-control-indicator-checked-bg: $dark; diff --git a/resources/ts/components/app.ts b/resources/ts/components/app.ts index 2f74e9f..c8cfd93 100644 --- a/resources/ts/components/app.ts +++ b/resources/ts/components/app.ts @@ -30,6 +30,8 @@ export class Application extends Vue { } }; + private count = 8; + private intervals = { messages: null, departures: null }; get messages() { diff --git a/resources/ts/components/ui/icon.ts b/resources/ts/components/ui/icon.ts index 419db53..e2928d5 100644 --- a/resources/ts/components/ui/icon.ts +++ b/resources/ts/components/ui/icon.ts @@ -23,7 +23,7 @@ import { faTimes, faTrashAlt } from "@fortawesome/pro-light-svg-icons"; -import { faClock as faClockBold, faCodeCommit, faSpinnerThird } from "@fortawesome/pro-regular-svg-icons"; +import { faClock as faClockBold, faCodeCommit, faMinus, faPlus, faSpinnerThird } from "@fortawesome/pro-regular-svg-icons"; import { faExclamationTriangle as faSolidExclamationTriangle, faWalking } from "@fortawesome/pro-solid-svg-icons"; import { fac } from "../../icons"; import { FontAwesomeIcon, FontAwesomeLayers, FontAwesomeLayersText } from "@fortawesome/vue-fontawesome"; @@ -81,6 +81,8 @@ const definitions: Dictionary<Icon> = { 'map': simple(faMapMarkerAlt), 'stop': simple(faSign), 'spinner': simple(faSpinnerThird, { spin: true }), + 'increment': simple(faPlus, { "fixed-width": true }), + 'decrement': simple(faMinus, { "fixed-width": true }), 'departure-warning': stack([ {icon: faClockBold}, {icon: faSolidExclamationTriangle, transform: "shrink-5 down-4 right-6"} diff --git a/resources/ts/components/ui/index.ts b/resources/ts/components/ui/index.ts index 9647ef5..8814273 100644 --- a/resources/ts/components/ui/index.ts +++ b/resources/ts/components/ui/index.ts @@ -1,2 +1,3 @@ export * from './switch'; export * from './icon'; +export * from './numeric-input' diff --git a/resources/ts/components/ui/numeric-input.ts b/resources/ts/components/ui/numeric-input.ts new file mode 100644 index 0000000..f8ef7e9 --- /dev/null +++ b/resources/ts/components/ui/numeric-input.ts @@ -0,0 +1,53 @@ +import Vue from 'vue' +import { Component, Prop } from 'vue-property-decorator' +import * as uuid from "uuid"; + +@Component({ + template: require('../../../components/ui/numeric.html'), + inheritAttrs: false +}) +export class UiNumericInput extends Vue { + @Prop({ + type: String, + default: () => `uuid-${uuid.v4()}` + }) + id: string; + + @Prop(Number) + value: number; + + @Prop({ type: Number, default: 1 }) + step: number; + + @Prop({ type: Number, default: -Infinity }) + min: number; + + @Prop({ type: Number, default: Infinity }) + max: number; + + update(ev) { + this.$emit('input', this.clamp(Number.parseInt(ev.target.value))); + } + + increment() { + this.$emit('input', this.clamp(this.value + this.step)); + } + + decrement() { + this.$emit('input', this.clamp(this.value - this.step)); + } + + clamp(value: number) { + return Math.max(Math.min(value, this.max), this.min); + } + + get canIncrement(): boolean { + return this.max - this.value > Number.EPSILON * 2; + } + + get canDecrement(): boolean { + return this.value - this.min > Number.EPSILON * 2; + } +} + +Vue.component('UiNumericInput', UiNumericInput); diff --git a/templates/app.html.twig b/templates/app.html.twig index 0817d50..eb64bd6 100644 --- a/templates/app.html.twig +++ b/templates/app.html.twig @@ -73,25 +73,34 @@ </button> <portal to="popups"> <popper reference="settings-departures" v-if="visibility.departures" arrow placement="left-start" @leave="visibility.departures = false"> - <h3 class="popper__heading flex"> - <label class="text" for="departures-auto-refresh"> - <ui-icon icon="refresh" fixed-width></ui-icon> - autoodświeżanie - </label> - <ui-switch id="departures-auto-refresh" v-model="autorefresh.departures.active" class="flex-space-left"></ui-switch> - </h3> - <div class="flex" v-if="autorefresh.departures.active"> - <label for="departures-auto-refresh-interval" class="text"> - <span class="sr-only">częstotliwość odświeżania</span> - co - </label> - <div class="input-group input-group-sm"> - <input type="text" class="form-control form-control-sm form-control-simple" id="departures-auto-refresh-interval" v-model="autorefresh.departures.interval"/> - <div class="input-group-append"> - <span class="input-group-text" aria-label="sekund">s</span> + <div class="form-group"> + <h3 class="popper__heading flex"> + <label class="text" for="departures-auto-refresh-interval"> + <ui-icon icon="refresh" fixed-width></ui-icon> + autoodświeżanie + </label> + <ui-switch id="departures-auto-refresh" v-model="autorefresh.departures.active" class="flex-space-left"></ui-switch> + </h3> + <div class="flex " v-if="autorefresh.departures.active"> + <label for="departures-auto-refresh-interval" class="text"> + <span class="sr-only">częstotliwość odświeżania</span> + co + </label> + <div class="input-group input-group-sm"> + <input type="text" class="form-control form-control-sm form-control-simple" id="departures-auto-refresh-interval" v-model="autorefresh.departures.interval"/> + <div class="input-group-append"> + <span class="input-group-text" aria-label="sekund">s</span> + </div> </div> </div> </div> + <div class="form-group"> + <label class="text" for="departures-count"> + <ui-icon icon="line-bus" fixed-width></ui-icon> + Liczba wpisów + </label> + <ui-numeric-input id="departures-count" v-model="count" :min="1" :max="16"></ui-numeric-input> + </div> </popper> </portal> </header> -- 2.45.2 From 7a54569820773475132eaa99c773cbf472e80ecf Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Wed, 18 Mar 2020 22:00:17 +0100 Subject: [PATCH 28/77] #47 - Extract departures settings to its own component and store module --- docker/nginx/czydojade | 2 +- resources/components/departures.html | 4 -- resources/components/settings/departures.html | 31 ++++++++++++ resources/styles/_form.scss | 5 ++ resources/ts/components/app.ts | 47 +++++++++++-------- resources/ts/components/departures.ts | 12 ++--- resources/ts/components/index.ts | 2 + .../ts/components/settings/departures.ts | 21 +++++++++ resources/ts/components/settings/index.ts | 1 + resources/ts/store/common.ts | 3 +- resources/ts/store/departures.ts | 11 +++-- resources/ts/store/index.ts | 14 ++++-- resources/ts/store/settings/departures.ts | 24 ++++++++++ .../Api/v1/DeparturesController.php | 2 +- templates/app.html.twig | 35 +++----------- 15 files changed, 140 insertions(+), 74 deletions(-) create mode 100644 resources/components/settings/departures.html create mode 100644 resources/ts/components/settings/departures.ts create mode 100644 resources/ts/components/settings/index.ts create mode 100644 resources/ts/store/settings/departures.ts diff --git a/docker/nginx/czydojade b/docker/nginx/czydojade index e9fbde6..0a33eed 100644 --- a/docker/nginx/czydojade +++ b/docker/nginx/czydojade @@ -26,4 +26,4 @@ server { internal; } } -} \ No newline at end of file +} diff --git a/resources/components/departures.html b/resources/components/departures.html index e2f02b8..20a1c04 100644 --- a/resources/components/departures.html +++ b/resources/components/departures.html @@ -2,8 +2,4 @@ <ul class="departures__list list-underlined"> <departure :departure="departure" :key="departure.key" v-for="departure in departures"/> </ul> - <div class="alert alert-info" v-if="stops.length === 0"> - <ui-icon icon="info"/> - Wybierz przystanki korzystając z wyszukiwarki poniżej, aby zobaczyć listę odjazdów. - </div> </div> diff --git a/resources/components/settings/departures.html b/resources/components/settings/departures.html new file mode 100644 index 0000000..402fca6 --- /dev/null +++ b/resources/components/settings/departures.html @@ -0,0 +1,31 @@ +<fragment> + <div class="form-group"> + <h3 class="popper__heading flex"> + <label class="text" for="departures-auto-refresh-interval"> + <ui-icon icon="refresh" fixed-width/> + autoodświeżanie + </label> + <ui-switch id="departures-auto-refresh" :value="autorefresh" @input="update({ autorefresh: $event })" class="flex-space-left"/> + </h3> + <div class="flex " v-if="autorefresh"> + <label for="departures-auto-refresh-interval" class="text"> + <span class="sr-only">częstotliwość odświeżania</span> + co + </label> + <div class="input-group input-group-sm"> + <input type="text" class="form-control form-control-sm form-control-simple" id="departures-auto-refresh-interval" + :value="autorefreshInterval" @input="update({ autorefreshInterval: Number.parseInt($event.target.value) })" /> + <div class="input-group-append"> + <span class="input-group-text" aria-label="sekund">s</span> + </div> + </div> + </div> + </div> + <div class="form-group"> + <label class="text" for="departures-count"> + <ui-icon icon="line-bus" fixed-width/> + liczba wpisów + </label> + <ui-numeric-input id="departures-count" :value="displayedEntriesCount" @input="update({ displayedEntriesCount: $event })" :min="1" :max="20"/> + </div> +</fragment> diff --git a/resources/styles/_form.scss b/resources/styles/_form.scss index 7e14acc..14da9d3 100644 --- a/resources/styles/_form.scss +++ b/resources/styles/_form.scss @@ -38,6 +38,11 @@ label { margin-left: 0; } +.btn-addon:disabled { + opacity: 1; + color: rgba($dark, .5) +} + .input-group-prepend { margin-right: 0; } diff --git a/resources/ts/components/app.ts b/resources/ts/components/app.ts index c8cfd93..0d06caa 100644 --- a/resources/ts/components/app.ts +++ b/resources/ts/components/app.ts @@ -2,9 +2,8 @@ import Vue from 'vue' import store from '../store' import { Component, Watch } from "vue-property-decorator"; import { Mutation, Action } from 'vuex-class' -import { ObtainPayload } from "../store/departures"; import { Stop } from "../model"; -import { PopperComponent } from "./utils"; +import { DeparturesSettingsState } from "../store/settings/departures"; @Component({ store }) export class Application extends Vue { @@ -23,15 +22,9 @@ export class Application extends Vue { messages: { active: true, interval: 60 - }, - departures: { - active: true, - interval: 10 } }; - private count = 8; - private intervals = { messages: null, departures: null }; get messages() { @@ -60,16 +53,39 @@ export class Application extends Vue { this.$el.classList.remove('not-ready'); } + created() { + this.initDeparturesRefreshInterval(); + } + + private initDeparturesRefreshInterval() { + const departuresAutorefreshCallback = () => { + const {autorefresh, autorefreshInterval} = this.$store.state['departures-settings'] as DeparturesSettingsState; + + if (this.intervals.departures) { + clearInterval(this.intervals.departures); + } + + if (autorefresh) { + this.intervals.departures = setInterval(() => this.updateDepartures(), Math.max(5, autorefreshInterval) * 1000) + } + }; + + this.$store.watch(({"departures-settings": state}) => state.autorefresh, departuresAutorefreshCallback); + this.$store.watch(({"departures-settings": state}) => state.autorefreshInterval, departuresAutorefreshCallback); + + departuresAutorefreshCallback(); + } + @Action('messages/update') updateMessages: () => void; - @Action('departures/update') updateDepartures: (payload: ObtainPayload) => void; + @Action('departures/update') updateDepartures: () => void; @Mutation add: (stops: Stop[]) => void; @Mutation remove: (stop: Stop) => void; @Mutation clear: () => void; @Watch('stops') - onStopUpdate(this: any, stops) { - this.updateDepartures({ stops }); + onStopUpdate() { + this.updateDepartures(); } @Watch('autorefresh', { immediate: true, deep: true }) @@ -79,17 +95,8 @@ export class Application extends Vue { this.intervals.messages = null; } - if (this.intervals.departures) { - clearInterval(this.intervals.departures); - this.intervals.messages = null; - } - if (settings.messages.active) { this.intervals.messages = setInterval(() => this.updateMessages(), Math.max(5, settings.messages.interval) * 1000); } - - if (settings.departures.active) { - this.intervals.departures = setInterval(() => this.updateDepartures({ stops: this.stops }), Math.max(5, settings.departures.interval) * 1000); - } } } diff --git a/resources/ts/components/departures.ts b/resources/ts/components/departures.ts index 7668877..f85e846 100644 --- a/resources/ts/components/departures.ts +++ b/resources/ts/components/departures.ts @@ -1,21 +1,15 @@ import Vue from 'vue' -import { Departure, Stop } from "../model"; +import { Departure } from "../model"; import { Component, Prop, Watch } from "vue-property-decorator"; -import { namespace } from 'vuex-class'; -import store from '../store' +import store, { Departures } from '../store' import { Trip } from "../model/trip"; import urls from "../urls"; import { Jsonified } from "../utils"; import * as moment from "moment"; -const { State } = namespace('departures'); - @Component({ template: require("../../components/departures.html"), store }) export class DeparturesComponent extends Vue { - @State departures: Departure[]; - - @Prop(Array) - stops: Stop[]; + @Departures.State departures: Departure[]; } @Component({ template: require("../../components/departures/departure.html") }) diff --git a/resources/ts/components/index.ts b/resources/ts/components/index.ts index cda0742..337f4e2 100644 --- a/resources/ts/components/index.ts +++ b/resources/ts/components/index.ts @@ -10,3 +10,5 @@ export * from './app' export * from './favourites' export * from './trip' export * from './ui' +export * from './settings' +export { Departures } from "../store"; diff --git a/resources/ts/components/settings/departures.ts b/resources/ts/components/settings/departures.ts new file mode 100644 index 0000000..c7b2499 --- /dev/null +++ b/resources/ts/components/settings/departures.ts @@ -0,0 +1,21 @@ +import { Component, Prop } from "vue-property-decorator"; +import store, { DeparturesSettings } from "../../store"; +import Vue from "vue"; +import { DeparturesSettingsState } from "../../store/settings/departures"; + +@Component({ template: require("../../../components/settings/departures.html"), store }) +export class SettingsDepartures extends Vue { + @DeparturesSettings.State + public autorefresh: boolean; + + @DeparturesSettings.State + public autorefreshInterval: number; + + @DeparturesSettings.State + public displayedEntriesCount: number; + + @DeparturesSettings.Mutation + public update: (state: Partial<DeparturesSettingsState>) => void; +} + +Vue.component('SettingsDepartures', SettingsDepartures); diff --git a/resources/ts/components/settings/index.ts b/resources/ts/components/settings/index.ts new file mode 100644 index 0000000..10d35a6 --- /dev/null +++ b/resources/ts/components/settings/index.ts @@ -0,0 +1 @@ +export * from "./departures" diff --git a/resources/ts/store/common.ts b/resources/ts/store/common.ts index 49e12c0..9daa91b 100644 --- a/resources/ts/store/common.ts +++ b/resources/ts/store/common.ts @@ -1,7 +1,6 @@ import { FetchingState } from "../utils"; import { Moment } from "moment"; import { Module, MutationTree } from "vuex"; -import { RootState } from "./root"; import * as moment from "moment"; export interface CommonState { @@ -24,4 +23,4 @@ export const mutations: MutationTree<CommonState> = { } }; -export default { state, mutations }; \ No newline at end of file +export default { state, mutations }; diff --git a/resources/ts/store/departures.ts b/resources/ts/store/departures.ts index 220ac06..201cbca 100644 --- a/resources/ts/store/departures.ts +++ b/resources/ts/store/departures.ts @@ -10,10 +10,6 @@ export interface DeparturesState extends CommonState { departures: Departure[], } -export interface ObtainPayload { - stops: Stop[] -} - export const departures: Module<DeparturesState, RootState> = { namespaced: true, state: { @@ -29,10 +25,15 @@ export const departures: Module<DeparturesState, RootState> = { ...common.mutations }, actions: { - async update({ commit }, { stops }: ObtainPayload) { + async update({ commit }) { + const count = this.state['departures-settings'].displayedEntriesCount; + const stops = this.state.stops; + commit('fetching'); + const response = await fetch(urls.prepare(urls.departures, { stop: stops.map(stop => stop.id), + limit: count || 8, })); if (!response.ok) { diff --git a/resources/ts/store/index.ts b/resources/ts/store/index.ts index 0719309..0feca3b 100644 --- a/resources/ts/store/index.ts +++ b/resources/ts/store/index.ts @@ -4,9 +4,10 @@ import messages, { MessagesState } from './messages'; import departures, { DeparturesState } from './departures' import favourites, { FavouritesState, localStorageSaver } from './favourites' -import { state, mutations, actions, RootState } from "./root"; +import { actions, mutations, RootState, state } from "./root"; import VuexPersistence from "vuex-persist"; import { namespace } from "vuex-class"; +import departureSettings from "./settings/departures"; export type State = { messages: MessagesState; @@ -15,7 +16,7 @@ export type State = { } & RootState; const localStoragePersist = new VuexPersistence<State>({ - reducer: state => ({ favourites: state.favourites }) + modules: ['favourites', 'departures-settings'], }); const sessionStoragePersist = new VuexPersistence<State>({ @@ -25,7 +26,12 @@ const sessionStoragePersist = new VuexPersistence<State>({ const store = new Vuex.Store({ state, mutations, actions, - modules: { messages, departures, favourites }, + modules: { + messages, + departures, + favourites, + 'departures-settings': departureSettings + }, plugins: [ // todo: remove after some time localStorageSaver('favourites.favourites', 'favourites'), @@ -37,3 +43,5 @@ const store = new Vuex.Store({ export default store; export const Favourites = namespace('favourites'); +export const DeparturesSettings = namespace('departures-settings'); +export const Departures = namespace('departures'); diff --git a/resources/ts/store/settings/departures.ts b/resources/ts/store/settings/departures.ts new file mode 100644 index 0000000..919c984 --- /dev/null +++ b/resources/ts/store/settings/departures.ts @@ -0,0 +1,24 @@ +import { ActionContext, Module } from "vuex"; +import { RootState } from "../root"; + +export type DeparturesSettingsState = { + autorefresh: boolean; + autorefreshInterval?: number; + displayedEntriesCount?: number; +} + +const departureSettings: Module<DeparturesSettingsState, RootState> = { + namespaced: true, + state: { + autorefresh: true, + autorefreshInterval: 10, + displayedEntriesCount: 10 + }, + mutations: { + update(state: DeparturesSettingsState, patch: Partial<DeparturesSettingsState>) { + Object.assign(state, patch); + } + } +}; + +export default departureSettings; diff --git a/src/Controller/Api/v1/DeparturesController.php b/src/Controller/Api/v1/DeparturesController.php index afa0798..2f98869 100644 --- a/src/Controller/Api/v1/DeparturesController.php +++ b/src/Controller/Api/v1/DeparturesController.php @@ -68,7 +68,7 @@ class DeparturesController extends Controller */ public function stops(DepartureRepository $departures, StopRepository $stops, Request $request) { - $stops = $stops->all(new IdFilter($request->query->get('stop'))); + $stops = $stops->all(new IdFilter($request->query->get('stop', []))); $result = $departures->current($stops, ...$this->getModifiersFromRequest($request)); return $this->json( diff --git a/templates/app.html.twig b/templates/app.html.twig index eb64bd6..d3b9f5f 100644 --- a/templates/app.html.twig +++ b/templates/app.html.twig @@ -73,38 +73,15 @@ </button> <portal to="popups"> <popper reference="settings-departures" v-if="visibility.departures" arrow placement="left-start" @leave="visibility.departures = false"> - <div class="form-group"> - <h3 class="popper__heading flex"> - <label class="text" for="departures-auto-refresh-interval"> - <ui-icon icon="refresh" fixed-width></ui-icon> - autoodświeżanie - </label> - <ui-switch id="departures-auto-refresh" v-model="autorefresh.departures.active" class="flex-space-left"></ui-switch> - </h3> - <div class="flex " v-if="autorefresh.departures.active"> - <label for="departures-auto-refresh-interval" class="text"> - <span class="sr-only">częstotliwość odświeżania</span> - co - </label> - <div class="input-group input-group-sm"> - <input type="text" class="form-control form-control-sm form-control-simple" id="departures-auto-refresh-interval" v-model="autorefresh.departures.interval"/> - <div class="input-group-append"> - <span class="input-group-text" aria-label="sekund">s</span> - </div> - </div> - </div> - </div> - <div class="form-group"> - <label class="text" for="departures-count"> - <ui-icon icon="line-bus" fixed-width></ui-icon> - Liczba wpisów - </label> - <ui-numeric-input id="departures-count" v-model="count" :min="1" :max="16"></ui-numeric-input> - </div> + <settings-departures></settings-departures> </popper> </portal> </header> - <departures :stops="stops"></departures> + <departures :stops="stops" v-if="stops.length > 0"></departures> + <div class="alert alert-info" v-else> + <ui-icon icon="info"></ui-icon> + Wybierz przystanki korzystając z wyszukiwarki poniżej, aby zobaczyć listę odjazdów. + </div> {% if provider.attribution %} <div class="attribution"> <ui-icon icon="info"></ui-icon> -- 2.45.2 From 984cb37c8f718d38240fda981ca7d367c160c993 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Thu, 19 Mar 2020 17:28:26 +0100 Subject: [PATCH 29/77] #33 - Relative departure times --- package.json | 2 + .../components/departures/departure.html | 21 ++- resources/components/settings/departures.html | 11 +- resources/styles/main.scss | 1 - resources/ts/app.ts | 4 + resources/ts/components/departures.ts | 11 +- .../ts/components/settings/departures.ts | 3 + resources/ts/components/ui/icon.ts | 5 +- resources/ts/store/settings/departures.ts | 2 + yarn.lock | 173 +++--------------- 10 files changed, 69 insertions(+), 164 deletions(-) diff --git a/package.json b/package.json index 4b43114..c938999 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "dependencies": { "@types/mapbox-gl-leaflet": "^0.0.1", "@types/uuid": "^3.4.6", + "@types/vue-moment": "^4.0.0", "@types/workbox-window": "^4.3.3", "clean-webpack-plugin": "^3.0.0", "copy-webpack-plugin": "^4.5.2", @@ -46,6 +47,7 @@ "portal-vue": "^2.1.7", "vue-dragscroll": "^1.10.2", "vue-fragment": "^1.5.1", + "vue-moment": "^4.1.0", "vue-removed-hook-mixin": "^0.1.1", "vue2-leaflet": "^1.0.2", "vuex": "^3.0.1", diff --git a/resources/components/departures/departure.html b/resources/components/departures/departure.html index 06b56d8..5b3aae2 100644 --- a/resources/components/departures/departure.html +++ b/resources/components/departures/departure.html @@ -8,18 +8,23 @@ <div class="departure__time"> <template v-if="!departure.estimated"> <tooltip placement="top-end">Czas rozkładowy, nieuwzględniający aktualnej sytuacji komunikacyjnej.</tooltip> - <ui-icon icon="departure-warning"/> + <ui-icon icon="departure-warning" class="mr-1"/> </template> - <span :class="[ 'departure__time', 'departure__time--delayed']" v-if="timeDiffers"> - {{ departure.scheduled.format('HH:mm') }} - </span> - <span class="badge" :class="[departure.delay < 0 ? 'badge-danger' : 'badge-warning']" - v-if="departure.delay < 0 || departure.delay > 30"> + <template v-if="!relativeTimes"> + <span :class="[ 'departure__time', 'departure__time--delayed']" v-if="timeDiffers"> + {{ departure.scheduled|moment('HH:mm') }} + </span> + <span class="badge" :class="[departure.delay < 0 ? 'badge-danger' : 'badge-warning']" + v-if="departure.delay < 0 || departure.delay > 30"> {{ departure.delay|signed }}s - </span> + </span> - <span class="departure__time">{{ time.format('HH:mm') }}</span> + <span class="departure__time">{{ time|moment('HH:mm') }}</span> + </template> + <template v-else> + {{ timeLeft|duration('humanize', true) }} + </template> </div> <div class="departure__stop"> diff --git a/resources/components/settings/departures.html b/resources/components/settings/departures.html index 402fca6..fc4a9d8 100644 --- a/resources/components/settings/departures.html +++ b/resources/components/settings/departures.html @@ -1,12 +1,12 @@ <fragment> <div class="form-group"> - <h3 class="popper__heading flex"> + <div class="flex"> <label class="text" for="departures-auto-refresh-interval"> <ui-icon icon="refresh" fixed-width/> autoodświeżanie </label> <ui-switch id="departures-auto-refresh" :value="autorefresh" @input="update({ autorefresh: $event })" class="flex-space-left"/> - </h3> + </div> <div class="flex " v-if="autorefresh"> <label for="departures-auto-refresh-interval" class="text"> <span class="sr-only">częstotliwość odświeżania</span> @@ -28,4 +28,11 @@ </label> <ui-numeric-input id="departures-count" :value="displayedEntriesCount" @input="update({ displayedEntriesCount: $event })" :min="1" :max="20"/> </div> + <div class="form-group flex"> + <label class="text" for="departures-relative-times"> + <ui-icon icon="relative-time" fixed-width/> + czas do odjazdu + </label> + <ui-switch id="departures-relative-times" :value="relativeTimes" @input="update({ relativeTimes: $event })" class="flex-space-left"/> + </div> </fragment> diff --git a/resources/styles/main.scss b/resources/styles/main.scss index 6be0b6c..8d139d0 100644 --- a/resources/styles/main.scss +++ b/resources/styles/main.scss @@ -6,7 +6,6 @@ $border-radius-sm: $border-radius; @import "~bootstrap/scss/functions"; @import "~bootstrap/scss/variables"; -$form-group-margin-bottom: $form-group-margin-bottom / 2; $primary: #005ea8; $custom-control-indicator-checked-bg: $dark; diff --git a/resources/ts/app.ts b/resources/ts/app.ts index 1d7fc4e..b92ee01 100644 --- a/resources/ts/app.ts +++ b/resources/ts/app.ts @@ -16,6 +16,9 @@ import { Workbox } from "workbox-window"; import { migrate } from "./store/migrations"; import { Component } from "vue-property-decorator"; +import * as VueMoment from "vue-moment"; +import * as moment from 'moment'; +import 'moment/locale/pl' window['$'] = window['jQuery'] = $; window['Popper'] = Popper; @@ -24,6 +27,7 @@ Vue.use(Vuex); Vue.use(PortalVue); Vue.use(VueDragscroll); Vue.use(VueFragment); +Vue.use(VueMoment, { moment }); declare module 'vue/types/vue' { interface Vue { diff --git a/resources/ts/components/departures.ts b/resources/ts/components/departures.ts index f85e846..19c00f8 100644 --- a/resources/ts/components/departures.ts +++ b/resources/ts/components/departures.ts @@ -1,7 +1,7 @@ import Vue from 'vue' import { Departure } from "../model"; import { Component, Prop, Watch } from "vue-property-decorator"; -import store, { Departures } from '../store' +import store, { Departures, DeparturesSettings } from '../store' import { Trip } from "../model/trip"; import urls from "../urls"; import { Jsonified } from "../utils"; @@ -12,11 +12,14 @@ export class DeparturesComponent extends Vue { @Departures.State departures: Departure[]; } -@Component({ template: require("../../components/departures/departure.html") }) +@Component({ template: require("../../components/departures/departure.html"), store }) export class DepartureComponent extends Vue { @Prop(Object) departure: Departure; scheduledTrip: Trip = null; + @DeparturesSettings.State + relativeTimes: boolean; + showTrip: boolean = false; processTrip(trip: Jsonified<Trip>): Trip { @@ -40,6 +43,10 @@ export class DepartureComponent extends Vue { return this.departure.estimated || this.departure.scheduled; } + get timeLeft() { + return moment.duration(this.time.diff(moment())); + } + @Watch('showTrip') async downloadTrips() { if (this.showTrip != true || this.trip != null) { diff --git a/resources/ts/components/settings/departures.ts b/resources/ts/components/settings/departures.ts index c7b2499..8625d0a 100644 --- a/resources/ts/components/settings/departures.ts +++ b/resources/ts/components/settings/departures.ts @@ -8,6 +8,9 @@ export class SettingsDepartures extends Vue { @DeparturesSettings.State public autorefresh: boolean; + @DeparturesSettings.State + public relativeTimes: boolean; + @DeparturesSettings.State public autorefreshInterval: number; diff --git a/resources/ts/components/ui/icon.ts b/resources/ts/components/ui/icon.ts index e2928d5..11863a0 100644 --- a/resources/ts/components/ui/icon.ts +++ b/resources/ts/components/ui/icon.ts @@ -7,11 +7,11 @@ import { faCheck, faCheckDouble, faChevronCircleUp, - faChevronDown, - faChevronUp, + faChevronDown, faChevronUp, faClock, faCog, faExclamationTriangle, + faHourglassHalf, faInfoCircle, faMapMarkerAlt, faMoon, @@ -83,6 +83,7 @@ const definitions: Dictionary<Icon> = { 'spinner': simple(faSpinnerThird, { spin: true }), 'increment': simple(faPlus, { "fixed-width": true }), 'decrement': simple(faMinus, { "fixed-width": true }), + 'relative-time': simple(faHourglassHalf), 'departure-warning': stack([ {icon: faClockBold}, {icon: faSolidExclamationTriangle, transform: "shrink-5 down-4 right-6"} diff --git a/resources/ts/store/settings/departures.ts b/resources/ts/store/settings/departures.ts index 919c984..2186ec3 100644 --- a/resources/ts/store/settings/departures.ts +++ b/resources/ts/store/settings/departures.ts @@ -5,12 +5,14 @@ export type DeparturesSettingsState = { autorefresh: boolean; autorefreshInterval?: number; displayedEntriesCount?: number; + relativeTimes: boolean, } const departureSettings: Module<DeparturesSettingsState, RootState> = { namespaced: true, state: { autorefresh: true, + relativeTimes: false, autorefreshInterval: 10, displayedEntriesCount: 10 }, diff --git a/yarn.lock b/yarn.lock index cc66e4d..b1ba8fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -306,6 +306,14 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.7.tgz#51d42247473bc00e38cc8dfaf70d936842a36c03" integrity sha512-C2j2FWgQkF1ru12SjZJyMaTPxs/f6n90+5G5qNakBxKXjTBc/YTSelHh4Pz1HUDwxFXD9WvpQhOGCDC+/Y4mIQ== +"@types/vue-moment@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/vue-moment/-/vue-moment-4.0.0.tgz#a70ffd56f6834d683710a9a3499224260a4f931b" + integrity sha512-29S5LD5gmQFvkhoKCAseKE036CVOKQGij1QWHCBmTzJwCb4SXvKGbrY1QIn9cAFtnxzkM55+wyjjo/apAfrdTQ== + dependencies: + moment ">=2.24.0" + vue ">=2.6.10" + "@types/webpack-sources@*": version "0.1.6" resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.6.tgz#3d21dfc2ec0ad0c77758e79362426a9ba7d7cbcb" @@ -1584,13 +1592,6 @@ debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@^3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -1661,11 +1662,6 @@ decompress@^4.0.0, decompress@^4.2.0: pify "^2.3.0" strip-dirs "^2.0.0" -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - define-properties@^1.1.2, define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -1731,11 +1727,6 @@ detect-file@^1.0.0: resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - diffie-hellman@^5.0.0: version "5.0.3" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" @@ -2368,13 +2359,6 @@ fs-extra@^4.0.2: jsonfile "^4.0.0" universalify "^0.1.0" -fs-minipass@^1.2.5: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" - integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== - dependencies: - minipass "^2.6.0" - fs-write-stream-atomic@^1.0.8: version "1.0.10" resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" @@ -2823,13 +2807,6 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -iconv-lite@^0.4.4: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - icss-replace-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" @@ -2852,13 +2829,6 @@ iferr@^0.1.5: resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= -ignore-walk@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" - integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== - dependencies: - minimatch "^3.0.4" - ignore@^3.3.5: version "3.3.10" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" @@ -3003,7 +2973,7 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: +ini@^1.3.4, ini@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== @@ -3831,21 +3801,6 @@ minimist@1.2.0, minimist@^1.1.3, minimist@^1.2.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= -minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" - integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - -minizlib@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" - integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== - dependencies: - minipass "^2.9.0" - mississippi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" @@ -3893,7 +3848,7 @@ mixin-deep@^1.2.0: dependencies: minimist "0.0.8" -moment@*, moment@^2.22.2: +moment@*, moment@>=2.24.0, moment@^2.19.2, moment@^2.22.2: version "2.24.0" resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== @@ -3915,11 +3870,6 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - murmurhash-js@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/murmurhash-js/-/murmurhash-js-1.0.0.tgz#b06278e21fc6c37fa5313732b0412bcb6ae15f51" @@ -3947,15 +3897,6 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" -needle@^2.2.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.2.tgz#3342dea100b7160960a450dc8c22160ac712a528" - integrity sha512-DUzITvPVDUy6vczKKYTnWc/pBZ0EnjMJnQ3y+Jo5zfKFimJs7S3HFCxCRZYB9FUZcrzUQr3WsmvZgddMEIZv6w== - dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - neo-async@^2.5.0, neo-async@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" @@ -4013,22 +3954,6 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" -node-pre-gyp@*: - version "0.14.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83" - integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4.4.2" - node-sass@^4.9.3: version "4.13.1" resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.13.1.tgz#9db5689696bb2eec2c32b98bfea4c7a2e992d0a3" @@ -4059,14 +3984,6 @@ node-sass@^4.9.3: dependencies: abbrev "1" -nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= - dependencies: - abbrev "1" - osenv "^0.1.4" - normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -4098,13 +4015,6 @@ normalize-url@2.0.1: query-string "^5.0.1" sort-keys "^2.0.0" -npm-bundled@^1.0.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" - integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== - dependencies: - npm-normalize-package-bin "^1.0.1" - npm-conf@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" @@ -4113,20 +4023,6 @@ npm-conf@^1.1.0: config-chain "^1.1.11" pify "^3.0.0" -npm-normalize-package-bin@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" - integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== - -npm-packlist@^1.1.6: - version "1.4.8" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" - integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== - dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" - npm-normalize-package-bin "^1.0.1" - npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -4134,7 +4030,7 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2: +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== @@ -4281,7 +4177,7 @@ os-tmpdir@^1.0.0: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -osenv@0, osenv@^0.1.4: +osenv@0: version "0.1.5" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== @@ -4814,16 +4710,6 @@ raw-loader@^0.5.1: resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa" integrity sha1-DD0L6u2KAclm2Xh793goElKpeao= -rc@^1.2.7: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" @@ -5041,7 +4927,7 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -rimraf@2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3: +rimraf@2, rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -5085,7 +4971,7 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -5111,7 +4997,7 @@ sass-loader@^7.1.0: pify "^4.0.1" semver "^6.3.0" -sax@^1.2.4, sax@~1.2.4: +sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -5608,11 +5494,6 @@ strip-indent@^1.0.1: dependencies: get-stdin "^4.0.1" -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - strip-outer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" @@ -5700,19 +5581,6 @@ tar@^2.0.0: fstream "^1.0.12" inherits "2" -tar@^4.4.2: - version "4.4.13" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" - integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== - dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.8.6" - minizlib "^1.2.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.3" - temp-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" @@ -6069,6 +5937,13 @@ vue-fragment@^1.5.1: resolved "https://registry.yarnpkg.com/vue-fragment/-/vue-fragment-1.5.1.tgz#44c070d55ed1e9a6c698ef57a5c83f64bb06feeb" integrity sha512-ig6eES6TcMBbANW71ylB+AJgRN+Zksb3f50AxjGpAk6hMzqmeuD80qeh4LJP0jVw2dMBMjgRUfIkrvxygoRgtQ== +vue-moment@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/vue-moment/-/vue-moment-4.1.0.tgz#092a8ff723a96c6f85a0a8e23ad30f0bf320f3b0" + integrity sha512-Gzisqpg82ItlrUyiD9d0Kfru+JorW2o4mQOH06lEDZNgxci0tv/fua1Hl0bo4DozDV2JK1r52Atn/8QVCu8qQw== + dependencies: + moment "^2.19.2" + vue-property-decorator@^7.0.0: version "7.3.0" resolved "https://registry.yarnpkg.com/vue-property-decorator/-/vue-property-decorator-7.3.0.tgz#d50d67f0b0f1c814f9f2fba36d6eeccbcc62dbb6" @@ -6089,7 +5964,7 @@ vue2-leaflet@^1.0.2: "@types/leaflet" "^1.2.11" leaflet "1.3.1" -vue@^2.5.17: +vue@>=2.6.10, vue@^2.5.17: version "2.6.11" resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.11.tgz#76594d877d4b12234406e84e35275c6d514125c5" integrity sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ== @@ -6398,7 +6273,7 @@ yallist@^2.1.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= -yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: +yallist@^3.0.2: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -- 2.45.2 From 057a7d6d01a06a6a10eaeb3f6096bff02559998e Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Thu, 19 Mar 2020 20:22:50 +0100 Subject: [PATCH 30/77] #41 - Move messaging settings to vuex store --- resources/components/messages.html | 40 +++++++++++++------- resources/components/settings/messages.html | 31 +++++++++++++++ resources/ts/components/app.ts | 40 ++++++++++---------- resources/ts/components/index.ts | 1 + resources/ts/components/messages.ts | 24 ++++++++---- resources/ts/components/settings/index.ts | 1 + resources/ts/components/settings/messages.ts | 21 ++++++++++ resources/ts/store/favourites.ts | 15 ++------ resources/ts/store/index.ts | 18 +++++---- resources/ts/store/settings/messages.ts | 24 ++++++++++++ templates/app.html.twig | 20 +--------- 11 files changed, 157 insertions(+), 78 deletions(-) create mode 100644 resources/components/settings/messages.html create mode 100644 resources/ts/components/settings/messages.ts create mode 100644 resources/ts/store/settings/messages.ts diff --git a/resources/components/messages.html b/resources/components/messages.html index d6cda3b..3ee5353 100644 --- a/resources/components/messages.html +++ b/resources/components/messages.html @@ -1,15 +1,29 @@ -<ul class="messages list-unstyled"> - <li class="message alert" :class="`alert-${type(message)}`" v-for="message in messages"> - <ui-icon :icon="`message-${type(message)}`" fixed-width /> - {{ message.message }} +<div class="messages mb-2"> + <ul class="list-unstyled mb-0"> + <li class="message alert" :class="`alert-${type(message)}`" v-for="message in messages"> + <ui-icon :icon="`message-${message.type}`" fixed-width/> + {{ message.message }} - <div class="message__info"> - <small class="message__date"> - Komunikat ważny od - {{ message.validFrom.format('HH:mm') }} - do - {{ message.validTo.format('HH:mm') }} - </small> + <div class="message__info"> + <small class="message__date"> + Komunikat ważny od + {{ message.validFrom.format('HH:mm') }} + do + {{ message.validTo.format('HH:mm') }} + </small> + </div> + </li> + </ul> + <template v-if="nonDisplayedCount > 0"> + <div class="flex"> + <button class="btn btn-action btn-sm flex-space-left" @click="showAll = !showAll"> + <template v-if="showAll"> + <ui-icon icon="chevron-up"/> {{ nonDisplayedCount }} mniej + </template> + <template v-else> + <ui-icon icon="chevron-down"/> {{ nonDisplayedCount }} więcej + </template> + </button> </div> - </li> -</ul> + </template> +</div> diff --git a/resources/components/settings/messages.html b/resources/components/settings/messages.html new file mode 100644 index 0000000..f185340 --- /dev/null +++ b/resources/components/settings/messages.html @@ -0,0 +1,31 @@ +<fragment> + <div class="form-group"> + <div class="flex"> + <label class="text" for="departures-auto-refresh-interval"> + <ui-icon icon="refresh" fixed-width/> + autoodświeżanie + </label> + <ui-switch id="departures-auto-refresh" :value="autorefresh" @input="update({ autorefresh: $event })" class="flex-space-left"/> + </div> + <div class="flex " v-if="autorefresh"> + <label for="departures-auto-refresh-interval" class="text"> + <span class="sr-only">częstotliwość odświeżania</span> + co + </label> + <div class="input-group input-group-sm"> + <input type="text" class="form-control form-control-sm form-control-simple" id="departures-auto-refresh-interval" + :value="autorefreshInterval" @input="update({ autorefreshInterval: Number.parseInt($event.target.value) })" /> + <div class="input-group-append"> + <span class="input-group-text" aria-label="sekund">s</span> + </div> + </div> + </div> + </div> + <div class="form-group"> + <label class="text" for="departures-count"> + <ui-icon icon="messages" fixed-width/> + wyświetlanych komunikatów + </label> + <ui-numeric-input id="departures-count" :value="displayedEntriesCount" @input="update({ displayedEntriesCount: $event })" :min="1" /> + </div> +</fragment> diff --git a/resources/ts/components/app.ts b/resources/ts/components/app.ts index 0d06caa..8949603 100644 --- a/resources/ts/components/app.ts +++ b/resources/ts/components/app.ts @@ -4,6 +4,7 @@ import { Component, Watch } from "vue-property-decorator"; import { Mutation, Action } from 'vuex-class' import { Stop } from "../model"; import { DeparturesSettingsState } from "../store/settings/departures"; +import { MessagesSettingsState } from "../store/settings/messages"; @Component({ store }) export class Application extends Vue { @@ -18,13 +19,6 @@ export class Application extends Vue { picker: 'search' }; - private autorefresh = { - messages: { - active: true, - interval: 60 - } - }; - private intervals = { messages: null, departures: null }; get messages() { @@ -55,6 +49,7 @@ export class Application extends Vue { created() { this.initDeparturesRefreshInterval(); + this.initMessagesRefreshInterval(); } private initDeparturesRefreshInterval() { @@ -76,6 +71,25 @@ export class Application extends Vue { departuresAutorefreshCallback(); } + private initMessagesRefreshInterval() { + const messagesAutorefreshCallback = () => { + const {autorefresh, autorefreshInterval} = this.$store.state['messages-settings'] as MessagesSettingsState; + + if (this.intervals.messages) { + clearInterval(this.intervals.messages); + } + + if (autorefresh) { + this.intervals.messages = setInterval(() => this.updateMessages(), Math.max(5, autorefreshInterval) * 1000) + } + }; + + this.$store.watch(({"messages-settings": state}) => state.autorefresh, messagesAutorefreshCallback); + this.$store.watch(({"messages-settings": state}) => state.autorefreshInterval, messagesAutorefreshCallback); + + messagesAutorefreshCallback(); + } + @Action('messages/update') updateMessages: () => void; @Action('departures/update') updateDepartures: () => void; @@ -87,16 +101,4 @@ export class Application extends Vue { onStopUpdate() { this.updateDepartures(); } - - @Watch('autorefresh', { immediate: true, deep: true }) - onAutorefreshUpdate(settings) { - if (this.intervals.messages) { - clearInterval(this.intervals.messages); - this.intervals.messages = null; - } - - if (settings.messages.active) { - this.intervals.messages = setInterval(() => this.updateMessages(), Math.max(5, settings.messages.interval) * 1000); - } - } } diff --git a/resources/ts/components/index.ts b/resources/ts/components/index.ts index 337f4e2..1e7038d 100644 --- a/resources/ts/components/index.ts +++ b/resources/ts/components/index.ts @@ -12,3 +12,4 @@ export * from './trip' export * from './ui' export * from './settings' export { Departures } from "../store"; +export { Messages } from "../store"; diff --git a/resources/ts/components/messages.ts b/resources/ts/components/messages.ts index 50b8140..e9f054c 100644 --- a/resources/ts/components/messages.ts +++ b/resources/ts/components/messages.ts @@ -1,18 +1,26 @@ import Vue from 'vue'; import { Component } from "vue-property-decorator"; import { Message } from "../model/message"; -import { namespace } from 'vuex-class'; -import store from '../store' - -const { State } = namespace('messages'); +import store, { Messages, MessagesSettings } from '../store' @Component({ template: require("../../components/messages.html"), store }) export class MessagesComponent extends Vue { - @State messages: Message[]; + @Messages.State('messages') + public allMessages: Message[]; - public icon(message: Message) { - switch (message.type) { - } + @MessagesSettings.State + public displayedEntriesCount: number; + + public showAll: boolean = false; + + get messages() { + return this.showAll + ? this.allMessages + : this.allMessages.slice(0, this.displayedEntriesCount); + } + + get nonDisplayedCount(): number { + return Math.max(this.allMessages.length - this.displayedEntriesCount, 0); } public type(message: Message) { diff --git a/resources/ts/components/settings/index.ts b/resources/ts/components/settings/index.ts index 10d35a6..21e734c 100644 --- a/resources/ts/components/settings/index.ts +++ b/resources/ts/components/settings/index.ts @@ -1 +1,2 @@ export * from "./departures" +export * from "./messages" diff --git a/resources/ts/components/settings/messages.ts b/resources/ts/components/settings/messages.ts new file mode 100644 index 0000000..4f66700 --- /dev/null +++ b/resources/ts/components/settings/messages.ts @@ -0,0 +1,21 @@ +import { Component } from "vue-property-decorator"; +import store, { MessagesSettings } from "../../store"; +import Vue from "vue"; +import { MessagesSettingsState } from "../../store/settings/messages"; + +@Component({template: require("../../../components/settings/messages.html"), store}) +export class SettingsMessages extends Vue { + @MessagesSettings.State + public autorefresh: boolean; + + @MessagesSettings.State + public autorefreshInterval: number; + + @MessagesSettings.State + public displayedEntriesCount: number; + + @MessagesSettings.Mutation + public update: (state: Partial<MessagesSettingsState>) => void; +} + +Vue.component('SettingsMessages', SettingsMessages); diff --git a/resources/ts/store/favourites.ts b/resources/ts/store/favourites.ts index 0ba6343..0f61f68 100644 --- a/resources/ts/store/favourites.ts +++ b/resources/ts/store/favourites.ts @@ -1,11 +1,10 @@ -import { RootState, SavedState } from "./root"; -import { Module, Plugin, Store } from "vuex"; -import * as utils from "../utils"; +import { RootState } from "./root"; +import { Module } from "vuex"; import { Stop } from "../model"; export interface Favourite { id: string; - name: string; + name: string; stops: Stop[]; } @@ -28,12 +27,4 @@ const favourites: Module<FavouritesState, RootState> = { } }; -export const localStorageSaver = (path: string, key: string): Plugin<any> => (store: Store<any>) => { - utils.set(store.state, path, JSON.parse(window.localStorage.getItem(key) || '[]')); - - store.subscribe((mutation, state) => { - window.localStorage.setItem(key, JSON.stringify(utils.get(state, path))); - }) -}; - export default favourites; diff --git a/resources/ts/store/index.ts b/resources/ts/store/index.ts index 0feca3b..bd4e43a 100644 --- a/resources/ts/store/index.ts +++ b/resources/ts/store/index.ts @@ -2,21 +2,24 @@ import Vuex from 'vuex'; import messages, { MessagesState } from './messages'; import departures, { DeparturesState } from './departures' -import favourites, { FavouritesState, localStorageSaver } from './favourites' +import favourites, { FavouritesState } from './favourites' +import departureSettings, { DeparturesSettingsState } from "./settings/departures"; +import messagesSettings, { MessagesSettingsState } from "./settings/messages"; import { actions, mutations, RootState, state } from "./root"; import VuexPersistence from "vuex-persist"; import { namespace } from "vuex-class"; -import departureSettings from "./settings/departures"; export type State = { messages: MessagesState; departures: DeparturesState; favourites: FavouritesState; + "departures-settings": DeparturesSettingsState, + "messages-settings": MessagesSettingsState, } & RootState; const localStoragePersist = new VuexPersistence<State>({ - modules: ['favourites', 'departures-settings'], + modules: ['favourites', 'departures-settings', 'messages-settings'], }); const sessionStoragePersist = new VuexPersistence<State>({ @@ -24,17 +27,16 @@ const sessionStoragePersist = new VuexPersistence<State>({ storage: window.sessionStorage }); -const store = new Vuex.Store({ +const store = new Vuex.Store<RootState>({ state, mutations, actions, modules: { messages, departures, favourites, - 'departures-settings': departureSettings + 'departures-settings': departureSettings, + 'messages-settings': messagesSettings, }, plugins: [ - // todo: remove after some time - localStorageSaver('favourites.favourites', 'favourites'), localStoragePersist.plugin, sessionStoragePersist.plugin, ] @@ -44,4 +46,6 @@ export default store; export const Favourites = namespace('favourites'); export const DeparturesSettings = namespace('departures-settings'); +export const MessagesSettings = namespace('messages-settings'); export const Departures = namespace('departures'); +export const Messages = namespace('messages'); diff --git a/resources/ts/store/settings/messages.ts b/resources/ts/store/settings/messages.ts new file mode 100644 index 0000000..116a499 --- /dev/null +++ b/resources/ts/store/settings/messages.ts @@ -0,0 +1,24 @@ +import { Module } from "vuex"; +import { RootState } from "../root"; + +export type MessagesSettingsState = { + autorefresh: boolean; + autorefreshInterval?: number; + displayedEntriesCount?: number; +} + +const messagesSettings: Module<MessagesSettingsState, RootState> = { + namespaced: true, + state: { + autorefresh: true, + autorefreshInterval: 60, + displayedEntriesCount: 2 + }, + mutations: { + update(state: MessagesSettingsState, patch: Partial<MessagesSettingsState>) { + Object.assign(state, patch); + } + } +}; + +export default messagesSettings; diff --git a/templates/app.html.twig b/templates/app.html.twig index d3b9f5f..467ab65 100644 --- a/templates/app.html.twig +++ b/templates/app.html.twig @@ -29,25 +29,7 @@ <portal to="popups"> <popper reference="settings-messages" v-if="visibility.messages" arrow placement="left-start" @leave="visibility.messages = false"> - <h3 class="popper__heading flex"> - <label class="text" for="messages-auto-refresh"> - <ui-icon icon="refresh" fixed-width></ui-icon> - autoodświeżanie - </label> - <ui-switch id="messages-auto-refresh" v-model="autorefresh.messages.active" class="flex-space-left"></ui-switch> - </h3> - <div class="flex" v-if="autorefresh.messages.active"> - <label for="messages-auto-refresh-interval" class="text"> - <span class="sr-only">częstotliwość odświeżania</span> - co - </label> - <div class="input-group input-group-sm"> - <input type="text" class="form-control form-control-sm form-control-simple" id="messages-auto-refresh-interval" v-model="autorefresh.messages.interval"/> - <div class="input-group-append"> - <span class="input-group-text" aria-label="sekund">s</span> - </div> - </div> - </div> + <settings-messages></settings-messages> </popper> </portal> </header> -- 2.45.2 From 4b9a9c54d8cb4c20a2970e2122d31890eafa6214 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sat, 21 Mar 2020 15:41:49 +0100 Subject: [PATCH 31/77] #48 - Fix bug with non serializing recursive departure --- config/packages/jms_serializer.yaml | 4 ++++ resources/ts/components/picker.ts | 2 +- .../WithDestinationsDatabaseHandler.php | 6 ++++++ src/Service/AggregateConverter.php | 21 ++++++++++++++++++- src/Service/SerializerContextFactory.php | 2 +- 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/config/packages/jms_serializer.yaml b/config/packages/jms_serializer.yaml index d25fa03..d83e1d3 100644 --- a/config/packages/jms_serializer.yaml +++ b/config/packages/jms_serializer.yaml @@ -1,4 +1,8 @@ jms_serializer: + default_context: + serialization: + serialize_null: true + visitors: xml_serialization: format_output: '%kernel.debug%' diff --git a/resources/ts/components/picker.ts b/resources/ts/components/picker.ts index 93493d1..4dbac37 100644 --- a/resources/ts/components/picker.ts +++ b/resources/ts/components/picker.ts @@ -42,7 +42,7 @@ export class PickerStopComponent extends Vue { [lines => lines.length > 2, ([first]) => `${first.symbol}…`], ); - return unique(this.stop.destinations || [], destination => destination.stop.name).map(compactLines); + return unique(this.stop.destinations || [], destination => destination.stop && destination.stop.name).map(compactLines); } } diff --git a/src/Handler/Database/WithDestinationsDatabaseHandler.php b/src/Handler/Database/WithDestinationsDatabaseHandler.php index f3f7879..eeb1dfb 100644 --- a/src/Handler/Database/WithDestinationsDatabaseHandler.php +++ b/src/Handler/Database/WithDestinationsDatabaseHandler.php @@ -7,6 +7,7 @@ use App\Event\PostProcessEvent; use App\Handler\PostProcessingHandler; use App\Model\Destination; use App\Model\Stop; +use App\Service\CacheableConverter; use App\Service\Converter; use App\Service\IdUtils; use Doctrine\ORM\EntityManagerInterface; @@ -25,6 +26,11 @@ class WithDestinationsDatabaseHandler implements PostProcessingHandler $this->em = $entityManager; $this->converter = $converter; $this->id = $id; + + if ($this->converter instanceof CacheableConverter) { + $this->converter = clone $this->converter; + $this->converter->flushCache(); + } } public function postProcess(PostProcessEvent $event) diff --git a/src/Service/AggregateConverter.php b/src/Service/AggregateConverter.php index ef180c7..e9087d1 100644 --- a/src/Service/AggregateConverter.php +++ b/src/Service/AggregateConverter.php @@ -3,8 +3,9 @@ namespace App\Service; use Tightenco\Collect\Support\Collection; +use function Kadet\Functional\Predicates\instance; -class AggregateConverter implements Converter +class AggregateConverter implements Converter, CacheableConverter { private $converters; @@ -42,4 +43,22 @@ class AggregateConverter implements Converter { return clone $this->converters; } + + public function flushCache() + { + $this + ->converters + ->filter(instance(CacheableConverter::class)) + ->each(function (CacheableConverter $converter) { + $converter->flushCache(); + }) + ; + } + + public function __clone() + { + $this->converters = $this->converters->map(function ($object) { + return clone $object; + }); + } } diff --git a/src/Service/SerializerContextFactory.php b/src/Service/SerializerContextFactory.php index 94156b9..310235f 100644 --- a/src/Service/SerializerContextFactory.php +++ b/src/Service/SerializerContextFactory.php @@ -23,7 +23,7 @@ final class SerializerContextFactory public function create($subject, array $groups = ['Default']) { - return SerializationContext::create()->setGroups($this->groups($subject, $groups)); + return SerializationContext::create()->setSerializeNull(true)->setGroups($this->groups($subject, $groups)); } private function groups($subject, array $groups) -- 2.45.2 From 03058f251b51af6b6cd212c2252c98179552f1ad Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sat, 2 May 2020 00:58:03 +0200 Subject: [PATCH 32/77] #40 - Add provider DTO and API endpoint --- config/routes.yaml | 5 + config/services.yaml | 14 ++- src/Controller/Api/v1/ProviderController.php | 31 ++++++ src/Model/Provider.php | 101 +++++++++++++++++++ src/Service/AggregateConverter.php | 34 +++++-- src/Service/ProviderConverter.php | 27 +++++ 6 files changed, 196 insertions(+), 16 deletions(-) create mode 100644 src/Controller/Api/v1/ProviderController.php create mode 100644 src/Model/Provider.php create mode 100644 src/Service/ProviderConverter.php diff --git a/config/routes.yaml b/config/routes.yaml index b42047c..d5f74b8 100644 --- a/config/routes.yaml +++ b/config/routes.yaml @@ -2,3 +2,8 @@ api_v1: resource: ../src/Controller/Api/v1 type: annotation prefix: /{provider}/api/v1 + +api_v1_providers: + path: /api/v1/providers + defaults: + _controller: '\App\Controller\Api\v1\ProviderController::index' diff --git a/config/services.yaml b/config/services.yaml index 9fe3e71..774f1d7 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -19,11 +19,14 @@ services: App\Provider\Provider: tags: [ app.provider ] + App\Service\Converter: + tags: [ app.converter ] + # makes classes in src/ available to be used as services # this creates a service per class whose id is the fully-qualified class name App\: resource: '../src/*' - exclude: '../src/{DependencyInjection,Exception,Modifie,Entity,Model,Migrations,Tests,Functions,Handler,Kernel.php}' + exclude: '../src/{DependencyInjection,Exception,Modifier,Entity,Model,Migrations,Tests,Functions,Handler,Kernel.php}' # controllers are imported separately to make sure services can be injected # as action arguments even if you don't extend any base controller class @@ -72,19 +75,14 @@ services: ProxyManager\Configuration: '@proxy.config' + # converter App\Service\AggregateConverter: arguments: - - !tagged_iterator app.converter + - !tagged_iterator app.converter App\Service\Converter: '@App\Service\AggregateConverter' - App\Service\EntityConverter: - tags: ['app.converter'] - - App\Service\ScheduledStopConverter: - tags: ['app.converter'] - # serializer configuration App\Service\SerializerContextFactory: arguments: diff --git a/src/Controller/Api/v1/ProviderController.php b/src/Controller/Api/v1/ProviderController.php new file mode 100644 index 0000000..67b0dcc --- /dev/null +++ b/src/Controller/Api/v1/ProviderController.php @@ -0,0 +1,31 @@ +<?php + +namespace App\Controller\Api\v1; + +use App\Controller\Controller; +use App\Service\Converter; +use App\Service\ProviderResolver; +use Swagger\Annotations as SWG; +use Symfony\Component\Routing\Annotation\Route; +use function Kadet\Functional\ref; + +/** + * @Route("/providers") + * @SWG\Tag(name="Providers") + */ +class ProviderController extends Controller +{ + /** + * @Route("/", methods={"GET"}) + */ + public function index(ProviderResolver $resolver, Converter $converter) + { + $providers = $resolver + ->all() + ->map(ref([$converter, 'convert'])) + ->values() + ->toArray() + ; + return $this->json($providers); + } +} diff --git a/src/Model/Provider.php b/src/Model/Provider.php new file mode 100644 index 0000000..854f8ec --- /dev/null +++ b/src/Model/Provider.php @@ -0,0 +1,101 @@ +<?php + +namespace App\Model; + +use Carbon\Carbon; +use JMS\Serializer\Annotation as Serializer; +use Swagger\Annotations as SWG; + +class Provider implements Fillable, Referable +{ + use FillTrait; + + /** + * Short identifier of provider, ex. "trojmiasto" + * @SWG\Property(example="trojmiasto") + * @Serializer\Type("string") + * @var string + */ + private $id; + + /** + * Full name of the provider, ex. "MZKZG Trójmiasto" + * @SWG\Property(example="MZKZG Trójmiasto") + * @Serializer\Type("string") + * @var string + */ + private $name; + + /** + * Short name of the provider for easier identification, ex. "Trójmiasto" or "Warszawa" + * @SWG\Property(example="Trójmiasto") + * @Serializer\Type("string") + * @var string + */ + private $shortName; + + /** + * Attribution to be presented for this provider, can contain HTML tags. + * @SWG\Property(example="Copyright by XYZ inc.") + * @Serializer\Type("string") + * @var string|null + */ + private $attribution; + + /** + * Time when data was last synchronized with this provider. + * @Serializer\Type("Carbon") + * @var Carbon|null + */ + private $lastUpdate; + + public function getId(): string + { + return $this->id; + } + + public function setId(string $id): void + { + $this->id = $id; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): void + { + $this->name = $name; + } + + public function getShortName(): string + { + return $this->shortName; + } + + public function setShortName(string $shortName): void + { + $this->shortName = $shortName; + } + + public function getAttribution(): ?string + { + return $this->attribution; + } + + public function setAttribution(?string $attribution): void + { + $this->attribution = $attribution; + } + + public function getLastUpdate(): ?Carbon + { + return $this->lastUpdate; + } + + public function setLastUpdate(?Carbon $lastUpdate): void + { + $this->lastUpdate = $lastUpdate; + } +} diff --git a/src/Service/AggregateConverter.php b/src/Service/AggregateConverter.php index e9087d1..f9e6dff 100644 --- a/src/Service/AggregateConverter.php +++ b/src/Service/AggregateConverter.php @@ -8,20 +8,19 @@ use function Kadet\Functional\Predicates\instance; class AggregateConverter implements Converter, CacheableConverter { private $converters; + private $cachedConverters; public function __construct(iterable $converters) { - $this->converters = collect($converters)->each(function (Converter $converter) { - if ($converter instanceof RecursiveConverter) { - $converter->setParent($this); - } - }); + $this->converters = $converters; } public function convert($entity) { + $this->ensureCachedConverters(); + /** @var Converter $converter */ - $converter = $this->converters->first(function (Converter $converter) use ($entity) { + $converter = $this->cachedConverters->first(function (Converter $converter) use ($entity) { return $converter->supports($entity); }); @@ -41,7 +40,9 @@ class AggregateConverter implements Converter, CacheableConverter public function getConverters(): Collection { - return clone $this->converters; + $this->ensureCachedConverters(); + + return clone $this->cachedConverters; } public function flushCache() @@ -57,8 +58,25 @@ class AggregateConverter implements Converter, CacheableConverter public function __clone() { - $this->converters = $this->converters->map(function ($object) { + $this->ensureCachedConverters(); + + $this->cachedConverters = $this->cachedConverters->map(function ($object) { return clone $object; }); } + + private function ensureCachedConverters() + { + if (!$this->cachedConverters) { + $this->cachedConverters = collect($this->converters) + ->filter(function (Converter $converter) { + return $converter !== $this; + }) + ->each(function (Converter $converter) { + if ($converter instanceof RecursiveConverter) { + $converter->setParent($this); + } + }); + } + } } diff --git a/src/Service/ProviderConverter.php b/src/Service/ProviderConverter.php new file mode 100644 index 0000000..f644553 --- /dev/null +++ b/src/Service/ProviderConverter.php @@ -0,0 +1,27 @@ +<?php + +namespace App\Service; + +use App\Model\Provider as ProviderDTO; +use App\Provider\Provider; + +class ProviderConverter implements Converter +{ + public function convert($entity) + { + /** @var Provider $entity */ + + return ProviderDTO::createFromArray([ + 'id' => $entity->getIdentifier(), + 'shortName' => $entity->getShortName(), + 'name' => $entity->getName(), + 'attribution' => $entity->getAttribution(), + 'lastUpdate' => $entity->getLastUpdate() ? clone $entity->getLastUpdate() : null, + ]); + } + + public function supports($entity) + { + return $entity instanceof Provider; + } +} -- 2.45.2 From 2659acdc5871279c9cce3511acdde075317f0be3 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sat, 2 May 2020 23:33:15 +0200 Subject: [PATCH 33/77] #40 - Add map based provider picker --- docker-compose.yml | 2 + resources/components/page/providers.html | 42 +++ resources/styles/_map.scss | 29 ++ resources/styles/main.scss | 17 ++ resources/styles/page/_provider-picker.scss | 62 +++++ resources/ts/app.ts | 10 +- resources/ts/components/app.ts | 5 +- resources/ts/components/index.ts | 2 + resources/ts/components/map.ts | 7 +- resources/ts/components/page/index.ts | 1 + resources/ts/components/page/providers.ts | 26 ++ resources/ts/model/common.ts | 4 + resources/ts/model/index.ts | 2 + resources/ts/model/provider.ts | 11 + resources/ts/model/stop.ts | 6 +- resources/ts/store/root.ts | 6 +- resources/ts/urls.ts | 4 +- src/Model/Provider.php | 16 ++ src/Provider/Dummy/DummyProvider.php | 6 + src/Provider/Provider.php | 2 + src/Provider/ZtmGdansk/ZtmGdanskProvider.php | 8 +- src/Service/ProviderConverter.php | 2 + templates/app.html.twig | 267 ++++++++++--------- templates/base.html.twig | 4 +- templates/choose.html.twig | 14 +- 25 files changed, 389 insertions(+), 166 deletions(-) create mode 100644 resources/components/page/providers.html create mode 100644 resources/styles/_map.scss create mode 100644 resources/styles/page/_provider-picker.scss create mode 100644 resources/ts/components/page/index.ts create mode 100644 resources/ts/components/page/providers.ts create mode 100644 resources/ts/model/common.ts create mode 100644 resources/ts/model/provider.ts diff --git a/docker-compose.yml b/docker-compose.yml index 065e519..8e724d0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,6 +17,8 @@ services: - ./:/var/www:cached - ./docker/php/log.conf:/usr/local/etc/php-fpm.d/zz-log.conf + + blackfire: image: blackfire/blackfire ports: ["8707"] diff --git a/resources/components/page/providers.html b/resources/components/page/providers.html new file mode 100644 index 0000000..04fbf90 --- /dev/null +++ b/resources/components/page/providers.html @@ -0,0 +1,42 @@ +<main class="d-flex"> + <div style="width: 100%"> + <l-map :center="{ lat: 52.0194, lon: 19.1451 }" :zoom=7 :options="{ zoomControl: false }" class="map"> + <l-vector-layer url="https://api.maptiler.com/maps/bright/style.json?key=8GX5FRUNgk4lB83GZT8Q" + token="not-needed" + attribution='<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>' + /> + + <div class="provider-picker"> + <h2 class="provider-picker__heading">Wybierz lokaliację</h2> + <ul class="provider-picker__providers"> + <li v-for="provider in providers" :key="provider.id" class="provider-picker__provider"> + <a :href="`/${provider.id}`" class="provider"> + <ui-icon icon="line-bus" size="2x" /> + <div> + <div class="provider__short-name">{{ provider.shortName }}</div> + <div class="provider__name">{{ provider.name }}</div> + </div> + <tooltip v-if="provider.lastUpdate != null">Ostatnia akutalizacja: {{ provider.lastUpdate|moment('YYYY-MM-DD HH:mm') }}</tooltip> + </a> + </li> + </ul> + </div> + + <l-marker :lat-lng="provider.location" v-for="provider in providers" :options="{ keyboard: false }" :key="provider.id"> + <l-icon> + <div class="map__label-box" tabindex="0"> + <a :href="`/${provider.id}`" class="provider"> + <ui-icon icon="line-bus" class="map__icon" /> + <div> + <div class="provider__short-name">{{ provider.shortName }}</div> + <div class="provider__name">{{ provider.name }}</div> + </div> + </a> + </div> + </l-icon> + </l-marker> + </l-map> + </div> + + <portal-target name="popups" multiple/> +</main> diff --git a/resources/styles/_map.scss b/resources/styles/_map.scss new file mode 100644 index 0000000..ab177bf --- /dev/null +++ b/resources/styles/_map.scss @@ -0,0 +1,29 @@ +.map__label-box { + @extend .popper; + + padding: .5rem; + background: white; + transform-origin: 50% 50%; + transform: translateX(-50%); + min-width: max-content; + + font-size: 9pt; + + font-weight: bold; + align-items: center; + + @include active { + transform: translateX(-50%) scale(1.1); + } + + @include flex-with-spacing(.5rem); +} + +.map__icon { + font-size: 1.5rem; +} + +img.map__icon { + width: 24px; + height: 24px; +} diff --git a/resources/styles/main.scss b/resources/styles/main.scss index 8d139d0..dbc1102 100644 --- a/resources/styles/main.scss +++ b/resources/styles/main.scss @@ -61,6 +61,20 @@ $grid-gutter-width: $spacer * 2; } } +@mixin active { + &:hover, &:active, &:focus, #{&}--active { + @content + } +} + +@mixin flex-with-spacing($spacing) { + display: flex; + + & > *:not(:last-child) { + margin-right: $spacing; + } +} + @import "common"; @import "stop"; @import "departure"; @@ -72,9 +86,12 @@ $grid-gutter-width: $spacer * 2; @import "favourites"; @import "trip"; @import "dragscroll"; +@import "map"; @import "ui/switch"; +@import "page/provider-picker"; + body { min-height: 100vh; display: flex; diff --git a/resources/styles/page/_provider-picker.scss b/resources/styles/page/_provider-picker.scss new file mode 100644 index 0000000..75bc5bb --- /dev/null +++ b/resources/styles/page/_provider-picker.scss @@ -0,0 +1,62 @@ +.provider__name { + font-size: .9em; + color: $gray-800; +} + +.provider__short-name { + font-weight: bold; +} + +.provider-picker { + @extend .popper; + padding: 1rem; + margin: 3rem; +} + +.provider-picker__heading { + font-size: 1.2rem; + font-weight: bold; + margin-bottom: 1rem; +} + +.provider-picker__providers { + list-style: none; + padding: 0; + margin: 0; +} + +.provider-picker__provider { + font-size: 1rem; + + .provider { + margin: 0 -1rem; + padding: .5rem 1rem; + + &:hover { + background: $gray-100; + } + } +} + +.provider { + @include flex-with-spacing(.5rem); + align-items: center; + + &:hover { + text-decoration: none; + } +} + +@include media-breakpoint-down('sm') { + .provider-picker { + position: absolute; + bottom: 0; + left: 0; + right: 0; + margin: 1.5rem; + } + + .provider-picker__providers { + max-height: 170px; + } +} diff --git a/resources/ts/app.ts b/resources/ts/app.ts index b92ee01..8ecef2b 100644 --- a/resources/ts/app.ts +++ b/resources/ts/app.ts @@ -14,7 +14,6 @@ import VueDragscroll from 'vue-dragscroll'; import { Plugin as VueFragment } from 'vue-fragment'; import { Workbox } from "workbox-window"; -import { migrate } from "./store/migrations"; import { Component } from "vue-property-decorator"; import * as VueMoment from "vue-moment"; import * as moment from 'moment'; @@ -41,6 +40,8 @@ Component.registerHooks(['removed']); // async dependencies (async function () { + const { migrate } = await import('./store/migrations'); + await migrate("vuex"); const [ components, { default: store } ] = await Promise.all([ @@ -50,17 +51,16 @@ Component.registerHooks(['removed']); import('bootstrap'), ] as const); + const appRoot = document.getElementById('app'); + // here goes "public" API window['app'] = Object.assign({ state: {} }, window['app'], { components, - application: new components.Application({ el: '#app' }) + application: appRoot ? new components.Application({ el: '#app' }) : new components.PageProviderList({ el: '#provider-picker' }), }); - store.dispatch('messages/update'); - store.dispatch('load', window['app'].state); - if ('serviceWorker' in navigator) { const wb = new Workbox("/service-worker.js"); diff --git a/resources/ts/components/app.ts b/resources/ts/components/app.ts index 8949603..24ce486 100644 --- a/resources/ts/components/app.ts +++ b/resources/ts/components/app.ts @@ -1,7 +1,7 @@ import Vue from 'vue' import store from '../store' import { Component, Watch } from "vue-property-decorator"; -import { Mutation, Action } from 'vuex-class' +import { Action, Mutation } from 'vuex-class' import { Stop } from "../model"; import { DeparturesSettingsState } from "../store/settings/departures"; import { MessagesSettingsState } from "../store/settings/messages"; @@ -48,6 +48,9 @@ export class Application extends Vue { } created() { + this.$store.dispatch('messages/update'); + this.$store.dispatch('load', window['app'].state); + this.initDeparturesRefreshInterval(); this.initMessagesRefreshInterval(); } diff --git a/resources/ts/components/index.ts b/resources/ts/components/index.ts index 1e7038d..460380e 100644 --- a/resources/ts/components/index.ts +++ b/resources/ts/components/index.ts @@ -11,5 +11,7 @@ export * from './favourites' export * from './trip' export * from './ui' export * from './settings' +export * from "./page" + export { Departures } from "../store"; export { Messages } from "../store"; diff --git a/resources/ts/components/map.ts b/resources/ts/components/map.ts index 4738985..e78e821 100644 --- a/resources/ts/components/map.ts +++ b/resources/ts/components/map.ts @@ -1,4 +1,4 @@ -import { LMap, LTileLayer, LMarker } from 'vue2-leaflet'; +import { LControl, LIcon, LMap, LMarker, LPopup, LTileLayer } from 'vue2-leaflet'; import Vue from 'vue'; import * as L from 'leaflet' @@ -48,5 +48,8 @@ Vue.component('LMap', LMap); Vue.component('LTileLayer', LTileLayer); Vue.component('LVectorLayer', LVectorLayer); Vue.component('LMarker', LMarker); +Vue.component('LControl', LControl); +Vue.component('LPopup', LPopup) +Vue.component('LIcon', LIcon); -export { LMap, LTileLayer, LMarker } from 'vue2-leaflet'; +export { LMap, LTileLayer, LMarker, LIcon, LControl, LPopup } from 'vue2-leaflet'; diff --git a/resources/ts/components/page/index.ts b/resources/ts/components/page/index.ts new file mode 100644 index 0000000..96bcb99 --- /dev/null +++ b/resources/ts/components/page/index.ts @@ -0,0 +1 @@ +export * from "./providers" diff --git a/resources/ts/components/page/providers.ts b/resources/ts/components/page/providers.ts new file mode 100644 index 0000000..7e257ba --- /dev/null +++ b/resources/ts/components/page/providers.ts @@ -0,0 +1,26 @@ +import Vue from 'vue' +import { Component } from 'vue-property-decorator' +import { Provider } from "../../model"; +import { Jsonified } from "../../utils"; +import * as moment from 'moment'; + +@Component({ + template: require('../../../components/page/providers.html'), +}) +export class PageProviderList extends Vue { + private providers: Provider[] = []; + + async created() { + const response = await fetch('/api/v1/providers'); + const result = await response.json() as Jsonified<Provider>[]; + + this.providers = result.map<Provider>(provider => { + return { + ...provider, + lastUpdate: provider.lastUpdate && moment(provider.lastUpdate) + } + }); + } +} + +Vue.component('PageProviderList', PageProviderList); diff --git a/resources/ts/model/common.ts b/resources/ts/model/common.ts new file mode 100644 index 0000000..6e7fc15 --- /dev/null +++ b/resources/ts/model/common.ts @@ -0,0 +1,4 @@ +export interface Location { + lat: number, + lng: number, +} diff --git a/resources/ts/model/index.ts b/resources/ts/model/index.ts index e4ca6d0..e9aaa2e 100644 --- a/resources/ts/model/index.ts +++ b/resources/ts/model/index.ts @@ -3,3 +3,5 @@ export * from './departure' export * from './line' export * from './error' export * from './identity' +export * from './common' +export * from './provider' diff --git a/resources/ts/model/provider.ts b/resources/ts/model/provider.ts new file mode 100644 index 0000000..e147218 --- /dev/null +++ b/resources/ts/model/provider.ts @@ -0,0 +1,11 @@ +import { Moment } from "moment"; +import { Location } from "./common"; + +export interface Provider { + id: string; + name: string; + shortName: string; + attribution?: string; + lastUpdate?: Moment; + location: Location; +} diff --git a/resources/ts/model/stop.ts b/resources/ts/model/stop.ts index d7bbd13..3cf1aff 100644 --- a/resources/ts/model/stop.ts +++ b/resources/ts/model/stop.ts @@ -1,13 +1,11 @@ import { Line } from "./line"; +import { Location } from "./common"; export interface Stop { id: any; name: string; description?: string; - location?: { - lat: number, - lng: number, - }; + location?: Location; onDemand?: boolean; variant?: string; } diff --git a/resources/ts/store/root.ts b/resources/ts/store/root.ts index 2a108ad..1c0c1ea 100644 --- a/resources/ts/store/root.ts +++ b/resources/ts/store/root.ts @@ -5,6 +5,7 @@ import { ensureArray } from "../utils"; export interface RootState { stops: Stop[], + provider: any, } export interface SavedState { @@ -13,7 +14,8 @@ export interface SavedState { } export const state: RootState = { - stops: [] + stops: [], + provider: null, }; export const mutations: MutationTree<RootState> = { @@ -37,4 +39,4 @@ export const actions: ActionTree<RootState, undefined> = { version: 1, stops: state.stops.map(stop => stop.id) }) -}; \ No newline at end of file +}; diff --git a/resources/ts/urls.ts b/resources/ts/urls.ts index 106a0a1..f371a2c 100644 --- a/resources/ts/urls.ts +++ b/resources/ts/urls.ts @@ -1,3 +1,5 @@ +import store from "./store"; + export type UrlParams = { [name: string]: any } @@ -61,5 +63,5 @@ export default { tracks: `${base}/stops/{id}/tracks` }, trip: `${base}/trips/{id}`, - prepare: (url: string, params: UrlParams = { }) => prepare(url, Object.assign({}, { provider: window['data'].provider }, params)) + prepare: (url: string, params: UrlParams = { }) => prepare(url, Object.assign({}, { provider: store.state.provider }, params)) } diff --git a/src/Model/Provider.php b/src/Model/Provider.php index 854f8ec..0ca7e92 100644 --- a/src/Model/Provider.php +++ b/src/Model/Provider.php @@ -49,6 +49,12 @@ class Provider implements Fillable, Referable */ private $lastUpdate; + /** + * Location of provider centre of interest. + * @var Location + */ + private $location; + public function getId(): string { return $this->id; @@ -98,4 +104,14 @@ class Provider implements Fillable, Referable { $this->lastUpdate = $lastUpdate; } + + public function getLocation(): Location + { + return $this->location; + } + + public function setLocation(Location $location): void + { + $this->location = $location; + } } diff --git a/src/Provider/Dummy/DummyProvider.php b/src/Provider/Dummy/DummyProvider.php index 722c03a..fa22c78 100644 --- a/src/Provider/Dummy/DummyProvider.php +++ b/src/Provider/Dummy/DummyProvider.php @@ -3,6 +3,7 @@ namespace App\Provider\Dummy; use App\Exception\NotSupportedException; +use App\Model\Location; use App\Provider\DepartureRepository; use App\Provider\LineRepository; use App\Provider\MessageRepository; @@ -78,6 +79,11 @@ class DummyProvider implements Provider return null; } + public function getLocation(): Location + { + return new Location(21.4474, 54.7837); + } + public function getTripRepository(): TripRepository { throw new NotSupportedException(); diff --git a/src/Provider/Provider.php b/src/Provider/Provider.php index d270290..482953a 100644 --- a/src/Provider/Provider.php +++ b/src/Provider/Provider.php @@ -2,6 +2,7 @@ namespace App\Provider; +use App\Model\Location; use Carbon\Carbon; interface Provider @@ -17,6 +18,7 @@ interface Provider public function getShortName(): string; public function getIdentifier(): string; public function getAttribution(): ?string; + public function getLocation(): Location; public function getLastUpdate(): ?Carbon; } diff --git a/src/Provider/ZtmGdansk/ZtmGdanskProvider.php b/src/Provider/ZtmGdansk/ZtmGdanskProvider.php index 26b2cbb..0428860 100644 --- a/src/Provider/ZtmGdansk/ZtmGdanskProvider.php +++ b/src/Provider/ZtmGdansk/ZtmGdanskProvider.php @@ -4,6 +4,7 @@ namespace App\Provider\ZtmGdansk; use App\Entity\ProviderEntity; +use App\Model\Location; use App\Provider\Database\GenericLineRepository; use App\Provider\Database\GenericScheduleRepository; use App\Provider\Database\GenericStopRepository; @@ -13,11 +14,9 @@ use App\Provider\DepartureRepository; use App\Provider\LineRepository; use App\Provider\MessageRepository; use App\Provider\Provider; -use App\Provider\ScheduleRepository; use App\Provider\StopRepository; use App\Provider\TrackRepository; use App\Provider\TripRepository; -use App\Provider\ZtmGdansk\{ZtmGdanskDepartureRepository, ZtmGdanskMessageRepository}; use App\Service\Proxy\ReferenceFactory; use Carbon\Carbon; use Doctrine\ORM\EntityManagerInterface; @@ -54,6 +53,11 @@ class ZtmGdanskProvider implements Provider return '<a href="http://ztm.gda.pl/otwarty_ztm">Otwarte Dane</a> Zarządu Transportu Miejskiego w Gdańsku'; } + public function getLocation(): Location + { + return new Location(18.6466, 54.3520); + } + public function __construct( EntityManagerInterface $em, GenericLineRepository $lines, diff --git a/src/Service/ProviderConverter.php b/src/Service/ProviderConverter.php index f644553..1cc7c7f 100644 --- a/src/Service/ProviderConverter.php +++ b/src/Service/ProviderConverter.php @@ -17,6 +17,7 @@ class ProviderConverter implements Converter 'name' => $entity->getName(), 'attribution' => $entity->getAttribution(), 'lastUpdate' => $entity->getLastUpdate() ? clone $entity->getLastUpdate() : null, + 'location' => $entity->getLocation(), ]); } @@ -25,3 +26,4 @@ class ProviderConverter implements Converter return $entity instanceof Provider; } } + diff --git a/templates/app.html.twig b/templates/app.html.twig index 467ab65..af27f36 100644 --- a/templates/app.html.twig +++ b/templates/app.html.twig @@ -3,146 +3,147 @@ {% block manifest path('webapp_manifest', { provider: provider.identifier }) %} {% block body %} - <div class="row"> - <div class="col-md-8 order-md-last"> - <section class="section messages" v-show="messages.count > 0"> - <header class="section__title flex"> - <h2> - <ui-icon icon="messages" fixed-width class="mr-2"></ui-icon> - Komunikaty <span class="ml-2 badge badge-pill badge-dark">{{ '{{ messages.count }}' }}</span> - </h2> - <button class="btn btn-action flex-space-left" ref="settings-messages" @click="visibility.messages = !visibility.messages"> - <tooltip>ustawienia</tooltip> - <ui-icon icon="settings" fixed-width></ui-icon> - </button> - <button class="btn btn-action" @click="updateMessages" ref="btn-messages-refresh"> - <tooltip>odśwież</tooltip> - <ui-icon icon="refresh" :spin="messages.state === 'fetching'" fixed-width></ui-icon> - </button> - <button class="btn btn-action" @click="sections.messages = !sections.messages"> - <tooltip> - {{ '{{ ' }} sections.messages ? 'zwiń' : 'rozwiń' {{ '}}' }} - <span class="sr-only">sekcję komunikatów</span> - </tooltip> - <ui-icon :icon="sections.messages ? 'chevron-up' : 'chevron-down'" fixed-width></ui-icon> - </button> + <main id="app" class="container not-ready"> + <div class="row"> + <div class="col-md-8 order-md-last"> + <section class="section messages" v-show="messages.count > 0"> + <header class="section__title flex"> + <h2> + <ui-icon icon="messages" fixed-width class="mr-2"></ui-icon> + Komunikaty <span class="ml-2 badge badge-pill badge-dark">{{ '{{ messages.count }}' }}</span> + </h2> + <button class="btn btn-action flex-space-left" ref="settings-messages" @click="visibility.messages = !visibility.messages"> + <tooltip>ustawienia</tooltip> + <ui-icon icon="settings" fixed-width></ui-icon> + </button> + <button class="btn btn-action" @click="updateMessages" ref="btn-messages-refresh"> + <tooltip>odśwież</tooltip> + <ui-icon icon="refresh" :spin="messages.state === 'fetching'" fixed-width></ui-icon> + </button> + <button class="btn btn-action" @click="sections.messages = !sections.messages"> + <tooltip> + {{ '{{ ' }} sections.messages ? 'zwiń' : 'rozwiń' {{ '}}' }} + <span class="sr-only">sekcję komunikatów</span> + </tooltip> + <ui-icon :icon="sections.messages ? 'chevron-up' : 'chevron-down'" fixed-width></ui-icon> + </button> - <portal to="popups"> - <popper reference="settings-messages" v-if="visibility.messages" arrow placement="left-start" @leave="visibility.messages = false"> - <settings-messages></settings-messages> - </popper> - </portal> - </header> - <fold :visible="sections.messages"> - <messages></messages> - </fold> - </section> + <portal to="popups"> + <popper reference="settings-messages" v-if="visibility.messages" arrow placement="left-start" @leave="visibility.messages = false"> + <settings-messages></settings-messages> + </popper> + </portal> + </header> + <fold :visible="sections.messages"> + <messages></messages> + </fold> + </section> + <section class="section"> + <header class="section__title flex"> + <h2> + <ui-icon icon="timetable" fixed-width></ui-icon> + <span class="text">Odjazdy</span> + </h2> - <section class="section"> - <header class="section__title flex"> - <h2> - <ui-icon icon="timetable" fixed-width></ui-icon> - <span class="text">Odjazdy</span> - </h2> - - <button class="btn btn-action flex-space-left" ref="settings-departures" @click="visibility.departures = !visibility.departures"> - <tooltip>ustawienia</tooltip> - <ui-icon icon="settings" fixed-width></ui-icon> - </button> - <button class="btn btn-action" @click="updateDepartures({ stops })"> - <tooltip>odśwież</tooltip> - <ui-icon icon="refresh" :spin="departures.state === 'fetching'" fixed-width></ui-icon> - </button> - <portal to="popups"> - <popper reference="settings-departures" v-if="visibility.departures" arrow placement="left-start" @leave="visibility.departures = false"> - <settings-departures></settings-departures> - </popper> - </portal> - </header> - <departures :stops="stops" v-if="stops.length > 0"></departures> - <div class="alert alert-info" v-else> - <ui-icon icon="info"></ui-icon> - Wybierz przystanki korzystając z wyszukiwarki poniżej, aby zobaczyć listę odjazdów. - </div> - {% if provider.attribution %} - <div class="attribution"> + <button class="btn btn-action flex-space-left" ref="settings-departures" @click="visibility.departures = !visibility.departures"> + <tooltip>ustawienia</tooltip> + <ui-icon icon="settings" fixed-width></ui-icon> + </button> + <button class="btn btn-action" @click="updateDepartures({ stops })"> + <tooltip>odśwież</tooltip> + <ui-icon icon="refresh" :spin="departures.state === 'fetching'" fixed-width></ui-icon> + </button> + <portal to="popups"> + <popper reference="settings-departures" v-if="visibility.departures" arrow placement="left-start" @leave="visibility.departures = false"> + <settings-departures></settings-departures> + </popper> + </portal> + </header> + <departures :stops="stops" v-if="stops.length > 0"></departures> + <div class="alert alert-info" v-else> <ui-icon icon="info"></ui-icon> - Pochodzenie danych: {{ provider.attribution|raw }} + Wybierz przystanki korzystając z wyszukiwarki poniżej, aby zobaczyć listę odjazdów. </div> - {% endif %} - </section> - </div> - <div class="col-md-4 order-md-first"> - <section class="section picker" v-if="stops.length > 0"> - <header class="section__title flex"> - <h2> - <ui-icon icon="stop" fixed-width></ui-icon> - <span class="text">Przystanki</span> - </h2> - <button class="btn btn-action flex-space-left" @click="clear"> - <tooltip>usuń wszystkie</tooltip> - <ui-icon icon="delete" fixed-width></ui-icon> - </button> - </header> - - <ul class="picker__stops list-underlined"> - <li v-for="stop in stops" :key="stop.id" class="d-flex align-items-center"> - <picker-stop :stop="stop" class="flex-grow-1"> - <template v-slot:primary-action> - <button @click="remove(stop)" class="btn btn-action"> - <tooltip>usuń przystanek</tooltip> - <ui-icon icon="remove-stop"></ui-icon> - </button> - </template> - </picker-stop> - </li> - </ul> - - <div class="d-flex mt-2"> - <button class="btn btn-action btn-sm flex-space-left" @click="visibility.save = true" ref="save"> - <ui-icon icon="favourite" fixed-width></ui-icon> - zapisz jako... - </button> - </div> - - <popper reference="save" v-if="visibility.save" arrow tabindex="-1" @leave="visibility.save = false" placement="bottom-end"> - <favourites-adder @saved="visibility.save = false"/> - </popper> - </section> - <section class="section picker"> - <header class="section__title flex"> - <template v-if="visibility.picker === 'search'"> - <h2 class="flex-grow-1"> - <ui-icon icon="search" fixed-width class="mr-1"></ui-icon> - Wybierz przystanki + {% if provider.attribution %} + <div class="attribution"> + <ui-icon icon="info"></ui-icon> + Pochodzenie danych: {{ provider.attribution|raw }} + </div> + {% endif %} + </section> + </div> + <div class="col-md-4 order-md-first"> + <section class="section picker" v-if="stops.length > 0"> + <header class="section__title flex"> + <h2> + <ui-icon icon="stop" fixed-width></ui-icon> + <span class="text">Przystanki</span> </h2> - <button class="btn btn-action" @click="visibility.picker = 'favourites'"> - <tooltip>Zapisane</tooltip> - <ui-icon icon="favourite" fixed-witdth></ui-icon> + <button class="btn btn-action flex-space-left" @click="clear"> + <tooltip>usuń wszystkie</tooltip> + <ui-icon icon="delete" fixed-width></ui-icon> </button> - </template> - <template v-else> - <h2 class="flex-grow-1"> - <ui-icon icon="favourite" fixed-width class="mr-1"></ui-icon> - Zapisane - </h2> - <button class="btn btn-action" @click="visibility.picker = 'search'"> - <tooltip>Wybierz przystanki</tooltip> - <ui-icon icon="search" fixed-witdth></ui-icon> - </button> - </template> - </header> - <div class="transition-box"> - <transition name="fade"> - <stop-finder @select="add" :blacklist="stops" v-if="visibility.picker === 'search'"></stop-finder> - <favourites v-else-if="visibility.picker === 'favourites'"></favourites> - </transition> - </div> - </section> - </div> - </div> + </header> - <portal-target name="popups" multiple></portal-target> + <ul class="picker__stops list-underlined"> + <li v-for="stop in stops" :key="stop.id" class="d-flex align-items-center"> + <picker-stop :stop="stop" class="flex-grow-1"> + <template v-slot:primary-action> + <button @click="remove(stop)" class="btn btn-action"> + <tooltip>usuń przystanek</tooltip> + <ui-icon icon="remove-stop"></ui-icon> + </button> + </template> + </picker-stop> + </li> + </ul> + + <div class="d-flex mt-2"> + <button class="btn btn-action btn-sm flex-space-left" @click="visibility.save = true" ref="save"> + <ui-icon icon="favourite" fixed-width></ui-icon> + zapisz jako... + </button> + </div> + + <popper reference="save" v-if="visibility.save" arrow tabindex="-1" @leave="visibility.save = false" placement="bottom-end"> + <favourites-adder @saved="visibility.save = false"/> + </popper> + </section> + <section class="section picker"> + <header class="section__title flex"> + <template v-if="visibility.picker === 'search'"> + <h2 class="flex-grow-1"> + <ui-icon icon="search" fixed-width class="mr-1"></ui-icon> + Wybierz przystanki + </h2> + <button class="btn btn-action" @click="visibility.picker = 'favourites'"> + <tooltip>Zapisane</tooltip> + <ui-icon icon="favourite" fixed-witdth></ui-icon> + </button> + </template> + <template v-else> + <h2 class="flex-grow-1"> + <ui-icon icon="favourite" fixed-width class="mr-1"></ui-icon> + Zapisane + </h2> + <button class="btn btn-action" @click="visibility.picker = 'search'"> + <tooltip>Wybierz przystanki</tooltip> + <ui-icon icon="search" fixed-witdth></ui-icon> + </button> + </template> + </header> + <div class="transition-box"> + <transition name="fade"> + <stop-finder @select="add" :blacklist="stops" v-if="visibility.picker === 'search'"></stop-finder> + <favourites v-else-if="visibility.picker === 'favourites'"></favourites> + </transition> + </div> + </section> + </div> + </div> + + <portal-target name="popups" multiple></portal-target> + </main> {% endblock %} {% block javascripts %} diff --git a/templates/base.html.twig b/templates/base.html.twig index 39b5778..39e540e 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -33,9 +33,7 @@ {% endif %} </head> <body> - <main role="main" class="container not-ready" id="app"> - {% block body %}{% endblock %} - </main> + {% block body '' %} <footer class="container"> {% block footer %} <span> diff --git a/templates/choose.html.twig b/templates/choose.html.twig index 397e154..086ade5 100644 --- a/templates/choose.html.twig +++ b/templates/choose.html.twig @@ -1,17 +1,5 @@ {% extends 'base.html.twig' %} {% block body %} - <div class="alert alert-primary"> - <ui-icon icon="info-circle"></ui-icon> - Wybierz źródło danych - </div> - <ul class="list-underlined"> - {% for provider in providers %} - <li title="Aktualizacja: {{ provider.lastUpdate ? provider.lastUpdate.format('Y.m.d H:i') : 'live' }}"> - <a href="{{ path('app', { provider: provider.identifier }) }}" class="btn btn-block btn-action text-left"> - {{ provider.name }} - </a> - </li> - {% endfor %} - </ul> + <main class="d-flex" id="provider-picker"></main> {% endblock %} -- 2.45.2 From af6a2a0756ac85fa082b254f333743405dc14dbb Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sat, 2 May 2020 23:39:27 +0200 Subject: [PATCH 34/77] #40 - Fix typo in provider picker header --- resources/components/page/providers.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/components/page/providers.html b/resources/components/page/providers.html index 04fbf90..d6fb7ec 100644 --- a/resources/components/page/providers.html +++ b/resources/components/page/providers.html @@ -7,7 +7,7 @@ /> <div class="provider-picker"> - <h2 class="provider-picker__heading">Wybierz lokaliację</h2> + <h2 class="provider-picker__heading">Wybierz lokalizację</h2> <ul class="provider-picker__providers"> <li v-for="provider in providers" :key="provider.id" class="provider-picker__provider"> <a :href="`/${provider.id}`" class="provider"> -- 2.45.2 From 0c5ffbb567b15cd56affd229cc8d82630a81ac82 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sat, 2 May 2020 23:51:50 +0200 Subject: [PATCH 35/77] #40 - Fix passing provider to Vue --- resources/ts/app.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/resources/ts/app.ts b/resources/ts/app.ts index 8ecef2b..71804a7 100644 --- a/resources/ts/app.ts +++ b/resources/ts/app.ts @@ -53,6 +53,11 @@ Component.registerHooks(['removed']); const appRoot = document.getElementById('app'); + store.replaceState({ + ...store.state, + provider: window['data']?.provider, + }); + // here goes "public" API window['app'] = Object.assign({ state: {} -- 2.45.2 From 7b7b59ce23fd4305fb26ee08889f751050f407a3 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 3 May 2020 00:03:54 +0200 Subject: [PATCH 36/77] #40 - (Hot) Fix Aggregate Converter loop --- src/Service/AggregateConverter.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Service/AggregateConverter.php b/src/Service/AggregateConverter.php index f9e6dff..1b22c84 100644 --- a/src/Service/AggregateConverter.php +++ b/src/Service/AggregateConverter.php @@ -47,8 +47,10 @@ class AggregateConverter implements Converter, CacheableConverter public function flushCache() { + $this->ensureCachedConverters(); + $this - ->converters + ->cachedConverters ->filter(instance(CacheableConverter::class)) ->each(function (CacheableConverter $converter) { $converter->flushCache(); @@ -70,7 +72,7 @@ class AggregateConverter implements Converter, CacheableConverter if (!$this->cachedConverters) { $this->cachedConverters = collect($this->converters) ->filter(function (Converter $converter) { - return $converter !== $this; + return $converter !== $this && !$converter instanceof AggregateConverter; }) ->each(function (Converter $converter) { if ($converter instanceof RecursiveConverter) { -- 2.45.2 From 4e86e127d84202ecc4b7686901dca392347b4e3d Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Fri, 18 Sep 2020 21:57:38 +0200 Subject: [PATCH 37/77] Add support for maskable and monochrome icons --- resources/images/icon-maskable.png | Bin 0 -> 28686 bytes resources/images/icon-monochrome.png | Bin 0 -> 12772 bytes templates/manifest.json.twig | 10 +++++++++- 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 resources/images/icon-maskable.png create mode 100644 resources/images/icon-monochrome.png diff --git a/resources/images/icon-maskable.png b/resources/images/icon-maskable.png new file mode 100644 index 0000000000000000000000000000000000000000..959df9d0a3d5577d455b4be77dab9f9735473137 GIT binary patch literal 28686 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 bA0m1?#Qh6>cry@a4Ca8r;l25KColgW4(o&a literal 0 HcmV?d00001 diff --git a/resources/images/icon-monochrome.png b/resources/images/icon-monochrome.png new file mode 100644 index 0000000000000000000000000000000000000000..c6f580f6117ab9dcb7663b84316c4306c707e50f GIT binary patch literal 12772 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 literal 0 HcmV?d00001 diff --git a/templates/manifest.json.twig b/templates/manifest.json.twig index 0fa40c9..4984474 100644 --- a/templates/manifest.json.twig +++ b/templates/manifest.json.twig @@ -6,7 +6,7 @@ "start_url": "{{ path('app', { provider: provider.identifier }) }}", "display": "standalone", "background_color": "white", - "theme_color": "#005ea8", + "theme_color": "white", "description": "Odpowiedź na odwieczne pytanie ludzkości - czy tramwaje jeżdżą?", "icons": [{ "src": "{{ asset('images/icon-256.png') }}", @@ -26,5 +26,13 @@ },{ "src": "{{ asset('images/icon-96.png') }}", "sizes": "96x96" + },{ + "src": "{{ asset('images/icon-maskable.png') }}", + "sizes": "512x512", + "purpose": "any maskable" + },{ + "src": "{{ asset('images/icon-monochrome.png') }}", + "sizes": "512x512", + "purpose": "monochrome" }] } -- 2.45.2 From bb81077d1c6615ae11366bbd8d11c35beb7e050b Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Fri, 18 Sep 2020 21:58:29 +0200 Subject: [PATCH 38/77] Add basic noscript warning --- templates/base.html.twig | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/templates/base.html.twig b/templates/base.html.twig index 39e540e..2143d4e 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -15,9 +15,12 @@ <link rel="apple-touch-icon" href="images/ios.png" sizes="512x512"> <link rel="apple-touch-icon" href="images/ios-80.png" sizes="80x80"> <link rel="apple-touch-icon" href="images/ios-192.png" sizes="192x192"> + <meta name="apple-mobile-web-app-title" content="Co Jedzie?"> <meta name="apple-mobile-web-app-capable" content="yes"> + <meta name="theme-color" content="white"/> + <title>{% block title %}Co Jedzie?{% endblock %}</title> {% if ga_tracking %} @@ -33,6 +36,13 @@ {% endif %} </head> <body> + <noscript> + <div class="container"> + <div class="alert alert-danger"> + Aplikacja wymaga do działania obsługi JavaScriptu. + </div> + </div> + </noscript> {% block body '' %} <footer class="container"> {% block footer %} -- 2.45.2 From 3abfa6dac3f5da3dee163f0b3a1870ae3bb11810 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Fri, 18 Sep 2020 22:16:29 +0200 Subject: [PATCH 39/77] Provide better maskable icon --- resources/images/icon-maskable.png | Bin 28686 -> 28040 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/resources/images/icon-maskable.png b/resources/images/icon-maskable.png index 959df9d0a3d5577d455b4be77dab9f9735473137..3c422167625c2f8f27fc79dd8885305e43f41eb5 100644 GIT binary patch literal 28040 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 literal 28686 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 bA0m1?#Qh6>cry@a4Ca8r;l25KColgW4(o&a -- 2.45.2 From ec479e5d77ee726e884ef43b8ccbab6b7bae6f40 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Fri, 18 Sep 2020 22:47:22 +0200 Subject: [PATCH 40/77] Unify provider and main webapp manifest (manifest.json) --- public/manifest.json | 30 --------------------------- src/Controller/MainController.php | 34 ++++++++++++++++++------------- src/Service/ProviderResolver.php | 23 ++++++++++++--------- templates/app.html.twig | 2 +- templates/manifest.json.twig | 7 ++++--- 5 files changed, 38 insertions(+), 58 deletions(-) delete mode 100644 public/manifest.json diff --git a/public/manifest.json b/public/manifest.json deleted file mode 100644 index 00ff1f9..0000000 --- a/public/manifest.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "Co Jedzie?", - "short_name": "Co Jedzie?", - "orientation": "portrait", - "lang": "pl_PL", - "start_url": ".", - "display": "standalone", - "background_color": "#005ea8", - "theme_color": "#005ea8", - "description": "Odpowiedź na odwieczne pytanie ludzkości - czy tramwaje jeżdżą?", - "icons": [{ - "src": "images/icon-256.png", - "sizes": "256x256" - },{ - "src": "images/icon-512.png", - "sizes": "512x512" - },{ - "src": "images/icon-64.png", - "sizes": "64x64" - },{ - "src": "images/icon-128.png", - "sizes": "128x128" - },{ - "src": "images/icon-192.png", - "sizes": "192x192" - },{ - "src": "images/icon-96.png", - "sizes": "96x96" - }] -} diff --git a/src/Controller/MainController.php b/src/Controller/MainController.php index 0987eb6..bfe8d15 100644 --- a/src/Controller/MainController.php +++ b/src/Controller/MainController.php @@ -2,7 +2,6 @@ namespace App\Controller; - use App\Provider\Provider; use App\Service\ProviderResolver; use Symfony\Component\HttpFoundation\Request; @@ -18,25 +17,32 @@ class MainController extends Controller return $this->render('choose.html.twig', ['providers' => $resolver->all()]); } + /** + * @Route("/{provider}/manifest.json", name="provider_manifest") + * @Route("/manifest.json", name="main_manifest") + */ + public function manifest(?Provider $provider = null) + { + $response = $this->render('manifest.json.twig', ['provider' => $provider]); + $response->headers->set('Content-Type', 'application/json'); + + return $response; + } + /** * @Route("/{provider}", name="app") */ public function app(Provider $provider, Request $request) { $state = json_decode($request->query->get('state', '{}'), true) ?: []; - $state = array_merge([ - 'version' => 1, - 'stops' => [], - ], $state); + $state = array_merge( + [ + 'version' => 1, + 'stops' => [], + ], + $state + ); return $this->render('app.html.twig', compact('state', 'provider')); } - - /** - * @Route("/{provider}/manifest.json", name="webapp_manifest") - */ - public function manifest(Provider $provider) - { - return $this->render('manifest.json.twig', ['provider' => $provider]); - } -} \ No newline at end of file +} diff --git a/src/Service/ProviderResolver.php b/src/Service/ProviderResolver.php index 85e2758..29a0193 100644 --- a/src/Service/ProviderResolver.php +++ b/src/Service/ProviderResolver.php @@ -6,8 +6,8 @@ namespace App\Service; use App\Exception\NonExistentServiceException; use App\Provider\Dummy\DummyProvider; use App\Provider\Provider; -use Kadet\Functional\Transforms as t; use Kadet\Functional\Predicates as p; +use Kadet\Functional\Transforms as t; use Tightenco\Collect\Support\Collection; class ProviderResolver @@ -23,16 +23,19 @@ class ProviderResolver } } - /**\ - * @param string $name - * - * @return \App\Provider\Provider - * @throws \App\Exception\NonExistentServiceException - */ - public function resolve(string $name): Provider + public function resolve(?string $name): ?Provider { + if (empty($name)) { + return null; + } + if (!$this->providers->has($name)) { - $message = sprintf("Provider '%s' doesn't exist, you can choose from: %s", $name, $this->providers->keys()->implode(', ')); + $message = sprintf( + "Provider '%s' doesn't exist, you can choose from: %s", + $name, + $this->providers->keys()->implode(', ') + ); + throw new NonExistentServiceException($message); } @@ -44,4 +47,4 @@ class ProviderResolver { return clone $this->providers; } -} \ No newline at end of file +} diff --git a/templates/app.html.twig b/templates/app.html.twig index af27f36..a8143e6 100644 --- a/templates/app.html.twig +++ b/templates/app.html.twig @@ -1,6 +1,6 @@ {% extends 'base.html.twig' %} {% block title "#{parent()} - #{provider.name}" %} -{% block manifest path('webapp_manifest', { provider: provider.identifier }) %} +{% block manifest path('provider_manifest', { provider: provider.identifier }) %} {% block body %} <main id="app" class="container not-ready"> diff --git a/templates/manifest.json.twig b/templates/manifest.json.twig index 4984474..24de7ff 100644 --- a/templates/manifest.json.twig +++ b/templates/manifest.json.twig @@ -1,13 +1,14 @@ { - "name": "Co Jedzie? - {{ provider.shortName }}", - "short_name": "Co Jedzie? - {{ provider.shortName }}", + "name": "Co Jedzie?{% if provider %} - {{ provider.shortName }}{% endif %}", + "short_name": "Co Jedzie?{% if provider %} - {{ provider.shortName }}{% endif %}", "orientation": "portrait", "lang": "pl_PL", - "start_url": "{{ path('app', { provider: provider.identifier }) }}", + "start_url": "{{ provider ? path('app', { provider: provider.identifier }) : path('choose') }}", "display": "standalone", "background_color": "white", "theme_color": "white", "description": "Odpowiedź na odwieczne pytanie ludzkości - czy tramwaje jeżdżą?", + "categories": ["navigation", "transport", "travel", "utilities"], "icons": [{ "src": "{{ asset('images/icon-256.png') }}", "sizes": "256x256" -- 2.45.2 From c541cf1a11ef654dadb096a26e77f77e1dccf444 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sat, 19 Sep 2020 19:26:18 +0200 Subject: [PATCH 41/77] #57 - Replace google analytics with google tag manager --- .env.dist | 2 +- config/packages/twig.yaml | 2 +- docker/nginx/czydojade | 2 +- resources/styles/main.scss | 4 ++++ templates/base.html.twig | 24 ++++++++++++++---------- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/.env.dist b/.env.dist index 3bab831..2edbb91 100644 --- a/.env.dist +++ b/.env.dist @@ -2,7 +2,7 @@ # Copy this file to .env file for development, create environment variables when deploying to production # https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration -GOOGLE_ANALYTICS= +GTM_TAG= ###> symfony/framework-bundle ### APP_ENV=dev diff --git a/config/packages/twig.yaml b/config/packages/twig.yaml index 95f2509..da841eb 100644 --- a/config/packages/twig.yaml +++ b/config/packages/twig.yaml @@ -3,4 +3,4 @@ twig: debug: '%kernel.debug%' strict_variables: '%kernel.debug%' globals: - ga_tracking: "%env(GOOGLE_ANALYTICS)%" + gtm_tracking: "%env(GTM_TAG)%" diff --git a/docker/nginx/czydojade b/docker/nginx/czydojade index 0a33eed..dbd1fe7 100644 --- a/docker/nginx/czydojade +++ b/docker/nginx/czydojade @@ -21,7 +21,7 @@ server { fastcgi_param APP_ENV "dev"; fastcgi_param DATABASE_URL "sqlite:///%kernel.project_dir%/var/app.db"; - fastcgi_param GOOGLE_ANALYTICS "UA-00000-00"; + fastcgi_param GTM_TAG "GTM-00000"; internal; } diff --git a/resources/styles/main.scss b/resources/styles/main.scss index dbc1102..c0ebdd6 100644 --- a/resources/styles/main.scss +++ b/resources/styles/main.scss @@ -92,6 +92,10 @@ $grid-gutter-width: $spacer * 2; @import "page/provider-picker"; +html, body { + overscroll-behavior-y: contain; +} + body { min-height: 100vh; display: flex; diff --git a/templates/base.html.twig b/templates/base.html.twig index 2143d4e..20775bb 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -23,20 +23,24 @@ <title>{% block title %}Co Jedzie?{% endblock %}</title> - {% if ga_tracking %} - <!-- Global site tag (gtag.js) - Google Analytics --> - <script async src="https://www.googletagmanager.com/gtag/js?id={{ ga_tracking }}"></script> - <script> - window.dataLayer = window.dataLayer || []; - function gtag(){dataLayer.push(arguments);} - - gtag('js', new Date()); - gtag('config', '{{ ga_tracking }}'); - </script> + {% if gtm_tracking %} + <!-- Google Tag Manager --> + <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': + new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], + j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= + 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); + })(window,document,'script','dataLayer','{{ gtm_tracking }}');</script> + <!-- End Google Tag Manager --> {% endif %} </head> <body> <noscript> + {% if gtm_tracking %} + <!-- Google Tag Manager (noscript) --> + <iframe src="https://www.googletagmanager.com/ns.html?id={{ gtm_tracking }}" + height="0" width="0" style="display:none;visibility:hidden"></iframe> + <!-- End Google Tag Manager (noscript) --> + {% endif %} <div class="container"> <div class="alert alert-danger"> Aplikacja wymaga do działania obsługi JavaScriptu. -- 2.45.2 From dcd3962220810052ba2ce3e0851256cd1a8d87f1 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Thu, 24 Sep 2020 19:30:14 +0200 Subject: [PATCH 42/77] #62 - Add background --- resources/images/background-2x.png | Bin 0 -> 45931 bytes resources/images/background.png | Bin 0 -> 19852 bytes resources/styles/_common.scss | 7 +++++++ resources/styles/main.scss | 2 ++ webpack.config.js | 2 +- 5 files changed, 10 insertions(+), 1 deletion(-) create mode 100755 resources/images/background-2x.png create mode 100755 resources/images/background.png diff --git a/resources/images/background-2x.png b/resources/images/background-2x.png new file mode 100755 index 0000000000000000000000000000000000000000..0797290a2776d5b3e37c7a7dee19e7d38d047170 GIT binary patch literal 45931 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 VZySkQ_`u+>mWG~s?%7-Z{{!Pvqf-C? literal 0 HcmV?d00001 diff --git a/resources/images/background.png b/resources/images/background.png new file mode 100755 index 0000000000000000000000000000000000000000..542bd95582cb36b83bcecb14f9d4a3f66fcd3258 GIT binary patch literal 19852 zcmY(r1z42L8#nq80xFFH(t-jiUDBZf2CX1SD&0tT2(JiBh@`ZjfD%i0igYZ9u)tE% zwKTiH5@+^(|K~gBd#=k1WapWgd*+@ye)n%SLQ6xH;tJCh2!be{Jbt7DL8N35L_kkQ z0{-Hf)&3Ivxa{)Szzu?~(&GOS{GJXxg&+>-$s?r~-UR6B2+zr<w9t@5A(n6dBI~H! z+dQt-?dedMq)F)j=NG>fp`Lb1j;dRKjEzTmV!?AcxHF;;>mc!L$svht#f{?VS5MEA zQ`1B1m9O#A8S#JC-02ZSU{t6w1-hw7lxS%nXY_LxeudGq;k%pbr~2uV;G6i5holL^ zAPQ0bNU?i;>kn033XvO^-Q~ENXO{Pm=Mkq^YY~1;>5M-cp6G}8=Go%JWCTnWa+2fQ z*upuEZ8}SXmHjTUv<t)3D(1E^jr=S0)yA9owaSvej2{^Gwk>mbvc%%53tIi=^-00| zHg^af1i%0ADMwlR1-qV$i;T&uE@A8I)sF04=e&IesRQfU%@UJeTKYfAalh^Fs562E z7+t#T_Z=CpbQM2aZv1Silh=DJbk6Qb)-snl!^+k6Etid?=b=$I&Ui=ZjPnUhe7qe_ zh9{#bFsAFkS!%p{ljQ*CcgE7NSNX{0>z?k!C)<{`y6$Xs-S?|m=5m;~{`7d+VzTfn zwYb?v#+#m*X;;qbD*!7QLF=`}n-7$}qEhUVP@z5<QW|C{9cZgGfoGkZS&??aa?~vA zx(Q>@-ye?6_)3@)Uk(oqQF{Qo3#J!RXUQg5?o-rFAhf8VCnz^zq72tve)XZ~Cs}r4 zpV??xgrX58r5?&SG^*!_k0t>vC`!szI<_dK4r|@dqHTK{HF}ep!I9OGE$eo<1dL0r zlK}L4l!l*XfASK&4C`k(+$W+Jx;tM-3@j?ID>Dg-qGOb+C>KO{|G-}-StN|0`G}I# zDNU9TGvEJCCP~?g@rVA6e1?~nMd7vz0aNysrvodtLX4Gf<Qk<TH`~hjE@@^Hj3K=? zJKH_zK(jeP5i)|Kg!Jj!t-6)pGJ)8Ni}R+IhKTNyNXXHGj_{B^<TT|4%|zMAnpkw# zf*60QaUOm(&C>X+F13a)^>^~NPZ*F4a*{D@9Cn-pgj!Dgq$WBLmJIUrto9WU*~@XT zhS%uF^TUGJZz$&H=NGO-<`j*&z;r&;Ju(l3lTBt&h6l}Tux4$@%~!n-Rl08TK_|-A zAgRLXHrE&Qyg$5mWpJgi{5uU_R7=<Kdio_W_@o9CF~p9k?e9(-IJa0{YC&WcF<_0B zHR{OA2bL>>0x<{J{q4n|igS}#O%bBm{koZZgvm6wHU)^tY3BHt8ztCSatF(cY}80T zM36|~u=+?^e81j;1P>slZ?6oCNJw;-=Q!zv2`S@r$^JYizRJ}nDH6EAL>o`WJ@TCc zf3${Pt=}UUBBS{T<1n(=9#u|Ij`p@BCM&EOOv<7w$miu}n)s(o;58*}r}#GkIx1*R zH0KuvjW)h(y$yGwiMK6*m*_1W6F`!ITc?ms*kHT|$p$AO<(Z{c=@r`ETVbzY_C01d zu0?Ttaib45-yNPa`_a3L_&tCwHYb3xl`W_VTX_!0#<&umkR2w6hQ;^X8nCXgV;%Nq zBT{_6G-uX=)I=g*GCOy`XIl!PzYdt~`Z=H$f;YmT(n}(jzZh^nPC?Q{LthTb2qfwE zyN(;Gzq-A#A%n7`)e=d}1b?^&s>(xx@zkle$7nJJ=-b-L({(Q>Aoc4TWXo!;7lEhV zSiOV#W>NxZ@|Tz}gqc4$5Tj5idv9iO6s3~8j)-0LWH9xaW=*C6Qyln2gsY$`nIMKd z-UfK+Ub?Kn`7ZS3%j8K~Ad4Cmk(qPO*ICuXK5^}NL~PM@`t1OqKgsHe;7ytpdjVml z8w~8M`j>(q!f?}Y)8-=i4u5&gni{Xds>|&i$39h*+aoLC?QQv6qXdu*n^zE2N(5w- zlJ3i%b2x7nPlK`tIp?rTeID1Z^>4AW{g^YexGEoTj@@QPUxtP_f!ProGyj22eg7_O zh<w_z^OsRDbuibpZ|5xmXZ5|*QT=VEEkXJ58Y@{VL8qsmffBR>Yk3J+OPiv2_q~!> zlWR*eM9{l1tsoz>18w}vqXr~Ih~(SY+)B*!v~hhyLlEXTEzK~T5NeI9Ah`(@Q`<)+ zTE<yb#M{vy%F7wYyX+mMNb@YODzZj*nWG=rE7wg2!jm;LX6_S^+QjI``$@9o&ECI1 z`l~L7??+J^3<kTabu_i#-llk!2x7SjbQi-(=)T|8C8lpRf<`TrGp#Kwyzc!}LV9_n z!XPz&LP?%<r~aWaS2pDv+GoTh8sQJo1gd=2bTKNq2SQB6<s`VK^9qEf@0oi*z|uzu zk`w{!vZ);R%$|)`QJ<9NRusYK3AGy!3)1vQUbuXefc4z7HL$z?F0AfAz@-sb3#bwp zFKAPnyq3xRQnnK(nb2poADX%e-#DPkUxpK5Wh#Fyqz&X0&{V%iN58cbL33n`Ux?@0 zHIhO~oUjPwlXJfsES4o<WlVJ4qX9OHcE32D7@0-1#9s`Y_+`jmu5DUzBY<EWO6TVZ z>Q~Wp6Ja#e{n$Avdm#~WIK1Q~LK9|t=&zj+Lkk7Jm+|?7BPwXxwa`gCWg;i}jyk)a z;`tbnc+>B@*hF3nZX)PnX7&<vKIQx<dq_HL$OPz<E{6~^Uj>P&FB=qWMaw~K6D&<i zW}78z-Z+~a{RAg@E@ed+rbs{QRpV7t7&YI`(OBR3<NSPTznOsmN>vS}&L$ux`yQ{K z%gz5xTL~q3ZksycP`%3|5Shbtz`#K)G7$zrUC;j4j*ftKvVT|ec>-|X^1r9)IEcrZ zc+z$@k_Dfh5J6&L4HCf5aM6ae=}OG?Jh{GuS|r#>=Vd=RL)F}UCiJUnX&J)}tn&JC zAiTx*d<AY=*dqo(f6_R2fq_!JMHu!4wed}<rDga1QsgBF5kZ?1za}<4JNvS&l~<UF zpiK~o{Lb4qx=)p>?I9PjVhMKePqK_Se$Y>SXH7hkWTg>*&30an&H2m2--Yc@Y)<^I z5!hz%FgG+eKTS?f*1fSnZ4gRB-PqXZjXAE{w19#qX*h^Mi#cPwT8QD*0zB+{dJ?bc z5f|qHTxrx$Ha9pv;IBue$nwkJoTd6sn;iN}-78$_S}4n)fLzRg`hmy))gX62r~M8F zBVcT7oCn+AAKk}NQI%gNfGE|1sX>e2;tvi#SIS939UefzC)D_nB{_XqOUwDh@3~NC zXz&CayPj!|W&iu}sx1gLf)|F-7##!p@4S&O2CcrM)|{#xV`F0o%?dR%HAl>Z3J62v zgi|U=xD**D!tU49*h-}7A}&tOWQ>iBUflQqL7SO)ky>fiu*plfUQW5emG23OL@Zi^ z+)+9?ar`Ms2BGmiV#cP%-#{!=tb25Hl(Mz8_4_LlJ|;p8nbl~pv8&TvDrf-ONwL$h ziE{F4=Yz)MhHYLn?MzI3HdfmJy7OsuUAd?E*uO$x)<IA2V)^UHll=BC)g;vdB~PT% zgkTOoS65D(kDptKJ-yw>O$?3m1M3cUo|k0Y{LOHl8_a6|vq)~M#*)L&6qo(dba!xI zMr^ecSq2dQHgAdvAcq=N;Yc{!kV;Gtbkx}WD>m4SnEatO{aP0y>-z{=9(QUXU4<lo zs?{R2gGsdBT!Y4|{9C^K;w{zOm<R)*9FzZ=4+K>|1SSoF?$O*zr|+=i7Ya7^y_Y7` zdmFA`dhHtqg2oBK)F?h$A7F9XlY@I@P^)L6<>$zpqZRRnCKINE#L-Kbg>OY|C{%+O z|9Qd<)&tVD^>v*>u>J4w0Z~-fLV_TYr|)x>aD25}dD^2Ljg`d-oxI%}y{?`+tP*L0 z@(*j=YF!Is*UEZ}#w}(3=(1uiZuYaUj7m{gpfrE?w8@7rT$Hk0gv*?7cupPqPV4IR zJ>y)}Tba?5&m0l47vkR*{N2;D-m>oo;uO;3C`H__s&nkXz+ISBi4p??!)Vn7W(%X) zvbuQ7*x2M-;4JY|C^!~qn@uop?(?LJ!S&fh6ZnOLs-HyKw>9^Acq{=_Rn=49T1TiD zPafW``?=*1!T#<1eP{>~?RZ*415WI-hMseB1quG(IfMf-AND725Gdb$(Cn_t;he@9 z&p|>sdxg5wVcH4nBI@B*>W)HPuvHisRJDJ>cHI2)`hxv|@#NHQkiMhb`M#&>$5pKf zzqk&`EPj!hb(hl?9z{k=X{ygYr=O-uv@<x~y+b6@W~k*Co;9<{5|4+c@E#kDnSE3z zgLb60(jg{Jl0}X1_LlO?H8TVPI(P5)xJyb&*{t|kqb?|Q4XPPGO71jEhDmQ;JS=#Y zCUZ_zSlo4SSJC^o)Od9lc2<_3P`66*eD(`!t?`DMY}i!E+o0V~-ApX}NTPeaI`lV7 zU%qX+I7g%I+6xiByI*r(cWllLk(HJ4t)fCSniwi27*PP`z+2lw@qPLevQlU52L~tX zzEv1|;!D8i8WhL+`uNoOp1&4*st|Pcs@RkaYVG^if_Q7Q_T>_y<0~$6`3Wr+wXIpa zlAAS6%8HpYBfjj05rrTGFs(p4vuR9vxubsP;7x}Fk0Qw7AVu><ho9-<DHWG<ua)EN z!vGmIA^7`{B#55ABhkh3o)#1{Q&V~d@9}S${O_&Y#m!b%Jw0|AQX*J+L1yeljKfbB z#r_rrwpej7Xvp`AwIJvO8oGuzxYN_c^5|@Zf^w3+ay2ZLN_Pm@G6@gqjDw{UY4!XO z_lq5^GpAFj&uWFUu~|e=W#Yf)GUzjXN0yF%Y-}NWG*A3GqPu?$>q~+RX=-R{dN%T= z-WSDtTbhOZM+<h(!?ya!V30{xLFU<Pb71kgBQezi4FY~)2nARFYl!CrE6V*n!(|0R z-_wYs_gk%PZuZ9zVL0Cfv^YEI#WT2inq?O3Od;6W*$Y*Rlu~#kEq3=)R)GY1TX>V= ztyh(YbTx*1NNMR`vs}k|+zXlZ{r=Sk^BckSZ0GIgOHI9zfy=XC?s1tcpgm&U(+@!c zanbR-3#&NhI|S`neT%=^)YjFhD;u2d?;m+d@k+9gk61|iVDPUc{`(qKMcdW{A}zQG zly&dU3Ftgmi1a#_;m+P3X9fbH*Fp*f|L01?Mc86T&f448iRAb%pB${j-DFg1tt4kz zcFm<B@4wJ6qlV_3n|M2hEXuf5WbrBUHkDn=xpL94_O%hQEQJ#KK9Zv&am)M2om#zU z75K%VyGXzp1I8=>r<t_D)qzzyZ350S5N^!@#9^{%vap##ni?53>gycTWnDDa8Jx+9 zTp^&m&CRElKVlbkyEC}Yz#xEjp-s_POg>bIbRwt7-yr4(0onwf27HRWC@+gCiEu+P zpSAdr7}RxV)(l|<Q&>oqc>?oLna6PuhSP{u&H$DCgBbbrW!mXJ@EuKHur<VpYtzrh zEwdtVn{tj)P2qEy4Ej-~f#X-iTGmY)8-<+`TK&x_3WLuLuHD(9+W+T1$v@j$TO($Y zkMrCADk+%r&0L7}aXV>o4Sz#!=MO%~#~8#y9?30KZ%WPdl19CL`X+h$EAVlD>i=ya zYjBC2G*oH*&?uAun)_&S??$S`k&k!%R(3>4Yl%86hspdye`_+~J6Nw*#weqUE(Lt# zZ8V|Xm*LzTsnY5|r2$cK9f2V1k-jAz+s_m0%b`jaW?7f!QqIJO=X-vABx4)2vb@gH ze}6NG@I6fW$Fvg<1<6A?5ayU6<PCMin##90TB|!O!gg&M?=qacu(*${Z~DW2aETyf zQl>s`h^)0^;rv{Fz-nJN*l9MT?r_eGT(*mX55h4hwH&sZ8YJ~~Wd*<XH;qz(iHyGc z2ZBodP`r0i4ZNtwzaihfd#k>VJ+YM(i-E)t!zNXn95rmWqG(-lcexmd5br{v!-E4H z$5W+b<zt6Zp|MKc_t$`DvuD1oT%rG_vp%%7T3I~jF2UE7^Zj1o*Eh?F5QBr8UfIJj zzQ05X-O3a_`X!iSdDiw^71Efu6UUyKLRzMyud4dWziNj56KBb2`Pls97vwgpzp){} zO6naGt_^S&T8kJ*wY|6@+j~rqb&c-5xx?IA>brOET7{)g5<axKXz|lG=sVjr?|-&9 z4%qV}8e);sXQX?^9sfk!T<Dw)d8m(+V2is^g2!*RD+WI09Ak4`U%Vorg~Q>MWIH!u z9%|b!<LSz4tI1D7-QT`7Ib)q0X9)-vvhw^D>@;Pj0eiDD!M@98dwl85GLxcchq!-P z9y-Uto%m|*fz7KVj_8<&ryBWgpX#475<snm)do6Z4RuY%m*`pok8=ouy<l&r!o$PG zKq`Kc-{d5ik(FimoLbVixVE<g+H%08SXtKH<*K<i>c=-r7rbm}S|LOt;Hvjp_Q!V8 z#GkJqeDiLTcou0T{92G|)igcJ(2LqTc@?D)rBe8W#FpQ1r?}@b)b;f`!A~dnONzO{ zm00Fe%*rBm71J+7ASoeLC}ed*#nV^d4(qp~g%)$q*Qb;K6`QUGU1}m(-7hE{?s7Az z!PZPe+G;T`0?t@@5}`lZ_j2^>RNReDx%SQXEWS+C9<xw}Gv`OQV3>}tsu<e^FNm*V z3%h)ehkqm-Ru-^@hJ*m{Z_=LOwsO1&X$Vzht68T0$2(kChCV^BTaeG<E01Uyqg5_W zWu1f;jwd$J1k<$<(QUKICgx{y1d>j5r>j}paUH*CLI89$X$QJ_c`*j`Nk*1|F{*zd z<zu#(u%i7K$L8t&tdzNn9J3IKTf_7WOjLE=%gtry8`66XbYt>%AU1^Jzb;<hRu<i$ zBut}aBpz4W_&qiM%&f^lnfPd)#+2o41ye|KGGW+mg}Mn*u%|D-7GwMqlJ>UFid+C4 z-0{@a5v$nZD2=EclZ{ddDi-DyBHJk+yF?Z)$S28+=rY@~CulycsKLMMC!od1n$Y9@ zDKGxJA_(wQ&6EFI0tzy6LVvXl!Z1Ng($0OUYKHsptN;qgn_o*`4d(7ET{I>{3<c*+ zcsv>I2ZBD!(LtQGXYI9rL88AE7CsA63Z`I8Bo1cn3;9{jH{#u>Um?LpMV0#p?fDyo zzk?t|k1pHzl=B&^_R6Cm=@Kd_87Y3An?~uTjVa><tu02vS-U!Qku@S$3FgG(_`Q85 z3dgh}baI91q|2}5nu{{(Kf45S0o4D-cgwj*hf~=4WJoC}Xyyy@UB2{h>|lm?6MTzp zq34bIPoWHYU7v)%YeEz!0qTU1V)16-R~ulCcA{1l6l7&js|M$eCk%AsNP}a6M-3*5 zxDm7ap)Iyi{;#)~Mu+>4O<oA9+SThB(s#za7W3U**|wZk;(%QydaJH)YAsYAsm=l& z$$}(ZvNV5#?yk%gNYVK8JRrUoc#YJRr|+8&_pxBOk8=DxOvuna*s~3CLWhXLJJ6rj zlasLc-5jEXz8IB{S^#+t4v54Jp&ArE`-AfaQlb(<Pv^5!u6gld88S5(Cx|!BbT!1d z$!obGhnIr%u_f_NHSs5*A&1GCG^R1yo&qAzQmvBFOgKwm{{tiX)2br|UvADi!M%p| zRb*_!rN_Nw7SA#&&OL8RKhiF@l}5j)C?l|mIWkEdSdcju_Gn<Dw28^T{V=O!|8NYU zaF;Nqr#^JZPFT-4p+lj8qn8DqEPWo8GDMBFJu8?LW!bXy>SBuQs4NgEK}nm?;R3R7 zr&5zjGJo1iP&YBox7Zi2P{F?&OFtkl9aLEm%NppvVnBCz&K3XlyXSC;w(Bj-GdiL? zlvtJ^p_1^32w`_wP=g;!$ZyK4lV8{{qm&y<irCwe64FoGNB-tNl^`fp;92|X3-3Cx zffGgVR$8o%E{&Rw^39wat9EQGJACn0&o<61@u+_`D(*lZADBNH7M>E-Q23-%IM5~N zqI6jCOc=Hszvll6y-#LjWR(6gF#)42!)Fuj3la-i{(;jZlME}1j%c$4y)=zHU7?~8 zbnh)AtAfS3IWx%ulJ^VTjd#Gr%QWW~BakrxG{cxccnvaG&G?a70dJq(m@+Xn8=HzQ z^xAad`Q&S`4(;-jH!)amv6AylYZg!QWdx;j!JB1GqlXX0i3)gs+?X6QCn%`Vuzrh} z=`<))+?RbRa?qE&G3wcPxR3Zia3ZVEIPsx(<DuWLfZu5Jv?)QTqvh?ETP4;N2A@?H zcK6Pl3pxH)i~8gUUhM3YGQp(^lc?6V#W|ic&@kSO%$Zyn9s^14nrv_9)=ikY%;^`_ z_17=aT9%Xop`mYCqkl!z%s;N0#O=P`*Z2@J)O}9Pp*9-$xNmOm=JOy0I~1CUAee<b zLZh9V^h6lOp(V@d!ctNEL!7xY{;pYB9~9?#l;&9wZd~&)QL2`ll9J?1jD-?g-m<{N zgd8CAUUtnB=6Wn~Q?Y3&f+ZH<D+8=QzS_K^{Ii0L$zBi$B~)yZ9bk&`%LjOcOcpuw z0?+OT`2Y*ij^LBCvw(Hadc(AA>IG6MMv+yj-%Cr%g<bZXWY=ODYa(}}y3-@iMm9XX zm^gk@28~c2mKJ(`5FR=h#8tk^V_R$+tWNIj+Y7Wg;n=C36nA2C6}m-vAYrODrYkC# zB+74o@hfohHhM=Etwq&f7rwg(lXw@3qwG{6z2lVqru;Fz>FIDp+-E{9&0V>;mV0k> zH0e4vPf{XI4&p*Hg+G#r875%*3F__8ErlB`B#A%)t&8C@wZ&17vS)Irn2|~N0LCT= zcj5t0be*rKJKOwg7B}wV6;xA&jA=Eed~alI%mg?1@$|W=u^#R=MsqXY_%|g2F9+JQ z`}6p=!F+KN!2{Cn{nTdD>fPhqN>gIS!lFm^FXZo$^1o5&IG?<P-jM*aM>&KaVTU6k z277mcC#K@m8Cg@Dymqf=R$S)kb8v&!zg6^`Wr@3ssJg%4VmvyCyF)}aaQ(BNLg2X( z1-CM02J1Ylw{mExFiWyQ`2hEecqXeQ@XW(8qIK?OMY#DHe04)LOM&}AfL^1DgDIur z9z0!1Pk<*E{m#=Hzx9qa?SAt@zHVZ@MMhJyzfw&Jdk}s0L&{P}yC8J78vK8)svpkG zHU)0a;bf!*%H)5#+0%9ILmr==<t-A-IqD0#dGUH2k;5ale;75daMd@>6y8`L^>Vn1 zyc%Nuw)<1g#<uo~2dUTYSqDlUcc$Fb@iq9cibU|uKrxe=_u$4CWfgN_e)*<f&l^=F z?T<x-;5|6mX8Y<gL{={AOdimAcJvOdoHWzzWFB$G-TH9_T}2C3OW&$?tICIR4u!0H z9JbEk_D`FU_=(ML<&Qo<#9W=*2|PQW9{-)H&OkI-mZ@>vpk~_Q?}HuFzseSaJb?mq zC)fAZ;eK5;fz1>ird~r><X?Xb4(1yfdB03ng|c?rzPJqwz;a}rBj4XR_?H0ebNCMo zV$vecafC8$80__ir+38gL#Eq7PrU5K6iroqE;j9qMbM=;@EdCv&SF-CIv=#BTLyTL zONYZ|&T8KN{yvlcgY06?eNL(pjNjS%E8TphY;*cqpRx;(uugKE3(yh8JR`5}lAE;- z)qlI~?dG@tH_Q1UdDt0tq01D04Ld~x4k<~4FN)##T$*LpwCfIcnTmu{H7sh;v77E@ zwXkGMs+q$BY~kMd#9{4cPw$L>k9hmDslQMw$$8Q7OT_12K+!h17hNeV>sGb4ah-%5 zeMCyawY~uXmM$K#Z%n)7V*|3rCJ7}e-^O}@=g$o%*xZnDRWWWEx8dR+#G1Sc>wFbj z$C?XgG6?k`r_B37)kH=vy%HipQ++9z;t|iyax&|EAIBD1^Sr~+QA=NM?*hUwACj#d zckhoANX3RFS{<u%c8yIOV@gFJJxgpiOVl3B)+dPRI#&!@Ua(qt%X+~?qPj`}z3ssq z5X73f4PR!C?HctBG$^`vBVbheUUIxZJ*#eNFh=M$AtW(moOiO)k+{J}5;<mVsnHp4 z*F+lpQ0OYoWz$bmK6j};;B6o{&xgD`AsrGO)l2sJGs^*P6ml%M<_RY!r;96;CMG6h z@{%cICE}qW9>0SzJJDAm=2fh(?vsQLwdIrK`iMiiG32v|%`SbMQjaziyxeQ4j4B;- zpXoFg_;#i1)=4Tjl|^G8)%vd7SO45iZGY0W5-We<B3abNLpV+aLX2@m_iH5W%3W5{ zpCxjp)QL&C9;a9<c3Q`L%2g+GA%u3yB@$v^a<Zp#J&i0${)d(F{TjfWqq|9>5vQg7 z-T+20EZ(3RA{hgL4n+rtvcWZ72@~Q84Q7#w9Z==*XlVK|LZ6YvE5(F*`}Vc*^@0Yn z^)9~66N`)HmVQ)_Lg40N{Ej@ls=Ym=7dtv}(Ht~;obTqebHh<4kg}|4aM;&dQ>NAv zsanJ?eJpG{wG#8YU}H&Jp>MamE*Yas{F(HudH3o#4G_gUocI3Tj?j;CvfNFZ1a;eY zyi$|s%$HemgcNm)HgN1NBB<cdtRS}QxUs6MO`yh4nqNoio)_i>q(kb|3k=$X5^TDc z$J-Q3sjD9Yuz2PRaznSRI)`_}Ld5pZi6H32f>s6MEWd0nQ$MZ2^|Yn6%<qm6<BD|) z5>9v$M?=0jc+=`+n`;4Nv2~v9yLBxsn%ZTaO{q_#UN4%xe&J5b8-|CMg1sX7eu5HN zELo{?Yv~i$p5b(Y>l0ydm+$N&*#V6C9~WR}r`~3xoKL4_B&ulGI5I#B;Ks;}`&&ow z+zE%Iz}czOs%qQ*m}qgW^kf%C;m_Pp;mw{VPJ1%ipJbbz7i1ChGT6;cwLU_J347#J zW8RWAe7iMJmf~DaPLS&{<H~9B#zyB0&v()yIYiL*3(I}-6W!0l-JDTHnR)yc&Ad{+ zaa-H$KbSYWjUr<zZ+MrQmUWsH4S(vWdc?y(xm|Y{K93X0%u>r64N^$nZ8(>C%LdPy zHSnLEnVz<_4CeRSnoNb)b(ra&ofX@A`7WGLvZxU6ER@ODiLkW<UTCzpmHtQ~ZUm)v z$X~Hvksnrm*Mp{FET>U<<Wcti`g-}@X&QqtALE}enA>gD*HnS0r^m?t1K7UXjZiJF zjT^T&D#nncF{ZeTQ@`B|rrSLWGdH(xu(7e}eJh8?OOi|KG<hrn4#2Q_YON>dXhRQ^ z<?Mj;*^#V~b)UI_sB?l=(ibpu!O(Xdl{N>8rWO<+*jV2l?H|X5|48R9WftBLAM5Q2 zRTKVrePf)A@<G5atUtNP(!R)f)P)J0v9xFV*YO#81F37<a3p$;dc+cpMlGf`6mQ75 z=)W~lVZWO-J6sbfKjs_pdd|`JHngLpohRB0>x{NZU~(+4tsC69*@5{r$vTqbV$+(W z94_8FXQ55WLsAm#>tmbo{cz>}Nyh&EO3=zbD+EWi>Lqok`evfT(v)jE`8m%Is)#SY zb^}$9oy&!MKLPb%Vza1$%v)vpTvpUmmg%LXOfcG;i6!b&&RB1-ukW2)ud`$IKpyKd z*~8!akpC1na>~(oHss`k{AkDIBS`7NcshO~9{g!REJ>whDyJk_`ivnt(luaq(GTX_ zGOtoHSpcx}sBzU$j)IoZ8L!5gK#jZW(*~AD9~`MOw6&##AkhL&bZ;8AwumqP&CPLu z&vAgl$Cm8>_X3D|Yk3VtGt>&rT7_$CYxONv2Uqsp{rp~@U2a4mOk4C?1SJ8oRm%J> zY)2l5S9+<eMA>3S*=2{ZoUEd@jxAGQ%pl6Kp(Tj=R+!g^{x(_LId{oxEC90||FY_) zJbUlC(=`)r0N5J3){}o#rvEE^X_)iK$J0~qOpcIM+o_VbH#A6~ph3SyR4|5pBT+?9 z0G$7Z>jCi9&~Hn=JHz*h&POXWAu}1@CX;onpYD!>EL;9Q*Ij!W)aY7zet5X{^;;~_ zDz*|E`A#)*HMAASMI>1{CO-mnDgy*%1u+BOBHsh)Ek6LvL#Ku6G6cDN&7s09tRU>j zxlXL&3{pbhw}Lta<S-1(FkzUbRN;A4>tva}g<{4_OO*u@yjiM|DSTS^TO)Sg=Wb$p zz*xIYrSD1Kp+~ViGk~F)ADQwcGoA&w#Wx4x@}^%$<2%zP?jvbe(zS9I`OKmlEW}^q zEcaM4ZJ=<oATUTPRI|n~jt0Zah)Isu;PH^LGL!eX*va=-=lkfKbQf&Vxh@^ROaVyx zhI|3Lop!JUyPW><GT;p)b)*JZYU^!K>sj)R(Ray{(A;XQuP++ojB<=}=+Ve8>h)l$ z;_ONC12y_Cdg6;B{aH@94C6}ga25ktR&n}(@?q~r#+H;s-JpS68v0sv<WM!A$T}xX z=-Nn5{bf0o<Yb1zy&P>Pu`%PYYFN4WL=D^&)hq*ErgUm@uAZ?Dt;XvbE8_tUm_GsJ zdKw#Afc{pP!q)b7p_@GaGZ;`yEvmX$`he=y1_Hdwh_+kW4wI!PTKZJVy!uE@pYzp4 z=M{kGvORNRlez?4XDKE%fPMG8Wj9F$j(i7?YT*8z$B$8Gr-$}cq=0QP`S194)=lv0 znefo+bz2{3JfoYFFH)b_FEdYBJCRLJ4=hAO1ANRVisSXG!J$xd2G|rFE`G9sb#|n5 z*lb}}m}#m2Rm!U6-R56@%4-J!>xURW#5Gh6BH)S`O0{HKvFQ=Jz=^AH9rNT<{A_qh zQcpqyQ#JBzMKZqzI=2w{;<z6_W;R%48?SM#zWBY=2S1c!Vm*ATd&#%~$NFgvi^T;_ z*KVuh$SqW}kwOem8mxH=1mBy&ulh3Rpw00$mz3U|qIXvDYn3P4=Ag5*Us9~Fsr;q7 zz_)L|oPBAdjHB6W*`A#}bIy@&15oMG`l}kMT@y<w)P@B8QXp4$Su`#X5zu1Fd=M); zB0f{-w-~Y+d(vISTo8-H;p|v{9?8eZPrC>WNmqUXTDaM^wk9Me8}&o&C$DHKazjQ> zGc-)NbSPm^zERbkPqa<R%oKB$u`c6}>lJxdg7a(XI!Liv3MA^oQCcMXQCj2^5gT9f zA*kj$aiZZ+>yyubZaOXrutOM*Ue=DN*%S&;G#NQQJ|5o29CG}%xn}uukX*?1#aIQY zprD|*0K_cw_)fnZ{GR~NYGe(n;h{x+k{=~?Ck8F&cLd!|2=R=RpPHV|;Ct|DfR`28 ze3CE`6>Q*MX+Gx7JodP*RuWz<<y6b{*xS|B%8@ZfWsogu&rmuZ8WI?NwNUP3|Cf5{ zOUN=ze(J2}iMYv4*vD$=trIIqi%VP2UC3z4C8jH0PfVRW{n1Auc%leXbYav3oBG2| zrEkihT9wL!U2>(rS&2Wco7(-4VP*!zJ+4hSbB2&%GTOW)b?n($`wTKX#4%nDSim6% zpD1oQ15>ui2abf$c<$X47iqPHVae+w^YFA`b9$wp6%`df`fZ3wb2nFyeJbeleAM2h zYIewf9>6qUG+3`GmtAqqV#g6a14l`f@5CL{!N)kiCW11U8G__2@GdOp70gBC^9y^r zYNevjB0(&9J>ELg-U_l&I&h@Nk@$EK-*ep0&^ytc3!}3r*K=^pSaMfKl!Jw2Wo5~z zf8Pa1%>@c=<49cMRnJ#mKlB~VrI=U2y_JVo%e)KIwyQ!VI0pH@U^<Mri>tbHqjY1r zVq#rVl9h4;)O3L>$zDZuhzJR*(CE6>8^?dPB?U2@WH1>SaKm@CBr-G%>3|AM_{7Q8 z)$V5Iw`ChzGK?8(Cw%9FO$H5uT;4C*ror*#5QkkK-FpY>#*o;{12m^1qto`*Z=|4U zC3o@Aa6jb2*#5V)w>8piqSEH&+}hsWn<~tkqGyb44{Y8wF28}>XR-nVSk@iTC{a?O z>35m>H*dz^{6~*3fyOfmK0%IYp5syfWh>T?f{PSZU&22km+a$Vu>H}oPTw#skcwan zHIJ71sxV-MBxyGS8V{Ri%kK4+PyRHHHC@L3^=WVlPfj^e%XM$axZC%Y_gPi8sWzV= zZ&{0{l8l22fOJYwe=BkZ0}K*$4K?yc^onii@5@<RTNjf5)F(eZJ@pR_x*RUdpI3-I z+wP(&2D+iMb?I*{|4ATPUnfUjuX0j1G2MF_fKW}EX-P;QxN%MUGYcTd^pf(|6#C-6 z%83`7$>R#Pj(BnYO|k<j+a<`8l|cP-vR)^xEYKKUL*}CTeN=yiYMqzxsH6%kXP4kf z;4rDIXIVz>ZtY~R(O)~%-bN>G^|^vGKKZ?A$YeRRo&QE!y<$QZP)qLahqXi}GoZSY zBG0O>PX2Yo18&2VC~BqhoK-!7^6orXM;Yo?If=9LHvRoax!UWVf_4V9NuDrrWF;TP zDPXFEZoy>D&w^%K?&qkdVth6R&!>tXT7-2!Ah2PZZEyH1Z{2XfEWZrs2BSxh4hX_S z+msagN|f)6j*oS}Lg^|OdQa=?<)<f(;sDe+X3OyBr~KsK+bXj*=_4Z}b}j<tYHv6u z`a}PbEoJ+^5t41s@%K|nG&_#wh9z)SMiiAte1#wB*}@hF*wadbt$kLvfASgKA|ocX zpNe<pjCEOf-ZW8|;h7QCq_)05@37nm6VoWFl8`m-m;KOoQQipGamF>7+(W)j8?YK> zvajp6Fj9MSvFU4S6W(GQ?ko91#^Iqwzw$?+ayHa>QrX$Dehi0g!k#4Nv#(g!3E^RK zGP-x?lIONu#iAwQW>SA*&;*a5oB#HhpFCX6!7MEYasOEOyNU40yRJW^eCGW{yn0LW z=2Lt>q|v^Pt=?zeS>3%+X5$D`Woa2X^|Qd1#0^@uAFP>NijTRJzqdN&Kd1QGrRZ9O zx*l5%6N#iT8-FRJBqOT{l(8B0nmOl>O}<-_O72_n=fwk#H$r}r#oQHt%F0Jypc$hI zC^7UOnoXnn)biqWOLxW}N%eK>qh4y=eQJ%VpLP$r&`M+u_^_^h_c6MO_1xzowDF#U z68TA&wDCyJ<BIYkLawg#le14pKO+?%*C1uOne6`qHoxEp<~R3z<<zI2Tw45%VX~Hu z>yYkq&oN8XjR2sKEH$e*fLOCmOLW#65P!{iGun)-f7Yk=Q_!?z1Vmjwf|RpMix-l^ z9l|{b!^BLk6WiEu%%uP<c8Ibo7szoxGEVA7$QEx6)8|AN-i;;Y#3n%Ilnflk_Wf-m zTYRJiLq}wfe<3pGD~KnC{yd$!wX74PEzLlA$4V^E(i2~&M}Ncx*J+Y<;S<DyjFFKJ zwQ^oG<Bfk@$l}+s#1-KJf>prQD?Tg25+HH!UDSZN4W5jsKPbzz_~4rBLYBMqZjFbB z2T*At=+&*0;9&+e`+$d%62O=$@@HgZ6w4>+<g)y9kSLs~Leb#ETAQ>fhW`K4q(eHa zX=dKaUz%Tx)~|{!p}DcKbRXZBRg+*rKkt9@Dh8O&sA{}&w|sO`SK40ApB`^?Eioi1 zam=PV8(Xh0D0;H9lWi=CXM8IbFIADja{g#-4gluX%u^q2u)mnzfS*&UVdk75j{ft? z1h%ugtNrm~lfEEpZX+mODEi$I?G?roCG7Y?D5#pE#?1uFV2)N9HRKfp)vqC^4NDa_ zQ<@lMXC#V7JU4%2zWw5SdD*it%i1&(HzizaOE2BESg~@y)NglsWW(b*99hVQ(n_*C zOc}7Ul|VU1P~4Uq50|Wt-^&4u&WC%y<RDDBHyg|Dd09r3g&fQD@RJf5aBGBiG~Geo zjJj9tg1B4hZ_Ark8#U@RE;omUPUzF$l=+IEEwph!A*CmS;E<J*D`wkH6x}I-!>jkC zFc}fG#Rv)y%<w+*cvi}^UV`P_JmtH62K6mLj~N(N3O{9}MIs|w0W+lCY-rX_Z=M?; zb7n6B$H+v<s=OJtmm{WR1RF3S32xt&BS(Mgi|P#UK0N~fNemS8^IYW+3T}ciBfZH_ z&hGBe5L9<_`fCOYIR)o_-I-UZeXdR}`DpGdpbktpq%QAwHMQJF$5lAYGCu<R_&IN7 zc42N!!;}9ufuH(*Ip7r)lDA?%e1g&FM<FE@6ioRCo1EL*IMjJYs2qtLIHmoLkECT} zDi8(5wUj{@7<D3aa1=Epu?u26bUy3R?tcC`Th;Y|Ukwcn>x|LOxsjqQM9*^xvX$Rx z9XAm)^J=F4DF4|WdWm!-9?{&a!Q#+oBWBX1L;Mve*qkl<+oo+Yb?#7VK)f+X8r`hz zW}8~^4Rwz2AcMu94Z5WcSQjd=!`cyc8T1`(Gcw69zGHg+%6E>b!<6R?@OlMhMmE1W z2xkcBx{3?$#OsgAi$Qv&GLsgz8uE<6C#eH$g`e_yc)}yp087qRFI1eA^Rcf@nP4y1 ztDu|7qLJb<U?yh92iLpeBXnw6C`Le)(xxfrh|VSYP#XWyw6Ez~Sv{+S<#?bTjkeAG zw~Aohx1uind~L`*GCO*Y)ipyM%wwJZBq~mc@pBlUZ@q%4{M)zyiPlqy{FLd^Z`H@) zT{AK|2pY=X!``qKPkT(keiIyp#sZ|_HRcZ!Z%5{Z?9bauioG^95d9FaA#*+(0V+xl zQt^3(_b90B1j^pf{Oun&uJ-fTzl_=&KC7_0GFJ;~sADmVlq9b}aujS`jJ<)xeHwZM zPGM^ypi}+X@Bq2|u#Ni;$4v)AZGm!g8P=LkFpEY3EUTL-ZE7zs;9uqGd&|(z$5fGR z19YaNmP-36*Smx-Eqno2P#;5Q&NBO7fHzE%aWULlBkro=^`2f{Es61a%gfdD@G=<U zkS0{Ag^95wZPz<J?|FroBwM&FGF`LFHm&PLe@p|2fnyTO)4$<~QIyJg3@DM$=Tb2s zy57X!Trs&G(A5+B<nZ3b+0kq3s#X^v*<N9yk!^zD=to*xr>C-smUaI9{YkmIonuj; zJ@jf7V61Rum)ZCLuYiE63gpp;(`J<afH}2+ut&c`7`LnZE?bic+;`Kk<k}Frm(9Y@ zYG3)gk->NHvcuhzk03nkEAzj=3<T!Jy}D1Ub8V?1b9U4o5E$Ysu9Jp-k?R^;^x!8A z*q{QQy7co@cz?iCn;cM~=85kqM6^iw$zE(0Bk|OXMhq)zyYS<nXAxY%`|ay9B`|_S z#Z0)-w&8>LN&&#$B-PI0v&MB~)ma!YQko7v?N;#H5Ql=%cavx9dST`2W9(mT^G0$` zeobq<L=ix$JhKanerz^Z0-mM*NPND-_3=Ja^luw*p#V@>MvKCZCLG4#&0kG?DIl|k z-treF2^pp59Do#`4qO>CR#HseBwPr~|K)9$3x#~U2{8U=qGZ=DSP@y7na#)A^Ij%? z_%}NjlzoO*`R)q#N*DwI4n%NlIps}tWW9DZqyFjU+`K*fW-c{Uy#n8C``emnX<wuO zvWHgdN2ac_25NRO^2;t}Q}3*_H7`R2#lz(>K^9c?!&YfmHd2B7rMFK~#Nt3gqV<f5 zimFhA)!N!QnIIg?+pD}Xa1shy_`leCzAVoz7C}P;^5;nW9T)w@2INMb31TwT;iZ5v zYWsh)>Ivwb>I&l)p2R##?*{dGYt7XZ3YWk@t2`-aQ;V2XwNE*KVYX?-^S%t1%yqmR zk@8Cx(q$Jmx8h28Os-JoRn6T5z|Tfoo4%J2_i}4BpdZ6c%24RZ7W_oIeY0Gf;Fr}o zLU$rqSfZl->Fa}yQUU%_Vb+uDB*D{+v0b+HMt@}9g#z1Mj+uzC-CdC+0^=Y)G%qbI zn2#bGOL=TR0@ZMKa=L%g1nOz$+o#U=0Tp4+QM1qQDrLF-vHpgq1zwYOq=swwtSztK z3gfm_4t5dAU|W;};pWUN1C+}7PE1?FT>=-MF$*XN9seAAZg#n>no!_}ifFbx=1_dR zU&*Pc&)1hI$IpC{u3k<A2sS3C1_H`V+joE&xrlrsHqvtdXI=r6M{?3;nTfjHMa29r zFh-t|K-4VSfIeJ!`1<Wzl*6}FZ*UY5x?6r`TR_ZfE;cKyZl5+S$Z;<`IlSTIysgtR z`-~?;V;$@J^c%sDv=pp`FY=mc7ovDchVkH%-FRB9CVmNw8Dl#^M5F@W+E{bk*zcHI zkk{z<jwMsm$nSXb`nM%!{#HPs(0a<4d}Rz5G|?I@>L(UtMEqTS3ao{hVNUFg_#AWo zpWr4(si{;7mL*8l@Qv8h#Bb}rWS_ME6*~0Aq5gEg`+!YT<BWHSYbrPwf*h~U_UwMx zUIg%yC9+H1En$fg@EHM7_xEm_$s*rapffh{HW1b(eAQed@9x+TUlVd{<e9zw`t94T zGq(xDaO6*&`n+XLEajZat+-HS&9fQSo2mP!Lg_0(F!SxrO}=QATsvCzDQ8LgiTn!D zS$xjopn4$e7Q6#e2vngV{ep_m1tsZ2^T&pJc8<5(+At9kY<x&NBgB@O*Bck3q2K`5 z%<ZiGQ=hmel8gcXnk_pjH5y{}Tsl8T9F_pZL*TpY@MU*v+V1guq$orfdXw-U!2QQ; z(l;`4Tw`$%YzsY$h|0;~eYw3NYi^ppf?JRcnzq#?@qbHaoK$fVs1@@-TVSxmD3T3y zRec*P?lv2bj^ubf(>3zOPS)*eCIxi~DQWwYmC;8JV}^XwuCi@*`qs5M0F4`!&~YBz zpLWZ1wvw}{XH)yfu@74Vd<B@2;g)?#m)>|LqczOZuDtt}Smv?R1>dI{HkK$NY0o1I z+3#$8Q&UsbR+@|E9Hdl#Fw-&l_HhGN6@Yt{Vb2n_?|<J!8j&Aw%S1_H7=$1z8emWJ zAbLd)I}^>isH>x^d7bR4`etYw_3r}c9*B3vKN-cIg6vbqOZB8FaNS*6H@Ngw@{Yg_ z#A$X5VVGuLBqa$E&3F=UAetj<l}wBDvg0xNN}=89aZMdJr4TjSRr|6|v?#IRMY;Lq z5+u%gi`F4S2Y<313=hP)6uX@|YAvH~Dw}D2+;P*(brCF<Vw922-1d}No1Z`O+TjkZ z1~gm0W4>@&Sb<8?v&sP3y)q8(9UsIcir;&(_Ncnf*HQ?tm8yMzWU8J-*~sy}kGZh3 z60@gmK-|$`#{xb)U>?Jz0$RNA4FAa)jytiUe6q_Ys+g(a+O5-syNX9TE<y(<O+Q#( zk>9H68EM;<u=HB0j;TfvQ^{|C%T^j2bBk_w$=vQVTsa0VesKTKyB=<>`#y2r|9PK# zK6kRFNG)YJB^fgXP+X6Xq%x52LTzuX4NjKUTE)nBRjWw64qSAcRVC@ZnP|^Ya#*d| zH>bqH<#WLsQCC;<j%2OpTp%E%^dZ=Gm&}Jv#qcr;^+cJDvu4+RsCBmoD|wtrn#zln zLQy}PNX|KOQ<s#H!L1l`aY(Z8bxv_Uwvlyn!;fhoUx1=Mlvhyj6DDIsbRl9VHly1_ z+d{FZTQ(n;&gAzm{iFnYg7Bd{WDu1caUJ%ykq&W!<{0a`{xUAgTW^K#`BY4xu7?m` zp4~=n&%$VP)5xtl3FKhV-}q~T=5$J}68YJK61*+n$p0?S(1|_fmqALhtQ>nvA-)(C zd0d82*Rj=>Qn&;A!R3mB+JBz7?;2DK^BN{}<eL%&V<O~NyhVoh3=>4jW`ArIOsy_+ zN&>W6$GM`dzauMWrc1D9*O1PWm}&+ylda@hQpPj5kA9o^Q1n+_YKOW|_%6r<FsDgV z3bHS#VnW?=11o!4Ht8t8m2_pgy{XA*abT}O3ReXjD68w7HOjsplk)L9zOVGN23&Sq zl~Oz|$ZrePFN_OvWD*OOcFlC|1nVI2S*?m1II0%xG3|`DZ7y;n@Eq{2|DgTPJ?1MK z^*oe!2!m@Lnf~z}J_i*Ljlk|ze~ko-s(QJsayHpH(|05+L@UP|=_^`6`(4U)<-DqU zpf=Q5qyL=r)&=&=k3#-Z;}-P_(r=K0AmYrW>D|frqJI&tikVWm<*!TN`H8N2B_co@ z191E97N9{mn_TF1$vdkr;|s~CBe}%wH)j4XLl?Av3kl>2yKMthXaf!yI$Fh=TFF&B z8TOl@`=_PpE2TmEOTH?oZYOZCf{~AAMG2qp^A{EOWeHbeNsP={c0?S5_=J*IS^m8= z;kp42^7Bj1>i~t?>4U?*<l>g|`Wjeu$*4CPbBl$oVXD)^fY~0|WrC_^__TjIm%id6 ziQ+ZHUuK36W2Z_2gM{DfB?oWV(YglRH}}I$&0sH)$uOTuQzW5koru=Xj4x5z)i(`_ zd-nJQ>JPe&!y9)zU)}pm4mxNkpTQb!$L|SGJIV1}P?3aYG@i@XU<ZbKb{93H$1)wl zb8BWgHyne=HnwLch82B{YmjxF0#XR7E+0zVeYRM%2k3?JLDs?knCPKO?l1s@PH@|H zd~R7N+%kQFvccH|y4T$XHZ@j<rm{5se}yo^uaa_|<aQAbRA*Y77v*iX;`gMQEcK=> zq~%sK`?s?c5G9-Tex}or1#eR~(kV&WGXkmCxhADKN9xYJu3rusI4QfIHZU?UfS#Gz zA3|*ynX{*_47%CC{AWPb1jJQ>!=%x)aUKTu;cFTQjS+CGPq+N=qq$$5g@e?+5q#PE zRL-lZ3Epg{VHy?c^YW^Ij>7Pm4>elrPJ?5B=?W8WURGfWCyjXBqGwNZfWycFQT^g@ z+5dL=KD5n_Z+~m+oWsy9Y8y9CW~rT^tD?$C?o~0)d3fDX{)XlcbB>sQ0w}HE?0)Sd zuRZp*UwvI4d+i7GBz}L&htiSOKDfD(($-ys<V;Cgj`bBgsE-7{>|lJZMvR!S*z5uX z#`+-d$I1pT97|(&fAP%-&fGUj&&mftT1Ja?k!jrqIzTv7NHFsT5jSpX_)oj<qrlm# z-`VEJ?NOKqz^yLHiLOYobmp!2_OGU^@vMQ{F)*b^K#C6zB}VJ6&#~C>9&Z^5nuI=} zHZ%FhXY*%R8WuIb$r<bX$6ZR9&rK17n2NGLnw5aMUm#6CpHkb{IDTv`yI6*-M*p)Y z>y_Ca2iu(91irqdw#?EXZ`dY1ucNYlZOfxU1l+%Xj-Kge*wv@JU<yg=w(;ZFPe2yj z>-`-w^{KG0(A~}Nd34noxTO_vwr9DrePcVm3j=0gi$vixNnVp%EdL{#OP<;mhl#94 zeA}5%8TW{ue#q|Uh%$LR=mrF<Gdkx&)cQS1PXkv|LEZd?C0j2iKx^ilwe`gKaVfJc z0Vv6MwL8Dj5w}A*h0>C6;_s{)uEDcVf-_!O&*;C&Ic%E}{A?i+Aw6@KW^p<ku*sAp znb&_T!=?uB!;47f6$`FMP;leF7vMi}Y5GJ@XRc6NN%h_TS3r>MX4}xEVU&HcKrKKF zxPS@I8@G(8C_8Z(j^kUX>OOQaVVHK{8V0kq9nvp1s{QSJUSFSGE!Nz!$pUHpXZL@b zC4>0eeFzG<JADStQl%h$fHWPY2S?EE=mypZ%h0h<D?E+lX{*!2MvcZ9Ul$klzH3cZ zFHtC%hn`i%@p=Sr2zOsd{twtp&l6C<8qGHN`dl+V<F4=Y+UfJ}7<FM6Hn=v@9PWs^ z+T*h&8_xB-q<EKl>EZpji)e#PFkGXBESocM!h1`;Rg^bT3`!MS1@UYkymJ8Yy+CvW z?Divh>1u}SZF{b_Z9nt-7WB8}XQF1Fz)j^YhSBJykbXw8i1Mdns`IynyQeoiM{LAO zC|e~x=ffgG;mB=AF*5l~H64S5!v5433;(})(5@W%Ed|9R@jDk>ghK007}8|>I9C<$ zUOhhSW5Bugae5;+4oA?_j^foX2YV0pk?<eI;P|PuHKpvZPk3+GD|e310M6(PlEuGo z1RZU*Y+YT$z|3@mayRxbzwkIK&5>lV>zF!uWY_EhP1nf$?#e$oPhXzSjJO)BOJXLg zn?B+#ha~Oro$(hIlqxPla5-<^yZd;6phbD-c6s$1S>C6zDxMR0AwLfzmK<IZ?}D<g zo~7sVW<5)Hv}zPmSwwMVQ8Q`!^sPx%kDIyQwk`7E_%gUQ#9v3e@n%Pct!!+}UD_b= zkDpWP>36{IB?*0v&e?|B{(Dem5MTa|AyC)^_qy8Jk7s~Q-Ky~8ZEl;8dS3hwgb%oH zBq#B@7&i^eHj(ALY$nSD=cZhNUY%~=#xwXcGbHSOUr1CVS4p#IL;w0H%394LmiNI| zNVEue)0Ayte7`f_#xcpyjs5S;K781ezpra~fg#mh&URx0QYQcMbw0CgxjRy8^6Aq_ z_Y>$QErC@<`N{s;xJlFnAP{wG9$oZfm<V3mzfmlf&VHry>OV!I6w@lY&14V)^rw_! zgWz+`)a-2juEm=c_Qx8;1#dfsihZ{+o)Sl(zJq_}9{+b;3&58!{BJImzGuyyc<hGb z;K_GUP<(=7#_~4652&?zEndg^-%uO;Z-`Sa8YFkne^H13fDK&%)e0B183XcWsML+* z2nsg;+e{K{&H-{e@O>ZnlIs0HbE4n4-AsuuP3f_?vYz7terV1de+4Z#Lv&7qj?sd| zjBd-`h7c>>YAB7t-%JHhCAir4zu!Lm-@mEaOQhKvfzN=uOOVDRXLB~->NntnL9I%w z|JP*k(`Lzt2j6@VA6fpV7QDmqXe)kM{_dX$e4na3Ud?Rm?4Vc*rW%L)N*MMB4*)=_ z`Li1@)5Nk6|L2ps*ef2tN5B?|O@nV20c9>*iLA4D@gop>O(x&RUnU;E6RCVT`_TLe z_j=c&!S7w`nvvr3nQiQk3wb#?$H`?#5nY!xA&(Wsc@>@2^tgZGR^To)2Q@fO5N<H} zi%jD0<OZwY4sl-BIl|O`k<Wk|uoUV4PYc%`&*s^NUrT>Uzh8rnF*2p=VMA-0Ref5O z_=;*t54N@|I#ol|St(6PW6Qp_K2@#Lq@hu|(iWi!s>-x}s)rDoN)V^$q9Y^~a*)@X zd{1ouzo+MVpXa{r=YFp1F6O)qA2zEqKQPS@00N?ogEWu!0y@YR2h#sTG)2?j%{ZPz zK}jh@4pB}XYW66ZdYX4Be$84SxrlH`-C;z)O_<Lj8gT1#%!D(^7v6CwQNA4$k$Vok zAJ7hC1?MU5Nh`Mbr5kQDzSI+LKD$vYt;HS9r5d=V54K-<RAY~SSt6cXnsYP7(9!Wu z(A*W6fus^sZ49s;iD_}Uet#kI(XB}wZ9hv5w<KW<@!Ucqh<RLlJGaGxYURcdULVyN zoe&Y7!CR86o}k~PhZj<Ds4e&*>x3fAsPft@D8i<FzCpNZgE8!S{4Xd$a%s9@l;4n$ zLXy6B{^5Dfd%qhud{T~o0#&3`?kuL$2PAr>G-UI4IZck$-AgQn>Qmn^Y+soZe9ZC) zW-Q|9yyVO=(;8{;;DUxJX2z~h>vuR7*8~nXQ;7mQIaym%I;n#-y$?vqODTsgMok!} zV@%OsF(3NUu?1_*3QACC8$TMJcn~UU1;ANBeFx$DTM6OrxV#6voV}bqBN@t{3NF*{ z{JaagUH~(uQ;A)fzNg*E7SsM^iw&-;um@nvBBM`QpuW*)G_>9Zg+@1+oy$=5TBGhP zTxDoe#(SO+?#C`3yrnO@mz%pzrh}3{8|B-%YIZ)|s^e11mp%5AvZGjkf7<ZM5%tFT zl0ao7`t9}axgS)j!PBTXd^S#|yH;$2u8@rKxpdez%#td0rY8@J{!2AF7%PI5yjg+d zXjjv*prRSIJpKH3-zz%Z>}&6lo1qRTfg`C79TefM0>_9mvr1<b{G<hP13x(Z9I-34 zGAR>e)%+(_4RIYQpgM6^Ao$)?v@hrv*|a)(kka8nWWQG0kmB-VWHE~|Ft^NYeUGo* z7f}BiIXRiwwTBvN*4<(Tg2q~WxJ6XybI^-Nr&c}eOUv~W_u$v}?0X=LZ{1mgHm-~_ z<*@DKjn$#vU5KodghWzzxCA6KqK<?xsVvc!UEs3vR+eP9oD7OvbrTr7%Sju7!*DCV zelRCC|72B9IL?)lc+};(EmUI(5PX4<+N7`8t?YI1R46ci?4L=uE}uTxPqfy2(2k9d zoe<k>n3g@<=F-QR8hS~0UM@AM@R}u1cnFr6OcW3Xs`EM$LS(Y%9mW9J?<f+{(8qve zxo+Y5Xm4-A#jLDacjc_|H7PT!h&+D9BYJ8GJODJwh;6F_3$X}hsDl-Pdd>MW4q0EA zfCu2Knn6@?*uAIs586ab=VmL;Ss*EPm#@riSHbPg3XAde^w^ZzUp>+Zx1v_Qvwp2x zWUllD$}qt{tPTG+sBh^hW2!iLbG<?#xpY}GB1EvN&#A+EDI0Z<1Fk(vTAgx-d9}Rq z>T@UVIS^^H9u9YaTROI?vW{Ou-}14<<AhT6rGt+`wFBn`y9!woe`SQdjHUn|I)NNQ zGPHhu>W}F}nNDvH*2mR^QU1}>Ddqno#4kk&zIEK5dBexpA)w+WVBBVB{%4$TXkee_ zg?;LfuNqc=w3l(@#7*^1_?SYD-xOb~*xTiqp!LLSEk(bVwOi0$(3t&D19f+)g;Y1S z2Oiy(5h~JXz%22nsxMvE<#fc#Tc+azmd=8X1`nD%t`_#>UurXfyiI+b?w7ilHJG={ zE8R}rUO>vU<%uoKuLL>nCPRg9-n>c6&?Myy>;RtFc=yc3k@E4!9jJIg1@QpLMb%E2 z&47oz-*>yrBZ!ZcV_N3AEFoxoay%drxoE*~!WSBrmVhAWr6Wa_u_-gk4R@UWHh7I$ zRs2vOeF)0p0Szv@z74G3hjFPL(`FcY9(#<9^tA_Ab$;Eg+VY99zACi)b8?l<Ug#7( z`Lk92LT~#OakEW4?^&5m7Aa1_G_=*-mS6E{!a!~en9+5Ph~gISGV<SxZTH$jnNh#7 zskK}T^pvIGUmURSY&3EjgxhAVGWTokGAWbBeb7urji8`$zJ}Z$V_xBM>SqYt3{07W z{w)3nPw}rSBg^f=I<||*ou2^T5u>16FA<*PG0S9?R-l+#V}aP;fWXl*W~2U=Oi>ID zk6YA}lti)lm_5|*D<_-vAlQD;rUT>zRnoU4Y3=ANR(qlDLhll38L0c(F7lgSi*IZE z(yyw4L(ND4a&oqNsukGc;pW96_QQMw9G%H|Dmop9cs(DKN@o>7+L}0K!tLml!J9VJ zctI62qx?A*Y+Et^H(qTZg1Ac-7VwC6c~QW$WPi#o7KUa1$orPRv-hX3E-=x95uuAD zoeF74oR~L(dO8uF9t`Th%%Awv#elSN+l8sGwlWVNKKvFac*&T|FiVslp5vKO2;^ou zrBv5VYb5j+(ul$WiUJn?IQQGhDsuap;JNpTiH>&dEAs&`_B1&;9gMwml>@S?8VOem z$9F@E1GF{*s@)|bd=8vpdWx%ANDI^-DJQGD08Z&foH~PS^Lu9W5()bdC<5M}kX7p| zSfCk`Y7~%bHy3Oe?=ENQMGF66<5n>*BM@5y0?!7dGX#6L8|S59?56#LCC5`vhOAdX zsWRr(G<5X11<DJU($9O(Wdpo5i%78R2+G6Q=?lC!w<-EIv%6e6JkcmLYpeExCXp<f gFjo!XTz_Ap<u^QYOR!QI>xs}ozr()u`@(<uKU+`O00000 literal 0 HcmV?d00001 diff --git a/resources/styles/_common.scss b/resources/styles/_common.scss index 3ea5003..ee625d9 100644 --- a/resources/styles/_common.scss +++ b/resources/styles/_common.scss @@ -60,7 +60,14 @@ } } +$section-safe-margin: 0.5rem; + .section { + padding: $section-safe-margin; + margin: -$section-safe-margin; + + background: rgba(white, 0.85); + margin-bottom: 1rem; .section__title { diff --git a/resources/styles/main.scss b/resources/styles/main.scss index c0ebdd6..5304c5c 100644 --- a/resources/styles/main.scss +++ b/resources/styles/main.scss @@ -100,10 +100,12 @@ body { min-height: 100vh; display: flex; flex-direction: column; + background: url("../images/background.png") repeat-x center bottom 63px; main { flex: 1 1 auto; position: relative; + margin-bottom: 2rem; > * { transition: opacity .3s ease-in-out; diff --git a/webpack.config.js b/webpack.config.js index 0382428..314ae97 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -36,7 +36,7 @@ const config = { test: /\.s[ac]ss$/, use: [{ loader: MiniCssExtractPlugin.loader, - }, "css-loader?sourceMap", "sass-loader?sourceMap"] + }, "css-loader?sourceMap&url=false", "sass-loader?sourceMap&url=false"] }, { test: /\.css$/, use: ["style-loader", "css-loader"] -- 2.45.2 From ceaa13bf2afb8ff36471f3abfcf96cfa698e8141 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sat, 26 Sep 2020 16:07:58 +0200 Subject: [PATCH 43/77] #18 - Basic Modal system --- resources/components/favourites/save.html | 2 +- resources/components/picker/stop.html | 4 +- resources/components/popper.html | 4 - resources/components/tooltip.html | 4 +- resources/components/ui/dialog.html | 29 +++ resources/styles/_map.scss | 2 +- resources/styles/main.scss | 16 +- resources/styles/page/_provider-picker.scss | 2 +- resources/styles/ui/_modal.scss | 58 ++++++ .../styles/{_popper.scss => ui/_popup.scss} | 20 +- resources/ts/app.ts | 4 + resources/ts/components/ui/dialog.ts | 187 ++++++++++++++++++ resources/ts/components/ui/icon.ts | 15 +- resources/ts/components/ui/index.ts | 1 + resources/ts/components/utils.ts | 106 ---------- resources/ts/filters.ts | 16 +- templates/app.html.twig | 16 +- 17 files changed, 341 insertions(+), 145 deletions(-) delete mode 100644 resources/components/popper.html create mode 100644 resources/components/ui/dialog.html create mode 100644 resources/styles/ui/_modal.scss rename resources/styles/{_popper.scss => ui/_popup.scss} (93%) create mode 100644 resources/ts/components/ui/dialog.ts diff --git a/resources/components/favourites/save.html b/resources/components/favourites/save.html index 544dc83..8607252 100644 --- a/resources/components/favourites/save.html +++ b/resources/components/favourites/save.html @@ -1,4 +1,4 @@ -<form class="favourite-add-form" @submit="save"> +<form class="favourite-add-form" @submit.prevent="save"> <div class="form-group"> <label for="favourite_add_name">Nazwa</label> <div class="input-group"> diff --git a/resources/components/picker/stop.html b/resources/components/picker/stop.html index 1f42643..b8d8997 100644 --- a/resources/components/picker/stop.html +++ b/resources/components/picker/stop.html @@ -35,8 +35,8 @@ </fold> <keep-alive> - <popper reference="action-map" v-if="showMap" arrow class="popper--no-padding" style="width: 500px;" placement="right-start" v-hover:inMap> + <ui-dialog reference="action-map" v-if="showMap" arrow class="ui-popup--no-padding" style="width: 500px;" placement="right-start" v-hover:inMap> <stop-map :stop="stop" style="height: 300px"/> - </popper> + </ui-dialog> </keep-alive> </div> diff --git a/resources/components/popper.html b/resources/components/popper.html deleted file mode 100644 index 84c1c94..0000000 --- a/resources/components/popper.html +++ /dev/null @@ -1,4 +0,0 @@ -<div :class="[ 'popper', arrow && 'popper--arrow' ]" v-on="$listeners"> - <div class="popper__arrow" ref="arrow" v-if="arrow"></div> - <slot /> -</div> diff --git a/resources/components/tooltip.html b/resources/components/tooltip.html index 65805b0..033eeb5 100644 --- a/resources/components/tooltip.html +++ b/resources/components/tooltip.html @@ -1,9 +1,9 @@ <fragment> <portal to="popups"> <transition name="tooltip"> - <popper class="popper--tooltip" aria-hidden="true" arrow :reference="root" :placement="placement" v-if="show" :responsive="false"> + <ui-dialog class="ui-popup--tooltip" aria-hidden="true" arrow :reference="root" :placement="placement" v-if="show" :responsive="false"> <slot /> - </popper> + </ui-dialog> </transition> </portal> <span ref="root" class="sr-only"><slot /></span> diff --git a/resources/components/ui/dialog.html b/resources/components/ui/dialog.html new file mode 100644 index 0000000..7adf4cb --- /dev/null +++ b/resources/components/ui/dialog.html @@ -0,0 +1,29 @@ +<div class="ui-backdrop" @click="handleBackdropClick" v-if="currentBehaviour === 'modal'"> + <div class="ui-modal" v-bind="$attrs"> + <div class="ui-modal__top-bar"> + <div class="ui-modal__header"> + <slot name="header"> + <div class="ui-modal__title">{{ title }}</div> + </slot> + </div> + <button class="btn btn-action ui-modal__close" @click.prevent="handleCloseClick"> + <ui-icon icon="close"/> + </button> + </div> + <slot /> + <div class="ui-modal__footer" v-if="hasFooter"> + <slot name="footer" /> + </div> + </div> +</div> +<div :class="[ 'ui-popup', arrow && 'ui-popup--arrow' ]" v-bind="$attrs" v-on="$listeners" v-else> + <div class="ui-popup__arrow" ref="arrow" v-if="arrow"></div> + <div class="ui-popup__header" v-if="hasHeader"> + <slot name="header" /> + </div> + <slot /> + <div class="ui-popup__footer" v-if="hasFooter"> + <slot name="footer" /> + </div> +</div> + diff --git a/resources/styles/_map.scss b/resources/styles/_map.scss index ab177bf..89f34fc 100644 --- a/resources/styles/_map.scss +++ b/resources/styles/_map.scss @@ -1,5 +1,5 @@ .map__label-box { - @extend .popper; + @extend .ui-popup; padding: .5rem; background: white; diff --git a/resources/styles/main.scss b/resources/styles/main.scss index 5304c5c..83d2198 100644 --- a/resources/styles/main.scss +++ b/resources/styles/main.scss @@ -75,12 +75,24 @@ $grid-gutter-width: $spacer * 2; } } +@mixin position($position, $top: inherit, $right: inherit, $bottom: inherit, $left: inherit) { + $right: if($right == inherit, $top, $right); + $bottom: if($bottom == inherit, $top, $bottom); + $left: if($left == inherit, $right, $left); + + position: $position; + + top: $top; + right: $right; + left: $left; + bottom: $bottom; +} + @import "common"; @import "stop"; @import "departure"; @import "line"; @import "controls"; -@import "popper"; @import "animations"; @import "form"; @import "favourites"; @@ -89,6 +101,8 @@ $grid-gutter-width: $spacer * 2; @import "map"; @import "ui/switch"; +@import "ui/popup"; +@import "ui/modal"; @import "page/provider-picker"; diff --git a/resources/styles/page/_provider-picker.scss b/resources/styles/page/_provider-picker.scss index 75bc5bb..939910d 100644 --- a/resources/styles/page/_provider-picker.scss +++ b/resources/styles/page/_provider-picker.scss @@ -8,7 +8,7 @@ } .provider-picker { - @extend .popper; + @extend .ui-popup; padding: 1rem; margin: 3rem; } diff --git a/resources/styles/ui/_modal.scss b/resources/styles/ui/_modal.scss new file mode 100644 index 0000000..2764a52 --- /dev/null +++ b/resources/styles/ui/_modal.scss @@ -0,0 +1,58 @@ +.ui-backdrop { + @include position(fixed, 0); + background: rgba(black, .75); + padding: $spacer; + display: flex; + flex-direction: column; + align-items: center; + overflow-y: auto; + overscroll-behavior-y: contain; + + &::after { + height: 1rem; + display: block; + content: ""; + } +} + +$dialog-margin: 1rem; +$dialog-sizes: ( + medium: 480px, + small: 320px, + large: 640px, +) +; + +.ui-modal { + padding: $dialog-margin; + background: white; + margin: auto; + box-shadow: rgba(black, .7) 0 1px 3px; + border-radius: 1px; + + @each $size, $width in $dialog-sizes { + .ui-modal--#{$size} { + width: $width; + } + } +} + +.ui-modal__close { + margin-right: -$dialog-margin; + padding: $dialog-margin $dialog-margin 0; + margin-top: -$dialog-margin; +} + +.ui-modal__header { + flex: 1 1 auto; +} + +.ui-modal__title { + font-weight: bold; + font-size: 0.875rem; +} + +.ui-modal__top-bar { + display: flex; + margin-bottom: $dialog-margin * 0.75; +} diff --git a/resources/styles/_popper.scss b/resources/styles/ui/_popup.scss similarity index 93% rename from resources/styles/_popper.scss rename to resources/styles/ui/_popup.scss index 7b9ea5b..384d6c2 100644 --- a/resources/styles/_popper.scss +++ b/resources/styles/ui/_popup.scss @@ -54,7 +54,7 @@ @mixin triangle-left($size, $color, $border: none) { @include triangle(left, $size, $color, $border); } @mixin triangle-right($size, $color, $border: none) { @include triangle(right, $size, $color, $border); } -.popper { +.ui-popup { $arrow-base: 8px; $arrow-color: white; $arrow-border: rgba(black, 0.2); @@ -74,17 +74,17 @@ border-radius: 2px; - .popper__arrow { + .ui-popup__arrow { position: absolute; width: 0; height: 0; } - &.popper--no-padding { + &.ui-popup--no-padding { padding: 0; } - .popper__heading { + .ui-popup__heading { font-size: $font-size-sm; font-weight: bold; margin-bottom: .5rem; @@ -105,7 +105,7 @@ &[x-placement*="#{$placement}"] { margin-#{map-get($opposite, $placement)}: $arrow-base; - .popper__arrow { + .ui-popup__arrow { #{map-get($opposite, $placement)}: 0; @include triangle(map-get($opposite, $placement), $arrow-base, $arrow-color, $arrow-border); } @@ -119,11 +119,11 @@ @include placement("bottom"); } - &.popper--arrow { + &.ui-popup--arrow { @include arrows; } - &.popper--tooltip { + &.ui-popup--tooltip { background: $dark; color: white; padding: .5rem .75rem; @@ -132,14 +132,14 @@ min-width: 0; box-shadow: none; - &.popper--arrow { + &.ui-popup--arrow { $arrow-color: $dark; $arrow-border: none; $arrow-base: 6px; @include arrows; - .popper__arrow::before { + .ui-popup__arrow::before { border: none; } } @@ -147,7 +147,7 @@ } @include media-breakpoint-down('sm') { - .popper { + .ui-popup { margin-left: $spacer; margin-right: $spacer; } diff --git a/resources/ts/app.ts b/resources/ts/app.ts index 71804a7..a201127 100644 --- a/resources/ts/app.ts +++ b/resources/ts/app.ts @@ -31,10 +31,14 @@ Vue.use(VueMoment, { moment }); declare module 'vue/types/vue' { interface Vue { $isTouch: boolean; + $hasSlot: (slot: string) => string; } } Vue.prototype.$isTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints > 0; +Vue.prototype.$hasSlot = function (this: Vue, slot: string): boolean { + return !!this.$slots[slot] || !!this.$scopedSlots[slot]; +} Component.registerHooks(['removed']); diff --git a/resources/ts/components/ui/dialog.ts b/resources/ts/components/ui/dialog.ts new file mode 100644 index 0000000..4ecd057 --- /dev/null +++ b/resources/ts/components/ui/dialog.ts @@ -0,0 +1,187 @@ +import Vue from "vue"; +import { Component, Prop, Watch } from "vue-property-decorator"; +import Popper, { Placement } from "popper.js"; +import { defaultBreakpoints } from "../../filters"; + +/** + * How popup will be presented to user: + * - "modal" - modal window + * - "popup" - simple popup + */ +export type DialogBehaviour = "modal" | "popup"; + +@Component({ + template: require('../../../components/ui/dialog.html'), + inheritAttrs: false, +}) +export default class UiDialog extends Vue { + @Prop({ type: String, default: "popup" }) + private behaviour: DialogBehaviour; + + @Prop({ type: String }) + private mobileBehaviour: DialogBehaviour; + + @Prop([String, HTMLElement]) + public reference: string | HTMLElement; + + @Prop(Object) + public refs: string; + + @Prop({ type: String, default: "auto" }) + public placement: Placement; + + @Prop(Boolean) + public arrow: boolean; + + @Prop({ type: Boolean, default: true }) + public responsive: boolean; + + @Prop(String) + public title: string; + + private isMobile: boolean = false; + + private _focusOutEvent; + private _resizeEvent; + + private _popper; + + get currentBehaviour(): DialogBehaviour { + if (!this.mobileBehaviour) { + return this.behaviour; + } + + return this.isMobile ? this.mobileBehaviour : this.behaviour; + } + + get hasFooter() { + return this.$hasSlot('footer') + } + + get hasHeader() { + return this.$hasSlot('header') + } + + private getReferenceElement() { + const isInWrapper = this.$parent.$options.name == 'portalTarget'; + + if (typeof this.reference === 'string') { + if (this.refs) { + return this.refs[this.reference]; + } + + if (isInWrapper) { + return this.$parent.$parent.$refs[this.reference]; + } + + return this.$parent.$refs[this.reference]; + } + + if (this.reference instanceof HTMLElement) { + return this.reference; + } + + return isInWrapper ? this.$parent.$el : this.$el.parentElement; + } + + focusOut(event: MouseEvent) { + if (this.$el.contains(event.target as Node)) { + return; + } + + this.$emit('leave', event); + } + + mounted() { + this.handleWindowResize(); + + if (this.behaviour === 'popup') { + this.initPopper(); + } + + window.addEventListener('resize', this._resizeEvent = this.handleWindowResize.bind(this)); + } + + private initPopper() { + const reference = this.getReferenceElement(); + + this._popper = new Popper(reference, this.$el, { + placement: this.placement, + modifiers: { + arrow: { enabled: this.arrow, element: this.$refs['arrow'] as Element }, + responsive: { + enabled: this.responsive, + order: 890, + fn(data) { + if (window.innerWidth < 560) { + data.instance.options.placement = 'top'; + data.styles.transform = `translate3d(0, ${ data.offsets.popper.top }px, 0)`; + data.styles.right = '0'; + data.styles.left = '0'; + data.styles.width = 'auto'; + data.arrowStyles.left = `${ data.offsets.popper.left + data.offsets.arrow.left }px`; + } + + return data; + } + } + } + }); + + this.$nextTick(() => { + this._popper && this._popper.update(); + document.addEventListener('click', this._focusOutEvent = this.focusOut.bind(this), { capture: true }); + }); + } + + private removePopper() { + this._popper.destroy() + this._popper = null; + } + + updated() { + if (this._popper) { + this._popper.update(); + } + } + + beforeDestroy() { + this._focusOutEvent && document.removeEventListener('click', this._focusOutEvent, { capture: true }); + } + + removed() { + if (this._popper) { + this.removePopper(); + } + } + + private handleBackdropClick(ev: Event) { + const target = ev.target as HTMLElement; + + if (target.classList.contains("ui-backdrop")) { + this.$emit('leave'); + } + } + + private handleCloseClick() { + this.$emit('leave'); + this.$emit('close'); + } + + private handleWindowResize() { + this.isMobile = screen.width < defaultBreakpoints.md; + } + + @Watch('currentBehaviour') + private handleBehaviourChange(newBehaviour: DialogBehaviour, oldBehaviour: DialogBehaviour) { + if (oldBehaviour === 'popup') { + this.removePopper(); + } + + if (newBehaviour === 'popup') { + this.$nextTick(() => this.initPopper()); + } + } +} + +Vue.component("ui-dialog", UiDialog); diff --git a/resources/ts/components/ui/icon.ts b/resources/ts/components/ui/icon.ts index 11863a0..b25535a 100644 --- a/resources/ts/components/ui/icon.ts +++ b/resources/ts/components/ui/icon.ts @@ -7,7 +7,8 @@ import { faCheck, faCheckDouble, faChevronCircleUp, - faChevronDown, faChevronUp, + faChevronDown, + faChevronUp, faClock, faCog, faExclamationTriangle, @@ -15,7 +16,8 @@ import { faInfoCircle, faMapMarkerAlt, faMoon, - faQuestionCircle, faQuestionSquare, + faQuestionCircle, + faQuestionSquare, faSearch, faSign, faStar, @@ -23,7 +25,13 @@ import { faTimes, faTrashAlt } from "@fortawesome/pro-light-svg-icons"; -import { faClock as faClockBold, faCodeCommit, faMinus, faPlus, faSpinnerThird } from "@fortawesome/pro-regular-svg-icons"; +import { + faClock as faClockBold, + faCodeCommit, + faMinus, + faPlus, + faSpinnerThird +} from "@fortawesome/pro-regular-svg-icons"; import { faExclamationTriangle as faSolidExclamationTriangle, faWalking } from "@fortawesome/pro-solid-svg-icons"; import { fac } from "../../icons"; import { FontAwesomeIcon, FontAwesomeLayers, FontAwesomeLayersText } from "@fortawesome/vue-fontawesome"; @@ -88,6 +96,7 @@ const definitions: Dictionary<Icon> = { {icon: faClockBold}, {icon: faSolidExclamationTriangle, transform: "shrink-5 down-4 right-6"} ]), + 'close': simple(faTimes), ...lineTypeIcons, ...messageTypeIcons, }; diff --git a/resources/ts/components/ui/index.ts b/resources/ts/components/ui/index.ts index 8814273..1909ea7 100644 --- a/resources/ts/components/ui/index.ts +++ b/resources/ts/components/ui/index.ts @@ -1,3 +1,4 @@ export * from './switch'; export * from './icon'; export * from './numeric-input' +export * from './dialog' diff --git a/resources/ts/components/utils.ts b/resources/ts/components/utils.ts index 9dc6837..464fc68 100644 --- a/resources/ts/components/utils.ts +++ b/resources/ts/components/utils.ts @@ -1,111 +1,6 @@ import Vue from 'vue'; import { Component, Prop, Watch } from "vue-property-decorator"; -import Popper, { Placement } from "popper.js"; -import vueRemovedHookMixin from "vue-removed-hook-mixin"; -@Component({ - template: require("../../components/popper.html"), - mixins: [ vueRemovedHookMixin ] -}) -export class PopperComponent extends Vue { - @Prop([ String, HTMLElement ]) - public reference: string | HTMLElement; - - @Prop(Object) - public refs: string; - - @Prop({ type: String, default: "auto" }) - public placement: Placement; - - @Prop(Boolean) - public arrow: boolean; - - @Prop({ type: Boolean, default: true }) - public responsive: boolean; - - private _event; - private _popper; - - private getReferenceElement() { - const isInPortal = this.$parent.$options.name == 'portalTarget'; - - if (typeof this.reference === 'string') { - if (this.refs) { - return this.refs[this.reference]; - } - - if (isInPortal) { - return this.$parent.$parent.$refs[this.reference]; - } - - return this.$parent.$refs[this.reference]; - } - - if (this.reference instanceof HTMLElement) { - return this.reference; - } - - return isInPortal ? this.$parent.$el : this.$el.parentElement; - } - - focusOut(event: MouseEvent) { - if (this.$el.contains(event.target as Node)) { - return; - } - - this.$emit('leave', event); - } - - mounted() { - const reference = this.getReferenceElement(); - - this._popper = new Popper(reference, this.$el, { - placement: this.placement, - modifiers: { - arrow: { enabled: this.arrow, element: this.$refs['arrow'] as Element }, - responsive: { - enabled: this.responsive, - order: 890, - fn(data) { - if (window.innerWidth < 560) { - data.instance.options.placement = 'top'; - data.styles.transform = `translate3d(0, ${data.offsets.popper.top}px, 0)`; - data.styles.right = '0'; - data.styles.left = '0'; - data.styles.width = 'auto'; - data.arrowStyles.left = `${data.offsets.popper.left + data.offsets.arrow.left}px`; - } - - return data; - } - } - } - }); - - this.$nextTick(() => { - this._popper.update(); - document.addEventListener('click', this._event = this.focusOut.bind(this), { capture: true }); - }); - } - - updated() { - this._popper.update(); - } - - @Watch('visible') - private onVisibilityUpdate() { - this._popper.update(); - window.dispatchEvent(new Event('resize')); - } - - beforeDestroy() { - this._event && document.removeEventListener('click', this._event, { capture: true }); - } - - removed() { - this._popper.destroy() - } -} @Component({ template: require('../../components/fold.html') }) export class FoldComponent extends Vue { @@ -151,7 +46,6 @@ export class LazyComponent extends Vue { } } -Vue.component('Popper', PopperComponent); Vue.component('Fold', FoldComponent); Vue.component('Lazy', LazyComponent); diff --git a/resources/ts/filters.ts b/resources/ts/filters.ts index 3a0e040..b3fd1e4 100644 --- a/resources/ts/filters.ts +++ b/resources/ts/filters.ts @@ -2,6 +2,14 @@ import { set, signed } from "./utils"; import Vue from 'vue'; import { condition } from "./decorators"; +export const defaultBreakpoints = { + 'xs': 0, + 'sm': 576, + 'md': 768, + 'lg': 1024, + 'xl': 1200, +} + Vue.filter('signed', signed); Vue.directive('hover', { @@ -61,13 +69,7 @@ Vue.directive('autofocus', { Vue.directive('responsive', { inserted(el, binding) { - const breakpoints = typeof binding.value === 'object' ? binding.value : { - 'xs': 0, - 'sm': 576, - 'md': 768, - 'lg': 1024, - 'xl': 1200, - }; + const breakpoints = typeof binding.value === 'object' ? binding.value : defaultBreakpoints; const resize = binding['resize'] = () => { const width = el.scrollWidth; diff --git a/templates/app.html.twig b/templates/app.html.twig index a8143e6..214d70c 100644 --- a/templates/app.html.twig +++ b/templates/app.html.twig @@ -29,9 +29,9 @@ </button> <portal to="popups"> - <popper reference="settings-messages" v-if="visibility.messages" arrow placement="left-start" @leave="visibility.messages = false"> + <ui-dialog reference="settings-messages" v-if="visibility.messages" arrow placement="left-start" @leave="visibility.messages = false"> <settings-messages></settings-messages> - </popper> + </ui-dialog> </portal> </header> <fold :visible="sections.messages"> @@ -54,9 +54,9 @@ <ui-icon icon="refresh" :spin="departures.state === 'fetching'" fixed-width></ui-icon> </button> <portal to="popups"> - <popper reference="settings-departures" v-if="visibility.departures" arrow placement="left-start" @leave="visibility.departures = false"> + <ui-dialog reference="settings-departures" v-if="visibility.departures" @leave="visibility.departures = false" arrow placement="left-start"> <settings-departures></settings-departures> - </popper> + </ui-dialog> </portal> </header> <departures :stops="stops" v-if="stops.length > 0"></departures> @@ -105,9 +105,11 @@ </button> </div> - <popper reference="save" v-if="visibility.save" arrow tabindex="-1" @leave="visibility.save = false" placement="bottom-end"> - <favourites-adder @saved="visibility.save = false"/> - </popper> + <portal to="popups"> + <ui-dialog reference="settings-messages" v-if="visibility.messages" arrow placement="left-start" @leave="visibility.messages = false"> + <favourites-adder @saved="visibility.save = false"/> + </ui-dialog> + </portal> </section> <section class="section picker"> <header class="section__title flex"> -- 2.45.2 From ccbe88a5322d8fef057aa4610bf708b190656c4e Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Thu, 1 Oct 2020 21:41:39 +0200 Subject: [PATCH 44/77] #18 - Refine modal system --- resources/components/picker/stop.html | 13 ++-- resources/components/stop/details.html | 4 +- resources/components/ui/dialog.html | 6 +- resources/styles/main.scss | 4 ++ resources/styles/ui/_modal.scss | 15 +++- resources/ts/components/ui/dialog.ts | 96 ++++++++++++++++++++++++-- templates/app.html.twig | 8 +-- 7 files changed, 127 insertions(+), 19 deletions(-) diff --git a/resources/components/picker/stop.html b/resources/components/picker/stop.html index b8d8997..63e3ebb 100644 --- a/resources/components/picker/stop.html +++ b/resources/components/picker/stop.html @@ -21,7 +21,7 @@ <slot name="actions"> <button class="btn btn-action" ref="action-info" @click="details = !details"> <tooltip>dodatkowe informacje</tooltip> - <ui-icon :icon="details ? 'info-hide' : 'info'"/> + <ui-icon icon="info"/> </button> <button class="btn btn-action" ref="action-map" v-hover:map> @@ -30,11 +30,16 @@ </slot> </div> </div> - <fold :visible="details" class="stop__details-fold" lazy> - <stop-details :stop="stop"/> - </fold> <keep-alive> + <portal to="popups"> + <ui-dialog v-if="details" @leave="details = false" behaviour="modal" class="ui-modal--medium" title="Szczegóły przystanku"> + <stop-details :stop="stop"/> + </ui-dialog> + </portal> + </keep-alive> + <keep-alive> + <!-- FIXME: This should be in portal but it's not possible due to information loss, maybe in vue3 it will be better?--> <ui-dialog reference="action-map" v-if="showMap" arrow class="ui-popup--no-padding" style="width: 500px;" placement="right-start" v-hover:inMap> <stop-map :stop="stop" style="height: 300px"/> </ui-dialog> diff --git a/resources/components/stop/details.html b/resources/components/stop/details.html index e8d0927..f04dc1c 100644 --- a/resources/components/stop/details.html +++ b/resources/components/stop/details.html @@ -16,7 +16,9 @@ <div class="track__description"> {{ track.description }} </div> - <span class="badge badge-pill badge-light track__order">#{{ order }}</span> + <span class="badge badge-pill badge-light track__order"> + #{{ order }} + </span> </li> </ul> </section> diff --git a/resources/components/ui/dialog.html b/resources/components/ui/dialog.html index 7adf4cb..8117b2e 100644 --- a/resources/components/ui/dialog.html +++ b/resources/components/ui/dialog.html @@ -1,9 +1,9 @@ <div class="ui-backdrop" @click="handleBackdropClick" v-if="currentBehaviour === 'modal'"> - <div class="ui-modal" v-bind="$attrs"> + <div class="ui-modal" v-bind="attrs" v-on="$listeners"> <div class="ui-modal__top-bar"> <div class="ui-modal__header"> <slot name="header"> - <div class="ui-modal__title">{{ title }}</div> + <div class="ui-modal__title"><slot name="title">{{ title }}</slot></div> </slot> </div> <button class="btn btn-action ui-modal__close" @click.prevent="handleCloseClick"> @@ -16,7 +16,7 @@ </div> </div> </div> -<div :class="[ 'ui-popup', arrow && 'ui-popup--arrow' ]" v-bind="$attrs" v-on="$listeners" v-else> +<div :class="[ 'ui-popup', arrow && 'ui-popup--arrow' ]" v-bind="attrs" :style="{ zIndex: zIndex }" v-on="$listeners" v-else> <div class="ui-popup__arrow" ref="arrow" v-if="arrow"></div> <div class="ui-popup__header" v-if="hasHeader"> <slot name="header" /> diff --git a/resources/styles/main.scss b/resources/styles/main.scss index 83d2198..63a5f4c 100644 --- a/resources/styles/main.scss +++ b/resources/styles/main.scss @@ -116,6 +116,10 @@ body { flex-direction: column; background: url("../images/background.png") repeat-x center bottom 63px; + &.contains-modal { + overflow-y: hidden; + } + main { flex: 1 1 auto; position: relative; diff --git a/resources/styles/ui/_modal.scss b/resources/styles/ui/_modal.scss index 2764a52..2192306 100644 --- a/resources/styles/ui/_modal.scss +++ b/resources/styles/ui/_modal.scss @@ -7,11 +7,14 @@ align-items: center; overflow-y: auto; overscroll-behavior-y: contain; + z-index: 10000; &::after { - height: 1rem; + height: $spacer; display: block; content: ""; + width: 1px; + flex: 0 0 auto; } } @@ -31,7 +34,7 @@ $dialog-sizes: ( border-radius: 1px; @each $size, $width in $dialog-sizes { - .ui-modal--#{$size} { + &.ui-modal--#{$size} { width: $width; } } @@ -56,3 +59,11 @@ $dialog-sizes: ( display: flex; margin-bottom: $dialog-margin * 0.75; } + +@include media-breakpoint-down('sm') { + @each $size, $width in $dialog-sizes { + .ui-modal.ui-modal--#{$size} { + width: 100%; + } + } +} diff --git a/resources/ts/components/ui/dialog.ts b/resources/ts/components/ui/dialog.ts index 4ecd057..18580ba 100644 --- a/resources/ts/components/ui/dialog.ts +++ b/resources/ts/components/ui/dialog.ts @@ -10,9 +10,31 @@ import { defaultBreakpoints } from "../../filters"; */ export type DialogBehaviour = "modal" | "popup"; +let openModalCounter: number = 0; + +function computeZIndexOfElement(element: HTMLElement): number { + let current = element; + + while (true) { + const zIndex = window.getComputedStyle(current).zIndex; + + if (zIndex !== "auto") { + return parseInt(zIndex); + } + + if (!current.parentElement) { + break; + } + + current = current.parentElement; + } + + return 0; +} + @Component({ - template: require('../../../components/ui/dialog.html'), inheritAttrs: false, + template: require('../../../components/ui/dialog.html'), }) export default class UiDialog extends Vue { @Prop({ type: String, default: "popup" }) @@ -41,11 +63,23 @@ export default class UiDialog extends Vue { private isMobile: boolean = false; + /** Inherited class hack */ + private staticClass: string[] = []; + + private zIndex: number = 1000; + private _focusOutEvent; private _resizeEvent; private _popper; + get attrs() { + return { + ...this.$attrs, + "class": this.staticClass + } + } + get currentBehaviour(): DialogBehaviour { if (!this.mobileBehaviour) { return this.behaviour; @@ -93,16 +127,60 @@ export default class UiDialog extends Vue { } mounted() { + this.zIndex = computeZIndexOfElement(this.getReferenceElement()) + 100; + this.handleWindowResize(); if (this.behaviour === 'popup') { - this.initPopper(); + this.mountPopper(); } + this.staticClass = Array.from(this.$el.classList).filter(cls => ["ui-backdrop", "ui-popup", "ui-popup--arrow"].indexOf(cls) === -1); + window.addEventListener('resize', this._resizeEvent = this.handleWindowResize.bind(this)); + + this._activated(); } - private initPopper() { + private _activated() { + if (this.behaviour === 'modal') { + this.mountModal(); + } + } + + private _deactivated() { + if (this.behaviour === 'modal') { + this.dismountModal(); + } + } + + private mountModal() { + if (openModalCounter === 0) { + document.body.style.paddingRight = `${window.screen.width - document.body.clientWidth}px` + document.body.classList.add('contains-modal'); + } + + openModalCounter++; + } + + private dismountModal() { + openModalCounter--; + + if (openModalCounter === 0) { + document.body.style.paddingRight = ""; + document.body.classList.remove('contains-modal'); + } + } + + activated() { + this._activated(); + } + + deactivated() { + this._deactivated(); + } + + private mountPopper() { const reference = this.getReferenceElement(); this._popper = new Popper(reference, this.$el, { @@ -147,6 +225,8 @@ export default class UiDialog extends Vue { beforeDestroy() { this._focusOutEvent && document.removeEventListener('click', this._focusOutEvent, { capture: true }); + + this._deactivated() } removed() { @@ -179,7 +259,15 @@ export default class UiDialog extends Vue { } if (newBehaviour === 'popup') { - this.$nextTick(() => this.initPopper()); + this.$nextTick(() => this.mountPopper()); + } + + if (newBehaviour === 'modal') { + this.mountModal(); + } + + if (oldBehaviour === 'modal') { + this.dismountModal(); } } } diff --git a/templates/app.html.twig b/templates/app.html.twig index 214d70c..90677c8 100644 --- a/templates/app.html.twig +++ b/templates/app.html.twig @@ -105,11 +105,9 @@ </button> </div> - <portal to="popups"> - <ui-dialog reference="settings-messages" v-if="visibility.messages" arrow placement="left-start" @leave="visibility.messages = false"> - <favourites-adder @saved="visibility.save = false"/> - </ui-dialog> - </portal> + <ui-dialog reference="save" v-if="visibility.save" arrow placement="bottom-end" @leave="visibility.save = false"> + <favourites-adder @saved="visibility.save = false"/> + </ui-dialog> </section> <section class="section picker"> <header class="section__title flex"> -- 2.45.2 From 9420764e9bcb68d5252768e65a542a3f54775352 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Fri, 2 Oct 2020 21:08:38 +0200 Subject: [PATCH 45/77] #62 - Fix some tiny errors related to background --- resources/components/stop/details.html | 10 ---------- resources/styles/_trip.scss | 3 +-- resources/styles/main.scss | 3 ++- resources/styles/ui/_modal.scss | 11 ++++++++++- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/resources/components/stop/details.html b/resources/components/stop/details.html index f04dc1c..dba5cda 100644 --- a/resources/components/stop/details.html +++ b/resources/components/stop/details.html @@ -22,16 +22,6 @@ </li> </ul> </section> - - <section> - <strong>Na mapie:</strong> - <div style="height: 350px" tabindex="-1"> - <l-map :center="stop.location" :zoom=17> - <l-tile-layer url="//{s}.tile.osm.org/{z}/{x}/{y}.png" attribution='© <a href="//osm.org/copyright">OpenStreetMap</a> contributors'></l-tile-layer> - <l-marker :lat-lng="stop.location"></l-marker> - </l-map> - </div> - </section> </div> <div v-else class="text-center"> <ui-icon icon="spinner"/> diff --git a/resources/styles/_trip.scss b/resources/styles/_trip.scss index 1f3020a..c0fc03a 100644 --- a/resources/styles/_trip.scss +++ b/resources/styles/_trip.scss @@ -60,11 +60,10 @@ $trip-visited: rgba($dark, .3); display: block; height: $trip-line-width; background: $dark; - width: 50%; + width: calc(50% - #{$trip-stop-marker-size / 2}); position: absolute; top: $trip-stop-marker-spacing + ($trip-stop-marker-size) / 2; transform: translateY(-50%); - z-index: -1; } &::after { diff --git a/resources/styles/main.scss b/resources/styles/main.scss index 63a5f4c..4f5aeee 100644 --- a/resources/styles/main.scss +++ b/resources/styles/main.scss @@ -123,7 +123,6 @@ body { main { flex: 1 1 auto; position: relative; - margin-bottom: 2rem; > * { transition: opacity .3s ease-in-out; @@ -159,6 +158,7 @@ body { font-size: small; color: $text-muted; text-align: right; + margin-top: 0.5rem; } footer { @@ -194,6 +194,7 @@ body { @include media-breakpoint-up('md') { #app { padding-top: 4rem; + padding-top: 2rem; } body footer > * { diff --git a/resources/styles/ui/_modal.scss b/resources/styles/ui/_modal.scss index 2192306..770be0b 100644 --- a/resources/styles/ui/_modal.scss +++ b/resources/styles/ui/_modal.scss @@ -18,7 +18,7 @@ } } -$dialog-margin: 1rem; +$dialog-margin: 2rem; $dialog-sizes: ( medium: 480px, small: 320px, @@ -32,6 +32,11 @@ $dialog-sizes: ( margin: auto; box-shadow: rgba(black, .7) 0 1px 3px; border-radius: 1px; + box-sizing: content-box; + + &.ui-modal--slim { + padding: $dialog-margin / 2; + } @each $size, $width in $dialog-sizes { &.ui-modal--#{$size} { @@ -61,6 +66,10 @@ $dialog-sizes: ( } @include media-breakpoint-down('sm') { + .ui-dialog { + padding: $dialog-margin / 2; + } + @each $size, $width in $dialog-sizes { .ui-modal.ui-modal--#{$size} { width: 100%; -- 2.45.2 From f2bdeb00044a2d8585bc27b46dd536d5beeeaa70 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Mon, 19 Oct 2020 23:11:37 +0200 Subject: [PATCH 46/77] #59 - add proper style for primary button --- resources/components/favourites/save.html | 9 ++++++--- resources/components/ui/dialog.html | 12 +++++++----- resources/styles/_controls.scss | 11 +++++++++++ resources/styles/main.scss | 3 ++- resources/styles/ui/_popup.scss | 4 ++++ templates/app.html.twig | 2 +- 6 files changed, 31 insertions(+), 10 deletions(-) diff --git a/resources/components/favourites/save.html b/resources/components/favourites/save.html index 8607252..6f31d62 100644 --- a/resources/components/favourites/save.html +++ b/resources/components/favourites/save.html @@ -5,9 +5,6 @@ <input class="form-control form-control-sm" placeholder="np. Z pracy" :class="{ 'is-invalid': errors.name.length > 0 }" id="favourite_add_name" v-model="name" v-autofocus/> - <button class="btn btn-sm btn-dark" type="submit"> - <ui-icon icon="add" /> - </button> <div v-if="errors.name.length > 0" class="invalid-feedback"> <p v-for="error in errors.name">{{ error }}</p> </div> @@ -18,4 +15,10 @@ <stop :stop="stop"/> </li> </ul> + <div class="favourite-add-form__actions"> + <button class="btn btn-sm btn-primary" type="submit"> + <ui-icon icon="add" /> + zapisz + </button> + </div> </form> diff --git a/resources/components/ui/dialog.html b/resources/components/ui/dialog.html index 8117b2e..8a8f2d8 100644 --- a/resources/components/ui/dialog.html +++ b/resources/components/ui/dialog.html @@ -1,9 +1,9 @@ -<div class="ui-backdrop" @click="handleBackdropClick" v-if="currentBehaviour === 'modal'"> +<div class="ui-backdrop" @click="handleBackdropClick" v-if="currentBehaviour === 'modal'" role="dialog"> <div class="ui-modal" v-bind="attrs" v-on="$listeners"> <div class="ui-modal__top-bar"> <div class="ui-modal__header"> <slot name="header"> - <div class="ui-modal__title"><slot name="title">{{ title }}</slot></div> + <div class="ui-modal__title" role="heading"><slot name="title">{{ title }}</slot></div> </slot> </div> <button class="btn btn-action ui-modal__close" @click.prevent="handleCloseClick"> @@ -16,10 +16,12 @@ </div> </div> </div> -<div :class="[ 'ui-popup', arrow && 'ui-popup--arrow' ]" v-bind="attrs" :style="{ zIndex: zIndex }" v-on="$listeners" v-else> +<div :class="[ 'ui-popup', arrow && 'ui-popup--arrow' ]" v-bind="attrs" :style="{ zIndex: zIndex }" v-on="$listeners" role="dialog" v-else> <div class="ui-popup__arrow" ref="arrow" v-if="arrow"></div> - <div class="ui-popup__header" v-if="hasHeader"> - <slot name="header" /> + <div class="ui-popup__header" v-if="hasHeader || title"> + <slot name="header"> + <div class="ui-popup__heading" role="heading"><slot name="title">{{ title }}</slot></div> + </slot> </div> <slot /> <div class="ui-popup__footer" v-if="hasFooter"> diff --git a/resources/styles/_controls.scss b/resources/styles/_controls.scss index 818cfae..6a479c8 100644 --- a/resources/styles/_controls.scss +++ b/resources/styles/_controls.scss @@ -13,9 +13,20 @@ } } + border-radius: 1.5px; + display: inline-block; &.btn-outline-action { @extend .btn-outline-dark; } + + &.btn-primary { + background: $primary-gradient; + border-color: transparent; + + &:hover { + border: 1px $primary solid; + } + } } diff --git a/resources/styles/main.scss b/resources/styles/main.scss index 4f5aeee..67dc67a 100644 --- a/resources/styles/main.scss +++ b/resources/styles/main.scss @@ -1,4 +1,4 @@ -$border-radius: 0; +$border-radius: 0; $border-radius-lg: $border-radius; $border-radius-sm: $border-radius; @@ -7,6 +7,7 @@ $border-radius-sm: $border-radius; @import "~bootstrap/scss/variables"; $primary: #005ea8; +$primary-gradient: linear-gradient(120deg, #0083c5 10%, #005ea8 90%); $custom-control-indicator-checked-bg: $dark; $custom-control-indicator-active-bg: $dark; diff --git a/resources/styles/ui/_popup.scss b/resources/styles/ui/_popup.scss index 384d6c2..90a42d6 100644 --- a/resources/styles/ui/_popup.scss +++ b/resources/styles/ui/_popup.scss @@ -84,6 +84,10 @@ padding: 0; } + *.ui-popup__header { + margin-bottom: 0.5rem; + } + .ui-popup__heading { font-size: $font-size-sm; font-weight: bold; diff --git a/templates/app.html.twig b/templates/app.html.twig index 90677c8..493012c 100644 --- a/templates/app.html.twig +++ b/templates/app.html.twig @@ -105,7 +105,7 @@ </button> </div> - <ui-dialog reference="save" v-if="visibility.save" arrow placement="bottom-end" @leave="visibility.save = false"> + <ui-dialog reference="save" v-if="visibility.save" arrow placement="bottom-end" @leave="visibility.save = false" title="Dodaj do ulubionych"> <favourites-adder @saved="visibility.save = false"/> </ui-dialog> </section> -- 2.45.2 From f49c7287fd259e8d14f0a0bd8c9b9a8667f922ad Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Tue, 20 Oct 2020 21:10:56 +0200 Subject: [PATCH 47/77] #59 - Add ability to replace favourite with confirmation. --- resources/components/favourites/save.html | 18 ++++++++++++++---- resources/styles/_controls.scss | 15 +++++++++++++++ resources/styles/main.scss | 2 ++ resources/styles/ui/_modal.scss | 1 + resources/ts/components/favourites.ts | 15 +++++++++++---- resources/ts/components/ui/icon.ts | 18 ++++++++++-------- resources/ts/store/favourites.ts | 9 ++++++++- resources/ts/utils.ts | 8 ++++++++ 8 files changed, 69 insertions(+), 17 deletions(-) diff --git a/resources/components/favourites/save.html b/resources/components/favourites/save.html index 6f31d62..0347554 100644 --- a/resources/components/favourites/save.html +++ b/resources/components/favourites/save.html @@ -16,9 +16,19 @@ </li> </ul> <div class="favourite-add-form__actions"> - <button class="btn btn-sm btn-primary" type="submit"> - <ui-icon icon="add" /> - zapisz - </button> + <template v-if="confirmation"> + <button class="btn btn-xs btn-danger" type="submit"> + nadpisz + </button> + <button class="btn btn-xs btn-action" @click="$emit('close')"> + anuluj + </button> + </template> + <template v-else> + <button class="btn btn-xs btn-primary" type="submit"> + <ui-icon icon="add" /> + zapisz + </button> + </template> </div> </form> diff --git a/resources/styles/_controls.scss b/resources/styles/_controls.scss index 6a479c8..e8879c4 100644 --- a/resources/styles/_controls.scss +++ b/resources/styles/_controls.scss @@ -13,6 +13,12 @@ } } + &.btn-xs { + font-size: 0.75rem; + font-weight: bold; + padding: 0.25rem 0.5rem; + } + border-radius: 1.5px; display: inline-block; @@ -29,4 +35,13 @@ border: 1px $primary solid; } } + + &.btn-danger { + background: $danger-gradient; + border-color: transparent; + + &:hover { + border: 1px $danger solid; + } + } } diff --git a/resources/styles/main.scss b/resources/styles/main.scss index 67dc67a..ada8ede 100644 --- a/resources/styles/main.scss +++ b/resources/styles/main.scss @@ -2,12 +2,14 @@ $border-radius: 0; $border-radius-lg: $border-radius; $border-radius-sm: $border-radius; +$danger: #cd2e12; @import "~bootstrap/scss/functions"; @import "~bootstrap/scss/variables"; $primary: #005ea8; $primary-gradient: linear-gradient(120deg, #0083c5 10%, #005ea8 90%); +$danger-gradient: linear-gradient(120deg, $danger 10%, darken($danger, 10%) 90%); $custom-control-indicator-checked-bg: $dark; $custom-control-indicator-active-bg: $dark; diff --git a/resources/styles/ui/_modal.scss b/resources/styles/ui/_modal.scss index 770be0b..242138c 100644 --- a/resources/styles/ui/_modal.scss +++ b/resources/styles/ui/_modal.scss @@ -73,6 +73,7 @@ $dialog-sizes: ( @each $size, $width in $dialog-sizes { .ui-modal.ui-modal--#{$size} { width: 100%; + box-sizing: border-box; } } } diff --git a/resources/ts/components/favourites.ts b/resources/ts/components/favourites.ts index 5a5f5bf..a7e0fd1 100644 --- a/resources/ts/components/favourites.ts +++ b/resources/ts/components/favourites.ts @@ -1,8 +1,7 @@ import Vue from 'vue' -import { Component, Prop } from 'vue-property-decorator' -import { namespace, State, Mutation } from "vuex-class"; +import { Component, Watch } from 'vue-property-decorator' +import { Mutation, State } from "vuex-class"; import { Favourite } from "../store/favourites"; -import { SavedState } from "../store/root"; import { Stop } from "../model"; import * as uuid from "uuid"; import { Favourites } from "../store"; @@ -34,8 +33,15 @@ export class FavouritesAdderComponent extends Vue { private name = ""; private errors = { name: [] }; + private confirmation = false; + @Favourites.Mutation add: (favourite: Favourite) => void; + @Watch('name') + handleNameChange() { + this.confirmation = false; + } + async save() { const favourite: Favourite = createFavouriteEntry(this.name, this.stops); @@ -54,8 +60,9 @@ export class FavouritesAdderComponent extends Vue { errors.name.push("Musisz podać nazwę."); } - if (this.$store.state.favourites.favourites.filter(other => other.name == favourite.name).length > 0) { + if (this.$store.state.favourites.favourites.filter(other => other.name == favourite.name).length > 0 && !this.confirmation) { errors.name.push("Istnieje już zapisana grupa przystanków o takiej nazwie."); + this.confirmation = true; } this.errors = errors; diff --git a/resources/ts/components/ui/icon.ts b/resources/ts/components/ui/icon.ts index b25535a..2dad8a9 100644 --- a/resources/ts/components/ui/icon.ts +++ b/resources/ts/components/ui/icon.ts @@ -53,12 +53,12 @@ const simple = (icon: IconDefinition, props: any = {}): SimpleIcon => ({ icon, ...props, type: "simple" }); -const stack = (icons: IconDescription[]): StackedIcon => ({type: "stacked", icons}); +const stack = (icons: IconDescription[]): StackedIcon => ({ type: "stacked", icons }); const lineTypeIcons = Object .values(fac) - .map<[string, Icon]>(icon => [ `line-${icon.iconName}`, simple(icon) ]) - .reduce((acc, [icon, definition]) => ({ ...acc, [icon]: definition}), {}) + .map<[string, Icon]>(icon => [`line-${ icon.iconName }`, simple(icon)]) + .reduce((acc, [icon, definition]) => ({ ...acc, [icon]: definition }), {}) const messageTypeIcons: Dictionary<Icon> = { 'message-breakdown': simple(faExclamationTriangle), @@ -66,7 +66,7 @@ const messageTypeIcons: Dictionary<Icon> = { 'message-unknown': simple(faQuestionCircle), }; -const definitions: Dictionary<Icon> = { +const definitions = { 'favourite': simple(faStar), 'unknown': simple(faQuestionSquare), 'add': simple(faCheck), @@ -93,14 +93,16 @@ const definitions: Dictionary<Icon> = { 'decrement': simple(faMinus, { "fixed-width": true }), 'relative-time': simple(faHourglassHalf), 'departure-warning': stack([ - {icon: faClockBold}, - {icon: faSolidExclamationTriangle, transform: "shrink-5 down-4 right-6"} + { icon: faClockBold }, + { icon: faSolidExclamationTriangle, transform: "shrink-5 down-4 right-6" } ]), 'close': simple(faTimes), ...lineTypeIcons, ...messageTypeIcons, }; +export type PredefinedIcon = keyof typeof definitions; + const extractAllIcons = (icons: Icon[]) => icons.map(icon => { switch (icon.type) { case "simple": @@ -122,11 +124,11 @@ library.add(...extractAllIcons(Object.values(definitions))); }) export class UiIcon extends Vue { @Prop({ - type: [ String, Object ], + type: [String, Object], validator: value => typeof value === "object" || Object.keys(definitions).includes(value), required: true, }) - icon: string | IconDefinition; + icon: PredefinedIcon | IconDefinition; get definition(): Icon { return typeof this.icon === "string" diff --git a/resources/ts/store/favourites.ts b/resources/ts/store/favourites.ts index 0f61f68..94f608e 100644 --- a/resources/ts/store/favourites.ts +++ b/resources/ts/store/favourites.ts @@ -1,6 +1,7 @@ import { RootState } from "./root"; import { Module } from "vuex"; import { Stop } from "../model"; +import { except } from "../utils"; export interface Favourite { id: string; @@ -19,7 +20,13 @@ const favourites: Module<FavouritesState, RootState> = { }, mutations: { add(state, favourite: Favourite) { - state.favourites.push(favourite); + const existing = state.favourites.find((current: Favourite) => current.name === favourite.name); + + if (!existing) { + state.favourites.push(favourite); + } + + Object.assign(existing, except(favourite, ["id"])); }, remove(state, favourite: Favourite) { state.favourites = state.favourites.filter(f => f != favourite); diff --git a/resources/ts/utils.ts b/resources/ts/utils.ts index d7d6a22..213ee92 100644 --- a/resources/ts/utils.ts +++ b/resources/ts/utils.ts @@ -38,6 +38,14 @@ export function filter<T, KT extends keyof T>(source: T, filter: (value: T[KT], return result; } +export function except<T>(source: T, keys: (keyof T)[]) { + return filter(source, (_, key) => !keys.includes(key)) +} + +export function only<T>(source: T, keys: (keyof T)[]) { + return filter(source, (_, key) => keys.includes(key)) +} + export function signed(number: number): string { return number > 0 ? `+${number}` : number.toString(); } -- 2.45.2 From aff94c1c0603866f659e2d8a4136d45a6ea935ec Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 1 Nov 2020 12:11:20 +0100 Subject: [PATCH 48/77] #62 - history of added stops --- resources/components/finder.html | 5 +- resources/components/picker/stop.html | 34 ++++++------- resources/components/stop/history.html | 11 +++++ resources/styles/_stop.scss | 6 ++- resources/ts/components/history.ts | 13 +++++ resources/ts/components/picker.ts | 15 +++++- resources/ts/components/ui/icon.ts | 2 + resources/ts/store/history.ts | 66 ++++++++++++++++++++++++++ resources/ts/store/index.ts | 10 ++-- templates/app.html.twig | 4 +- 10 files changed, 140 insertions(+), 26 deletions(-) create mode 100644 resources/components/stop/history.html create mode 100644 resources/ts/components/history.ts create mode 100644 resources/ts/store/history.ts diff --git a/resources/components/finder.html b/resources/components/finder.html index 7f34e33..8e309a2 100644 --- a/resources/components/finder.html +++ b/resources/components/finder.html @@ -3,6 +3,7 @@ <div v-if="filter.length < 3" class="mt-2"> <favourites /> + <stop-history /> </div> <div v-if="state === 'fetching'" class="text-center p-4"> @@ -22,9 +23,9 @@ </div> <ul class="stop-group__stops list-underlined"> <li v-for="stop in group" :key="stop.id" class="d-flex"> - <picker-stop :stop="stop" class="flex-grow-1"> + <picker-stop :stop="stop" class="flex-grow-1 finder__stop"> <template v-slot:primary-action> - <button @click="select(stop, $event)" class="btn btn-action"> + <button @click="select(stop, $event)" class="btn btn-action stretched-link"> <tooltip>dodaj przystanek</tooltip> <ui-icon icon="add" /> </button> diff --git a/resources/components/picker/stop.html b/resources/components/picker/stop.html index 63e3ebb..626dc17 100644 --- a/resources/components/picker/stop.html +++ b/resources/components/picker/stop.html @@ -1,23 +1,25 @@ -<div class="finder__stop"> +<div> <div class="d-flex"> - <slot name="primary-action" /> - <div class="overflow-hidden align-self-center"> - <stop :stop="stop" /> - <div class="stop__destinations" v-if="destinations && destinations.length > 0"> - <ul class="ml-1"> - <li class="stop__destination destination" v-for="destination in destinations" :key="destination.stop.id"> - <ul class="destination__lines"> - <li v-for="line in destination.lines"> - <line-symbol :line="line" :key="line.symbol" simple/> - </li> - </ul> - <span class="destination__name ml-1">{{ destination.stop.name }}</span> - </li> - </ul> + <div class="d-flex position-relative" style="min-width: 0"> + <slot name="primary-action" /> + <div class="overflow-hidden align-self-center"> + <stop :stop="stop" /> + <div class="stop__destinations" v-if="destinations && destinations.length > 0"> + <ul> + <li class="stop__destination destination" v-for="destination in destinations" :key="destination.stop.id"> + <ul class="destination__lines"> + <li v-for="line in destination.lines"> + <line-symbol :line="line" :key="line.symbol" simple/> + </li> + </ul> + <span class="destination__name ml-1">{{ destination.stop.name }}</span> + </li> + </ul> + </div> </div> </div> - <div class="stop__actions flex-space-left"> + <div class="stop__actions"> <slot name="actions"> <button class="btn btn-action" ref="action-info" @click="details = !details"> <tooltip>dodatkowe informacje</tooltip> diff --git a/resources/components/stop/history.html b/resources/components/stop/history.html new file mode 100644 index 0000000..945d672 --- /dev/null +++ b/resources/components/stop/history.html @@ -0,0 +1,11 @@ +<ul class="list-underlined history" v-if="all.length > 0"> + <li v-for="entry in all" class="history__entry"> + <picker-stop :stop="entry.stop" class="flex-grow-1 finder__stop"> + <template v-slot:primary-action> + <button @click="select(entry.stop, $event)" class="btn btn-action stretched-link"> + <ui-icon icon="history" /> + </button> + </template> + </picker-stop> + </li> +</ul> diff --git a/resources/styles/_stop.scss b/resources/styles/_stop.scss index e72315f..b695a2c 100644 --- a/resources/styles/_stop.scss +++ b/resources/styles/_stop.scss @@ -76,8 +76,12 @@ .stop-group__header { @extend .section__title; display: flex; - padding: 0 !important; margin-bottom: 0 !important; + + .actions { + margin: -.5rem -.75rem; + margin-left: auto; + } } .stop-group__name { diff --git a/resources/ts/components/history.ts b/resources/ts/components/history.ts new file mode 100644 index 0000000..3f1260f --- /dev/null +++ b/resources/ts/components/history.ts @@ -0,0 +1,13 @@ +import Component from "vue-class-component"; +import Vue from "vue"; +import { History } from "../store"; +import { HistoryEntry } from "../store/history"; +import { Mutation } from "vuex-class"; +import { Stop } from "../model"; + +@Component({ template: require('../../components/stop/history.html' )}) +export class StopHistory extends Vue { + @History.Getter all: HistoryEntry[]; + + @Mutation("add") select: (stops: Stop[]) => void; +} diff --git a/resources/ts/components/picker.ts b/resources/ts/components/picker.ts index 4dbac37..2faa73a 100644 --- a/resources/ts/components/picker.ts +++ b/resources/ts/components/picker.ts @@ -1,10 +1,13 @@ import Component from "vue-class-component"; import Vue from "vue"; -import { Destination, Line, StopWithDestinations as Stop, StopGroup, StopGroups } from "../model"; +import { Line, StopGroup, StopGroups, StopWithDestinations as Stop } from "../model"; import { Prop, Watch } from "vue-property-decorator"; import { FetchingState, filter, map, match, unique } from "../utils"; import { debounce } from "../decorators"; import urls from '../urls'; +import { Mutation } from "vuex-class"; +import { HistoryEntry } from "../store/history"; +import { StopHistory } from "./history"; @Component({ template: require('../../components/picker/stop.html') }) export class PickerStopComponent extends Vue { @@ -49,7 +52,8 @@ export class PickerStopComponent extends Vue { @Component({ template: require('../../components/finder.html'), components: { - "PickerStop": PickerStopComponent + "PickerStop": PickerStopComponent, + "StopHistory": StopHistory, } }) export class FinderComponent extends Vue { @@ -61,6 +65,8 @@ export class FinderComponent extends Vue { @Prop({default: [], type: Array}) public blacklist: Stop[]; + @Mutation('history/push') pushToHistory: (entry: HistoryEntry) => void; + get filtered(): StopGroups { const groups = map( this.found, @@ -91,6 +97,11 @@ export class FinderComponent extends Vue { } private select(stop) { + this.pushToHistory({ + date: this.$moment(), + stop: stop, + }) + this.$emit('select', stop); } } diff --git a/resources/ts/components/ui/icon.ts b/resources/ts/components/ui/icon.ts index 2dad8a9..6e80aa0 100644 --- a/resources/ts/components/ui/icon.ts +++ b/resources/ts/components/ui/icon.ts @@ -12,6 +12,7 @@ import { faClock, faCog, faExclamationTriangle, + faHistory, faHourglassHalf, faInfoCircle, faMapMarkerAlt, @@ -97,6 +98,7 @@ const definitions = { { icon: faSolidExclamationTriangle, transform: "shrink-5 down-4 right-6" } ]), 'close': simple(faTimes), + 'history': simple(faHistory), ...lineTypeIcons, ...messageTypeIcons, }; diff --git a/resources/ts/store/history.ts b/resources/ts/store/history.ts new file mode 100644 index 0000000..dcfc805 --- /dev/null +++ b/resources/ts/store/history.ts @@ -0,0 +1,66 @@ +import { Stop } from "../model"; +import { Module } from "vuex"; +import { RootState } from "./root"; +import * as moment from "moment"; +import { Moment } from "moment"; +import { Jsonified } from "../utils"; + +export interface HistoryEntry { + stop: Stop, + date: Moment, +} + +export interface HistorySettings { + maxEntries: number, +} + +export interface HistoryState { + entries: Jsonified<HistoryEntry>[], + settings: HistorySettings, +} + +export function serializeHistoryEntry(entry: HistoryEntry): Jsonified<HistoryEntry> { + return { + ...entry, + date: entry.date.toISOString(), + } +} + +export function deserializeHistoryEntry(serialized: Jsonified<HistoryEntry>): HistoryEntry { + return { + ...serialized, + date: moment(serialized.date), + } +} + +export const history: Module<HistoryState, RootState> = { + namespaced: true, + state: { + entries: [], + settings: { + maxEntries: 10, + } + }, + mutations: { + clear(state: HistoryState) { + state.entries = []; + }, + push(state: HistoryState, entry: HistoryEntry) { + state.entries = state.entries.filter(cur => cur.stop.id != entry.stop.id); + state.entries.unshift(serializeHistoryEntry(entry)); + + if (state.entries.length > state.settings.maxEntries) { + state.entries = state.entries.slice(0, state.settings.maxEntries); + } + }, + saveSettings(state: HistoryState, settings: Partial<HistorySettings>) { + Object.assign(state.settings, settings); + } + }, + getters: { + all: ({ entries, settings }) => entries.slice(0, settings.maxEntries).map(deserializeHistoryEntry), + latest: ({ entries }) => n => entries.slice(0, n).map(deserializeHistoryEntry), + } +} + +export default history; diff --git a/resources/ts/store/index.ts b/resources/ts/store/index.ts index bd4e43a..326c361 100644 --- a/resources/ts/store/index.ts +++ b/resources/ts/store/index.ts @@ -3,6 +3,7 @@ import Vuex from 'vuex'; import messages, { MessagesState } from './messages'; import departures, { DeparturesState } from './departures' import favourites, { FavouritesState } from './favourites' +import history, { HistoryState } from "./history"; import departureSettings, { DeparturesSettingsState } from "./settings/departures"; import messagesSettings, { MessagesSettingsState } from "./settings/messages"; @@ -14,12 +15,13 @@ export type State = { messages: MessagesState; departures: DeparturesState; favourites: FavouritesState; - "departures-settings": DeparturesSettingsState, - "messages-settings": MessagesSettingsState, + "departures-settings": DeparturesSettingsState; + "messages-settings": MessagesSettingsState; + history: HistoryState; } & RootState; const localStoragePersist = new VuexPersistence<State>({ - modules: ['favourites', 'departures-settings', 'messages-settings'], + modules: ['favourites', 'departures-settings', 'messages-settings', 'history'], }); const sessionStoragePersist = new VuexPersistence<State>({ @@ -35,6 +37,7 @@ const store = new Vuex.Store<RootState>({ favourites, 'departures-settings': departureSettings, 'messages-settings': messagesSettings, + history, }, plugins: [ localStoragePersist.plugin, @@ -49,3 +52,4 @@ export const DeparturesSettings = namespace('departures-settings'); export const MessagesSettings = namespace('messages-settings'); export const Departures = namespace('departures'); export const Messages = namespace('messages'); +export const History = namespace('history'); diff --git a/templates/app.html.twig b/templates/app.html.twig index 493012c..c6cc468 100644 --- a/templates/app.html.twig +++ b/templates/app.html.twig @@ -86,8 +86,8 @@ </header> <ul class="picker__stops list-underlined"> - <li v-for="stop in stops" :key="stop.id" class="d-flex align-items-center"> - <picker-stop :stop="stop" class="flex-grow-1"> + <li v-for="stop in stops" :key="stop.id" class="picker__stop"> + <picker-stop :stop="stop"> <template v-slot:primary-action> <button @click="remove(stop)" class="btn btn-action"> <tooltip>usuń przystanek</tooltip> -- 2.45.2 From e7717016c76f918d15df78a28bf94ca8c87b71e2 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 1 Nov 2020 17:57:06 +0100 Subject: [PATCH 49/77] #50 - split front and api parts --- .gitignore | 18 ------- .env.dist => api/.env.dist | 0 api/.gitignore | 16 +++++++ {docker/php => api}/Dockerfile | 0 {bin => api/bin}/console | 0 composer.json => api/composer.json | 0 composer.lock => api/composer.lock | 0 {config => api/config}/bundles.php | 0 .../config}/packages/dev/jms_serializer.yaml | 0 .../config}/packages/dev/monolog.yaml | 0 .../config}/packages/dev/routing.yaml | 0 .../config}/packages/dev/web_profiler.yaml | 0 {config => api/config}/packages/doctrine.yaml | 0 .../config}/packages/doctrine_migrations.yaml | 0 .../config}/packages/framework.yaml | 0 .../config}/packages/jms_serializer.yaml | 0 .../config}/packages/nelmio_api_doc.yaml | 0 .../config}/packages/prod/doctrine.yaml | 0 .../config}/packages/prod/jms_serializer.yaml | 0 .../config}/packages/prod/monolog.yaml | 0 {config => api/config}/packages/routing.yaml | 0 .../packages/sensio_framework_extra.yaml | 0 .../config}/packages/test/framework.yaml | 0 .../config}/packages/test/monolog.yaml | 0 .../config}/packages/test/web_profiler.yaml | 0 .../config}/packages/translation.yaml | 0 {config => api/config}/packages/twig.yaml | 0 {config => api/config}/routes.yaml | 0 .../config}/routes/annotations.yaml | 0 {config => api/config}/routes/dev/twig.yaml | 0 .../config}/routes/dev/web_profiler.yaml | 0 .../config}/routes/nelmio_api_doc.yaml | 0 {config => api/config}/services.yaml | 0 {public => api/public}/index.php | 0 ruleset.xml => api/ruleset.xml | 0 .../Asset/ModifiedTimeVersionStrategy.php | 0 {src => api/src}/Command/UpdateCommand.php | 0 {src => api/src}/Controller/.gitignore | 0 .../Api/v1/DeparturesController.php | 0 .../Controller/Api/v1/MessagesController.php | 0 .../Controller/Api/v1/ProviderController.php | 0 .../Controller/Api/v1/StopsController.php | 0 .../Controller/Api/v1/TracksController.php | 0 .../src}/Controller/Api/v1/TripController.php | 0 {src => api/src}/Controller/Controller.php | 0 .../src}/Controller/MainController.php | 0 .../src}/Doctrine/CarbonDateTimeType.php | 0 {src => api/src}/Entity/Entity.php | 0 {src => api/src}/Entity/LineEntity.php | 0 {src => api/src}/Entity/OperatorEntity.php | 0 {src => api/src}/Entity/ProviderEntity.php | 0 .../src}/Entity/ProviderReferenceTrait.php | 0 .../src}/Entity/ReferableEntityTrait.php | 0 {src => api/src}/Entity/StopEntity.php | 0 {src => api/src}/Entity/TrackEntity.php | 0 {src => api/src}/Entity/TrackStopEntity.php | 0 {src => api/src}/Entity/TripEntity.php | 0 {src => api/src}/Entity/TripStopEntity.php | 0 {src => api/src}/Event/DataUpdateEvent.php | 0 .../Event/HandleDatabaseModifierEvent.php | 0 .../src}/Event/HandleModifierEvent.php | 0 {src => api/src}/Event/PostProcessEvent.php | 0 .../Exception/InvalidArgumentException.php | 0 .../Exception/NonExistentServiceException.php | 0 .../src}/Exception/NotSupportedException.php | 0 .../UnsupportedModifierException.php | 0 {src => api/src}/Functions/helpers.php | 0 {src => api/src}/Functions/index.php | 0 .../Database/FieldFilterDatabaseHandler.php | 0 .../Database/GenericWithDatabaseHandler.php | 0 .../Database/IdFilterDatabaseHandler.php | 0 .../Handler/Database/LimitDatabaseHandler.php | 0 .../RelatedFilterDatabaseGenericHandler.php | 0 .../Database/TrackByStopDatabaseHandler.php | 0 .../WithDestinationsDatabaseHandler.php | 0 {src => api/src}/Handler/ModifierHandler.php | 0 .../src}/Handler/PostProcessingHandler.php | 0 {src => api/src}/Kernel.php | 0 {src => api/src}/Migrations/.gitignore | 0 .../src}/Migrations/Version20180907212032.php | 0 .../src}/Migrations/Version20181027124203.php | 0 .../src}/Migrations/Version20190111212909.php | 0 .../src}/Migrations/Version20200103160747.php | 0 .../src}/Migrations/Version20200103170517.php | 0 .../src}/Migrations/Version20200131151757.php | 0 .../src}/Migrations/Version20200206183956.php | 0 .../src}/Migrations/Version20200314112552.php | 0 {src => api/src}/Model/Departure.php | 0 {src => api/src}/Model/Destination.php | 0 {src => api/src}/Model/FillTrait.php | 0 {src => api/src}/Model/Fillable.php | 0 {src => api/src}/Model/JustReference.php | 0 {src => api/src}/Model/Line.php | 0 {src => api/src}/Model/Location.php | 0 {src => api/src}/Model/Message.php | 0 {src => api/src}/Model/Operator.php | 0 {src => api/src}/Model/Provider.php | 0 {src => api/src}/Model/Referable.php | 0 {src => api/src}/Model/ReferableTrait.php | 0 {src => api/src}/Model/ScheduledStop.php | 0 {src => api/src}/Model/Stop.php | 0 {src => api/src}/Model/StopGroup.php | 0 {src => api/src}/Model/Track.php | 0 {src => api/src}/Model/TrackStop.php | 0 {src => api/src}/Model/Trip.php | 0 {src => api/src}/Model/Vehicle.php | 0 {src => api/src}/Modifier/FieldFilter.php | 0 {src => api/src}/Modifier/IdFilter.php | 0 {src => api/src}/Modifier/Limit.php | 0 {src => api/src}/Modifier/Modifier.php | 0 {src => api/src}/Modifier/RelatedFilter.php | 0 {src => api/src}/Modifier/With.php | 0 .../Provider/Database/DatabaseRepository.php | 0 .../Database/GenericLineRepository.php | 0 .../Database/GenericOperatorRepository.php | 0 .../Database/GenericScheduleRepository.php | 0 .../Database/GenericStopRepository.php | 0 .../Database/GenericTrackRepository.php | 0 .../Database/GenericTripRepository.php | 0 .../src}/Provider/DepartureRepository.php | 0 .../Dummy/DummyDepartureRepository.php | 0 .../Provider/Dummy/DummyMessageRepository.php | 0 .../src}/Provider/Dummy/DummyProvider.php | 0 .../Provider/Dummy/DummyStopRepository.php | 0 .../src}/Provider/FluentRepository.php | 0 {src => api/src}/Provider/LineRepository.php | 0 .../src}/Provider/MessageRepository.php | 0 .../src}/Provider/OperatorRepository.php | 0 {src => api/src}/Provider/Provider.php | 0 {src => api/src}/Provider/Repository.php | 0 .../src}/Provider/ScheduleRepository.php | 0 {src => api/src}/Provider/StopRepository.php | 0 {src => api/src}/Provider/TrackRepository.php | 0 {src => api/src}/Provider/TripRepository.php | 0 .../ZtmGdanskDataUpdateSubscriber.php | 0 .../ZtmGdanskDepartureRepository.php | 0 .../ZtmGdansk/ZtmGdanskMessageRepository.php | 0 .../ZtmGdanskMessageTypeClassifier.php | 0 .../Provider/ZtmGdansk/ZtmGdanskProvider.php | 0 .../src}/Serialization/CarbonHandler.php | 0 .../LaravelCollectionHandler.php | 0 .../src}/Serialization/SerializeAs.php | 0 .../src}/Service/AggregateConverter.php | 0 .../src}/Service/CacheableConverter.php | 0 {src => api/src}/Service/Converter.php | 0 {src => api/src}/Service/DataUpdater.php | 0 {src => api/src}/Service/EntityConverter.php | 0 .../src}/Service/EntityReferenceFactory.php | 0 {src => api/src}/Service/HandlerProvider.php | 0 {src => api/src}/Service/IdUtils.php | 0 {src => api/src}/Service/IterableUtils.php | 0 {src => api/src}/Service/ModifierUtils.php | 0 .../Normalizer/JustReferenceNormalizer.php | 0 .../Service/Normalizer/StopNormalizer.php | 0 .../src}/Service/ProviderConverter.php | 0 .../Service/ProviderParameterConverter.php | 0 {src => api/src}/Service/ProviderResolver.php | 0 .../src}/Service/Proxy/ReferenceFactory.php | 0 .../Proxy/ReferenceObjectGenerator.php | 0 .../src}/Service/RecursiveConverter.php | 0 .../src}/Service/RecursiveConverterTrait.php | 0 .../Service/RepositoryParameterConverter.php | 0 .../src}/Service/ScheduledStopConverter.php | 0 .../src}/Service/SerializerContextFactory.php | 0 {src => api/src}/Service/VersionExtension.php | 0 .../JustReferenceSerializationSubscriber.php | 0 symfony.lock => api/symfony.lock | 0 {templates => api/templates}/app.html.twig | 0 {templates => api/templates}/base.html.twig | 8 ++-- .../SwaggerUi/index.html.twig | 0 {templates => api/templates}/choose.html.twig | 0 .../templates}/manifest.json.twig | 0 {translations => api/translations}/.gitignore | 0 docker-compose.yml | 11 ++--- docker/nginx/czydojade | 44 ++++++++++-------- front/.gitignore | 5 ++ package.json => front/package.json | 0 front/public/.gitkeep | 0 .../resources}/components/departures.html | 0 .../components/departures/departure.html | 0 .../resources}/components/favourites.html | 0 .../components/favourites/save.html | 0 .../resources}/components/finder.html | 0 .../resources}/components/fold.html | 0 .../resources}/components/lazy.html | 0 .../resources}/components/line.html | 0 .../resources}/components/messages.html | 0 .../resources}/components/page/providers.html | 0 .../resources}/components/picker/stop.html | 0 .../components/settings/departures.html | 0 .../components/settings/messages.html | 0 .../resources}/components/stop.html | 0 .../resources}/components/stop/details.html | 0 .../resources}/components/stop/history.html | 0 .../resources}/components/stop/map.html | 0 .../resources}/components/tooltip.html | 0 .../resources}/components/trip.html | 0 .../resources}/components/ui/dialog.html | 0 .../resources}/components/ui/icon.html | 0 .../resources}/components/ui/numeric.html | 0 .../resources}/components/ui/switch.html | 0 .../resources}/icons/light/bus.svg | 0 .../resources}/icons/light/icons.ai | 0 .../resources}/icons/light/metro.svg | 0 .../resources}/icons/light/train.svg | 0 .../resources}/icons/light/tram.svg | 0 .../resources}/icons/light/trolleybus.svg | 0 .../resources}/icons/light/unknown.svg | 0 .../resources}/images/app-icon.ai | 0 .../resources}/images/background-2x.png | Bin .../resources}/images/background.png | Bin .../resources}/images/favicon-2x.png | Bin .../resources}/images/favicon-72.png | Bin .../resources}/images/favicon.ai | 0 .../resources}/images/favicon.ico | Bin .../resources}/images/favicon.png | Bin .../resources}/images/icon-128.png | Bin .../resources}/images/icon-192.png | Bin .../resources}/images/icon-256.png | Bin .../resources}/images/icon-512.png | Bin .../resources}/images/icon-64.png | Bin .../resources}/images/icon-96.png | Bin .../resources}/images/icon-maskable.png | Bin .../resources}/images/icon-monochrome.png | Bin .../resources}/images/ios-192.png | Bin .../resources}/images/ios-80.png | Bin {resources => front/resources}/images/ios.png | Bin .../resources}/images/kadet-net-logo.png | Bin .../resources}/images/logo-cojedzie.ai | 0 .../resources}/images/logo-concepts.ai | 0 .../resources}/images/logo-superhi.png | Bin .../resources}/images/logo-vector.svg | 0 {resources => front/resources}/images/logo.ai | 0 .../resources}/images/logo.png | Bin .../resources}/styles/_animations.scss | 0 .../resources}/styles/_common.scss | 0 .../resources}/styles/_controls.scss | 0 .../resources}/styles/_departure.scss | 0 .../resources}/styles/_dragscroll.scss | 0 .../resources}/styles/_favourites.scss | 0 .../resources}/styles/_form.scss | 0 .../resources}/styles/_line.scss | 0 .../resources}/styles/_map.scss | 0 .../resources}/styles/_stop.scss | 0 .../resources}/styles/_trigonometry.scss | 0 .../resources}/styles/_trip.scss | 0 .../resources}/styles/api.scss | 0 .../resources}/styles/main.scss | 0 .../styles/page/_provider-picker.scss | 0 .../resources}/styles/ui/_modal.scss | 0 .../resources}/styles/ui/_popup.scss | 0 .../resources}/styles/ui/_switch.scss | 0 .../resources}/svg-icon-loader.js | 0 {resources => front/resources}/ts/app.ts | 0 .../resources}/ts/components/app.ts | 0 .../resources}/ts/components/departures.ts | 0 .../resources}/ts/components/favourites.ts | 0 .../resources}/ts/components/history.ts | 0 .../resources}/ts/components/index.ts | 0 .../resources}/ts/components/line.ts | 0 .../resources}/ts/components/map.ts | 0 .../resources}/ts/components/messages.ts | 0 .../resources}/ts/components/page/index.ts | 0 .../ts/components/page/providers.ts | 0 .../resources}/ts/components/picker.ts | 0 .../ts/components/settings/departures.ts | 0 .../ts/components/settings/index.ts | 0 .../ts/components/settings/messages.ts | 0 .../resources}/ts/components/stop.ts | 0 .../resources}/ts/components/tooltip.ts | 0 .../resources}/ts/components/trip.ts | 0 .../resources}/ts/components/ui/dialog.ts | 0 .../resources}/ts/components/ui/icon.ts | 0 .../resources}/ts/components/ui/index.ts | 0 .../ts/components/ui/numeric-input.ts | 0 .../resources}/ts/components/ui/switch.ts | 0 .../resources}/ts/components/utils.ts | 0 .../resources}/ts/decorators.ts | 0 {resources => front/resources}/ts/filters.ts | 0 {resources => front/resources}/ts/icons.ts | 0 .../resources}/ts/model/common.ts | 0 .../resources}/ts/model/departure.ts | 0 .../resources}/ts/model/error.ts | 0 .../resources}/ts/model/identity.ts | 0 .../resources}/ts/model/index.ts | 0 .../resources}/ts/model/line.ts | 0 .../resources}/ts/model/message.ts | 0 .../resources}/ts/model/provider.ts | 0 .../resources}/ts/model/stop.ts | 0 .../resources}/ts/model/trip.ts | 0 .../resources}/ts/store/common.ts | 0 .../resources}/ts/store/departures.ts | 0 .../resources}/ts/store/favourites.ts | 0 .../resources}/ts/store/history.ts | 0 .../resources}/ts/store/index.ts | 0 .../resources}/ts/store/messages.ts | 0 .../resources}/ts/store/migrations.ts | 0 .../resources}/ts/store/root.ts | 0 .../ts/store/settings/departures.ts | 0 .../resources}/ts/store/settings/messages.ts | 0 .../resources}/ts/types/webpack.d.ts | 0 {resources => front/resources}/ts/urls.ts | 0 {resources => front/resources}/ts/utils.ts | 0 tsconfig.json => front/tsconfig.json | 0 webpack.config.js => front/webpack.config.js | 0 yarn.lock => front/yarn.lock | 0 306 files changed, 55 insertions(+), 47 deletions(-) rename .env.dist => api/.env.dist (100%) create mode 100644 api/.gitignore rename {docker/php => api}/Dockerfile (100%) rename {bin => api/bin}/console (100%) rename composer.json => api/composer.json (100%) rename composer.lock => api/composer.lock (100%) rename {config => api/config}/bundles.php (100%) rename {config => api/config}/packages/dev/jms_serializer.yaml (100%) rename {config => api/config}/packages/dev/monolog.yaml (100%) rename {config => api/config}/packages/dev/routing.yaml (100%) rename {config => api/config}/packages/dev/web_profiler.yaml (100%) rename {config => api/config}/packages/doctrine.yaml (100%) rename {config => api/config}/packages/doctrine_migrations.yaml (100%) rename {config => api/config}/packages/framework.yaml (100%) rename {config => api/config}/packages/jms_serializer.yaml (100%) rename {config => api/config}/packages/nelmio_api_doc.yaml (100%) rename {config => api/config}/packages/prod/doctrine.yaml (100%) rename {config => api/config}/packages/prod/jms_serializer.yaml (100%) rename {config => api/config}/packages/prod/monolog.yaml (100%) rename {config => api/config}/packages/routing.yaml (100%) rename {config => api/config}/packages/sensio_framework_extra.yaml (100%) rename {config => api/config}/packages/test/framework.yaml (100%) rename {config => api/config}/packages/test/monolog.yaml (100%) rename {config => api/config}/packages/test/web_profiler.yaml (100%) rename {config => api/config}/packages/translation.yaml (100%) rename {config => api/config}/packages/twig.yaml (100%) rename {config => api/config}/routes.yaml (100%) rename {config => api/config}/routes/annotations.yaml (100%) rename {config => api/config}/routes/dev/twig.yaml (100%) rename {config => api/config}/routes/dev/web_profiler.yaml (100%) rename {config => api/config}/routes/nelmio_api_doc.yaml (100%) rename {config => api/config}/services.yaml (100%) rename {public => api/public}/index.php (100%) rename ruleset.xml => api/ruleset.xml (100%) rename {src => api/src}/Asset/ModifiedTimeVersionStrategy.php (100%) rename {src => api/src}/Command/UpdateCommand.php (100%) rename {src => api/src}/Controller/.gitignore (100%) rename {src => api/src}/Controller/Api/v1/DeparturesController.php (100%) rename {src => api/src}/Controller/Api/v1/MessagesController.php (100%) rename {src => api/src}/Controller/Api/v1/ProviderController.php (100%) rename {src => api/src}/Controller/Api/v1/StopsController.php (100%) rename {src => api/src}/Controller/Api/v1/TracksController.php (100%) rename {src => api/src}/Controller/Api/v1/TripController.php (100%) rename {src => api/src}/Controller/Controller.php (100%) rename {src => api/src}/Controller/MainController.php (100%) rename {src => api/src}/Doctrine/CarbonDateTimeType.php (100%) rename {src => api/src}/Entity/Entity.php (100%) rename {src => api/src}/Entity/LineEntity.php (100%) rename {src => api/src}/Entity/OperatorEntity.php (100%) rename {src => api/src}/Entity/ProviderEntity.php (100%) rename {src => api/src}/Entity/ProviderReferenceTrait.php (100%) rename {src => api/src}/Entity/ReferableEntityTrait.php (100%) rename {src => api/src}/Entity/StopEntity.php (100%) rename {src => api/src}/Entity/TrackEntity.php (100%) rename {src => api/src}/Entity/TrackStopEntity.php (100%) rename {src => api/src}/Entity/TripEntity.php (100%) rename {src => api/src}/Entity/TripStopEntity.php (100%) rename {src => api/src}/Event/DataUpdateEvent.php (100%) rename {src => api/src}/Event/HandleDatabaseModifierEvent.php (100%) rename {src => api/src}/Event/HandleModifierEvent.php (100%) rename {src => api/src}/Event/PostProcessEvent.php (100%) rename {src => api/src}/Exception/InvalidArgumentException.php (100%) rename {src => api/src}/Exception/NonExistentServiceException.php (100%) rename {src => api/src}/Exception/NotSupportedException.php (100%) rename {src => api/src}/Exception/UnsupportedModifierException.php (100%) rename {src => api/src}/Functions/helpers.php (100%) rename {src => api/src}/Functions/index.php (100%) rename {src => api/src}/Handler/Database/FieldFilterDatabaseHandler.php (100%) rename {src => api/src}/Handler/Database/GenericWithDatabaseHandler.php (100%) rename {src => api/src}/Handler/Database/IdFilterDatabaseHandler.php (100%) rename {src => api/src}/Handler/Database/LimitDatabaseHandler.php (100%) rename {src => api/src}/Handler/Database/RelatedFilterDatabaseGenericHandler.php (100%) rename {src => api/src}/Handler/Database/TrackByStopDatabaseHandler.php (100%) rename {src => api/src}/Handler/Database/WithDestinationsDatabaseHandler.php (100%) rename {src => api/src}/Handler/ModifierHandler.php (100%) rename {src => api/src}/Handler/PostProcessingHandler.php (100%) rename {src => api/src}/Kernel.php (100%) rename {src => api/src}/Migrations/.gitignore (100%) rename {src => api/src}/Migrations/Version20180907212032.php (100%) rename {src => api/src}/Migrations/Version20181027124203.php (100%) rename {src => api/src}/Migrations/Version20190111212909.php (100%) rename {src => api/src}/Migrations/Version20200103160747.php (100%) rename {src => api/src}/Migrations/Version20200103170517.php (100%) rename {src => api/src}/Migrations/Version20200131151757.php (100%) rename {src => api/src}/Migrations/Version20200206183956.php (100%) rename {src => api/src}/Migrations/Version20200314112552.php (100%) rename {src => api/src}/Model/Departure.php (100%) rename {src => api/src}/Model/Destination.php (100%) rename {src => api/src}/Model/FillTrait.php (100%) rename {src => api/src}/Model/Fillable.php (100%) rename {src => api/src}/Model/JustReference.php (100%) rename {src => api/src}/Model/Line.php (100%) rename {src => api/src}/Model/Location.php (100%) rename {src => api/src}/Model/Message.php (100%) rename {src => api/src}/Model/Operator.php (100%) rename {src => api/src}/Model/Provider.php (100%) rename {src => api/src}/Model/Referable.php (100%) rename {src => api/src}/Model/ReferableTrait.php (100%) rename {src => api/src}/Model/ScheduledStop.php (100%) rename {src => api/src}/Model/Stop.php (100%) rename {src => api/src}/Model/StopGroup.php (100%) rename {src => api/src}/Model/Track.php (100%) rename {src => api/src}/Model/TrackStop.php (100%) rename {src => api/src}/Model/Trip.php (100%) rename {src => api/src}/Model/Vehicle.php (100%) rename {src => api/src}/Modifier/FieldFilter.php (100%) rename {src => api/src}/Modifier/IdFilter.php (100%) rename {src => api/src}/Modifier/Limit.php (100%) rename {src => api/src}/Modifier/Modifier.php (100%) rename {src => api/src}/Modifier/RelatedFilter.php (100%) rename {src => api/src}/Modifier/With.php (100%) rename {src => api/src}/Provider/Database/DatabaseRepository.php (100%) rename {src => api/src}/Provider/Database/GenericLineRepository.php (100%) rename {src => api/src}/Provider/Database/GenericOperatorRepository.php (100%) rename {src => api/src}/Provider/Database/GenericScheduleRepository.php (100%) rename {src => api/src}/Provider/Database/GenericStopRepository.php (100%) rename {src => api/src}/Provider/Database/GenericTrackRepository.php (100%) rename {src => api/src}/Provider/Database/GenericTripRepository.php (100%) rename {src => api/src}/Provider/DepartureRepository.php (100%) rename {src => api/src}/Provider/Dummy/DummyDepartureRepository.php (100%) rename {src => api/src}/Provider/Dummy/DummyMessageRepository.php (100%) rename {src => api/src}/Provider/Dummy/DummyProvider.php (100%) rename {src => api/src}/Provider/Dummy/DummyStopRepository.php (100%) rename {src => api/src}/Provider/FluentRepository.php (100%) rename {src => api/src}/Provider/LineRepository.php (100%) rename {src => api/src}/Provider/MessageRepository.php (100%) rename {src => api/src}/Provider/OperatorRepository.php (100%) rename {src => api/src}/Provider/Provider.php (100%) rename {src => api/src}/Provider/Repository.php (100%) rename {src => api/src}/Provider/ScheduleRepository.php (100%) rename {src => api/src}/Provider/StopRepository.php (100%) rename {src => api/src}/Provider/TrackRepository.php (100%) rename {src => api/src}/Provider/TripRepository.php (100%) rename {src => api/src}/Provider/ZtmGdansk/ZtmGdanskDataUpdateSubscriber.php (100%) rename {src => api/src}/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php (100%) rename {src => api/src}/Provider/ZtmGdansk/ZtmGdanskMessageRepository.php (100%) rename {src => api/src}/Provider/ZtmGdansk/ZtmGdanskMessageTypeClassifier.php (100%) rename {src => api/src}/Provider/ZtmGdansk/ZtmGdanskProvider.php (100%) rename {src => api/src}/Serialization/CarbonHandler.php (100%) rename {src => api/src}/Serialization/LaravelCollectionHandler.php (100%) rename {src => api/src}/Serialization/SerializeAs.php (100%) rename {src => api/src}/Service/AggregateConverter.php (100%) rename {src => api/src}/Service/CacheableConverter.php (100%) rename {src => api/src}/Service/Converter.php (100%) rename {src => api/src}/Service/DataUpdater.php (100%) rename {src => api/src}/Service/EntityConverter.php (100%) rename {src => api/src}/Service/EntityReferenceFactory.php (100%) rename {src => api/src}/Service/HandlerProvider.php (100%) rename {src => api/src}/Service/IdUtils.php (100%) rename {src => api/src}/Service/IterableUtils.php (100%) rename {src => api/src}/Service/ModifierUtils.php (100%) rename {src => api/src}/Service/Normalizer/JustReferenceNormalizer.php (100%) rename {src => api/src}/Service/Normalizer/StopNormalizer.php (100%) rename {src => api/src}/Service/ProviderConverter.php (100%) rename {src => api/src}/Service/ProviderParameterConverter.php (100%) rename {src => api/src}/Service/ProviderResolver.php (100%) rename {src => api/src}/Service/Proxy/ReferenceFactory.php (100%) rename {src => api/src}/Service/Proxy/ReferenceObjectGenerator.php (100%) rename {src => api/src}/Service/RecursiveConverter.php (100%) rename {src => api/src}/Service/RecursiveConverterTrait.php (100%) rename {src => api/src}/Service/RepositoryParameterConverter.php (100%) rename {src => api/src}/Service/ScheduledStopConverter.php (100%) rename {src => api/src}/Service/SerializerContextFactory.php (100%) rename {src => api/src}/Service/VersionExtension.php (100%) rename {src => api/src}/Subscriber/JustReferenceSerializationSubscriber.php (100%) rename symfony.lock => api/symfony.lock (100%) rename {templates => api/templates}/app.html.twig (100%) rename {templates => api/templates}/base.html.twig (88%) rename {templates => api/templates}/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig (100%) rename {templates => api/templates}/choose.html.twig (100%) rename {templates => api/templates}/manifest.json.twig (100%) rename {translations => api/translations}/.gitignore (100%) create mode 100644 front/.gitignore rename package.json => front/package.json (100%) create mode 100644 front/public/.gitkeep rename {resources => front/resources}/components/departures.html (100%) rename {resources => front/resources}/components/departures/departure.html (100%) rename {resources => front/resources}/components/favourites.html (100%) rename {resources => front/resources}/components/favourites/save.html (100%) rename {resources => front/resources}/components/finder.html (100%) rename {resources => front/resources}/components/fold.html (100%) rename {resources => front/resources}/components/lazy.html (100%) rename {resources => front/resources}/components/line.html (100%) rename {resources => front/resources}/components/messages.html (100%) rename {resources => front/resources}/components/page/providers.html (100%) rename {resources => front/resources}/components/picker/stop.html (100%) rename {resources => front/resources}/components/settings/departures.html (100%) rename {resources => front/resources}/components/settings/messages.html (100%) rename {resources => front/resources}/components/stop.html (100%) rename {resources => front/resources}/components/stop/details.html (100%) rename {resources => front/resources}/components/stop/history.html (100%) rename {resources => front/resources}/components/stop/map.html (100%) rename {resources => front/resources}/components/tooltip.html (100%) rename {resources => front/resources}/components/trip.html (100%) rename {resources => front/resources}/components/ui/dialog.html (100%) rename {resources => front/resources}/components/ui/icon.html (100%) rename {resources => front/resources}/components/ui/numeric.html (100%) rename {resources => front/resources}/components/ui/switch.html (100%) rename {resources => front/resources}/icons/light/bus.svg (100%) rename {resources => front/resources}/icons/light/icons.ai (100%) rename {resources => front/resources}/icons/light/metro.svg (100%) rename {resources => front/resources}/icons/light/train.svg (100%) rename {resources => front/resources}/icons/light/tram.svg (100%) rename {resources => front/resources}/icons/light/trolleybus.svg (100%) rename {resources => front/resources}/icons/light/unknown.svg (100%) rename {resources => front/resources}/images/app-icon.ai (100%) rename {resources => front/resources}/images/background-2x.png (100%) rename {resources => front/resources}/images/background.png (100%) rename {resources => front/resources}/images/favicon-2x.png (100%) rename {resources => front/resources}/images/favicon-72.png (100%) rename {resources => front/resources}/images/favicon.ai (100%) rename {resources => front/resources}/images/favicon.ico (100%) rename {resources => front/resources}/images/favicon.png (100%) rename {resources => front/resources}/images/icon-128.png (100%) rename {resources => front/resources}/images/icon-192.png (100%) rename {resources => front/resources}/images/icon-256.png (100%) rename {resources => front/resources}/images/icon-512.png (100%) rename {resources => front/resources}/images/icon-64.png (100%) rename {resources => front/resources}/images/icon-96.png (100%) rename {resources => front/resources}/images/icon-maskable.png (100%) rename {resources => front/resources}/images/icon-monochrome.png (100%) rename {resources => front/resources}/images/ios-192.png (100%) rename {resources => front/resources}/images/ios-80.png (100%) rename {resources => front/resources}/images/ios.png (100%) rename {resources => front/resources}/images/kadet-net-logo.png (100%) rename {resources => front/resources}/images/logo-cojedzie.ai (100%) rename {resources => front/resources}/images/logo-concepts.ai (100%) rename {resources => front/resources}/images/logo-superhi.png (100%) rename {resources => front/resources}/images/logo-vector.svg (100%) rename {resources => front/resources}/images/logo.ai (100%) rename {resources => front/resources}/images/logo.png (100%) rename {resources => front/resources}/styles/_animations.scss (100%) rename {resources => front/resources}/styles/_common.scss (100%) rename {resources => front/resources}/styles/_controls.scss (100%) rename {resources => front/resources}/styles/_departure.scss (100%) rename {resources => front/resources}/styles/_dragscroll.scss (100%) rename {resources => front/resources}/styles/_favourites.scss (100%) rename {resources => front/resources}/styles/_form.scss (100%) rename {resources => front/resources}/styles/_line.scss (100%) rename {resources => front/resources}/styles/_map.scss (100%) rename {resources => front/resources}/styles/_stop.scss (100%) rename {resources => front/resources}/styles/_trigonometry.scss (100%) rename {resources => front/resources}/styles/_trip.scss (100%) rename {resources => front/resources}/styles/api.scss (100%) rename {resources => front/resources}/styles/main.scss (100%) rename {resources => front/resources}/styles/page/_provider-picker.scss (100%) rename {resources => front/resources}/styles/ui/_modal.scss (100%) rename {resources => front/resources}/styles/ui/_popup.scss (100%) rename {resources => front/resources}/styles/ui/_switch.scss (100%) rename {resources => front/resources}/svg-icon-loader.js (100%) rename {resources => front/resources}/ts/app.ts (100%) rename {resources => front/resources}/ts/components/app.ts (100%) rename {resources => front/resources}/ts/components/departures.ts (100%) rename {resources => front/resources}/ts/components/favourites.ts (100%) rename {resources => front/resources}/ts/components/history.ts (100%) rename {resources => front/resources}/ts/components/index.ts (100%) rename {resources => front/resources}/ts/components/line.ts (100%) rename {resources => front/resources}/ts/components/map.ts (100%) rename {resources => front/resources}/ts/components/messages.ts (100%) rename {resources => front/resources}/ts/components/page/index.ts (100%) rename {resources => front/resources}/ts/components/page/providers.ts (100%) rename {resources => front/resources}/ts/components/picker.ts (100%) rename {resources => front/resources}/ts/components/settings/departures.ts (100%) rename {resources => front/resources}/ts/components/settings/index.ts (100%) rename {resources => front/resources}/ts/components/settings/messages.ts (100%) rename {resources => front/resources}/ts/components/stop.ts (100%) rename {resources => front/resources}/ts/components/tooltip.ts (100%) rename {resources => front/resources}/ts/components/trip.ts (100%) rename {resources => front/resources}/ts/components/ui/dialog.ts (100%) rename {resources => front/resources}/ts/components/ui/icon.ts (100%) rename {resources => front/resources}/ts/components/ui/index.ts (100%) rename {resources => front/resources}/ts/components/ui/numeric-input.ts (100%) rename {resources => front/resources}/ts/components/ui/switch.ts (100%) rename {resources => front/resources}/ts/components/utils.ts (100%) rename {resources => front/resources}/ts/decorators.ts (100%) rename {resources => front/resources}/ts/filters.ts (100%) rename {resources => front/resources}/ts/icons.ts (100%) rename {resources => front/resources}/ts/model/common.ts (100%) rename {resources => front/resources}/ts/model/departure.ts (100%) rename {resources => front/resources}/ts/model/error.ts (100%) rename {resources => front/resources}/ts/model/identity.ts (100%) rename {resources => front/resources}/ts/model/index.ts (100%) rename {resources => front/resources}/ts/model/line.ts (100%) rename {resources => front/resources}/ts/model/message.ts (100%) rename {resources => front/resources}/ts/model/provider.ts (100%) rename {resources => front/resources}/ts/model/stop.ts (100%) rename {resources => front/resources}/ts/model/trip.ts (100%) rename {resources => front/resources}/ts/store/common.ts (100%) rename {resources => front/resources}/ts/store/departures.ts (100%) rename {resources => front/resources}/ts/store/favourites.ts (100%) rename {resources => front/resources}/ts/store/history.ts (100%) rename {resources => front/resources}/ts/store/index.ts (100%) rename {resources => front/resources}/ts/store/messages.ts (100%) rename {resources => front/resources}/ts/store/migrations.ts (100%) rename {resources => front/resources}/ts/store/root.ts (100%) rename {resources => front/resources}/ts/store/settings/departures.ts (100%) rename {resources => front/resources}/ts/store/settings/messages.ts (100%) rename {resources => front/resources}/ts/types/webpack.d.ts (100%) rename {resources => front/resources}/ts/urls.ts (100%) rename {resources => front/resources}/ts/utils.ts (100%) rename tsconfig.json => front/tsconfig.json (100%) rename webpack.config.js => front/webpack.config.js (100%) rename yarn.lock => front/yarn.lock (100%) diff --git a/.gitignore b/.gitignore index 429897d..85e7c1d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,19 +1 @@ - -###> symfony/framework-bundle ### -/.env -/public/bundles/ -/var/ -/vendor/ -###< symfony/framework-bundle ### - -###> symfony/web-server-bundle ### -/.web-server-pid -###< symfony/web-server-bundle ### - -/node_modules/ /.idea/ -/public/* -!/public/index.php -!/public/manifest.jso - -/yarn-error.log diff --git a/.env.dist b/api/.env.dist similarity index 100% rename from .env.dist rename to api/.env.dist diff --git a/api/.gitignore b/api/.gitignore new file mode 100644 index 0000000..5e19b63 --- /dev/null +++ b/api/.gitignore @@ -0,0 +1,16 @@ + +###> symfony/framework-bundle ### +/.env +/public/bundles/ +/var/ +/vendor/ +###< symfony/framework-bundle ### + +###> symfony/web-server-bundle ### +/.web-server-pid +###< symfony/web-server-bundle ### + +/node_modules/ +/public/* +!/public/index.php + diff --git a/docker/php/Dockerfile b/api/Dockerfile similarity index 100% rename from docker/php/Dockerfile rename to api/Dockerfile diff --git a/bin/console b/api/bin/console similarity index 100% rename from bin/console rename to api/bin/console diff --git a/composer.json b/api/composer.json similarity index 100% rename from composer.json rename to api/composer.json diff --git a/composer.lock b/api/composer.lock similarity index 100% rename from composer.lock rename to api/composer.lock diff --git a/config/bundles.php b/api/config/bundles.php similarity index 100% rename from config/bundles.php rename to api/config/bundles.php diff --git a/config/packages/dev/jms_serializer.yaml b/api/config/packages/dev/jms_serializer.yaml similarity index 100% rename from config/packages/dev/jms_serializer.yaml rename to api/config/packages/dev/jms_serializer.yaml diff --git a/config/packages/dev/monolog.yaml b/api/config/packages/dev/monolog.yaml similarity index 100% rename from config/packages/dev/monolog.yaml rename to api/config/packages/dev/monolog.yaml diff --git a/config/packages/dev/routing.yaml b/api/config/packages/dev/routing.yaml similarity index 100% rename from config/packages/dev/routing.yaml rename to api/config/packages/dev/routing.yaml diff --git a/config/packages/dev/web_profiler.yaml b/api/config/packages/dev/web_profiler.yaml similarity index 100% rename from config/packages/dev/web_profiler.yaml rename to api/config/packages/dev/web_profiler.yaml diff --git a/config/packages/doctrine.yaml b/api/config/packages/doctrine.yaml similarity index 100% rename from config/packages/doctrine.yaml rename to api/config/packages/doctrine.yaml diff --git a/config/packages/doctrine_migrations.yaml b/api/config/packages/doctrine_migrations.yaml similarity index 100% rename from config/packages/doctrine_migrations.yaml rename to api/config/packages/doctrine_migrations.yaml diff --git a/config/packages/framework.yaml b/api/config/packages/framework.yaml similarity index 100% rename from config/packages/framework.yaml rename to api/config/packages/framework.yaml diff --git a/config/packages/jms_serializer.yaml b/api/config/packages/jms_serializer.yaml similarity index 100% rename from config/packages/jms_serializer.yaml rename to api/config/packages/jms_serializer.yaml diff --git a/config/packages/nelmio_api_doc.yaml b/api/config/packages/nelmio_api_doc.yaml similarity index 100% rename from config/packages/nelmio_api_doc.yaml rename to api/config/packages/nelmio_api_doc.yaml diff --git a/config/packages/prod/doctrine.yaml b/api/config/packages/prod/doctrine.yaml similarity index 100% rename from config/packages/prod/doctrine.yaml rename to api/config/packages/prod/doctrine.yaml diff --git a/config/packages/prod/jms_serializer.yaml b/api/config/packages/prod/jms_serializer.yaml similarity index 100% rename from config/packages/prod/jms_serializer.yaml rename to api/config/packages/prod/jms_serializer.yaml diff --git a/config/packages/prod/monolog.yaml b/api/config/packages/prod/monolog.yaml similarity index 100% rename from config/packages/prod/monolog.yaml rename to api/config/packages/prod/monolog.yaml diff --git a/config/packages/routing.yaml b/api/config/packages/routing.yaml similarity index 100% rename from config/packages/routing.yaml rename to api/config/packages/routing.yaml diff --git a/config/packages/sensio_framework_extra.yaml b/api/config/packages/sensio_framework_extra.yaml similarity index 100% rename from config/packages/sensio_framework_extra.yaml rename to api/config/packages/sensio_framework_extra.yaml diff --git a/config/packages/test/framework.yaml b/api/config/packages/test/framework.yaml similarity index 100% rename from config/packages/test/framework.yaml rename to api/config/packages/test/framework.yaml diff --git a/config/packages/test/monolog.yaml b/api/config/packages/test/monolog.yaml similarity index 100% rename from config/packages/test/monolog.yaml rename to api/config/packages/test/monolog.yaml diff --git a/config/packages/test/web_profiler.yaml b/api/config/packages/test/web_profiler.yaml similarity index 100% rename from config/packages/test/web_profiler.yaml rename to api/config/packages/test/web_profiler.yaml diff --git a/config/packages/translation.yaml b/api/config/packages/translation.yaml similarity index 100% rename from config/packages/translation.yaml rename to api/config/packages/translation.yaml diff --git a/config/packages/twig.yaml b/api/config/packages/twig.yaml similarity index 100% rename from config/packages/twig.yaml rename to api/config/packages/twig.yaml diff --git a/config/routes.yaml b/api/config/routes.yaml similarity index 100% rename from config/routes.yaml rename to api/config/routes.yaml diff --git a/config/routes/annotations.yaml b/api/config/routes/annotations.yaml similarity index 100% rename from config/routes/annotations.yaml rename to api/config/routes/annotations.yaml diff --git a/config/routes/dev/twig.yaml b/api/config/routes/dev/twig.yaml similarity index 100% rename from config/routes/dev/twig.yaml rename to api/config/routes/dev/twig.yaml diff --git a/config/routes/dev/web_profiler.yaml b/api/config/routes/dev/web_profiler.yaml similarity index 100% rename from config/routes/dev/web_profiler.yaml rename to api/config/routes/dev/web_profiler.yaml diff --git a/config/routes/nelmio_api_doc.yaml b/api/config/routes/nelmio_api_doc.yaml similarity index 100% rename from config/routes/nelmio_api_doc.yaml rename to api/config/routes/nelmio_api_doc.yaml diff --git a/config/services.yaml b/api/config/services.yaml similarity index 100% rename from config/services.yaml rename to api/config/services.yaml diff --git a/public/index.php b/api/public/index.php similarity index 100% rename from public/index.php rename to api/public/index.php diff --git a/ruleset.xml b/api/ruleset.xml similarity index 100% rename from ruleset.xml rename to api/ruleset.xml diff --git a/src/Asset/ModifiedTimeVersionStrategy.php b/api/src/Asset/ModifiedTimeVersionStrategy.php similarity index 100% rename from src/Asset/ModifiedTimeVersionStrategy.php rename to api/src/Asset/ModifiedTimeVersionStrategy.php diff --git a/src/Command/UpdateCommand.php b/api/src/Command/UpdateCommand.php similarity index 100% rename from src/Command/UpdateCommand.php rename to api/src/Command/UpdateCommand.php diff --git a/src/Controller/.gitignore b/api/src/Controller/.gitignore similarity index 100% rename from src/Controller/.gitignore rename to api/src/Controller/.gitignore diff --git a/src/Controller/Api/v1/DeparturesController.php b/api/src/Controller/Api/v1/DeparturesController.php similarity index 100% rename from src/Controller/Api/v1/DeparturesController.php rename to api/src/Controller/Api/v1/DeparturesController.php diff --git a/src/Controller/Api/v1/MessagesController.php b/api/src/Controller/Api/v1/MessagesController.php similarity index 100% rename from src/Controller/Api/v1/MessagesController.php rename to api/src/Controller/Api/v1/MessagesController.php diff --git a/src/Controller/Api/v1/ProviderController.php b/api/src/Controller/Api/v1/ProviderController.php similarity index 100% rename from src/Controller/Api/v1/ProviderController.php rename to api/src/Controller/Api/v1/ProviderController.php diff --git a/src/Controller/Api/v1/StopsController.php b/api/src/Controller/Api/v1/StopsController.php similarity index 100% rename from src/Controller/Api/v1/StopsController.php rename to api/src/Controller/Api/v1/StopsController.php diff --git a/src/Controller/Api/v1/TracksController.php b/api/src/Controller/Api/v1/TracksController.php similarity index 100% rename from src/Controller/Api/v1/TracksController.php rename to api/src/Controller/Api/v1/TracksController.php diff --git a/src/Controller/Api/v1/TripController.php b/api/src/Controller/Api/v1/TripController.php similarity index 100% rename from src/Controller/Api/v1/TripController.php rename to api/src/Controller/Api/v1/TripController.php diff --git a/src/Controller/Controller.php b/api/src/Controller/Controller.php similarity index 100% rename from src/Controller/Controller.php rename to api/src/Controller/Controller.php diff --git a/src/Controller/MainController.php b/api/src/Controller/MainController.php similarity index 100% rename from src/Controller/MainController.php rename to api/src/Controller/MainController.php diff --git a/src/Doctrine/CarbonDateTimeType.php b/api/src/Doctrine/CarbonDateTimeType.php similarity index 100% rename from src/Doctrine/CarbonDateTimeType.php rename to api/src/Doctrine/CarbonDateTimeType.php diff --git a/src/Entity/Entity.php b/api/src/Entity/Entity.php similarity index 100% rename from src/Entity/Entity.php rename to api/src/Entity/Entity.php diff --git a/src/Entity/LineEntity.php b/api/src/Entity/LineEntity.php similarity index 100% rename from src/Entity/LineEntity.php rename to api/src/Entity/LineEntity.php diff --git a/src/Entity/OperatorEntity.php b/api/src/Entity/OperatorEntity.php similarity index 100% rename from src/Entity/OperatorEntity.php rename to api/src/Entity/OperatorEntity.php diff --git a/src/Entity/ProviderEntity.php b/api/src/Entity/ProviderEntity.php similarity index 100% rename from src/Entity/ProviderEntity.php rename to api/src/Entity/ProviderEntity.php diff --git a/src/Entity/ProviderReferenceTrait.php b/api/src/Entity/ProviderReferenceTrait.php similarity index 100% rename from src/Entity/ProviderReferenceTrait.php rename to api/src/Entity/ProviderReferenceTrait.php diff --git a/src/Entity/ReferableEntityTrait.php b/api/src/Entity/ReferableEntityTrait.php similarity index 100% rename from src/Entity/ReferableEntityTrait.php rename to api/src/Entity/ReferableEntityTrait.php diff --git a/src/Entity/StopEntity.php b/api/src/Entity/StopEntity.php similarity index 100% rename from src/Entity/StopEntity.php rename to api/src/Entity/StopEntity.php diff --git a/src/Entity/TrackEntity.php b/api/src/Entity/TrackEntity.php similarity index 100% rename from src/Entity/TrackEntity.php rename to api/src/Entity/TrackEntity.php diff --git a/src/Entity/TrackStopEntity.php b/api/src/Entity/TrackStopEntity.php similarity index 100% rename from src/Entity/TrackStopEntity.php rename to api/src/Entity/TrackStopEntity.php diff --git a/src/Entity/TripEntity.php b/api/src/Entity/TripEntity.php similarity index 100% rename from src/Entity/TripEntity.php rename to api/src/Entity/TripEntity.php diff --git a/src/Entity/TripStopEntity.php b/api/src/Entity/TripStopEntity.php similarity index 100% rename from src/Entity/TripStopEntity.php rename to api/src/Entity/TripStopEntity.php diff --git a/src/Event/DataUpdateEvent.php b/api/src/Event/DataUpdateEvent.php similarity index 100% rename from src/Event/DataUpdateEvent.php rename to api/src/Event/DataUpdateEvent.php diff --git a/src/Event/HandleDatabaseModifierEvent.php b/api/src/Event/HandleDatabaseModifierEvent.php similarity index 100% rename from src/Event/HandleDatabaseModifierEvent.php rename to api/src/Event/HandleDatabaseModifierEvent.php diff --git a/src/Event/HandleModifierEvent.php b/api/src/Event/HandleModifierEvent.php similarity index 100% rename from src/Event/HandleModifierEvent.php rename to api/src/Event/HandleModifierEvent.php diff --git a/src/Event/PostProcessEvent.php b/api/src/Event/PostProcessEvent.php similarity index 100% rename from src/Event/PostProcessEvent.php rename to api/src/Event/PostProcessEvent.php diff --git a/src/Exception/InvalidArgumentException.php b/api/src/Exception/InvalidArgumentException.php similarity index 100% rename from src/Exception/InvalidArgumentException.php rename to api/src/Exception/InvalidArgumentException.php diff --git a/src/Exception/NonExistentServiceException.php b/api/src/Exception/NonExistentServiceException.php similarity index 100% rename from src/Exception/NonExistentServiceException.php rename to api/src/Exception/NonExistentServiceException.php diff --git a/src/Exception/NotSupportedException.php b/api/src/Exception/NotSupportedException.php similarity index 100% rename from src/Exception/NotSupportedException.php rename to api/src/Exception/NotSupportedException.php diff --git a/src/Exception/UnsupportedModifierException.php b/api/src/Exception/UnsupportedModifierException.php similarity index 100% rename from src/Exception/UnsupportedModifierException.php rename to api/src/Exception/UnsupportedModifierException.php diff --git a/src/Functions/helpers.php b/api/src/Functions/helpers.php similarity index 100% rename from src/Functions/helpers.php rename to api/src/Functions/helpers.php diff --git a/src/Functions/index.php b/api/src/Functions/index.php similarity index 100% rename from src/Functions/index.php rename to api/src/Functions/index.php diff --git a/src/Handler/Database/FieldFilterDatabaseHandler.php b/api/src/Handler/Database/FieldFilterDatabaseHandler.php similarity index 100% rename from src/Handler/Database/FieldFilterDatabaseHandler.php rename to api/src/Handler/Database/FieldFilterDatabaseHandler.php diff --git a/src/Handler/Database/GenericWithDatabaseHandler.php b/api/src/Handler/Database/GenericWithDatabaseHandler.php similarity index 100% rename from src/Handler/Database/GenericWithDatabaseHandler.php rename to api/src/Handler/Database/GenericWithDatabaseHandler.php diff --git a/src/Handler/Database/IdFilterDatabaseHandler.php b/api/src/Handler/Database/IdFilterDatabaseHandler.php similarity index 100% rename from src/Handler/Database/IdFilterDatabaseHandler.php rename to api/src/Handler/Database/IdFilterDatabaseHandler.php diff --git a/src/Handler/Database/LimitDatabaseHandler.php b/api/src/Handler/Database/LimitDatabaseHandler.php similarity index 100% rename from src/Handler/Database/LimitDatabaseHandler.php rename to api/src/Handler/Database/LimitDatabaseHandler.php diff --git a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php b/api/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php similarity index 100% rename from src/Handler/Database/RelatedFilterDatabaseGenericHandler.php rename to api/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php diff --git a/src/Handler/Database/TrackByStopDatabaseHandler.php b/api/src/Handler/Database/TrackByStopDatabaseHandler.php similarity index 100% rename from src/Handler/Database/TrackByStopDatabaseHandler.php rename to api/src/Handler/Database/TrackByStopDatabaseHandler.php diff --git a/src/Handler/Database/WithDestinationsDatabaseHandler.php b/api/src/Handler/Database/WithDestinationsDatabaseHandler.php similarity index 100% rename from src/Handler/Database/WithDestinationsDatabaseHandler.php rename to api/src/Handler/Database/WithDestinationsDatabaseHandler.php diff --git a/src/Handler/ModifierHandler.php b/api/src/Handler/ModifierHandler.php similarity index 100% rename from src/Handler/ModifierHandler.php rename to api/src/Handler/ModifierHandler.php diff --git a/src/Handler/PostProcessingHandler.php b/api/src/Handler/PostProcessingHandler.php similarity index 100% rename from src/Handler/PostProcessingHandler.php rename to api/src/Handler/PostProcessingHandler.php diff --git a/src/Kernel.php b/api/src/Kernel.php similarity index 100% rename from src/Kernel.php rename to api/src/Kernel.php diff --git a/src/Migrations/.gitignore b/api/src/Migrations/.gitignore similarity index 100% rename from src/Migrations/.gitignore rename to api/src/Migrations/.gitignore diff --git a/src/Migrations/Version20180907212032.php b/api/src/Migrations/Version20180907212032.php similarity index 100% rename from src/Migrations/Version20180907212032.php rename to api/src/Migrations/Version20180907212032.php diff --git a/src/Migrations/Version20181027124203.php b/api/src/Migrations/Version20181027124203.php similarity index 100% rename from src/Migrations/Version20181027124203.php rename to api/src/Migrations/Version20181027124203.php diff --git a/src/Migrations/Version20190111212909.php b/api/src/Migrations/Version20190111212909.php similarity index 100% rename from src/Migrations/Version20190111212909.php rename to api/src/Migrations/Version20190111212909.php diff --git a/src/Migrations/Version20200103160747.php b/api/src/Migrations/Version20200103160747.php similarity index 100% rename from src/Migrations/Version20200103160747.php rename to api/src/Migrations/Version20200103160747.php diff --git a/src/Migrations/Version20200103170517.php b/api/src/Migrations/Version20200103170517.php similarity index 100% rename from src/Migrations/Version20200103170517.php rename to api/src/Migrations/Version20200103170517.php diff --git a/src/Migrations/Version20200131151757.php b/api/src/Migrations/Version20200131151757.php similarity index 100% rename from src/Migrations/Version20200131151757.php rename to api/src/Migrations/Version20200131151757.php diff --git a/src/Migrations/Version20200206183956.php b/api/src/Migrations/Version20200206183956.php similarity index 100% rename from src/Migrations/Version20200206183956.php rename to api/src/Migrations/Version20200206183956.php diff --git a/src/Migrations/Version20200314112552.php b/api/src/Migrations/Version20200314112552.php similarity index 100% rename from src/Migrations/Version20200314112552.php rename to api/src/Migrations/Version20200314112552.php diff --git a/src/Model/Departure.php b/api/src/Model/Departure.php similarity index 100% rename from src/Model/Departure.php rename to api/src/Model/Departure.php diff --git a/src/Model/Destination.php b/api/src/Model/Destination.php similarity index 100% rename from src/Model/Destination.php rename to api/src/Model/Destination.php diff --git a/src/Model/FillTrait.php b/api/src/Model/FillTrait.php similarity index 100% rename from src/Model/FillTrait.php rename to api/src/Model/FillTrait.php diff --git a/src/Model/Fillable.php b/api/src/Model/Fillable.php similarity index 100% rename from src/Model/Fillable.php rename to api/src/Model/Fillable.php diff --git a/src/Model/JustReference.php b/api/src/Model/JustReference.php similarity index 100% rename from src/Model/JustReference.php rename to api/src/Model/JustReference.php diff --git a/src/Model/Line.php b/api/src/Model/Line.php similarity index 100% rename from src/Model/Line.php rename to api/src/Model/Line.php diff --git a/src/Model/Location.php b/api/src/Model/Location.php similarity index 100% rename from src/Model/Location.php rename to api/src/Model/Location.php diff --git a/src/Model/Message.php b/api/src/Model/Message.php similarity index 100% rename from src/Model/Message.php rename to api/src/Model/Message.php diff --git a/src/Model/Operator.php b/api/src/Model/Operator.php similarity index 100% rename from src/Model/Operator.php rename to api/src/Model/Operator.php diff --git a/src/Model/Provider.php b/api/src/Model/Provider.php similarity index 100% rename from src/Model/Provider.php rename to api/src/Model/Provider.php diff --git a/src/Model/Referable.php b/api/src/Model/Referable.php similarity index 100% rename from src/Model/Referable.php rename to api/src/Model/Referable.php diff --git a/src/Model/ReferableTrait.php b/api/src/Model/ReferableTrait.php similarity index 100% rename from src/Model/ReferableTrait.php rename to api/src/Model/ReferableTrait.php diff --git a/src/Model/ScheduledStop.php b/api/src/Model/ScheduledStop.php similarity index 100% rename from src/Model/ScheduledStop.php rename to api/src/Model/ScheduledStop.php diff --git a/src/Model/Stop.php b/api/src/Model/Stop.php similarity index 100% rename from src/Model/Stop.php rename to api/src/Model/Stop.php diff --git a/src/Model/StopGroup.php b/api/src/Model/StopGroup.php similarity index 100% rename from src/Model/StopGroup.php rename to api/src/Model/StopGroup.php diff --git a/src/Model/Track.php b/api/src/Model/Track.php similarity index 100% rename from src/Model/Track.php rename to api/src/Model/Track.php diff --git a/src/Model/TrackStop.php b/api/src/Model/TrackStop.php similarity index 100% rename from src/Model/TrackStop.php rename to api/src/Model/TrackStop.php diff --git a/src/Model/Trip.php b/api/src/Model/Trip.php similarity index 100% rename from src/Model/Trip.php rename to api/src/Model/Trip.php diff --git a/src/Model/Vehicle.php b/api/src/Model/Vehicle.php similarity index 100% rename from src/Model/Vehicle.php rename to api/src/Model/Vehicle.php diff --git a/src/Modifier/FieldFilter.php b/api/src/Modifier/FieldFilter.php similarity index 100% rename from src/Modifier/FieldFilter.php rename to api/src/Modifier/FieldFilter.php diff --git a/src/Modifier/IdFilter.php b/api/src/Modifier/IdFilter.php similarity index 100% rename from src/Modifier/IdFilter.php rename to api/src/Modifier/IdFilter.php diff --git a/src/Modifier/Limit.php b/api/src/Modifier/Limit.php similarity index 100% rename from src/Modifier/Limit.php rename to api/src/Modifier/Limit.php diff --git a/src/Modifier/Modifier.php b/api/src/Modifier/Modifier.php similarity index 100% rename from src/Modifier/Modifier.php rename to api/src/Modifier/Modifier.php diff --git a/src/Modifier/RelatedFilter.php b/api/src/Modifier/RelatedFilter.php similarity index 100% rename from src/Modifier/RelatedFilter.php rename to api/src/Modifier/RelatedFilter.php diff --git a/src/Modifier/With.php b/api/src/Modifier/With.php similarity index 100% rename from src/Modifier/With.php rename to api/src/Modifier/With.php diff --git a/src/Provider/Database/DatabaseRepository.php b/api/src/Provider/Database/DatabaseRepository.php similarity index 100% rename from src/Provider/Database/DatabaseRepository.php rename to api/src/Provider/Database/DatabaseRepository.php diff --git a/src/Provider/Database/GenericLineRepository.php b/api/src/Provider/Database/GenericLineRepository.php similarity index 100% rename from src/Provider/Database/GenericLineRepository.php rename to api/src/Provider/Database/GenericLineRepository.php diff --git a/src/Provider/Database/GenericOperatorRepository.php b/api/src/Provider/Database/GenericOperatorRepository.php similarity index 100% rename from src/Provider/Database/GenericOperatorRepository.php rename to api/src/Provider/Database/GenericOperatorRepository.php diff --git a/src/Provider/Database/GenericScheduleRepository.php b/api/src/Provider/Database/GenericScheduleRepository.php similarity index 100% rename from src/Provider/Database/GenericScheduleRepository.php rename to api/src/Provider/Database/GenericScheduleRepository.php diff --git a/src/Provider/Database/GenericStopRepository.php b/api/src/Provider/Database/GenericStopRepository.php similarity index 100% rename from src/Provider/Database/GenericStopRepository.php rename to api/src/Provider/Database/GenericStopRepository.php diff --git a/src/Provider/Database/GenericTrackRepository.php b/api/src/Provider/Database/GenericTrackRepository.php similarity index 100% rename from src/Provider/Database/GenericTrackRepository.php rename to api/src/Provider/Database/GenericTrackRepository.php diff --git a/src/Provider/Database/GenericTripRepository.php b/api/src/Provider/Database/GenericTripRepository.php similarity index 100% rename from src/Provider/Database/GenericTripRepository.php rename to api/src/Provider/Database/GenericTripRepository.php diff --git a/src/Provider/DepartureRepository.php b/api/src/Provider/DepartureRepository.php similarity index 100% rename from src/Provider/DepartureRepository.php rename to api/src/Provider/DepartureRepository.php diff --git a/src/Provider/Dummy/DummyDepartureRepository.php b/api/src/Provider/Dummy/DummyDepartureRepository.php similarity index 100% rename from src/Provider/Dummy/DummyDepartureRepository.php rename to api/src/Provider/Dummy/DummyDepartureRepository.php diff --git a/src/Provider/Dummy/DummyMessageRepository.php b/api/src/Provider/Dummy/DummyMessageRepository.php similarity index 100% rename from src/Provider/Dummy/DummyMessageRepository.php rename to api/src/Provider/Dummy/DummyMessageRepository.php diff --git a/src/Provider/Dummy/DummyProvider.php b/api/src/Provider/Dummy/DummyProvider.php similarity index 100% rename from src/Provider/Dummy/DummyProvider.php rename to api/src/Provider/Dummy/DummyProvider.php diff --git a/src/Provider/Dummy/DummyStopRepository.php b/api/src/Provider/Dummy/DummyStopRepository.php similarity index 100% rename from src/Provider/Dummy/DummyStopRepository.php rename to api/src/Provider/Dummy/DummyStopRepository.php diff --git a/src/Provider/FluentRepository.php b/api/src/Provider/FluentRepository.php similarity index 100% rename from src/Provider/FluentRepository.php rename to api/src/Provider/FluentRepository.php diff --git a/src/Provider/LineRepository.php b/api/src/Provider/LineRepository.php similarity index 100% rename from src/Provider/LineRepository.php rename to api/src/Provider/LineRepository.php diff --git a/src/Provider/MessageRepository.php b/api/src/Provider/MessageRepository.php similarity index 100% rename from src/Provider/MessageRepository.php rename to api/src/Provider/MessageRepository.php diff --git a/src/Provider/OperatorRepository.php b/api/src/Provider/OperatorRepository.php similarity index 100% rename from src/Provider/OperatorRepository.php rename to api/src/Provider/OperatorRepository.php diff --git a/src/Provider/Provider.php b/api/src/Provider/Provider.php similarity index 100% rename from src/Provider/Provider.php rename to api/src/Provider/Provider.php diff --git a/src/Provider/Repository.php b/api/src/Provider/Repository.php similarity index 100% rename from src/Provider/Repository.php rename to api/src/Provider/Repository.php diff --git a/src/Provider/ScheduleRepository.php b/api/src/Provider/ScheduleRepository.php similarity index 100% rename from src/Provider/ScheduleRepository.php rename to api/src/Provider/ScheduleRepository.php diff --git a/src/Provider/StopRepository.php b/api/src/Provider/StopRepository.php similarity index 100% rename from src/Provider/StopRepository.php rename to api/src/Provider/StopRepository.php diff --git a/src/Provider/TrackRepository.php b/api/src/Provider/TrackRepository.php similarity index 100% rename from src/Provider/TrackRepository.php rename to api/src/Provider/TrackRepository.php diff --git a/src/Provider/TripRepository.php b/api/src/Provider/TripRepository.php similarity index 100% rename from src/Provider/TripRepository.php rename to api/src/Provider/TripRepository.php diff --git a/src/Provider/ZtmGdansk/ZtmGdanskDataUpdateSubscriber.php b/api/src/Provider/ZtmGdansk/ZtmGdanskDataUpdateSubscriber.php similarity index 100% rename from src/Provider/ZtmGdansk/ZtmGdanskDataUpdateSubscriber.php rename to api/src/Provider/ZtmGdansk/ZtmGdanskDataUpdateSubscriber.php diff --git a/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php b/api/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php similarity index 100% rename from src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php rename to api/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php diff --git a/src/Provider/ZtmGdansk/ZtmGdanskMessageRepository.php b/api/src/Provider/ZtmGdansk/ZtmGdanskMessageRepository.php similarity index 100% rename from src/Provider/ZtmGdansk/ZtmGdanskMessageRepository.php rename to api/src/Provider/ZtmGdansk/ZtmGdanskMessageRepository.php diff --git a/src/Provider/ZtmGdansk/ZtmGdanskMessageTypeClassifier.php b/api/src/Provider/ZtmGdansk/ZtmGdanskMessageTypeClassifier.php similarity index 100% rename from src/Provider/ZtmGdansk/ZtmGdanskMessageTypeClassifier.php rename to api/src/Provider/ZtmGdansk/ZtmGdanskMessageTypeClassifier.php diff --git a/src/Provider/ZtmGdansk/ZtmGdanskProvider.php b/api/src/Provider/ZtmGdansk/ZtmGdanskProvider.php similarity index 100% rename from src/Provider/ZtmGdansk/ZtmGdanskProvider.php rename to api/src/Provider/ZtmGdansk/ZtmGdanskProvider.php diff --git a/src/Serialization/CarbonHandler.php b/api/src/Serialization/CarbonHandler.php similarity index 100% rename from src/Serialization/CarbonHandler.php rename to api/src/Serialization/CarbonHandler.php diff --git a/src/Serialization/LaravelCollectionHandler.php b/api/src/Serialization/LaravelCollectionHandler.php similarity index 100% rename from src/Serialization/LaravelCollectionHandler.php rename to api/src/Serialization/LaravelCollectionHandler.php diff --git a/src/Serialization/SerializeAs.php b/api/src/Serialization/SerializeAs.php similarity index 100% rename from src/Serialization/SerializeAs.php rename to api/src/Serialization/SerializeAs.php diff --git a/src/Service/AggregateConverter.php b/api/src/Service/AggregateConverter.php similarity index 100% rename from src/Service/AggregateConverter.php rename to api/src/Service/AggregateConverter.php diff --git a/src/Service/CacheableConverter.php b/api/src/Service/CacheableConverter.php similarity index 100% rename from src/Service/CacheableConverter.php rename to api/src/Service/CacheableConverter.php diff --git a/src/Service/Converter.php b/api/src/Service/Converter.php similarity index 100% rename from src/Service/Converter.php rename to api/src/Service/Converter.php diff --git a/src/Service/DataUpdater.php b/api/src/Service/DataUpdater.php similarity index 100% rename from src/Service/DataUpdater.php rename to api/src/Service/DataUpdater.php diff --git a/src/Service/EntityConverter.php b/api/src/Service/EntityConverter.php similarity index 100% rename from src/Service/EntityConverter.php rename to api/src/Service/EntityConverter.php diff --git a/src/Service/EntityReferenceFactory.php b/api/src/Service/EntityReferenceFactory.php similarity index 100% rename from src/Service/EntityReferenceFactory.php rename to api/src/Service/EntityReferenceFactory.php diff --git a/src/Service/HandlerProvider.php b/api/src/Service/HandlerProvider.php similarity index 100% rename from src/Service/HandlerProvider.php rename to api/src/Service/HandlerProvider.php diff --git a/src/Service/IdUtils.php b/api/src/Service/IdUtils.php similarity index 100% rename from src/Service/IdUtils.php rename to api/src/Service/IdUtils.php diff --git a/src/Service/IterableUtils.php b/api/src/Service/IterableUtils.php similarity index 100% rename from src/Service/IterableUtils.php rename to api/src/Service/IterableUtils.php diff --git a/src/Service/ModifierUtils.php b/api/src/Service/ModifierUtils.php similarity index 100% rename from src/Service/ModifierUtils.php rename to api/src/Service/ModifierUtils.php diff --git a/src/Service/Normalizer/JustReferenceNormalizer.php b/api/src/Service/Normalizer/JustReferenceNormalizer.php similarity index 100% rename from src/Service/Normalizer/JustReferenceNormalizer.php rename to api/src/Service/Normalizer/JustReferenceNormalizer.php diff --git a/src/Service/Normalizer/StopNormalizer.php b/api/src/Service/Normalizer/StopNormalizer.php similarity index 100% rename from src/Service/Normalizer/StopNormalizer.php rename to api/src/Service/Normalizer/StopNormalizer.php diff --git a/src/Service/ProviderConverter.php b/api/src/Service/ProviderConverter.php similarity index 100% rename from src/Service/ProviderConverter.php rename to api/src/Service/ProviderConverter.php diff --git a/src/Service/ProviderParameterConverter.php b/api/src/Service/ProviderParameterConverter.php similarity index 100% rename from src/Service/ProviderParameterConverter.php rename to api/src/Service/ProviderParameterConverter.php diff --git a/src/Service/ProviderResolver.php b/api/src/Service/ProviderResolver.php similarity index 100% rename from src/Service/ProviderResolver.php rename to api/src/Service/ProviderResolver.php diff --git a/src/Service/Proxy/ReferenceFactory.php b/api/src/Service/Proxy/ReferenceFactory.php similarity index 100% rename from src/Service/Proxy/ReferenceFactory.php rename to api/src/Service/Proxy/ReferenceFactory.php diff --git a/src/Service/Proxy/ReferenceObjectGenerator.php b/api/src/Service/Proxy/ReferenceObjectGenerator.php similarity index 100% rename from src/Service/Proxy/ReferenceObjectGenerator.php rename to api/src/Service/Proxy/ReferenceObjectGenerator.php diff --git a/src/Service/RecursiveConverter.php b/api/src/Service/RecursiveConverter.php similarity index 100% rename from src/Service/RecursiveConverter.php rename to api/src/Service/RecursiveConverter.php diff --git a/src/Service/RecursiveConverterTrait.php b/api/src/Service/RecursiveConverterTrait.php similarity index 100% rename from src/Service/RecursiveConverterTrait.php rename to api/src/Service/RecursiveConverterTrait.php diff --git a/src/Service/RepositoryParameterConverter.php b/api/src/Service/RepositoryParameterConverter.php similarity index 100% rename from src/Service/RepositoryParameterConverter.php rename to api/src/Service/RepositoryParameterConverter.php diff --git a/src/Service/ScheduledStopConverter.php b/api/src/Service/ScheduledStopConverter.php similarity index 100% rename from src/Service/ScheduledStopConverter.php rename to api/src/Service/ScheduledStopConverter.php diff --git a/src/Service/SerializerContextFactory.php b/api/src/Service/SerializerContextFactory.php similarity index 100% rename from src/Service/SerializerContextFactory.php rename to api/src/Service/SerializerContextFactory.php diff --git a/src/Service/VersionExtension.php b/api/src/Service/VersionExtension.php similarity index 100% rename from src/Service/VersionExtension.php rename to api/src/Service/VersionExtension.php diff --git a/src/Subscriber/JustReferenceSerializationSubscriber.php b/api/src/Subscriber/JustReferenceSerializationSubscriber.php similarity index 100% rename from src/Subscriber/JustReferenceSerializationSubscriber.php rename to api/src/Subscriber/JustReferenceSerializationSubscriber.php diff --git a/symfony.lock b/api/symfony.lock similarity index 100% rename from symfony.lock rename to api/symfony.lock diff --git a/templates/app.html.twig b/api/templates/app.html.twig similarity index 100% rename from templates/app.html.twig rename to api/templates/app.html.twig diff --git a/templates/base.html.twig b/api/templates/base.html.twig similarity index 88% rename from templates/base.html.twig rename to api/templates/base.html.twig index 20775bb..e123df6 100644 --- a/templates/base.html.twig +++ b/api/templates/base.html.twig @@ -3,7 +3,7 @@ <head> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - <link rel="stylesheet" href="{{ asset('dist/main.css') }}" /> + <link rel="stylesheet" href="dist/main.css" /> <link rel="manifest" href="{% block manifest 'manifest.json' %}" /> <!-- icons --> @@ -51,18 +51,18 @@ <footer class="container"> {% block footer %} <span> - <img src="{{ asset('images/logo.png') }}" alt="co jedzie logo"/> + <img src="images/logo.png" alt="co jedzie logo"/> v. {{ version() }} • <a href="{{ url('app.swagger_ui') }}">API</a> </span> <span class="copyright flex flex-space-left justify-content-end"> - <a href="https://kadet.net"><img src="{{ asset('images/kadet-net-logo.png') }}" alt="kadet.net logo" class="mx-1"/></a> + <a href="https://kadet.net"><img src="images/kadet-net-logo.png" alt="kadet.net logo" class="mx-1"/></a> © {{ 'now'|date('Y') }} </span> {% endblock %} </footer> {% block javascripts %}{% endblock %} - <script src="{{ asset('dist/main.js') }}"></script> + <script src="dist/main.js"></script> </body> </html> diff --git a/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig b/api/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig similarity index 100% rename from templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig rename to api/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig diff --git a/templates/choose.html.twig b/api/templates/choose.html.twig similarity index 100% rename from templates/choose.html.twig rename to api/templates/choose.html.twig diff --git a/templates/manifest.json.twig b/api/templates/manifest.json.twig similarity index 100% rename from templates/manifest.json.twig rename to api/templates/manifest.json.twig diff --git a/translations/.gitignore b/api/translations/.gitignore similarity index 100% rename from translations/.gitignore rename to api/translations/.gitignore diff --git a/docker-compose.yml b/docker-compose.yml index 8e724d0..a3a6004 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,19 +6,18 @@ services: ports: - "8080:80" volumes: - - ./:/var/www:cached + - ./front:/var/www/front:cached + - ./api:/var/www/api:cached - ./docker/nginx/czydojade:/etc/nginx/conf.d/czydojade.conf - php: - build: docker/php + api: + build: ./api env_file: - ./docker/php/.env volumes: - - ./:/var/www:cached + - ./api:/var/www:cached - ./docker/php/log.conf:/usr/local/etc/php-fpm.d/zz-log.conf - - blackfire: image: blackfire/blackfire ports: ["8707"] diff --git a/docker/nginx/czydojade b/docker/nginx/czydojade index dbd1fe7..5b9ea65 100644 --- a/docker/nginx/czydojade +++ b/docker/nginx/czydojade @@ -1,29 +1,35 @@ server { - root /var/www/public/; - server_name czydojade.localhost; + root /var/www/front/public/; + server_name cojedzie.localhost; index index.php; - location / { - try_files $uri $uri/ /index.php?$args; + location ~ \.(js|css)$ { + expires 1y; + } - location ~ \.(js|css)$ { - expires 1y; - } + location / { + try_files $uri $uri/ /index.php?$args; + } - location ~ ^/index\.php(/|$) { - fastcgi_pass php:9000; - fastcgi_split_path_info ^(.+\.php)(/.*)$; + location = / { + root /var/www/api/public/; + } - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; - fastcgi_param DOCUMENT_ROOT $realpath_root; + location ~ (.+).php(/|$) { + root /var/www/api/public/; - fastcgi_param APP_ENV "dev"; - fastcgi_param DATABASE_URL "sqlite:///%kernel.project_dir%/var/app.db"; - fastcgi_param GTM_TAG "GTM-00000"; + fastcgi_pass api:9000; + fastcgi_split_path_info ^(.+\.php)(/.*)$; - internal; - } - } + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME /var/www/public/$fastcgi_script_name; + fastcgi_param DOCUMENT_ROOT /var/www/public/; + + fastcgi_param APP_ENV "dev"; + fastcgi_param DATABASE_URL "sqlite:///%kernel.project_dir%/var/app.db"; + fastcgi_param GTM_TAG "GTM-00000"; + + internal; + } } diff --git a/front/.gitignore b/front/.gitignore new file mode 100644 index 0000000..fec845e --- /dev/null +++ b/front/.gitignore @@ -0,0 +1,5 @@ +yarn-error.log + +/public/* +!/public/.gitkeep +/node_modules/ diff --git a/package.json b/front/package.json similarity index 100% rename from package.json rename to front/package.json diff --git a/front/public/.gitkeep b/front/public/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/resources/components/departures.html b/front/resources/components/departures.html similarity index 100% rename from resources/components/departures.html rename to front/resources/components/departures.html diff --git a/resources/components/departures/departure.html b/front/resources/components/departures/departure.html similarity index 100% rename from resources/components/departures/departure.html rename to front/resources/components/departures/departure.html diff --git a/resources/components/favourites.html b/front/resources/components/favourites.html similarity index 100% rename from resources/components/favourites.html rename to front/resources/components/favourites.html diff --git a/resources/components/favourites/save.html b/front/resources/components/favourites/save.html similarity index 100% rename from resources/components/favourites/save.html rename to front/resources/components/favourites/save.html diff --git a/resources/components/finder.html b/front/resources/components/finder.html similarity index 100% rename from resources/components/finder.html rename to front/resources/components/finder.html diff --git a/resources/components/fold.html b/front/resources/components/fold.html similarity index 100% rename from resources/components/fold.html rename to front/resources/components/fold.html diff --git a/resources/components/lazy.html b/front/resources/components/lazy.html similarity index 100% rename from resources/components/lazy.html rename to front/resources/components/lazy.html diff --git a/resources/components/line.html b/front/resources/components/line.html similarity index 100% rename from resources/components/line.html rename to front/resources/components/line.html diff --git a/resources/components/messages.html b/front/resources/components/messages.html similarity index 100% rename from resources/components/messages.html rename to front/resources/components/messages.html diff --git a/resources/components/page/providers.html b/front/resources/components/page/providers.html similarity index 100% rename from resources/components/page/providers.html rename to front/resources/components/page/providers.html diff --git a/resources/components/picker/stop.html b/front/resources/components/picker/stop.html similarity index 100% rename from resources/components/picker/stop.html rename to front/resources/components/picker/stop.html diff --git a/resources/components/settings/departures.html b/front/resources/components/settings/departures.html similarity index 100% rename from resources/components/settings/departures.html rename to front/resources/components/settings/departures.html diff --git a/resources/components/settings/messages.html b/front/resources/components/settings/messages.html similarity index 100% rename from resources/components/settings/messages.html rename to front/resources/components/settings/messages.html diff --git a/resources/components/stop.html b/front/resources/components/stop.html similarity index 100% rename from resources/components/stop.html rename to front/resources/components/stop.html diff --git a/resources/components/stop/details.html b/front/resources/components/stop/details.html similarity index 100% rename from resources/components/stop/details.html rename to front/resources/components/stop/details.html diff --git a/resources/components/stop/history.html b/front/resources/components/stop/history.html similarity index 100% rename from resources/components/stop/history.html rename to front/resources/components/stop/history.html diff --git a/resources/components/stop/map.html b/front/resources/components/stop/map.html similarity index 100% rename from resources/components/stop/map.html rename to front/resources/components/stop/map.html diff --git a/resources/components/tooltip.html b/front/resources/components/tooltip.html similarity index 100% rename from resources/components/tooltip.html rename to front/resources/components/tooltip.html diff --git a/resources/components/trip.html b/front/resources/components/trip.html similarity index 100% rename from resources/components/trip.html rename to front/resources/components/trip.html diff --git a/resources/components/ui/dialog.html b/front/resources/components/ui/dialog.html similarity index 100% rename from resources/components/ui/dialog.html rename to front/resources/components/ui/dialog.html diff --git a/resources/components/ui/icon.html b/front/resources/components/ui/icon.html similarity index 100% rename from resources/components/ui/icon.html rename to front/resources/components/ui/icon.html diff --git a/resources/components/ui/numeric.html b/front/resources/components/ui/numeric.html similarity index 100% rename from resources/components/ui/numeric.html rename to front/resources/components/ui/numeric.html diff --git a/resources/components/ui/switch.html b/front/resources/components/ui/switch.html similarity index 100% rename from resources/components/ui/switch.html rename to front/resources/components/ui/switch.html diff --git a/resources/icons/light/bus.svg b/front/resources/icons/light/bus.svg similarity index 100% rename from resources/icons/light/bus.svg rename to front/resources/icons/light/bus.svg diff --git a/resources/icons/light/icons.ai b/front/resources/icons/light/icons.ai similarity index 100% rename from resources/icons/light/icons.ai rename to front/resources/icons/light/icons.ai diff --git a/resources/icons/light/metro.svg b/front/resources/icons/light/metro.svg similarity index 100% rename from resources/icons/light/metro.svg rename to front/resources/icons/light/metro.svg diff --git a/resources/icons/light/train.svg b/front/resources/icons/light/train.svg similarity index 100% rename from resources/icons/light/train.svg rename to front/resources/icons/light/train.svg diff --git a/resources/icons/light/tram.svg b/front/resources/icons/light/tram.svg similarity index 100% rename from resources/icons/light/tram.svg rename to front/resources/icons/light/tram.svg diff --git a/resources/icons/light/trolleybus.svg b/front/resources/icons/light/trolleybus.svg similarity index 100% rename from resources/icons/light/trolleybus.svg rename to front/resources/icons/light/trolleybus.svg diff --git a/resources/icons/light/unknown.svg b/front/resources/icons/light/unknown.svg similarity index 100% rename from resources/icons/light/unknown.svg rename to front/resources/icons/light/unknown.svg diff --git a/resources/images/app-icon.ai b/front/resources/images/app-icon.ai similarity index 100% rename from resources/images/app-icon.ai rename to front/resources/images/app-icon.ai diff --git a/resources/images/background-2x.png b/front/resources/images/background-2x.png similarity index 100% rename from resources/images/background-2x.png rename to front/resources/images/background-2x.png diff --git a/resources/images/background.png b/front/resources/images/background.png similarity index 100% rename from resources/images/background.png rename to front/resources/images/background.png diff --git a/resources/images/favicon-2x.png b/front/resources/images/favicon-2x.png similarity index 100% rename from resources/images/favicon-2x.png rename to front/resources/images/favicon-2x.png diff --git a/resources/images/favicon-72.png b/front/resources/images/favicon-72.png similarity index 100% rename from resources/images/favicon-72.png rename to front/resources/images/favicon-72.png diff --git a/resources/images/favicon.ai b/front/resources/images/favicon.ai similarity index 100% rename from resources/images/favicon.ai rename to front/resources/images/favicon.ai diff --git a/resources/images/favicon.ico b/front/resources/images/favicon.ico similarity index 100% rename from resources/images/favicon.ico rename to front/resources/images/favicon.ico diff --git a/resources/images/favicon.png b/front/resources/images/favicon.png similarity index 100% rename from resources/images/favicon.png rename to front/resources/images/favicon.png diff --git a/resources/images/icon-128.png b/front/resources/images/icon-128.png similarity index 100% rename from resources/images/icon-128.png rename to front/resources/images/icon-128.png diff --git a/resources/images/icon-192.png b/front/resources/images/icon-192.png similarity index 100% rename from resources/images/icon-192.png rename to front/resources/images/icon-192.png diff --git a/resources/images/icon-256.png b/front/resources/images/icon-256.png similarity index 100% rename from resources/images/icon-256.png rename to front/resources/images/icon-256.png diff --git a/resources/images/icon-512.png b/front/resources/images/icon-512.png similarity index 100% rename from resources/images/icon-512.png rename to front/resources/images/icon-512.png diff --git a/resources/images/icon-64.png b/front/resources/images/icon-64.png similarity index 100% rename from resources/images/icon-64.png rename to front/resources/images/icon-64.png diff --git a/resources/images/icon-96.png b/front/resources/images/icon-96.png similarity index 100% rename from resources/images/icon-96.png rename to front/resources/images/icon-96.png diff --git a/resources/images/icon-maskable.png b/front/resources/images/icon-maskable.png similarity index 100% rename from resources/images/icon-maskable.png rename to front/resources/images/icon-maskable.png diff --git a/resources/images/icon-monochrome.png b/front/resources/images/icon-monochrome.png similarity index 100% rename from resources/images/icon-monochrome.png rename to front/resources/images/icon-monochrome.png diff --git a/resources/images/ios-192.png b/front/resources/images/ios-192.png similarity index 100% rename from resources/images/ios-192.png rename to front/resources/images/ios-192.png diff --git a/resources/images/ios-80.png b/front/resources/images/ios-80.png similarity index 100% rename from resources/images/ios-80.png rename to front/resources/images/ios-80.png diff --git a/resources/images/ios.png b/front/resources/images/ios.png similarity index 100% rename from resources/images/ios.png rename to front/resources/images/ios.png diff --git a/resources/images/kadet-net-logo.png b/front/resources/images/kadet-net-logo.png similarity index 100% rename from resources/images/kadet-net-logo.png rename to front/resources/images/kadet-net-logo.png diff --git a/resources/images/logo-cojedzie.ai b/front/resources/images/logo-cojedzie.ai similarity index 100% rename from resources/images/logo-cojedzie.ai rename to front/resources/images/logo-cojedzie.ai diff --git a/resources/images/logo-concepts.ai b/front/resources/images/logo-concepts.ai similarity index 100% rename from resources/images/logo-concepts.ai rename to front/resources/images/logo-concepts.ai diff --git a/resources/images/logo-superhi.png b/front/resources/images/logo-superhi.png similarity index 100% rename from resources/images/logo-superhi.png rename to front/resources/images/logo-superhi.png diff --git a/resources/images/logo-vector.svg b/front/resources/images/logo-vector.svg similarity index 100% rename from resources/images/logo-vector.svg rename to front/resources/images/logo-vector.svg diff --git a/resources/images/logo.ai b/front/resources/images/logo.ai similarity index 100% rename from resources/images/logo.ai rename to front/resources/images/logo.ai diff --git a/resources/images/logo.png b/front/resources/images/logo.png similarity index 100% rename from resources/images/logo.png rename to front/resources/images/logo.png diff --git a/resources/styles/_animations.scss b/front/resources/styles/_animations.scss similarity index 100% rename from resources/styles/_animations.scss rename to front/resources/styles/_animations.scss diff --git a/resources/styles/_common.scss b/front/resources/styles/_common.scss similarity index 100% rename from resources/styles/_common.scss rename to front/resources/styles/_common.scss diff --git a/resources/styles/_controls.scss b/front/resources/styles/_controls.scss similarity index 100% rename from resources/styles/_controls.scss rename to front/resources/styles/_controls.scss diff --git a/resources/styles/_departure.scss b/front/resources/styles/_departure.scss similarity index 100% rename from resources/styles/_departure.scss rename to front/resources/styles/_departure.scss diff --git a/resources/styles/_dragscroll.scss b/front/resources/styles/_dragscroll.scss similarity index 100% rename from resources/styles/_dragscroll.scss rename to front/resources/styles/_dragscroll.scss diff --git a/resources/styles/_favourites.scss b/front/resources/styles/_favourites.scss similarity index 100% rename from resources/styles/_favourites.scss rename to front/resources/styles/_favourites.scss diff --git a/resources/styles/_form.scss b/front/resources/styles/_form.scss similarity index 100% rename from resources/styles/_form.scss rename to front/resources/styles/_form.scss diff --git a/resources/styles/_line.scss b/front/resources/styles/_line.scss similarity index 100% rename from resources/styles/_line.scss rename to front/resources/styles/_line.scss diff --git a/resources/styles/_map.scss b/front/resources/styles/_map.scss similarity index 100% rename from resources/styles/_map.scss rename to front/resources/styles/_map.scss diff --git a/resources/styles/_stop.scss b/front/resources/styles/_stop.scss similarity index 100% rename from resources/styles/_stop.scss rename to front/resources/styles/_stop.scss diff --git a/resources/styles/_trigonometry.scss b/front/resources/styles/_trigonometry.scss similarity index 100% rename from resources/styles/_trigonometry.scss rename to front/resources/styles/_trigonometry.scss diff --git a/resources/styles/_trip.scss b/front/resources/styles/_trip.scss similarity index 100% rename from resources/styles/_trip.scss rename to front/resources/styles/_trip.scss diff --git a/resources/styles/api.scss b/front/resources/styles/api.scss similarity index 100% rename from resources/styles/api.scss rename to front/resources/styles/api.scss diff --git a/resources/styles/main.scss b/front/resources/styles/main.scss similarity index 100% rename from resources/styles/main.scss rename to front/resources/styles/main.scss diff --git a/resources/styles/page/_provider-picker.scss b/front/resources/styles/page/_provider-picker.scss similarity index 100% rename from resources/styles/page/_provider-picker.scss rename to front/resources/styles/page/_provider-picker.scss diff --git a/resources/styles/ui/_modal.scss b/front/resources/styles/ui/_modal.scss similarity index 100% rename from resources/styles/ui/_modal.scss rename to front/resources/styles/ui/_modal.scss diff --git a/resources/styles/ui/_popup.scss b/front/resources/styles/ui/_popup.scss similarity index 100% rename from resources/styles/ui/_popup.scss rename to front/resources/styles/ui/_popup.scss diff --git a/resources/styles/ui/_switch.scss b/front/resources/styles/ui/_switch.scss similarity index 100% rename from resources/styles/ui/_switch.scss rename to front/resources/styles/ui/_switch.scss diff --git a/resources/svg-icon-loader.js b/front/resources/svg-icon-loader.js similarity index 100% rename from resources/svg-icon-loader.js rename to front/resources/svg-icon-loader.js diff --git a/resources/ts/app.ts b/front/resources/ts/app.ts similarity index 100% rename from resources/ts/app.ts rename to front/resources/ts/app.ts diff --git a/resources/ts/components/app.ts b/front/resources/ts/components/app.ts similarity index 100% rename from resources/ts/components/app.ts rename to front/resources/ts/components/app.ts diff --git a/resources/ts/components/departures.ts b/front/resources/ts/components/departures.ts similarity index 100% rename from resources/ts/components/departures.ts rename to front/resources/ts/components/departures.ts diff --git a/resources/ts/components/favourites.ts b/front/resources/ts/components/favourites.ts similarity index 100% rename from resources/ts/components/favourites.ts rename to front/resources/ts/components/favourites.ts diff --git a/resources/ts/components/history.ts b/front/resources/ts/components/history.ts similarity index 100% rename from resources/ts/components/history.ts rename to front/resources/ts/components/history.ts diff --git a/resources/ts/components/index.ts b/front/resources/ts/components/index.ts similarity index 100% rename from resources/ts/components/index.ts rename to front/resources/ts/components/index.ts diff --git a/resources/ts/components/line.ts b/front/resources/ts/components/line.ts similarity index 100% rename from resources/ts/components/line.ts rename to front/resources/ts/components/line.ts diff --git a/resources/ts/components/map.ts b/front/resources/ts/components/map.ts similarity index 100% rename from resources/ts/components/map.ts rename to front/resources/ts/components/map.ts diff --git a/resources/ts/components/messages.ts b/front/resources/ts/components/messages.ts similarity index 100% rename from resources/ts/components/messages.ts rename to front/resources/ts/components/messages.ts diff --git a/resources/ts/components/page/index.ts b/front/resources/ts/components/page/index.ts similarity index 100% rename from resources/ts/components/page/index.ts rename to front/resources/ts/components/page/index.ts diff --git a/resources/ts/components/page/providers.ts b/front/resources/ts/components/page/providers.ts similarity index 100% rename from resources/ts/components/page/providers.ts rename to front/resources/ts/components/page/providers.ts diff --git a/resources/ts/components/picker.ts b/front/resources/ts/components/picker.ts similarity index 100% rename from resources/ts/components/picker.ts rename to front/resources/ts/components/picker.ts diff --git a/resources/ts/components/settings/departures.ts b/front/resources/ts/components/settings/departures.ts similarity index 100% rename from resources/ts/components/settings/departures.ts rename to front/resources/ts/components/settings/departures.ts diff --git a/resources/ts/components/settings/index.ts b/front/resources/ts/components/settings/index.ts similarity index 100% rename from resources/ts/components/settings/index.ts rename to front/resources/ts/components/settings/index.ts diff --git a/resources/ts/components/settings/messages.ts b/front/resources/ts/components/settings/messages.ts similarity index 100% rename from resources/ts/components/settings/messages.ts rename to front/resources/ts/components/settings/messages.ts diff --git a/resources/ts/components/stop.ts b/front/resources/ts/components/stop.ts similarity index 100% rename from resources/ts/components/stop.ts rename to front/resources/ts/components/stop.ts diff --git a/resources/ts/components/tooltip.ts b/front/resources/ts/components/tooltip.ts similarity index 100% rename from resources/ts/components/tooltip.ts rename to front/resources/ts/components/tooltip.ts diff --git a/resources/ts/components/trip.ts b/front/resources/ts/components/trip.ts similarity index 100% rename from resources/ts/components/trip.ts rename to front/resources/ts/components/trip.ts diff --git a/resources/ts/components/ui/dialog.ts b/front/resources/ts/components/ui/dialog.ts similarity index 100% rename from resources/ts/components/ui/dialog.ts rename to front/resources/ts/components/ui/dialog.ts diff --git a/resources/ts/components/ui/icon.ts b/front/resources/ts/components/ui/icon.ts similarity index 100% rename from resources/ts/components/ui/icon.ts rename to front/resources/ts/components/ui/icon.ts diff --git a/resources/ts/components/ui/index.ts b/front/resources/ts/components/ui/index.ts similarity index 100% rename from resources/ts/components/ui/index.ts rename to front/resources/ts/components/ui/index.ts diff --git a/resources/ts/components/ui/numeric-input.ts b/front/resources/ts/components/ui/numeric-input.ts similarity index 100% rename from resources/ts/components/ui/numeric-input.ts rename to front/resources/ts/components/ui/numeric-input.ts diff --git a/resources/ts/components/ui/switch.ts b/front/resources/ts/components/ui/switch.ts similarity index 100% rename from resources/ts/components/ui/switch.ts rename to front/resources/ts/components/ui/switch.ts diff --git a/resources/ts/components/utils.ts b/front/resources/ts/components/utils.ts similarity index 100% rename from resources/ts/components/utils.ts rename to front/resources/ts/components/utils.ts diff --git a/resources/ts/decorators.ts b/front/resources/ts/decorators.ts similarity index 100% rename from resources/ts/decorators.ts rename to front/resources/ts/decorators.ts diff --git a/resources/ts/filters.ts b/front/resources/ts/filters.ts similarity index 100% rename from resources/ts/filters.ts rename to front/resources/ts/filters.ts diff --git a/resources/ts/icons.ts b/front/resources/ts/icons.ts similarity index 100% rename from resources/ts/icons.ts rename to front/resources/ts/icons.ts diff --git a/resources/ts/model/common.ts b/front/resources/ts/model/common.ts similarity index 100% rename from resources/ts/model/common.ts rename to front/resources/ts/model/common.ts diff --git a/resources/ts/model/departure.ts b/front/resources/ts/model/departure.ts similarity index 100% rename from resources/ts/model/departure.ts rename to front/resources/ts/model/departure.ts diff --git a/resources/ts/model/error.ts b/front/resources/ts/model/error.ts similarity index 100% rename from resources/ts/model/error.ts rename to front/resources/ts/model/error.ts diff --git a/resources/ts/model/identity.ts b/front/resources/ts/model/identity.ts similarity index 100% rename from resources/ts/model/identity.ts rename to front/resources/ts/model/identity.ts diff --git a/resources/ts/model/index.ts b/front/resources/ts/model/index.ts similarity index 100% rename from resources/ts/model/index.ts rename to front/resources/ts/model/index.ts diff --git a/resources/ts/model/line.ts b/front/resources/ts/model/line.ts similarity index 100% rename from resources/ts/model/line.ts rename to front/resources/ts/model/line.ts diff --git a/resources/ts/model/message.ts b/front/resources/ts/model/message.ts similarity index 100% rename from resources/ts/model/message.ts rename to front/resources/ts/model/message.ts diff --git a/resources/ts/model/provider.ts b/front/resources/ts/model/provider.ts similarity index 100% rename from resources/ts/model/provider.ts rename to front/resources/ts/model/provider.ts diff --git a/resources/ts/model/stop.ts b/front/resources/ts/model/stop.ts similarity index 100% rename from resources/ts/model/stop.ts rename to front/resources/ts/model/stop.ts diff --git a/resources/ts/model/trip.ts b/front/resources/ts/model/trip.ts similarity index 100% rename from resources/ts/model/trip.ts rename to front/resources/ts/model/trip.ts diff --git a/resources/ts/store/common.ts b/front/resources/ts/store/common.ts similarity index 100% rename from resources/ts/store/common.ts rename to front/resources/ts/store/common.ts diff --git a/resources/ts/store/departures.ts b/front/resources/ts/store/departures.ts similarity index 100% rename from resources/ts/store/departures.ts rename to front/resources/ts/store/departures.ts diff --git a/resources/ts/store/favourites.ts b/front/resources/ts/store/favourites.ts similarity index 100% rename from resources/ts/store/favourites.ts rename to front/resources/ts/store/favourites.ts diff --git a/resources/ts/store/history.ts b/front/resources/ts/store/history.ts similarity index 100% rename from resources/ts/store/history.ts rename to front/resources/ts/store/history.ts diff --git a/resources/ts/store/index.ts b/front/resources/ts/store/index.ts similarity index 100% rename from resources/ts/store/index.ts rename to front/resources/ts/store/index.ts diff --git a/resources/ts/store/messages.ts b/front/resources/ts/store/messages.ts similarity index 100% rename from resources/ts/store/messages.ts rename to front/resources/ts/store/messages.ts diff --git a/resources/ts/store/migrations.ts b/front/resources/ts/store/migrations.ts similarity index 100% rename from resources/ts/store/migrations.ts rename to front/resources/ts/store/migrations.ts diff --git a/resources/ts/store/root.ts b/front/resources/ts/store/root.ts similarity index 100% rename from resources/ts/store/root.ts rename to front/resources/ts/store/root.ts diff --git a/resources/ts/store/settings/departures.ts b/front/resources/ts/store/settings/departures.ts similarity index 100% rename from resources/ts/store/settings/departures.ts rename to front/resources/ts/store/settings/departures.ts diff --git a/resources/ts/store/settings/messages.ts b/front/resources/ts/store/settings/messages.ts similarity index 100% rename from resources/ts/store/settings/messages.ts rename to front/resources/ts/store/settings/messages.ts diff --git a/resources/ts/types/webpack.d.ts b/front/resources/ts/types/webpack.d.ts similarity index 100% rename from resources/ts/types/webpack.d.ts rename to front/resources/ts/types/webpack.d.ts diff --git a/resources/ts/urls.ts b/front/resources/ts/urls.ts similarity index 100% rename from resources/ts/urls.ts rename to front/resources/ts/urls.ts diff --git a/resources/ts/utils.ts b/front/resources/ts/utils.ts similarity index 100% rename from resources/ts/utils.ts rename to front/resources/ts/utils.ts diff --git a/tsconfig.json b/front/tsconfig.json similarity index 100% rename from tsconfig.json rename to front/tsconfig.json diff --git a/webpack.config.js b/front/webpack.config.js similarity index 100% rename from webpack.config.js rename to front/webpack.config.js diff --git a/yarn.lock b/front/yarn.lock similarity index 100% rename from yarn.lock rename to front/yarn.lock -- 2.45.2 From 3b02275b01c7c90395ffe8da1217f9025343cfb6 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 1 Nov 2020 18:39:47 +0100 Subject: [PATCH 50/77] #50 - cleanup frontend directory structure --- .../NelmioApiDocBundle/SwaggerUi/index.html.twig | 4 ++-- front/{resources/ts => src}/app.ts | 0 front/{resources/ts => src}/components/app.ts | 0 .../ts => src}/components/departures.ts | 4 ++-- .../ts => src}/components/favourites.ts | 4 ++-- .../{resources/ts => src}/components/history.ts | 2 +- front/{resources/ts => src}/components/index.ts | 0 front/{resources/ts => src}/components/line.ts | 2 +- front/{resources/ts => src}/components/map.ts | 0 .../{resources/ts => src}/components/messages.ts | 2 +- .../ts => src}/components/page/index.ts | 0 .../ts => src}/components/page/providers.ts | 2 +- front/{resources/ts => src}/components/picker.ts | 4 ++-- .../ts => src}/components/settings/departures.ts | 4 ++-- .../ts => src}/components/settings/index.ts | 0 .../ts => src}/components/settings/messages.ts | 2 +- front/{resources/ts => src}/components/stop.ts | 6 +++--- .../{resources/ts => src}/components/tooltip.ts | 2 +- front/{resources/ts => src}/components/trip.ts | 2 +- .../ts => src}/components/ui/dialog.ts | 2 +- .../{resources/ts => src}/components/ui/icon.ts | 2 +- .../{resources/ts => src}/components/ui/index.ts | 0 .../ts => src}/components/ui/numeric-input.ts | 2 +- .../ts => src}/components/ui/switch.ts | 2 +- front/{resources/ts => src}/components/utils.ts | 4 ++-- front/{resources/ts => src}/decorators.ts | 0 front/{resources/ts => src}/filters.ts | 0 front/{resources/ts => src}/icons.ts | 16 ++++++++-------- front/{resources/ts => src}/model/common.ts | 0 front/{resources/ts => src}/model/departure.ts | 0 front/{resources/ts => src}/model/error.ts | 0 front/{resources/ts => src}/model/identity.ts | 0 front/{resources/ts => src}/model/index.ts | 0 front/{resources/ts => src}/model/line.ts | 0 front/{resources/ts => src}/model/message.ts | 0 front/{resources/ts => src}/model/provider.ts | 0 front/{resources/ts => src}/model/stop.ts | 0 front/{resources/ts => src}/model/trip.ts | 0 front/{resources/ts => src}/store/common.ts | 0 front/{resources/ts => src}/store/departures.ts | 0 front/{resources/ts => src}/store/favourites.ts | 0 front/{resources/ts => src}/store/history.ts | 0 front/{resources/ts => src}/store/index.ts | 0 front/{resources/ts => src}/store/messages.ts | 0 front/{resources/ts => src}/store/migrations.ts | 0 front/{resources/ts => src}/store/root.ts | 0 .../ts => src}/store/settings/departures.ts | 0 .../ts => src}/store/settings/messages.ts | 0 front/{resources/ts => src}/types/webpack.d.ts | 0 front/{resources/ts => src}/urls.ts | 0 front/{resources/ts => src}/utils.ts | 0 front/{resources => }/styles/_animations.scss | 0 front/{resources => }/styles/_common.scss | 0 front/{resources => }/styles/_controls.scss | 0 front/{resources => }/styles/_departure.scss | 0 front/{resources => }/styles/_dragscroll.scss | 0 front/{resources => }/styles/_favourites.scss | 0 front/{resources => }/styles/_form.scss | 0 front/{resources => }/styles/_line.scss | 0 front/{resources => }/styles/_map.scss | 0 front/{resources => }/styles/_stop.scss | 0 front/{resources => }/styles/_trigonometry.scss | 0 front/{resources => }/styles/_trip.scss | 0 front/{resources => }/styles/api.scss | 0 front/{resources => }/styles/main.scss | 0 .../styles/page/_provider-picker.scss | 0 front/{resources => }/styles/ui/_modal.scss | 0 front/{resources => }/styles/ui/_popup.scss | 0 front/{resources => }/styles/ui/_switch.scss | 0 .../components => templates}/departures.html | 0 .../departures/departure.html | 0 .../components => templates}/favourites.html | 0 .../favourites/save.html | 0 .../components => templates}/finder.html | 0 .../components => templates}/fold.html | 0 .../components => templates}/lazy.html | 0 .../components => templates}/line.html | 0 .../components => templates}/messages.html | 0 .../components => templates}/page/providers.html | 0 .../components => templates}/picker/stop.html | 0 .../settings/departures.html | 0 .../settings/messages.html | 0 .../components => templates}/stop.html | 0 .../components => templates}/stop/details.html | 0 .../components => templates}/stop/history.html | 0 .../components => templates}/stop/map.html | 0 .../components => templates}/tooltip.html | 0 .../components => templates}/trip.html | 0 .../components => templates}/ui/dialog.html | 0 .../components => templates}/ui/icon.html | 0 .../components => templates}/ui/numeric.html | 0 .../components => templates}/ui/switch.html | 0 front/tsconfig.json | 14 +++++++++++--- front/webpack.config.js | 10 +++++++--- 94 files changed, 52 insertions(+), 40 deletions(-) rename front/{resources/ts => src}/app.ts (100%) rename front/{resources/ts => src}/components/app.ts (100%) rename front/{resources/ts => src}/components/departures.ts (92%) rename front/{resources/ts => src}/components/favourites.ts (93%) rename front/{resources/ts => src}/components/history.ts (83%) rename front/{resources/ts => src}/components/index.ts (100%) rename front/{resources/ts => src}/components/line.ts (81%) rename front/{resources/ts => src}/components/map.ts (100%) rename front/{resources/ts => src}/components/messages.ts (92%) rename front/{resources/ts => src}/components/page/index.ts (100%) rename front/{resources/ts => src}/components/page/providers.ts (91%) rename front/{resources/ts => src}/components/picker.ts (96%) rename front/{resources/ts => src}/components/settings/departures.ts (81%) rename front/{resources/ts => src}/components/settings/index.ts (100%) rename front/{resources/ts => src}/components/settings/messages.ts (87%) rename front/{resources/ts => src}/components/stop.ts (86%) rename front/{resources/ts => src}/components/tooltip.ts (97%) rename front/{resources/ts => src}/components/trip.ts (94%) rename front/{resources/ts => src}/components/ui/dialog.ts (99%) rename front/{resources/ts => src}/components/ui/icon.ts (98%) rename front/{resources/ts => src}/components/ui/index.ts (100%) rename front/{resources/ts => src}/components/ui/numeric-input.ts (94%) rename front/{resources/ts => src}/components/ui/switch.ts (87%) rename front/{resources/ts => src}/components/utils.ts (91%) rename front/{resources/ts => src}/decorators.ts (100%) rename front/{resources/ts => src}/filters.ts (100%) rename front/{resources/ts => src}/icons.ts (66%) rename front/{resources/ts => src}/model/common.ts (100%) rename front/{resources/ts => src}/model/departure.ts (100%) rename front/{resources/ts => src}/model/error.ts (100%) rename front/{resources/ts => src}/model/identity.ts (100%) rename front/{resources/ts => src}/model/index.ts (100%) rename front/{resources/ts => src}/model/line.ts (100%) rename front/{resources/ts => src}/model/message.ts (100%) rename front/{resources/ts => src}/model/provider.ts (100%) rename front/{resources/ts => src}/model/stop.ts (100%) rename front/{resources/ts => src}/model/trip.ts (100%) rename front/{resources/ts => src}/store/common.ts (100%) rename front/{resources/ts => src}/store/departures.ts (100%) rename front/{resources/ts => src}/store/favourites.ts (100%) rename front/{resources/ts => src}/store/history.ts (100%) rename front/{resources/ts => src}/store/index.ts (100%) rename front/{resources/ts => src}/store/messages.ts (100%) rename front/{resources/ts => src}/store/migrations.ts (100%) rename front/{resources/ts => src}/store/root.ts (100%) rename front/{resources/ts => src}/store/settings/departures.ts (100%) rename front/{resources/ts => src}/store/settings/messages.ts (100%) rename front/{resources/ts => src}/types/webpack.d.ts (100%) rename front/{resources/ts => src}/urls.ts (100%) rename front/{resources/ts => src}/utils.ts (100%) rename front/{resources => }/styles/_animations.scss (100%) rename front/{resources => }/styles/_common.scss (100%) rename front/{resources => }/styles/_controls.scss (100%) rename front/{resources => }/styles/_departure.scss (100%) rename front/{resources => }/styles/_dragscroll.scss (100%) rename front/{resources => }/styles/_favourites.scss (100%) rename front/{resources => }/styles/_form.scss (100%) rename front/{resources => }/styles/_line.scss (100%) rename front/{resources => }/styles/_map.scss (100%) rename front/{resources => }/styles/_stop.scss (100%) rename front/{resources => }/styles/_trigonometry.scss (100%) rename front/{resources => }/styles/_trip.scss (100%) rename front/{resources => }/styles/api.scss (100%) rename front/{resources => }/styles/main.scss (100%) rename front/{resources => }/styles/page/_provider-picker.scss (100%) rename front/{resources => }/styles/ui/_modal.scss (100%) rename front/{resources => }/styles/ui/_popup.scss (100%) rename front/{resources => }/styles/ui/_switch.scss (100%) rename front/{resources/components => templates}/departures.html (100%) rename front/{resources/components => templates}/departures/departure.html (100%) rename front/{resources/components => templates}/favourites.html (100%) rename front/{resources/components => templates}/favourites/save.html (100%) rename front/{resources/components => templates}/finder.html (100%) rename front/{resources/components => templates}/fold.html (100%) rename front/{resources/components => templates}/lazy.html (100%) rename front/{resources/components => templates}/line.html (100%) rename front/{resources/components => templates}/messages.html (100%) rename front/{resources/components => templates}/page/providers.html (100%) rename front/{resources/components => templates}/picker/stop.html (100%) rename front/{resources/components => templates}/settings/departures.html (100%) rename front/{resources/components => templates}/settings/messages.html (100%) rename front/{resources/components => templates}/stop.html (100%) rename front/{resources/components => templates}/stop/details.html (100%) rename front/{resources/components => templates}/stop/history.html (100%) rename front/{resources/components => templates}/stop/map.html (100%) rename front/{resources/components => templates}/tooltip.html (100%) rename front/{resources/components => templates}/trip.html (100%) rename front/{resources/components => templates}/ui/dialog.html (100%) rename front/{resources/components => templates}/ui/icon.html (100%) rename front/{resources/components => templates}/ui/numeric.html (100%) rename front/{resources/components => templates}/ui/switch.html (100%) diff --git a/api/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig b/api/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig index 0d4e685..ceb859e 100644 --- a/api/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig +++ b/api/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig @@ -5,5 +5,5 @@ {% block stylesheets %} {{ parent() }} <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700"> - <link rel="stylesheet" href="{{ asset('dist/api.css') }}" /> -{% endblock stylesheets %} \ No newline at end of file + <link rel="stylesheet" href="dist/api.css" /> +{% endblock stylesheets %} diff --git a/front/resources/ts/app.ts b/front/src/app.ts similarity index 100% rename from front/resources/ts/app.ts rename to front/src/app.ts diff --git a/front/resources/ts/components/app.ts b/front/src/components/app.ts similarity index 100% rename from front/resources/ts/components/app.ts rename to front/src/components/app.ts diff --git a/front/resources/ts/components/departures.ts b/front/src/components/departures.ts similarity index 92% rename from front/resources/ts/components/departures.ts rename to front/src/components/departures.ts index 19c00f8..3318ef5 100644 --- a/front/resources/ts/components/departures.ts +++ b/front/src/components/departures.ts @@ -7,12 +7,12 @@ import urls from "../urls"; import { Jsonified } from "../utils"; import * as moment from "moment"; -@Component({ template: require("../../components/departures.html"), store }) +@Component({ template: require("../../templates/departures.html"), store }) export class DeparturesComponent extends Vue { @Departures.State departures: Departure[]; } -@Component({ template: require("../../components/departures/departure.html"), store }) +@Component({ template: require("../../templates/departures/departure.html"), store }) export class DepartureComponent extends Vue { @Prop(Object) departure: Departure; scheduledTrip: Trip = null; diff --git a/front/resources/ts/components/favourites.ts b/front/src/components/favourites.ts similarity index 93% rename from front/resources/ts/components/favourites.ts rename to front/src/components/favourites.ts index a7e0fd1..2f89150 100644 --- a/front/resources/ts/components/favourites.ts +++ b/front/src/components/favourites.ts @@ -7,7 +7,7 @@ import * as uuid from "uuid"; import { Favourites } from "../store"; -@Component({ template: require('../../components/favourites.html' )}) +@Component({ template: require('../../templates/favourites.html' )}) export class FavouritesComponent extends Vue { @Favourites.State favourites: Favourite[]; @Favourites.Mutation remove: (fav: Favourite) => void; @@ -26,7 +26,7 @@ function createFavouriteEntry(name: string, stops: Stop[]): Favourite { } } -@Component({ template: require('../../components/favourites/save.html' )}) +@Component({ template: require('../../templates/favourites/save.html' )}) export class FavouritesAdderComponent extends Vue { @State stops: Stop[]; diff --git a/front/resources/ts/components/history.ts b/front/src/components/history.ts similarity index 83% rename from front/resources/ts/components/history.ts rename to front/src/components/history.ts index 3f1260f..f7ee2b9 100644 --- a/front/resources/ts/components/history.ts +++ b/front/src/components/history.ts @@ -5,7 +5,7 @@ import { HistoryEntry } from "../store/history"; import { Mutation } from "vuex-class"; import { Stop } from "../model"; -@Component({ template: require('../../components/stop/history.html' )}) +@Component({ template: require('../../templates/stop/history.html' )}) export class StopHistory extends Vue { @History.Getter all: HistoryEntry[]; diff --git a/front/resources/ts/components/index.ts b/front/src/components/index.ts similarity index 100% rename from front/resources/ts/components/index.ts rename to front/src/components/index.ts diff --git a/front/resources/ts/components/line.ts b/front/src/components/line.ts similarity index 81% rename from front/resources/ts/components/line.ts rename to front/src/components/line.ts index 86ca509..30be33a 100644 --- a/front/resources/ts/components/line.ts +++ b/front/src/components/line.ts @@ -2,7 +2,7 @@ import Vue from 'vue' import { Component, Prop } from 'vue-property-decorator' import { Line } from "../model"; -@Component({ template: require('../../components/line.html' )}) +@Component({ template: require('../../templates/line.html' )}) export class LineComponent extends Vue { @Prop(Object) public line: Line; diff --git a/front/resources/ts/components/map.ts b/front/src/components/map.ts similarity index 100% rename from front/resources/ts/components/map.ts rename to front/src/components/map.ts diff --git a/front/resources/ts/components/messages.ts b/front/src/components/messages.ts similarity index 92% rename from front/resources/ts/components/messages.ts rename to front/src/components/messages.ts index e9f054c..0c50186 100644 --- a/front/resources/ts/components/messages.ts +++ b/front/src/components/messages.ts @@ -3,7 +3,7 @@ import { Component } from "vue-property-decorator"; import { Message } from "../model/message"; import store, { Messages, MessagesSettings } from '../store' -@Component({ template: require("../../components/messages.html"), store }) +@Component({ template: require("../../templates/messages.html"), store }) export class MessagesComponent extends Vue { @Messages.State('messages') public allMessages: Message[]; diff --git a/front/resources/ts/components/page/index.ts b/front/src/components/page/index.ts similarity index 100% rename from front/resources/ts/components/page/index.ts rename to front/src/components/page/index.ts diff --git a/front/resources/ts/components/page/providers.ts b/front/src/components/page/providers.ts similarity index 91% rename from front/resources/ts/components/page/providers.ts rename to front/src/components/page/providers.ts index 7e257ba..dc6b484 100644 --- a/front/resources/ts/components/page/providers.ts +++ b/front/src/components/page/providers.ts @@ -5,7 +5,7 @@ import { Jsonified } from "../../utils"; import * as moment from 'moment'; @Component({ - template: require('../../../components/page/providers.html'), + template: require('../../../templates/page/providers.html'), }) export class PageProviderList extends Vue { private providers: Provider[] = []; diff --git a/front/resources/ts/components/picker.ts b/front/src/components/picker.ts similarity index 96% rename from front/resources/ts/components/picker.ts rename to front/src/components/picker.ts index 2faa73a..3b7f072 100644 --- a/front/resources/ts/components/picker.ts +++ b/front/src/components/picker.ts @@ -9,7 +9,7 @@ import { Mutation } from "vuex-class"; import { HistoryEntry } from "../store/history"; import { StopHistory } from "./history"; -@Component({ template: require('../../components/picker/stop.html') }) +@Component({ template: require('../../templates/picker/stop.html') }) export class PickerStopComponent extends Vue { @Prop(Object) public stop: Stop; @@ -50,7 +50,7 @@ export class PickerStopComponent extends Vue { } @Component({ - template: require('../../components/finder.html'), + template: require('../../templates/finder.html'), components: { "PickerStop": PickerStopComponent, "StopHistory": StopHistory, diff --git a/front/resources/ts/components/settings/departures.ts b/front/src/components/settings/departures.ts similarity index 81% rename from front/resources/ts/components/settings/departures.ts rename to front/src/components/settings/departures.ts index 8625d0a..8e35873 100644 --- a/front/resources/ts/components/settings/departures.ts +++ b/front/src/components/settings/departures.ts @@ -1,9 +1,9 @@ -import { Component, Prop } from "vue-property-decorator"; +import { Component } from "vue-property-decorator"; import store, { DeparturesSettings } from "../../store"; import Vue from "vue"; import { DeparturesSettingsState } from "../../store/settings/departures"; -@Component({ template: require("../../../components/settings/departures.html"), store }) +@Component({ template: require("../../../templates/settings/departures.html"), store }) export class SettingsDepartures extends Vue { @DeparturesSettings.State public autorefresh: boolean; diff --git a/front/resources/ts/components/settings/index.ts b/front/src/components/settings/index.ts similarity index 100% rename from front/resources/ts/components/settings/index.ts rename to front/src/components/settings/index.ts diff --git a/front/resources/ts/components/settings/messages.ts b/front/src/components/settings/messages.ts similarity index 87% rename from front/resources/ts/components/settings/messages.ts rename to front/src/components/settings/messages.ts index 4f66700..fc2a268 100644 --- a/front/resources/ts/components/settings/messages.ts +++ b/front/src/components/settings/messages.ts @@ -3,7 +3,7 @@ import store, { MessagesSettings } from "../../store"; import Vue from "vue"; import { MessagesSettingsState } from "../../store/settings/messages"; -@Component({template: require("../../../components/settings/messages.html"), store}) +@Component({template: require("../../../templates/settings/messages.html"), store}) export class SettingsMessages extends Vue { @MessagesSettings.State public autorefresh: boolean; diff --git a/front/resources/ts/components/stop.ts b/front/src/components/stop.ts similarity index 86% rename from front/resources/ts/components/stop.ts rename to front/src/components/stop.ts index 1439564..0afd0b0 100644 --- a/front/resources/ts/components/stop.ts +++ b/front/src/components/stop.ts @@ -3,7 +3,7 @@ import { Line, Stop, Track } from "../model"; import Vue from 'vue'; import urls from "../urls"; -@Component({ template: require('../../components/stop/details.html') }) +@Component({ template: require('../../templates/stop/details.html') }) class StopDetailsComponent extends Vue { @Prop(Object) public stop: Stop; @@ -35,13 +35,13 @@ class StopDetailsComponent extends Vue { } } -@Component({ template: require('../../components/stop.html') }) +@Component({ template: require('../../templates/stop.html') }) export class StopComponent extends Vue { @Prop(Object) public stop: Stop; } -@Component({ template: require('../../components/stop/map.html') }) +@Component({ template: require('../../templates/stop/map.html') }) export class StopMapComponent extends Vue { @Prop(Object) public stop: Stop; diff --git a/front/resources/ts/components/tooltip.ts b/front/src/components/tooltip.ts similarity index 97% rename from front/resources/ts/components/tooltip.ts rename to front/src/components/tooltip.ts index 4bb6b9e..1276133 100644 --- a/front/resources/ts/components/tooltip.ts +++ b/front/src/components/tooltip.ts @@ -10,7 +10,7 @@ type Trigger = "hover" | "focus" | "long-press"; const longPressTimeout = 1000; -@Component({ template: require('../../components/tooltip.html') }) +@Component({ template: require('../../templates/tooltip.html') }) export class TooltipComponent extends Vue { @Prop({ type: String, default: "top" }) public placement: string; @Prop({ type: Number, default: 400 }) public delay: number; diff --git a/front/resources/ts/components/trip.ts b/front/src/components/trip.ts similarity index 94% rename from front/resources/ts/components/trip.ts rename to front/src/components/trip.ts index fb70e0e..584ba82 100644 --- a/front/resources/ts/components/trip.ts +++ b/front/src/components/trip.ts @@ -7,7 +7,7 @@ import * as moment from 'moment'; type ScheduledStopInfo = ScheduledStop & { visited: boolean, current: boolean }; -@Component({ template: require("../../components/trip.html") }) +@Component({ template: require("../../templates/trip.html") }) export class TripComponent extends Vue { @Prop(Array) public schedule: ScheduledStop[]; @Prop(Object) public current: Stop; diff --git a/front/resources/ts/components/ui/dialog.ts b/front/src/components/ui/dialog.ts similarity index 99% rename from front/resources/ts/components/ui/dialog.ts rename to front/src/components/ui/dialog.ts index 18580ba..d8be47f 100644 --- a/front/resources/ts/components/ui/dialog.ts +++ b/front/src/components/ui/dialog.ts @@ -34,7 +34,7 @@ function computeZIndexOfElement(element: HTMLElement): number { @Component({ inheritAttrs: false, - template: require('../../../components/ui/dialog.html'), + template: require('../../../templates/ui/dialog.html'), }) export default class UiDialog extends Vue { @Prop({ type: String, default: "popup" }) diff --git a/front/resources/ts/components/ui/icon.ts b/front/src/components/ui/icon.ts similarity index 98% rename from front/resources/ts/components/ui/icon.ts rename to front/src/components/ui/icon.ts index 6e80aa0..dc41d63 100644 --- a/front/resources/ts/components/ui/icon.ts +++ b/front/src/components/ui/icon.ts @@ -117,7 +117,7 @@ const extractAllIcons = (icons: Icon[]) => icons.map(icon => { library.add(...extractAllIcons(Object.values(definitions))); @Component({ - template: require('../../../components/ui/icon.html'), + template: require('../../../templates/ui/icon.html'), components: { fa: FontAwesomeIcon, faLayers: FontAwesomeLayers, diff --git a/front/resources/ts/components/ui/index.ts b/front/src/components/ui/index.ts similarity index 100% rename from front/resources/ts/components/ui/index.ts rename to front/src/components/ui/index.ts diff --git a/front/resources/ts/components/ui/numeric-input.ts b/front/src/components/ui/numeric-input.ts similarity index 94% rename from front/resources/ts/components/ui/numeric-input.ts rename to front/src/components/ui/numeric-input.ts index f8ef7e9..54e2192 100644 --- a/front/resources/ts/components/ui/numeric-input.ts +++ b/front/src/components/ui/numeric-input.ts @@ -3,7 +3,7 @@ import { Component, Prop } from 'vue-property-decorator' import * as uuid from "uuid"; @Component({ - template: require('../../../components/ui/numeric.html'), + template: require('../../../templates/ui/numeric.html'), inheritAttrs: false }) export class UiNumericInput extends Vue { diff --git a/front/resources/ts/components/ui/switch.ts b/front/src/components/ui/switch.ts similarity index 87% rename from front/resources/ts/components/ui/switch.ts rename to front/src/components/ui/switch.ts index d8a6dce..ff819b1 100644 --- a/front/resources/ts/components/ui/switch.ts +++ b/front/src/components/ui/switch.ts @@ -3,7 +3,7 @@ import { Component, Prop } from 'vue-property-decorator' import * as uuid from "uuid"; @Component({ - template: require('../../../components/ui/switch.html'), + template: require('../../../templates/ui/switch.html'), inheritAttrs: false }) export class UiSwitch extends Vue { diff --git a/front/resources/ts/components/utils.ts b/front/src/components/utils.ts similarity index 91% rename from front/resources/ts/components/utils.ts rename to front/src/components/utils.ts index 464fc68..edfd173 100644 --- a/front/resources/ts/components/utils.ts +++ b/front/src/components/utils.ts @@ -2,7 +2,7 @@ import Vue from 'vue'; import { Component, Prop, Watch } from "vue-property-decorator"; -@Component({ template: require('../../components/fold.html') }) +@Component({ template: require('../../templates/fold.html') }) export class FoldComponent extends Vue { private observer: MutationObserver; @@ -34,7 +34,7 @@ export class FoldComponent extends Vue { } } -@Component({ template: require("../../components/lazy.html") }) +@Component({ template: require("../../templates/lazy.html") }) export class LazyComponent extends Vue { @Prop(Boolean) public activate: boolean; diff --git a/front/resources/ts/decorators.ts b/front/src/decorators.ts similarity index 100% rename from front/resources/ts/decorators.ts rename to front/src/decorators.ts diff --git a/front/resources/ts/filters.ts b/front/src/filters.ts similarity index 100% rename from front/resources/ts/filters.ts rename to front/src/filters.ts diff --git a/front/resources/ts/icons.ts b/front/src/icons.ts similarity index 66% rename from front/resources/ts/icons.ts rename to front/src/icons.ts index 9dd6072..7684894 100644 --- a/front/resources/ts/icons.ts +++ b/front/src/icons.ts @@ -1,11 +1,11 @@ -import { IconPack, IconDefinition } from '@fortawesome/fontawesome-svg-core'; +import { IconDefinition, IconPack } from '@fortawesome/fontawesome-svg-core'; -import * as bus from "../icons/light/bus.svg"; -import * as tram from "../icons/light/tram.svg"; -import * as trolleybus from "../icons/light/trolleybus.svg"; -import * as metro from "../icons/light/metro.svg"; -import * as train from "../icons/light/train.svg"; -import * as unknown from "../icons/light/unknown.svg"; +import * as bus from "@resources/icons/light/bus.svg"; +import * as tram from "@resources/icons/light/tram.svg"; +import * as trolleybus from "@resources/icons/light/trolleybus.svg"; +import * as metro from "@resources/icons/light/metro.svg"; +import * as train from "@resources/icons/light/train.svg"; +import * as unknown from "@resources/icons/light/unknown.svg"; export const faBus: IconDefinition = <any>{ prefix: 'fac', @@ -45,4 +45,4 @@ export const faUnknown = <any>{ export const fac: IconPack = { faBus, faTram, faTrain, faTrolleybus, faMetro, faUnknown -}; \ No newline at end of file +}; diff --git a/front/resources/ts/model/common.ts b/front/src/model/common.ts similarity index 100% rename from front/resources/ts/model/common.ts rename to front/src/model/common.ts diff --git a/front/resources/ts/model/departure.ts b/front/src/model/departure.ts similarity index 100% rename from front/resources/ts/model/departure.ts rename to front/src/model/departure.ts diff --git a/front/resources/ts/model/error.ts b/front/src/model/error.ts similarity index 100% rename from front/resources/ts/model/error.ts rename to front/src/model/error.ts diff --git a/front/resources/ts/model/identity.ts b/front/src/model/identity.ts similarity index 100% rename from front/resources/ts/model/identity.ts rename to front/src/model/identity.ts diff --git a/front/resources/ts/model/index.ts b/front/src/model/index.ts similarity index 100% rename from front/resources/ts/model/index.ts rename to front/src/model/index.ts diff --git a/front/resources/ts/model/line.ts b/front/src/model/line.ts similarity index 100% rename from front/resources/ts/model/line.ts rename to front/src/model/line.ts diff --git a/front/resources/ts/model/message.ts b/front/src/model/message.ts similarity index 100% rename from front/resources/ts/model/message.ts rename to front/src/model/message.ts diff --git a/front/resources/ts/model/provider.ts b/front/src/model/provider.ts similarity index 100% rename from front/resources/ts/model/provider.ts rename to front/src/model/provider.ts diff --git a/front/resources/ts/model/stop.ts b/front/src/model/stop.ts similarity index 100% rename from front/resources/ts/model/stop.ts rename to front/src/model/stop.ts diff --git a/front/resources/ts/model/trip.ts b/front/src/model/trip.ts similarity index 100% rename from front/resources/ts/model/trip.ts rename to front/src/model/trip.ts diff --git a/front/resources/ts/store/common.ts b/front/src/store/common.ts similarity index 100% rename from front/resources/ts/store/common.ts rename to front/src/store/common.ts diff --git a/front/resources/ts/store/departures.ts b/front/src/store/departures.ts similarity index 100% rename from front/resources/ts/store/departures.ts rename to front/src/store/departures.ts diff --git a/front/resources/ts/store/favourites.ts b/front/src/store/favourites.ts similarity index 100% rename from front/resources/ts/store/favourites.ts rename to front/src/store/favourites.ts diff --git a/front/resources/ts/store/history.ts b/front/src/store/history.ts similarity index 100% rename from front/resources/ts/store/history.ts rename to front/src/store/history.ts diff --git a/front/resources/ts/store/index.ts b/front/src/store/index.ts similarity index 100% rename from front/resources/ts/store/index.ts rename to front/src/store/index.ts diff --git a/front/resources/ts/store/messages.ts b/front/src/store/messages.ts similarity index 100% rename from front/resources/ts/store/messages.ts rename to front/src/store/messages.ts diff --git a/front/resources/ts/store/migrations.ts b/front/src/store/migrations.ts similarity index 100% rename from front/resources/ts/store/migrations.ts rename to front/src/store/migrations.ts diff --git a/front/resources/ts/store/root.ts b/front/src/store/root.ts similarity index 100% rename from front/resources/ts/store/root.ts rename to front/src/store/root.ts diff --git a/front/resources/ts/store/settings/departures.ts b/front/src/store/settings/departures.ts similarity index 100% rename from front/resources/ts/store/settings/departures.ts rename to front/src/store/settings/departures.ts diff --git a/front/resources/ts/store/settings/messages.ts b/front/src/store/settings/messages.ts similarity index 100% rename from front/resources/ts/store/settings/messages.ts rename to front/src/store/settings/messages.ts diff --git a/front/resources/ts/types/webpack.d.ts b/front/src/types/webpack.d.ts similarity index 100% rename from front/resources/ts/types/webpack.d.ts rename to front/src/types/webpack.d.ts diff --git a/front/resources/ts/urls.ts b/front/src/urls.ts similarity index 100% rename from front/resources/ts/urls.ts rename to front/src/urls.ts diff --git a/front/resources/ts/utils.ts b/front/src/utils.ts similarity index 100% rename from front/resources/ts/utils.ts rename to front/src/utils.ts diff --git a/front/resources/styles/_animations.scss b/front/styles/_animations.scss similarity index 100% rename from front/resources/styles/_animations.scss rename to front/styles/_animations.scss diff --git a/front/resources/styles/_common.scss b/front/styles/_common.scss similarity index 100% rename from front/resources/styles/_common.scss rename to front/styles/_common.scss diff --git a/front/resources/styles/_controls.scss b/front/styles/_controls.scss similarity index 100% rename from front/resources/styles/_controls.scss rename to front/styles/_controls.scss diff --git a/front/resources/styles/_departure.scss b/front/styles/_departure.scss similarity index 100% rename from front/resources/styles/_departure.scss rename to front/styles/_departure.scss diff --git a/front/resources/styles/_dragscroll.scss b/front/styles/_dragscroll.scss similarity index 100% rename from front/resources/styles/_dragscroll.scss rename to front/styles/_dragscroll.scss diff --git a/front/resources/styles/_favourites.scss b/front/styles/_favourites.scss similarity index 100% rename from front/resources/styles/_favourites.scss rename to front/styles/_favourites.scss diff --git a/front/resources/styles/_form.scss b/front/styles/_form.scss similarity index 100% rename from front/resources/styles/_form.scss rename to front/styles/_form.scss diff --git a/front/resources/styles/_line.scss b/front/styles/_line.scss similarity index 100% rename from front/resources/styles/_line.scss rename to front/styles/_line.scss diff --git a/front/resources/styles/_map.scss b/front/styles/_map.scss similarity index 100% rename from front/resources/styles/_map.scss rename to front/styles/_map.scss diff --git a/front/resources/styles/_stop.scss b/front/styles/_stop.scss similarity index 100% rename from front/resources/styles/_stop.scss rename to front/styles/_stop.scss diff --git a/front/resources/styles/_trigonometry.scss b/front/styles/_trigonometry.scss similarity index 100% rename from front/resources/styles/_trigonometry.scss rename to front/styles/_trigonometry.scss diff --git a/front/resources/styles/_trip.scss b/front/styles/_trip.scss similarity index 100% rename from front/resources/styles/_trip.scss rename to front/styles/_trip.scss diff --git a/front/resources/styles/api.scss b/front/styles/api.scss similarity index 100% rename from front/resources/styles/api.scss rename to front/styles/api.scss diff --git a/front/resources/styles/main.scss b/front/styles/main.scss similarity index 100% rename from front/resources/styles/main.scss rename to front/styles/main.scss diff --git a/front/resources/styles/page/_provider-picker.scss b/front/styles/page/_provider-picker.scss similarity index 100% rename from front/resources/styles/page/_provider-picker.scss rename to front/styles/page/_provider-picker.scss diff --git a/front/resources/styles/ui/_modal.scss b/front/styles/ui/_modal.scss similarity index 100% rename from front/resources/styles/ui/_modal.scss rename to front/styles/ui/_modal.scss diff --git a/front/resources/styles/ui/_popup.scss b/front/styles/ui/_popup.scss similarity index 100% rename from front/resources/styles/ui/_popup.scss rename to front/styles/ui/_popup.scss diff --git a/front/resources/styles/ui/_switch.scss b/front/styles/ui/_switch.scss similarity index 100% rename from front/resources/styles/ui/_switch.scss rename to front/styles/ui/_switch.scss diff --git a/front/resources/components/departures.html b/front/templates/departures.html similarity index 100% rename from front/resources/components/departures.html rename to front/templates/departures.html diff --git a/front/resources/components/departures/departure.html b/front/templates/departures/departure.html similarity index 100% rename from front/resources/components/departures/departure.html rename to front/templates/departures/departure.html diff --git a/front/resources/components/favourites.html b/front/templates/favourites.html similarity index 100% rename from front/resources/components/favourites.html rename to front/templates/favourites.html diff --git a/front/resources/components/favourites/save.html b/front/templates/favourites/save.html similarity index 100% rename from front/resources/components/favourites/save.html rename to front/templates/favourites/save.html diff --git a/front/resources/components/finder.html b/front/templates/finder.html similarity index 100% rename from front/resources/components/finder.html rename to front/templates/finder.html diff --git a/front/resources/components/fold.html b/front/templates/fold.html similarity index 100% rename from front/resources/components/fold.html rename to front/templates/fold.html diff --git a/front/resources/components/lazy.html b/front/templates/lazy.html similarity index 100% rename from front/resources/components/lazy.html rename to front/templates/lazy.html diff --git a/front/resources/components/line.html b/front/templates/line.html similarity index 100% rename from front/resources/components/line.html rename to front/templates/line.html diff --git a/front/resources/components/messages.html b/front/templates/messages.html similarity index 100% rename from front/resources/components/messages.html rename to front/templates/messages.html diff --git a/front/resources/components/page/providers.html b/front/templates/page/providers.html similarity index 100% rename from front/resources/components/page/providers.html rename to front/templates/page/providers.html diff --git a/front/resources/components/picker/stop.html b/front/templates/picker/stop.html similarity index 100% rename from front/resources/components/picker/stop.html rename to front/templates/picker/stop.html diff --git a/front/resources/components/settings/departures.html b/front/templates/settings/departures.html similarity index 100% rename from front/resources/components/settings/departures.html rename to front/templates/settings/departures.html diff --git a/front/resources/components/settings/messages.html b/front/templates/settings/messages.html similarity index 100% rename from front/resources/components/settings/messages.html rename to front/templates/settings/messages.html diff --git a/front/resources/components/stop.html b/front/templates/stop.html similarity index 100% rename from front/resources/components/stop.html rename to front/templates/stop.html diff --git a/front/resources/components/stop/details.html b/front/templates/stop/details.html similarity index 100% rename from front/resources/components/stop/details.html rename to front/templates/stop/details.html diff --git a/front/resources/components/stop/history.html b/front/templates/stop/history.html similarity index 100% rename from front/resources/components/stop/history.html rename to front/templates/stop/history.html diff --git a/front/resources/components/stop/map.html b/front/templates/stop/map.html similarity index 100% rename from front/resources/components/stop/map.html rename to front/templates/stop/map.html diff --git a/front/resources/components/tooltip.html b/front/templates/tooltip.html similarity index 100% rename from front/resources/components/tooltip.html rename to front/templates/tooltip.html diff --git a/front/resources/components/trip.html b/front/templates/trip.html similarity index 100% rename from front/resources/components/trip.html rename to front/templates/trip.html diff --git a/front/resources/components/ui/dialog.html b/front/templates/ui/dialog.html similarity index 100% rename from front/resources/components/ui/dialog.html rename to front/templates/ui/dialog.html diff --git a/front/resources/components/ui/icon.html b/front/templates/ui/icon.html similarity index 100% rename from front/resources/components/ui/icon.html rename to front/templates/ui/icon.html diff --git a/front/resources/components/ui/numeric.html b/front/templates/ui/numeric.html similarity index 100% rename from front/resources/components/ui/numeric.html rename to front/templates/ui/numeric.html diff --git a/front/resources/components/ui/switch.html b/front/templates/ui/switch.html similarity index 100% rename from front/resources/components/ui/switch.html rename to front/templates/ui/switch.html diff --git a/front/tsconfig.json b/front/tsconfig.json index 3d3c4a9..62af5bd 100644 --- a/front/tsconfig.json +++ b/front/tsconfig.json @@ -7,8 +7,16 @@ "sourceMap": true, "noImplicitThis": true, "moduleResolution": "node", - "downlevelIteration": true + "downlevelIteration": true, + "allowSyntheticDefaultImports": true, + "baseUrl": "./", + "paths": { + "@templates/*": ["./templates/*"], + "@resources/*": ["./resources/*"], + "@styles/*": ["./styles/*"], + "@/*": ["./src/*"] + } }, - "files": ["resources/ts/app.ts"], - "include": ["resources/ts/**/*.ts"] + "files": ["src/app.ts"], + "include": ["src/**/*.ts"] } diff --git a/front/webpack.config.js b/front/webpack.config.js index 314ae97..1762344 100644 --- a/front/webpack.config.js +++ b/front/webpack.config.js @@ -7,8 +7,8 @@ const { GenerateSW } = require('workbox-webpack-plugin'); const config = { entry: { - main: ['./resources/ts/app.ts'], - api: ['./resources/styles/api.scss'] + main: ['./src/app.ts'], + api: ['./styles/api.scss'] }, output: { path: path.resolve('./public/dist/'), @@ -20,7 +20,11 @@ const config = { extensions: ['.tsx', '.ts', '.js'], alias: { 'vue$': 'vue/dist/vue.esm.js', - 'mapbox-gl$': 'mapbox-gl/dist/mapbox-gl-unminified' + 'mapbox-gl$': 'mapbox-gl/dist/mapbox-gl-unminified', + "@templates": path.resolve(__dirname, "./templates"), + "@resources": path.resolve(__dirname, "./resources"), + "@styles": path.resolve(__dirname, "./styles"), + "@/": path.resolve(__dirname, "/src"), } }, module: { -- 2.45.2 From 6a6721e2f785375e5b089f0c40910bb90d43cbbf Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 1 Nov 2020 18:50:54 +0100 Subject: [PATCH 51/77] #50 - add useful aliases for frontend --- front/src/components/app.ts | 6 +++--- front/src/components/departures.ts | 10 +++++----- front/src/components/favourites.ts | 10 +++++----- front/src/components/history.ts | 8 ++++---- front/src/components/line.ts | 4 ++-- front/src/components/messages.ts | 4 ++-- front/src/components/page/providers.ts | 6 +++--- front/src/components/picker.ts | 10 +++++----- front/src/components/settings/departures.ts | 4 ++-- front/src/components/settings/messages.ts | 4 ++-- front/src/components/stop.ts | 6 +++--- front/src/components/tooltip.ts | 2 +- front/src/components/trip.ts | 6 +++--- front/src/components/ui/dialog.ts | 4 ++-- front/src/components/ui/icon.ts | 6 +++--- front/src/components/ui/numeric-input.ts | 2 +- front/src/components/ui/switch.ts | 2 +- front/src/components/utils.ts | 4 ++-- front/src/store/common.ts | 6 +++--- front/src/store/departures.ts | 4 ++-- front/src/store/favourites.ts | 4 ++-- front/src/store/history.ts | 4 ++-- front/src/store/messages.ts | 4 ++-- front/src/store/migrations.ts | 2 +- front/src/store/root.ts | 4 ++-- front/webpack.config.js | 2 +- 26 files changed, 64 insertions(+), 64 deletions(-) diff --git a/front/src/components/app.ts b/front/src/components/app.ts index 24ce486..5c28266 100644 --- a/front/src/components/app.ts +++ b/front/src/components/app.ts @@ -2,9 +2,9 @@ import Vue from 'vue' import store from '../store' import { Component, Watch } from "vue-property-decorator"; import { Action, Mutation } from 'vuex-class' -import { Stop } from "../model"; -import { DeparturesSettingsState } from "../store/settings/departures"; -import { MessagesSettingsState } from "../store/settings/messages"; +import { Stop } from "@/model"; +import { DeparturesSettingsState } from "@/store/settings/departures"; +import { MessagesSettingsState } from "@/store/settings/messages"; @Component({ store }) export class Application extends Vue { diff --git a/front/src/components/departures.ts b/front/src/components/departures.ts index 3318ef5..01e35d0 100644 --- a/front/src/components/departures.ts +++ b/front/src/components/departures.ts @@ -1,18 +1,18 @@ import Vue from 'vue' -import { Departure } from "../model"; +import { Departure } from "@/model"; import { Component, Prop, Watch } from "vue-property-decorator"; import store, { Departures, DeparturesSettings } from '../store' -import { Trip } from "../model/trip"; +import { Trip } from "@/model/trip"; import urls from "../urls"; -import { Jsonified } from "../utils"; +import { Jsonified } from "@/utils"; import * as moment from "moment"; -@Component({ template: require("../../templates/departures.html"), store }) +@Component({ template: require("@templates/departures.html"), store }) export class DeparturesComponent extends Vue { @Departures.State departures: Departure[]; } -@Component({ template: require("../../templates/departures/departure.html"), store }) +@Component({ template: require("@templates/departures/departure.html"), store }) export class DepartureComponent extends Vue { @Prop(Object) departure: Departure; scheduledTrip: Trip = null; diff --git a/front/src/components/favourites.ts b/front/src/components/favourites.ts index 2f89150..73ab33b 100644 --- a/front/src/components/favourites.ts +++ b/front/src/components/favourites.ts @@ -1,13 +1,13 @@ import Vue from 'vue' import { Component, Watch } from 'vue-property-decorator' import { Mutation, State } from "vuex-class"; -import { Favourite } from "../store/favourites"; -import { Stop } from "../model"; +import { Favourite } from "@/store/favourites"; +import { Stop } from "@/model"; import * as uuid from "uuid"; -import { Favourites } from "../store"; +import { Favourites } from "@/store"; -@Component({ template: require('../../templates/favourites.html' )}) +@Component({ template: require('@templates/favourites.html' )}) export class FavouritesComponent extends Vue { @Favourites.State favourites: Favourite[]; @Favourites.Mutation remove: (fav: Favourite) => void; @@ -26,7 +26,7 @@ function createFavouriteEntry(name: string, stops: Stop[]): Favourite { } } -@Component({ template: require('../../templates/favourites/save.html' )}) +@Component({ template: require('@templates/favourites/save.html' )}) export class FavouritesAdderComponent extends Vue { @State stops: Stop[]; diff --git a/front/src/components/history.ts b/front/src/components/history.ts index f7ee2b9..31c392f 100644 --- a/front/src/components/history.ts +++ b/front/src/components/history.ts @@ -1,11 +1,11 @@ import Component from "vue-class-component"; import Vue from "vue"; -import { History } from "../store"; -import { HistoryEntry } from "../store/history"; +import { History } from "@/store"; +import { HistoryEntry } from "@/store/history"; import { Mutation } from "vuex-class"; -import { Stop } from "../model"; +import { Stop } from "@/model"; -@Component({ template: require('../../templates/stop/history.html' )}) +@Component({ template: require('@templates/stop/history.html' )}) export class StopHistory extends Vue { @History.Getter all: HistoryEntry[]; diff --git a/front/src/components/line.ts b/front/src/components/line.ts index 30be33a..41648b9 100644 --- a/front/src/components/line.ts +++ b/front/src/components/line.ts @@ -1,8 +1,8 @@ import Vue from 'vue' import { Component, Prop } from 'vue-property-decorator' -import { Line } from "../model"; +import { Line } from "@/model"; -@Component({ template: require('../../templates/line.html' )}) +@Component({ template: require('@templates/line.html' )}) export class LineComponent extends Vue { @Prop(Object) public line: Line; diff --git a/front/src/components/messages.ts b/front/src/components/messages.ts index 0c50186..463baf2 100644 --- a/front/src/components/messages.ts +++ b/front/src/components/messages.ts @@ -1,9 +1,9 @@ import Vue from 'vue'; import { Component } from "vue-property-decorator"; -import { Message } from "../model/message"; +import { Message } from "@/model/message"; import store, { Messages, MessagesSettings } from '../store' -@Component({ template: require("../../templates/messages.html"), store }) +@Component({ template: require("@templates/messages.html"), store }) export class MessagesComponent extends Vue { @Messages.State('messages') public allMessages: Message[]; diff --git a/front/src/components/page/providers.ts b/front/src/components/page/providers.ts index dc6b484..35746b9 100644 --- a/front/src/components/page/providers.ts +++ b/front/src/components/page/providers.ts @@ -1,11 +1,11 @@ import Vue from 'vue' import { Component } from 'vue-property-decorator' -import { Provider } from "../../model"; -import { Jsonified } from "../../utils"; +import { Provider } from "@/model"; +import { Jsonified } from "@/utils"; import * as moment from 'moment'; @Component({ - template: require('../../../templates/page/providers.html'), + template: require('@templates/page/providers.html'), }) export class PageProviderList extends Vue { private providers: Provider[] = []; diff --git a/front/src/components/picker.ts b/front/src/components/picker.ts index 3b7f072..662ebff 100644 --- a/front/src/components/picker.ts +++ b/front/src/components/picker.ts @@ -2,14 +2,14 @@ import Component from "vue-class-component"; import Vue from "vue"; import { Line, StopGroup, StopGroups, StopWithDestinations as Stop } from "../model"; import { Prop, Watch } from "vue-property-decorator"; -import { FetchingState, filter, map, match, unique } from "../utils"; -import { debounce } from "../decorators"; +import { FetchingState, filter, map, match, unique } from "@/utils"; +import { debounce } from "@/decorators"; import urls from '../urls'; import { Mutation } from "vuex-class"; -import { HistoryEntry } from "../store/history"; +import { HistoryEntry } from "@/store/history"; import { StopHistory } from "./history"; -@Component({ template: require('../../templates/picker/stop.html') }) +@Component({ template: require('@templates/picker/stop.html') }) export class PickerStopComponent extends Vue { @Prop(Object) public stop: Stop; @@ -50,7 +50,7 @@ export class PickerStopComponent extends Vue { } @Component({ - template: require('../../templates/finder.html'), + template: require('@templates/finder.html'), components: { "PickerStop": PickerStopComponent, "StopHistory": StopHistory, diff --git a/front/src/components/settings/departures.ts b/front/src/components/settings/departures.ts index 8e35873..f4c5a43 100644 --- a/front/src/components/settings/departures.ts +++ b/front/src/components/settings/departures.ts @@ -1,9 +1,9 @@ import { Component } from "vue-property-decorator"; import store, { DeparturesSettings } from "../../store"; import Vue from "vue"; -import { DeparturesSettingsState } from "../../store/settings/departures"; +import { DeparturesSettingsState } from "@/store/settings/departures"; -@Component({ template: require("../../../templates/settings/departures.html"), store }) +@Component({ template: require("@templates/settings/departures.html"), store }) export class SettingsDepartures extends Vue { @DeparturesSettings.State public autorefresh: boolean; diff --git a/front/src/components/settings/messages.ts b/front/src/components/settings/messages.ts index fc2a268..8f4b1e5 100644 --- a/front/src/components/settings/messages.ts +++ b/front/src/components/settings/messages.ts @@ -1,9 +1,9 @@ import { Component } from "vue-property-decorator"; import store, { MessagesSettings } from "../../store"; import Vue from "vue"; -import { MessagesSettingsState } from "../../store/settings/messages"; +import { MessagesSettingsState } from "@/store/settings/messages"; -@Component({template: require("../../../templates/settings/messages.html"), store}) +@Component({template: require("@templates/settings/messages.html"), store}) export class SettingsMessages extends Vue { @MessagesSettings.State public autorefresh: boolean; diff --git a/front/src/components/stop.ts b/front/src/components/stop.ts index 0afd0b0..a5fdd52 100644 --- a/front/src/components/stop.ts +++ b/front/src/components/stop.ts @@ -3,7 +3,7 @@ import { Line, Stop, Track } from "../model"; import Vue from 'vue'; import urls from "../urls"; -@Component({ template: require('../../templates/stop/details.html') }) +@Component({ template: require('@templates/stop/details.html') }) class StopDetailsComponent extends Vue { @Prop(Object) public stop: Stop; @@ -35,13 +35,13 @@ class StopDetailsComponent extends Vue { } } -@Component({ template: require('../../templates/stop.html') }) +@Component({ template: require('@templates/stop.html') }) export class StopComponent extends Vue { @Prop(Object) public stop: Stop; } -@Component({ template: require('../../templates/stop/map.html') }) +@Component({ template: require('@templates/stop/map.html') }) export class StopMapComponent extends Vue { @Prop(Object) public stop: Stop; diff --git a/front/src/components/tooltip.ts b/front/src/components/tooltip.ts index 1276133..5a0f826 100644 --- a/front/src/components/tooltip.ts +++ b/front/src/components/tooltip.ts @@ -10,7 +10,7 @@ type Trigger = "hover" | "focus" | "long-press"; const longPressTimeout = 1000; -@Component({ template: require('../../templates/tooltip.html') }) +@Component({ template: require('@templates/tooltip.html') }) export class TooltipComponent extends Vue { @Prop({ type: String, default: "top" }) public placement: string; @Prop({ type: Number, default: 400 }) public delay: number; diff --git a/front/src/components/trip.ts b/front/src/components/trip.ts index 584ba82..24bde4e 100644 --- a/front/src/components/trip.ts +++ b/front/src/components/trip.ts @@ -1,13 +1,13 @@ import Vue from "vue"; import Component from "vue-class-component"; import { Prop } from "vue-property-decorator"; -import { ScheduledStop } from "../model/trip"; -import { Stop } from "../model"; +import { ScheduledStop } from "@/model/trip"; +import { Stop } from "@/model"; import * as moment from 'moment'; type ScheduledStopInfo = ScheduledStop & { visited: boolean, current: boolean }; -@Component({ template: require("../../templates/trip.html") }) +@Component({ template: require("@templates/trip.html") }) export class TripComponent extends Vue { @Prop(Array) public schedule: ScheduledStop[]; @Prop(Object) public current: Stop; diff --git a/front/src/components/ui/dialog.ts b/front/src/components/ui/dialog.ts index d8be47f..365102d 100644 --- a/front/src/components/ui/dialog.ts +++ b/front/src/components/ui/dialog.ts @@ -1,7 +1,7 @@ import Vue from "vue"; import { Component, Prop, Watch } from "vue-property-decorator"; import Popper, { Placement } from "popper.js"; -import { defaultBreakpoints } from "../../filters"; +import { defaultBreakpoints } from "@/filters"; /** * How popup will be presented to user: @@ -34,7 +34,7 @@ function computeZIndexOfElement(element: HTMLElement): number { @Component({ inheritAttrs: false, - template: require('../../../templates/ui/dialog.html'), + template: require('@templates/ui/dialog.html'), }) export default class UiDialog extends Vue { @Prop({ type: String, default: "popup" }) diff --git a/front/src/components/ui/icon.ts b/front/src/components/ui/icon.ts index dc41d63..3f656f2 100644 --- a/front/src/components/ui/icon.ts +++ b/front/src/components/ui/icon.ts @@ -1,7 +1,7 @@ import Vue from 'vue' import { Component, Prop } from 'vue-property-decorator' import { IconDefinition, library } from "@fortawesome/fontawesome-svg-core" -import { Dictionary } from "../../utils"; +import { Dictionary } from "@/utils"; import { faBullhorn, faCheck, @@ -34,7 +34,7 @@ import { faSpinnerThird } from "@fortawesome/pro-regular-svg-icons"; import { faExclamationTriangle as faSolidExclamationTriangle, faWalking } from "@fortawesome/pro-solid-svg-icons"; -import { fac } from "../../icons"; +import { fac } from "@/icons"; import { FontAwesomeIcon, FontAwesomeLayers, FontAwesomeLayersText } from "@fortawesome/vue-fontawesome"; type IconDescription = { icon: IconDefinition, [prop: string]: any } @@ -117,7 +117,7 @@ const extractAllIcons = (icons: Icon[]) => icons.map(icon => { library.add(...extractAllIcons(Object.values(definitions))); @Component({ - template: require('../../../templates/ui/icon.html'), + template: require('@templates/ui/icon.html'), components: { fa: FontAwesomeIcon, faLayers: FontAwesomeLayers, diff --git a/front/src/components/ui/numeric-input.ts b/front/src/components/ui/numeric-input.ts index 54e2192..df4a0fe 100644 --- a/front/src/components/ui/numeric-input.ts +++ b/front/src/components/ui/numeric-input.ts @@ -3,7 +3,7 @@ import { Component, Prop } from 'vue-property-decorator' import * as uuid from "uuid"; @Component({ - template: require('../../../templates/ui/numeric.html'), + template: require('@templates/ui/numeric.html'), inheritAttrs: false }) export class UiNumericInput extends Vue { diff --git a/front/src/components/ui/switch.ts b/front/src/components/ui/switch.ts index ff819b1..46756a3 100644 --- a/front/src/components/ui/switch.ts +++ b/front/src/components/ui/switch.ts @@ -3,7 +3,7 @@ import { Component, Prop } from 'vue-property-decorator' import * as uuid from "uuid"; @Component({ - template: require('../../../templates/ui/switch.html'), + template: require('@templates/ui/switch.html'), inheritAttrs: false }) export class UiSwitch extends Vue { diff --git a/front/src/components/utils.ts b/front/src/components/utils.ts index edfd173..ad59830 100644 --- a/front/src/components/utils.ts +++ b/front/src/components/utils.ts @@ -2,7 +2,7 @@ import Vue from 'vue'; import { Component, Prop, Watch } from "vue-property-decorator"; -@Component({ template: require('../../templates/fold.html') }) +@Component({ template: require('@templates/fold.html') }) export class FoldComponent extends Vue { private observer: MutationObserver; @@ -34,7 +34,7 @@ export class FoldComponent extends Vue { } } -@Component({ template: require("../../templates/lazy.html") }) +@Component({ template: require("@templates/lazy.html") }) export class LazyComponent extends Vue { @Prop(Boolean) public activate: boolean; diff --git a/front/src/store/common.ts b/front/src/store/common.ts index 9daa91b..f87a1ac 100644 --- a/front/src/store/common.ts +++ b/front/src/store/common.ts @@ -1,7 +1,7 @@ -import { FetchingState } from "../utils"; -import { Moment } from "moment"; -import { Module, MutationTree } from "vuex"; +import { FetchingState } from "@/utils"; import * as moment from "moment"; +import { Moment } from "moment"; +import { MutationTree } from "vuex"; export interface CommonState { state: FetchingState, diff --git a/front/src/store/departures.ts b/front/src/store/departures.ts index 201cbca..08ab4b4 100644 --- a/front/src/store/departures.ts +++ b/front/src/store/departures.ts @@ -1,10 +1,10 @@ import { Module } from "vuex"; import { RootState } from "./root"; -import { Departure, Line, Stop } from "../model"; +import { Departure, Line } from "../model"; import * as moment from 'moment' import common, { CommonState } from './common' import urls from "../urls"; -import { Jsonified } from "../utils"; +import { Jsonified } from "@/utils"; export interface DeparturesState extends CommonState { departures: Departure[], diff --git a/front/src/store/favourites.ts b/front/src/store/favourites.ts index 94f608e..c0e9376 100644 --- a/front/src/store/favourites.ts +++ b/front/src/store/favourites.ts @@ -1,7 +1,7 @@ import { RootState } from "./root"; import { Module } from "vuex"; -import { Stop } from "../model"; -import { except } from "../utils"; +import { Stop } from "@/model"; +import { except } from "@/utils"; export interface Favourite { id: string; diff --git a/front/src/store/history.ts b/front/src/store/history.ts index dcfc805..b6e781c 100644 --- a/front/src/store/history.ts +++ b/front/src/store/history.ts @@ -1,9 +1,9 @@ -import { Stop } from "../model"; +import { Stop } from "@/model"; import { Module } from "vuex"; import { RootState } from "./root"; import * as moment from "moment"; import { Moment } from "moment"; -import { Jsonified } from "../utils"; +import { Jsonified } from "@/utils"; export interface HistoryEntry { stop: Stop, diff --git a/front/src/store/messages.ts b/front/src/store/messages.ts index d24dae2..06ad16e 100644 --- a/front/src/store/messages.ts +++ b/front/src/store/messages.ts @@ -1,9 +1,9 @@ import { ActionContext, Module } from "vuex"; import { RootState } from "./root"; -import { Message, MessageType } from "../model/message"; +import { Message, MessageType } from "@/model/message"; import common, { CommonState } from "./common"; import urls from "../urls"; -import { Jsonified } from "../utils"; +import { Jsonified } from "@/utils"; import * as moment from 'moment'; export interface MessagesState extends CommonState { diff --git a/front/src/store/migrations.ts b/front/src/store/migrations.ts index 87f3946..76f54d1 100644 --- a/front/src/store/migrations.ts +++ b/front/src/store/migrations.ts @@ -1,4 +1,4 @@ -import { distinct } from "../utils"; +import { distinct } from "@/utils"; import urls from "../urls"; import * as uuid from "uuid"; diff --git a/front/src/store/root.ts b/front/src/store/root.ts index 1c0c1ea..359f2c8 100644 --- a/front/src/store/root.ts +++ b/front/src/store/root.ts @@ -1,7 +1,7 @@ -import { Stop } from "../model"; +import { Stop } from "@/model"; import { ActionTree, MutationTree } from "vuex"; import urls from "../urls"; -import { ensureArray } from "../utils"; +import { ensureArray } from "@/utils"; export interface RootState { stops: Stop[], diff --git a/front/webpack.config.js b/front/webpack.config.js index 1762344..c1aa148 100644 --- a/front/webpack.config.js +++ b/front/webpack.config.js @@ -24,7 +24,7 @@ const config = { "@templates": path.resolve(__dirname, "./templates"), "@resources": path.resolve(__dirname, "./resources"), "@styles": path.resolve(__dirname, "./styles"), - "@/": path.resolve(__dirname, "/src"), + "@": path.resolve(__dirname, "./src"), } }, module: { -- 2.45.2 From 3ba9a92c0ba2e3bb85322af7931195be1fb8cf39 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Mon, 2 Nov 2020 22:04:40 +0100 Subject: [PATCH 52/77] #50 - move frontend routing to frontend instead of symfony --- api/config/packages/nelmio_api_doc.yaml | 2 +- api/config/routes.yaml | 9 +- .../Controller/Api/v1/ProviderController.php | 16 +- .../Controller/Api/v1/TracksController.php | 7 +- api/templates/app.html.twig | 139 ---------- .../SwaggerUi/index.html.twig | 2 +- docker/nginx/czydojade | 18 +- front/package.json | 2 + front/resources/index.html | 48 ++++ front/src/app.ts | 17 +- front/src/components/application.ts | 20 ++ front/src/components/index.ts | 5 +- front/src/components/{app.ts => main.ts} | 16 +- front/src/components/page/index.ts | 1 - .../providers.ts => provider-chooser.ts} | 4 +- front/src/components/tooltip.ts | 2 +- front/src/store/root.ts | 12 + front/src/urls.ts | 7 +- front/templates/app.html | 5 + front/templates/main.html | 142 ++++++++++ front/templates/page/providers.html | 76 +++--- front/webpack.config.js | 18 +- front/yarn.lock | 252 +++++++++++++++++- 23 files changed, 579 insertions(+), 241 deletions(-) create mode 100644 front/resources/index.html create mode 100644 front/src/components/application.ts rename front/src/components/{app.ts => main.ts} (88%) delete mode 100644 front/src/components/page/index.ts rename front/src/components/{page/providers.ts => provider-chooser.ts} (87%) create mode 100644 front/templates/app.html create mode 100644 front/templates/main.html diff --git a/api/config/packages/nelmio_api_doc.yaml b/api/config/packages/nelmio_api_doc.yaml index c449eee..edbcb92 100644 --- a/api/config/packages/nelmio_api_doc.yaml +++ b/api/config/packages/nelmio_api_doc.yaml @@ -13,7 +13,7 @@ nelmio_api_doc: areas: path_patterns: - - ^/[^\/]+/api(?!/doc$) # Accepts routes under /api except /api/doc + - /api(?!/doc$) # Accepts routes under /api except /api/doc diff --git a/api/config/routes.yaml b/api/config/routes.yaml index d5f74b8..0c54567 100644 --- a/api/config/routes.yaml +++ b/api/config/routes.yaml @@ -1,9 +1,16 @@ api_v1: resource: ../src/Controller/Api/v1 type: annotation - prefix: /{provider}/api/v1 + prefix: /api/v1/{provider} api_v1_providers: path: /api/v1/providers + methods: ["GET"] defaults: _controller: '\App\Controller\Api\v1\ProviderController::index' + +api_v1_providers_one: + path: /api/v1/providers/{id} + methods: ["GET"] + defaults: + _controller: '\App\Controller\Api\v1\ProviderController::one' diff --git a/api/src/Controller/Api/v1/ProviderController.php b/api/src/Controller/Api/v1/ProviderController.php index 67b0dcc..8516fe9 100644 --- a/api/src/Controller/Api/v1/ProviderController.php +++ b/api/src/Controller/Api/v1/ProviderController.php @@ -5,19 +5,10 @@ namespace App\Controller\Api\v1; use App\Controller\Controller; use App\Service\Converter; use App\Service\ProviderResolver; -use Swagger\Annotations as SWG; -use Symfony\Component\Routing\Annotation\Route; use function Kadet\Functional\ref; -/** - * @Route("/providers") - * @SWG\Tag(name="Providers") - */ class ProviderController extends Controller { - /** - * @Route("/", methods={"GET"}) - */ public function index(ProviderResolver $resolver, Converter $converter) { $providers = $resolver @@ -28,4 +19,11 @@ class ProviderController extends Controller ; return $this->json($providers); } + + public function one(ProviderResolver $resolver, Converter $converter, $id) + { + $provider = $resolver->resolve($id); + + return $this->json($converter->convert($provider)); + } } diff --git a/api/src/Controller/Api/v1/TracksController.php b/api/src/Controller/Api/v1/TracksController.php index 54cece5..9dc7c4e 100644 --- a/api/src/Controller/Api/v1/TracksController.php +++ b/api/src/Controller/Api/v1/TracksController.php @@ -9,11 +9,8 @@ use App\Model\Track; use App\Modifier\IdFilter; use App\Modifier\RelatedFilter; use App\Provider\TrackRepository; -use App\Service\IterableUtils; -use Nelmio\ApiDocBundle\Annotation\Model; use Swagger\Annotations as SWG; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Annotation\Route; use function App\Functions\encapsulate; use function Kadet\Functional\ref; @@ -41,6 +38,10 @@ class TracksController extends Controller /** * @Route("/stops", methods={"GET"}) * @Route("/{track}/stops", methods={"GET"}) + * + * @SWG\Tag(name="Tracks") + * + * @SWG\Response(response=200, description="Stops related to specified query.") */ public function stops(Request $request, TrackRepository $repository) { diff --git a/api/templates/app.html.twig b/api/templates/app.html.twig index c6cc468..fc3d4d8 100644 --- a/api/templates/app.html.twig +++ b/api/templates/app.html.twig @@ -4,145 +4,6 @@ {% block body %} <main id="app" class="container not-ready"> - <div class="row"> - <div class="col-md-8 order-md-last"> - <section class="section messages" v-show="messages.count > 0"> - <header class="section__title flex"> - <h2> - <ui-icon icon="messages" fixed-width class="mr-2"></ui-icon> - Komunikaty <span class="ml-2 badge badge-pill badge-dark">{{ '{{ messages.count }}' }}</span> - </h2> - <button class="btn btn-action flex-space-left" ref="settings-messages" @click="visibility.messages = !visibility.messages"> - <tooltip>ustawienia</tooltip> - <ui-icon icon="settings" fixed-width></ui-icon> - </button> - <button class="btn btn-action" @click="updateMessages" ref="btn-messages-refresh"> - <tooltip>odśwież</tooltip> - <ui-icon icon="refresh" :spin="messages.state === 'fetching'" fixed-width></ui-icon> - </button> - <button class="btn btn-action" @click="sections.messages = !sections.messages"> - <tooltip> - {{ '{{ ' }} sections.messages ? 'zwiń' : 'rozwiń' {{ '}}' }} - <span class="sr-only">sekcję komunikatów</span> - </tooltip> - <ui-icon :icon="sections.messages ? 'chevron-up' : 'chevron-down'" fixed-width></ui-icon> - </button> - - <portal to="popups"> - <ui-dialog reference="settings-messages" v-if="visibility.messages" arrow placement="left-start" @leave="visibility.messages = false"> - <settings-messages></settings-messages> - </ui-dialog> - </portal> - </header> - <fold :visible="sections.messages"> - <messages></messages> - </fold> - </section> - <section class="section"> - <header class="section__title flex"> - <h2> - <ui-icon icon="timetable" fixed-width></ui-icon> - <span class="text">Odjazdy</span> - </h2> - - <button class="btn btn-action flex-space-left" ref="settings-departures" @click="visibility.departures = !visibility.departures"> - <tooltip>ustawienia</tooltip> - <ui-icon icon="settings" fixed-width></ui-icon> - </button> - <button class="btn btn-action" @click="updateDepartures({ stops })"> - <tooltip>odśwież</tooltip> - <ui-icon icon="refresh" :spin="departures.state === 'fetching'" fixed-width></ui-icon> - </button> - <portal to="popups"> - <ui-dialog reference="settings-departures" v-if="visibility.departures" @leave="visibility.departures = false" arrow placement="left-start"> - <settings-departures></settings-departures> - </ui-dialog> - </portal> - </header> - <departures :stops="stops" v-if="stops.length > 0"></departures> - <div class="alert alert-info" v-else> - <ui-icon icon="info"></ui-icon> - Wybierz przystanki korzystając z wyszukiwarki poniżej, aby zobaczyć listę odjazdów. - </div> - {% if provider.attribution %} - <div class="attribution"> - <ui-icon icon="info"></ui-icon> - Pochodzenie danych: {{ provider.attribution|raw }} - </div> - {% endif %} - </section> - </div> - <div class="col-md-4 order-md-first"> - <section class="section picker" v-if="stops.length > 0"> - <header class="section__title flex"> - <h2> - <ui-icon icon="stop" fixed-width></ui-icon> - <span class="text">Przystanki</span> - </h2> - <button class="btn btn-action flex-space-left" @click="clear"> - <tooltip>usuń wszystkie</tooltip> - <ui-icon icon="delete" fixed-width></ui-icon> - </button> - </header> - - <ul class="picker__stops list-underlined"> - <li v-for="stop in stops" :key="stop.id" class="picker__stop"> - <picker-stop :stop="stop"> - <template v-slot:primary-action> - <button @click="remove(stop)" class="btn btn-action"> - <tooltip>usuń przystanek</tooltip> - <ui-icon icon="remove-stop"></ui-icon> - </button> - </template> - </picker-stop> - </li> - </ul> - - <div class="d-flex mt-2"> - <button class="btn btn-action btn-sm flex-space-left" @click="visibility.save = true" ref="save"> - <ui-icon icon="favourite" fixed-width></ui-icon> - zapisz jako... - </button> - </div> - - <ui-dialog reference="save" v-if="visibility.save" arrow placement="bottom-end" @leave="visibility.save = false" title="Dodaj do ulubionych"> - <favourites-adder @saved="visibility.save = false"/> - </ui-dialog> - </section> - <section class="section picker"> - <header class="section__title flex"> - <template v-if="visibility.picker === 'search'"> - <h2 class="flex-grow-1"> - <ui-icon icon="search" fixed-width class="mr-1"></ui-icon> - Wybierz przystanki - </h2> - <button class="btn btn-action" @click="visibility.picker = 'favourites'"> - <tooltip>Zapisane</tooltip> - <ui-icon icon="favourite" fixed-witdth></ui-icon> - </button> - </template> - <template v-else> - <h2 class="flex-grow-1"> - <ui-icon icon="favourite" fixed-width class="mr-1"></ui-icon> - Zapisane - </h2> - <button class="btn btn-action" @click="visibility.picker = 'search'"> - <tooltip>Wybierz przystanki</tooltip> - <ui-icon icon="search" fixed-witdth></ui-icon> - </button> - </template> - </header> - <div class="transition-box"> - <transition name="fade"> - <stop-finder @select="add" :blacklist="stops" v-if="visibility.picker === 'search'"></stop-finder> - <favourites v-else-if="visibility.picker === 'favourites'"></favourites> - </transition> - </div> - </section> - </div> - </div> - - <portal-target name="popups" multiple></portal-target> </main> {% endblock %} diff --git a/api/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig b/api/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig index ceb859e..d156f6d 100644 --- a/api/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig +++ b/api/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig @@ -5,5 +5,5 @@ {% block stylesheets %} {{ parent() }} <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700"> - <link rel="stylesheet" href="dist/api.css" /> + <link rel="stylesheet" href="/dist/api.css" /> {% endblock stylesheets %} diff --git a/docker/nginx/czydojade b/docker/nginx/czydojade index 5b9ea65..54294a0 100644 --- a/docker/nginx/czydojade +++ b/docker/nginx/czydojade @@ -2,18 +2,20 @@ server { root /var/www/front/public/; server_name cojedzie.localhost; - index index.php; + index dist/index.html; - location ~ \.(js|css)$ { - expires 1y; + location /api/ { + root /var/www/api/public/; + try_files $uri $uri/ index.php$is_args$args; + } + + location /bundles/ { + root /var/www/api/public/; + try_files $uri $uri/; } location / { - try_files $uri $uri/ /index.php?$args; - } - - location = / { - root /var/www/api/public/; + try_files $uri $uri/ /dist/index.html =404; } location ~ (.+).php(/|$) { diff --git a/front/package.json b/front/package.json index c938999..b995721 100644 --- a/front/package.json +++ b/front/package.json @@ -40,6 +40,7 @@ "@types/workbox-window": "^4.3.3", "clean-webpack-plugin": "^3.0.0", "copy-webpack-plugin": "^4.5.2", + "html-webpack-plugin": "^4.5.0", "imagemin-webpack-plugin": "^2.3.0", "mapbox-gl": "^1.6.1", "mapbox-gl-leaflet": "^0.0.11", @@ -49,6 +50,7 @@ "vue-fragment": "^1.5.1", "vue-moment": "^4.1.0", "vue-removed-hook-mixin": "^0.1.1", + "vue-router": "^3.4.8", "vue2-leaflet": "^1.0.2", "vuex": "^3.0.1", "vuex-class": "^0.3.1", diff --git a/front/resources/index.html b/front/resources/index.html new file mode 100644 index 0000000..1cab4f8 --- /dev/null +++ b/front/resources/index.html @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8"/> + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> + <link rel="stylesheet" href="dist/main.css"/> + <link rel="manifest" href="manifest.json"/> + + <!-- icons --> + <link rel="icon" href="images/favicon.png" sizes="16x16"/> + <link rel="icon" href="images/favicon-2x.png" sizes="32x32"/> + <link rel="icon" href="images/favicon.ico"/> + + <!-- Apple shit --> + <link rel="apple-touch-icon" href="images/ios.png" sizes="512x512"> + <link rel="apple-touch-icon" href="images/ios-80.png" sizes="80x80"> + <link rel="apple-touch-icon" href="images/ios-192.png" sizes="192x192"> + + <meta name="apple-mobile-web-app-title" content="Co Jedzie?"> + <meta name="apple-mobile-web-app-capable" content="yes"> + + <meta name="theme-color" content="white"/> + + <title>Co Jedzie?</title> + </head> + <body> + <noscript> + <div class="container"> + <div class="alert alert-danger"> + Aplikacja wymaga do działania obsługi JavaScriptu. + </div> + </div> + </noscript> + <main id="root" class="container not-ready"> + </main> + <footer class="container"> + <span> + <img src="images/logo.png" alt="co jedzie logo"/> + v.<%= htmlWebpackPlugin.options.version %> • + <a href="/api/doc">API</a> + </span> + <span class="copyright flex flex-space-left justify-content-end"> + <a href="https://kadet.net"><img src="images/kadet-net-logo.png" alt="kadet.net logo" class="mx-1"/></a> + © <%= htmlWebpackPlugin.options.year %> + </span> + </footer> + </body> +</html> diff --git a/front/src/app.ts b/front/src/app.ts index a201127..eeec40a 100644 --- a/front/src/app.ts +++ b/front/src/app.ts @@ -18,6 +18,7 @@ import { Component } from "vue-property-decorator"; import * as VueMoment from "vue-moment"; import * as moment from 'moment'; import 'moment/locale/pl' +import VueRouter from "vue-router"; window['$'] = window['jQuery'] = $; window['Popper'] = Popper; @@ -27,6 +28,7 @@ Vue.use(PortalVue); Vue.use(VueDragscroll); Vue.use(VueFragment); Vue.use(VueMoment, { moment }); +Vue.use(VueRouter); declare module 'vue/types/vue' { interface Vue { @@ -55,20 +57,7 @@ Component.registerHooks(['removed']); import('bootstrap'), ] as const); - const appRoot = document.getElementById('app'); - - store.replaceState({ - ...store.state, - provider: window['data']?.provider, - }); - - // here goes "public" API - window['app'] = Object.assign({ - state: {} - }, window['app'], { - components, - application: appRoot ? new components.Application({ el: '#app' }) : new components.PageProviderList({ el: '#provider-picker' }), - }); + const application = new components.Application().$mount("#root") if ('serviceWorker' in navigator) { const wb = new Workbox("/service-worker.js"); diff --git a/front/src/components/application.ts b/front/src/components/application.ts new file mode 100644 index 0000000..44a71c9 --- /dev/null +++ b/front/src/components/application.ts @@ -0,0 +1,20 @@ +import Vue from "vue"; +import Component from "vue-class-component"; +import VueRouter, { RouteConfig } from "vue-router"; +import { Main, ProviderChooser } from "@/components"; +import store from "@/store"; + +const routes: RouteConfig[] = [ + { path: "/:provider", component: Main }, + { path: "/", component: ProviderChooser }, +] + +export const router = new VueRouter({ + routes, + mode: 'history', +}); + +@Component({ template: require("@templates/app.html"), router, store }) +export class Application extends Vue { + +} diff --git a/front/src/components/index.ts b/front/src/components/index.ts index 460380e..bb642b7 100644 --- a/front/src/components/index.ts +++ b/front/src/components/index.ts @@ -6,12 +6,13 @@ export * from './departures' export * from './stop' export * from './messages' export * from './map' -export * from './app' +export * from './main' export * from './favourites' export * from './trip' export * from './ui' export * from './settings' -export * from "./page" +export * from "./provider-chooser" +export * from "./application" export { Departures } from "../store"; export { Messages } from "../store"; diff --git a/front/src/components/app.ts b/front/src/components/main.ts similarity index 88% rename from front/src/components/app.ts rename to front/src/components/main.ts index 5c28266..b5122e3 100644 --- a/front/src/components/app.ts +++ b/front/src/components/main.ts @@ -1,13 +1,12 @@ import Vue from 'vue' -import store from '../store' import { Component, Watch } from "vue-property-decorator"; -import { Action, Mutation } from 'vuex-class' -import { Stop } from "@/model"; +import { Action, Mutation, State } from 'vuex-class' +import { Provider, Stop } from "@/model"; import { DeparturesSettingsState } from "@/store/settings/departures"; import { MessagesSettingsState } from "@/store/settings/messages"; -@Component({ store }) -export class Application extends Vue { +@Component({ template: require("@templates/main.html") }) +export class Main extends Vue { private sections = { messages: true }; @@ -21,6 +20,8 @@ export class Application extends Vue { private intervals = { messages: null, departures: null }; + @State private provider: Provider; + get messages() { return { count: this.$store.getters['messages/count'], @@ -47,9 +48,10 @@ export class Application extends Vue { this.$el.classList.remove('not-ready'); } - created() { + async created() { + await this.$store.dispatch('loadProvider', { provider: this.$route.params.provider }); this.$store.dispatch('messages/update'); - this.$store.dispatch('load', window['app'].state); + this.$store.dispatch('load', { }); this.initDeparturesRefreshInterval(); this.initMessagesRefreshInterval(); diff --git a/front/src/components/page/index.ts b/front/src/components/page/index.ts deleted file mode 100644 index 96bcb99..0000000 --- a/front/src/components/page/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./providers" diff --git a/front/src/components/page/providers.ts b/front/src/components/provider-chooser.ts similarity index 87% rename from front/src/components/page/providers.ts rename to front/src/components/provider-chooser.ts index 35746b9..f8a37cb 100644 --- a/front/src/components/page/providers.ts +++ b/front/src/components/provider-chooser.ts @@ -7,7 +7,7 @@ import * as moment from 'moment'; @Component({ template: require('@templates/page/providers.html'), }) -export class PageProviderList extends Vue { +export class ProviderChooser extends Vue { private providers: Provider[] = []; async created() { @@ -23,4 +23,4 @@ export class PageProviderList extends Vue { } } -Vue.component('PageProviderList', PageProviderList); +Vue.component('ProviderChooser', ProviderChooser); diff --git a/front/src/components/tooltip.ts b/front/src/components/tooltip.ts index 5a0f826..7639aaa 100644 --- a/front/src/components/tooltip.ts +++ b/front/src/components/tooltip.ts @@ -3,7 +3,7 @@ import Component from "vue-class-component"; import { Prop, Watch } from "vue-property-decorator"; type Events = { - [evnet: string]: (...any) => void, + [event: string]: (...any) => void, } type Trigger = "hover" | "focus" | "long-press"; diff --git a/front/src/store/root.ts b/front/src/store/root.ts index 359f2c8..c0ced46 100644 --- a/front/src/store/root.ts +++ b/front/src/store/root.ts @@ -13,6 +13,10 @@ export interface SavedState { stops: string[], } +export interface LoadProviderActionPayload { + provider: string; +} + export const state: RootState = { stops: [], provider: null, @@ -23,9 +27,17 @@ export const mutations: MutationTree<RootState> = { replace: (state, stops) => state.stops = stops, remove: (state, stop) => state.stops = state.stops.filter(s => s != stop), clear: (state) => state.stops = [], + setProvider: (state, provider) => state.provider = provider, }; export const actions: ActionTree<RootState, undefined> = { + async loadProvider({ commit }, { provider }) { + const response = await fetch(urls.prepare(urls.providers.get, { provider })); + + if (response.ok) { + commit('setProvider', await response.json()); + } + }, async load({ commit }, { stops }: SavedState) { if (stops.length > 0) { const response = await fetch(urls.prepare(urls.stops.all, { id: stops })); diff --git a/front/src/urls.ts b/front/src/urls.ts index f371a2c..a9fc14c 100644 --- a/front/src/urls.ts +++ b/front/src/urls.ts @@ -51,7 +51,7 @@ export function prepare(url: string, params: UrlParams = { }) { return Object.keys(params).length > 0 ? `${url}?${query(params)}` : url; } -const base = '/{provider}/api/v1'; +const base = '/api/v1/{provider}'; export default { departures: `${base}/departures`, @@ -62,6 +62,9 @@ export default { get: `${base}/stops/{id}`, tracks: `${base}/stops/{id}/tracks` }, + providers: { + get: `/api/v1/providers/{provider}`, + }, trip: `${base}/trips/{id}`, - prepare: (url: string, params: UrlParams = { }) => prepare(url, Object.assign({}, { provider: store.state.provider }, params)) + prepare: (url: string, params: UrlParams = { }) => prepare(url, Object.assign({}, { provider: store.state.provider?.id }, params)) } diff --git a/front/templates/app.html b/front/templates/app.html new file mode 100644 index 0000000..4809ece --- /dev/null +++ b/front/templates/app.html @@ -0,0 +1,5 @@ +<main class="d-flex"> + <router-view /> + + <portal-target name="popups" multiple /> +</main> diff --git a/front/templates/main.html b/front/templates/main.html new file mode 100644 index 0000000..141a79c --- /dev/null +++ b/front/templates/main.html @@ -0,0 +1,142 @@ +<div class="container" id="app"> + <div class="row"> + <div class="col-md-8 order-md-last"> + <section class="section messages" v-show="messages.count > 0"> + <header class="section__title flex"> + <h2> + <ui-icon icon="messages" fixed-width class="mr-2"></ui-icon> + Komunikaty <span class="ml-2 badge badge-pill badge-dark">{{ messages.count }}</span> + </h2> + <button class="btn btn-action flex-space-left" ref="settings-messages" + @click="visibility.messages = !visibility.messages"> + <tooltip>ustawienia</tooltip> + <ui-icon icon="settings" fixed-width></ui-icon> + </button> + <button class="btn btn-action" @click="updateMessages" ref="btn-messages-refresh"> + <tooltip>odśwież</tooltip> + <ui-icon icon="refresh" :spin="messages.state === 'fetching'" fixed-width></ui-icon> + </button> + <button class="btn btn-action" @click="sections.messages = !sections.messages"> + <tooltip> + {{ sections.messages ? 'zwiń' : 'rozwiń' }} + <span class="sr-only">sekcję komunikatów</span> + </tooltip> + <ui-icon :icon="sections.messages ? 'chevron-up' : 'chevron-down'" fixed-width></ui-icon> + </button> + + <portal to="popups"> + <ui-dialog reference="settings-messages" v-if="visibility.messages" arrow placement="left-start" + @leave="visibility.messages = false"> + <settings-messages></settings-messages> + </ui-dialog> + </portal> + </header> + <fold :visible="sections.messages"> + <messages></messages> + </fold> + </section> + <section class="section"> + <header class="section__title flex"> + <h2> + <ui-icon icon="timetable" fixed-width></ui-icon> + <span class="text">Odjazdy</span> + </h2> + + <button class="btn btn-action flex-space-left" ref="settings-departures" + @click="visibility.departures = !visibility.departures"> + <tooltip>ustawienia</tooltip> + <ui-icon icon="settings" fixed-width></ui-icon> + </button> + <button class="btn btn-action" @click="updateDepartures({ stops })"> + <tooltip>odśwież</tooltip> + <ui-icon icon="refresh" :spin="departures.state === 'fetching'" fixed-width></ui-icon> + </button> + <portal to="popups"> + <ui-dialog reference="settings-departures" v-if="visibility.departures" + @leave="visibility.departures = false" arrow placement="left-start"> + <settings-departures></settings-departures> + </ui-dialog> + </portal> + </header> + <departures :stops="stops" v-if="stops.length > 0"></departures> + <div class="alert alert-info" v-else> + <ui-icon icon="info"></ui-icon> + Wybierz przystanki korzystając z wyszukiwarki poniżej, aby zobaczyć listę odjazdów. + </div> + <div class="attribution" v-if="provider && provider.attribution"> + <ui-icon icon="info"></ui-icon> + Pochodzenie danych: <span class="attribution__attribution" v-html="provider.attribution"></span> + </div> + </section> + </div> + <div class="col-md-4 order-md-first"> + <section class="section picker" v-if="stops.length > 0"> + <header class="section__title flex"> + <h2> + <ui-icon icon="stop" fixed-width></ui-icon> + <span class="text">Przystanki</span> + </h2> + <button class="btn btn-action flex-space-left" @click="clear"> + <tooltip>usuń wszystkie</tooltip> + <ui-icon icon="delete" fixed-width></ui-icon> + </button> + </header> + + <ul class="picker__stops list-underlined"> + <li v-for="stop in stops" :key="stop.id" class="picker__stop"> + <picker-stop :stop="stop"> + <template v-slot:primary-action> + <button @click="remove(stop)" class="btn btn-action"> + <tooltip>usuń przystanek</tooltip> + <ui-icon icon="remove-stop"></ui-icon> + </button> + </template> + </picker-stop> + </li> + </ul> + + <div class="d-flex mt-2"> + <button class="btn btn-action btn-sm flex-space-left" @click="visibility.save = true" ref="save"> + <ui-icon icon="favourite" fixed-width></ui-icon> + zapisz jako... + </button> + </div> + + <ui-dialog reference="save" v-if="visibility.save" arrow placement="bottom-end" + @leave="visibility.save = false" title="Dodaj do ulubionych"> + <favourites-adder @saved="visibility.save = false"/> + </ui-dialog> + </section> + <section class="section picker"> + <header class="section__title flex"> + <template v-if="visibility.picker === 'search'"> + <h2 class="flex-grow-1"> + <ui-icon icon="search" fixed-width class="mr-1"></ui-icon> + Wybierz przystanki + </h2> + <button class="btn btn-action" @click="visibility.picker = 'favourites'"> + <tooltip>Zapisane</tooltip> + <ui-icon icon="favourite" fixed-witdth></ui-icon> + </button> + </template> + <template v-else> + <h2 class="flex-grow-1"> + <ui-icon icon="favourite" fixed-width class="mr-1"></ui-icon> + Zapisane + </h2> + <button class="btn btn-action" @click="visibility.picker = 'search'"> + <tooltip>Wybierz przystanki</tooltip> + <ui-icon icon="search" fixed-witdth></ui-icon> + </button> + </template> + </header> + <div class="transition-box"> + <transition name="fade"> + <stop-finder @select="add" :blacklist="stops" v-if="visibility.picker === 'search'"></stop-finder> + <favourites v-else-if="visibility.picker === 'favourites'"></favourites> + </transition> + </div> + </section> + </div> + </div> +</div> diff --git a/front/templates/page/providers.html b/front/templates/page/providers.html index d6fb7ec..77099ed 100644 --- a/front/templates/page/providers.html +++ b/front/templates/page/providers.html @@ -1,42 +1,38 @@ -<main class="d-flex"> - <div style="width: 100%"> - <l-map :center="{ lat: 52.0194, lon: 19.1451 }" :zoom=7 :options="{ zoomControl: false }" class="map"> - <l-vector-layer url="https://api.maptiler.com/maps/bright/style.json?key=8GX5FRUNgk4lB83GZT8Q" - token="not-needed" - attribution='<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>' - /> +<div style="width: 100%"> + <l-map :center="{ lat: 52.0194, lon: 19.1451 }" :zoom=7 :options="{ zoomControl: false }" class="map"> + <l-vector-layer url="https://api.maptiler.com/maps/bright/style.json?key=8GX5FRUNgk4lB83GZT8Q" + token="not-needed" + attribution='<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>' + /> - <div class="provider-picker"> - <h2 class="provider-picker__heading">Wybierz lokalizację</h2> - <ul class="provider-picker__providers"> - <li v-for="provider in providers" :key="provider.id" class="provider-picker__provider"> - <a :href="`/${provider.id}`" class="provider"> - <ui-icon icon="line-bus" size="2x" /> - <div> - <div class="provider__short-name">{{ provider.shortName }}</div> - <div class="provider__name">{{ provider.name }}</div> - </div> - <tooltip v-if="provider.lastUpdate != null">Ostatnia akutalizacja: {{ provider.lastUpdate|moment('YYYY-MM-DD HH:mm') }}</tooltip> - </a> - </li> - </ul> - </div> + <div class="provider-picker"> + <h2 class="provider-picker__heading">Wybierz lokalizację</h2> + <ul class="provider-picker__providers"> + <li v-for="provider in providers" :key="provider.id" class="provider-picker__provider"> + <a :href="`/${provider.id}`" class="provider"> + <ui-icon icon="line-bus" size="2x" /> + <div> + <div class="provider__short-name">{{ provider.shortName }}</div> + <div class="provider__name">{{ provider.name }}</div> + </div> + <tooltip v-if="provider.lastUpdate != null">Ostatnia akutalizacja: {{ provider.lastUpdate|moment('YYYY-MM-DD HH:mm') }}</tooltip> + </a> + </li> + </ul> + </div> - <l-marker :lat-lng="provider.location" v-for="provider in providers" :options="{ keyboard: false }" :key="provider.id"> - <l-icon> - <div class="map__label-box" tabindex="0"> - <a :href="`/${provider.id}`" class="provider"> - <ui-icon icon="line-bus" class="map__icon" /> - <div> - <div class="provider__short-name">{{ provider.shortName }}</div> - <div class="provider__name">{{ provider.name }}</div> - </div> - </a> - </div> - </l-icon> - </l-marker> - </l-map> - </div> - - <portal-target name="popups" multiple/> -</main> + <l-marker :lat-lng="provider.location" v-for="provider in providers" :options="{ keyboard: false }" :key="provider.id"> + <l-icon> + <div class="map__label-box" tabindex="0"> + <a :href="`/${provider.id}`" class="provider"> + <ui-icon icon="line-bus" class="map__icon" /> + <div> + <div class="provider__short-name">{{ provider.shortName }}</div> + <div class="provider__name">{{ provider.name }}</div> + </div> + </a> + </div> + </l-icon> + </l-marker> + </l-map> +</div> diff --git a/front/webpack.config.js b/front/webpack.config.js index c1aa148..6fb9c8a 100644 --- a/front/webpack.config.js +++ b/front/webpack.config.js @@ -4,6 +4,7 @@ const CopyWebpackPlugin = require('copy-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const ImageminPlugin = require('imagemin-webpack-plugin').default; const { GenerateSW } = require('workbox-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); const config = { entry: { @@ -59,11 +60,13 @@ const config = { use: 'file-loader' }, { test: /\.html?$/, - use: 'raw-loader' + use: 'raw-loader', + exclude: [ + path.resolve('./resources/index.html') + ] }] }, plugins: [ - new CleanWebpackPlugin(), new MiniCssExtractPlugin({ filename: '[name].css' }), new CopyWebpackPlugin([{ from: './resources/images/', to: '../images/', ignore: ['*.ai'] }]), new ImageminPlugin({ test: /\.(jpe?g|png|gif|svg)$/i }), @@ -77,7 +80,7 @@ const config = { handler: 'CacheFirst', }], swDest: '../service-worker.js' - }) + }), ] }; @@ -86,5 +89,14 @@ module.exports = (env, argv) => { config.devtool = 'inline-source-map'; } + config.plugins.push( + new HtmlWebpackPlugin({ + template: path.resolve(__dirname, "./resources/index.html"), + chunks: ['main'], + year: new Date().getFullYear(), + version: process.env.CZYDOJADE_VERSION || (argv.mode === 'development' ? '2020.11-dev' : '2020.11'), + }) + ) + return config; }; diff --git a/front/yarn.lock b/front/yarn.lock index b1ba8fa..4d5f6a7 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -188,6 +188,11 @@ "@types/minimatch" "*" "@types/node" "*" +"@types/html-minifier-terser@^5.0.0": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#3c9ee980f1a10d6021ae6632ca3e79ca2ec4fb50" + integrity sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA== + "@types/imagemin-gifsicle@^5.2.0": version "5.2.0" resolved "https://registry.yarnpkg.com/@types/imagemin-gifsicle/-/imagemin-gifsicle-5.2.0.tgz#349160f17412e26de8d5794e70aad504781ea7d8" @@ -294,6 +299,11 @@ resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.5.tgz#9adbc12950582aa65ead76bffdf39fe0c27a3c02" integrity sha512-/gG2M/Imw7cQFp8PGvz/SwocNrmKFjFsm5Pb8HdbHkZ1K8pmuPzOX4VeVoiEecFCVf4CsN1r3/BRvx+6sNqwtQ== +"@types/tapable@^1.0.5": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.6.tgz#a9ca4b70a18b270ccb2bc0aaafefd1d486b7ea74" + integrity sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA== + "@types/uglify-js@*": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082" @@ -335,6 +345,18 @@ "@types/webpack-sources" "*" source-map "^0.6.0" +"@types/webpack@^4.41.8": + version "4.41.24" + resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.24.tgz#75b664abe3d5bcfe54e64313ca3b43e498550422" + integrity sha512-1A0MXPwZiMOD3DPMuOKUKcpkdPo8Lq33UGggZ7xio6wJ/jV1dAu5cXDrOfGDnldUroPIRLsr/DT43/GqOA4RFQ== + dependencies: + "@types/anymatch" "*" + "@types/node" "*" + "@types/tapable" "*" + "@types/uglify-js" "*" + "@types/webpack-sources" "*" + source-map "^0.6.0" + "@types/workbox-window@^4.3.3": version "4.3.3" resolved "https://registry.yarnpkg.com/@types/workbox-window/-/workbox-window-4.3.3.tgz#47f91df7ce7eea5c151a6beb3e8398c7db8ee538" @@ -1102,6 +1124,14 @@ call-me-maybe@^1.0.1: resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= +camel-case@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.1.tgz#1fc41c854f00e2f7d0139dfeba1542d6896fe547" + integrity sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q== + dependencies: + pascal-case "^3.1.1" + tslib "^1.10.0" + camelcase-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" @@ -1217,6 +1247,13 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +clean-css@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78" + integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA== + dependencies: + source-map "~0.6.0" + clean-webpack-plugin@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/clean-webpack-plugin/-/clean-webpack-plugin-3.0.0.tgz#a99d8ec34c1c628a4541567aa7b457446460c62b" @@ -1305,6 +1342,11 @@ commander@^2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== +commander@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + commander@~2.8.1: version "2.8.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" @@ -1517,6 +1559,16 @@ css-select-base-adapter@^0.1.1: resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== +css-select@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + css-select@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" @@ -1544,6 +1596,11 @@ css-tree@1.0.0-alpha.37: mdn-data "2.0.4" source-map "^0.6.1" +css-what@2.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" + integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== + css-what@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.2.1.tgz#f4a8f12421064621b456755e34a03a2c22df5da1" @@ -1751,6 +1808,13 @@ dir-glob@^2.0.0: dependencies: path-type "^3.0.0" +dom-converter@^0.2: + version "0.2.0" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" + integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== + dependencies: + utila "~0.4" + dom-serializer@0: version "0.2.2" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" @@ -1764,7 +1828,7 @@ domain-browser@^1.1.1: resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== -domelementtype@1: +domelementtype@1, domelementtype@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== @@ -1774,7 +1838,22 @@ domelementtype@^2.0.1: resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d" integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ== -domutils@^1.7.0: +domhandler@^2.3.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" + integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== + dependencies: + domelementtype "1" + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^1.5.1, domutils@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== @@ -1782,6 +1861,14 @@ domutils@^1.7.0: dom-serializer "0" domelementtype "1" +dot-case@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.3.tgz#21d3b52efaaba2ea5fda875bb1aa8124521cf4aa" + integrity sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA== + dependencies: + no-case "^3.0.3" + tslib "^1.10.0" + download@^6.2.2: version "6.2.5" resolved "https://registry.yarnpkg.com/download/-/download-6.2.5.tgz#acd6a542e4cd0bb42ca70cfc98c9e43b07039714" @@ -1893,6 +1980,11 @@ enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0: memory-fs "^0.5.0" tapable "^1.0.0" +entities@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== + entities@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" @@ -2762,6 +2854,11 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -2788,6 +2885,46 @@ html-comment-regex@^1.1.0: resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7" integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ== +html-minifier-terser@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#922e96f1f3bb60832c2634b79884096389b1f054" + integrity sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg== + dependencies: + camel-case "^4.1.1" + clean-css "^4.2.3" + commander "^4.1.1" + he "^1.2.0" + param-case "^3.0.3" + relateurl "^0.2.7" + terser "^4.6.3" + +html-webpack-plugin@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.5.0.tgz#625097650886b97ea5dae331c320e3238f6c121c" + integrity sha512-MouoXEYSjTzCrjIxWwg8gxL5fE2X2WZJLmBYXlaJhQUH5K/b5OrqmV7T4dB7iu0xkmJ6JlUuV6fFVtnqbPopZw== + dependencies: + "@types/html-minifier-terser" "^5.0.0" + "@types/tapable" "^1.0.5" + "@types/webpack" "^4.41.8" + html-minifier-terser "^5.0.1" + loader-utils "^1.2.3" + lodash "^4.17.15" + pretty-error "^2.1.1" + tapable "^1.1.3" + util.promisify "1.0.0" + +htmlparser2@^3.3.0: + version "3.10.1" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" + integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== + dependencies: + domelementtype "^1.3.1" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^3.1.1" + http-cache-semantics@3.8.1: version "3.8.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" @@ -3517,6 +3654,11 @@ lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.15, lodash@~4.17.10: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== +lodash@^4.17.20: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + logalot@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/logalot/-/logalot-2.1.0.tgz#5f8e8c90d304edf12530951a5554abb8c5e3f552" @@ -3538,6 +3680,13 @@ loud-rejection@^1.0.0: currently-unhandled "^0.4.1" signal-exit "^3.0.0" +lower-case@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.1.tgz#39eeb36e396115cc05e29422eaea9e692c9408c7" + integrity sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ== + dependencies: + tslib "^1.10.0" + lowercase-keys@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" @@ -3907,6 +4056,14 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +no-case@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.3.tgz#c21b434c1ffe48b39087e86cfb4d2582e9df18f8" + integrity sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw== + dependencies: + lower-case "^2.0.1" + tslib "^1.10.0" + node-gyp@^3.8.0: version "3.8.0" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" @@ -4040,7 +4197,7 @@ npm-run-path@^2.0.0: gauge "~2.7.3" set-blocking "~2.0.0" -nth-check@^1.0.2: +nth-check@^1.0.2, nth-check@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== @@ -4098,7 +4255,7 @@ object.assign@^4.1.0: has-symbols "^1.0.0" object-keys "^1.0.11" -object.getownpropertydescriptors@^2.1.0: +object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== @@ -4317,6 +4474,14 @@ parallel-transform@^1.1.0: inherits "^2.0.3" readable-stream "^2.1.5" +param-case@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.3.tgz#4be41f8399eff621c56eebb829a5e451d9801238" + integrity sha512-VWBVyimc1+QrzappRs7waeN2YmoZFCGXWASRYX1/rGHtXqEcrGEIDm+jqIwFa2fRXNgQEwrxaYuIrX0WcAguTA== + dependencies: + dot-case "^3.0.3" + tslib "^1.10.0" + parse-asn1@^5.0.0: version "5.1.5" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e" @@ -4341,6 +4506,14 @@ parse-passwd@^1.0.0: resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= +pascal-case@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.1.tgz#5ac1975133ed619281e88920973d2cd1f279de5f" + integrity sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA== + dependencies: + no-case "^3.0.3" + tslib "^1.10.0" + pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" @@ -4564,6 +4737,14 @@ pretty-bytes@^5.1.0: resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2" integrity sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg== +pretty-error@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6" + integrity sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw== + dependencies: + lodash "^4.17.20" + renderkid "^2.0.4" + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -4740,6 +4921,15 @@ read-pkg@^1.0.0: string_decoder "~1.1.1" util-deprecate "~1.0.1" +readable-stream@^3.1.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readdirp@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" @@ -4808,11 +4998,27 @@ regjsparser@^0.1.4: dependencies: jsesc "~0.5.0" +relateurl@^0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= +renderkid@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.4.tgz#d325e532afb28d3f8796ffee306be8ffd6fc864c" + integrity sha512-K2eXrSOJdq+HuKzlcjOlGoOarUu5SDguDEhE7+Ah4zuOWL40j8A/oHvLlLob9PSTNvVnBd+/q0Er1QfpEuem5g== + dependencies: + css-select "^1.1.0" + dom-converter "^0.2" + htmlparser2 "^3.3.0" + lodash "^4.17.20" + strip-ansi "^3.0.0" + repeat-element@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" @@ -5229,7 +5435,7 @@ source-map@^0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -5416,7 +5622,7 @@ string.prototype.trimright@^2.1.1: define-properties "^1.1.3" function-bind "^1.1.1" -string_decoder@^1.0.0: +string_decoder@^1.0.0, string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== @@ -5618,6 +5824,15 @@ terser@^4.1.2: source-map "~0.6.1" source-map-support "~0.5.12" +terser@^4.6.3: + version "4.8.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" + integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + through2@^2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" @@ -5721,6 +5936,11 @@ ts-loader@^4.5.0: micromatch "^3.1.4" semver "^5.0.1" +tslib@^1.10.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + tslib@^1.9.0: version "1.10.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" @@ -5852,11 +6072,19 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= +util.promisify@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== + dependencies: + define-properties "^1.1.2" + object.getownpropertydescriptors "^2.0.3" + util.promisify@^1.0.0, util.promisify@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" @@ -5881,6 +6109,11 @@ util@^0.11.0: dependencies: inherits "2.0.3" +utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= + uuid@^3.0.1, uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" @@ -5956,6 +6189,11 @@ vue-removed-hook-mixin@^0.1.1: resolved "https://registry.yarnpkg.com/vue-removed-hook-mixin/-/vue-removed-hook-mixin-0.1.1.tgz#df2e939c87d8ecf1707f0b3b3a21def81dedbaf5" integrity sha512-ElO0fn1QT25S7WVHUS7rSug7qBHwR/OPxBTdaH2+DdMz0A/lyw3H40c/Q08k2xvndmx7tAglsevcTk2DgKPsvw== +vue-router@^3.4.8: + version "3.4.8" + resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.4.8.tgz#2c06261d35d8075893470352d42d70b6287b8194" + integrity sha512-3BsR84AqarcmweXjItxw3jwQsiYNssYg090yi4rlzTnCJxmHtkyCvhNz9Z7qRSOkmiV485KkUCReTp5AjNY4wg== + vue2-leaflet@^1.0.2: version "1.2.3" resolved "https://registry.yarnpkg.com/vue2-leaflet/-/vue2-leaflet-1.2.3.tgz#00ddeb9db4fb9a5e3b8f9c09cd97a4734366415e" -- 2.45.2 From e7006b89ea582139a638165f76988bcca9511050 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 22 Nov 2020 14:28:09 +0100 Subject: [PATCH 53/77] #50 - Update manifest on page change --- api/templates/manifest.json.twig | 2 +- front/src/components/main.ts | 2 ++ front/src/components/provider-chooser.ts | 5 +++++ front/src/urls.ts | 4 ++++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/api/templates/manifest.json.twig b/api/templates/manifest.json.twig index 24de7ff..b27f4ed 100644 --- a/api/templates/manifest.json.twig +++ b/api/templates/manifest.json.twig @@ -2,7 +2,7 @@ "name": "Co Jedzie?{% if provider %} - {{ provider.shortName }}{% endif %}", "short_name": "Co Jedzie?{% if provider %} - {{ provider.shortName }}{% endif %}", "orientation": "portrait", - "lang": "pl_PL", + "lang": "pl-PL", "start_url": "{{ provider ? path('app', { provider: provider.identifier }) : path('choose') }}", "display": "standalone", "background_color": "white", diff --git a/front/src/components/main.ts b/front/src/components/main.ts index b5122e3..7ef0158 100644 --- a/front/src/components/main.ts +++ b/front/src/components/main.ts @@ -4,6 +4,7 @@ import { Action, Mutation, State } from 'vuex-class' import { Provider, Stop } from "@/model"; import { DeparturesSettingsState } from "@/store/settings/departures"; import { MessagesSettingsState } from "@/store/settings/messages"; +import urls from "@/urls"; @Component({ template: require("@templates/main.html") }) export class Main extends Vue { @@ -46,6 +47,7 @@ export class Main extends Vue { mounted() { this.$el.classList.remove('not-ready'); + document.querySelector<HTMLLinkElement>('link[rel="manifest"]').href = urls.prepare(urls.manifest.provider, { provider: this.$route.params.provider }); } async created() { diff --git a/front/src/components/provider-chooser.ts b/front/src/components/provider-chooser.ts index f8a37cb..5ea9bf8 100644 --- a/front/src/components/provider-chooser.ts +++ b/front/src/components/provider-chooser.ts @@ -3,6 +3,7 @@ import { Component } from 'vue-property-decorator' import { Provider } from "@/model"; import { Jsonified } from "@/utils"; import * as moment from 'moment'; +import urls from "@/urls"; @Component({ template: require('@templates/page/providers.html'), @@ -10,6 +11,10 @@ import * as moment from 'moment'; export class ProviderChooser extends Vue { private providers: Provider[] = []; + mounted() { + document.querySelector<HTMLLinkElement>('link[rel="manifest"]').href = urls.manifest.main; + } + async created() { const response = await fetch('/api/v1/providers'); const result = await response.json() as Jsonified<Provider>[]; diff --git a/front/src/urls.ts b/front/src/urls.ts index a9fc14c..9b659cf 100644 --- a/front/src/urls.ts +++ b/front/src/urls.ts @@ -66,5 +66,9 @@ export default { get: `/api/v1/providers/{provider}`, }, trip: `${base}/trips/{id}`, + manifest: { + main: '/manifest.json', + provider: '/{provider}/manifest.json', + }, prepare: (url: string, params: UrlParams = { }) => prepare(url, Object.assign({}, { provider: store.state.provider?.id }, params)) } -- 2.45.2 From 832d1e327ab5375c0fca2d2c440ad35966a28242 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 22 Nov 2020 16:03:14 +0100 Subject: [PATCH 54/77] #50 - simple frontend server to supply manifest --- front/.gitignore | 1 + front/package.json | 14 +- front/resources/index.html | 48 --- front/resources/manifest.json | 39 +++ front/resources/views/index.ejs | 65 ++++ front/server/index.ts | 82 +++++ front/server/tsconfig.json | 15 + front/webpack.config.js | 9 - front/yarn.lock | 515 +++++++++++++++++++++++++++++++- 9 files changed, 721 insertions(+), 67 deletions(-) delete mode 100644 front/resources/index.html create mode 100644 front/resources/manifest.json create mode 100644 front/resources/views/index.ejs create mode 100644 front/server/index.ts create mode 100644 front/server/tsconfig.json diff --git a/front/.gitignore b/front/.gitignore index fec845e..02ec49f 100644 --- a/front/.gitignore +++ b/front/.gitignore @@ -3,3 +3,4 @@ yarn-error.log /public/* !/public/.gitkeep /node_modules/ +/build/ diff --git a/front/package.json b/front/package.json index b995721..b4cb4bc 100644 --- a/front/package.json +++ b/front/package.json @@ -13,6 +13,13 @@ "@types/jquery": "^3.3.6", "@types/moment": "^2.13.0", "@types/popper.js": "^1.11.0", + "@types/ejs": "^3.0.5", + "@types/express": "^4.17.9", + "@types/mapbox-gl-leaflet": "^0.0.1", + "@types/request": "^2.48.5", + "@types/uuid": "^3.4.6", + "@types/vue-moment": "^4.0.0", + "@types/workbox-window": "^4.3.3", "bootstrap": "^4.3.1", "css-loader": "^1.0.0", "file-loader": "^2.0.0", @@ -34,18 +41,17 @@ "xpath": "^0.0.27" }, "dependencies": { - "@types/mapbox-gl-leaflet": "^0.0.1", - "@types/uuid": "^3.4.6", - "@types/vue-moment": "^4.0.0", - "@types/workbox-window": "^4.3.3", "clean-webpack-plugin": "^3.0.0", "copy-webpack-plugin": "^4.5.2", + "ejs": "^3.1.5", + "express": "^4.17.1", "html-webpack-plugin": "^4.5.0", "imagemin-webpack-plugin": "^2.3.0", "mapbox-gl": "^1.6.1", "mapbox-gl-leaflet": "^0.0.11", "mini-css-extract-plugin": "^0.4.2", "portal-vue": "^2.1.7", + "request": "^2.88.2", "vue-dragscroll": "^1.10.2", "vue-fragment": "^1.5.1", "vue-moment": "^4.1.0", diff --git a/front/resources/index.html b/front/resources/index.html deleted file mode 100644 index 1cab4f8..0000000 --- a/front/resources/index.html +++ /dev/null @@ -1,48 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <meta charset="UTF-8"/> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - <link rel="stylesheet" href="dist/main.css"/> - <link rel="manifest" href="manifest.json"/> - - <!-- icons --> - <link rel="icon" href="images/favicon.png" sizes="16x16"/> - <link rel="icon" href="images/favicon-2x.png" sizes="32x32"/> - <link rel="icon" href="images/favicon.ico"/> - - <!-- Apple shit --> - <link rel="apple-touch-icon" href="images/ios.png" sizes="512x512"> - <link rel="apple-touch-icon" href="images/ios-80.png" sizes="80x80"> - <link rel="apple-touch-icon" href="images/ios-192.png" sizes="192x192"> - - <meta name="apple-mobile-web-app-title" content="Co Jedzie?"> - <meta name="apple-mobile-web-app-capable" content="yes"> - - <meta name="theme-color" content="white"/> - - <title>Co Jedzie?</title> - </head> - <body> - <noscript> - <div class="container"> - <div class="alert alert-danger"> - Aplikacja wymaga do działania obsługi JavaScriptu. - </div> - </div> - </noscript> - <main id="root" class="container not-ready"> - </main> - <footer class="container"> - <span> - <img src="images/logo.png" alt="co jedzie logo"/> - v.<%= htmlWebpackPlugin.options.version %> • - <a href="/api/doc">API</a> - </span> - <span class="copyright flex flex-space-left justify-content-end"> - <a href="https://kadet.net"><img src="images/kadet-net-logo.png" alt="kadet.net logo" class="mx-1"/></a> - © <%= htmlWebpackPlugin.options.year %> - </span> - </footer> - </body> -</html> diff --git a/front/resources/manifest.json b/front/resources/manifest.json new file mode 100644 index 0000000..00dd533 --- /dev/null +++ b/front/resources/manifest.json @@ -0,0 +1,39 @@ +{ + "name": "Co Jedzie?", + "short_name": "Co Jedzie?", + "orientation": "portrait", + "lang": "pl_PL", + "start_url": "/", + "display": "standalone", + "background_color": "white", + "theme_color": "white", + "description": "Odpowiedź na odwieczne pytanie ludzkości - czy tramwaje jeżdżą?", + "categories": ["navigation", "transport", "travel", "utilities"], + "icons": [{ + "src": "/images/icon-256.png", + "sizes": "256x256" + },{ + "src": "/images/icon-512.png", + "sizes": "512x512" + },{ + "src": "/images/icon-64.png", + "sizes": "64x64" + },{ + "src": "/images/icon-128.png", + "sizes": "128x128" + },{ + "src": "/images/icon-192.png", + "sizes": "192x192" + },{ + "src": "/images/icon-96.png", + "sizes": "96x96" + },{ + "src": "/images/icon-maskable.png", + "sizes": "512x512", + "purpose": "any maskable" + },{ + "src": "/images/icon-monochrome.png", + "sizes": "512x512", + "purpose": "monochrome" + }] +} diff --git a/front/resources/views/index.ejs b/front/resources/views/index.ejs new file mode 100644 index 0000000..b4ecffc --- /dev/null +++ b/front/resources/views/index.ejs @@ -0,0 +1,65 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8"/> + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> + <link rel="stylesheet" href="/dist/main.css"/> + <link rel="manifest" href="<%= manifest_path %>"/> + + <!-- icons --> + <link rel="icon" href="/images/favicon.png" sizes="16x16"/> + <link rel="icon" href="/images/favicon-2x.png" sizes="32x32"/> + <link rel="icon" href="/images/favicon.ico"/> + + <!-- Apple shit --> + <link rel="apple-touch-icon" href="/images/ios.png" sizes="512x512"> + <link rel="apple-touch-icon" href="/images/ios-80.png" sizes="80x80"> + <link rel="apple-touch-icon" href="/images/ios-192.png" sizes="192x192"> + + <meta name="apple-mobile-web-app-title" content="Co Jedzie?"> + <meta name="apple-mobile-web-app-capable" content="yes"> + + <meta name="theme-color" content="white"/> + + <title>Co Jedzie?</title> + + <% if (gtm_tracking) { %> + <!-- Google Tag Manager --> + <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': + new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], + j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= + 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); + })(window,document,'script','dataLayer','<%= gtm_tracking %>');</script> + <!-- End Google Tag Manager --> + <% } %> + </head> + <body> + <noscript> + <% if (gtm_tracking) { %> + <!-- Google Tag Manager (noscript) --> + <iframe src="https://www.googletagmanager.com/ns.html?id=<%= gtm_tracking %>" + height="0" width="0" style="display:none;visibility:hidden"></iframe> + <!-- End Google Tag Manager (noscript) --> + <% } %> + <div class="container"> + <div class="alert alert-danger"> + Aplikacja wymaga do działania obsługi JavaScriptu. + </div> + </div> + </noscript> + <main id="root" class="container not-ready"> + </main> + <footer class="container"> + <span> + <img src="images/logo.png" alt="co jedzie logo"/> + v.<%= version %> • + <a href="/api/doc">API</a> + </span> + <span class="copyright flex flex-space-left justify-content-end"> + <a href="https://kadet.net"><img src="images/kadet-net-logo.png" alt="kadet.net logo" class="mx-1"/></a> + © <%= year %> + </span> + </footer> + <script src="/dist/main.js"></script> + </body> +</html> diff --git a/front/server/index.ts b/front/server/index.ts new file mode 100644 index 0000000..c499c9a --- /dev/null +++ b/front/server/index.ts @@ -0,0 +1,82 @@ +import express from 'express'; +import path from "path"; +import fs from "fs"; +import request from "request"; + +const server = express(); + +const port = parseInt(process.env.APP_PORT) || 3000; +const host = process.env.APP_HOST || 'localhost'; +const api = process.env.APP_API || "https://cojedzie.pl/api/v1/"; + +const gtm_tracking = process.env.APP_GTM || ''; +const version = "2020.11-dev"; + +const manifest = JSON.parse( + fs.readFileSync(path.join(__dirname, "../resources/manifest.json")).toString("utf-8") +); + +const provider_manifests = {} + +function generateProviderManifest(provider: any) { + return { + ...manifest, + start_url: `/${provider.id}`, + name: `${manifest.name} - ${provider.name}`, + short_name: `${manifest.short_name} - ${provider.shortName}`, + }; +} + +server.set("views", path.join(__dirname, "../resources/views/")); +server.set("view engine", "ejs"); + +server.use(express.static(path.join(__dirname, "../public/"))) + +server.get("/:provider?/manifest.json", (req, res) => { + const provider = req.params.provider; + + if (typeof provider === "undefined") { + res.send(manifest); + return; + } + + if (typeof provider_manifests[provider] !== "undefined") { + res.send(provider_manifests[provider]); + return; + } + + console.log(`No manifest entry for ${provider}, calling ${api}/providers/${provider}`); + + request.get(`${api}/providers/${provider}`, (err, _, body) => { + try { + const info = JSON.parse(body); + provider_manifests[provider] = generateProviderManifest(info); + + console.info(`Generated manifest for ${provider}`, provider_manifests[provider]); + + res.send(provider_manifests[provider]); + } catch(error) { + console.error(`Problem with generating manifest for ${provider}: ${error.message}`); + res.send(manifest); + } + }) +}) + +server.get("/:provider?", (req, res) => { + const manifest_path = req.params.provider + ? `/${req.params.provider}/manifest.json` + : "/manifest.json"; + + const year = (new Date()).getFullYear(); + + res.render("index", { + manifest_path, + gtm_tracking, + version, + year, + }) +}) + +server.listen(port, host, () => { + console.info(`Server started at ${host}:${port}`); +}); diff --git a/front/server/tsconfig.json b/front/server/tsconfig.json new file mode 100644 index 0000000..81e0750 --- /dev/null +++ b/front/server/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "lib": ["es2015", "es2016.array.include", "es2017.object"], + "sourceMap": true, + "esModuleInterop": true, + "target": "es6", + "module": "commonjs", + "moduleResolution": "node", + "baseUrl": "./", + "outDir": "../build/", + "skipLibCheck": true + }, + "files": ["./index.ts"], + "include": ["./**/*.ts"] +} diff --git a/front/webpack.config.js b/front/webpack.config.js index 6fb9c8a..e897b78 100644 --- a/front/webpack.config.js +++ b/front/webpack.config.js @@ -89,14 +89,5 @@ module.exports = (env, argv) => { config.devtool = 'inline-source-map'; } - config.plugins.push( - new HtmlWebpackPlugin({ - template: path.resolve(__dirname, "./resources/index.html"), - chunks: ['main'], - year: new Date().getFullYear(), - version: process.env.CZYDOJADE_VERSION || (argv.mode === 'development' ? '2020.11-dev' : '2020.11'), - }) - ) - return config; }; diff --git a/front/yarn.lock b/front/yarn.lock index 4d5f6a7..052244f 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -161,6 +161,14 @@ resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== +"@types/body-parser@*": + version "1.19.0" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f" + integrity sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ== + dependencies: + "@types/connect" "*" + "@types/node" "*" + "@types/bootstrap@^4.3.1": version "4.3.1" resolved "https://registry.yarnpkg.com/@types/bootstrap/-/bootstrap-4.3.1.tgz#15fa89a4d275b114a4eceb90909d4eb8b90d43f5" @@ -169,11 +177,47 @@ "@types/jquery" "*" popper.js "^1.14.1" +"@types/caseless@*": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8" + integrity sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w== + +"@types/connect@*": + version "3.4.33" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546" + integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A== + dependencies: + "@types/node" "*" + +"@types/ejs@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/ejs/-/ejs-3.0.5.tgz#95a3a1c3d9603eba80fe67ff56da1ba275ef2eda" + integrity sha512-k4ef69sS4sIqAPW9GoBnN+URAON2LeL1H0duQvL4RgdEBna19/WattYSA1qYqvbVEDRTSWzOw56tCLhC/m/IOw== + "@types/events@*": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== +"@types/express-serve-static-core@*": + version "4.17.13" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.13.tgz#d9af025e925fc8b089be37423b8d1eac781be084" + integrity sha512-RgDi5a4nuzam073lRGKTUIaL3eF2+H7LJvJ8eUnCI0wA6SNjXc44DCmWNiTLs/AZ7QlsFWZiw/gTG3nSQGL0fA== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + +"@types/express@^4.17.9": + version "4.17.9" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.9.tgz#f5f2df6add703ff28428add52bdec8a1091b0a78" + integrity sha512-SDzEIZInC4sivGIFY4Sz1GG6J9UObPwCInYJjko2jzOf/Imx/dlpume6Xxwj1ORL82tBbmN4cPDIDkLbWHk9hw== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "*" + "@types/qs" "*" + "@types/serve-static" "*" + "@types/geojson@*": version "7946.0.7" resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.7.tgz#c8fa532b60a0042219cdf173ca21a975ef0666ad" @@ -250,6 +294,11 @@ dependencies: "@types/leaflet" "*" +"@types/mime@*": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a" + integrity sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q== + "@types/minimatch@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" @@ -279,6 +328,34 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== +"@types/qs@*": + version "6.9.5" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.5.tgz#434711bdd49eb5ee69d90c1d67c354a9a8ecb18b" + integrity sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ== + +"@types/range-parser@*": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" + integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== + +"@types/request@^2.48.5": + version "2.48.5" + resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.5.tgz#019b8536b402069f6d11bee1b2c03e7f232937a0" + integrity sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ== + dependencies: + "@types/caseless" "*" + "@types/node" "*" + "@types/tough-cookie" "*" + form-data "^2.5.0" + +"@types/serve-static@*": + version "1.13.8" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.8.tgz#851129d434433c7082148574ffec263d58309c46" + integrity sha512-MoJhSQreaVoL+/hurAZzIm8wafFR6ajiTM1m4A0kv6AGeVBl4r4pOV8bGFrjjq1sGxDTnCoF8i22o0/aE5XCyA== + dependencies: + "@types/mime" "*" + "@types/node" "*" + "@types/sizzle@*": version "2.3.2" resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" @@ -304,6 +381,11 @@ resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.6.tgz#a9ca4b70a18b270ccb2bc0aaafefd1d486b7ea74" integrity sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA== +"@types/tough-cookie@*": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.0.tgz#fef1904e4668b6e5ecee60c52cc6a078ffa6697d" + integrity sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A== + "@types/uglify-js@*": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082" @@ -523,6 +605,14 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + acorn@^6.2.1: version "6.4.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.0.tgz#b659d2ffbafa24baf5db1cdbb2c94a983ecd2784" @@ -548,6 +638,16 @@ ajv@^6.1.0, ajv@^6.10.2, ajv@^6.5.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^6.12.3: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" @@ -645,6 +745,11 @@ array-find-index@^1.0.1: resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -716,6 +821,11 @@ async-throttle@^1.1.0: resolved "https://registry.yarnpkg.com/async-throttle/-/async-throttle-1.1.0.tgz#229e7f3fa7a2a797e86f360e6309a08224d4fa7a" integrity sha1-Ip5/P6eip5fobzYOYwmggiTU+no= +async@0.9.x: + version "0.9.2" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -898,6 +1008,22 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== +body-parser@1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + boolbase@^1.0.0, boolbase@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" @@ -1051,6 +1177,11 @@ builtin-status-codes@^3.0.0: resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + cacache@^10.0.4: version "10.0.4" resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" @@ -1178,7 +1309,7 @@ caw@^2.0.0, caw@^2.0.1: tunnel-agent "^0.6.0" url-to-options "^1.0.1" -chalk@2.4.2, chalk@^2.3.0, chalk@^2.4.1: +chalk@2.4.2, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1412,13 +1543,28 @@ constants-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= -content-disposition@^0.5.2: +content-disposition@0.5.3, content-disposition@^0.5.2: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== dependencies: safe-buffer "5.1.2" +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + copy-concurrently@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" @@ -1642,7 +1788,7 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -debug@^2.2.0, debug@^2.3.3: +debug@2.6.9, debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -1771,6 +1917,11 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + des.js@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" @@ -1779,6 +1930,11 @@ des.js@^1.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + detect-file@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" @@ -1932,6 +2088,18 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +ejs@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.5.tgz#aed723844dc20acb4b170cd9ab1017e476a0d93b" + integrity sha512-dldq3ZfFtgVTJMLjOe+/3sROTzALlL9E34V4/sDtUd/KlBSS0s6U1/+WPE1B4sj9CXHJpL1M6rhNJnc9Wbal9w== + dependencies: + jake "^10.6.1" + elliptic@^6.0.0: version "6.5.2" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762" @@ -1955,6 +2123,11 @@ emojis-list@^2.0.0: resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -2030,6 +2203,11 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -2070,6 +2248,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + events@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59" @@ -2160,6 +2343,42 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2: dependencies: homedir-polyfill "^1.0.1" +express@^4.17.1: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.0" + content-disposition "0.5.3" + content-type "~1.0.4" + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" + safe-buffer "5.1.2" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + ext-list@^2.0.0: version "2.2.2" resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37" @@ -2309,6 +2528,13 @@ file-uri-to-path@1.0.0: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== +filelist@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.1.tgz#f10d1a3ae86c1694808e8f20906f43d4c9132dbb" + integrity sha512-8zSK6Nu0DQIC08mUC46sWGXi+q3GGpKydAG36k+JDba6VRpkevvOWUW5a/PhShij4+vHT9M+ghgG7eM+a9JDUQ== + dependencies: + minimatch "^3.0.4" + filename-reserved-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" @@ -2333,6 +2559,19 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + find-cache-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" @@ -2413,6 +2652,15 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= +form-data@^2.5.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" + integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" @@ -2422,6 +2670,11 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" @@ -2429,6 +2682,11 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + from2@^2.1.0, from2@^2.1.1: version "2.3.0" resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" @@ -2766,6 +3024,14 @@ har-validator@~5.1.0: ajv "^6.5.5" har-schema "^2.0.0" +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -2930,6 +3196,28 @@ http-cache-semantics@3.8.1: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -2944,6 +3232,13 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + icss-replace-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" @@ -3095,7 +3390,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -3138,6 +3433,11 @@ invert-kv@^2.0.0: resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -3420,6 +3720,16 @@ isurl@^1.0.0-alpha5: has-to-string-tag-x "^1.2.0" is-object "^1.0.1" +jake@^10.6.1: + version "10.8.2" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.2.tgz#ebc9de8558160a66d82d0eadc6a2e58fbc500a7b" + integrity sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A== + dependencies: + async "0.9.x" + chalk "^2.4.2" + filelist "^1.0.1" + minimatch "^3.0.4" + jpegtran-bin@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jpegtran-bin/-/jpegtran-bin-4.0.0.tgz#d00aed809fba7aa6f30817e59eee4ddf198f8f10" @@ -3814,6 +4124,11 @@ mdn-data@2.0.4: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + mem@^4.0.0: version "4.3.0" resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" @@ -3855,11 +4170,21 @@ meow@^3.3.0, meow@^3.7.0: redent "^1.0.0" trim-newlines "^1.0.0" +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + merge2@^1.2.3: version "1.3.0" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw== +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -3892,6 +4217,11 @@ mime-db@1.43.0, mime-db@^1.28.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== +mime-db@1.44.0: + version "1.44.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" + integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== + mime-types@^2.1.12, mime-types@~2.1.19: version "2.1.26" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" @@ -3899,6 +4229,18 @@ mime-types@^2.1.12, mime-types@~2.1.19: dependencies: mime-db "1.43.0" +mime-types@~2.1.24: + version "2.1.27" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" + integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== + dependencies: + mime-db "1.44.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + mimic-fn@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -4019,6 +4361,11 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + murmurhash-js@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/murmurhash-js/-/murmurhash-js-1.0.0.tgz#b06278e21fc6c37fa5313732b0412bcb6ae15f51" @@ -4046,6 +4393,11 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + neo-async@^2.5.0, neo-async@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" @@ -4280,6 +4632,13 @@ object.values@^1.1.0: function-bind "^1.1.1" has "^1.0.3" +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -4506,6 +4865,11 @@ parse-passwd@^1.0.0: resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + pascal-case@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.1.tgz#5ac1975133ed619281e88920973d2cd1f279de5f" @@ -4561,6 +4925,11 @@ path-parse@^1.0.6: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" @@ -4770,6 +5139,14 @@ protocol-buffers-schema@^3.3.1: resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.4.0.tgz#2f0ea31ca96627d680bf2fefae7ebfa2b6453eae" integrity sha512-G/2kcamPF2S49W5yaMGdIpkG6+5wZF0fzBteLKgEHjbNzqjZQ85aAs1iJGto31EJaSTkNvHs5IXuHSaTLWBAiA== +proxy-addr@~2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" + integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.9.1" + prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -4785,6 +5162,11 @@ psl@^1.1.24: resolved "https://registry.yarnpkg.com/psl/-/psl-1.7.0.tgz#f1c4c47a8ef97167dea5d6bbf4816d736e884a3c" integrity sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ== +psl@^1.1.28: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + public-encrypt@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" @@ -4832,7 +5214,7 @@ punycode@^1.2.4, punycode@^1.4.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= -punycode@^2.1.0: +punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== @@ -4842,6 +5224,11 @@ q@^1.1.2: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -4886,6 +5273,21 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + raw-loader@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa" @@ -5067,6 +5469,32 @@ request@^2.87.0, request@^2.88.0: tunnel-agent "^0.6.0" uuid "^3.3.2" +request@^2.88.2: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -5177,7 +5605,7 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -5267,6 +5695,25 @@ semver@~5.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + serialize-javascript@^1.4.0: version "1.9.1" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.9.1.tgz#cfc200aef77b600c47da9bb8149c943e798c2fdb" @@ -5277,6 +5724,16 @@ serialize-javascript@^2.1.2: resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -5297,6 +5754,11 @@ setimmediate@^1.0.4: resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + sha.js@^2.4.0, sha.js@^2.4.8: version "2.4.11" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" @@ -5536,6 +5998,11 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + stdout-stream@^1.4.0: version "1.4.1" resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de" @@ -5898,6 +6365,11 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + tough-cookie@~2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" @@ -5906,6 +6378,14 @@ tough-cookie@~2.4.3: psl "^1.1.24" punycode "^1.4.1" +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" @@ -5963,6 +6443,14 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -6010,6 +6498,11 @@ universalify@^0.1.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + unquote@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" @@ -6114,6 +6607,11 @@ utila@~0.4: resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + uuid@^3.0.1, uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" @@ -6132,6 +6630,11 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" -- 2.45.2 From 7523d288d3a06554266696bfeaf526acaa5b8146 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 22 Nov 2020 19:59:03 +0100 Subject: [PATCH 55/77] #50 - create Dockerfile for frontend --- front/.dockerignore | 4 ++ front/Dockerfile | 34 +++++++++++++++ front/package.json | 28 +++++++------ front/public/.gitkeep | 0 front/resources/fontawesome/.gitignore | 3 ++ front/resources/views/index.ejs | 4 +- front/server/{index.ts => server.ts} | 15 ++++--- front/server/tsconfig.json | 2 +- front/webpack.config.js | 4 +- front/yarn.lock | 57 +++++++++++--------------- 10 files changed, 97 insertions(+), 54 deletions(-) create mode 100644 front/.dockerignore create mode 100644 front/Dockerfile delete mode 100644 front/public/.gitkeep create mode 100644 front/resources/fontawesome/.gitignore rename front/server/{index.ts => server.ts} (83%) diff --git a/front/.dockerignore b/front/.dockerignore new file mode 100644 index 0000000..c7c2b54 --- /dev/null +++ b/front/.dockerignore @@ -0,0 +1,4 @@ +/node_modules/ +/build/ +yarn-error* +npm-debug* diff --git a/front/Dockerfile b/front/Dockerfile new file mode 100644 index 0000000..f7a57df --- /dev/null +++ b/front/Dockerfile @@ -0,0 +1,34 @@ +FROM node:15.2.1 as build + +WORKDIR /app +COPY . . + +# install dependencies +RUN yarn install +RUN find resources/fontawesome -type f -name '*.tgz' | sed s/^/file:/ | xargs yarn add-no-save + +# build stuff +RUN yarn run build:app +RUN yarn run build:server + +# server dependencies step +FROM node:15.2.1 as prod-dependencies + +WORKDIR /app + +COPY . . + +# install dependencies +RUN yarn install --production + +FROM node:15.2.1-slim + +WORKDIR /app + +COPY --from=build /app/build/ build +COPY --from=build /app/resources/ resources +COPY --from=prod-dependencies /app/node_modules/ node_modules + +EXPOSE 3000 + +CMD ["node", "build/server.js"] diff --git a/front/package.json b/front/package.json index b4cb4bc..e43d65e 100644 --- a/front/package.json +++ b/front/package.json @@ -1,21 +1,18 @@ { - "name": "co-jedzie", + "name": "cojedzie", "version": "1.0.0", "author": "Kacper Donat <kadet1090@gmail.com>", "license": "MIT", "devDependencies": { "@fortawesome/fontawesome-svg-core": "^1.2.4", - "@fortawesome/pro-light-svg-icons": "^5.3.1", - "@fortawesome/pro-regular-svg-icons": "^5.3.1", - "@fortawesome/pro-solid-svg-icons": "^5.3.1", "@fortawesome/vue-fontawesome": "^0.1.1", "@types/bootstrap": "^4.3.1", - "@types/jquery": "^3.3.6", - "@types/moment": "^2.13.0", - "@types/popper.js": "^1.11.0", "@types/ejs": "^3.0.5", "@types/express": "^4.17.9", + "@types/jquery": "^3.3.6", "@types/mapbox-gl-leaflet": "^0.0.1", + "@types/moment": "^2.13.0", + "@types/popper.js": "^1.11.0", "@types/request": "^2.48.5", "@types/uuid": "^3.4.6", "@types/vue-moment": "^4.0.0", @@ -38,20 +35,16 @@ "webpack": "^4.17.0", "webpack-cli": "^3.1.0", "xmldom": "^0.1.27", - "xpath": "^0.0.27" - }, - "dependencies": { + "xpath": "^0.0.27", + "yarn-add-no-save": "^1.0.3", "clean-webpack-plugin": "^3.0.0", "copy-webpack-plugin": "^4.5.2", - "ejs": "^3.1.5", - "express": "^4.17.1", "html-webpack-plugin": "^4.5.0", "imagemin-webpack-plugin": "^2.3.0", "mapbox-gl": "^1.6.1", "mapbox-gl-leaflet": "^0.0.11", "mini-css-extract-plugin": "^0.4.2", "portal-vue": "^2.1.7", - "request": "^2.88.2", "vue-dragscroll": "^1.10.2", "vue-fragment": "^1.5.1", "vue-moment": "^4.1.0", @@ -63,5 +56,14 @@ "vuex-persist": "^2.2.0", "workbox-webpack-plugin": "^4.3.1", "workbox-window": "^4.3.1" + }, + "dependencies": { + "ejs": "^3.1.5", + "express": "^4.17.1", + "request": "^2.88.2" + }, + "scripts": { + "build:server": "tsc -p server", + "build:app": "webpack --config webpack.config.js --mode production --progress" } } diff --git a/front/public/.gitkeep b/front/public/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/front/resources/fontawesome/.gitignore b/front/resources/fontawesome/.gitignore new file mode 100644 index 0000000..39d81c9 --- /dev/null +++ b/front/resources/fontawesome/.gitignore @@ -0,0 +1,3 @@ +# this folder is created to store fontawesome pro packages +* +!.gitignore diff --git a/front/resources/views/index.ejs b/front/resources/views/index.ejs index b4ecffc..f99ad2b 100644 --- a/front/resources/views/index.ejs +++ b/front/resources/views/index.ejs @@ -51,12 +51,12 @@ </main> <footer class="container"> <span> - <img src="images/logo.png" alt="co jedzie logo"/> + <img src="/images/logo.png" alt="co jedzie logo"/> v.<%= version %> • <a href="/api/doc">API</a> </span> <span class="copyright flex flex-space-left justify-content-end"> - <a href="https://kadet.net"><img src="images/kadet-net-logo.png" alt="kadet.net logo" class="mx-1"/></a> + <a href="https://kadet.net"><img src="/images/kadet-net-logo.png" alt="kadet.net logo" class="mx-1"/></a> © <%= year %> </span> </footer> diff --git a/front/server/index.ts b/front/server/server.ts similarity index 83% rename from front/server/index.ts rename to front/server/server.ts index c499c9a..23c6d25 100644 --- a/front/server/index.ts +++ b/front/server/server.ts @@ -6,8 +6,8 @@ import request from "request"; const server = express(); const port = parseInt(process.env.APP_PORT) || 3000; -const host = process.env.APP_HOST || 'localhost'; -const api = process.env.APP_API || "https://cojedzie.pl/api/v1/"; +const host = process.env.APP_HOST || '0.0.0.0'; +const api = process.env.APP_API || "https://cojedzie.pl/api"; const gtm_tracking = process.env.APP_GTM || ''; const version = "2020.11-dev"; @@ -30,7 +30,7 @@ function generateProviderManifest(provider: any) { server.set("views", path.join(__dirname, "../resources/views/")); server.set("view engine", "ejs"); -server.use(express.static(path.join(__dirname, "../public/"))) +server.use(express.static(path.join(__dirname, "../build/public/"))) server.get("/:provider?/manifest.json", (req, res) => { const provider = req.params.provider; @@ -47,7 +47,7 @@ server.get("/:provider?/manifest.json", (req, res) => { console.log(`No manifest entry for ${provider}, calling ${api}/providers/${provider}`); - request.get(`${api}/providers/${provider}`, (err, _, body) => { + request.get(`${api}/v1/providers/${provider}`, (err, _, body) => { try { const info = JSON.parse(body); provider_manifests[provider] = generateProviderManifest(info); @@ -62,7 +62,7 @@ server.get("/:provider?/manifest.json", (req, res) => { }) }) -server.get("/:provider?", (req, res) => { +server.get("/:provider?/*", (req, res) => { const manifest_path = req.params.provider ? `/${req.params.provider}/manifest.json` : "/manifest.json"; @@ -80,3 +80,8 @@ server.get("/:provider?", (req, res) => { server.listen(port, host, () => { console.info(`Server started at ${host}:${port}`); }); + +process.on('SIGINT', function() { + console.info("Terminating server..."); + process.exit(); +}); diff --git a/front/server/tsconfig.json b/front/server/tsconfig.json index 81e0750..390f710 100644 --- a/front/server/tsconfig.json +++ b/front/server/tsconfig.json @@ -10,6 +10,6 @@ "outDir": "../build/", "skipLibCheck": true }, - "files": ["./index.ts"], + "files": ["./server.ts"], "include": ["./**/*.ts"] } diff --git a/front/webpack.config.js b/front/webpack.config.js index e897b78..e745e5b 100644 --- a/front/webpack.config.js +++ b/front/webpack.config.js @@ -6,13 +6,15 @@ const ImageminPlugin = require('imagemin-webpack-plugin').default; const { GenerateSW } = require('workbox-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); +const output_dir = path.resolve('./build/') + const config = { entry: { main: ['./src/app.ts'], api: ['./styles/api.scss'] }, output: { - path: path.resolve('./public/dist/'), + path: path.join(output_dir, './public/dist/'), publicPath: "/dist/", filename: "[name].js", chunkFilename: '[name].[chunkhash:8].js' diff --git a/front/yarn.lock b/front/yarn.lock index 052244f..a9f96ac 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -9,43 +9,22 @@ dependencies: regenerator-runtime "^0.13.2" -"@fortawesome/fontawesome-common-types@^0.2.27": - version "0.2.27" - resolved "https://npm.fontawesome.com/@fortawesome/fontawesome-common-types/-/0.2.27/fontawesome-common-types-0.2.27.tgz#19706345859fc46adf3684ed01d11b40903b87e9" - integrity sha512-97GaByGaXDGMkzcJX7VmR/jRJd8h1mfhtA7RsxDBN61GnWE/PPCZhOdwG/8OZYktiRUF0CvFOr+VgRkJrt6TWg== +"@fortawesome/fontawesome-common-types@^0.2.32": + version "0.2.32" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.32.tgz#3436795d5684f22742989bfa08f46f50f516f259" + integrity sha512-ux2EDjKMpcdHBVLi/eWZynnPxs0BtFVXJkgHIxXRl+9ZFaHPvYamAfCzeeQFqHRjuJtX90wVnMRaMQAAlctz3w== "@fortawesome/fontawesome-svg-core@^1.2.4": - version "1.2.27" - resolved "https://npm.fontawesome.com/@fortawesome/fontawesome-svg-core/-/1.2.27/fontawesome-svg-core-1.2.27.tgz#e4db8e3be81a40988213507c3e3d0c158a6641a3" - integrity sha512-sOD3DKynocnHYpuw2sLPnTunDj7rLk91LYhi2axUYwuGe9cPCw7Bsu9EWtVdNJP+IYgTCZIbyARKXuy5K/nv+Q== + version "1.2.32" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.32.tgz#da092bfc7266aa274be8604de610d7115f9ba6cf" + integrity sha512-XjqyeLCsR/c/usUpdWcOdVtWFVjPbDFBTQkn2fQRrWhhUoxriQohO2RWDxLyUM8XpD+Zzg5xwJ8gqTYGDLeGaQ== dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.27" - -"@fortawesome/pro-light-svg-icons@^5.3.1": - version "5.12.1" - resolved "https://npm.fontawesome.com/@fortawesome/pro-light-svg-icons/-/5.12.1/pro-light-svg-icons-5.12.1.tgz#802f8aac0204c41c7a138c5c9547d3cadbeec39a" - integrity sha512-vCT7qkoJINQuNEW7N+i1ioZQ7FHp5UiRPAHxuRS5qFPOXlVxtK8+Yf8DZ+KOpPQiwXoDX0tKFuS6Jc1HOB1qIg== - dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.27" - -"@fortawesome/pro-regular-svg-icons@^5.3.1": - version "5.12.1" - resolved "https://npm.fontawesome.com/@fortawesome/pro-regular-svg-icons/-/5.12.1/pro-regular-svg-icons-5.12.1.tgz#852f782eb2f50ee56784f6bb05d62d249b1c0794" - integrity sha512-IHwJ1Jj8zfNwC3Bj2m+YD21L1et9Ocxu6RCSLVqpTYgz2BT7CwUzHy83hUL+4JDEuA41sYyZjdsAXDgg5+DKZg== - dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.27" - -"@fortawesome/pro-solid-svg-icons@^5.3.1": - version "5.12.1" - resolved "https://npm.fontawesome.com/@fortawesome/pro-solid-svg-icons/-/5.12.1/pro-solid-svg-icons-5.12.1.tgz#1de223a184a81f40c1ab575880168c82c7afc773" - integrity sha512-7xhIu8QuBBK9/grUVx28rs9MNJaMQppt/rrhY2LMiYuETVKrYzHuTDvjS+UXaKsgHN31JTM/vVMVro/daTB/uw== - dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.27" + "@fortawesome/fontawesome-common-types" "^0.2.32" "@fortawesome/vue-fontawesome@^0.1.1": - version "0.1.9" - resolved "https://npm.fontawesome.com/@fortawesome/vue-fontawesome/-/0.1.9/vue-fontawesome-0.1.9.tgz#d3af6d4e50f337327de90447fe35fa1e117a2fbe" - integrity sha512-h/emhmZz+DfB2zOGLWawNwXq82UYhn9waTfUjLLmeaIqtnIyNt6kYlpQT/vzJjLZRDRvY2IEJAh1di5qKpKVpA== + version "0.1.10" + resolved "https://registry.yarnpkg.com/@fortawesome/vue-fontawesome/-/vue-fontawesome-0.1.10.tgz#eeeec1e4e8850bed0468f938292b06cda793bf34" + integrity sha512-b2+SLF31h32LSepVcXe+BQ63yvbq5qmTCy4KfFogCYm2bn68H5sDWUnX+U7MBqnM2aeEk9M7xSoqGnu+wSdY6w== "@hapi/address@2.x.x": version "2.1.4" @@ -6813,6 +6792,13 @@ which@1, which@^1.2.14, which@^1.2.9, which@^1.3.1: dependencies: isexe "^2.0.0" +which@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + wide-align@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" @@ -7070,6 +7056,13 @@ yargs@^7.0.0: y18n "^3.2.1" yargs-parser "^5.0.0" +yarn-add-no-save@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/yarn-add-no-save/-/yarn-add-no-save-1.0.3.tgz#03540f86802a46a86db83bc7357b248cd282315b" + integrity sha512-ngmmxwYOogvYPjFDXGjoj35r/DteDzfiyoq5BI+kKSCCXW/I2gJA3KAgbm/7yFmcDE9CGSaORpNbYfglGYuxtA== + dependencies: + which "^2.0.2" + yauzl@^2.4.2: version "2.10.0" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" -- 2.45.2 From 3e1271a88fa8be60b206df7bfc78356cf039b205 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 22 Nov 2020 23:07:50 +0100 Subject: [PATCH 56/77] #50 - docker-compose now uses frontend server --- api/.env.dist | 2 -- api/config/packages/twig.yaml | 2 -- docker-compose.yml | 11 ++++++++++- docker/nginx/{czydojade => cojedzie.conf} | 10 ++++++---- front/resources/manifest.json | 2 +- 5 files changed, 17 insertions(+), 10 deletions(-) rename docker/nginx/{czydojade => cojedzie.conf} (83%) diff --git a/api/.env.dist b/api/.env.dist index 2edbb91..69f196a 100644 --- a/api/.env.dist +++ b/api/.env.dist @@ -2,8 +2,6 @@ # Copy this file to .env file for development, create environment variables when deploying to production # https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration -GTM_TAG= - ###> symfony/framework-bundle ### APP_ENV=dev APP_SECRET=1bdf86cdc78fba654e4f2c309c6bbdbd diff --git a/api/config/packages/twig.yaml b/api/config/packages/twig.yaml index da841eb..3b315dc 100644 --- a/api/config/packages/twig.yaml +++ b/api/config/packages/twig.yaml @@ -2,5 +2,3 @@ twig: paths: ['%kernel.project_dir%/templates'] debug: '%kernel.debug%' strict_variables: '%kernel.debug%' - globals: - gtm_tracking: "%env(GTM_TAG)%" diff --git a/docker-compose.yml b/docker-compose.yml index a3a6004..5b7ca4b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: volumes: - ./front:/var/www/front:cached - ./api:/var/www/api:cached - - ./docker/nginx/czydojade:/etc/nginx/conf.d/czydojade.conf + - ./docker/nginx/cojedzie.conf:/etc/nginx/conf.d/cojedzie.conf api: build: ./api @@ -18,6 +18,15 @@ services: - ./api:/var/www:cached - ./docker/php/log.conf:/usr/local/etc/php-fpm.d/zz-log.conf + frontend: + image: node:15.2.1 + working_dir: /app + environment: + - APP_API=http://nginx/api + volumes: + - ./front:/app + command: ["node", "build/server.js"] + blackfire: image: blackfire/blackfire ports: ["8707"] diff --git a/docker/nginx/czydojade b/docker/nginx/cojedzie.conf similarity index 83% rename from docker/nginx/czydojade rename to docker/nginx/cojedzie.conf index 54294a0..83bad87 100644 --- a/docker/nginx/czydojade +++ b/docker/nginx/cojedzie.conf @@ -2,8 +2,6 @@ server { root /var/www/front/public/; server_name cojedzie.localhost; - index dist/index.html; - location /api/ { root /var/www/api/public/; try_files $uri $uri/ index.php$is_args$args; @@ -15,7 +13,12 @@ server { } location / { - try_files $uri $uri/ /dist/index.html =404; + try_files $uri $uri/ @frontend; + } + + location @frontend { + proxy_pass http://frontend:3000; + proxy_intercept_errors on; } location ~ (.+).php(/|$) { @@ -30,7 +33,6 @@ server { fastcgi_param APP_ENV "dev"; fastcgi_param DATABASE_URL "sqlite:///%kernel.project_dir%/var/app.db"; - fastcgi_param GTM_TAG "GTM-00000"; internal; } diff --git a/front/resources/manifest.json b/front/resources/manifest.json index 00dd533..7e6fb1e 100644 --- a/front/resources/manifest.json +++ b/front/resources/manifest.json @@ -2,7 +2,7 @@ "name": "Co Jedzie?", "short_name": "Co Jedzie?", "orientation": "portrait", - "lang": "pl_PL", + "lang": "pl-PL", "start_url": "/", "display": "standalone", "background_color": "white", -- 2.45.2 From c4f5ae0d65098d03b703e8b3d4ecc12026713743 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Mon, 23 Nov 2020 00:13:50 +0100 Subject: [PATCH 57/77] #50 - make JSON default format for API --- api/config/packages/dev/web_profiler.yaml | 2 +- api/config/packages/routing.yaml | 1 + api/config/routes/dev/framework.yaml | 3 + api/config/routes/dev/twig.yaml | 3 - api/config/services.yaml | 7 -- api/public/index.php | 2 +- api/src/Asset/ModifiedTimeVersionStrategy.php | 32 --------- .../Controller/Api/v1/ProviderController.php | 11 ++- api/src/Controller/MainController.php | 48 ------------- api/src/Service/VersionExtension.php | 18 ----- api/src/Subscriber/JSONFormatSubscriber.php | 28 ++++++++ api/templates/app.html.twig | 19 ------ api/templates/base.html.twig | 68 ------------------- api/templates/choose.html.twig | 5 -- api/templates/manifest.json.twig | 39 ----------- 15 files changed, 42 insertions(+), 244 deletions(-) create mode 100644 api/config/routes/dev/framework.yaml delete mode 100644 api/config/routes/dev/twig.yaml delete mode 100644 api/src/Asset/ModifiedTimeVersionStrategy.php delete mode 100644 api/src/Controller/MainController.php delete mode 100644 api/src/Service/VersionExtension.php create mode 100644 api/src/Subscriber/JSONFormatSubscriber.php delete mode 100644 api/templates/app.html.twig delete mode 100644 api/templates/base.html.twig delete mode 100644 api/templates/choose.html.twig delete mode 100644 api/templates/manifest.json.twig diff --git a/api/config/packages/dev/web_profiler.yaml b/api/config/packages/dev/web_profiler.yaml index e92166a..7bb98b9 100644 --- a/api/config/packages/dev/web_profiler.yaml +++ b/api/config/packages/dev/web_profiler.yaml @@ -1,5 +1,5 @@ web_profiler: - toolbar: true + toolbar: false intercept_redirects: false framework: diff --git a/api/config/packages/routing.yaml b/api/config/packages/routing.yaml index 368bc7f..80f4810 100644 --- a/api/config/packages/routing.yaml +++ b/api/config/packages/routing.yaml @@ -1,3 +1,4 @@ framework: router: strict_requirements: ~ + diff --git a/api/config/routes/dev/framework.yaml b/api/config/routes/dev/framework.yaml new file mode 100644 index 0000000..bcbbf13 --- /dev/null +++ b/api/config/routes/dev/framework.yaml @@ -0,0 +1,3 @@ +_errors: + resource: '@FrameworkBundle/Resources/config/routing/errors.xml' + prefix: /_error diff --git a/api/config/routes/dev/twig.yaml b/api/config/routes/dev/twig.yaml deleted file mode 100644 index f4ee839..0000000 --- a/api/config/routes/dev/twig.yaml +++ /dev/null @@ -1,3 +0,0 @@ -_errors: - resource: '@TwigBundle/Resources/config/routing/errors.xml' - prefix: /_error diff --git a/api/config/services.yaml b/api/config/services.yaml index 774f1d7..7b8e853 100644 --- a/api/config/services.yaml +++ b/api/config/services.yaml @@ -42,13 +42,6 @@ services: resource: '../src/Handler' tags: [ app.handler ] - # add more service definitions when explicit configuration is needed - # please note that last definitions always *replace* previous ones - - #assets - assets.modified_time_version_strategy: - class: App\Asset\ModifiedTimeVersionStrategy - #eerialziser jms_serializer.serialized_name_annotation_strategy: class: JMS\Serializer\Naming\SerializedNameAnnotationStrategy diff --git a/api/public/index.php b/api/public/index.php index 732f5b8..980d765 100644 --- a/api/public/index.php +++ b/api/public/index.php @@ -1,8 +1,8 @@ <?php use App\Kernel; -use Symfony\Component\Debug\Debug; use Symfony\Component\Dotenv\Dotenv; +use Symfony\Component\ErrorHandler\Debug; use Symfony\Component\HttpFoundation\Request; require __DIR__.'/../vendor/autoload.php'; diff --git a/api/src/Asset/ModifiedTimeVersionStrategy.php b/api/src/Asset/ModifiedTimeVersionStrategy.php deleted file mode 100644 index c7446d0..0000000 --- a/api/src/Asset/ModifiedTimeVersionStrategy.php +++ /dev/null @@ -1,32 +0,0 @@ -<?php - -namespace App\Asset; - -use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface; - -class ModifiedTimeVersionStrategy implements VersionStrategyInterface -{ - /** - * Returns the asset version for an asset. - * - * @param string $path A path - * - * @return string The version string - */ - public function getVersion($path) - { - return filemtime($path); - } - - /** - * Applies version to the supplied path. - * - * @param string $path A path - * - * @return string The versionized path - */ - public function applyVersion($path) - { - return sprintf('%s?v=%s', $path, $this->getVersion($path)); - } -} \ No newline at end of file diff --git a/api/src/Controller/Api/v1/ProviderController.php b/api/src/Controller/Api/v1/ProviderController.php index 8516fe9..ff192a7 100644 --- a/api/src/Controller/Api/v1/ProviderController.php +++ b/api/src/Controller/Api/v1/ProviderController.php @@ -3,8 +3,10 @@ namespace App\Controller\Api\v1; use App\Controller\Controller; +use App\Exception\NonExistentServiceException; use App\Service\Converter; use App\Service\ProviderResolver; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use function Kadet\Functional\ref; class ProviderController extends Controller @@ -22,8 +24,11 @@ class ProviderController extends Controller public function one(ProviderResolver $resolver, Converter $converter, $id) { - $provider = $resolver->resolve($id); - - return $this->json($converter->convert($provider)); + try { + $provider = $resolver->resolve($id); + return $this->json($converter->convert($provider)); + } catch (NonExistentServiceException $exception) { + throw new NotFoundHttpException($exception->getMessage()); + } } } diff --git a/api/src/Controller/MainController.php b/api/src/Controller/MainController.php deleted file mode 100644 index bfe8d15..0000000 --- a/api/src/Controller/MainController.php +++ /dev/null @@ -1,48 +0,0 @@ -<?php - -namespace App\Controller; - -use App\Provider\Provider; -use App\Service\ProviderResolver; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\Routing\Annotation\Route; - -class MainController extends Controller -{ - /** - * @Route("/", name="choose") - */ - public function choose(ProviderResolver $resolver) - { - return $this->render('choose.html.twig', ['providers' => $resolver->all()]); - } - - /** - * @Route("/{provider}/manifest.json", name="provider_manifest") - * @Route("/manifest.json", name="main_manifest") - */ - public function manifest(?Provider $provider = null) - { - $response = $this->render('manifest.json.twig', ['provider' => $provider]); - $response->headers->set('Content-Type', 'application/json'); - - return $response; - } - - /** - * @Route("/{provider}", name="app") - */ - public function app(Provider $provider, Request $request) - { - $state = json_decode($request->query->get('state', '{}'), true) ?: []; - $state = array_merge( - [ - 'version' => 1, - 'stops' => [], - ], - $state - ); - - return $this->render('app.html.twig', compact('state', 'provider')); - } -} diff --git a/api/src/Service/VersionExtension.php b/api/src/Service/VersionExtension.php deleted file mode 100644 index 45ae2c1..0000000 --- a/api/src/Service/VersionExtension.php +++ /dev/null @@ -1,18 +0,0 @@ -<?php - -namespace App\Service; - -use Twig\Extension\AbstractExtension; -use Twig\TwigFunction; - -class VersionExtension extends AbstractExtension -{ - public function getFunctions() - { - return [ - new TwigFunction('version', function () { - return substr(`git rev-parse HEAD`, 0, 8) ?: '0.2'; - }) - ]; - } -} diff --git a/api/src/Subscriber/JSONFormatSubscriber.php b/api/src/Subscriber/JSONFormatSubscriber.php new file mode 100644 index 0000000..373a373 --- /dev/null +++ b/api/src/Subscriber/JSONFormatSubscriber.php @@ -0,0 +1,28 @@ +<?php + + +namespace App\Subscriber; + + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\Event\RequestEvent; +use Symfony\Component\HttpKernel\KernelEvents; + +class JSONFormatSubscriber implements EventSubscriberInterface +{ + public static function getSubscribedEvents() + { + return [ + KernelEvents::REQUEST => "onRequest", + ]; + } + + public function onRequest(RequestEvent $event) + { + $request = $event->getRequest(); + + if (!$request->attributes->has('_format')) { + $request->attributes->set('_format', 'json'); + } + } +} diff --git a/api/templates/app.html.twig b/api/templates/app.html.twig deleted file mode 100644 index fc3d4d8..0000000 --- a/api/templates/app.html.twig +++ /dev/null @@ -1,19 +0,0 @@ -{% extends 'base.html.twig' %} -{% block title "#{parent()} - #{provider.name}" %} -{% block manifest path('provider_manifest', { provider: provider.identifier }) %} - -{% block body %} - <main id="app" class="container not-ready"> - </main> -{% endblock %} - -{% block javascripts %} - <script> - window.data = { - provider: {{ provider.identifier|json_encode|raw }} - }; - - window.app = {}; - window.app.state = {{ state|json_encode|raw }}; - </script> -{% endblock %} diff --git a/api/templates/base.html.twig b/api/templates/base.html.twig deleted file mode 100644 index e123df6..0000000 --- a/api/templates/base.html.twig +++ /dev/null @@ -1,68 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <meta charset="UTF-8"/> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - <link rel="stylesheet" href="dist/main.css" /> - <link rel="manifest" href="{% block manifest 'manifest.json' %}" /> - - <!-- icons --> - <link rel="icon" href="images/favicon.png" sizes="16x16" /> - <link rel="icon" href="images/favicon-2x.png" sizes="32x32" /> - <link rel="icon" href="images/favicon.ico" /> - - <!-- Apple shit --> - <link rel="apple-touch-icon" href="images/ios.png" sizes="512x512"> - <link rel="apple-touch-icon" href="images/ios-80.png" sizes="80x80"> - <link rel="apple-touch-icon" href="images/ios-192.png" sizes="192x192"> - - <meta name="apple-mobile-web-app-title" content="Co Jedzie?"> - <meta name="apple-mobile-web-app-capable" content="yes"> - - <meta name="theme-color" content="white"/> - - <title>{% block title %}Co Jedzie?{% endblock %}</title> - - {% if gtm_tracking %} - <!-- Google Tag Manager --> - <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': - new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], - j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= - 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); - })(window,document,'script','dataLayer','{{ gtm_tracking }}');</script> - <!-- End Google Tag Manager --> - {% endif %} - </head> - <body> - <noscript> - {% if gtm_tracking %} - <!-- Google Tag Manager (noscript) --> - <iframe src="https://www.googletagmanager.com/ns.html?id={{ gtm_tracking }}" - height="0" width="0" style="display:none;visibility:hidden"></iframe> - <!-- End Google Tag Manager (noscript) --> - {% endif %} - <div class="container"> - <div class="alert alert-danger"> - Aplikacja wymaga do działania obsługi JavaScriptu. - </div> - </div> - </noscript> - {% block body '' %} - <footer class="container"> - {% block footer %} - <span> - <img src="images/logo.png" alt="co jedzie logo"/> - v. {{ version() }} • - <a href="{{ url('app.swagger_ui') }}">API</a> - </span> - <span class="copyright flex flex-space-left justify-content-end"> - <a href="https://kadet.net"><img src="images/kadet-net-logo.png" alt="kadet.net logo" class="mx-1"/></a> - © {{ 'now'|date('Y') }} - </span> - {% endblock %} - </footer> - - {% block javascripts %}{% endblock %} - <script src="dist/main.js"></script> - </body> -</html> diff --git a/api/templates/choose.html.twig b/api/templates/choose.html.twig deleted file mode 100644 index 086ade5..0000000 --- a/api/templates/choose.html.twig +++ /dev/null @@ -1,5 +0,0 @@ -{% extends 'base.html.twig' %} - -{% block body %} - <main class="d-flex" id="provider-picker"></main> -{% endblock %} diff --git a/api/templates/manifest.json.twig b/api/templates/manifest.json.twig deleted file mode 100644 index b27f4ed..0000000 --- a/api/templates/manifest.json.twig +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "Co Jedzie?{% if provider %} - {{ provider.shortName }}{% endif %}", - "short_name": "Co Jedzie?{% if provider %} - {{ provider.shortName }}{% endif %}", - "orientation": "portrait", - "lang": "pl-PL", - "start_url": "{{ provider ? path('app', { provider: provider.identifier }) : path('choose') }}", - "display": "standalone", - "background_color": "white", - "theme_color": "white", - "description": "Odpowiedź na odwieczne pytanie ludzkości - czy tramwaje jeżdżą?", - "categories": ["navigation", "transport", "travel", "utilities"], - "icons": [{ - "src": "{{ asset('images/icon-256.png') }}", - "sizes": "256x256" - },{ - "src": "{{ asset('images/icon-512.png') }}", - "sizes": "512x512" - },{ - "src": "{{ asset('images/icon-64.png') }}", - "sizes": "64x64" - },{ - "src": "{{ asset('images/icon-128.png') }}", - "sizes": "128x128" - },{ - "src": "{{ asset('images/icon-192.png') }}", - "sizes": "192x192" - },{ - "src": "{{ asset('images/icon-96.png') }}", - "sizes": "96x96" - },{ - "src": "{{ asset('images/icon-maskable.png') }}", - "sizes": "512x512", - "purpose": "any maskable" - },{ - "src": "{{ asset('images/icon-monochrome.png') }}", - "sizes": "512x512", - "purpose": "monochrome" - }] -} -- 2.45.2 From a8277face6a21e757ed3534bdc36fd4ea227d39a Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sat, 28 Nov 2020 16:01:46 +0100 Subject: [PATCH 58/77] #50 - update dependencies --- api/.gitignore | 6 - api/composer.json | 14 +- api/composer.lock | 4374 +++++++++++++++++++++++----------------- api/config/bundles.php | 1 - api/symfony.lock | 12 - 5 files changed, 2547 insertions(+), 1860 deletions(-) diff --git a/api/.gitignore b/api/.gitignore index 5e19b63..cb7bf0d 100644 --- a/api/.gitignore +++ b/api/.gitignore @@ -1,15 +1,9 @@ - ###> symfony/framework-bundle ### /.env /public/bundles/ /var/ /vendor/ ###< symfony/framework-bundle ### - -###> symfony/web-server-bundle ### -/.web-server-pid -###< symfony/web-server-bundle ### - /node_modules/ /public/* !/public/index.php diff --git a/api/composer.json b/api/composer.json index 87d236f..4b433b5 100644 --- a/api/composer.json +++ b/api/composer.json @@ -23,12 +23,10 @@ "symfony/profiler-pack": "^1.0", "symfony/twig-bundle": "^4.4", "symfony/yaml": "^4.4", - "tightenco/collect": "^5.6" - }, - "require-dev": { - "symfony/dotenv": "^4.4", - "symfony/web-server-bundle": "^4.4", - "kadet/functional": "dev-master" + "tightenco/collect": "^5.6", + "kadet/functional": "dev-master", + "spiral/roadrunner": "^1.8", + "symfony/dotenv": "^4.4" }, "config": { "preferred-install": { @@ -44,7 +42,9 @@ "psr-4": { "App\\": "src/" }, - "files": ["./src/Functions/index.php"] + "files": [ + "./src/Functions/index.php" + ] }, "autoload-dev": { "psr-4": { diff --git a/api/composer.lock b/api/composer.lock index b88b749..def9adb 100644 --- a/api/composer.lock +++ b/api/composer.lock @@ -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": "8efb4e4271b8598760e37b9b33d9a14f", + "content-hash": "3a72c43fdf868b0a9b09154437791b3d", "packages": [ { "name": "cerbero/json-objects", @@ -62,34 +62,114 @@ "parser", "stream" ], + "support": { + "issues": "https://github.com/cerbero90/json-objects/issues", + "source": "https://github.com/cerbero90/json-objects/tree/v1.1.2" + }, "time": "2019-04-26T13:04:36+00:00" }, { - "name": "doctrine/annotations", - "version": "v1.8.0", + "name": "composer/package-versions-deprecated", + "version": "1.11.99.1", "source": { "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc" + "url": "https://github.com/composer/package-versions-deprecated.git", + "reference": "7413f0b55a051e89485c5cb9f765fe24bb02a7b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/904dca4eb10715b92569fbcd79e201d5c349b6bc", - "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc", + "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/7413f0b55a051e89485c5cb9f765fe24bb02a7b6", + "reference": "7413f0b55a051e89485c5cb9f765fe24bb02a7b6", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.1.0 || ^2.0", + "php": "^7 || ^8" + }, + "replace": { + "ocramius/package-versions": "1.11.99" + }, + "require-dev": { + "composer/composer": "^1.9.3 || ^2.0@dev", + "ext-zip": "^1.13", + "phpunit/phpunit": "^6.5 || ^7" + }, + "type": "composer-plugin", + "extra": { + "class": "PackageVersions\\Installer", + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "PackageVersions\\": "src/PackageVersions" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", + "support": { + "issues": "https://github.com/composer/package-versions-deprecated/issues", + "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.1" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2020-11-11T10:22:58+00:00" + }, + { + "name": "doctrine/annotations", + "version": "1.11.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/ce77a7ba1770462cd705a91a151b6c3746f9c6ad", + "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad", "shasum": "" }, "require": { "doctrine/lexer": "1.*", - "php": "^7.1" + "ext-tokenizer": "*", + "php": "^7.1 || ^8.0" }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "^7.5" + "doctrine/coding-standard": "^6.0 || ^8.1", + "phpstan/phpstan": "^0.12.20", + "phpunit/phpunit": "^7.5 || ^9.1.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7.x-dev" + "dev-master": "1.11.x-dev" } }, "autoload": { @@ -124,30 +204,34 @@ } ], "description": "Docblock Annotations Parser", - "homepage": "http://www.doctrine-project.org", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", "keywords": [ "annotations", "docblock", "parser" ], - "time": "2019-10-01T18:55:10+00:00" + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/1.11.1" + }, + "time": "2020-10-26T10:28:16+00:00" }, { "name": "doctrine/cache", - "version": "1.10.0", + "version": "1.10.2", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "382e7f4db9a12dc6c19431743a2b096041bcdd62" + "reference": "13e3381b25847283a91948d04640543941309727" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/382e7f4db9a12dc6c19431743a2b096041bcdd62", - "reference": "382e7f4db9a12dc6c19431743a2b096041bcdd62", + "url": "https://api.github.com/repos/doctrine/cache/zipball/13e3381b25847283a91948d04640543941309727", + "reference": "13e3381b25847283a91948d04640543941309727", "shasum": "" }, "require": { - "php": "~7.1" + "php": "~7.1 || ^8.0" }, "conflict": { "doctrine/common": ">2.2,<2.4" @@ -212,37 +296,50 @@ "redis", "xcache" ], - "time": "2019-11-29T15:36:20+00:00" + "support": { + "issues": "https://github.com/doctrine/cache/issues", + "source": "https://github.com/doctrine/cache/tree/1.10.x" + }, + "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%2Fcache", + "type": "tidelift" + } + ], + "time": "2020-07-07T18:54:01+00:00" }, { "name": "doctrine/collections", - "version": "1.6.4", + "version": "1.6.7", "source": { "type": "git", "url": "https://github.com/doctrine/collections.git", - "reference": "6b1e4b2b66f6d6e49983cebfe23a21b7ccc5b0d7" + "reference": "55f8b799269a1a472457bd1a41b4f379d4cfba4a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/6b1e4b2b66f6d6e49983cebfe23a21b7ccc5b0d7", - "reference": "6b1e4b2b66f6d6e49983cebfe23a21b7ccc5b0d7", + "url": "https://api.github.com/repos/doctrine/collections/zipball/55f8b799269a1a472457bd1a41b4f379d4cfba4a", + "reference": "55f8b799269a1a472457bd1a41b4f379d4cfba4a", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": "^7.1.3 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^6.0", "phpstan/phpstan-shim": "^0.9.2", "phpunit/phpunit": "^7.0", - "vimeo/psalm": "^3.2.2" + "vimeo/psalm": "^3.8.1" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.6.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Common\\Collections\\": "lib/Doctrine/Common/Collections" @@ -282,20 +379,24 @@ "iterators", "php" ], - "time": "2019-11-13T13:07:11+00:00" + "support": { + "issues": "https://github.com/doctrine/collections/issues", + "source": "https://github.com/doctrine/collections/tree/1.6.7" + }, + "time": "2020-07-27T17:53:49+00:00" }, { "name": "doctrine/common", - "version": "2.12.0", + "version": "2.13.3", "source": { "type": "git", "url": "https://github.com/doctrine/common.git", - "reference": "2053eafdf60c2172ee1373d1b9289ba1db7f1fc6" + "reference": "f3812c026e557892c34ef37f6ab808a6b567da7f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/common/zipball/2053eafdf60c2172ee1373d1b9289ba1db7f1fc6", - "reference": "2053eafdf60c2172ee1373d1b9289ba1db7f1fc6", + "url": "https://api.github.com/repos/doctrine/common/zipball/f3812c026e557892c34ef37f6ab808a6b567da7f", + "reference": "f3812c026e557892c34ef37f6ab808a6b567da7f", "shasum": "" }, "require": { @@ -305,9 +406,9 @@ "doctrine/event-manager": "^1.0", "doctrine/inflector": "^1.0", "doctrine/lexer": "^1.0", - "doctrine/persistence": "^1.1", + "doctrine/persistence": "^1.3.3", "doctrine/reflection": "^1.0", - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^1.0", @@ -365,34 +466,54 @@ "doctrine", "php" ], - "time": "2020-01-10T15:49:25+00:00" + "support": { + "issues": "https://github.com/doctrine/common/issues", + "source": "https://github.com/doctrine/common/tree/2.13.x" + }, + "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%2Fcommon", + "type": "tidelift" + } + ], + "time": "2020-06-05T16:46:05+00:00" }, { "name": "doctrine/dbal", - "version": "v2.10.1", + "version": "2.12.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "c2b8e6e82732a64ecde1cddf9e1e06cb8556e3d8" + "reference": "adce7a954a1c2f14f85e94aed90c8489af204086" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/c2b8e6e82732a64ecde1cddf9e1e06cb8556e3d8", - "reference": "c2b8e6e82732a64ecde1cddf9e1e06cb8556e3d8", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/adce7a954a1c2f14f85e94aed90c8489af204086", + "reference": "adce7a954a1c2f14f85e94aed90c8489af204086", "shasum": "" }, "require": { "doctrine/cache": "^1.0", "doctrine/event-manager": "^1.0", "ext-pdo": "*", - "php": "^7.2" + "php": "^7.3 || ^8" }, "require-dev": { - "doctrine/coding-standard": "^6.0", + "doctrine/coding-standard": "^8.1", "jetbrains/phpstorm-stubs": "^2019.1", - "phpstan/phpstan": "^0.11.3", - "phpunit/phpunit": "^8.4.1", - "symfony/console": "^2.0.5|^3.0|^4.0|^5.0" + "phpstan/phpstan": "^0.12.40", + "phpunit/phpunit": "^9.4", + "psalm/plugin-phpunit": "^0.10.0", + "symfony/console": "^2.0.5|^3.0|^4.0|^5.0", + "vimeo/psalm": "^3.17.2" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -403,8 +524,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.10.x-dev", - "dev-develop": "3.0.x-dev" + "dev-master": "4.0.x-dev" } }, "autoload": { @@ -457,27 +577,45 @@ "sqlserver", "sqlsrv" ], - "time": "2020-01-04T12:56:21+00:00" + "support": { + "issues": "https://github.com/doctrine/dbal/issues", + "source": "https://github.com/doctrine/dbal/tree/2.12.1" + }, + "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%2Fdbal", + "type": "tidelift" + } + ], + "time": "2020-11-14T20:26:58+00:00" }, { "name": "doctrine/doctrine-bundle", - "version": "2.0.6", + "version": "2.2.1", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineBundle.git", - "reference": "0ef972d3b730f975c80db9fffa4b2a0258c91442" + "reference": "9e07bb1ff35d35d9ec4597b79e5d05502d7d4d43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/0ef972d3b730f975c80db9fffa4b2a0258c91442", - "reference": "0ef972d3b730f975c80db9fffa4b2a0258c91442", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/9e07bb1ff35d35d9ec4597b79e5d05502d7d4d43", + "reference": "9e07bb1ff35d35d9ec4597b79e5d05502d7d4d43", "shasum": "" }, "require": { - "doctrine/dbal": "^2.9.0", - "doctrine/persistence": "^1.3.3", - "jdorn/sql-formatter": "^1.2.16", - "php": "^7.1", + "doctrine/dbal": "^2.9.0|^3.0", + "doctrine/persistence": "^1.3.3|^2.0", + "doctrine/sql-formatter": "^1.0.1", + "php": "^7.1 || ^8.0", "symfony/cache": "^4.3.3|^5.0", "symfony/config": "^4.3.3|^5.0", "symfony/console": "^3.4.30|^4.3.3|^5.0", @@ -491,17 +629,18 @@ "twig/twig": "<1.34|>=2.0,<2.4" }, "require-dev": { - "doctrine/coding-standard": "^6.0", + "doctrine/coding-standard": "^8.0", "doctrine/orm": "^2.6", "ocramius/proxy-manager": "^2.1", - "phpunit/phpunit": "^7.5", + "phpunit/phpunit": "^7.5 || ^9.3", "symfony/phpunit-bridge": "^4.2", "symfony/property-info": "^4.3.3|^5.0", + "symfony/proxy-manager-bridge": "^3.4|^4.3.3|^5.0", "symfony/twig-bridge": "^3.4.30|^4.3.3|^5.0", "symfony/validator": "^3.4.30|^4.3.3|^5.0", "symfony/web-profiler-bundle": "^3.4.30|^4.3.3|^5.0", "symfony/yaml": "^3.4.30|^4.3.3|^5.0", - "twig/twig": "^1.34|^2.12" + "twig/twig": "^1.34|^2.12|^3.0" }, "suggest": { "doctrine/orm": "The Doctrine ORM integration is optional in the bundle.", @@ -510,7 +649,7 @@ "type": "symfony-bundle", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "2.3.x-dev" } }, "autoload": { @@ -548,7 +687,25 @@ "orm", "persistence" ], - "time": "2019-12-19T13:47:07+00:00" + "support": { + "issues": "https://github.com/doctrine/DoctrineBundle/issues", + "source": "https://github.com/doctrine/DoctrineBundle/tree/2.2.1" + }, + "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%2Fdoctrine-bundle", + "type": "tidelift" + } + ], + "time": "2020-11-10T20:42:15+00:00" }, { "name": "doctrine/doctrine-cache-bundle", @@ -639,20 +796,24 @@ "cache", "caching" ], + "support": { + "issues": "https://github.com/doctrine/DoctrineCacheBundle/issues", + "source": "https://github.com/doctrine/DoctrineCacheBundle/tree/1.4.0" + }, "time": "2019-11-29T11:22:01+00:00" }, { "name": "doctrine/doctrine-migrations-bundle", - "version": "2.1.2", + "version": "2.2.1", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineMigrationsBundle.git", - "reference": "856437e8de96a70233e1f0cc2352fc8dd15a899d" + "reference": "955077b68c377310cf9538fc982be11d36ab75d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/856437e8de96a70233e1f0cc2352fc8dd15a899d", - "reference": "856437e8de96a70233e1f0cc2352fc8dd15a899d", + "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/955077b68c377310cf9538fc982be11d36ab75d4", + "reference": "955077b68c377310cf9538fc982be11d36ab75d4", "shasum": "" }, "require": { @@ -707,24 +868,42 @@ "migrations", "schema" ], - "time": "2019-11-13T12:57:41+00:00" + "support": { + "issues": "https://github.com/doctrine/DoctrineMigrationsBundle/issues", + "source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/2.2.1" + }, + "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%2Fdoctrine-migrations-bundle", + "type": "tidelift" + } + ], + "time": "2020-11-11T09:59:06+00:00" }, { "name": "doctrine/event-manager", - "version": "1.1.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/event-manager.git", - "reference": "629572819973f13486371cb611386eb17851e85c" + "reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/629572819973f13486371cb611386eb17851e85c", - "reference": "629572819973f13486371cb611386eb17851e85c", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/41370af6a30faa9dc0368c4a6814d596e81aba7f", + "reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "conflict": { "doctrine/common": "<2.9@dev" @@ -783,37 +962,60 @@ "event system", "events" ], - "time": "2019-11-10T09:48:07+00:00" + "support": { + "issues": "https://github.com/doctrine/event-manager/issues", + "source": "https://github.com/doctrine/event-manager/tree/1.1.x" + }, + "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%2Fevent-manager", + "type": "tidelift" + } + ], + "time": "2020-05-29T18:28:51+00:00" }, { "name": "doctrine/inflector", - "version": "1.3.1", + "version": "1.4.3", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "ec3a55242203ffa6a4b27c58176da97ff0a7aec1" + "reference": "4650c8b30c753a76bf44fb2ed00117d6f367490c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/ec3a55242203ffa6a4b27c58176da97ff0a7aec1", - "reference": "ec3a55242203ffa6a4b27c58176da97ff0a7aec1", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/4650c8b30c753a76bf44fb2ed00117d6f367490c", + "reference": "4650c8b30c753a76bf44fb2ed00117d6f367490c", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.2 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^6.2" + "doctrine/coding-standard": "^7.0", + "phpstan/phpstan": "^0.11", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-strict-rules": "^0.11", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { "psr-4": { - "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector" + "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector", + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" } }, "notification-url": "https://packagist.org/downloads/", @@ -842,48 +1044,67 @@ "email": "schmittjoh@gmail.com" } ], - "description": "Common String Manipulations with regard to casing and singular/plural rules.", - "homepage": "http://www.doctrine-project.org", + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", "keywords": [ "inflection", - "pluralize", - "singularize", - "string" + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" ], - "time": "2019-10-30T19:59:35+00:00" + "support": { + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/1.4.x" + }, + "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-29T07:19:59+00:00" }, { "name": "doctrine/instantiator", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" + "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", - "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", + "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^6.0", + "doctrine/coding-standard": "^8.0", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.13", - "phpstan/phpstan-phpunit": "^0.11", - "phpstan/phpstan-shim": "^0.11", - "phpunit/phpunit": "^7.0" + "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" @@ -897,7 +1118,7 @@ { "name": "Marco Pivetta", "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" + "homepage": "https://ocramius.github.io/" } ], "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", @@ -906,24 +1127,42 @@ "constructor", "instantiate" ], - "time": "2019-10-21T16:45:58+00:00" + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.4.0" + }, + "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%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2020-11-10T18:47:58+00:00" }, { "name": "doctrine/lexer", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6" + "reference": "e864bbf5904cb8f5bb334f99209b48018522f042" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", - "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042", + "reference": "e864bbf5904cb8f5bb334f99209b48018522f042", "shasum": "" }, "require": { - "php": "^7.2" + "php": "^7.2 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^6.0", @@ -968,25 +1207,43 @@ "parser", "php" ], - "time": "2019-10-30T14:39:59+00:00" + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/1.2.1" + }, + "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" }, { "name": "doctrine/migrations", - "version": "2.2.1", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/doctrine/migrations.git", - "reference": "a3987131febeb0e9acb3c47ab0df0af004588934" + "reference": "100e85a8509b521f010901890f042e9401a3043b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/migrations/zipball/a3987131febeb0e9acb3c47ab0df0af004588934", - "reference": "a3987131febeb0e9acb3c47ab0df0af004588934", + "url": "https://api.github.com/repos/doctrine/migrations/zipball/100e85a8509b521f010901890f042e9401a3043b", + "reference": "100e85a8509b521f010901890f042e9401a3043b", "shasum": "" }, "require": { + "composer/package-versions-deprecated": "^1.8", "doctrine/dbal": "^2.9", - "ocramius/package-versions": "^1.3", "ocramius/proxy-manager": "^2.0.2", "php": "^7.1", "symfony/console": "^3.4||^4.0||^5.0", @@ -1050,39 +1307,62 @@ "migrations", "php" ], - "time": "2019-12-04T06:09:14+00:00" + "support": { + "issues": "https://github.com/doctrine/migrations/issues", + "source": "https://github.com/doctrine/migrations/tree/2.3.0" + }, + "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%2Fmigrations", + "type": "tidelift" + } + ], + "time": "2020-07-04T16:28:35+00:00" }, { "name": "doctrine/orm", - "version": "v2.7.0", + "version": "2.7.4", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "4d763ca4c925f647b248b9fa01b5f47aa3685d62" + "reference": "7d84a4998091ece4d645253ac65de9f879eeed2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/4d763ca4c925f647b248b9fa01b5f47aa3685d62", - "reference": "4d763ca4c925f647b248b9fa01b5f47aa3685d62", + "url": "https://api.github.com/repos/doctrine/orm/zipball/7d84a4998091ece4d645253ac65de9f879eeed2f", + "reference": "7d84a4998091ece4d645253ac65de9f879eeed2f", "shasum": "" }, "require": { + "composer/package-versions-deprecated": "^1.8", "doctrine/annotations": "^1.8", "doctrine/cache": "^1.9.1", "doctrine/collections": "^1.5", - "doctrine/common": "^2.11", + "doctrine/common": "^2.11 || ^3.0", "doctrine/dbal": "^2.9.3", "doctrine/event-manager": "^1.1", + "doctrine/inflector": "^1.0", "doctrine/instantiator": "^1.3", - "doctrine/persistence": "^1.2", + "doctrine/lexer": "^1.0", + "doctrine/persistence": "^1.3.3 || ^2.0", "ext-pdo": "*", "php": "^7.1", "symfony/console": "^3.0|^4.0|^5.0" }, "require-dev": { "doctrine/coding-standard": "^5.0", + "phpstan/phpstan": "^0.12.18", "phpunit/phpunit": "^7.5", - "symfony/yaml": "^3.4|^4.0|^5.0" + "symfony/yaml": "^3.4|^4.0|^5.0", + "vimeo/psalm": "^3.11" }, "suggest": { "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" @@ -1133,20 +1413,24 @@ "database", "orm" ], - "time": "2019-11-19T08:38:05+00:00" + "support": { + "issues": "https://github.com/doctrine/orm/issues", + "source": "https://github.com/doctrine/orm/tree/2.7.4" + }, + "time": "2020-10-10T17:11:26+00:00" }, { "name": "doctrine/persistence", - "version": "1.3.4", + "version": "1.3.8", "source": { "type": "git", "url": "https://github.com/doctrine/persistence.git", - "reference": "ff7e08b0f814be2cd20c52dc3c8a262579376b94" + "reference": "7a6eac9fb6f61bba91328f15aa7547f4806ca288" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/persistence/zipball/ff7e08b0f814be2cd20c52dc3c8a262579376b94", - "reference": "ff7e08b0f814be2cd20c52dc3c8a262579376b94", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/7a6eac9fb6f61bba91328f15aa7547f4806ca288", + "reference": "7a6eac9fb6f61bba91328f15aa7547f4806ca288", "shasum": "" }, "require": { @@ -1154,8 +1438,8 @@ "doctrine/cache": "^1.0", "doctrine/collections": "^1.0", "doctrine/event-manager": "^1.0", - "doctrine/reflection": "^1.0", - "php": "^7.1" + "doctrine/reflection": "^1.2", + "php": "^7.1 || ^8.0" }, "conflict": { "doctrine/common": "<2.10@dev" @@ -1163,7 +1447,8 @@ "require-dev": { "doctrine/coding-standard": "^6.0", "phpstan/phpstan": "^0.11", - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "vimeo/psalm": "^3.11" }, "type": "library", "extra": { @@ -1216,41 +1501,59 @@ "orm", "persistence" ], - "time": "2020-01-09T19:49:17+00:00" + "support": { + "issues": "https://github.com/doctrine/persistence/issues", + "source": "https://github.com/doctrine/persistence/tree/1.3.x" + }, + "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%2Fpersistence", + "type": "tidelift" + } + ], + "time": "2020-06-20T12:56:16+00:00" }, { "name": "doctrine/reflection", - "version": "v1.1.0", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/doctrine/reflection.git", - "reference": "bc420ead87fdfe08c03ecc3549db603a45b06d4c" + "reference": "fa587178be682efe90d005e3a322590d6ebb59a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/reflection/zipball/bc420ead87fdfe08c03ecc3549db603a45b06d4c", - "reference": "bc420ead87fdfe08c03ecc3549db603a45b06d4c", + "url": "https://api.github.com/repos/doctrine/reflection/zipball/fa587178be682efe90d005e3a322590d6ebb59a5", + "reference": "fa587178be682efe90d005e3a322590d6ebb59a5", "shasum": "" }, "require": { "doctrine/annotations": "^1.0", "ext-tokenizer": "*", - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "conflict": { "doctrine/common": "<2.9" }, "require-dev": { - "doctrine/coding-standard": "^5.0", + "doctrine/coding-standard": "^6.0 || ^8.2.0", "doctrine/common": "^2.10", - "phpstan/phpstan": "^0.11.0", - "phpstan/phpstan-phpunit": "^0.11.0", - "phpunit/phpunit": "^7.0" + "phpstan/phpstan": "^0.11.0 || ^0.12.20", + "phpstan/phpstan-phpunit": "^0.11.0 || ^0.12.16", + "phpunit/phpunit": "^7.5 || ^9.1.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -1294,151 +1597,36 @@ "reflection", "static" ], - "time": "2020-01-08T19:53:19+00:00" + "support": { + "issues": "https://github.com/doctrine/reflection/issues", + "source": "https://github.com/doctrine/reflection/tree/1.2.2" + }, + "abandoned": "roave/better-reflection", + "time": "2020-10-27T21:46:55+00:00" }, { - "name": "exsyst/swagger", - "version": "v0.4.1", + "name": "doctrine/sql-formatter", + "version": "1.1.1", "source": { "type": "git", - "url": "https://github.com/GuilhemN/swagger.git", - "reference": "a02984db5edacdce2b4e09dae5ba8fe17a0e449e" + "url": "https://github.com/doctrine/sql-formatter.git", + "reference": "56070bebac6e77230ed7d306ad13528e60732871" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GuilhemN/swagger/zipball/a02984db5edacdce2b4e09dae5ba8fe17a0e449e", - "reference": "a02984db5edacdce2b4e09dae5ba8fe17a0e449e", + "url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/56070bebac6e77230ed7d306ad13528e60732871", + "reference": "56070bebac6e77230ed7d306ad13528e60732871", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^6.5" + "bamarni/composer-bin-plugin": "^1.4" }, - "type": "library", - "autoload": { - "psr-4": { - "EXSyst\\Component\\Swagger\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" + "bin": [ + "bin/sql-formatter" ], - "authors": [ - { - "name": "Ener-Getick", - "email": "egetick@gmail.com" - } - ], - "description": "A php library to manipulate Swagger specifications", - "time": "2018-07-27T06:40:00+00:00" - }, - { - "name": "hoa/compiler", - "version": "3.17.08.08", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Compiler.git", - "reference": "aa09caf0bf28adae6654ca6ee415ee2f522672de" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Compiler/zipball/aa09caf0bf28adae6654ca6ee415ee2f522672de", - "reference": "aa09caf0bf28adae6654ca6ee415ee2f522672de", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0", - "hoa/exception": "~1.0", - "hoa/file": "~1.0", - "hoa/iterator": "~2.0", - "hoa/math": "~1.0", - "hoa/protocol": "~1.0", - "hoa/regex": "~1.0", - "hoa/visitor": "~2.0" - }, - "require-dev": { - "hoa/json": "~2.0", - "hoa/test": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Compiler\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Compiler library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "algebraic", - "ast", - "compiler", - "context-free", - "coverage", - "exhaustive", - "grammar", - "isotropic", - "language", - "lexer", - "library", - "ll1", - "llk", - "parser", - "pp", - "random", - "regular", - "rule", - "sampler", - "syntax", - "token", - "trace", - "uniform" - ], - "time": "2017-08-08T07:44:07+00:00" - }, - { - "name": "hoa/consistency", - "version": "1.17.05.02", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Consistency.git", - "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Consistency/zipball/fd7d0adc82410507f332516faf655b6ed22e4c2f", - "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f", - "shasum": "" - }, - "require": { - "hoa/exception": "~1.0", - "php": ">=5.5.0" - }, - "require-dev": { - "hoa/stream": "~1.0", - "hoa/test": "~2.0" - }, "type": "library", "extra": { "branch-alias": { @@ -1447,707 +1635,8 @@ }, "autoload": { "psr-4": { - "Hoa\\Consistency\\": "." - }, - "files": [ - "Prelude.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" + "Doctrine\\SqlFormatter\\": "src" } - ], - "description": "The Hoa\\Consistency library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "autoloader", - "callable", - "consistency", - "entity", - "flex", - "keyword", - "library" - ], - "time": "2017-05-02T12:18:12+00:00" - }, - { - "name": "hoa/event", - "version": "1.17.01.13", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Event.git", - "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Event/zipball/6c0060dced212ffa3af0e34bb46624f990b29c54", - "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0", - "hoa/exception": "~1.0" - }, - "require-dev": { - "hoa/test": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Event\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Event library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "event", - "library", - "listener", - "observer" - ], - "time": "2017-01-13T15:30:50+00:00" - }, - { - "name": "hoa/exception", - "version": "1.17.01.16", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Exception.git", - "reference": "091727d46420a3d7468ef0595651488bfc3a458f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Exception/zipball/091727d46420a3d7468ef0595651488bfc3a458f", - "reference": "091727d46420a3d7468ef0595651488bfc3a458f", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0", - "hoa/event": "~1.0" - }, - "require-dev": { - "hoa/test": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Exception\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Exception library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "exception", - "library" - ], - "time": "2017-01-16T07:53:27+00:00" - }, - { - "name": "hoa/file", - "version": "1.17.07.11", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/File.git", - "reference": "35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/File/zipball/35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca", - "reference": "35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0", - "hoa/event": "~1.0", - "hoa/exception": "~1.0", - "hoa/iterator": "~2.0", - "hoa/stream": "~1.0" - }, - "require-dev": { - "hoa/test": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\File\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\File library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "Socket", - "directory", - "file", - "finder", - "library", - "link", - "temporary" - ], - "time": "2017-07-11T07:42:15+00:00" - }, - { - "name": "hoa/iterator", - "version": "2.17.01.10", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Iterator.git", - "reference": "d1120ba09cb4ccd049c86d10058ab94af245f0cc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Iterator/zipball/d1120ba09cb4ccd049c86d10058ab94af245f0cc", - "reference": "d1120ba09cb4ccd049c86d10058ab94af245f0cc", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0", - "hoa/exception": "~1.0" - }, - "require-dev": { - "hoa/test": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Iterator\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Iterator library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "iterator", - "library" - ], - "time": "2017-01-10T10:34:47+00:00" - }, - { - "name": "hoa/math", - "version": "1.17.05.16", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Math.git", - "reference": "7150785d30f5d565704912116a462e9f5bc83a0c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Math/zipball/7150785d30f5d565704912116a462e9f5bc83a0c", - "reference": "7150785d30f5d565704912116a462e9f5bc83a0c", - "shasum": "" - }, - "require": { - "hoa/compiler": "~3.0", - "hoa/consistency": "~1.0", - "hoa/exception": "~1.0", - "hoa/iterator": "~2.0", - "hoa/protocol": "~1.0", - "hoa/zformat": "~1.0" - }, - "require-dev": { - "hoa/test": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Math\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Math library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "arrangement", - "combination", - "combinatorics", - "counting", - "library", - "math", - "permutation", - "sampler", - "set" - ], - "time": "2017-05-16T08:02:17+00:00" - }, - { - "name": "hoa/protocol", - "version": "1.17.01.14", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Protocol.git", - "reference": "5c2cf972151c45f373230da170ea015deecf19e2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Protocol/zipball/5c2cf972151c45f373230da170ea015deecf19e2", - "reference": "5c2cf972151c45f373230da170ea015deecf19e2", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0", - "hoa/exception": "~1.0" - }, - "require-dev": { - "hoa/test": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Protocol\\": "." - }, - "files": [ - "Wrapper.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Protocol library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "library", - "protocol", - "resource", - "stream", - "wrapper" - ], - "time": "2017-01-14T12:26:10+00:00" - }, - { - "name": "hoa/regex", - "version": "1.17.01.13", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Regex.git", - "reference": "7e263a61b6fb45c1d03d8e5ef77668518abd5bec" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Regex/zipball/7e263a61b6fb45c1d03d8e5ef77668518abd5bec", - "reference": "7e263a61b6fb45c1d03d8e5ef77668518abd5bec", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0", - "hoa/exception": "~1.0", - "hoa/math": "~1.0", - "hoa/protocol": "~1.0", - "hoa/ustring": "~4.0", - "hoa/visitor": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Regex\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Regex library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "compiler", - "library", - "regex" - ], - "time": "2017-01-13T16:10:24+00:00" - }, - { - "name": "hoa/stream", - "version": "1.17.02.21", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Stream.git", - "reference": "3293cfffca2de10525df51436adf88a559151d82" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Stream/zipball/3293cfffca2de10525df51436adf88a559151d82", - "reference": "3293cfffca2de10525df51436adf88a559151d82", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0", - "hoa/event": "~1.0", - "hoa/exception": "~1.0", - "hoa/protocol": "~1.0" - }, - "require-dev": { - "hoa/test": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Stream\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Stream library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "Context", - "bucket", - "composite", - "filter", - "in", - "library", - "out", - "protocol", - "stream", - "wrapper" - ], - "time": "2017-02-21T16:01:06+00:00" - }, - { - "name": "hoa/ustring", - "version": "4.17.01.16", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Ustring.git", - "reference": "e6326e2739178799b1fe3fdd92029f9517fa17a0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Ustring/zipball/e6326e2739178799b1fe3fdd92029f9517fa17a0", - "reference": "e6326e2739178799b1fe3fdd92029f9517fa17a0", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0", - "hoa/exception": "~1.0" - }, - "require-dev": { - "hoa/test": "~2.0" - }, - "suggest": { - "ext-iconv": "ext/iconv must be present (or a third implementation) to use Hoa\\Ustring::transcode().", - "ext-intl": "To get a better Hoa\\Ustring::toAscii() and Hoa\\Ustring::compareTo()." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Ustring\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Ustring library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "library", - "search", - "string", - "unicode" - ], - "time": "2017-01-16T07:08:25+00:00" - }, - { - "name": "hoa/visitor", - "version": "2.17.01.16", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Visitor.git", - "reference": "c18fe1cbac98ae449e0d56e87469103ba08f224a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Visitor/zipball/c18fe1cbac98ae449e0d56e87469103ba08f224a", - "reference": "c18fe1cbac98ae449e0d56e87469103ba08f224a", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0" - }, - "require-dev": { - "hoa/test": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Visitor\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Visitor library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "library", - "structure", - "visit", - "visitor" - ], - "time": "2017-01-16T07:02:03+00:00" - }, - { - "name": "hoa/zformat", - "version": "1.17.01.10", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Zformat.git", - "reference": "522c381a2a075d4b9dbb42eb4592dd09520e4ac2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Zformat/zipball/522c381a2a075d4b9dbb42eb4592dd09520e4ac2", - "reference": "522c381a2a075d4b9dbb42eb4592dd09520e4ac2", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0", - "hoa/exception": "~1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Zformat\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Zformat library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "library", - "parameter", - "zformat" - ], - "time": "2017-01-10T10:39:54+00:00" - }, - { - "name": "jdorn/sql-formatter", - "version": "v1.2.17", - "source": { - "type": "git", - "url": "https://github.com/jdorn/sql-formatter.git", - "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/jdorn/sql-formatter/zipball/64990d96e0959dff8e059dfcdc1af130728d92bc", - "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc", - "shasum": "" - }, - "require": { - "php": ">=5.2.4" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "lib" - ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2161,25 +1650,72 @@ } ], "description": "a PHP SQL highlighting library", - "homepage": "https://github.com/jdorn/sql-formatter/", + "homepage": "https://github.com/doctrine/sql-formatter/", "keywords": [ "highlight", "sql" ], - "time": "2014-01-12T16:20:24+00:00" + "support": { + "issues": "https://github.com/doctrine/sql-formatter/issues", + "source": "https://github.com/doctrine/sql-formatter/tree/1.1.x" + }, + "time": "2020-07-30T16:57:33+00:00" }, { - "name": "jms/metadata", - "version": "2.1.0", + "name": "exsyst/swagger", + "version": "v0.4.2", "source": { "type": "git", - "url": "https://github.com/schmittjoh/metadata.git", - "reference": "8d8958103485c2cbdd9a9684c3869312ebdaf73a" + "url": "https://github.com/GuilhemN/swagger.git", + "reference": "5d4ad40fe816b7783adc090b64fba6c392be64bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/8d8958103485c2cbdd9a9684c3869312ebdaf73a", - "reference": "8d8958103485c2cbdd9a9684c3869312ebdaf73a", + "url": "https://api.github.com/repos/GuilhemN/swagger/zipball/5d4ad40fe816b7783adc090b64fba6c392be64bc", + "reference": "5d4ad40fe816b7783adc090b64fba6c392be64bc", + "shasum": "" + }, + "require": { + "php": "^7.0|^8.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.1.8|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "EXSyst\\Component\\Swagger\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilhem Niot", + "email": "guilhem@gniot.fr" + } + ], + "description": "A php library to manipulate Swagger specifications", + "support": { + "issues": "https://github.com/GuilhemN/swagger/issues", + "source": "https://github.com/GuilhemN/swagger/tree/v0.4.2" + }, + "time": "2020-11-19T17:14:18+00:00" + }, + { + "name": "jms/metadata", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/metadata.git", + "reference": "6eb35fce7142234946d58d13e1aa829e9b78b095" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/6eb35fce7142234946d58d13e1aa829e9b78b095", + "reference": "6eb35fce7142234946d58d13e1aa829e9b78b095", "shasum": "" }, "require": { @@ -2189,7 +1725,8 @@ "doctrine/cache": "^1.0", "doctrine/coding-standard": "^4.0", "phpunit/phpunit": "^7.0", - "symfony/cache": "^3.1|^4.0" + "symfony/cache": "^3.1|^4.0|^5.0", + "symfony/dependency-injection": "^3.1|^4.0|^5.0" }, "type": "library", "extra": { @@ -2223,42 +1760,42 @@ "xml", "yaml" ], - "time": "2019-09-17T15:30:40+00:00" + "support": { + "issues": "https://github.com/schmittjoh/metadata/issues", + "source": "https://github.com/schmittjoh/metadata/tree/master" + }, + "time": "2020-06-06T16:52:59+00:00" }, { "name": "jms/serializer", - "version": "3.4.0", + "version": "3.10.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/serializer.git", - "reference": "e2d3c49d9322a08ee32221a5623c898160dada79" + "reference": "0ed0b6aa79cc029772286f2dc262f6933674b0ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/e2d3c49d9322a08ee32221a5623c898160dada79", - "reference": "e2d3c49d9322a08ee32221a5623c898160dada79", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/0ed0b6aa79cc029772286f2dc262f6933674b0ec", + "reference": "0ed0b6aa79cc029772286f2dc262f6933674b0ec", "shasum": "" }, "require": { "doctrine/annotations": "^1.0", "doctrine/instantiator": "^1.0.3", - "hoa/compiler": "^3.17.08.08", + "doctrine/lexer": "^1.1", "jms/metadata": "^2.0", "php": "^7.2" }, - "conflict": { - "hoa/consistency": "<1.17.05.02", - "hoa/core": "*", - "hoa/iterator": "<2.16.03.15" - }, "require-dev": { - "doctrine/coding-standard": "^5.0", + "doctrine/coding-standard": "^8.1", "doctrine/orm": "~2.1", + "doctrine/persistence": "^1.3.3|^2.0|^3.0", "doctrine/phpcr-odm": "^1.3|^2.0", "ext-pdo_sqlite": "*", "jackalope/jackalope-doctrine-dbal": "^1.1.5", "ocramius/proxy-manager": "^1.0|^2.0", - "phpunit/phpunit": "^7.5||^8.0", + "phpunit/phpunit": "^8.0||^9.0", "psr/container": "^1.0", "symfony/dependency-injection": "^3.0|^4.0|^5.0", "symfony/expression-language": "^3.0|^4.0|^5.0", @@ -2267,7 +1804,7 @@ "symfony/translation": "^3.0|^4.0|^5.0", "symfony/validator": "^3.1.9|^4.0|^5.0", "symfony/yaml": "^3.3|^4.0|^5.0", - "twig/twig": "~1.34|~2.4" + "twig/twig": "~1.34|~2.4|^3.0" }, "suggest": { "doctrine/cache": "Required if you like to use cache functionality.", @@ -2277,7 +1814,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "3.10-dev" } }, "autoload": { @@ -2308,31 +1845,42 @@ "serialization", "xml" ], - "time": "2019-12-14T20:49:23+00:00" + "support": { + "issues": "https://github.com/schmittjoh/serializer/issues", + "source": "https://github.com/schmittjoh/serializer/tree/3.10.0" + }, + "funding": [ + { + "url": "https://github.com/goetas", + "type": "github" + } + ], + "time": "2020-10-29T20:24:00+00:00" }, { "name": "jms/serializer-bundle", - "version": "3.5.0", + "version": "3.7.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/JMSSerializerBundle.git", - "reference": "5793ec59b2243365a625c0fd78415732097c11e8" + "reference": "0ee8b75bfc484a342aa0471e3c6d9ad96fb430cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/JMSSerializerBundle/zipball/5793ec59b2243365a625c0fd78415732097c11e8", - "reference": "5793ec59b2243365a625c0fd78415732097c11e8", + "url": "https://api.github.com/repos/schmittjoh/JMSSerializerBundle/zipball/0ee8b75bfc484a342aa0471e3c6d9ad96fb430cf", + "reference": "0ee8b75bfc484a342aa0471e3c6d9ad96fb430cf", "shasum": "" }, "require": { - "jms/serializer": "^2.3|^3.0", + "jms/metadata": "^2.3", + "jms/serializer": "^3.0", "php": "^7.2", "symfony/dependency-injection": "^3.3 || ^4.0 || ^5.0", "symfony/framework-bundle": "^3.0 || ^4.0 || ^5.0" }, "require-dev": { "doctrine/orm": "^2.4", - "phpunit/phpunit": "^6.0", + "phpunit/phpunit": "^6.0|^7.0", "symfony/expression-language": "^3.0 || ^4.0 || ^5.0", "symfony/finder": "^3.0 || ^4.0 || ^5.0", "symfony/form": "^3.0 || ^4.0 || ^5.0", @@ -2348,7 +1896,7 @@ "type": "symfony-bundle", "extra": { "branch-alias": { - "dev-master": "3.5-dev" + "dev-master": "3.7-dev" } }, "autoload": { @@ -2381,20 +1929,30 @@ "serialization", "xml" ], - "time": "2019-11-29T13:03:07+00:00" + "support": { + "issues": "https://github.com/schmittjoh/JMSSerializerBundle/issues", + "source": "https://github.com/schmittjoh/JMSSerializerBundle/tree/master" + }, + "funding": [ + { + "url": "https://github.com/goetas", + "type": "github" + } + ], + "time": "2020-06-28T11:26:21+00:00" }, { "name": "kylekatarnls/update-helper", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/kylekatarnls/update-helper.git", - "reference": "5786fa188e0361b9adf9e8199d7280d1b2db165e" + "reference": "429be50660ed8a196e0798e5939760f168ec8ce9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kylekatarnls/update-helper/zipball/5786fa188e0361b9adf9e8199d7280d1b2db165e", - "reference": "5786fa188e0361b9adf9e8199d7280d1b2db165e", + "url": "https://api.github.com/repos/kylekatarnls/update-helper/zipball/429be50660ed8a196e0798e5939760f168ec8ce9", + "reference": "429be50660ed8a196e0798e5939760f168ec8ce9", "shasum": "" }, "require": { @@ -2426,24 +1984,42 @@ } ], "description": "Update helper", - "time": "2019-07-29T11:03:54+00:00" + "support": { + "issues": "https://github.com/kylekatarnls/update-helper/issues", + "source": "https://github.com/kylekatarnls/update-helper/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } + ], + "time": "2020-04-07T20:44:10+00:00" }, { "name": "monolog/monolog", - "version": "2.0.2", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "c861fcba2ca29404dc9e617eedd9eff4616986b8" + "reference": "f9eee5cec93dfb313a38b6b288741e84e53f02d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c861fcba2ca29404dc9e617eedd9eff4616986b8", - "reference": "c861fcba2ca29404dc9e617eedd9eff4616986b8", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f9eee5cec93dfb313a38b6b288741e84e53f02d5", + "reference": "f9eee5cec93dfb313a38b6b288741e84e53f02d5", "shasum": "" }, "require": { - "php": "^7.2", + "php": ">=7.2", "psr/log": "^1.0.1" }, "provide": { @@ -2454,11 +2030,11 @@ "doctrine/couchdb": "~1.0@dev", "elasticsearch/elasticsearch": "^6.0", "graylog2/gelf-php": "^1.4.2", - "jakub-onderka/php-parallel-lint": "^0.9", "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", + "php-parallel-lint/php-parallel-lint": "^1.0", "phpspec/prophecy": "^1.6.1", - "phpunit/phpunit": "^8.3", + "phpunit/phpunit": "^8.5", "predis/predis": "^1.1", "rollbar/rollbar": "^1.3", "ruflin/elastica": ">=0.90 <3.0", @@ -2507,56 +2083,70 @@ "logging", "psr-3" ], - "time": "2019-12-20T14:22:59+00:00" + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/2.1.1" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2020-07-23T08:41:23+00:00" }, { "name": "nelmio/api-doc-bundle", - "version": "v3.5.0", + "version": "v3.7.4", "source": { "type": "git", "url": "https://github.com/nelmio/NelmioApiDocBundle.git", - "reference": "f596adfb4d16e65d1a1941f907092a119d4c76cb" + "reference": "290df23dc0060c4daaed95a7f37845f16a287ebd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nelmio/NelmioApiDocBundle/zipball/f596adfb4d16e65d1a1941f907092a119d4c76cb", - "reference": "f596adfb4d16e65d1a1941f907092a119d4c76cb", + "url": "https://api.github.com/repos/nelmio/NelmioApiDocBundle/zipball/290df23dc0060c4daaed95a7f37845f16a287ebd", + "reference": "290df23dc0060c4daaed95a7f37845f16a287ebd", "shasum": "" }, "require": { "exsyst/swagger": "^0.4.1", - "php": "^7.0", - "phpdocumentor/reflection-docblock": "^3.1|^4.0", - "symfony/framework-bundle": "^3.4|^4.0", - "symfony/options-resolver": "^3.4.4|^4.0", - "symfony/property-info": "^3.4|^4.0", + "php": "^7.1", + "phpdocumentor/reflection-docblock": "^3.1|^4.0|^5.0", + "symfony/framework-bundle": "^3.4|^4.0|^5.0", + "symfony/options-resolver": "^3.4.4|^4.0|^5.0", + "symfony/property-info": "^3.4|^4.0|^5.0", "zircote/swagger-php": "^2.0.9" }, "conflict": { "symfony/framework-bundle": "4.2.7" }, "require-dev": { - "api-platform/core": "^2.1.0", + "api-platform/core": "^2.1.2", "doctrine/annotations": "^1.2", "doctrine/common": "^2.4", - "friendsofsymfony/rest-bundle": "^2.0", + "friendsofsymfony/rest-bundle": "^2.0|^3.0@beta", "jms/serializer": "^1.14|^3.0", - "jms/serializer-bundle": "^2.0|^3.0", + "jms/serializer-bundle": "^2.3|^3.0", "sensio/framework-extra-bundle": "^3.0.13|^4.0|^5.0", - "symfony/asset": "^3.4|^4.0", - "symfony/browser-kit": "^3.4|^4.0", - "symfony/cache": "^3.4|^4.0", - "symfony/config": "^3.4|^4.0", - "symfony/console": "^3.4|^4.0", - "symfony/dom-crawler": "^3.4|^4.0", - "symfony/form": "^3.4|^4.0", - "symfony/phpunit-bridge": "^3.4.24|^4.0", - "symfony/property-access": "^3.4|^4.0", - "symfony/routing": "^3.4|^4.0", - "symfony/stopwatch": "^3.4|^4.0", - "symfony/templating": "^3.4|^4.0", - "symfony/twig-bundle": "^3.4|^4.0", - "symfony/validator": "^3.4|^4.0", + "symfony/asset": "^3.4|^4.0|^5.0", + "symfony/browser-kit": "^3.4|^4.0|^5.0", + "symfony/cache": "^3.4|^4.0|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/form": "^3.4|^4.0|^5.0", + "symfony/phpunit-bridge": "^3.4.24|^4.0|^5.0", + "symfony/property-access": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4.42|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/twig-bundle": "^3.4|^4.0|^5.0", + "symfony/validator": "^3.4|^4.0|^5.0", "willdurand/hateoas-bundle": "^1.0|^2.0" }, "suggest": { @@ -2566,13 +2156,16 @@ "type": "symfony-bundle", "extra": { "branch-alias": { - "dev-master": "3.2.x-dev" + "dev-3.x": "3.7.x-dev" } }, "autoload": { "psr-4": { "Nelmio\\ApiDocBundle\\": "" - } + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2595,7 +2188,11 @@ "documentation", "rest" ], - "time": "2019-11-21T17:18:16+00:00" + "support": { + "issues": "https://github.com/nelmio/NelmioApiDocBundle/issues", + "source": "https://github.com/nelmio/NelmioApiDocBundle/tree/v3.7.4" + }, + "time": "2020-09-29T10:30:21+00:00" }, { "name": "nesbot/carbon", @@ -2656,59 +2253,12 @@ "datetime", "time" ], + "support": { + "issues": "https://github.com/briannesbitt/Carbon/issues", + "source": "https://github.com/briannesbitt/Carbon" + }, "time": "2019-10-14T05:51:36+00:00" }, - { - "name": "ocramius/package-versions", - "version": "1.5.1", - "source": { - "type": "git", - "url": "https://github.com/Ocramius/PackageVersions.git", - "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/1d32342b8c1eb27353c8887c366147b4c2da673c", - "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0.0", - "php": "^7.3.0" - }, - "require-dev": { - "composer/composer": "^1.8.6", - "doctrine/coding-standard": "^6.0.0", - "ext-zip": "*", - "infection/infection": "^0.13.4", - "phpunit/phpunit": "^8.2.5", - "vimeo/psalm": "^3.4.9" - }, - "type": "composer-plugin", - "extra": { - "class": "PackageVersions\\Installer", - "branch-alias": { - "dev-master": "1.6.x-dev" - } - }, - "autoload": { - "psr-4": { - "PackageVersions\\": "src/PackageVersions" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - } - ], - "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", - "time": "2019-07-17T15:49:50+00:00" - }, { "name": "ocramius/proxy-manager", "version": "2.2.3", @@ -2777,32 +2327,33 @@ "proxy pattern", "service proxies" ], + "support": { + "issues": "https://github.com/Ocramius/ProxyManager/issues", + "source": "https://github.com/Ocramius/ProxyManager/tree/2.2.x" + }, "time": "2019-08-10T08:37:15+00:00" }, { "name": "phpdocumentor/reflection-common", - "version": "2.0.0", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", - "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", "shasum": "" }, "require": { - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "~6" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.x-dev" + "dev-2.x": "2.x-dev" } }, "autoload": { @@ -2829,45 +2380,45 @@ "reflection", "static analysis" ], - "time": "2018-08-07T13:53:10+00:00" + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.4", + "version": "5.2.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c" + "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/da3fd972d6bafd628114f7e7e036f45944b62e9c", - "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", + "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", "shasum": "" }, "require": { - "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", - "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", - "webmozart/assert": "^1.0" + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" }, "require-dev": { - "doctrine/instantiator": "^1.0.5", - "mockery/mockery": "^1.0", - "phpdocumentor/type-resolver": "0.4.*", - "phpunit/phpunit": "^6.4" + "mockery/mockery": "~1.3.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-master": "5.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -2878,38 +2429,44 @@ { "name": "Mike van Riel", "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2019-12-28T18:55:12+00:00" + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master" + }, + "time": "2020-09-03T19:13:55+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.0.1", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" + "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", - "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", "shasum": "" }, "require": { - "php": "^7.1", + "php": "^7.2 || ^8.0", "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "ext-tokenizer": "^7.1", - "mockery/mockery": "~1", - "phpunit/phpunit": "^7.0" + "ext-tokenizer": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-1.x": "1.x-dev" } }, "autoload": { @@ -2928,7 +2485,11 @@ } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "time": "2019-08-22T18:11:29+00:00" + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0" + }, + "time": "2020-09-17T18:55:26+00:00" }, { "name": "psr/cache", @@ -2974,6 +2535,9 @@ "psr", "psr-6" ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, "time": "2016-08-06T20:24:11+00:00" }, { @@ -3023,6 +2587,10 @@ "container-interop", "psr" ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/master" + }, "time": "2017-02-14T16:28:37+00:00" }, { @@ -3073,20 +2641,23 @@ "request", "response" ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, "time": "2016-08-06T14:39:51+00:00" }, { "name": "psr/log", - "version": "1.1.2", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", "shasum": "" }, "require": { @@ -3120,30 +2691,32 @@ "psr", "psr-3" ], - "time": "2019-11-01T11:05:21+00:00" + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.3" + }, + "time": "2020-03-23T09:12:05+00:00" }, { "name": "salsify/json-streaming-parser", - "version": "v8.1.0", + "version": "v8.2.0", "source": { "type": "git", "url": "https://github.com/salsify/jsonstreamingparser.git", - "reference": "0e5b5cb12611fe5376af653b360e12e8c6c6f3bd" + "reference": "4ae5394136a037e09402ba8b48dbf4e20475e69d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/salsify/jsonstreamingparser/zipball/0e5b5cb12611fe5376af653b360e12e8c6c6f3bd", - "reference": "0e5b5cb12611fe5376af653b360e12e8c6c6f3bd", + "url": "https://api.github.com/repos/salsify/jsonstreamingparser/zipball/4ae5394136a037e09402ba8b48dbf4e20475e69d", + "reference": "4ae5394136a037e09402ba8b48dbf4e20475e69d", "shasum": "" }, "require": { "ext-ctype": "*", "ext-mbstring": "*", - "php": "^7.1" + "php": ">=7.1" }, "require-dev": { - "ext-json": "*", - "satooshi/php-coveralls": "~2.0" + "ext-json": "*" }, "type": "library", "extra": { @@ -3188,59 +2761,61 @@ "parser", "streaming" ], - "time": "2019-10-13T13:40:17+00:00" + "support": { + "issues": "https://github.com/salsify/jsonstreamingparser/issues", + "source": "https://github.com/salsify/jsonstreamingparser/tree/master" + }, + "time": "2020-05-22T20:10:04+00:00" }, { "name": "sensio/framework-extra-bundle", - "version": "v5.5.3", + "version": "v5.6.1", "source": { "type": "git", "url": "https://github.com/sensiolabs/SensioFrameworkExtraBundle.git", - "reference": "98f0807137b13d0acfdf3c255a731516e97015de" + "reference": "430d14c01836b77c28092883d195a43ce413ee32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sensiolabs/SensioFrameworkExtraBundle/zipball/98f0807137b13d0acfdf3c255a731516e97015de", - "reference": "98f0807137b13d0acfdf3c255a731516e97015de", + "url": "https://api.github.com/repos/sensiolabs/SensioFrameworkExtraBundle/zipball/430d14c01836b77c28092883d195a43ce413ee32", + "reference": "430d14c01836b77c28092883d195a43ce413ee32", "shasum": "" }, "require": { "doctrine/annotations": "^1.0", - "php": ">=7.1.3", - "symfony/config": "^4.3|^5.0", - "symfony/dependency-injection": "^4.3|^5.0", - "symfony/framework-bundle": "^4.3|^5.0", - "symfony/http-kernel": "^4.3|^5.0" + "php": ">=7.2.5", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/framework-bundle": "^4.4|^5.0", + "symfony/http-kernel": "^4.4|^5.0" }, "conflict": { - "doctrine/doctrine-cache-bundle": "<1.3.1" + "doctrine/doctrine-cache-bundle": "<1.3.1", + "doctrine/persistence": "<1.3" }, "require-dev": { + "doctrine/dbal": "^2.10|^3.0", "doctrine/doctrine-bundle": "^1.11|^2.0", "doctrine/orm": "^2.5", "nyholm/psr7": "^1.1", - "symfony/browser-kit": "^4.3|^5.0", - "symfony/dom-crawler": "^4.3|^5.0", - "symfony/expression-language": "^4.3|^5.0", - "symfony/finder": "^4.3|^5.0", + "symfony/browser-kit": "^4.4|^5.0", + "symfony/doctrine-bridge": "^4.4|^5.0", + "symfony/dom-crawler": "^4.4|^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/finder": "^4.4|^5.0", "symfony/monolog-bridge": "^4.0|^5.0", "symfony/monolog-bundle": "^3.2", - "symfony/phpunit-bridge": "^4.3.5|^5.0", + "symfony/phpunit-bridge": "^4.4.9|^5.0.9", "symfony/psr-http-message-bridge": "^1.1", - "symfony/security-bundle": "^4.3|^5.0", - "symfony/twig-bundle": "^4.3|^5.0", - "symfony/yaml": "^4.3|^5.0", + "symfony/security-bundle": "^4.4|^5.0", + "symfony/twig-bundle": "^4.4|^5.0", + "symfony/yaml": "^4.4|^5.0", "twig/twig": "^1.34|^2.4|^3.0" }, - "suggest": { - "symfony/expression-language": "", - "symfony/psr-http-message-bridge": "To use the PSR-7 converters", - "symfony/security-bundle": "" - }, "type": "symfony-bundle", "extra": { "branch-alias": { - "dev-master": "5.5.x-dev" + "dev-master": "5.6.x-dev" } }, "autoload": { @@ -3266,24 +2841,28 @@ "annotations", "controllers" ], - "time": "2019-12-27T08:57:19+00:00" + "support": { + "issues": "https://github.com/sensiolabs/SensioFrameworkExtraBundle/issues", + "source": "https://github.com/sensiolabs/SensioFrameworkExtraBundle/tree/v5.6.1" + }, + "time": "2020-08-25T19:10:18+00:00" }, { "name": "symfony/asset", - "version": "v4.4.2", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/asset.git", - "reference": "7ec5fc653dab63d7519a6f411982ee224a696d66" + "reference": "627761b47f94affdd8405e65245a8e1bbb810399" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset/zipball/7ec5fc653dab63d7519a6f411982ee224a696d66", - "reference": "7ec5fc653dab63d7519a6f411982ee224a696d66", + "url": "https://api.github.com/repos/symfony/asset/zipball/627761b47f94affdd8405e65245a8e1bbb810399", + "reference": "627761b47f94affdd8405e65245a8e1bbb810399", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": ">=7.1.3" }, "require-dev": { "symfony/http-foundation": "^3.4|^4.0|^5.0", @@ -3293,11 +2872,6 @@ "symfony/http-foundation": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Asset\\": "" @@ -3322,27 +2896,45 @@ ], "description": "Symfony Asset Component", "homepage": "https://symfony.com", - "time": "2019-10-12T00:35:04+00:00" + "support": { + "source": "https://github.com/symfony/asset/tree/v4.4.16" + }, + "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-10-24T11:50:19+00:00" }, { "name": "symfony/cache", - "version": "v5.0.2", + "version": "v5.1.8", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "6e8d978878ae5de705ec9fabbb6011cc18776bc9" + "reference": "d7bc33e9f9028f49f87057e7944c076d9593f046" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/6e8d978878ae5de705ec9fabbb6011cc18776bc9", - "reference": "6e8d978878ae5de705ec9fabbb6011cc18776bc9", + "url": "https://api.github.com/repos/symfony/cache/zipball/d7bc33e9f9028f49f87057e7944c076d9593f046", + "reference": "d7bc33e9f9028f49f87057e7944c076d9593f046", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": ">=7.2.5", "psr/cache": "~1.0", "psr/log": "~1.0", "symfony/cache-contracts": "^1.1.7|^2", + "symfony/polyfill-php80": "^1.15", "symfony/service-contracts": "^1.1|^2", "symfony/var-exporter": "^4.4|^5.0" }, @@ -3359,20 +2951,16 @@ }, "require-dev": { "cache/integration-tests": "dev-master", - "doctrine/cache": "~1.6", - "doctrine/dbal": "~2.5", - "predis/predis": "~1.1", + "doctrine/cache": "^1.6", + "doctrine/dbal": "^2.5|^3.0", + "predis/predis": "^1.1", "psr/simple-cache": "^1.0", "symfony/config": "^4.4|^5.0", "symfony/dependency-injection": "^4.4|^5.0", + "symfony/filesystem": "^4.4|^5.0", "symfony/var-dumper": "^4.4|^5.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Cache\\": "" @@ -3401,24 +2989,41 @@ "caching", "psr6" ], - "time": "2019-12-12T13:03:32+00:00" + "support": { + "source": "https://github.com/symfony/cache/tree/v5.1.8" + }, + "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-10-25T23:21:56+00:00" }, { "name": "symfony/cache-contracts", - "version": "v2.0.1", + "version": "v2.2.0", "source": { "type": "git", "url": "https://github.com/symfony/cache-contracts.git", - "reference": "23ed8bfc1a4115feca942cb5f1aacdf3dcdf3c16" + "reference": "8034ca0b61d4dd967f3698aaa1da2507b631d0cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/23ed8bfc1a4115feca942cb5f1aacdf3dcdf3c16", - "reference": "23ed8bfc1a4115feca942cb5f1aacdf3dcdf3c16", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/8034ca0b61d4dd967f3698aaa1da2507b631d0cb", + "reference": "8034ca0b61d4dd967f3698aaa1da2507b631d0cb", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": ">=7.2.5", "psr/cache": "^1.0" }, "suggest": { @@ -3427,7 +3032,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.2-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -3459,26 +3068,45 @@ "interoperability", "standards" ], - "time": "2019-11-18T17:27:11+00:00" + "support": { + "source": "https://github.com/symfony/cache-contracts/tree/v2.2.0" + }, + "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-09-07T11:33:47+00:00" }, { "name": "symfony/config", - "version": "v5.0.2", + "version": "v5.1.8", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "7f930484966350906185ba0a604728f7898b7ba0" + "reference": "11baeefa4c179d6908655a7b6be728f62367c193" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/7f930484966350906185ba0a604728f7898b7ba0", - "reference": "7f930484966350906185ba0a604728f7898b7ba0", + "url": "https://api.github.com/repos/symfony/config/zipball/11baeefa4c179d6908655a7b6be728f62367c193", + "reference": "11baeefa4c179d6908655a7b6be728f62367c193", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", "symfony/filesystem": "^4.4|^5.0", - "symfony/polyfill-ctype": "~1.8" + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.15" }, "conflict": { "symfony/finder": "<4.4" @@ -3494,11 +3122,6 @@ "symfony/yaml": "To use the yaml reference dumper" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Config\\": "" @@ -3523,26 +3146,44 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2019-12-18T13:50:31+00:00" + "support": { + "source": "https://github.com/symfony/config/tree/v5.1.8" + }, + "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-10-24T12:01:57+00:00" }, { "name": "symfony/console", - "version": "v4.4.2", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "82437719dab1e6bdd28726af14cb345c2ec816d0" + "reference": "20f73dd143a5815d475e0838ff867bce1eebd9d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/82437719dab1e6bdd28726af14cb345c2ec816d0", - "reference": "82437719dab1e6bdd28726af14cb345c2ec816d0", + "url": "https://api.github.com/repos/symfony/console/zipball/20f73dd143a5815d475e0838ff867bce1eebd9d5", + "reference": "20f73dd143a5815d475e0838ff867bce1eebd9d5", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php73": "^1.8", + "symfony/polyfill-php80": "^1.15", "symfony/service-contracts": "^1.1|^2" }, "conflict": { @@ -3570,11 +3211,6 @@ "symfony/process": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Console\\": "" @@ -3599,25 +3235,43 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2019-12-17T10:32:23+00:00" + "support": { + "source": "https://github.com/symfony/console/tree/v4.4.16" + }, + "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-10-24T11:50:19+00:00" }, { "name": "symfony/debug", - "version": "v4.4.2", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "5c4c1db977dc70bb3250e1308d3e8c6341aa38f5" + "reference": "c87adf3fc1cd0bf4758316a3a150d50a8f957ef4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/5c4c1db977dc70bb3250e1308d3e8c6341aa38f5", - "reference": "5c4c1db977dc70bb3250e1308d3e8c6341aa38f5", + "url": "https://api.github.com/repos/symfony/debug/zipball/c87adf3fc1cd0bf4758316a3a150d50a8f957ef4", + "reference": "c87adf3fc1cd0bf4758316a3a150d50a8f957ef4", "shasum": "" }, "require": { - "php": "^7.1.3", - "psr/log": "~1.0" + "php": ">=7.1.3", + "psr/log": "~1.0", + "symfony/polyfill-php80": "^1.15" }, "conflict": { "symfony/http-kernel": "<3.4" @@ -3626,11 +3280,6 @@ "symfony/http-kernel": "^3.4|^4.0|^5.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Debug\\": "" @@ -3655,29 +3304,48 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2019-12-16T14:46:54+00:00" + "support": { + "source": "https://github.com/symfony/debug/tree/v4.4.16" + }, + "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-10-24T11:50:19+00:00" }, { "name": "symfony/dependency-injection", - "version": "v5.0.2", + "version": "v5.1.8", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "f9dbfbf487d08f60b1c83220edcd16559d1e40a2" + "reference": "829ca6bceaf68036a123a13a979f3c89289eae78" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f9dbfbf487d08f60b1c83220edcd16559d1e40a2", - "reference": "f9dbfbf487d08f60b1c83220edcd16559d1e40a2", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/829ca6bceaf68036a123a13a979f3c89289eae78", + "reference": "829ca6bceaf68036a123a13a979f3c89289eae78", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": ">=7.2.5", "psr/container": "^1.0", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php80": "^1.15", "symfony/service-contracts": "^1.1.6|^2" }, "conflict": { - "symfony/config": "<5.0", + "symfony/config": "<5.1", "symfony/finder": "<4.4", "symfony/proxy-manager-bridge": "<4.4", "symfony/yaml": "<4.4" @@ -3687,7 +3355,7 @@ "symfony/service-implementation": "1.0" }, "require-dev": { - "symfony/config": "^5.0", + "symfony/config": "^5.1", "symfony/expression-language": "^4.4|^5.0", "symfony/yaml": "^4.4|^5.0" }, @@ -3699,11 +3367,6 @@ "symfony/yaml": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\DependencyInjection\\": "" @@ -3728,26 +3391,110 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2019-12-19T16:01:11+00:00" + "support": { + "source": "https://github.com/symfony/dependency-injection/tree/v5.1.8" + }, + "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-10-27T10:11:13+00:00" }, { - "name": "symfony/doctrine-bridge", - "version": "v4.4.2", + "name": "symfony/deprecation-contracts", + "version": "v2.2.0", "source": { "type": "git", - "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "3e40beb8dbb06d2967e37938f4c3f20f425137a6" + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/3e40beb8dbb06d2967e37938f4c3f20f425137a6", - "reference": "3e40beb8dbb06d2967e37938f4c3f20f425137a6", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5fa56b4074d1ae755beb55617ddafe6f5d78f665", + "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "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": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/master" + }, + "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-09-07T11:33:47+00:00" + }, + { + "name": "symfony/doctrine-bridge", + "version": "v4.4.16", + "source": { + "type": "git", + "url": "https://github.com/symfony/doctrine-bridge.git", + "reference": "12ce8950c685afb954026c2d0c975dfed3fc32f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/12ce8950c685afb954026c2d0c975dfed3fc32f3", + "reference": "12ce8950c685afb954026c2d0c975dfed3fc32f3", "shasum": "" }, "require": { "doctrine/event-manager": "~1.0", - "doctrine/persistence": "^1.3", - "php": "^7.1.3", + "doctrine/persistence": "^1.3|^2", + "php": ">=7.1.3", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^1.1|^2" @@ -3762,17 +3509,18 @@ "symfony/validator": "<4.4.2|<5.0.2,>=5.0" }, "require-dev": { + "composer/package-versions-deprecated": "^1.8", "doctrine/annotations": "~1.7", "doctrine/cache": "~1.6", "doctrine/collections": "~1.0", - "doctrine/data-fixtures": "1.0.*", - "doctrine/dbal": "~2.4", + "doctrine/data-fixtures": "^1.1", + "doctrine/dbal": "~2.4|^3.0", "doctrine/orm": "^2.6.3", "doctrine/reflection": "~1.0", "symfony/config": "^4.2|^5.0", "symfony/dependency-injection": "^3.4|^4.0|^5.0", "symfony/expression-language": "^3.4|^4.0|^5.0", - "symfony/form": "^4.4|^5.0", + "symfony/form": "^4.4.11|^5.0.11", "symfony/http-kernel": "^4.3.7", "symfony/messenger": "^4.4|^5.0", "symfony/property-access": "^3.4|^4.0|^5.0", @@ -3793,11 +3541,6 @@ "symfony/validator": "" }, "type": "symfony-bridge", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Bridge\\Doctrine\\": "" @@ -3822,26 +3565,44 @@ ], "description": "Symfony Doctrine Bridge", "homepage": "https://symfony.com", - "time": "2019-12-17T08:15:02+00:00" + "support": { + "source": "https://github.com/symfony/doctrine-bridge/tree/v4.4.16" + }, + "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-10-24T11:50:19+00:00" }, { "name": "symfony/error-handler", - "version": "v4.4.2", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "6d7d7712a6ff5215ec26215672293b154f1db8c1" + "reference": "363cca01cabf98e4f1c447b14d0a68617f003613" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/6d7d7712a6ff5215ec26215672293b154f1db8c1", - "reference": "6d7d7712a6ff5215ec26215672293b154f1db8c1", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/363cca01cabf98e4f1c447b14d0a68617f003613", + "reference": "363cca01cabf98e4f1c447b14d0a68617f003613", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "psr/log": "~1.0", - "symfony/debug": "^4.4", + "symfony/debug": "^4.4.5", + "symfony/polyfill-php80": "^1.15", "symfony/var-dumper": "^4.4|^5.0" }, "require-dev": { @@ -3849,11 +3610,6 @@ "symfony/serializer": "^4.4|^5.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\ErrorHandler\\": "" @@ -3878,24 +3634,41 @@ ], "description": "Symfony ErrorHandler Component", "homepage": "https://symfony.com", - "time": "2019-12-16T14:46:54+00:00" + "support": { + "source": "https://github.com/symfony/error-handler/tree/v4.4.16" + }, + "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-10-24T11:50:19+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.4.2", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b3c3068a72623287550fe20b84a2b01dcba2686f" + "reference": "4204f13d2d0b7ad09454f221bb2195fccdf1fe98" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b3c3068a72623287550fe20b84a2b01dcba2686f", - "reference": "b3c3068a72623287550fe20b84a2b01dcba2686f", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/4204f13d2d0b7ad09454f221bb2195fccdf1fe98", + "reference": "4204f13d2d0b7ad09454f221bb2195fccdf1fe98", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "symfony/event-dispatcher-contracts": "^1.1" }, "conflict": { @@ -3909,6 +3682,7 @@ "psr/log": "~1.0", "symfony/config": "^3.4|^4.0|^5.0", "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/error-handler": "~3.4|~4.4", "symfony/expression-language": "^3.4|^4.0|^5.0", "symfony/http-foundation": "^3.4|^4.0|^5.0", "symfony/service-contracts": "^1.1|^2", @@ -3919,11 +3693,6 @@ "symfony/http-kernel": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\EventDispatcher\\": "" @@ -3948,24 +3717,41 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2019-11-28T13:33:56+00:00" + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.16" + }, + "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-10-24T11:50:19+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v1.1.7", + "version": "v1.1.9", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18" + "reference": "84e23fdcd2517bf37aecbd16967e83f0caee25a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c43ab685673fb6c8d84220c77897b1d6cdbe1d18", - "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/84e23fdcd2517bf37aecbd16967e83f0caee25a7", + "reference": "84e23fdcd2517bf37aecbd16967e83f0caee25a7", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": ">=7.1.3" }, "suggest": { "psr/event-dispatcher": "", @@ -3975,6 +3761,10 @@ "extra": { "branch-alias": { "dev-master": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -4006,32 +3796,44 @@ "interoperability", "standards" ], - "time": "2019-09-17T09:54:03+00:00" + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.9" + }, + "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-06T13:19:58+00:00" }, { "name": "symfony/filesystem", - "version": "v5.0.2", + "version": "v5.1.8", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "1d71f670bc5a07b9ccc97dc44f932177a322d4e6" + "reference": "df08650ea7aee2d925380069c131a66124d79177" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/1d71f670bc5a07b9ccc97dc44f932177a322d4e6", - "reference": "1d71f670bc5a07b9ccc97dc44f932177a322d4e6", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/df08650ea7aee2d925380069c131a66124d79177", + "reference": "df08650ea7aee2d925380069c131a66124d79177", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": ">=7.2.5", "symfony/polyfill-ctype": "~1.8" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Filesystem\\": "" @@ -4056,31 +3858,43 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2019-11-26T23:25:11+00:00" + "support": { + "source": "https://github.com/symfony/filesystem/tree/v5.1.8" + }, + "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-10-24T12:01:57+00:00" }, { "name": "symfony/finder", - "version": "v5.0.2", + "version": "v5.1.8", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "17874dd8ab9a19422028ad56172fb294287a701b" + "reference": "e70eb5a69c2ff61ea135a13d2266e8914a67b3a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/17874dd8ab9a19422028ad56172fb294287a701b", - "reference": "17874dd8ab9a19422028ad56172fb294287a701b", + "url": "https://api.github.com/repos/symfony/finder/zipball/e70eb5a69c2ff61ea135a13d2266e8914a67b3a0", + "reference": "e70eb5a69c2ff61ea135a13d2266e8914a67b3a0", "shasum": "" }, "require": { - "php": "^7.2.5" + "php": ">=7.2.5" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Finder\\": "" @@ -4105,36 +3919,53 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2019-11-18T17:27:11+00:00" + "support": { + "source": "https://github.com/symfony/finder/tree/v5.1.8" + }, + "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-10-24T12:01:57+00:00" }, { "name": "symfony/flex", - "version": "v1.6.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/symfony/flex.git", - "reference": "952f45d1c5077e658cb16a61d11603bee873f968" + "reference": "e38520236bdc911c2f219634b485bc328746e980" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/flex/zipball/952f45d1c5077e658cb16a61d11603bee873f968", - "reference": "952f45d1c5077e658cb16a61d11603bee873f968", + "url": "https://api.github.com/repos/symfony/flex/zipball/e38520236bdc911c2f219634b485bc328746e980", + "reference": "e38520236bdc911c2f219634b485bc328746e980", "shasum": "" }, "require": { - "composer-plugin-api": "^1.0", - "php": "^7.0" + "composer-plugin-api": "^1.0|^2.0", + "php": ">=7.1" }, "require-dev": { - "composer/composer": "^1.0.2", - "symfony/dotenv": "^3.4|^4.0|^5.0", - "symfony/phpunit-bridge": "^3.4.19|^4.1.8|^5.0", - "symfony/process": "^2.7|^3.0|^4.0|^5.0" + "composer/composer": "^1.0.2|^2.0", + "symfony/dotenv": "^4.4|^5.0", + "symfony/phpunit-bridge": "^4.4|^5.0", + "symfony/process": "^3.4|^4.4|^5.0" }, "type": "composer-plugin", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-main": "1.9-dev" }, "class": "Symfony\\Flex\\Flex" }, @@ -4154,25 +3985,43 @@ } ], "description": "Composer plugin for Symfony", - "time": "2019-12-13T18:05:11+00:00" + "support": { + "issues": "https://github.com/symfony/flex/issues", + "source": "https://github.com/symfony/flex/tree/v1.10.0" + }, + "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-11-05T10:56:45+00:00" }, { "name": "symfony/framework-bundle", - "version": "v4.4.2", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "c80526b4c22f6ddc23080225bf276f094d2c398e" + "reference": "0067e02d6ca55e284617777ed90cd086d3836457" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/c80526b4c22f6ddc23080225bf276f094d2c398e", - "reference": "c80526b4c22f6ddc23080225bf276f094d2c398e", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/0067e02d6ca55e284617777ed90cd086d3836457", + "reference": "0067e02d6ca55e284617777ed90cd086d3836457", "shasum": "" }, "require": { "ext-xml": "*", - "php": "^7.1.3", + "php": ">=7.1.3", "symfony/cache": "^4.4|^5.0", "symfony/config": "^4.3.4|^5.0", "symfony/dependency-injection": "^4.4.1|^5.0.1", @@ -4256,11 +4105,6 @@ "symfony/yaml": "For using the debug:config and lint:yaml commands" }, "type": "symfony-bundle", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Bundle\\FrameworkBundle\\": "" @@ -4285,37 +4129,134 @@ ], "description": "Symfony FrameworkBundle", "homepage": "https://symfony.com", - "time": "2019-12-17T08:15:02+00:00" + "support": { + "source": "https://github.com/symfony/framework-bundle/tree/v4.4.16" + }, + "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-10-24T11:50:19+00:00" }, { - "name": "symfony/http-foundation", - "version": "v5.0.2", + "name": "symfony/http-client-contracts", + "version": "v2.3.1", "source": { "type": "git", - "url": "https://github.com/symfony/http-foundation.git", - "reference": "5dd7f6be6e62d86ba6f3154cf40e78936367978b" + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "41db680a15018f9c1d4b23516059633ce280ca33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/5dd7f6be6e62d86ba6f3154cf40e78936367978b", - "reference": "5dd7f6be6e62d86ba6f3154cf40e78936367978b", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/41db680a15018f9c1d4b23516059633ce280ca33", + "reference": "41db680a15018f9c1d4b23516059633ce280ca33", "shasum": "" }, "require": { - "php": "^7.2.5", - "symfony/mime": "^4.4|^5.0", - "symfony/polyfill-mbstring": "~1.1" + "php": ">=7.2.5" }, - "require-dev": { - "predis/predis": "~1.0", - "symfony/expression-language": "^4.4|^5.0" + "suggest": { + "symfony/http-client-implementation": "" }, "type": "library", "extra": { + "branch-version": "2.3", "branch-alias": { - "dev-master": "5.0-dev" + "dev-main": "2.3-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + } + }, + "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": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v2.3.1" + }, + "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-10-14T17:08:19+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v5.1.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "a2860ec970404b0233ab1e59e0568d3277d32b6f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a2860ec970404b0233ab1e59e0568d3277d32b6f", + "reference": "a2860ec970404b0233ab1e59e0568d3277d32b6f", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php80": "^1.15" + }, + "require-dev": { + "predis/predis": "~1.0", + "symfony/cache": "^4.4|^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0" + }, + "suggest": { + "symfony/mime": "To use the file extension guesser" + }, + "type": "library", "autoload": { "psr-4": { "Symfony\\Component\\HttpFoundation\\": "" @@ -4340,30 +4281,49 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2019-12-19T16:01:11+00:00" + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v5.1.8" + }, + "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-10-24T12:01:57+00:00" }, { "name": "symfony/http-kernel", - "version": "v4.4.2", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "fe310d2e95cd4c356836c8ecb0895a46d97fede2" + "reference": "109b2a46e470a487ec8b0ffea4b0bb993aaf42ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/fe310d2e95cd4c356836c8ecb0895a46d97fede2", - "reference": "fe310d2e95cd4c356836c8ecb0895a46d97fede2", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/109b2a46e470a487ec8b0ffea4b0bb993aaf42ed", + "reference": "109b2a46e470a487ec8b0ffea4b0bb993aaf42ed", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "psr/log": "~1.0", "symfony/error-handler": "^4.4", "symfony/event-dispatcher": "^4.4", + "symfony/http-client-contracts": "^1.1|^2", "symfony/http-foundation": "^4.4|^5.0", "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-php73": "^1.9" + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.15" }, "conflict": { "symfony/browser-kit": "<4.3", @@ -4401,11 +4361,6 @@ "symfony/dependency-injection": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\HttpKernel\\": "" @@ -4430,145 +4385,42 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2019-12-19T16:23:40+00:00" - }, - { - "name": "symfony/inflector", - "version": "v5.0.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/inflector.git", - "reference": "aaeb5e293294070d1b061fa3d7889bac69909320" + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v4.4.16" }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/inflector/zipball/aaeb5e293294070d1b061fa3d7889bac69909320", - "reference": "aaeb5e293294070d1b061fa3d7889bac69909320", - "shasum": "" - }, - "require": { - "php": "^7.2.5", - "symfony/polyfill-ctype": "~1.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Inflector\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ + "funding": [ { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Inflector Component", - "homepage": "https://symfony.com", - "keywords": [ - "inflection", - "pluralize", - "singularize", - "string", - "symfony", - "words" - ], - "time": "2019-11-18T17:27:11+00:00" - }, - { - "name": "symfony/mime", - "version": "v5.0.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/mime.git", - "reference": "0e6a4ced216e49d457eddcefb61132173a876d79" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/0e6a4ced216e49d457eddcefb61132173a876d79", - "reference": "0e6a4ced216e49d457eddcefb61132173a876d79", - "shasum": "" - }, - "require": { - "php": "^7.2.5", - "symfony/polyfill-intl-idn": "^1.10", - "symfony/polyfill-mbstring": "^1.0" - }, - "conflict": { - "symfony/mailer": "<4.4" - }, - "require-dev": { - "egulias/email-validator": "^2.1.10", - "symfony/dependency-injection": "^4.4|^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Mime\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "url": "https://github.com/fabpot", + "type": "github" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "description": "A library to manipulate MIME messages", - "homepage": "https://symfony.com", - "keywords": [ - "mime", - "mime-type" - ], - "time": "2019-11-30T14:12:50+00:00" + "time": "2020-10-28T05:50:56+00:00" }, { "name": "symfony/monolog-bridge", - "version": "v5.0.2", + "version": "v5.1.8", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "dfac10ea8a5863949966d9b6030984c079bec665" + "reference": "0c507eddb704a3154b53f066cc0b587c4586c868" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/dfac10ea8a5863949966d9b6030984c079bec665", - "reference": "dfac10ea8a5863949966d9b6030984c079bec665", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/0c507eddb704a3154b53f066cc0b587c4586c868", + "reference": "0c507eddb704a3154b53f066cc0b587c4586c868", "shasum": "" }, "require": { "monolog/monolog": "^1.25.1|^2", - "php": "^7.2.5", + "php": ">=7.2.5", "symfony/http-kernel": "^4.4|^5.0", "symfony/service-contracts": "^1.1|^2" }, @@ -4579,6 +4431,8 @@ "require-dev": { "symfony/console": "^4.4|^5.0", "symfony/http-client": "^4.4|^5.0", + "symfony/mailer": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0", "symfony/security-core": "^4.4|^5.0", "symfony/var-dumper": "^4.4|^5.0" }, @@ -4588,11 +4442,6 @@ "symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler." }, "type": "symfony-bridge", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Bridge\\Monolog\\": "" @@ -4617,20 +4466,37 @@ ], "description": "Symfony Monolog Bridge", "homepage": "https://symfony.com", - "time": "2019-12-10T11:06:55+00:00" + "support": { + "source": "https://github.com/symfony/monolog-bridge/tree/v5.1.8" + }, + "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-10-24T12:01:57+00:00" }, { "name": "symfony/monolog-bundle", - "version": "v3.5.0", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bundle.git", - "reference": "dd80460fcfe1fa2050a7103ad818e9d0686ce6fd" + "reference": "e495f5c7e4e672ffef4357d4a4d85f010802f940" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/dd80460fcfe1fa2050a7103ad818e9d0686ce6fd", - "reference": "dd80460fcfe1fa2050a7103ad818e9d0686ce6fd", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/e495f5c7e4e672ffef4357d4a4d85f010802f940", + "reference": "e495f5c7e4e672ffef4357d4a4d85f010802f940", "shasum": "" }, "require": { @@ -4643,7 +4509,7 @@ }, "require-dev": { "symfony/console": "~3.4 || ~4.0 || ^5.0", - "symfony/phpunit-bridge": "^3.4.19 || ^4.0 || ^5.0", + "symfony/phpunit-bridge": "^4.4 || ^5.0", "symfony/yaml": "~3.4 || ~4.0 || ^5.0" }, "type": "symfony-bundle", @@ -4680,31 +4546,46 @@ "log", "logging" ], - "time": "2019-11-13T13:11:14+00:00" + "support": { + "issues": "https://github.com/symfony/monolog-bundle/issues", + "source": "https://github.com/symfony/monolog-bundle/tree/v3.6.0" + }, + "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-10-06T15:12:11+00:00" }, { "name": "symfony/options-resolver", - "version": "v4.4.2", + "version": "v5.1.8", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "2be23e63f33de16b49294ea6581f462932a77e2f" + "reference": "c6a02905e4ffc7a1498e8ee019db2b477cd1cc02" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/2be23e63f33de16b49294ea6581f462932a77e2f", - "reference": "2be23e63f33de16b49294ea6581f462932a77e2f", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/c6a02905e4ffc7a1498e8ee019db2b477cd1cc02", + "reference": "c6a02905e4ffc7a1498e8ee019db2b477cd1cc02", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php80": "^1.15" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\OptionsResolver\\": "" @@ -4734,27 +4615,45 @@ "configuration", "options" ], - "time": "2019-10-28T21:57:16+00:00" + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v5.1.8" + }, + "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-10-24T12:01:57+00:00" }, { "name": "symfony/orm-pack", - "version": "v1.0.7", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/symfony/orm-pack.git", - "reference": "c57f5e05232ca40626eb9fa52a32bc8565e9231c" + "reference": "21ac491414b5815e5ebb7425908c1d1568d2e775" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/orm-pack/zipball/c57f5e05232ca40626eb9fa52a32bc8565e9231c", - "reference": "c57f5e05232ca40626eb9fa52a32bc8565e9231c", + "url": "https://api.github.com/repos/symfony/orm-pack/zipball/21ac491414b5815e5ebb7425908c1d1568d2e775", + "reference": "21ac491414b5815e5ebb7425908c1d1568d2e775", "shasum": "" }, "require": { - "doctrine/doctrine-bundle": "^1.6.10|^2.0", - "doctrine/doctrine-migrations-bundle": "^1.3|^2.0", - "doctrine/orm": "^2.5.11", - "php": "^7.0" + "composer/package-versions-deprecated": "*", + "doctrine/common": "^2", + "doctrine/doctrine-bundle": "^2", + "doctrine/doctrine-migrations-bundle": "^2", + "doctrine/orm": "^2" }, "type": "symfony-pack", "notification-url": "https://packagist.org/downloads/", @@ -4762,26 +4661,42 @@ "MIT" ], "description": "A pack for the Doctrine ORM", - "time": "2019-10-18T05:41:09+00:00" + "support": { + "issues": "https://github.com/symfony/orm-pack/issues", + "source": "https://github.com/symfony/orm-pack/tree/v1.2.0" + }, + "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-08-31T10:20:18+00:00" }, { - "name": "symfony/polyfill-intl-idn", - "version": "v1.13.1", + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.20.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "6f9c239e61e1b0c9229a28ff89a812dc449c3d46" + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/6f9c239e61e1b0c9229a28ff89a812dc449c3d46", - "reference": "6f9c239e61e1b0c9229a28ff89a812dc449c3d46", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c", + "reference": "c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c", "shasum": "" }, "require": { - "php": ">=5.3.3", - "symfony/polyfill-mbstring": "^1.3", - "symfony/polyfill-php72": "^1.9" + "php": ">=7.1" }, "suggest": { "ext-intl": "For best performance" @@ -4789,12 +4704,16 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" }, "files": [ "bootstrap.php" @@ -4806,42 +4725,143 @@ ], "authors": [ { - "name": "Laurent Bassin", - "email": "laurent@bassin.info" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "description": "Symfony polyfill for intl's grapheme_* functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "idn", + "grapheme", "intl", "polyfill", "portable", "shim" ], - "time": "2019-11-27T13:56:44+00:00" + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.20.0" + }, + "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-10-23T14:02:19+00:00" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.13.1", + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.20.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f" + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "727d1096295d807c309fb01a851577302394c897" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7b4aab9743c30be783b73de055d24a39cf4b954f", - "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/727d1096295d807c309fb01a851577302394c897", + "reference": "727d1096295d807c309fb01a851577302394c897", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.20-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" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.20.0" + }, + "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-10-23T14:02:19+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "39d483bdf39be819deabf04ec872eb0b2410b531" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/39d483bdf39be819deabf04ec872eb0b2410b531", + "reference": "39d483bdf39be819deabf04ec872eb0b2410b531", + "shasum": "" + }, + "require": { + "php": ">=7.1" }, "suggest": { "ext-mbstring": "For best performance" @@ -4849,7 +4869,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -4883,29 +4907,50 @@ "portable", "shim" ], - "time": "2019-11-27T14:18:11+00:00" + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.20.0" + }, + "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-10-23T14:02:19+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.13.1", + "version": "v1.20.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "66fea50f6cb37a35eea048d75a7d99a45b586038" + "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/66fea50f6cb37a35eea048d75a7d99a45b586038", - "reference": "66fea50f6cb37a35eea048d75a7d99a45b586038", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cede45fcdfabdd6043b3592e83678e42ec69e930", + "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -4938,29 +4983,50 @@ "portable", "shim" ], - "time": "2019-11-27T13:56:44+00:00" + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.20.0" + }, + "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-10-23T14:02:19+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.13.1", + "version": "v1.20.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "4b0e2222c55a25b4541305a053013d5647d3a25f" + "reference": "8ff431c517be11c78c48a39a66d37431e26a6bed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/4b0e2222c55a25b4541305a053013d5647d3a25f", - "reference": "4b0e2222c55a25b4541305a053013d5647d3a25f", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/8ff431c517be11c78c48a39a66d37431e26a6bed", + "reference": "8ff431c517be11c78c48a39a66d37431e26a6bed", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -4996,24 +5062,123 @@ "portable", "shim" ], - "time": "2019-11-27T16:25:15+00:00" + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.20.0" + }, + "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-10-23T14:02:19+00:00" }, { - "name": "symfony/profiler-pack", - "version": "v1.0.4", + "name": "symfony/polyfill-php80", + "version": "v1.20.0", "source": { "type": "git", - "url": "https://github.com/symfony/profiler-pack.git", - "reference": "99c4370632c2a59bb0444852f92140074ef02209" + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/profiler-pack/zipball/99c4370632c2a59bb0444852f92140074ef02209", - "reference": "99c4370632c2a59bb0444852f92140074ef02209", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/e70aa8b064c5b72d3df2abd5ab1e90464ad009de", + "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.20.0" + }, + "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-10-23T14:02:19+00:00" + }, + { + "name": "symfony/profiler-pack", + "version": "v1.0.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/profiler-pack.git", + "reference": "29ec66471082b4eb068db11eb4f0a48c277653f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/profiler-pack/zipball/29ec66471082b4eb068db11eb4f0a48c277653f7", + "reference": "29ec66471082b4eb068db11eb4f0a48c277653f7", "shasum": "" }, "require": { - "php": "^7.0", "symfony/stopwatch": "*", "symfony/twig-bundle": "*", "symfony/web-profiler-bundle": "*" @@ -5024,37 +5189,56 @@ "MIT" ], "description": "A pack for the Symfony web profiler", - "time": "2018-12-10T12:11:44+00:00" + "support": { + "issues": "https://github.com/symfony/profiler-pack/issues", + "source": "https://github.com/symfony/profiler-pack/tree/v1.0.5" + }, + "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-08-12T06:50:46+00:00" }, { "name": "symfony/property-info", - "version": "v4.4.2", + "version": "v5.1.8", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "8afd280f159697177e48eefa89efd4db60a57665" + "reference": "fc15c51f829887b62a94a917ba793f51e80ea3e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/8afd280f159697177e48eefa89efd4db60a57665", - "reference": "8afd280f159697177e48eefa89efd4db60a57665", + "url": "https://api.github.com/repos/symfony/property-info/zipball/fc15c51f829887b62a94a917ba793f51e80ea3e1", + "reference": "fc15c51f829887b62a94a917ba793f51e80ea3e1", "shasum": "" }, "require": { - "php": "^7.1.3", - "symfony/inflector": "^3.4|^4.0|^5.0" + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.15", + "symfony/string": "^5.1" }, "conflict": { - "phpdocumentor/reflection-docblock": "<3.0||>=3.2.0,<3.2.2", + "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<0.3.0", - "symfony/dependency-injection": "<3.4" + "symfony/dependency-injection": "<4.4" }, "require-dev": { "doctrine/annotations": "~1.7", - "phpdocumentor/reflection-docblock": "^3.0|^4.0", - "symfony/cache": "^3.4|^4.0|^5.0", - "symfony/dependency-injection": "^3.4|^4.0|^5.0", - "symfony/serializer": "^3.4|^4.0|^5.0" + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/cache": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" }, "suggest": { "phpdocumentor/reflection-docblock": "To use the PHPDoc", @@ -5063,11 +5247,6 @@ "symfony/serializer": "To use Serializer metadata" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\PropertyInfo\\": "" @@ -5100,24 +5279,43 @@ "type", "validator" ], - "time": "2019-11-05T16:11:08+00:00" + "support": { + "source": "https://github.com/symfony/property-info/tree/v5.1.8" + }, + "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-10-24T12:01:57+00:00" }, { "name": "symfony/routing", - "version": "v5.0.2", + "version": "v5.1.8", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "120c5fa4f4ef5466cbb510ece8126e0007285301" + "reference": "d6ceee2a37b61b41079005207bf37746d1bfe71f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/120c5fa4f4ef5466cbb510ece8126e0007285301", - "reference": "120c5fa4f4ef5466cbb510ece8126e0007285301", + "url": "https://api.github.com/repos/symfony/routing/zipball/d6ceee2a37b61b41079005207bf37746d1bfe71f", + "reference": "d6ceee2a37b61b41079005207bf37746d1bfe71f", "shasum": "" }, "require": { - "php": "^7.2.5" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php80": "^1.15" }, "conflict": { "symfony/config": "<5.0", @@ -5141,11 +5339,6 @@ "symfony/yaml": "For using the YAML loader" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Routing\\": "" @@ -5176,24 +5369,41 @@ "uri", "url" ], - "time": "2019-12-12T13:03:32+00:00" + "support": { + "source": "https://github.com/symfony/routing/tree/v5.1.8" + }, + "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-10-24T12:01:57+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.0.1", + "version": "v2.2.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "144c5e51266b281231e947b51223ba14acf1a749" + "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/144c5e51266b281231e947b51223ba14acf1a749", - "reference": "144c5e51266b281231e947b51223ba14acf1a749", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d15da7ba4957ffb8f1747218be9e1a121fd298a1", + "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": ">=7.2.5", "psr/container": "^1.0" }, "suggest": { @@ -5202,7 +5412,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.2-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -5234,32 +5448,44 @@ "interoperability", "standards" ], - "time": "2019-11-18T17:27:11+00:00" + "support": { + "source": "https://github.com/symfony/service-contracts/tree/master" + }, + "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-09-07T11:33:47+00:00" }, { "name": "symfony/stopwatch", - "version": "v5.0.2", + "version": "v5.1.8", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "d410282956706e0b08681a5527447a8e6b6f421e" + "reference": "3d9f57c89011f0266e6b1d469e5c0110513859d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/d410282956706e0b08681a5527447a8e6b6f421e", - "reference": "d410282956706e0b08681a5527447a8e6b6f421e", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/3d9f57c89011f0266e6b1d469e5c0110513859d5", + "reference": "3d9f57c89011f0266e6b1d469e5c0110513859d5", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": ">=7.2.5", "symfony/service-contracts": "^1.0|^2" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Stopwatch\\": "" @@ -5284,24 +5510,124 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2019-11-18T17:27:11+00:00" + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v5.1.8" + }, + "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-10-24T12:01:57+00:00" }, { - "name": "symfony/translation", - "version": "v4.4.2", + "name": "symfony/string", + "version": "v5.1.8", "source": { "type": "git", - "url": "https://github.com/symfony/translation.git", - "reference": "f7669f48a9633bf8139bc026c755e894b7206677" + "url": "https://github.com/symfony/string.git", + "reference": "a97573e960303db71be0dd8fda9be3bca5e0feea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/f7669f48a9633bf8139bc026c755e894b7206677", - "reference": "f7669f48a9633bf8139bc026c755e894b7206677", + "url": "https://api.github.com/repos/symfony/string/zipball/a97573e960303db71be0dd8fda9be3bca5e0feea", + "reference": "a97573e960303db71be0dd8fda9be3bca5e0feea", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "~1.15" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "files": [ + "Resources/functions.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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 String component", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v5.1.8" + }, + "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-10-24T12:01:57+00:00" + }, + { + "name": "symfony/translation", + "version": "v4.4.16", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "73095716af79f610f3b6338b911357393fdd10ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/73095716af79f610f3b6338b911357393fdd10ab", + "reference": "73095716af79f610f3b6338b911357393fdd10ab", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", "symfony/polyfill-mbstring": "~1.0", "symfony/translation-contracts": "^1.1.6|^2" }, @@ -5331,11 +5657,6 @@ "symfony/yaml": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Translation\\": "" @@ -5360,24 +5681,41 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2019-12-12T12:53:52+00:00" + "support": { + "source": "https://github.com/symfony/translation/tree/v4.4.16" + }, + "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-10-24T11:50:19+00:00" }, { "name": "symfony/translation-contracts", - "version": "v2.0.1", + "version": "v2.3.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "8cc682ac458d75557203b2f2f14b0b92e1c744ed" + "reference": "e2eaa60b558f26a4b0354e1bbb25636efaaad105" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/8cc682ac458d75557203b2f2f14b0b92e1c744ed", - "reference": "8cc682ac458d75557203b2f2f14b0b92e1c744ed", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/e2eaa60b558f26a4b0354e1bbb25636efaaad105", + "reference": "e2eaa60b558f26a4b0354e1bbb25636efaaad105", "shasum": "" }, "require": { - "php": "^7.2.5" + "php": ">=7.2.5" }, "suggest": { "symfony/translation-implementation": "" @@ -5385,7 +5723,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.3-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -5417,24 +5759,41 @@ "interoperability", "standards" ], - "time": "2019-11-18T17:27:11+00:00" + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v2.3.0" + }, + "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-09-28T13:05:58+00:00" }, { "name": "symfony/twig-bridge", - "version": "v4.4.2", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "936cf6f5b973377345e8ac43870987ef8e747ce3" + "reference": "841c46c963891122429cfa1b56f06aeef9c1c010" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/936cf6f5b973377345e8ac43870987ef8e747ce3", - "reference": "936cf6f5b973377345e8ac43870987ef8e747ce3", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/841c46c963891122429cfa1b56f06aeef9c1c010", + "reference": "841c46c963891122429cfa1b56f06aeef9c1c010", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "symfony/translation-contracts": "^1.1|^2", "twig/twig": "^1.41|^2.10|^3.0" }, @@ -5491,11 +5850,6 @@ "symfony/yaml": "For using the YamlExtension" }, "type": "symfony-bridge", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Bridge\\Twig\\": "" @@ -5520,24 +5874,41 @@ ], "description": "Symfony Twig Bridge", "homepage": "https://symfony.com", - "time": "2019-12-05T05:58:42+00:00" + "support": { + "source": "https://github.com/symfony/twig-bridge/tree/v4.4.16" + }, + "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-10-24T11:50:19+00:00" }, { "name": "symfony/twig-bundle", - "version": "v4.4.2", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "a6e7bd9731256a55b2270c1283de8bc3bda06e8f" + "reference": "9acacb72d30ee1ea0331762906a129a66a9d9883" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/a6e7bd9731256a55b2270c1283de8bc3bda06e8f", - "reference": "a6e7bd9731256a55b2270c1283de8bc3bda06e8f", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/9acacb72d30ee1ea0331762906a129a66a9d9883", + "reference": "9acacb72d30ee1ea0331762906a129a66a9d9883", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "symfony/http-foundation": "^4.3|^5.0", "symfony/http-kernel": "^4.4", "symfony/polyfill-ctype": "~1.8", @@ -5566,11 +5937,6 @@ "symfony/yaml": "^3.4|^4.0|^5.0" }, "type": "symfony-bundle", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Bundle\\TwigBundle\\": "" @@ -5595,26 +5961,44 @@ ], "description": "Symfony TwigBundle", "homepage": "https://symfony.com", - "time": "2019-12-10T11:13:11+00:00" + "support": { + "source": "https://github.com/symfony/twig-bundle/tree/v4.4.16" + }, + "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-10-24T11:50:19+00:00" }, { "name": "symfony/var-dumper", - "version": "v4.4.2", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "be330f919bdb395d1e0c3f2bfb8948512d6bdd99" + "reference": "3718e18b68d955348ad860e505991802c09f5f73" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/be330f919bdb395d1e0c3f2bfb8948512d6bdd99", - "reference": "be330f919bdb395d1e0c3f2bfb8948512d6bdd99", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3718e18b68d955348ad860e505991802c09f5f73", + "reference": "3718e18b68d955348ad860e505991802c09f5f73", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php72": "~1.5" + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.15" }, "conflict": { "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", @@ -5635,11 +6019,6 @@ "Resources/bin/var-dump-server" ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "files": [ "Resources/functions/dump.php" @@ -5671,34 +6050,47 @@ "debug", "dump" ], - "time": "2019-12-18T13:41:29+00:00" + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v4.4.16" + }, + "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-10-26T20:47:51+00:00" }, { "name": "symfony/var-exporter", - "version": "v5.0.2", + "version": "v5.1.8", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "1b9653e68d5b701bf6d9c91bdd3660078c9f4f28" + "reference": "b4048bfc6248413592462c029381bdb2f7b6525f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/1b9653e68d5b701bf6d9c91bdd3660078c9f4f28", - "reference": "1b9653e68d5b701bf6d9c91bdd3660078c9f4f28", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/b4048bfc6248413592462c029381bdb2f7b6525f", + "reference": "b4048bfc6248413592462c029381bdb2f7b6525f", "shasum": "" }, "require": { - "php": "^7.2.5" + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.15" }, "require-dev": { - "symfony/var-dumper": "^4.4|^5.0" + "symfony/var-dumper": "^4.4.9|^5.0.9" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\VarExporter\\": "" @@ -5731,24 +6123,41 @@ "instantiate", "serialize" ], - "time": "2019-12-01T08:48:26+00:00" + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v5.1.8" + }, + "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-10-24T12:01:57+00:00" }, { "name": "symfony/web-profiler-bundle", - "version": "v5.0.2", + "version": "v5.0.11", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "6cc40446060e174a690e0f6da90731133b29b664" + "reference": "3b6dbd2cc76275e117d5c55923c7f511ead22bae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/6cc40446060e174a690e0f6da90731133b29b664", - "reference": "6cc40446060e174a690e0f6da90731133b29b664", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/3b6dbd2cc76275e117d5c55923c7f511ead22bae", + "reference": "3b6dbd2cc76275e117d5c55923c7f511ead22bae", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": ">=7.2.5", "symfony/config": "^4.4|^5.0", "symfony/framework-bundle": "^4.4|^5.0", "symfony/http-kernel": "^4.4|^5.0", @@ -5761,7 +6170,9 @@ "symfony/messenger": "<4.4" }, "require-dev": { + "symfony/browser-kit": "^4.4|^5.0", "symfony/console": "^4.4|^5.0", + "symfony/css-selector": "^4.4|^5.0", "symfony/dependency-injection": "^4.4|^5.0", "symfony/stopwatch": "^4.4|^5.0" }, @@ -5795,24 +6206,41 @@ ], "description": "Symfony WebProfilerBundle", "homepage": "https://symfony.com", - "time": "2019-11-21T07:02:40+00:00" + "support": { + "source": "https://github.com/symfony/web-profiler-bundle/tree/v5.0.11" + }, + "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-23T08:36:09+00:00" }, { "name": "symfony/yaml", - "version": "v4.4.2", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "a08832b974dd5fafe3085a66d41fe4c84bb2628c" + "reference": "543cb4dbd45ed803f08a9a65f27fb149b5dd20c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/a08832b974dd5fafe3085a66d41fe4c84bb2628c", - "reference": "a08832b974dd5fafe3085a66d41fe4c84bb2628c", + "url": "https://api.github.com/repos/symfony/yaml/zipball/543cb4dbd45ed803f08a9a65f27fb149b5dd20c2", + "reference": "543cb4dbd45ed803f08a9a65f27fb149b5dd20c2", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "symfony/polyfill-ctype": "~1.8" }, "conflict": { @@ -5825,11 +6253,6 @@ "symfony/console": "For validating YAML files using the lint command" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Yaml\\": "" @@ -5854,19 +6277,36 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2019-12-10T10:33:21+00:00" + "support": { + "source": "https://github.com/symfony/yaml/tree/v4.4.16" + }, + "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-10-24T11:50:19+00:00" }, { "name": "tightenco/collect", - "version": "v5.8.35", + "version": "v5.8.38", "source": { "type": "git", - "url": "https://github.com/tightenco/collect.git", + "url": "https://github.com/tighten/collect.git", "reference": "c93a7039e6207ad533a09109838fe80933fcc72c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tightenco/collect/zipball/c93a7039e6207ad533a09109838fe80933fcc72c", + "url": "https://api.github.com/repos/tighten/collect/zipball/c93a7039e6207ad533a09109838fe80933fcc72c", "reference": "c93a7039e6207ad533a09109838fe80933fcc72c", "shasum": "" }, @@ -5904,35 +6344,39 @@ "collection", "laravel" ], + "support": { + "issues": "https://github.com/tighten/collect/issues", + "source": "https://github.com/tighten/collect/tree/v5.8.38" + }, "time": "2019-09-17T18:57:01+00:00" }, { "name": "twig/twig", - "version": "v3.0.1", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "28f856a4c57eeb24485916e8a68403f41a133616" + "reference": "b02fa41f3783a2616eccef7b92fbc2343ffed737" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/28f856a4c57eeb24485916e8a68403f41a133616", - "reference": "28f856a4c57eeb24485916e8a68403f41a133616", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/b02fa41f3783a2616eccef7b92fbc2343ffed737", + "reference": "b02fa41f3783a2616eccef7b92fbc2343ffed737", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": ">=7.2.5", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-mbstring": "^1.3" }, "require-dev": { "psr/container": "^1.0", - "symfony/phpunit-bridge": "^4.4|^5.0" + "symfony/phpunit-bridge": "^4.4.9|^5.0.9" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -5966,28 +6410,43 @@ "keywords": [ "templating" ], - "time": "2019-12-28T07:17:28+00:00" + "support": { + "issues": "https://github.com/twigphp/Twig/issues", + "source": "https://github.com/twigphp/Twig/tree/v3.1.1" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2020-10-27T19:28:23+00:00" }, { "name": "webmozart/assert", - "version": "1.6.0", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "573381c0a64f155a0d9a23f4b0c797194805b925" + "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925", - "reference": "573381c0a64f155a0d9a23f4b0c797194805b925", + "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", + "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0", + "php": "^5.3.3 || ^7.0 || ^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "vimeo/psalm": "<3.6.0" + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<3.9.1" }, "require-dev": { "phpunit/phpunit": "^4.8.36 || ^7.5.13" @@ -6014,7 +6473,11 @@ "check", "validate" ], - "time": "2019-11-24T13:36:37+00:00" + "support": { + "issues": "https://github.com/webmozart/assert/issues", + "source": "https://github.com/webmozart/assert/tree/master" + }, + "time": "2020-07-08T17:02:28+00:00" }, { "name": "zendframework/zend-code", @@ -6071,6 +6534,14 @@ "code", "zf" ], + "support": { + "chat": "https://zendframework-slack.herokuapp.com", + "docs": "https://docs.zendframework.com/zend-code/", + "forum": "https://discourse.zendframework.com/c/questions/components", + "issues": "https://github.com/zendframework/zend-code/issues", + "rss": "https://github.com/zendframework/zend-code/releases.atom", + "source": "https://github.com/zendframework/zend-code" + }, "abandoned": "laminas/laminas-code", "time": "2019-12-10T19:21:15+00:00" }, @@ -6126,21 +6597,25 @@ "events", "zf2" ], + "support": { + "issues": "https://github.com/zendframework/zend-eventmanager/issues", + "source": "https://github.com/zendframework/zend-eventmanager/tree/master" + }, "abandoned": "laminas/laminas-eventmanager", "time": "2018-04-25T15:33:34+00:00" }, { "name": "zircote/swagger-php", - "version": "2.0.14", + "version": "2.0.16", "source": { "type": "git", "url": "https://github.com/zircote/swagger-php.git", - "reference": "f2a00f26796e5cd08fd812275ba2db3d1e807663" + "reference": "a25c1bfe508e5f27d5f618648449593a79cbe406" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zircote/swagger-php/zipball/f2a00f26796e5cd08fd812275ba2db3d1e807663", - "reference": "f2a00f26796e5cd08fd812275ba2db3d1e807663", + "url": "https://api.github.com/repos/zircote/swagger-php/zipball/a25c1bfe508e5f27d5f618648449593a79cbe406", + "reference": "a25c1bfe508e5f27d5f618648449593a79cbe406", "shasum": "" }, "require": { @@ -6189,7 +6664,11 @@ "rest", "service discovery" ], - "time": "2019-05-17T10:10:34+00:00" + "support": { + "issues": "https://github.com/zircote/swagger-php/issues", + "source": "https://github.com/zircote/swagger-php/tree/2.0.16" + }, + "time": "2020-05-10T13:42:24+00:00" } ], "packages-dev": [ @@ -6208,6 +6687,7 @@ "phpunit/phpunit": "^7.0", "psy/psysh": "@stable" }, + "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -6231,31 +6711,347 @@ "time": "2018-09-08T09:28:23+00:00" }, { - "name": "symfony/dotenv", - "version": "v4.4.2", + "name": "laminas/laminas-diactoros", + "version": "2.5.0", "source": { "type": "git", - "url": "https://github.com/symfony/dotenv.git", - "reference": "c387ab37887f997162a8579d335b38f328d27859" + "url": "https://github.com/laminas/laminas-diactoros.git", + "reference": "4ff7400c1c12e404144992ef43c8b733fd9ad516" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/c387ab37887f997162a8579d335b38f328d27859", - "reference": "c387ab37887f997162a8579d335b38f328d27859", + "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/4ff7400c1c12e404144992ef43c8b733fd9ad516", + "reference": "4ff7400c1c12e404144992ef43c8b733fd9ad516", "shasum": "" }, "require": { - "php": "^7.1.3" + "laminas/laminas-zendframework-bridge": "^1.0", + "php": "^7.3 || ~8.0.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "conflict": { + "phpspec/prophecy": "<1.9.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "replace": { + "zendframework/zend-diactoros": "^2.2.1" + }, + "require-dev": { + "ext-curl": "*", + "ext-dom": "*", + "ext-gd": "*", + "ext-libxml": "*", + "http-interop/http-factory-tests": "^0.8.0", + "laminas/laminas-coding-standard": "~1.0.0", + "php-http/psr7-integration-tests": "^1.1", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.1" + }, + "type": "library", + "extra": { + "laminas": { + "config-provider": "Laminas\\Diactoros\\ConfigProvider", + "module": "Laminas\\Diactoros" + } + }, + "autoload": { + "files": [ + "src/functions/create_uploaded_file.php", + "src/functions/marshal_headers_from_sapi.php", + "src/functions/marshal_method_from_sapi.php", + "src/functions/marshal_protocol_version_from_sapi.php", + "src/functions/marshal_uri_from_sapi.php", + "src/functions/normalize_server.php", + "src/functions/normalize_uploaded_files.php", + "src/functions/parse_cookie_header.php", + "src/functions/create_uploaded_file.legacy.php", + "src/functions/marshal_headers_from_sapi.legacy.php", + "src/functions/marshal_method_from_sapi.legacy.php", + "src/functions/marshal_protocol_version_from_sapi.legacy.php", + "src/functions/marshal_uri_from_sapi.legacy.php", + "src/functions/normalize_server.legacy.php", + "src/functions/normalize_uploaded_files.legacy.php", + "src/functions/parse_cookie_header.legacy.php" + ], + "psr-4": { + "Laminas\\Diactoros\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "PSR HTTP Message implementations", + "homepage": "https://laminas.dev", + "keywords": [ + "http", + "laminas", + "psr", + "psr-17", + "psr-7" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-diactoros/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-diactoros/issues", + "rss": "https://github.com/laminas/laminas-diactoros/releases.atom", + "source": "https://github.com/laminas/laminas-diactoros" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2020-11-18T18:39:28+00:00" + }, + { + "name": "laminas/laminas-zendframework-bridge", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-zendframework-bridge.git", + "reference": "6ede70583e101030bcace4dcddd648f760ddf642" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/6ede70583e101030bcace4dcddd648f760ddf642", + "reference": "6ede70583e101030bcace4dcddd648f760ddf642", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "extra": { + "laminas": { + "module": "Laminas\\ZendFrameworkBridge" + } + }, + "autoload": { + "files": [ + "src/autoload.php" + ], + "psr-4": { + "Laminas\\ZendFrameworkBridge\\": "src//" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Alias legacy ZF class names to Laminas Project equivalents.", + "keywords": [ + "ZendFramework", + "autoloading", + "laminas", + "zf" + ], + "support": { + "forum": "https://discourse.laminas.dev/", + "issues": "https://github.com/laminas/laminas-zendframework-bridge/issues", + "rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom", + "source": "https://github.com/laminas/laminas-zendframework-bridge" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2020-09-14T14:23:00+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "time": "2019-04-30T12:38:16+00:00" + }, + { + "name": "spiral/goridge", + "version": "v2.4.5", + "source": { + "type": "git", + "url": "https://github.com/spiral/goridge-php.git", + "reference": "a7373de7f86a5452f8ad61bd1340dc158626f7f8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spiral/goridge-php/zipball/a7373de7f86a5452f8ad61bd1340dc158626f7f8", + "reference": "a7373de7f86a5452f8ad61bd1340dc158626f7f8", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=7.2" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.23", + "phpunit/phpunit": "~8.0", + "spiral/code-style": "^1.0" + }, + "type": "goridge", + "autoload": { + "psr-4": { + "Spiral\\Goridge\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anton Titov / Wolfy-J", + "email": "wolfy.jd@gmail.com" + } + ], + "description": "High-performance PHP-to-Golang RPC bridge", + "support": { + "issues": "https://github.com/spiral/goridge-php/issues", + "source": "https://github.com/spiral/goridge-php/tree/v2.4.5" + }, + "time": "2020-08-14T14:28:30+00:00" + }, + { + "name": "spiral/roadrunner", + "version": "v1.8.4", + "source": { + "type": "git", + "url": "https://github.com/spiral/roadrunner.git", + "reference": "561003b0b66a4f767782552a9282d824b08831be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spiral/roadrunner/zipball/561003b0b66a4f767782552a9282d824b08831be", + "reference": "561003b0b66a4f767782552a9282d824b08831be", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "laminas/laminas-diactoros": "^1.3 || ^2.0", + "php": "^7.2", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "spiral/goridge": "^2.4.2", + "symfony/console": "^2.5.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" + }, + "require-dev": { + "phpstan/phpstan": "~0.12" + }, + "bin": [ + "bin/rr" + ], + "type": "server", + "autoload": { + "psr-4": { + "Spiral\\RoadRunner\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anton Titov / Wolfy-J", + "email": "wolfy.jd@gmail.com" + }, + { + "name": "RoadRunner Community", + "homepage": "https://github.com/spiral/roadrunner/graphs/contributors" + } + ], + "description": "High-performance PHP application server, load-balancer and process manager written in Golang", + "support": { + "issues": "https://github.com/spiral/roadrunner/issues", + "source": "https://github.com/spiral/roadrunner/tree/v1.8.4" + }, + "time": "2020-10-21T11:03:49+00:00" + }, + { + "name": "symfony/dotenv", + "version": "v4.4.16", + "source": { + "type": "git", + "url": "https://github.com/symfony/dotenv.git", + "reference": "450e2dad0b42431ad9558bc8adf07e8c4b55d1cd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/450e2dad0b42431ad9558bc8adf07e8c4b55d1cd", + "reference": "450e2dad0b42431ad9558bc8adf07e8c4b55d1cd", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" }, "require-dev": { "symfony/process": "^3.4.2|^4.0|^5.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Dotenv\\": "" @@ -6285,115 +7081,24 @@ "env", "environment" ], - "time": "2019-12-19T15:57:49+00:00" - }, - { - "name": "symfony/process", - "version": "v5.0.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "ea2dc31b59d63abd9bc2356ac72eb7b3f3469f0e" + "support": { + "source": "https://github.com/symfony/dotenv/tree/v4.4.16" }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/ea2dc31b59d63abd9bc2356ac72eb7b3f3469f0e", - "reference": "ea2dc31b59d63abd9bc2356ac72eb7b3f3469f0e", - "shasum": "" - }, - "require": { - "php": "^7.2.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ + "funding": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Process Component", - "homepage": "https://symfony.com", - "time": "2019-12-10T11:06:55+00:00" - }, - { - "name": "symfony/web-server-bundle", - "version": "v4.4.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/web-server-bundle.git", - "reference": "301dad4563b21a791a796da9a736408215b9e9fc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/web-server-bundle/zipball/301dad4563b21a791a796da9a736408215b9e9fc", - "reference": "301dad4563b21a791a796da9a736408215b9e9fc", - "shasum": "" - }, - "require": { - "php": "^7.1.3", - "symfony/config": "^3.4|^4.0|^5.0", - "symfony/console": "^3.4|^4.0|^5.0", - "symfony/dependency-injection": "^3.4|^4.0|^5.0", - "symfony/http-kernel": "^3.4|^4.0|^5.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/process": "^3.4.2|^4.0.2|^5.0" - }, - "suggest": { - "symfony/expression-language": "For using the filter option of the log server.", - "symfony/monolog-bridge": "For using the log server." - }, - "type": "symfony-bundle", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Bundle\\WebServerBundle\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "url": "https://github.com/fabpot", + "type": "github" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "description": "Symfony WebServerBundle", - "homepage": "https://symfony.com", - "time": "2019-11-26T23:16:41+00:00" + "time": "2020-10-24T11:50:19+00:00" } ], "aliases": [], @@ -6412,5 +7117,6 @@ "platform-dev": [], "platform-overrides": { "php": "7.3.12" - } + }, + "plugin-api-version": "2.0.0" } diff --git a/api/config/bundles.php b/api/config/bundles.php index 47980cd..88de49b 100644 --- a/api/config/bundles.php +++ b/api/config/bundles.php @@ -2,7 +2,6 @@ return [ Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], - Symfony\Bundle\WebServerBundle\WebServerBundle::class => ['dev' => true], Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true], Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle::class => ['all' => true], diff --git a/api/symfony.lock b/api/symfony.lock index 6946a9f..8722835 100644 --- a/api/symfony.lock +++ b/api/symfony.lock @@ -307,9 +307,6 @@ "symfony/polyfill-php73": { "version": "v1.13.1" }, - "symfony/process": { - "version": "v4.1.3" - }, "symfony/profiler-pack": { "version": "v1.0.4" }, @@ -384,15 +381,6 @@ "config/routes/dev/web_profiler.yaml" ] }, - "symfony/web-server-bundle": { - "version": "3.3", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "master", - "version": "3.3", - "ref": "dae9b39fd6717970be7601101ce5aa960bf53d9a" - } - }, "symfony/yaml": { "version": "v4.1.3" }, -- 2.45.2 From dbbd397c233e7b26afac5bc0bb5b0db1d6a231d9 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 29 Nov 2020 19:56:16 +0100 Subject: [PATCH 59/77] #50 - Change docker base to alpine linux --- api/.dockerignore | 4 + api/.gitignore | 3 + api/.rr.dev.yaml | 11 + api/.rr.yaml | 13 + api/Dockerfile | 37 - api/composer.json | 10 +- api/composer.lock | 1391 ++++++++++------- api/config/bundles.php | 1 + api/config/packages/baldinof_road_runner.yaml | 18 + api/fpm.Dockerfile | 31 + api/rr.Dockerfile | 24 + api/symfony.lock | 30 +- docker-compose.yml | 4 +- docker/nginx/cojedzie.conf | 5 + 14 files changed, 1007 insertions(+), 575 deletions(-) create mode 100644 api/.dockerignore create mode 100644 api/.rr.dev.yaml create mode 100644 api/.rr.yaml delete mode 100644 api/Dockerfile create mode 100644 api/config/packages/baldinof_road_runner.yaml create mode 100644 api/fpm.Dockerfile create mode 100644 api/rr.Dockerfile diff --git a/api/.dockerignore b/api/.dockerignore new file mode 100644 index 0000000..8ee5090 --- /dev/null +++ b/api/.dockerignore @@ -0,0 +1,4 @@ +/vendor/ +/var/*.db +/var/cache/* +/var/log/ diff --git a/api/.gitignore b/api/.gitignore index cb7bf0d..bc4b385 100644 --- a/api/.gitignore +++ b/api/.gitignore @@ -8,3 +8,6 @@ /public/* !/public/index.php +###> baldinof/roadrunner-bundle ### +/bin/rr +###< baldinof/roadrunner-bundle ### diff --git a/api/.rr.dev.yaml b/api/.rr.dev.yaml new file mode 100644 index 0000000..709cd3d --- /dev/null +++ b/api/.rr.dev.yaml @@ -0,0 +1,11 @@ +include: + - .rr.yaml + +reload: + enabled: true + interval: 1s + patterns: [".php"] + services: + http: + dirs: ["."] + recursive: true diff --git a/api/.rr.yaml b/api/.rr.yaml new file mode 100644 index 0000000..8360a06 --- /dev/null +++ b/api/.rr.yaml @@ -0,0 +1,13 @@ +http: + address: "0.0.0.0:8080" + + uploads: + forbid: [".php", ".exe", ".bat"] + + workers: + command: "php bin/console baldinof:roadrunner:worker" + relay: "unix://var/roadrunner.sock" + +static: + dir: "public" + forbid: [".php", ".htaccess"] diff --git a/api/Dockerfile b/api/Dockerfile deleted file mode 100644 index 27e1b3a..0000000 --- a/api/Dockerfile +++ /dev/null @@ -1,37 +0,0 @@ -FROM php:7.3-fpm - -ARG XDEBUG_REMOTE_HOST="172.17.0.1" - -RUN apt-get update && \ - apt-get install -y --no-install-recommends git zip libzip-dev - -RUN docker-php-ext-install zip - -# XDebug -RUN pecl install xdebug-2.9.0 && docker-php-ext-enable xdebug -RUN echo "xdebug.remote_enable = 1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \ - echo "xdebug.remote_host = ${XDEBUG_REMOTE_HOST}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; - -# Blackfire -RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \ - && curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/amd64/$version \ - && mkdir -p /tmp/blackfire \ - && tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \ - && mv /tmp/blackfire/blackfire-*.so $(php -r "echo ini_get ('extension_dir');")/blackfire.so \ - && printf "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8707\n" > $PHP_INI_DIR/conf.d/blackfire.ini \ - && rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz - -#Composer -RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ - && php composer-setup.php \ - && php -r "unlink('composer-setup.php');" \ - && mv composer.phar /usr/local/bin/composer \ - && chmod +x /usr/local/bin/composer - -# Timezone -RUN ln -snf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime -RUN echo "date.timezone = Europe/Warsaw" >> /usr/local/etc/php/conf.d/datetime.ini; - -WORKDIR /var/www - -EXPOSE 9001 diff --git a/api/composer.json b/api/composer.json index 4b433b5..33a7ea3 100644 --- a/api/composer.json +++ b/api/composer.json @@ -7,15 +7,19 @@ "ext-ctype": "*", "ext-iconv": "*", "ext-json": "*", + "baldinof/roadrunner-bundle": "^1.3", "cerbero/json-objects": "^1.1", "doctrine/doctrine-cache-bundle": "^1.4", "jms/serializer-bundle": "^3.5", + "kadet/functional": "dev-master", "nelmio/api-doc-bundle": "^3.5", "nesbot/carbon": "^1.33", "ocramius/proxy-manager": "^2.0", "sensio/framework-extra-bundle": "^5.2", + "spiral/roadrunner": "^1.8", "symfony/asset": "^4.4", "symfony/console": "^4.4", + "symfony/dotenv": "^4.4", "symfony/flex": "^1.1", "symfony/framework-bundle": "^4.4", "symfony/monolog-bundle": "^3.3", @@ -23,10 +27,7 @@ "symfony/profiler-pack": "^1.0", "symfony/twig-bundle": "^4.4", "symfony/yaml": "^4.4", - "tightenco/collect": "^5.6", - "kadet/functional": "dev-master", - "spiral/roadrunner": "^1.8", - "symfony/dotenv": "^4.4" + "tightenco/collect": "^5.6" }, "config": { "preferred-install": { @@ -43,6 +44,7 @@ "App\\": "src/" }, "files": [ + "vendor/symfony/dependency-injection/Loader/Configurator/ContainerConfigurator.php", "./src/Functions/index.php" ] }, diff --git a/api/composer.lock b/api/composer.lock index def9adb..f32a200 100644 --- a/api/composer.lock +++ b/api/composer.lock @@ -4,8 +4,93 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3a72c43fdf868b0a9b09154437791b3d", + "content-hash": "294e71e4f7c26065cc294792790581e9", "packages": [ + { + "name": "baldinof/roadrunner-bundle", + "version": "1.3.3", + "source": { + "type": "git", + "url": "https://github.com/Baldinof/roadrunner-bundle.git", + "reference": "c377846b5fe7529b207a4b803c91d752a532aa2f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Baldinof/roadrunner-bundle/zipball/c377846b5fe7529b207a4b803c91d752a532aa2f", + "reference": "c377846b5fe7529b207a4b803c91d752a532aa2f", + "shasum": "" + }, + "require": { + "dflydev/fig-cookies": "^2.0", + "php": ">=7.3", + "php-http/discovery": "^1.9", + "psr/http-factory": "^1.0", + "psr/http-factory-implementation": "1.0.0", + "psr/http-server-handler": "^1.0", + "psr/http-server-middleware": "^1.0", + "psr/log": "^1.1", + "spiral/goridge": "^2.0.2", + "spiral/roadrunner": "^1.5", + "symfony/config": "^4.4 || ^5.0", + "symfony/dependency-injection": "^4.4 || ^5.0", + "symfony/http-kernel": "^4.4 || ^5.0", + "symfony/psr-http-message-bridge": "^1.1 || ^2.0", + "symfony/yaml": "^4.4 || ^5.0" + }, + "require-dev": { + "blackfire/php-sdk": "^1.21", + "doctrine/doctrine-bundle": "^2.0", + "doctrine/mongodb-odm-bundle": "^4.1", + "doctrine/orm": "^2.7.3", + "friendsofphp/php-cs-fixer": "^2.16", + "nyholm/psr7": "^1.2", + "ocramius/package-versions": "^1.10 || ^2.0", + "phpspec/prophecy": "^1.11", + "phpspec/prophecy-phpunit": "^2.0", + "phpstan/phpstan": "^0.12.2", + "phpunit/phpunit": "^9.1", + "sentry/sentry-symfony": "^3.4", + "symfony/framework-bundle": "^4.0||^5.0", + "symfony/proxy-manager-bridge": "^4.0 || ^5.0", + "symfony/var-dumper": "^4.0||^5.0" + }, + "suggest": { + "nyholm/psr7": "For a super lightweight PSR-7/17 implementation", + "symfony/proxy-manager-bridge": "For doctrine re-connection implementation" + }, + "type": "symfony-bundle", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Baldinof\\RoadRunnerBundle\\": "src", + "Tests\\Baldinof\\RoadRunnerBundle\\": "tests" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Baldino", + "email": "baldinof@gmail.com" + } + ], + "description": "A RoadRunner worker as a Symfony Bundle", + "support": { + "issues": "https://github.com/Baldinof/roadrunner-bundle/issues", + "source": "https://github.com/Baldinof/roadrunner-bundle/tree/1.3.3" + }, + "funding": [ + { + "url": "https://github.com/Baldinof", + "type": "github" + } + ], + "time": "2020-09-25T09:54:58+00:00" + }, { "name": "cerbero/json-objects", "version": "v1.1.2", @@ -141,6 +226,64 @@ ], "time": "2020-11-11T10:22:58+00:00" }, + { + "name": "dflydev/fig-cookies", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/dflydev/dflydev-fig-cookies.git", + "reference": "733af78ddad60aec96f7c4a1204619dd4d62afff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dflydev/dflydev-fig-cookies/zipball/733af78ddad60aec96f7c4a1204619dd4d62afff", + "reference": "733af78ddad60aec96f7c4a1204619dd4d62afff", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "php": "^7.2", + "psr/http-message": "^1" + }, + "require-dev": { + "doctrine/coding-standard": "^4", + "phpstan/phpstan": "^0.10.1", + "phpunit/phpunit": "^7.2.6", + "squizlabs/php_codesniffer": "^3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Dflydev\\FigCookies\\": "src/Dflydev/FigCookies" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Beau Simensen", + "email": "beau@dflydev.com" + } + ], + "description": "Cookies for PSR-7 HTTP Message Interface.", + "keywords": [ + "cookies", + "psr-7", + "psr7" + ], + "support": { + "issues": "https://github.com/dflydev/dflydev-fig-cookies/issues", + "source": "https://github.com/dflydev/dflydev-fig-cookies/tree/v2.0.1" + }, + "time": "2020-01-02T16:13:22+00:00" + }, { "name": "doctrine/annotations", "version": "1.11.1", @@ -800,6 +943,7 @@ "issues": "https://github.com/doctrine/DoctrineCacheBundle/issues", "source": "https://github.com/doctrine/DoctrineCacheBundle/tree/1.4.0" }, + "abandoned": true, "time": "2019-11-29T11:22:01+00:00" }, { @@ -1941,6 +2085,44 @@ ], "time": "2020-06-28T11:26:21+00:00" }, + { + "name": "kadet/functional", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://git.kadet.net/kadet/functional-php.git", + "reference": "0b58a4c6207d6e7b95902bb81e49b9ec207fc909" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0", + "psy/psysh": "@stable" + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-4": { + "Kadet\\Functional\\": "./src/" + }, + "files": [ + "./src/functions.php", + "./src/Predicates/index.php" + ] + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kacper Donat", + "email": "kadet1090@gmail.com" + } + ], + "description": "Functional library for PHP", + "time": "2018-09-08T09:28:23+00:00" + }, { "name": "kylekatarnls/update-helper", "version": "1.2.1", @@ -2004,6 +2186,166 @@ ], "time": "2020-04-07T20:44:10+00:00" }, + { + "name": "laminas/laminas-diactoros", + "version": "2.5.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-diactoros.git", + "reference": "4ff7400c1c12e404144992ef43c8b733fd9ad516" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/4ff7400c1c12e404144992ef43c8b733fd9ad516", + "reference": "4ff7400c1c12e404144992ef43c8b733fd9ad516", + "shasum": "" + }, + "require": { + "laminas/laminas-zendframework-bridge": "^1.0", + "php": "^7.3 || ~8.0.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "conflict": { + "phpspec/prophecy": "<1.9.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "replace": { + "zendframework/zend-diactoros": "^2.2.1" + }, + "require-dev": { + "ext-curl": "*", + "ext-dom": "*", + "ext-gd": "*", + "ext-libxml": "*", + "http-interop/http-factory-tests": "^0.8.0", + "laminas/laminas-coding-standard": "~1.0.0", + "php-http/psr7-integration-tests": "^1.1", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.1" + }, + "type": "library", + "extra": { + "laminas": { + "config-provider": "Laminas\\Diactoros\\ConfigProvider", + "module": "Laminas\\Diactoros" + } + }, + "autoload": { + "files": [ + "src/functions/create_uploaded_file.php", + "src/functions/marshal_headers_from_sapi.php", + "src/functions/marshal_method_from_sapi.php", + "src/functions/marshal_protocol_version_from_sapi.php", + "src/functions/marshal_uri_from_sapi.php", + "src/functions/normalize_server.php", + "src/functions/normalize_uploaded_files.php", + "src/functions/parse_cookie_header.php", + "src/functions/create_uploaded_file.legacy.php", + "src/functions/marshal_headers_from_sapi.legacy.php", + "src/functions/marshal_method_from_sapi.legacy.php", + "src/functions/marshal_protocol_version_from_sapi.legacy.php", + "src/functions/marshal_uri_from_sapi.legacy.php", + "src/functions/normalize_server.legacy.php", + "src/functions/normalize_uploaded_files.legacy.php", + "src/functions/parse_cookie_header.legacy.php" + ], + "psr-4": { + "Laminas\\Diactoros\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "PSR HTTP Message implementations", + "homepage": "https://laminas.dev", + "keywords": [ + "http", + "laminas", + "psr", + "psr-17", + "psr-7" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-diactoros/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-diactoros/issues", + "rss": "https://github.com/laminas/laminas-diactoros/releases.atom", + "source": "https://github.com/laminas/laminas-diactoros" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2020-11-18T18:39:28+00:00" + }, + { + "name": "laminas/laminas-zendframework-bridge", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-zendframework-bridge.git", + "reference": "6ede70583e101030bcace4dcddd648f760ddf642" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/6ede70583e101030bcace4dcddd648f760ddf642", + "reference": "6ede70583e101030bcace4dcddd648f760ddf642", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "extra": { + "laminas": { + "module": "Laminas\\ZendFrameworkBridge" + } + }, + "autoload": { + "files": [ + "src/autoload.php" + ], + "psr-4": { + "Laminas\\ZendFrameworkBridge\\": "src//" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Alias legacy ZF class names to Laminas Project equivalents.", + "keywords": [ + "ZendFramework", + "autoloading", + "laminas", + "zf" + ], + "support": { + "forum": "https://discourse.laminas.dev/", + "issues": "https://github.com/laminas/laminas-zendframework-bridge/issues", + "rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom", + "source": "https://github.com/laminas/laminas-zendframework-bridge" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2020-09-14T14:23:00+00:00" + }, { "name": "monolog/monolog", "version": "2.1.1", @@ -2333,6 +2675,75 @@ }, "time": "2019-08-10T08:37:15+00:00" }, + { + "name": "php-http/discovery", + "version": "1.13.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/discovery.git", + "reference": "788f72d64c43dc361e7fcc7464c3d947c64984a7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/discovery/zipball/788f72d64c43dc361e7fcc7464c3d947c64984a7", + "reference": "788f72d64c43dc361e7fcc7464c3d947c64984a7", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "nyholm/psr7": "<1.0" + }, + "require-dev": { + "graham-campbell/phpspec-skip-example-extension": "^5.0", + "php-http/httplug": "^1.0 || ^2.0", + "php-http/message-factory": "^1.0", + "phpspec/phpspec": "^5.1 || ^6.1", + "puli/composer-plugin": "1.0.0-beta10" + }, + "suggest": { + "php-http/message": "Allow to use Guzzle, Diactoros or Slim Framework factories", + "puli/composer-plugin": "Sets up Puli which is recommended for Discovery to work. Check http://docs.php-http.org/en/latest/discovery.html for more details." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Discovery\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Finds installed HTTPlug implementations and PSR-7 message factories", + "homepage": "http://php-http.org", + "keywords": [ + "adapter", + "client", + "discovery", + "factory", + "http", + "message", + "psr7" + ], + "support": { + "issues": "https://github.com/php-http/discovery/issues", + "source": "https://github.com/php-http/discovery/tree/1.13.0" + }, + "time": "2020-11-27T14:49:42+00:00" + }, { "name": "phpdocumentor/reflection-common", "version": "2.2.0", @@ -2593,6 +3004,61 @@ }, "time": "2017-02-14T16:28:37+00:00" }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "time": "2019-04-30T12:38:16+00:00" + }, { "name": "psr/http-message", "version": "1.0.1", @@ -2646,6 +3112,120 @@ }, "time": "2016-08-06T14:39:51+00:00" }, + { + "name": "psr/http-server-handler", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-handler.git", + "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/aff2f80e33b7f026ec96bb42f63242dc50ffcae7", + "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side request handler", + "keywords": [ + "handler", + "http", + "http-interop", + "psr", + "psr-15", + "psr-7", + "request", + "response", + "server" + ], + "support": { + "issues": "https://github.com/php-fig/http-server-handler/issues", + "source": "https://github.com/php-fig/http-server-handler/tree/master" + }, + "time": "2018-10-30T16:46:14+00:00" + }, + { + "name": "psr/http-server-middleware", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-middleware.git", + "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/2296f45510945530b9dceb8bcedb5cb84d40c5f5", + "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0", + "psr/http-server-handler": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side middleware", + "keywords": [ + "http", + "http-interop", + "middleware", + "psr", + "psr-15", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-server-middleware/issues", + "source": "https://github.com/php-fig/http-server-middleware/tree/master" + }, + "time": "2018-10-30T17:12:04+00:00" + }, { "name": "psr/log", "version": "1.1.3", @@ -2847,6 +3427,112 @@ }, "time": "2020-08-25T19:10:18+00:00" }, + { + "name": "spiral/goridge", + "version": "v2.4.5", + "source": { + "type": "git", + "url": "https://github.com/spiral/goridge-php.git", + "reference": "a7373de7f86a5452f8ad61bd1340dc158626f7f8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spiral/goridge-php/zipball/a7373de7f86a5452f8ad61bd1340dc158626f7f8", + "reference": "a7373de7f86a5452f8ad61bd1340dc158626f7f8", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=7.2" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.23", + "phpunit/phpunit": "~8.0", + "spiral/code-style": "^1.0" + }, + "type": "goridge", + "autoload": { + "psr-4": { + "Spiral\\Goridge\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anton Titov / Wolfy-J", + "email": "wolfy.jd@gmail.com" + } + ], + "description": "High-performance PHP-to-Golang RPC bridge", + "support": { + "issues": "https://github.com/spiral/goridge-php/issues", + "source": "https://github.com/spiral/goridge-php/tree/v2.4.5" + }, + "time": "2020-08-14T14:28:30+00:00" + }, + { + "name": "spiral/roadrunner", + "version": "v1.8.4", + "source": { + "type": "git", + "url": "https://github.com/spiral/roadrunner.git", + "reference": "561003b0b66a4f767782552a9282d824b08831be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spiral/roadrunner/zipball/561003b0b66a4f767782552a9282d824b08831be", + "reference": "561003b0b66a4f767782552a9282d824b08831be", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "laminas/laminas-diactoros": "^1.3 || ^2.0", + "php": "^7.2", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "spiral/goridge": "^2.4.2", + "symfony/console": "^2.5.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" + }, + "require-dev": { + "phpstan/phpstan": "~0.12" + }, + "bin": [ + "bin/rr" + ], + "type": "server", + "autoload": { + "psr-4": { + "Spiral\\RoadRunner\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anton Titov / Wolfy-J", + "email": "wolfy.jd@gmail.com" + }, + { + "name": "RoadRunner Community", + "homepage": "https://github.com/spiral/roadrunner/graphs/contributors" + } + ], + "description": "High-performance PHP application server, load-balancer and process manager written in Golang", + "support": { + "issues": "https://github.com/spiral/roadrunner/issues", + "source": "https://github.com/spiral/roadrunner/tree/v1.8.4" + }, + "time": "2020-10-21T11:03:49+00:00" + }, { "name": "symfony/asset", "version": "v4.4.16", @@ -3584,6 +4270,75 @@ ], "time": "2020-10-24T11:50:19+00:00" }, + { + "name": "symfony/dotenv", + "version": "v4.4.16", + "source": { + "type": "git", + "url": "https://github.com/symfony/dotenv.git", + "reference": "450e2dad0b42431ad9558bc8adf07e8c4b55d1cd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/450e2dad0b42431ad9558bc8adf07e8c4b55d1cd", + "reference": "450e2dad0b42431ad9558bc8adf07e8c4b55d1cd", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "require-dev": { + "symfony/process": "^3.4.2|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Dotenv\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Registers environment variables from a .env file", + "homepage": "https://symfony.com", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "source": "https://github.com/symfony/dotenv/tree/v4.4.16" + }, + "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-10-24T11:50:19+00:00" + }, { "name": "symfony/error-handler", "version": "v4.4.16", @@ -4926,82 +5681,6 @@ ], "time": "2020-10-23T14:02:19+00:00" }, - { - "name": "symfony/polyfill-php72", - "version": "v1.20.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cede45fcdfabdd6043b3592e83678e42ec69e930", - "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.20-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "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.2+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.20.0" - }, - "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-10-23T14:02:19+00:00" - }, { "name": "symfony/polyfill-php73", "version": "v1.20.0", @@ -5298,6 +5977,88 @@ ], "time": "2020-10-24T12:01:57+00:00" }, + { + "name": "symfony/psr-http-message-bridge", + "version": "v2.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/psr-http-message-bridge.git", + "reference": "51a21cb3ba3927d4b4bf8f25cc55763351af5f2e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/51a21cb3ba3927d4b4bf8f25cc55763351af5f2e", + "reference": "51a21cb3ba3927d4b4bf8f25cc55763351af5f2e", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0", + "symfony/http-foundation": "^4.4 || ^5.0" + }, + "require-dev": { + "nyholm/psr7": "^1.1", + "symfony/phpunit-bridge": "^4.4 || ^5.0" + }, + "suggest": { + "nyholm/psr7": "For a super lightweight PSR-7/17 implementation" + }, + "type": "symfony-bridge", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bridge\\PsrHttpMessage\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "PSR HTTP message bridge", + "homepage": "http://symfony.com", + "keywords": [ + "http", + "http-message", + "psr-17", + "psr-7" + ], + "support": { + "issues": "https://github.com/symfony/psr-http-message-bridge/issues", + "source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.0.2" + }, + "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-09-29T08:17:46+00:00" + }, { "name": "symfony/routing", "version": "v5.1.8", @@ -5982,33 +6743,32 @@ }, { "name": "symfony/var-dumper", - "version": "v4.4.16", + "version": "v5.1.8", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "3718e18b68d955348ad860e505991802c09f5f73" + "reference": "4e13f3fcefb1fcaaa5efb5403581406f4e840b9a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3718e18b68d955348ad860e505991802c09f5f73", - "reference": "3718e18b68d955348ad860e505991802c09f5f73", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/4e13f3fcefb1fcaaa5efb5403581406f4e840b9a", + "reference": "4e13f3fcefb1fcaaa5efb5403581406f4e840b9a", "shasum": "" }, "require": { - "php": ">=7.1.3", + "php": ">=7.2.5", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php72": "~1.5", "symfony/polyfill-php80": "^1.15" }, "conflict": { - "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", - "symfony/console": "<3.4" + "phpunit/phpunit": "<5.4.3", + "symfony/console": "<4.4" }, "require-dev": { "ext-iconv": "*", - "symfony/console": "^3.4|^4.0|^5.0", + "symfony/console": "^4.4|^5.0", "symfony/process": "^4.4|^5.0", - "twig/twig": "^1.34|^2.4|^3.0" + "twig/twig": "^2.4|^3.0" }, "suggest": { "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", @@ -6051,7 +6811,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v4.4.16" + "source": "https://github.com/symfony/var-dumper/tree/v5.1.8" }, "funding": [ { @@ -6067,7 +6827,7 @@ "type": "tidelift" } ], - "time": "2020-10-26T20:47:51+00:00" + "time": "2020-10-27T10:11:13+00:00" }, { "name": "symfony/var-exporter", @@ -6298,26 +7058,26 @@ }, { "name": "tightenco/collect", - "version": "v5.8.38", + "version": "v5.6.33", "source": { "type": "git", "url": "https://github.com/tighten/collect.git", - "reference": "c93a7039e6207ad533a09109838fe80933fcc72c" + "reference": "d7381736dca44ac17d0805a25191b094e5a22446" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tighten/collect/zipball/c93a7039e6207ad533a09109838fe80933fcc72c", - "reference": "c93a7039e6207ad533a09109838fe80933fcc72c", + "url": "https://api.github.com/repos/tighten/collect/zipball/d7381736dca44ac17d0805a25191b094e5a22446", + "reference": "d7381736dca44ac17d0805a25191b094e5a22446", "shasum": "" }, "require": { - "php": "^7.1.3", - "symfony/var-dumper": ">=3.4 <5" + "php": ">=7.1.3", + "symfony/var-dumper": ">=3.1.10" }, "require-dev": { - "mockery/mockery": "^1.0", - "nesbot/carbon": "^1.26.3", - "phpunit/phpunit": "^7.0" + "mockery/mockery": "~1.0", + "nesbot/carbon": "~1.20", + "phpunit/phpunit": "~7.0" }, "type": "library", "autoload": { @@ -6346,9 +7106,9 @@ ], "support": { "issues": "https://github.com/tighten/collect/issues", - "source": "https://github.com/tighten/collect/tree/v5.8.38" + "source": "https://github.com/tighten/collect/tree/v5.6.33" }, - "time": "2019-09-17T18:57:01+00:00" + "time": "2018-08-09T16:56:26+00:00" }, { "name": "twig/twig", @@ -6671,436 +7431,7 @@ "time": "2020-05-10T13:42:24+00:00" } ], - "packages-dev": [ - { - "name": "kadet/functional", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://git.kadet.net/kadet/functional-php.git", - "reference": "0b58a4c6207d6e7b95902bb81e49b9ec207fc909" - }, - "require": { - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0", - "psy/psysh": "@stable" - }, - "default-branch": true, - "type": "library", - "autoload": { - "psr-4": { - "Kadet\\Functional\\": "./src/" - }, - "files": [ - "./src/functions.php", - "./src/Predicates/index.php" - ] - }, - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kacper Donat", - "email": "kadet1090@gmail.com" - } - ], - "description": "Functional library for PHP", - "time": "2018-09-08T09:28:23+00:00" - }, - { - "name": "laminas/laminas-diactoros", - "version": "2.5.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-diactoros.git", - "reference": "4ff7400c1c12e404144992ef43c8b733fd9ad516" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/4ff7400c1c12e404144992ef43c8b733fd9ad516", - "reference": "4ff7400c1c12e404144992ef43c8b733fd9ad516", - "shasum": "" - }, - "require": { - "laminas/laminas-zendframework-bridge": "^1.0", - "php": "^7.3 || ~8.0.0", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.0" - }, - "conflict": { - "phpspec/prophecy": "<1.9.0" - }, - "provide": { - "psr/http-factory-implementation": "1.0", - "psr/http-message-implementation": "1.0" - }, - "replace": { - "zendframework/zend-diactoros": "^2.2.1" - }, - "require-dev": { - "ext-curl": "*", - "ext-dom": "*", - "ext-gd": "*", - "ext-libxml": "*", - "http-interop/http-factory-tests": "^0.8.0", - "laminas/laminas-coding-standard": "~1.0.0", - "php-http/psr7-integration-tests": "^1.1", - "phpspec/prophecy-phpunit": "^2.0", - "phpunit/phpunit": "^9.1" - }, - "type": "library", - "extra": { - "laminas": { - "config-provider": "Laminas\\Diactoros\\ConfigProvider", - "module": "Laminas\\Diactoros" - } - }, - "autoload": { - "files": [ - "src/functions/create_uploaded_file.php", - "src/functions/marshal_headers_from_sapi.php", - "src/functions/marshal_method_from_sapi.php", - "src/functions/marshal_protocol_version_from_sapi.php", - "src/functions/marshal_uri_from_sapi.php", - "src/functions/normalize_server.php", - "src/functions/normalize_uploaded_files.php", - "src/functions/parse_cookie_header.php", - "src/functions/create_uploaded_file.legacy.php", - "src/functions/marshal_headers_from_sapi.legacy.php", - "src/functions/marshal_method_from_sapi.legacy.php", - "src/functions/marshal_protocol_version_from_sapi.legacy.php", - "src/functions/marshal_uri_from_sapi.legacy.php", - "src/functions/normalize_server.legacy.php", - "src/functions/normalize_uploaded_files.legacy.php", - "src/functions/parse_cookie_header.legacy.php" - ], - "psr-4": { - "Laminas\\Diactoros\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "PSR HTTP Message implementations", - "homepage": "https://laminas.dev", - "keywords": [ - "http", - "laminas", - "psr", - "psr-17", - "psr-7" - ], - "support": { - "chat": "https://laminas.dev/chat", - "docs": "https://docs.laminas.dev/laminas-diactoros/", - "forum": "https://discourse.laminas.dev", - "issues": "https://github.com/laminas/laminas-diactoros/issues", - "rss": "https://github.com/laminas/laminas-diactoros/releases.atom", - "source": "https://github.com/laminas/laminas-diactoros" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2020-11-18T18:39:28+00:00" - }, - { - "name": "laminas/laminas-zendframework-bridge", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-zendframework-bridge.git", - "reference": "6ede70583e101030bcace4dcddd648f760ddf642" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/6ede70583e101030bcace4dcddd648f760ddf642", - "reference": "6ede70583e101030bcace4dcddd648f760ddf642", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3", - "squizlabs/php_codesniffer": "^3.5" - }, - "type": "library", - "extra": { - "laminas": { - "module": "Laminas\\ZendFrameworkBridge" - } - }, - "autoload": { - "files": [ - "src/autoload.php" - ], - "psr-4": { - "Laminas\\ZendFrameworkBridge\\": "src//" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Alias legacy ZF class names to Laminas Project equivalents.", - "keywords": [ - "ZendFramework", - "autoloading", - "laminas", - "zf" - ], - "support": { - "forum": "https://discourse.laminas.dev/", - "issues": "https://github.com/laminas/laminas-zendframework-bridge/issues", - "rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom", - "source": "https://github.com/laminas/laminas-zendframework-bridge" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2020-09-14T14:23:00+00:00" - }, - { - "name": "psr/http-factory", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-factory.git", - "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", - "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", - "shasum": "" - }, - "require": { - "php": ">=7.0.0", - "psr/http-message": "^1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interfaces for PSR-7 HTTP message factories", - "keywords": [ - "factory", - "http", - "message", - "psr", - "psr-17", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-factory/tree/master" - }, - "time": "2019-04-30T12:38:16+00:00" - }, - { - "name": "spiral/goridge", - "version": "v2.4.5", - "source": { - "type": "git", - "url": "https://github.com/spiral/goridge-php.git", - "reference": "a7373de7f86a5452f8ad61bd1340dc158626f7f8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/spiral/goridge-php/zipball/a7373de7f86a5452f8ad61bd1340dc158626f7f8", - "reference": "a7373de7f86a5452f8ad61bd1340dc158626f7f8", - "shasum": "" - }, - "require": { - "ext-json": "*", - "php": ">=7.2" - }, - "require-dev": { - "phpstan/phpstan": "^0.12.23", - "phpunit/phpunit": "~8.0", - "spiral/code-style": "^1.0" - }, - "type": "goridge", - "autoload": { - "psr-4": { - "Spiral\\Goridge\\": "src/" - }, - "files": [ - "src/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Anton Titov / Wolfy-J", - "email": "wolfy.jd@gmail.com" - } - ], - "description": "High-performance PHP-to-Golang RPC bridge", - "support": { - "issues": "https://github.com/spiral/goridge-php/issues", - "source": "https://github.com/spiral/goridge-php/tree/v2.4.5" - }, - "time": "2020-08-14T14:28:30+00:00" - }, - { - "name": "spiral/roadrunner", - "version": "v1.8.4", - "source": { - "type": "git", - "url": "https://github.com/spiral/roadrunner.git", - "reference": "561003b0b66a4f767782552a9282d824b08831be" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/spiral/roadrunner/zipball/561003b0b66a4f767782552a9282d824b08831be", - "reference": "561003b0b66a4f767782552a9282d824b08831be", - "shasum": "" - }, - "require": { - "ext-curl": "*", - "ext-json": "*", - "laminas/laminas-diactoros": "^1.3 || ^2.0", - "php": "^7.2", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.0", - "spiral/goridge": "^2.4.2", - "symfony/console": "^2.5.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" - }, - "require-dev": { - "phpstan/phpstan": "~0.12" - }, - "bin": [ - "bin/rr" - ], - "type": "server", - "autoload": { - "psr-4": { - "Spiral\\RoadRunner\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Anton Titov / Wolfy-J", - "email": "wolfy.jd@gmail.com" - }, - { - "name": "RoadRunner Community", - "homepage": "https://github.com/spiral/roadrunner/graphs/contributors" - } - ], - "description": "High-performance PHP application server, load-balancer and process manager written in Golang", - "support": { - "issues": "https://github.com/spiral/roadrunner/issues", - "source": "https://github.com/spiral/roadrunner/tree/v1.8.4" - }, - "time": "2020-10-21T11:03:49+00:00" - }, - { - "name": "symfony/dotenv", - "version": "v4.4.16", - "source": { - "type": "git", - "url": "https://github.com/symfony/dotenv.git", - "reference": "450e2dad0b42431ad9558bc8adf07e8c4b55d1cd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/450e2dad0b42431ad9558bc8adf07e8c4b55d1cd", - "reference": "450e2dad0b42431ad9558bc8adf07e8c4b55d1cd", - "shasum": "" - }, - "require": { - "php": ">=7.1.3" - }, - "require-dev": { - "symfony/process": "^3.4.2|^4.0|^5.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Dotenv\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Registers environment variables from a .env file", - "homepage": "https://symfony.com", - "keywords": [ - "dotenv", - "env", - "environment" - ], - "support": { - "source": "https://github.com/symfony/dotenv/tree/v4.4.16" - }, - "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-10-24T11:50:19+00:00" - } - ], + "packages-dev": [], "aliases": [], "minimum-stability": "stable", "stability-flags": { diff --git a/api/config/bundles.php b/api/config/bundles.php index 88de49b..3e39222 100644 --- a/api/config/bundles.php +++ b/api/config/bundles.php @@ -11,4 +11,5 @@ return [ Nelmio\ApiDocBundle\NelmioApiDocBundle::class => ['all' => true], JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true], Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], + Baldinof\RoadRunnerBundle\BaldinofRoadRunnerBundle::class => ['all' => true], ]; diff --git a/api/config/packages/baldinof_road_runner.yaml b/api/config/packages/baldinof_road_runner.yaml new file mode 100644 index 0000000..65267f3 --- /dev/null +++ b/api/config/packages/baldinof_road_runner.yaml @@ -0,0 +1,18 @@ +baldinof_road_runner: + # The kernel is preserved between requests. Change this to `true` + # if you want to reboot it, and use a fresh container on each request. + should_reboot_kernel: false + + # Integrations are automatically detected, depending on installed bundle & current configuration + # See https://github.com/baldinof/roadrunner-bundle#integrations + default_integrations: true + + # Allow to send prometheus metrics to the master RoadRunner process, + # via a `Spiral\RoadRunner\MetricsInterface` service. + # See https://github.com/baldinof/roadrunner-bundle#metrics + metrics_enabled: false + + # You can use middlewares to manipulate PSR requests & responses. + # See https://github.com/baldinof/roadrunner-bundle#middlewares + # middlewares: + # - App\Middleware\YourMiddleware diff --git a/api/fpm.Dockerfile b/api/fpm.Dockerfile new file mode 100644 index 0000000..386ae2d --- /dev/null +++ b/api/fpm.Dockerfile @@ -0,0 +1,31 @@ +FROM php:7.4-fpm-alpine + +RUN apk add --no-cache autoconf openssl-dev g++ make pcre-dev icu-dev zlib-dev libzip-dev git && \ + docker-php-ext-install bcmath intl opcache zip sockets; + +# XDebug +RUN pecl install xdebug-3.0.0 && docker-php-ext-enable xdebug +RUN echo "xdebug.mode = develop,debug" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \ + echo "xdebug.discover_client_host = On" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; + +RUN apk del --purge autoconf g++ make + +# Blackfire +RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \ + && curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/amd64/$version \ + && mkdir -p /tmp/blackfire \ + && tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \ + && mv /tmp/blackfire/blackfire-*.so $(php -r "echo ini_get ('extension_dir');")/blackfire.so \ + && printf "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8707\n" > $PHP_INI_DIR/conf.d/blackfire.ini \ + && rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz + +#Composer +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +# Timezone +RUN ln -snf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime && + echo "date.timezone = Europe/Warsaw" >> /usr/local/etc/php/conf.d/datetime.ini; + +WORKDIR /var/www + +EXPOSE 9001 diff --git a/api/rr.Dockerfile b/api/rr.Dockerfile new file mode 100644 index 0000000..8bebd41 --- /dev/null +++ b/api/rr.Dockerfile @@ -0,0 +1,24 @@ +FROM php:7.4-alpine + +RUN apk add --no-cache autoconf openssl-dev g++ make pcre-dev icu-dev zlib-dev libzip-dev git && \ + docker-php-ext-install bcmath intl opcache zip sockets && \ + apk del --purge autoconf g++ make + +WORKDIR /usr/src/app + +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer +COPY . . + +RUN composer install --no-dev --no-scripts --no-plugins --prefer-dist --no-progress --no-interaction +RUN ./vendor/bin/rr get-binary --location /usr/local/bin + +ENV APP_ENV=prod +ENV DATABASE_URL="sqlite:///var/db/app.db" + +RUN composer dump-autoload --optimize && \ + composer check-platform-reqs && \ + php bin/console cache:warmup + +EXPOSE 8080 + +CMD ["rr", "serve"] diff --git a/api/symfony.lock b/api/symfony.lock index 8722835..b6915e2 100644 --- a/api/symfony.lock +++ b/api/symfony.lock @@ -1,7 +1,22 @@ { + "baldinof/roadrunner-bundle": { + "version": "1.2", + "recipe": { + "repo": "github.com/symfony/recipes-contrib", + "branch": "master", + "version": "1.2", + "ref": "47c159c44eb9e6902828da4acbb4199757dd378f" + }, + "files": [ + "config/packages/baldinof_road_runner.yaml" + ] + }, "cerbero/json-objects": { "version": "v1.1.2" }, + "dflydev/fig-cookies": { + "version": "v2.0.1" + }, "doctrine/annotations": { "version": "1.0", "recipe": { @@ -163,6 +178,9 @@ "php": { "version": "7.3.12" }, + "php-http/discovery": { + "version": "1.13.0" + }, "phpdocumentor/reflection-common": { "version": "1.0.1" }, @@ -181,6 +199,12 @@ "psr/http-message": { "version": "1.0.1" }, + "psr/http-server-handler": { + "version": "1.0.1" + }, + "psr/http-server-middleware": { + "version": "1.0.1" + }, "psr/log": { "version": "1.0.2" }, @@ -301,9 +325,6 @@ "symfony/polyfill-mbstring": { "version": "v1.9.0" }, - "symfony/polyfill-php72": { - "version": "v1.9.0" - }, "symfony/polyfill-php73": { "version": "v1.13.1" }, @@ -316,6 +337,9 @@ "symfony/property-info": { "version": "v4.1.3" }, + "symfony/psr-http-message-bridge": { + "version": "v2.0.2" + }, "symfony/routing": { "version": "4.0", "recipe": { diff --git a/docker-compose.yml b/docker-compose.yml index 5b7ca4b..85f2b9c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,9 @@ services: - ./docker/nginx/cojedzie.conf:/etc/nginx/conf.d/cojedzie.conf api: - build: ./api + build: + context: ./api + dockerfile: fpm.Dockerfile env_file: - ./docker/php/.env volumes: diff --git a/docker/nginx/cojedzie.conf b/docker/nginx/cojedzie.conf index 83bad87..b60243d 100644 --- a/docker/nginx/cojedzie.conf +++ b/docker/nginx/cojedzie.conf @@ -7,6 +7,11 @@ server { try_files $uri $uri/ index.php$is_args$args; } + location /_profiler/ { + root /var/www/api/public/; + try_files $uri $uri/ index.php$is_args$args; + } + location /bundles/ { root /var/www/api/public/; try_files $uri $uri/; -- 2.45.2 From bf5cadb13486eeb0c7871f0e5a1e6d26f53b749a Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 29 Nov 2020 23:50:57 +0100 Subject: [PATCH 60/77] #50 - Create dev docker api image --- api/.dockerignore | 4 +--- api/dev.Dockerfile | 34 ++++++++++++++++++++++++++++++++++ api/fpm.Dockerfile | 29 +++++++++++------------------ api/rr.Dockerfile | 6 +++--- api/symfony.lock | 39 +++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 2 +- 6 files changed, 89 insertions(+), 25 deletions(-) create mode 100644 api/dev.Dockerfile diff --git a/api/.dockerignore b/api/.dockerignore index 8ee5090..768d5ef 100644 --- a/api/.dockerignore +++ b/api/.dockerignore @@ -1,4 +1,2 @@ /vendor/ -/var/*.db -/var/cache/* -/var/log/ +/var/ diff --git a/api/dev.Dockerfile b/api/dev.Dockerfile new file mode 100644 index 0000000..5db7050 --- /dev/null +++ b/api/dev.Dockerfile @@ -0,0 +1,34 @@ +FROM php:7.4-fpm-alpine + +ENV APP_ENV=dev +ENV DATABASE_URL="sqlite:///var/db/app.db" + +RUN apk add --no-cache autoconf openssl-dev g++ make pcre-dev icu-dev zlib-dev libzip-dev git && \ + docker-php-ext-install bcmath intl opcache zip sockets; + +# XDebug +RUN pecl install xdebug-3.0.0 && docker-php-ext-enable xdebug +RUN echo "xdebug.mode = develop,debug" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \ + echo "xdebug.discover_client_host = On" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; + +RUN apk del --purge autoconf g++ make + +# Blackfire +RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \ + && curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/amd64/$version \ + && mkdir -p /tmp/blackfire \ + && tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \ + && mv /tmp/blackfire/blackfire-*.so $(php -r "echo ini_get ('extension_dir');")/blackfire.so \ + && printf "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8707\n" > $PHP_INI_DIR/conf.d/blackfire.ini \ + && rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz + +#Composer +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +# Timezone +RUN ln -snf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime && + echo "date.timezone = Europe/Warsaw" >> /usr/local/etc/php/conf.d/datetime.ini; + +WORKDIR /var/www + +EXPOSE 9001 diff --git a/api/fpm.Dockerfile b/api/fpm.Dockerfile index 386ae2d..d3b9fe2 100644 --- a/api/fpm.Dockerfile +++ b/api/fpm.Dockerfile @@ -1,26 +1,19 @@ FROM php:7.4-fpm-alpine +ENV APP_ENV=prod +ENV DATABASE_URL="sqlite:///var/db/app.db" + RUN apk add --no-cache autoconf openssl-dev g++ make pcre-dev icu-dev zlib-dev libzip-dev git && \ - docker-php-ext-install bcmath intl opcache zip sockets; + docker-php-ext-install bcmath intl opcache zip sockets && \ + apk del --purge autoconf g++ make; -# XDebug -RUN pecl install xdebug-3.0.0 && docker-php-ext-enable xdebug -RUN echo "xdebug.mode = develop,debug" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \ - echo "xdebug.discover_client_host = On" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; - -RUN apk del --purge autoconf g++ make - -# Blackfire -RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \ - && curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/amd64/$version \ - && mkdir -p /tmp/blackfire \ - && tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \ - && mv /tmp/blackfire/blackfire-*.so $(php -r "echo ini_get ('extension_dir');")/blackfire.so \ - && printf "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8707\n" > $PHP_INI_DIR/conf.d/blackfire.ini \ - && rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz - -#Composer COPY --from=composer:latest /usr/bin/composer /usr/bin/composer +COPY . . + +RUN composer install --no-dev --no-scripts --no-plugins --prefer-dist --no-progress --no-interaction && \ + composer dump-autoload --optimize && \ + composer check-platform-reqs && \ + php bin/console cache:warmup # Timezone RUN ln -snf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime && diff --git a/api/rr.Dockerfile b/api/rr.Dockerfile index 8bebd41..59b914f 100644 --- a/api/rr.Dockerfile +++ b/api/rr.Dockerfile @@ -1,5 +1,8 @@ FROM php:7.4-alpine +ENV APP_ENV=prod +ENV DATABASE_URL="sqlite:///var/db/app.db" + RUN apk add --no-cache autoconf openssl-dev g++ make pcre-dev icu-dev zlib-dev libzip-dev git && \ docker-php-ext-install bcmath intl opcache zip sockets && \ apk del --purge autoconf g++ make @@ -12,9 +15,6 @@ COPY . . RUN composer install --no-dev --no-scripts --no-plugins --prefer-dist --no-progress --no-interaction RUN ./vendor/bin/rr get-binary --location /usr/local/bin -ENV APP_ENV=prod -ENV DATABASE_URL="sqlite:///var/db/app.db" - RUN composer dump-autoload --optimize && \ composer check-platform-reqs && \ php bin/console cache:warmup diff --git a/api/symfony.lock b/api/symfony.lock index b6915e2..c2bc392 100644 --- a/api/symfony.lock +++ b/api/symfony.lock @@ -14,6 +14,9 @@ "cerbero/json-objects": { "version": "v1.1.2" }, + "composer/package-versions-deprecated": { + "version": "1.11.99.1" + }, "dflydev/fig-cookies": { "version": "v2.0.1" }, @@ -83,6 +86,9 @@ "doctrine/reflection": { "version": "v1.0.0" }, + "doctrine/sql-formatter": { + "version": "1.1.1" + }, "exsyst/swagger": { "version": "v0.4.1" }, @@ -154,6 +160,12 @@ "kylekatarnls/update-helper": { "version": "1.2.0" }, + "laminas/laminas-diactoros": { + "version": "2.5.0" + }, + "laminas/laminas-zendframework-bridge": { + "version": "1.1.1" + }, "monolog/monolog": { "version": "1.23.0" }, @@ -196,6 +208,9 @@ "psr/container": { "version": "1.0.0" }, + "psr/http-factory": { + "version": "1.0.1" + }, "psr/http-message": { "version": "1.0.1" }, @@ -223,6 +238,12 @@ "ref": "fb7e19da7f013d0d422fa9bce16f5c510e27609b" } }, + "spiral/goridge": { + "version": "v2.4.5" + }, + "spiral/roadrunner": { + "version": "v1.8.4" + }, "symfony/asset": { "version": "v4.1.4" }, @@ -250,6 +271,9 @@ "symfony/dependency-injection": { "version": "v4.1.3" }, + "symfony/deprecation-contracts": { + "version": "v2.2.0" + }, "symfony/doctrine-bridge": { "version": "v4.1.4" }, @@ -289,6 +313,9 @@ "ref": "87c585d24de9f43bca80ebcfd5cf5cb39445d95f" } }, + "symfony/http-client-contracts": { + "version": "v2.3.1" + }, "symfony/http-foundation": { "version": "v4.1.3" }, @@ -319,15 +346,24 @@ "symfony/orm-pack": { "version": "v1.0.5" }, + "symfony/polyfill-intl-grapheme": { + "version": "v1.20.0" + }, "symfony/polyfill-intl-idn": { "version": "v1.13.1" }, + "symfony/polyfill-intl-normalizer": { + "version": "v1.20.0" + }, "symfony/polyfill-mbstring": { "version": "v1.9.0" }, "symfony/polyfill-php73": { "version": "v1.13.1" }, + "symfony/polyfill-php80": { + "version": "v1.20.0" + }, "symfony/profiler-pack": { "version": "v1.0.4" }, @@ -361,6 +397,9 @@ "symfony/stopwatch": { "version": "v4.1.12" }, + "symfony/string": { + "version": "v5.1.8" + }, "symfony/translation": { "version": "3.3", "recipe": { diff --git a/docker-compose.yml b/docker-compose.yml index 85f2b9c..7fe3baa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,7 +13,7 @@ services: api: build: context: ./api - dockerfile: fpm.Dockerfile + dockerfile: dev.Dockerfile env_file: - ./docker/php/.env volumes: -- 2.45.2 From 9cf50b988a0dcedbd5d7b6879ef74945b1d0ca41 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Mon, 30 Nov 2020 00:21:41 +0100 Subject: [PATCH 61/77] #50 - Fix symfony version to 4.4 --- api/{.env.dist => .env} | 13 +- api/.gitignore | 5 +- api/composer.json | 3 +- api/composer.lock | 945 +++++++++--------- api/config/bootstrap.php | 23 + api/config/packages/cache.yaml | 19 + api/config/packages/doctrine.yaml | 11 +- api/config/packages/doctrine_migrations.yaml | 4 +- api/config/packages/framework.yaml | 26 +- api/config/packages/prod/doctrine.yaml | 25 +- api/config/packages/test/twig.yaml | 2 + api/config/packages/twig.yaml | 3 +- api/config/preload.php | 9 + api/dev.Dockerfile | 6 +- api/{src/Controller => migrations}/.gitignore | 0 .../Version20180907212032.php | 0 .../Version20181027124203.php | 0 .../Version20190111212909.php | 0 .../Version20200103160747.php | 0 .../Version20200103170517.php | 0 .../Version20200131151757.php | 0 .../Version20200206183956.php | 0 .../Version20200314112552.php | 0 api/public/index.php | 23 +- api/src/Functions/index.php | 2 +- api/src/Kernel.php | 40 +- api/src/Migrations/.gitignore | 0 api/symfony.lock | 78 +- 28 files changed, 655 insertions(+), 582 deletions(-) rename api/{.env.dist => .env} (52%) create mode 100644 api/config/bootstrap.php create mode 100644 api/config/packages/cache.yaml create mode 100644 api/config/packages/test/twig.yaml create mode 100644 api/config/preload.php rename api/{src/Controller => migrations}/.gitignore (100%) rename api/{src/Migrations => migrations}/Version20180907212032.php (100%) rename api/{src/Migrations => migrations}/Version20181027124203.php (100%) rename api/{src/Migrations => migrations}/Version20190111212909.php (100%) rename api/{src/Migrations => migrations}/Version20200103160747.php (100%) rename api/{src/Migrations => migrations}/Version20200103170517.php (100%) rename api/{src/Migrations => migrations}/Version20200131151757.php (100%) rename api/{src/Migrations => migrations}/Version20200206183956.php (100%) rename api/{src/Migrations => migrations}/Version20200314112552.php (100%) delete mode 100644 api/src/Migrations/.gitignore diff --git a/api/.env.dist b/api/.env similarity index 52% rename from api/.env.dist rename to api/.env index 69f196a..8e84d99 100644 --- a/api/.env.dist +++ b/api/.env @@ -4,12 +4,15 @@ ###> symfony/framework-bundle ### APP_ENV=dev -APP_SECRET=1bdf86cdc78fba654e4f2c309c6bbdbd +APP_SECRET=494a9d1f8cc383f16075f4d5e54ae1a2 +#TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 +#TRUSTED_HOSTS='^(localhost|example\.com)$' ###< symfony/framework-bundle ### ###> doctrine/doctrine-bundle ### -# Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url -# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db" -# Configure your db driver and server_version in config/packages/doctrine.yaml -DATABASE_URL=sqlite:///%kernel.project_dir%/var/app.db +# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url +# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml +# +DATABASE_URL="sqlite:///%kernel.project_dir%/var/app.db" +# DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=5.7" ###< doctrine/doctrine-bundle ### diff --git a/api/.gitignore b/api/.gitignore index bc4b385..5aa718b 100644 --- a/api/.gitignore +++ b/api/.gitignore @@ -1,5 +1,8 @@ ###> symfony/framework-bundle ### -/.env +/.env.local +/.env.local.php +/.env.*.local +/config/secrets/prod/prod.decrypt.private.php /public/bundles/ /var/ /vendor/ diff --git a/api/composer.json b/api/composer.json index 33a7ea3..49dd6d3 100644 --- a/api/composer.json +++ b/api/composer.json @@ -77,7 +77,8 @@ }, "extra": { "symfony": { - "allow-contrib": true + "allow-contrib": true, + "require": "4.4.*" } }, "repositories": [ diff --git a/api/composer.lock b/api/composer.lock index f32a200..79d594b 100644 --- a/api/composer.lock +++ b/api/composer.lock @@ -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": "294e71e4f7c26065cc294792790581e9", + "content-hash": "b29e467a46157fea720fdc35c6921f47", "packages": [ { "name": "baldinof/roadrunner-bundle", @@ -2348,21 +2348,21 @@ }, { "name": "monolog/monolog", - "version": "2.1.1", + "version": "1.25.5", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "f9eee5cec93dfb313a38b6b288741e84e53f02d5" + "reference": "1817faadd1846cd08be9a49e905dc68823bc38c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f9eee5cec93dfb313a38b6b288741e84e53f02d5", - "reference": "f9eee5cec93dfb313a38b6b288741e84e53f02d5", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1817faadd1846cd08be9a49e905dc68823bc38c0", + "reference": "1817faadd1846cd08be9a49e905dc68823bc38c0", "shasum": "" }, "require": { - "php": ">=7.2", - "psr/log": "^1.0.1" + "php": ">=5.3.0", + "psr/log": "~1.0" }, "provide": { "psr/log-implementation": "1.0.0" @@ -2370,36 +2370,32 @@ "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", - "elasticsearch/elasticsearch": "^6.0", - "graylog2/gelf-php": "^1.4.2", + "graylog2/gelf-php": "~1.0", "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", "php-parallel-lint/php-parallel-lint": "^1.0", - "phpspec/prophecy": "^1.6.1", - "phpunit/phpunit": "^8.5", - "predis/predis": "^1.1", - "rollbar/rollbar": "^1.3", + "phpunit/phpunit": "~4.5", "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", "swiftmailer/swiftmailer": "^5.3|^6.0" }, "suggest": { "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", "doctrine/couchdb": "Allow sending log messages to a CouchDB server", - "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", - "ext-mbstring": "Allow to work properly with unicode symbols", - "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-mongo": "Allow sending log messages to a MongoDB server", "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", "php-console/php-console": "Allow sending log messages to Google Chrome", "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -2427,7 +2423,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.1.1" + "source": "https://github.com/Seldaek/monolog/tree/1.25.5" }, "funding": [ { @@ -2439,7 +2435,7 @@ "type": "tidelift" } ], - "time": "2020-07-23T08:41:23+00:00" + "time": "2020-07-23T08:35:51+00:00" }, { "name": "nelmio/api-doc-bundle", @@ -3535,7 +3531,7 @@ }, { "name": "symfony/asset", - "version": "v4.4.16", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/asset.git", @@ -3583,7 +3579,7 @@ "description": "Symfony Asset Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/asset/tree/v4.4.16" + "source": "https://github.com/symfony/asset/tree/v4.4.17" }, "funding": [ { @@ -3603,30 +3599,29 @@ }, { "name": "symfony/cache", - "version": "v5.1.8", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "d7bc33e9f9028f49f87057e7944c076d9593f046" + "reference": "6d330ca81ce5c98f22224c980507a7f7a7df82e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/d7bc33e9f9028f49f87057e7944c076d9593f046", - "reference": "d7bc33e9f9028f49f87057e7944c076d9593f046", + "url": "https://api.github.com/repos/symfony/cache/zipball/6d330ca81ce5c98f22224c980507a7f7a7df82e8", + "reference": "6d330ca81ce5c98f22224c980507a7f7a7df82e8", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=7.1.3", "psr/cache": "~1.0", "psr/log": "~1.0", "symfony/cache-contracts": "^1.1.7|^2", - "symfony/polyfill-php80": "^1.15", "symfony/service-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0" + "symfony/var-exporter": "^4.2|^5.0" }, "conflict": { "doctrine/dbal": "<2.5", - "symfony/dependency-injection": "<4.4", + "symfony/dependency-injection": "<3.4", "symfony/http-kernel": "<4.4", "symfony/var-dumper": "<4.4" }, @@ -3641,9 +3636,10 @@ "doctrine/dbal": "^2.5|^3.0", "predis/predis": "^1.1", "psr/simple-cache": "^1.0", - "symfony/config": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.1|^5.0", "symfony/filesystem": "^4.4|^5.0", + "symfony/http-kernel": "^4.4|^5.0", "symfony/var-dumper": "^4.4|^5.0" }, "type": "library", @@ -3676,7 +3672,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v5.1.8" + "source": "https://github.com/symfony/cache/tree/v4.4.17" }, "funding": [ { @@ -3692,7 +3688,7 @@ "type": "tidelift" } ], - "time": "2020-10-25T23:21:56+00:00" + "time": "2020-11-16T17:15:10+00:00" }, { "name": "symfony/cache-contracts", @@ -3775,34 +3771,32 @@ }, { "name": "symfony/config", - "version": "v5.1.8", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "11baeefa4c179d6908655a7b6be728f62367c193" + "reference": "4da4a6b07cc7d8d7d3e29842bc9c20401d555065" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/11baeefa4c179d6908655a7b6be728f62367c193", - "reference": "11baeefa4c179d6908655a7b6be728f62367c193", + "url": "https://api.github.com/repos/symfony/config/zipball/4da4a6b07cc7d8d7d3e29842bc9c20401d555065", + "reference": "4da4a6b07cc7d8d7d3e29842bc9c20401d555065", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/filesystem": "^4.4|^5.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php80": "^1.15" + "php": ">=7.1.3", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/finder": "<4.4" + "symfony/finder": "<3.4" }, "require-dev": { - "symfony/event-dispatcher": "^4.4|^5.0", - "symfony/finder": "^4.4|^5.0", - "symfony/messenger": "^4.4|^5.0", + "symfony/event-dispatcher": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/messenger": "^4.1|^5.0", "symfony/service-contracts": "^1.1|^2", - "symfony/yaml": "^4.4|^5.0" + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -3833,7 +3827,7 @@ "description": "Symfony Config Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.1.8" + "source": "https://github.com/symfony/config/tree/v4.4.17" }, "funding": [ { @@ -3849,20 +3843,20 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:01:57+00:00" + "time": "2020-11-16T11:15:53+00:00" }, { "name": "symfony/console", - "version": "v4.4.16", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "20f73dd143a5815d475e0838ff867bce1eebd9d5" + "reference": "c8e37f6928c19816437a4dd7bf16e3bd79941470" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/20f73dd143a5815d475e0838ff867bce1eebd9d5", - "reference": "20f73dd143a5815d475e0838ff867bce1eebd9d5", + "url": "https://api.github.com/repos/symfony/console/zipball/c8e37f6928c19816437a4dd7bf16e3bd79941470", + "reference": "c8e37f6928c19816437a4dd7bf16e3bd79941470", "shasum": "" }, "require": { @@ -3922,7 +3916,7 @@ "description": "Symfony Console Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/console/tree/v4.4.16" + "source": "https://github.com/symfony/console/tree/v4.4.17" }, "funding": [ { @@ -3938,20 +3932,20 @@ "type": "tidelift" } ], - "time": "2020-10-24T11:50:19+00:00" + "time": "2020-11-28T10:15:42+00:00" }, { "name": "symfony/debug", - "version": "v4.4.16", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "c87adf3fc1cd0bf4758316a3a150d50a8f957ef4" + "reference": "65fe7b49868378319b82da3035fb30801b931c47" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/c87adf3fc1cd0bf4758316a3a150d50a8f957ef4", - "reference": "c87adf3fc1cd0bf4758316a3a150d50a8f957ef4", + "url": "https://api.github.com/repos/symfony/debug/zipball/65fe7b49868378319b82da3035fb30801b931c47", + "reference": "65fe7b49868378319b82da3035fb30801b931c47", "shasum": "" }, "require": { @@ -3991,7 +3985,7 @@ "description": "Symfony Debug Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/debug/tree/v4.4.16" + "source": "https://github.com/symfony/debug/tree/v4.4.17" }, "funding": [ { @@ -4007,43 +4001,41 @@ "type": "tidelift" } ], - "time": "2020-10-24T11:50:19+00:00" + "time": "2020-10-28T20:42:29+00:00" }, { "name": "symfony/dependency-injection", - "version": "v5.1.8", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "829ca6bceaf68036a123a13a979f3c89289eae78" + "reference": "7126a3a25466a29b844c21394aabf6e7cf717b24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/829ca6bceaf68036a123a13a979f3c89289eae78", - "reference": "829ca6bceaf68036a123a13a979f3c89289eae78", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/7126a3a25466a29b844c21394aabf6e7cf717b24", + "reference": "7126a3a25466a29b844c21394aabf6e7cf717b24", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=7.1.3", "psr/container": "^1.0", - "symfony/deprecation-contracts": "^2.1", - "symfony/polyfill-php80": "^1.15", "symfony/service-contracts": "^1.1.6|^2" }, "conflict": { - "symfony/config": "<5.1", - "symfony/finder": "<4.4", - "symfony/proxy-manager-bridge": "<4.4", - "symfony/yaml": "<4.4" + "symfony/config": "<4.3|>=5.0", + "symfony/finder": "<3.4", + "symfony/proxy-manager-bridge": "<3.4", + "symfony/yaml": "<3.4" }, "provide": { "psr/container-implementation": "1.0", "symfony/service-implementation": "1.0" }, "require-dev": { - "symfony/config": "^5.1", - "symfony/expression-language": "^4.4|^5.0", - "symfony/yaml": "^4.4|^5.0" + "symfony/config": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/config": "", @@ -4078,7 +4070,7 @@ "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.1.8" + "source": "https://github.com/symfony/dependency-injection/tree/v4.4.17" }, "funding": [ { @@ -4094,87 +4086,20 @@ "type": "tidelift" } ], - "time": "2020-10-27T10:11:13+00:00" - }, - { - "name": "symfony/deprecation-contracts", - "version": "v2.2.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5fa56b4074d1ae755beb55617ddafe6f5d78f665", - "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.2-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "files": [ - "function.php" - ] - }, - "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": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/master" - }, - "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-09-07T11:33:47+00:00" + "time": "2020-11-27T15:54:06+00:00" }, { "name": "symfony/doctrine-bridge", - "version": "v4.4.16", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "12ce8950c685afb954026c2d0c975dfed3fc32f3" + "reference": "cc9cc380f51c3ab7ad396fad8b30fc184894e6c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/12ce8950c685afb954026c2d0c975dfed3fc32f3", - "reference": "12ce8950c685afb954026c2d0c975dfed3fc32f3", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/cc9cc380f51c3ab7ad396fad8b30fc184894e6c1", + "reference": "cc9cc380f51c3ab7ad396fad8b30fc184894e6c1", "shasum": "" }, "require": { @@ -4202,7 +4127,6 @@ "doctrine/data-fixtures": "^1.1", "doctrine/dbal": "~2.4|^3.0", "doctrine/orm": "^2.6.3", - "doctrine/reflection": "~1.0", "symfony/config": "^4.2|^5.0", "symfony/dependency-injection": "^3.4|^4.0|^5.0", "symfony/expression-language": "^3.4|^4.0|^5.0", @@ -4252,7 +4176,7 @@ "description": "Symfony Doctrine Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v4.4.16" + "source": "https://github.com/symfony/doctrine-bridge/tree/v4.4.17" }, "funding": [ { @@ -4268,20 +4192,20 @@ "type": "tidelift" } ], - "time": "2020-10-24T11:50:19+00:00" + "time": "2020-11-09T19:21:10+00:00" }, { "name": "symfony/dotenv", - "version": "v4.4.16", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "450e2dad0b42431ad9558bc8adf07e8c4b55d1cd" + "reference": "6dd958a0c30bdf816ddef5052655a06d87fa343c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/450e2dad0b42431ad9558bc8adf07e8c4b55d1cd", - "reference": "450e2dad0b42431ad9558bc8adf07e8c4b55d1cd", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/6dd958a0c30bdf816ddef5052655a06d87fa343c", + "reference": "6dd958a0c30bdf816ddef5052655a06d87fa343c", "shasum": "" }, "require": { @@ -4321,7 +4245,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v4.4.16" + "source": "https://github.com/symfony/dotenv/tree/v4.4.17" }, "funding": [ { @@ -4337,20 +4261,20 @@ "type": "tidelift" } ], - "time": "2020-10-24T11:50:19+00:00" + "time": "2020-11-14T17:10:20+00:00" }, { "name": "symfony/error-handler", - "version": "v4.4.16", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "363cca01cabf98e4f1c447b14d0a68617f003613" + "reference": "b0887cf8fc692eef2a4cf11cee3c5f5eb93fcfdf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/363cca01cabf98e4f1c447b14d0a68617f003613", - "reference": "363cca01cabf98e4f1c447b14d0a68617f003613", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/b0887cf8fc692eef2a4cf11cee3c5f5eb93fcfdf", + "reference": "b0887cf8fc692eef2a4cf11cee3c5f5eb93fcfdf", "shasum": "" }, "require": { @@ -4390,7 +4314,7 @@ "description": "Symfony ErrorHandler Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v4.4.16" + "source": "https://github.com/symfony/error-handler/tree/v4.4.17" }, "funding": [ { @@ -4406,20 +4330,20 @@ "type": "tidelift" } ], - "time": "2020-10-24T11:50:19+00:00" + "time": "2020-10-28T20:42:29+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.4.16", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "4204f13d2d0b7ad09454f221bb2195fccdf1fe98" + "reference": "f029d6f21eac61ab23198e7aca40e7638e8c8924" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/4204f13d2d0b7ad09454f221bb2195fccdf1fe98", - "reference": "4204f13d2d0b7ad09454f221bb2195fccdf1fe98", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/f029d6f21eac61ab23198e7aca40e7638e8c8924", + "reference": "f029d6f21eac61ab23198e7aca40e7638e8c8924", "shasum": "" }, "require": { @@ -4473,7 +4397,7 @@ "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.16" + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.17" }, "funding": [ { @@ -4489,7 +4413,7 @@ "type": "tidelift" } ], - "time": "2020-10-24T11:50:19+00:00" + "time": "2020-10-31T22:44:29+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -4572,20 +4496,20 @@ }, { "name": "symfony/filesystem", - "version": "v5.1.8", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "df08650ea7aee2d925380069c131a66124d79177" + "reference": "17b83e36a911aefa2cfe04bbf6328ec4c040c1b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/df08650ea7aee2d925380069c131a66124d79177", - "reference": "df08650ea7aee2d925380069c131a66124d79177", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/17b83e36a911aefa2cfe04bbf6328ec4c040c1b2", + "reference": "17b83e36a911aefa2cfe04bbf6328ec4c040c1b2", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=7.1.3", "symfony/polyfill-ctype": "~1.8" }, "type": "library", @@ -4614,7 +4538,7 @@ "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.1.8" + "source": "https://github.com/symfony/filesystem/tree/v4.4.17" }, "funding": [ { @@ -4630,24 +4554,24 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:01:57+00:00" + "time": "2020-11-11T22:20:15+00:00" }, { "name": "symfony/finder", - "version": "v5.1.8", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "e70eb5a69c2ff61ea135a13d2266e8914a67b3a0" + "reference": "9f1d1d883b79a91ef320c0c6e803494e042ef36e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/e70eb5a69c2ff61ea135a13d2266e8914a67b3a0", - "reference": "e70eb5a69c2ff61ea135a13d2266e8914a67b3a0", + "url": "https://api.github.com/repos/symfony/finder/zipball/9f1d1d883b79a91ef320c0c6e803494e042ef36e", + "reference": "9f1d1d883b79a91ef320c0c6e803494e042ef36e", "shasum": "" }, "require": { - "php": ">=7.2.5" + "php": ">=7.1.3" }, "type": "library", "autoload": { @@ -4675,7 +4599,7 @@ "description": "Symfony Finder Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.1.8" + "source": "https://github.com/symfony/finder/tree/v4.4.17" }, "funding": [ { @@ -4691,7 +4615,7 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:01:57+00:00" + "time": "2020-11-17T19:45:34+00:00" }, { "name": "symfony/flex", @@ -4762,16 +4686,16 @@ }, { "name": "symfony/framework-bundle", - "version": "v4.4.16", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "0067e02d6ca55e284617777ed90cd086d3836457" + "reference": "3aea107a3cf50c351a492ab855caa6b2fd0f66a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/0067e02d6ca55e284617777ed90cd086d3836457", - "reference": "0067e02d6ca55e284617777ed90cd086d3836457", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/3aea107a3cf50c351a492ab855caa6b2fd0f66a2", + "reference": "3aea107a3cf50c351a492ab855caa6b2fd0f66a2", "shasum": "" }, "require": { @@ -4885,7 +4809,7 @@ "description": "Symfony FrameworkBundle", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v4.4.16" + "source": "https://github.com/symfony/framework-bundle/tree/v4.4.17" }, "funding": [ { @@ -4901,7 +4825,7 @@ "type": "tidelift" } ], - "time": "2020-10-24T11:50:19+00:00" + "time": "2020-11-27T14:11:20+00:00" }, { "name": "symfony/http-client-contracts", @@ -4984,32 +4908,26 @@ }, { "name": "symfony/http-foundation", - "version": "v5.1.8", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "a2860ec970404b0233ab1e59e0568d3277d32b6f" + "reference": "9eeb37ec0ff3049c782ca67041648e28ddd75a94" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a2860ec970404b0233ab1e59e0568d3277d32b6f", - "reference": "a2860ec970404b0233ab1e59e0568d3277d32b6f", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9eeb37ec0ff3049c782ca67041648e28ddd75a94", + "reference": "9eeb37ec0ff3049c782ca67041648e28ddd75a94", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php80": "^1.15" + "php": ">=7.1.3", + "symfony/mime": "^4.3|^5.0", + "symfony/polyfill-mbstring": "~1.1" }, "require-dev": { "predis/predis": "~1.0", - "symfony/cache": "^4.4|^5.0", - "symfony/expression-language": "^4.4|^5.0", - "symfony/mime": "^4.4|^5.0" - }, - "suggest": { - "symfony/mime": "To use the file extension guesser" + "symfony/expression-language": "^3.4|^4.0|^5.0" }, "type": "library", "autoload": { @@ -5037,7 +4955,7 @@ "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.1.8" + "source": "https://github.com/symfony/http-foundation/tree/v4.4.17" }, "funding": [ { @@ -5053,20 +4971,20 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:01:57+00:00" + "time": "2020-11-03T11:58:18+00:00" }, { "name": "symfony/http-kernel", - "version": "v4.4.16", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "109b2a46e470a487ec8b0ffea4b0bb993aaf42ed" + "reference": "9f5605ee05406d8afa40dc4f2954c6a61de3a984" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/109b2a46e470a487ec8b0ffea4b0bb993aaf42ed", - "reference": "109b2a46e470a487ec8b0ffea4b0bb993aaf42ed", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/9f5605ee05406d8afa40dc4f2954c6a61de3a984", + "reference": "9f5605ee05406d8afa40dc4f2954c6a61de3a984", "shasum": "" }, "require": { @@ -5141,7 +5059,7 @@ "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v4.4.16" + "source": "https://github.com/symfony/http-kernel/tree/v4.4.17" }, "funding": [ { @@ -5157,39 +5075,181 @@ "type": "tidelift" } ], - "time": "2020-10-28T05:50:56+00:00" + "time": "2020-11-29T09:23:08+00:00" }, { - "name": "symfony/monolog-bridge", - "version": "v5.1.8", + "name": "symfony/inflector", + "version": "v4.4.17", "source": { "type": "git", - "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "0c507eddb704a3154b53f066cc0b587c4586c868" + "url": "https://github.com/symfony/inflector.git", + "reference": "a2ca868d7fc02800db67d1e1b6e5c83882d2aaa6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/0c507eddb704a3154b53f066cc0b587c4586c868", - "reference": "0c507eddb704a3154b53f066cc0b587c4586c868", + "url": "https://api.github.com/repos/symfony/inflector/zipball/a2ca868d7fc02800db67d1e1b6e5c83882d2aaa6", + "reference": "a2ca868d7fc02800db67d1e1b6e5c83882d2aaa6", "shasum": "" }, "require": { - "monolog/monolog": "^1.25.1|^2", - "php": ">=7.2.5", - "symfony/http-kernel": "^4.4|^5.0", + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Inflector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Inflector Component", + "homepage": "https://symfony.com", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string", + "symfony", + "words" + ], + "support": { + "source": "https://github.com/symfony/inflector/tree/v4.4.17" + }, + "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-10-24T11:50:19+00:00" + }, + { + "name": "symfony/mime", + "version": "v4.4.17", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "4148b752f7e961931887410513ce3d9e267d25f2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/4148b752f7e961931887410513ce3d9e267d25f2", + "reference": "4148b752f7e961931887410513ce3d9e267d25f2", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10", + "symfony/dependency-injection": "^3.4|^4.1|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A library to manipulate MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v4.4.17" + }, + "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-10-28T20:42:29+00:00" + }, + { + "name": "symfony/monolog-bridge", + "version": "v4.4.17", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bridge.git", + "reference": "0ac6b8e8c742ae75e8840feb1852fdf01d02d3ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/0ac6b8e8c742ae75e8840feb1852fdf01d02d3ed", + "reference": "0ac6b8e8c742ae75e8840feb1852fdf01d02d3ed", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.25.1", + "php": ">=7.1.3", + "symfony/http-kernel": "^4.3", "symfony/service-contracts": "^1.1|^2" }, "conflict": { - "symfony/console": "<4.4", - "symfony/http-foundation": "<4.4" + "symfony/console": "<3.4", + "symfony/http-foundation": "<3.4" }, "require-dev": { - "symfony/console": "^4.4|^5.0", + "symfony/console": "^3.4|^4.0|^5.0", "symfony/http-client": "^4.4|^5.0", - "symfony/mailer": "^4.4|^5.0", - "symfony/mime": "^4.4|^5.0", - "symfony/security-core": "^4.4|^5.0", - "symfony/var-dumper": "^4.4|^5.0" + "symfony/security-core": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings.", @@ -5222,7 +5282,7 @@ "description": "Symfony Monolog Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/monolog-bridge/tree/v5.1.8" + "source": "https://github.com/symfony/monolog-bridge/tree/v4.4.17" }, "funding": [ { @@ -5238,7 +5298,7 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:01:57+00:00" + "time": "2020-10-28T20:42:29+00:00" }, { "name": "symfony/monolog-bundle", @@ -5323,22 +5383,20 @@ }, { "name": "symfony/options-resolver", - "version": "v5.1.8", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "c6a02905e4ffc7a1498e8ee019db2b477cd1cc02" + "reference": "157a252222251310fe50c71012b4e72f01325850" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/c6a02905e4ffc7a1498e8ee019db2b477cd1cc02", - "reference": "c6a02905e4ffc7a1498e8ee019db2b477cd1cc02", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/157a252222251310fe50c71012b4e72f01325850", + "reference": "157a252222251310fe50c71012b4e72f01325850", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/polyfill-php80": "^1.15" + "php": ">=7.1.3" }, "type": "library", "autoload": { @@ -5371,7 +5429,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v5.1.8" + "source": "https://github.com/symfony/options-resolver/tree/v4.4.17" }, "funding": [ { @@ -5387,7 +5445,7 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:01:57+00:00" + "time": "2020-10-24T11:50:19+00:00" }, { "name": "symfony/orm-pack", @@ -5437,21 +5495,23 @@ "time": "2020-08-31T10:20:18+00:00" }, { - "name": "symfony/polyfill-intl-grapheme", + "name": "symfony/polyfill-intl-idn", "version": "v1.20.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c" + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "3b75acd829741c768bc8b1f84eb33265e7cc5117" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c", - "reference": "c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/3b75acd829741c768bc8b1f84eb33265e7cc5117", + "reference": "3b75acd829741c768bc8b1f84eb33265e7cc5117", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" }, "suggest": { "ext-intl": "For best performance" @@ -5468,7 +5528,7 @@ }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + "Symfony\\Polyfill\\Intl\\Idn\\": "" }, "files": [ "bootstrap.php" @@ -5480,26 +5540,30 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's grapheme_* functions", + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "grapheme", + "idn", "intl", "polyfill", "portable", "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.20.0" }, "funding": [ { @@ -5681,6 +5745,82 @@ ], "time": "2020-10-23T14:02:19+00:00" }, + { + "name": "symfony/polyfill-php72", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cede45fcdfabdd6043b3592e83678e42ec69e930", + "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "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.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.20.0" + }, + "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-10-23T14:02:19+00:00" + }, { "name": "symfony/polyfill-php73", "version": "v1.20.0", @@ -5890,34 +6030,33 @@ }, { "name": "symfony/property-info", - "version": "v5.1.8", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "fc15c51f829887b62a94a917ba793f51e80ea3e1" + "reference": "b355ee4a241094f72b8f96709a83619b8be064b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/fc15c51f829887b62a94a917ba793f51e80ea3e1", - "reference": "fc15c51f829887b62a94a917ba793f51e80ea3e1", + "url": "https://api.github.com/repos/symfony/property-info/zipball/b355ee4a241094f72b8f96709a83619b8be064b2", + "reference": "b355ee4a241094f72b8f96709a83619b8be064b2", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.15", - "symfony/string": "^5.1" + "php": ">=7.1.3", + "symfony/inflector": "^3.4|^4.0|^5.0" }, "conflict": { - "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/reflection-docblock": "<3.0||>=3.2.0,<3.2.2", "phpdocumentor/type-resolver": "<0.3.0", - "symfony/dependency-injection": "<4.4" + "symfony/dependency-injection": "<3.4" }, "require-dev": { "doctrine/annotations": "~1.7", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/cache": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/serializer": "^4.4|^5.0" + "symfony/cache": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/serializer": "^3.4|^4.0|^5.0" }, "suggest": { "phpdocumentor/reflection-docblock": "To use the PHPDoc", @@ -5959,7 +6098,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v5.1.8" + "source": "https://github.com/symfony/property-info/tree/v4.4.17" }, "funding": [ { @@ -5975,7 +6114,7 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:01:57+00:00" + "time": "2020-10-28T20:42:29+00:00" }, { "name": "symfony/psr-http-message-bridge", @@ -6061,36 +6200,34 @@ }, { "name": "symfony/routing", - "version": "v5.1.8", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "d6ceee2a37b61b41079005207bf37746d1bfe71f" + "reference": "08712c5dd5041c03e997e13892f45884faccd868" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/d6ceee2a37b61b41079005207bf37746d1bfe71f", - "reference": "d6ceee2a37b61b41079005207bf37746d1bfe71f", + "url": "https://api.github.com/repos/symfony/routing/zipball/08712c5dd5041c03e997e13892f45884faccd868", + "reference": "08712c5dd5041c03e997e13892f45884faccd868", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/polyfill-php80": "^1.15" + "php": ">=7.1.3" }, "conflict": { - "symfony/config": "<5.0", - "symfony/dependency-injection": "<4.4", - "symfony/yaml": "<4.4" + "symfony/config": "<4.2", + "symfony/dependency-injection": "<3.4", + "symfony/yaml": "<3.4" }, "require-dev": { "doctrine/annotations": "~1.2", "psr/log": "~1.0", - "symfony/config": "^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/expression-language": "^4.4|^5.0", - "symfony/http-foundation": "^4.4|^5.0", - "symfony/yaml": "^4.4|^5.0" + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "doctrine/annotations": "For using the annotation loader", @@ -6131,7 +6268,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v5.1.8" + "source": "https://github.com/symfony/routing/tree/v4.4.17" }, "funding": [ { @@ -6147,7 +6284,7 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:01:57+00:00" + "time": "2020-11-24T13:31:32+00:00" }, { "name": "symfony/service-contracts", @@ -6230,20 +6367,20 @@ }, { "name": "symfony/stopwatch", - "version": "v5.1.8", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "3d9f57c89011f0266e6b1d469e5c0110513859d5" + "reference": "c7a594108ed01c89555c4e1bb123b4a54aee2595" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/3d9f57c89011f0266e6b1d469e5c0110513859d5", - "reference": "3d9f57c89011f0266e6b1d469e5c0110513859d5", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/c7a594108ed01c89555c4e1bb123b4a54aee2595", + "reference": "c7a594108ed01c89555c4e1bb123b4a54aee2595", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=7.1.3", "symfony/service-contracts": "^1.0|^2" }, "type": "library", @@ -6272,7 +6409,7 @@ "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.1.8" + "source": "https://github.com/symfony/stopwatch/tree/v4.4.17" }, "funding": [ { @@ -6288,103 +6425,20 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:01:57+00:00" - }, - { - "name": "symfony/string", - "version": "v5.1.8", - "source": { - "type": "git", - "url": "https://github.com/symfony/string.git", - "reference": "a97573e960303db71be0dd8fda9be3bca5e0feea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/a97573e960303db71be0dd8fda9be3bca5e0feea", - "reference": "a97573e960303db71be0dd8fda9be3bca5e0feea", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "~1.15" - }, - "require-dev": { - "symfony/error-handler": "^4.4|^5.0", - "symfony/http-client": "^4.4|^5.0", - "symfony/translation-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\String\\": "" - }, - "files": [ - "Resources/functions.php" - ], - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "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 String component", - "homepage": "https://symfony.com", - "keywords": [ - "grapheme", - "i18n", - "string", - "unicode", - "utf-8", - "utf8" - ], - "support": { - "source": "https://github.com/symfony/string/tree/v5.1.8" - }, - "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-10-24T12:01:57+00:00" + "time": "2020-10-31T22:44:29+00:00" }, { "name": "symfony/translation", - "version": "v4.4.16", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "73095716af79f610f3b6338b911357393fdd10ab" + "reference": "84821e6a14a637e817f25d11147388695b6f790a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/73095716af79f610f3b6338b911357393fdd10ab", - "reference": "73095716af79f610f3b6338b911357393fdd10ab", + "url": "https://api.github.com/repos/symfony/translation/zipball/84821e6a14a637e817f25d11147388695b6f790a", + "reference": "84821e6a14a637e817f25d11147388695b6f790a", "shasum": "" }, "require": { @@ -6443,7 +6497,7 @@ "description": "Symfony Translation Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v4.4.16" + "source": "https://github.com/symfony/translation/tree/v4.4.17" }, "funding": [ { @@ -6459,7 +6513,7 @@ "type": "tidelift" } ], - "time": "2020-10-24T11:50:19+00:00" + "time": "2020-11-27T06:35:49+00:00" }, { "name": "symfony/translation-contracts", @@ -6541,16 +6595,16 @@ }, { "name": "symfony/twig-bridge", - "version": "v4.4.16", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "841c46c963891122429cfa1b56f06aeef9c1c010" + "reference": "7d119d2cffb4d11a42690205c2427625c80a060e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/841c46c963891122429cfa1b56f06aeef9c1c010", - "reference": "841c46c963891122429cfa1b56f06aeef9c1c010", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/7d119d2cffb4d11a42690205c2427625c80a060e", + "reference": "7d119d2cffb4d11a42690205c2427625c80a060e", "shasum": "" }, "require": { @@ -6573,7 +6627,7 @@ "symfony/error-handler": "^4.4|^5.0", "symfony/expression-language": "^3.4|^4.0|^5.0", "symfony/finder": "^3.4|^4.0|^5.0", - "symfony/form": "^4.3.5", + "symfony/form": "^4.4.17", "symfony/http-foundation": "^4.3|^5.0", "symfony/http-kernel": "^4.4", "symfony/mime": "^4.3|^5.0", @@ -6636,7 +6690,7 @@ "description": "Symfony Twig Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v4.4.16" + "source": "https://github.com/symfony/twig-bridge/tree/v4.4.17" }, "funding": [ { @@ -6652,11 +6706,11 @@ "type": "tidelift" } ], - "time": "2020-10-24T11:50:19+00:00" + "time": "2020-11-17T16:25:11+00:00" }, { "name": "symfony/twig-bundle", - "version": "v4.4.16", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", @@ -6723,7 +6777,7 @@ "description": "Symfony TwigBundle", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v4.4.16" + "source": "https://github.com/symfony/twig-bundle/tree/v4.4.17" }, "funding": [ { @@ -6743,32 +6797,33 @@ }, { "name": "symfony/var-dumper", - "version": "v5.1.8", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "4e13f3fcefb1fcaaa5efb5403581406f4e840b9a" + "reference": "65c6f1e848cda840ef7278686c8e30a7cc353c93" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/4e13f3fcefb1fcaaa5efb5403581406f4e840b9a", - "reference": "4e13f3fcefb1fcaaa5efb5403581406f4e840b9a", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/65c6f1e848cda840ef7278686c8e30a7cc353c93", + "reference": "65c6f1e848cda840ef7278686c8e30a7cc353c93", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=7.1.3", "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", "symfony/polyfill-php80": "^1.15" }, "conflict": { - "phpunit/phpunit": "<5.4.3", - "symfony/console": "<4.4" + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" }, "require-dev": { "ext-iconv": "*", - "symfony/console": "^4.4|^5.0", + "symfony/console": "^3.4|^4.0|^5.0", "symfony/process": "^4.4|^5.0", - "twig/twig": "^2.4|^3.0" + "twig/twig": "^1.34|^2.4|^3.0" }, "suggest": { "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", @@ -6811,7 +6866,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.1.8" + "source": "https://github.com/symfony/var-dumper/tree/v4.4.17" }, "funding": [ { @@ -6827,25 +6882,24 @@ "type": "tidelift" } ], - "time": "2020-10-27T10:11:13+00:00" + "time": "2020-11-24T09:55:37+00:00" }, { "name": "symfony/var-exporter", - "version": "v5.1.8", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "b4048bfc6248413592462c029381bdb2f7b6525f" + "reference": "f04b7d187b120e0a44c18a2d479c2dd0abe99d9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/b4048bfc6248413592462c029381bdb2f7b6525f", - "reference": "b4048bfc6248413592462c029381bdb2f7b6525f", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/f04b7d187b120e0a44c18a2d479c2dd0abe99d9c", + "reference": "f04b7d187b120e0a44c18a2d479c2dd0abe99d9c", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.15" + "php": ">=7.1.3" }, "require-dev": { "symfony/var-dumper": "^4.4.9|^5.0.9" @@ -6884,7 +6938,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v5.1.8" + "source": "https://github.com/symfony/var-exporter/tree/v4.4.17" }, "funding": [ { @@ -6900,48 +6954,43 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:01:57+00:00" + "time": "2020-10-28T20:42:29+00:00" }, { "name": "symfony/web-profiler-bundle", - "version": "v5.0.11", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "3b6dbd2cc76275e117d5c55923c7f511ead22bae" + "reference": "cd980f0df4ae7696d18fd908503fc61ae67ac48d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/3b6dbd2cc76275e117d5c55923c7f511ead22bae", - "reference": "3b6dbd2cc76275e117d5c55923c7f511ead22bae", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/cd980f0df4ae7696d18fd908503fc61ae67ac48d", + "reference": "cd980f0df4ae7696d18fd908503fc61ae67ac48d", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/config": "^4.4|^5.0", + "php": ">=7.1.3", + "symfony/config": "^4.2|^5.0", "symfony/framework-bundle": "^4.4|^5.0", - "symfony/http-kernel": "^4.4|^5.0", - "symfony/routing": "^4.4|^5.0", - "symfony/twig-bundle": "^4.4|^5.0", - "twig/twig": "^2.10|^3.0" + "symfony/http-kernel": "^4.4", + "symfony/routing": "^4.3|^5.0", + "symfony/twig-bundle": "^4.2|^5.0", + "twig/twig": "^1.41|^2.10|^3.0" }, "conflict": { - "symfony/form": "<4.4", - "symfony/messenger": "<4.4" + "symfony/form": "<4.3", + "symfony/messenger": "<4.2" }, "require-dev": { - "symfony/browser-kit": "^4.4|^5.0", - "symfony/console": "^4.4|^5.0", - "symfony/css-selector": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/stopwatch": "^4.4|^5.0" + "symfony/browser-kit": "^4.3|^5.0", + "symfony/console": "^4.3|^5.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0" }, "type": "symfony-bundle", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Bundle\\WebProfilerBundle\\": "" @@ -6967,7 +7016,7 @@ "description": "Symfony WebProfilerBundle", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v5.0.11" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v4.4.17" }, "funding": [ { @@ -6983,20 +7032,20 @@ "type": "tidelift" } ], - "time": "2020-07-23T08:36:09+00:00" + "time": "2020-10-28T20:42:29+00:00" }, { "name": "symfony/yaml", - "version": "v4.4.16", + "version": "v4.4.17", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "543cb4dbd45ed803f08a9a65f27fb149b5dd20c2" + "reference": "7531361cf38e4816821b4a12a42542b3c6143ad1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/543cb4dbd45ed803f08a9a65f27fb149b5dd20c2", - "reference": "543cb4dbd45ed803f08a9a65f27fb149b5dd20c2", + "url": "https://api.github.com/repos/symfony/yaml/zipball/7531361cf38e4816821b4a12a42542b3c6143ad1", + "reference": "7531361cf38e4816821b4a12a42542b3c6143ad1", "shasum": "" }, "require": { @@ -7038,7 +7087,7 @@ "description": "Symfony Yaml Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v4.4.16" + "source": "https://github.com/symfony/yaml/tree/v4.4.17" }, "funding": [ { @@ -7054,30 +7103,30 @@ "type": "tidelift" } ], - "time": "2020-10-24T11:50:19+00:00" + "time": "2020-11-24T12:28:30+00:00" }, { "name": "tightenco/collect", - "version": "v5.6.33", + "version": "v5.8.38", "source": { "type": "git", "url": "https://github.com/tighten/collect.git", - "reference": "d7381736dca44ac17d0805a25191b094e5a22446" + "reference": "c93a7039e6207ad533a09109838fe80933fcc72c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tighten/collect/zipball/d7381736dca44ac17d0805a25191b094e5a22446", - "reference": "d7381736dca44ac17d0805a25191b094e5a22446", + "url": "https://api.github.com/repos/tighten/collect/zipball/c93a7039e6207ad533a09109838fe80933fcc72c", + "reference": "c93a7039e6207ad533a09109838fe80933fcc72c", "shasum": "" }, "require": { - "php": ">=7.1.3", - "symfony/var-dumper": ">=3.1.10" + "php": "^7.1.3", + "symfony/var-dumper": ">=3.4 <5" }, "require-dev": { - "mockery/mockery": "~1.0", - "nesbot/carbon": "~1.20", - "phpunit/phpunit": "~7.0" + "mockery/mockery": "^1.0", + "nesbot/carbon": "^1.26.3", + "phpunit/phpunit": "^7.0" }, "type": "library", "autoload": { @@ -7106,9 +7155,9 @@ ], "support": { "issues": "https://github.com/tighten/collect/issues", - "source": "https://github.com/tighten/collect/tree/v5.6.33" + "source": "https://github.com/tighten/collect/tree/v5.8.38" }, - "time": "2018-08-09T16:56:26+00:00" + "time": "2019-09-17T18:57:01+00:00" }, { "name": "twig/twig", diff --git a/api/config/bootstrap.php b/api/config/bootstrap.php new file mode 100644 index 0000000..55560fb --- /dev/null +++ b/api/config/bootstrap.php @@ -0,0 +1,23 @@ +<?php + +use Symfony\Component\Dotenv\Dotenv; + +require dirname(__DIR__).'/vendor/autoload.php'; + +if (!class_exists(Dotenv::class)) { + throw new LogicException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.'); +} + +// Load cached env vars if the .env.local.php file exists +// Run "composer dump-env prod" to create it (requires symfony/flex >=1.2) +if (is_array($env = @include dirname(__DIR__).'/.env.local.php') && (!isset($env['APP_ENV']) || ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? $env['APP_ENV']) === $env['APP_ENV'])) { + (new Dotenv(false))->populate($env); +} else { + // load all the .env files + (new Dotenv(false))->loadEnv(dirname(__DIR__).'/.env'); +} + +$_SERVER += $_ENV; +$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev'; +$_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV']; +$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0'; diff --git a/api/config/packages/cache.yaml b/api/config/packages/cache.yaml new file mode 100644 index 0000000..6899b72 --- /dev/null +++ b/api/config/packages/cache.yaml @@ -0,0 +1,19 @@ +framework: + cache: + # Unique name of your app: used to compute stable namespaces for cache keys. + #prefix_seed: your_vendor_name/app_name + + # The "app" cache stores to the filesystem by default. + # The data in this cache should persist between deploys. + # Other options include: + + # Redis + #app: cache.adapter.redis + #default_redis_provider: redis://localhost + + # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) + #app: cache.adapter.apcu + + # Namespaced pools use the above "app" backend by default + #pools: + #my.dedicated.cache: null diff --git a/api/config/packages/doctrine.yaml b/api/config/packages/doctrine.yaml index ca2f098..42dc149 100644 --- a/api/config/packages/doctrine.yaml +++ b/api/config/packages/doctrine.yaml @@ -5,14 +5,13 @@ doctrine: dbal: driver: 'pdo_sqlite' url: '%env(resolve:DATABASE_URL)%' - logging: true - profiling: true + logging: '%kernel.debug%' + profiling: '%kernel.debug%' types: datetime: App\Doctrine\CarbonDateTimeType - orm: - auto_generate_proxy_classes: '%kernel.debug%' - naming_strategy: doctrine.orm.naming_strategy.underscore + auto_generate_proxy_classes: true + naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware auto_mapping: true mappings: App: @@ -20,4 +19,4 @@ doctrine: type: annotation dir: '%kernel.project_dir%/src/Entity' prefix: 'App\Entity' - alias: Entity + alias: App diff --git a/api/config/packages/doctrine_migrations.yaml b/api/config/packages/doctrine_migrations.yaml index 70959a6..263db11 100644 --- a/api/config/packages/doctrine_migrations.yaml +++ b/api/config/packages/doctrine_migrations.yaml @@ -1,3 +1,3 @@ doctrine_migrations: - dir_name: '%kernel.project_dir%/src/Migrations' - namespace: DoctrineMigrations + migrations_paths: + 'DoctrineMigrations': '%kernel.project_dir%/migrations' diff --git a/api/config/packages/framework.yaml b/api/config/packages/framework.yaml index 8b24418..aaed681 100644 --- a/api/config/packages/framework.yaml +++ b/api/config/packages/framework.yaml @@ -1,30 +1,6 @@ framework: secret: '%env(APP_SECRET)%' - #default_locale: en - #csrf_protection: true - #http_method_override: true + csrf_protection: false - # Enables session support. Note that the session will ONLY be started if you read or write from it. - # Remove or comment this section to explicitly disable session support. - session: - handler_id: ~ - - #esi: true - #fragments: true php_errors: log: true - - cache: - # Put the unique name of your app here: the prefix seed - # is used to compute stable namespaces for cache keys. - #prefix_seed: your_vendor_name/app_name - - # The app cache caches to the filesystem by default. - # Other options include: - - # Redis - #app: cache.adapter.redis - #default_redis_provider: redis://localhost - - # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) - #app: cache.adapter.apcu diff --git a/api/config/packages/prod/doctrine.yaml b/api/config/packages/prod/doctrine.yaml index 2f16f0f..084f59a 100644 --- a/api/config/packages/prod/doctrine.yaml +++ b/api/config/packages/prod/doctrine.yaml @@ -1,26 +1,15 @@ doctrine: orm: + auto_generate_proxy_classes: false metadata_cache_driver: - type: service - id: doctrine.system_cache_provider + type: pool + pool: doctrine.system_cache_pool query_cache_driver: - type: service - id: doctrine.system_cache_provider + type: pool + pool: doctrine.system_cache_pool result_cache_driver: - type: service - id: doctrine.result_cache_provider - -services: - doctrine.result_cache_provider: - class: Symfony\Component\Cache\DoctrineProvider - public: false - arguments: - - '@doctrine.result_cache_pool' - doctrine.system_cache_provider: - class: Symfony\Component\Cache\DoctrineProvider - public: false - arguments: - - '@doctrine.system_cache_pool' + type: pool + pool: doctrine.result_cache_pool framework: cache: diff --git a/api/config/packages/test/twig.yaml b/api/config/packages/test/twig.yaml new file mode 100644 index 0000000..8c6e0b4 --- /dev/null +++ b/api/config/packages/test/twig.yaml @@ -0,0 +1,2 @@ +twig: + strict_variables: true diff --git a/api/config/packages/twig.yaml b/api/config/packages/twig.yaml index 3b315dc..6403e6a 100644 --- a/api/config/packages/twig.yaml +++ b/api/config/packages/twig.yaml @@ -1,4 +1,5 @@ twig: - paths: ['%kernel.project_dir%/templates'] + default_path: '%kernel.project_dir%/templates' debug: '%kernel.debug%' strict_variables: '%kernel.debug%' + exception_controller: null diff --git a/api/config/preload.php b/api/config/preload.php new file mode 100644 index 0000000..064bdcd --- /dev/null +++ b/api/config/preload.php @@ -0,0 +1,9 @@ +<?php + +if (file_exists(dirname(__DIR__).'/var/cache/prod/srcApp_KernelProdContainer.preload.php')) { + require dirname(__DIR__).'/var/cache/prod/srcApp_KernelProdContainer.preload.php'; +} + +if (file_exists(dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php')) { + require dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php'; +} diff --git a/api/dev.Dockerfile b/api/dev.Dockerfile index 5db7050..51fb1d1 100644 --- a/api/dev.Dockerfile +++ b/api/dev.Dockerfile @@ -8,8 +8,8 @@ RUN apk add --no-cache autoconf openssl-dev g++ make pcre-dev icu-dev zlib-dev l # XDebug RUN pecl install xdebug-3.0.0 && docker-php-ext-enable xdebug -RUN echo "xdebug.mode = develop,debug" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \ - echo "xdebug.discover_client_host = On" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; +RUN echo "xdebug.mode=debug" >> $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini && \ + echo "xdebug.discover_client_host=On" >> $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini; RUN apk del --purge autoconf g++ make @@ -26,7 +26,7 @@ RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \ COPY --from=composer:latest /usr/bin/composer /usr/bin/composer # Timezone -RUN ln -snf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime && +RUN ln -snf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime && \ echo "date.timezone = Europe/Warsaw" >> /usr/local/etc/php/conf.d/datetime.ini; WORKDIR /var/www diff --git a/api/src/Controller/.gitignore b/api/migrations/.gitignore similarity index 100% rename from api/src/Controller/.gitignore rename to api/migrations/.gitignore diff --git a/api/src/Migrations/Version20180907212032.php b/api/migrations/Version20180907212032.php similarity index 100% rename from api/src/Migrations/Version20180907212032.php rename to api/migrations/Version20180907212032.php diff --git a/api/src/Migrations/Version20181027124203.php b/api/migrations/Version20181027124203.php similarity index 100% rename from api/src/Migrations/Version20181027124203.php rename to api/migrations/Version20181027124203.php diff --git a/api/src/Migrations/Version20190111212909.php b/api/migrations/Version20190111212909.php similarity index 100% rename from api/src/Migrations/Version20190111212909.php rename to api/migrations/Version20190111212909.php diff --git a/api/src/Migrations/Version20200103160747.php b/api/migrations/Version20200103160747.php similarity index 100% rename from api/src/Migrations/Version20200103160747.php rename to api/migrations/Version20200103160747.php diff --git a/api/src/Migrations/Version20200103170517.php b/api/migrations/Version20200103170517.php similarity index 100% rename from api/src/Migrations/Version20200103170517.php rename to api/migrations/Version20200103170517.php diff --git a/api/src/Migrations/Version20200131151757.php b/api/migrations/Version20200131151757.php similarity index 100% rename from api/src/Migrations/Version20200131151757.php rename to api/migrations/Version20200131151757.php diff --git a/api/src/Migrations/Version20200206183956.php b/api/migrations/Version20200206183956.php similarity index 100% rename from api/src/Migrations/Version20200206183956.php rename to api/migrations/Version20200206183956.php diff --git a/api/src/Migrations/Version20200314112552.php b/api/migrations/Version20200314112552.php similarity index 100% rename from api/src/Migrations/Version20200314112552.php rename to api/migrations/Version20200314112552.php diff --git a/api/public/index.php b/api/public/index.php index 980d765..d0b6e02 100644 --- a/api/public/index.php +++ b/api/public/index.php @@ -1,39 +1,26 @@ <?php use App\Kernel; -use Symfony\Component\Dotenv\Dotenv; use Symfony\Component\ErrorHandler\Debug; use Symfony\Component\HttpFoundation\Request; -require __DIR__.'/../vendor/autoload.php'; +require dirname(__DIR__).'/config/bootstrap.php'; -// The check is to ensure we don't use .env in production -if (!isset($_SERVER['APP_ENV'])) { - if (!class_exists(Dotenv::class)) { - throw new \RuntimeException('APP_ENV environment variable is not defined. You need to define environment variables for configuration or add "symfony/dotenv" as a Composer dependency to load variables from a .env file.'); - } - (new Dotenv())->load(__DIR__.'/../.env'); -} - -$env = $_SERVER['APP_ENV'] ?? 'dev'; -$debug = (bool) ($_SERVER['APP_DEBUG'] ?? ('prod' !== $env)); - -if ($debug) { +if ($_SERVER['APP_DEBUG']) { umask(0000); Debug::enable(); } if ($trustedProxies = $_SERVER['TRUSTED_PROXIES'] ?? false) { - Request::setTrustedProxies(explode(',', $trustedProxies), Request::HEADER_X_FORWARDED_ALL ^ Request::HEADER_X_FORWARDED_HOST); + Request::setTrustedProxies(explode(',', $trustedProxies), Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO); } if ($trustedHosts = $_SERVER['TRUSTED_HOSTS'] ?? false) { - Request::setTrustedHosts(explode(',', $trustedHosts)); + Request::setTrustedHosts([$trustedHosts]); } -\Doctrine\Common\Annotations\AnnotationReader::addGlobalIgnoredName('alias'); -$kernel = new Kernel($env, $debug); +$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send(); diff --git a/api/src/Functions/index.php b/api/src/Functions/index.php index a0028ce..5215295 100644 --- a/api/src/Functions/index.php +++ b/api/src/Functions/index.php @@ -1,3 +1,3 @@ <?php -require_once __DIR__ . '/helpers.php'; \ No newline at end of file +require_once __DIR__ . '/helpers.php'; diff --git a/api/src/Kernel.php b/api/src/Kernel.php index 68c3c16..1cd0572 100644 --- a/api/src/Kernel.php +++ b/api/src/Kernel.php @@ -2,7 +2,6 @@ namespace App; -use Doctrine\Common\Annotations\AnnotationReader; use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\Config\Resource\FileResource; @@ -14,53 +13,42 @@ class Kernel extends BaseKernel { use MicroKernelTrait; - const CONFIG_EXTS = '.{php,xml,yaml,yml}'; + private const CONFIG_EXTS = '.{php,xml,yaml,yml}'; - public function getCacheDir() - { - return $this->getProjectDir().'/var/cache/'.$this->environment; - } - - public function getLogDir() - { - return $this->getProjectDir().'/var/log'; - } - - public function registerBundles() + public function registerBundles(): iterable { $contents = require $this->getProjectDir().'/config/bundles.php'; foreach ($contents as $class => $envs) { - if (isset($envs['all']) || isset($envs[$this->environment])) { + if ($envs[$this->environment] ?? $envs['all'] ?? false) { yield new $class(); } } } - protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader) + public function getProjectDir(): string + { + return \dirname(__DIR__); + } + + protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader): void { $container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php')); - // Feel free to remove the "container.autowiring.strict_mode" parameter - // if you are using symfony/dependency-injection 4.0+ as it's the default behavior - $container->setParameter('container.autowiring.strict_mode', true); - $container->setParameter('container.dumper.inline_class_loader', true); + $container->setParameter('container.dumper.inline_class_loader', \PHP_VERSION_ID < 70400 || $this->debug); + $container->setParameter('container.dumper.inline_factories', true); $confDir = $this->getProjectDir().'/config'; $loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob'); - $loader->load($confDir.'/{packages}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob'); + $loader->load($confDir.'/{packages}/'.$this->environment.'/*'.self::CONFIG_EXTS, 'glob'); $loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob'); $loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob'); - - if (!file_exists($this->getCacheDir().'/proxy')) { - mkdir($this->getCacheDir().'/proxy'); - } } - protected function configureRoutes(RouteCollectionBuilder $routes) + protected function configureRoutes(RouteCollectionBuilder $routes): void { $confDir = $this->getProjectDir().'/config'; + $routes->import($confDir.'/{routes}/'.$this->environment.'/*'.self::CONFIG_EXTS, '/', 'glob'); $routes->import($confDir.'/{routes}/*'.self::CONFIG_EXTS, '/', 'glob'); - $routes->import($confDir.'/{routes}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, '/', 'glob'); $routes->import($confDir.'/{routes}'.self::CONFIG_EXTS, '/', 'glob'); } } diff --git a/api/src/Migrations/.gitignore b/api/src/Migrations/.gitignore deleted file mode 100644 index e69de29..0000000 diff --git a/api/symfony.lock b/api/symfony.lock index c2bc392..a73e0f8 100644 --- a/api/symfony.lock +++ b/api/symfony.lock @@ -42,25 +42,35 @@ "version": "v2.8.0" }, "doctrine/doctrine-bundle": { - "version": "1.6", + "version": "2.0", "recipe": { "repo": "github.com/symfony/recipes", "branch": "master", - "version": "1.6", - "ref": "ae205d5114e719deb64d2110f56ef910787d1e04" - } + "version": "2.0", + "ref": "368794356c1fb634e58b38ad2addb36933f2e73e" + }, + "files": [ + "config/packages/doctrine.yaml", + "config/packages/prod/doctrine.yaml", + "src/Entity/.gitignore", + "src/Repository/.gitignore" + ] }, "doctrine/doctrine-cache-bundle": { "version": "1.3.3" }, "doctrine/doctrine-migrations-bundle": { - "version": "1.2", + "version": "2.2", "recipe": { "repo": "github.com/symfony/recipes", "branch": "master", - "version": "1.2", - "ref": "c1431086fec31f17fbcfe6d6d7e92059458facc1" - } + "version": "2.2", + "ref": "baaa439e3e3179e69e3da84b671f0a3e4a2f56ad" + }, + "files": [ + "config/packages/doctrine_migrations.yaml", + "migrations/.gitignore" + ] }, "doctrine/event-manager": { "version": "v1.0.0" @@ -271,9 +281,6 @@ "symfony/dependency-injection": { "version": "v4.1.3" }, - "symfony/deprecation-contracts": { - "version": "v2.2.0" - }, "symfony/doctrine-bridge": { "version": "v4.1.4" }, @@ -301,17 +308,32 @@ "repo": "github.com/symfony/recipes", "branch": "master", "version": "1.0", - "ref": "e921bdbfe20cdefa3b82f379d1cd36df1bc8d115" - } + "ref": "c0eeb50665f0f77226616b6038a9b06c03752d8e" + }, + "files": [ + ".env" + ] }, "symfony/framework-bundle": { - "version": "3.3", + "version": "4.4", "recipe": { "repo": "github.com/symfony/recipes", "branch": "master", - "version": "3.3", - "ref": "87c585d24de9f43bca80ebcfd5cf5cb39445d95f" - } + "version": "4.4", + "ref": "df1f2fe60b8fbb5cf7e26a7af19445c128a13b90" + }, + "files": [ + "config/bootstrap.php", + "config/packages/cache.yaml", + "config/packages/framework.yaml", + "config/packages/test/framework.yaml", + "config/preload.php", + "config/routes/dev/framework.yaml", + "config/services.yaml", + "public/index.php", + "src/Controller/.gitignore", + "src/Kernel.php" + ] }, "symfony/http-client-contracts": { "version": "v2.3.1" @@ -346,9 +368,6 @@ "symfony/orm-pack": { "version": "v1.0.5" }, - "symfony/polyfill-intl-grapheme": { - "version": "v1.20.0" - }, "symfony/polyfill-intl-idn": { "version": "v1.13.1" }, @@ -358,6 +377,9 @@ "symfony/polyfill-mbstring": { "version": "v1.9.0" }, + "symfony/polyfill-php72": { + "version": "v1.20.0" + }, "symfony/polyfill-php73": { "version": "v1.13.1" }, @@ -397,9 +419,6 @@ "symfony/stopwatch": { "version": "v4.1.12" }, - "symfony/string": { - "version": "v5.1.8" - }, "symfony/translation": { "version": "3.3", "recipe": { @@ -416,13 +435,18 @@ "version": "v4.1.3" }, "symfony/twig-bundle": { - "version": "3.3", + "version": "4.4", "recipe": { "repo": "github.com/symfony/recipes", "branch": "master", - "version": "3.3", - "ref": "f75ac166398e107796ca94cc57fa1edaa06ec47f" - } + "version": "4.4", + "ref": "15a41bbd66a1323d09824a189b485c126bbefa51" + }, + "files": [ + "config/packages/test/twig.yaml", + "config/packages/twig.yaml", + "templates/base.html.twig" + ] }, "symfony/var-dumper": { "version": "v4.1.3" -- 2.45.2 From c17c9f212205c7d7474435b83eff844c3bc1011c Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Tue, 1 Dec 2020 21:23:37 +0100 Subject: [PATCH 62/77] #50 - Autocreate proxy dir --- api/src/Service/Proxy/FileLocator.php | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 api/src/Service/Proxy/FileLocator.php diff --git a/api/src/Service/Proxy/FileLocator.php b/api/src/Service/Proxy/FileLocator.php new file mode 100644 index 0000000..4abee52 --- /dev/null +++ b/api/src/Service/Proxy/FileLocator.php @@ -0,0 +1,10 @@ +<?php + + +namespace App\Service\Proxy; + + +class FileLocator +{ + +} -- 2.45.2 From 0e73a000702b989f1f415a593654dd88f963c626 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Fri, 18 Dec 2020 15:19:58 +0100 Subject: [PATCH 63/77] #50 - Add simple README and LICENSE files --- LICENSE.md | 0 README.md | 0 api/bin/docker-init.sh | 5 +++++ api/config/services.yaml | 3 +-- api/fpm.Dockerfile | 5 +++-- api/rr.Dockerfile | 5 +++-- api/src/Service/Proxy/FileLocator.php | 13 ++++++++++--- 7 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 LICENSE.md create mode 100644 README.md create mode 100755 api/bin/docker-init.sh diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/api/bin/docker-init.sh b/api/bin/docker-init.sh new file mode 100755 index 0000000..0799aea --- /dev/null +++ b/api/bin/docker-init.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +./bin/console doctrine:migrations:migrate --no-interaction + +exec "$@" diff --git a/api/config/services.yaml b/api/config/services.yaml index 7b8e853..aeb122d 100644 --- a/api/config/services.yaml +++ b/api/config/services.yaml @@ -53,7 +53,7 @@ services: #proxy configuration proxy.locator: - class: 'ProxyManager\FileLocator\FileLocator' + class: 'App\Service\Proxy\FileLocator' arguments: ['%kernel.cache_dir%/proxy'] proxy.strategy: @@ -68,7 +68,6 @@ services: ProxyManager\Configuration: '@proxy.config' - # converter App\Service\AggregateConverter: arguments: diff --git a/api/fpm.Dockerfile b/api/fpm.Dockerfile index d3b9fe2..f5955a5 100644 --- a/api/fpm.Dockerfile +++ b/api/fpm.Dockerfile @@ -1,7 +1,8 @@ FROM php:7.4-fpm-alpine ENV APP_ENV=prod -ENV DATABASE_URL="sqlite:///var/db/app.db" +ENV DATABASE_URL="sqlite:////var/db/app.db" +ENV PATH=$PATH:/usr/src/app/bin RUN apk add --no-cache autoconf openssl-dev g++ make pcre-dev icu-dev zlib-dev libzip-dev git && \ docker-php-ext-install bcmath intl opcache zip sockets && \ @@ -21,4 +22,4 @@ RUN ln -snf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime && WORKDIR /var/www -EXPOSE 9001 +CMD ["./bin/docker-init.sh", "php-fpm"] diff --git a/api/rr.Dockerfile b/api/rr.Dockerfile index 59b914f..56fa7e2 100644 --- a/api/rr.Dockerfile +++ b/api/rr.Dockerfile @@ -1,7 +1,8 @@ FROM php:7.4-alpine ENV APP_ENV=prod -ENV DATABASE_URL="sqlite:///var/db/app.db" +ENV DATABASE_URL="sqlite:////var/db/app.db" +ENV PATH=$PATH:/usr/src/app/bin RUN apk add --no-cache autoconf openssl-dev g++ make pcre-dev icu-dev zlib-dev libzip-dev git && \ docker-php-ext-install bcmath intl opcache zip sockets && \ @@ -21,4 +22,4 @@ RUN composer dump-autoload --optimize && \ EXPOSE 8080 -CMD ["rr", "serve"] +CMD ["./bin/docker-init.sh", "rr", "serve"] diff --git a/api/src/Service/Proxy/FileLocator.php b/api/src/Service/Proxy/FileLocator.php index 4abee52..0d34263 100644 --- a/api/src/Service/Proxy/FileLocator.php +++ b/api/src/Service/Proxy/FileLocator.php @@ -1,10 +1,17 @@ <?php - namespace App\Service\Proxy; - -class FileLocator +final class FileLocator extends \ProxyManager\FileLocator\FileLocator { + public function __construct(string $proxiesDirectory) + { + $absolutePath = realpath($proxiesDirectory); + if ($absolutePath === false) { + mkdir($proxiesDirectory, 0755, true); + } + + parent::__construct($proxiesDirectory); + } } -- 2.45.2 From f1033cd6894af8f4271dd0a5749d56c81a6c8044 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sat, 19 Dec 2020 09:38:54 +0100 Subject: [PATCH 64/77] #50 - Add simple README and LICENSE files --- LICENSE.md | 41 +++++++++++++++++++++++++++++++++++++++++ README.md | 21 +++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/LICENSE.md b/LICENSE.md index e69de29..92d7487 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -0,0 +1,41 @@ +“Commons Clause” License Condition v1.0 + +The Software is provided to you by the Licensor under the License, as defined +below, subject to the following condition. + +Without limiting other conditions in the License, the grant of rights under the +License will not include, and the License does not grant to you, the right to +Sell the Software. + +For purposes of the foregoing, “Sell” means practicing any or all of the rights +granted to you under the License to provide to third parties, for a fee or other +consideration (including without limitation fees for hosting or consulting/ +support services related to the Software), a product or service whose value +derives, entirely or substantially, from the functionality of the Software. Any +license notice or attribution required by the License must also include this +Commons Clause License Condition notice. + +Software: Co Jedzie + +License: MIT + +Licensor: Kacper Donat + +Copyright 2020 Kacper Donat + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index e69de29..ef893b0 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,21 @@ +# [Co Jedzie](https://cojedzie.pl) + + + +Co Jedzie is an app that allows you to quickly and easily check realtime departure times on public transport stops. It +aims to be the central hub for all public transport information you will need. + +You can use the app at [cojedzie.pl](https://cojedzie.pl). + +# Available cities +For now tricity is the only available data source. + +# Contributing +Want to contribute? + +# License +This project is [fair-code](https://faircode.io/) licensed under [MIT with Commons Clause](./LICENSE.md). Basically, Co +Jedzie is free and code is available to everyone, but it's not allowed to make money directly with it. + +Note that data collected from available data sources is licensed by their respective owners, thus it may be +available under different terms than the project itself and may require additional permissions to use. -- 2.45.2 From f6bbe6cf0fbe9de530a1327d9bcf970156f3dd7f Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Wed, 31 Mar 2021 21:08:33 +0200 Subject: [PATCH 65/77] #50 - Update PHP dependencies --- api/.rr.yaml | 2 +- api/composer.json | 3 +- api/composer.lock | 1206 +++++++++++++++++++++++++------------------- api/dev.Dockerfile | 15 +- api/symfony.lock | 9 + docker/php/.env | 2 +- 6 files changed, 706 insertions(+), 531 deletions(-) diff --git a/api/.rr.yaml b/api/.rr.yaml index 8360a06..79cff58 100644 --- a/api/.rr.yaml +++ b/api/.rr.yaml @@ -9,5 +9,5 @@ http: relay: "unix://var/roadrunner.sock" static: - dir: "public" + dir: "public" forbid: [".php", ".htaccess"] diff --git a/api/composer.json b/api/composer.json index 49dd6d3..cab8897 100644 --- a/api/composer.json +++ b/api/composer.json @@ -1,7 +1,8 @@ { "name": "kadet/cojedzie", + "description": "Co Jedzie", "type": "project", - "license": "MIT", + "license": "MIT with Commons Clause", "require": { "php": "^7.1.3", "ext-ctype": "*", diff --git a/api/composer.lock b/api/composer.lock index 79d594b..b5b35d6 100644 --- a/api/composer.lock +++ b/api/composer.lock @@ -8,20 +8,21 @@ "packages": [ { "name": "baldinof/roadrunner-bundle", - "version": "1.3.3", + "version": "1.5.3", "source": { "type": "git", "url": "https://github.com/Baldinof/roadrunner-bundle.git", - "reference": "c377846b5fe7529b207a4b803c91d752a532aa2f" + "reference": "541bfe21cf76233f70b2b840b8f8260c6b779d83" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Baldinof/roadrunner-bundle/zipball/c377846b5fe7529b207a4b803c91d752a532aa2f", - "reference": "c377846b5fe7529b207a4b803c91d752a532aa2f", + "url": "https://api.github.com/repos/Baldinof/roadrunner-bundle/zipball/541bfe21cf76233f70b2b840b8f8260c6b779d83", + "reference": "541bfe21cf76233f70b2b840b8f8260c6b779d83", "shasum": "" }, "require": { - "dflydev/fig-cookies": "^2.0", + "dflydev/fig-cookies": "^3.0", + "jean85/pretty-package-versions": "^1.5 || ^2.0", "php": ">=7.3", "php-http/discovery": "^1.9", "psr/http-factory": "^1.0", @@ -37,10 +38,13 @@ "symfony/psr-http-message-bridge": "^1.1 || ^2.0", "symfony/yaml": "^4.4 || ^5.0" }, + "conflict": { + "doctrine/doctrine-bundle": "<2.1.1" + }, "require-dev": { "blackfire/php-sdk": "^1.21", - "doctrine/doctrine-bundle": "^2.0", - "doctrine/mongodb-odm-bundle": "^4.1", + "doctrine/doctrine-bundle": "^2.1.1", + "doctrine/mongodb-odm": "^2.2", "doctrine/orm": "^2.7.3", "friendsofphp/php-cs-fixer": "^2.16", "nyholm/psr7": "^1.2", @@ -49,7 +53,7 @@ "phpspec/prophecy-phpunit": "^2.0", "phpstan/phpstan": "^0.12.2", "phpunit/phpunit": "^9.1", - "sentry/sentry-symfony": "^3.4", + "sentry/sentry-symfony": "^3.4||^4.0", "symfony/framework-bundle": "^4.0||^5.0", "symfony/proxy-manager-bridge": "^4.0 || ^5.0", "symfony/var-dumper": "^4.0||^5.0" @@ -81,7 +85,7 @@ "description": "A RoadRunner worker as a Symfony Bundle", "support": { "issues": "https://github.com/Baldinof/roadrunner-bundle/issues", - "source": "https://github.com/Baldinof/roadrunner-bundle/tree/1.3.3" + "source": "https://github.com/Baldinof/roadrunner-bundle/tree/1.5.3" }, "funding": [ { @@ -89,29 +93,29 @@ "type": "github" } ], - "time": "2020-09-25T09:54:58+00:00" + "time": "2021-03-30T07:23:57+00:00" }, { "name": "cerbero/json-objects", - "version": "v1.1.2", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/cerbero90/json-objects.git", - "reference": "21eac219bb20ca80318fec88821217d7417ee09a" + "reference": "d0e2bfed9b5562746733865ec3f5c1febc0b5534" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cerbero90/json-objects/zipball/21eac219bb20ca80318fec88821217d7417ee09a", - "reference": "21eac219bb20ca80318fec88821217d7417ee09a", + "url": "https://api.github.com/repos/cerbero90/json-objects/zipball/d0e2bfed9b5562746733865ec3f5c1febc0b5534", + "reference": "d0e2bfed9b5562746733865ec3f5c1febc0b5534", "shasum": "" }, "require": { - "php": "~7.1", + "php": "^7.1||^8.0", "psr/http-message": "^1.0", - "salsify/json-streaming-parser": "^8.0" + "salsify/json-streaming-parser": "^8.2" }, "require-dev": { - "mockery/mockery": "^1.2", + "mockery/mockery": "^1.3", "phpunit/phpunit": ">=7.0", "squizlabs/php_codesniffer": "^3.0" }, @@ -149,9 +153,9 @@ ], "support": { "issues": "https://github.com/cerbero90/json-objects/issues", - "source": "https://github.com/cerbero90/json-objects/tree/v1.1.2" + "source": "https://github.com/cerbero90/json-objects/tree/v1.2.0" }, - "time": "2019-04-26T13:04:36+00:00" + "time": "2021-01-14T01:52:31+00:00" }, { "name": "composer/package-versions-deprecated", @@ -228,33 +232,37 @@ }, { "name": "dflydev/fig-cookies", - "version": "v2.0.1", + "version": "v3.0.0", "source": { "type": "git", "url": "https://github.com/dflydev/dflydev-fig-cookies.git", - "reference": "733af78ddad60aec96f7c4a1204619dd4d62afff" + "reference": "ea6934204b1b34ffdf5130dc7e0928d18ced2498" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dflydev/dflydev-fig-cookies/zipball/733af78ddad60aec96f7c4a1204619dd4d62afff", - "reference": "733af78ddad60aec96f7c4a1204619dd4d62afff", + "url": "https://api.github.com/repos/dflydev/dflydev-fig-cookies/zipball/ea6934204b1b34ffdf5130dc7e0928d18ced2498", + "reference": "ea6934204b1b34ffdf5130dc7e0928d18ced2498", "shasum": "" }, "require": { "ext-pcre": "*", - "php": "^7.2", + "php": "^7.2 || ^8.0", "psr/http-message": "^1" }, "require-dev": { - "doctrine/coding-standard": "^4", - "phpstan/phpstan": "^0.10.1", - "phpunit/phpunit": "^7.2.6", - "squizlabs/php_codesniffer": "^3.3" + "doctrine/coding-standard": "^8", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12.16", + "phpunit/phpunit": "^7.2.6 || ^9", + "scrutinizer/ocular": "^1.8", + "squizlabs/php_codesniffer": "^3.3", + "vimeo/psalm": "^4.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-main": "3.0.x-dev" } }, "autoload": { @@ -280,22 +288,22 @@ ], "support": { "issues": "https://github.com/dflydev/dflydev-fig-cookies/issues", - "source": "https://github.com/dflydev/dflydev-fig-cookies/tree/v2.0.1" + "source": "https://github.com/dflydev/dflydev-fig-cookies/tree/v3.0.0" }, - "time": "2020-01-02T16:13:22+00:00" + "time": "2021-01-22T02:53:56+00:00" }, { "name": "doctrine/annotations", - "version": "1.11.1", + "version": "1.12.1", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad" + "reference": "b17c5014ef81d212ac539f07a1001832df1b6d3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/ce77a7ba1770462cd705a91a151b6c3746f9c6ad", - "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/b17c5014ef81d212ac539f07a1001832df1b6d3b", + "reference": "b17c5014ef81d212ac539f07a1001832df1b6d3b", "shasum": "" }, "require": { @@ -310,11 +318,6 @@ "phpunit/phpunit": "^7.5 || ^9.1.5" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" @@ -355,9 +358,9 @@ ], "support": { "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.11.1" + "source": "https://github.com/doctrine/annotations/tree/1.12.1" }, - "time": "2020-10-26T10:28:16+00:00" + "time": "2021-02-21T21:00:45+00:00" }, { "name": "doctrine/cache", @@ -631,32 +634,32 @@ }, { "name": "doctrine/dbal", - "version": "2.12.1", + "version": "2.13.0", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "adce7a954a1c2f14f85e94aed90c8489af204086" + "reference": "67d56d3203b33db29834e6b2fcdbfdc50535d796" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/adce7a954a1c2f14f85e94aed90c8489af204086", - "reference": "adce7a954a1c2f14f85e94aed90c8489af204086", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/67d56d3203b33db29834e6b2fcdbfdc50535d796", + "reference": "67d56d3203b33db29834e6b2fcdbfdc50535d796", "shasum": "" }, "require": { "doctrine/cache": "^1.0", + "doctrine/deprecations": "^0.5.3", "doctrine/event-manager": "^1.0", "ext-pdo": "*", - "php": "^7.3 || ^8" + "php": "^7.1 || ^8" }, "require-dev": { - "doctrine/coding-standard": "^8.1", - "jetbrains/phpstorm-stubs": "^2019.1", - "phpstan/phpstan": "^0.12.40", - "phpunit/phpunit": "^9.4", - "psalm/plugin-phpunit": "^0.10.0", + "doctrine/coding-standard": "8.2.0", + "jetbrains/phpstorm-stubs": "2020.2", + "phpstan/phpstan": "0.12.81", + "phpunit/phpunit": "^7.5.20|^8.5|9.5.0", "symfony/console": "^2.0.5|^3.0|^4.0|^5.0", - "vimeo/psalm": "^3.17.2" + "vimeo/psalm": "4.6.4" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -665,11 +668,6 @@ "bin/doctrine-dbal" ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\DBAL\\": "lib/Doctrine/DBAL" @@ -722,7 +720,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/2.12.1" + "source": "https://github.com/doctrine/dbal/tree/2.13.0" }, "funding": [ { @@ -738,20 +736,63 @@ "type": "tidelift" } ], - "time": "2020-11-14T20:26:58+00:00" + "time": "2021-03-28T18:10:53+00:00" }, { - "name": "doctrine/doctrine-bundle", - "version": "2.2.1", + "name": "doctrine/deprecations", + "version": "v0.5.3", "source": { "type": "git", - "url": "https://github.com/doctrine/DoctrineBundle.git", - "reference": "9e07bb1ff35d35d9ec4597b79e5d05502d7d4d43" + "url": "https://github.com/doctrine/deprecations.git", + "reference": "9504165960a1f83cc1480e2be1dd0a0478561314" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/9e07bb1ff35d35d9ec4597b79e5d05502d7d4d43", - "reference": "9e07bb1ff35d35d9ec4597b79e5d05502d7d4d43", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/9504165960a1f83cc1480e2be1dd0a0478561314", + "reference": "9504165960a1f83cc1480e2be1dd0a0478561314", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0|^7.0|^8.0", + "phpunit/phpunit": "^7.0|^8.0|^9.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/v0.5.3" + }, + "time": "2021-03-21T12:59:47+00:00" + }, + { + "name": "doctrine/doctrine-bundle", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/DoctrineBundle.git", + "reference": "8b922578bdee2243a26202b13df795e170efaef8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/8b922578bdee2243a26202b13df795e170efaef8", + "reference": "8b922578bdee2243a26202b13df795e170efaef8", "shasum": "" }, "require": { @@ -774,8 +815,8 @@ "require-dev": { "doctrine/coding-standard": "^8.0", "doctrine/orm": "^2.6", - "ocramius/proxy-manager": "^2.1", - "phpunit/phpunit": "^7.5 || ^9.3", + "friendsofphp/proxy-manager-lts": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.0 || ^9.3", "symfony/phpunit-bridge": "^4.2", "symfony/property-info": "^4.3.3|^5.0", "symfony/proxy-manager-bridge": "^3.4|^4.3.3|^5.0", @@ -832,7 +873,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineBundle/issues", - "source": "https://github.com/doctrine/DoctrineBundle/tree/2.2.1" + "source": "https://github.com/doctrine/DoctrineBundle/tree/2.3.0" }, "funding": [ { @@ -848,7 +889,7 @@ "type": "tidelift" } ], - "time": "2020-11-10T20:42:15+00:00" + "time": "2021-03-16T16:24:04+00:00" }, { "name": "doctrine/doctrine-cache-bundle", @@ -948,30 +989,30 @@ }, { "name": "doctrine/doctrine-migrations-bundle", - "version": "2.2.1", + "version": "2.2.2", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineMigrationsBundle.git", - "reference": "955077b68c377310cf9538fc982be11d36ab75d4" + "reference": "85f0b847174daf243362c7da80efe1539be64f47" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/955077b68c377310cf9538fc982be11d36ab75d4", - "reference": "955077b68c377310cf9538fc982be11d36ab75d4", + "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/85f0b847174daf243362c7da80efe1539be64f47", + "reference": "85f0b847174daf243362c7da80efe1539be64f47", "shasum": "" }, "require": { "doctrine/doctrine-bundle": "~1.0|~2.0", "doctrine/migrations": "^2.2", - "php": "^7.1", + "php": "^7.1|^8.0", "symfony/framework-bundle": "~3.4|~4.0|~5.0" }, "require-dev": { - "doctrine/coding-standard": "^5.0", + "doctrine/coding-standard": "^8.0", "mikey179/vfsstream": "^1.6", - "phpstan/phpstan": "^0.9.2", - "phpstan/phpstan-strict-rules": "^0.9", - "phpunit/phpunit": "^6.4|^7.0" + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^7.0|^8.0|^9.0" }, "type": "symfony-bundle", "extra": { @@ -1014,7 +1055,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineMigrationsBundle/issues", - "source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/2.2.1" + "source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/2.2.2" }, "funding": [ { @@ -1030,7 +1071,7 @@ "type": "tidelift" } ], - "time": "2020-11-11T09:59:06+00:00" + "time": "2020-12-23T15:06:17+00:00" }, { "name": "doctrine/event-manager", @@ -1373,16 +1414,16 @@ }, { "name": "doctrine/migrations", - "version": "2.3.0", + "version": "2.3.1", "source": { "type": "git", "url": "https://github.com/doctrine/migrations.git", - "reference": "100e85a8509b521f010901890f042e9401a3043b" + "reference": "af915024d41669600354efe78664ee86dfca62e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/migrations/zipball/100e85a8509b521f010901890f042e9401a3043b", - "reference": "100e85a8509b521f010901890f042e9401a3043b", + "url": "https://api.github.com/repos/doctrine/migrations/zipball/af915024d41669600354efe78664ee86dfca62e1", + "reference": "af915024d41669600354efe78664ee86dfca62e1", "shasum": "" }, "require": { @@ -1390,7 +1431,7 @@ "doctrine/dbal": "^2.9", "ocramius/proxy-manager": "^2.0.2", "php": "^7.1", - "symfony/console": "^3.4||^4.0||^5.0", + "symfony/console": "^3.4||^4.4.16||^5.0", "symfony/stopwatch": "^3.4||^4.0||^5.0" }, "require-dev": { @@ -1403,7 +1444,7 @@ "phpstan/phpstan-deprecation-rules": "^0.10", "phpstan/phpstan-phpunit": "^0.10", "phpstan/phpstan-strict-rules": "^0.10", - "phpunit/phpunit": "^7.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.4", "symfony/process": "^3.4||^4.0||^5.0", "symfony/yaml": "^3.4||^4.0||^5.0" }, @@ -1453,7 +1494,7 @@ ], "support": { "issues": "https://github.com/doctrine/migrations/issues", - "source": "https://github.com/doctrine/migrations/tree/2.3.0" + "source": "https://github.com/doctrine/migrations/tree/2.3.1" }, "funding": [ { @@ -1469,25 +1510,25 @@ "type": "tidelift" } ], - "time": "2020-07-04T16:28:35+00:00" + "time": "2020-12-05T19:13:58+00:00" }, { "name": "doctrine/orm", - "version": "2.7.4", + "version": "2.7.5", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "7d84a4998091ece4d645253ac65de9f879eeed2f" + "reference": "01187c9260cd085529ddd1273665217cae659640" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/7d84a4998091ece4d645253ac65de9f879eeed2f", - "reference": "7d84a4998091ece4d645253ac65de9f879eeed2f", + "url": "https://api.github.com/repos/doctrine/orm/zipball/01187c9260cd085529ddd1273665217cae659640", + "reference": "01187c9260cd085529ddd1273665217cae659640", "shasum": "" }, "require": { "composer/package-versions-deprecated": "^1.8", - "doctrine/annotations": "^1.8", + "doctrine/annotations": "^1.11.1", "doctrine/cache": "^1.9.1", "doctrine/collections": "^1.5", "doctrine/common": "^2.11 || ^3.0", @@ -1502,9 +1543,9 @@ "symfony/console": "^3.0|^4.0|^5.0" }, "require-dev": { - "doctrine/coding-standard": "^5.0", + "doctrine/coding-standard": "^6.0", "phpstan/phpstan": "^0.12.18", - "phpunit/phpunit": "^7.5", + "phpunit/phpunit": "^8.0", "symfony/yaml": "^3.4|^4.0|^5.0", "vimeo/psalm": "^3.11" }, @@ -1559,9 +1600,9 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/2.7.4" + "source": "https://github.com/doctrine/orm/tree/2.7.5" }, - "time": "2020-10-10T17:11:26+00:00" + "time": "2020-12-03T08:52:14+00:00" }, { "name": "doctrine/persistence", @@ -1849,26 +1890,87 @@ "time": "2020-11-19T17:14:18+00:00" }, { - "name": "jms/metadata", - "version": "2.3.0", + "name": "jean85/pretty-package-versions", + "version": "2.0.3", "source": { "type": "git", - "url": "https://github.com/schmittjoh/metadata.git", - "reference": "6eb35fce7142234946d58d13e1aa829e9b78b095" + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "b2c4ec2033a0196317a467cb197c7c843b794ddf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/6eb35fce7142234946d58d13e1aa829e9b78b095", - "reference": "6eb35fce7142234946d58d13e1aa829e9b78b095", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/b2c4ec2033a0196317a467cb197c7c843b794ddf", + "reference": "b2c4ec2033a0196317a467cb197c7c843b794ddf", "shasum": "" }, "require": { - "php": "^7.2" + "composer-runtime-api": "^2.0.0", + "php": "^7.1|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.17", + "jean85/composer-provided-replaced-stub-package": "^1.0", + "phpstan/phpstan": "^0.12.66", + "phpunit/phpunit": "^7.5|^8.5|^9.4", + "vimeo/psalm": "^4.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A library to get pretty versions strings of installed dependencies", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "support": { + "issues": "https://github.com/Jean85/pretty-package-versions/issues", + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.3" + }, + "time": "2021-02-22T10:52:38+00:00" + }, + { + "name": "jms/metadata", + "version": "2.5.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/metadata.git", + "reference": "b5c52549807b2d855b3d7e36ec164c00eb547338" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/b5c52549807b2d855b3d7e36ec164c00eb547338", + "reference": "b5c52549807b2d855b3d7e36ec164c00eb547338", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" }, "require-dev": { "doctrine/cache": "^1.0", - "doctrine/coding-standard": "^4.0", - "phpunit/phpunit": "^7.0", + "doctrine/coding-standard": "^8.0", + "mikey179/vfsstream": "^1.6.7", + "phpunit/phpunit": "^8.5|^9.0", + "psr/container": "^1.0", "symfony/cache": "^3.1|^4.0|^5.0", "symfony/dependency-injection": "^3.1|^4.0|^5.0" }, @@ -1906,22 +2008,22 @@ ], "support": { "issues": "https://github.com/schmittjoh/metadata/issues", - "source": "https://github.com/schmittjoh/metadata/tree/master" + "source": "https://github.com/schmittjoh/metadata/tree/2.5.0" }, - "time": "2020-06-06T16:52:59+00:00" + "time": "2021-03-07T19:20:09+00:00" }, { "name": "jms/serializer", - "version": "3.10.0", + "version": "3.12.2", "source": { "type": "git", "url": "https://github.com/schmittjoh/serializer.git", - "reference": "0ed0b6aa79cc029772286f2dc262f6933674b0ec" + "reference": "ea54838a0acd960839b7401bfd83fcd6ebe34aed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/0ed0b6aa79cc029772286f2dc262f6933674b0ec", - "reference": "0ed0b6aa79cc029772286f2dc262f6933674b0ec", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/ea54838a0acd960839b7401bfd83fcd6ebe34aed", + "reference": "ea54838a0acd960839b7401bfd83fcd6ebe34aed", "shasum": "" }, "require": { @@ -1929,7 +2031,8 @@ "doctrine/instantiator": "^1.0.3", "doctrine/lexer": "^1.1", "jms/metadata": "^2.0", - "php": "^7.2" + "php": "^7.2||^8.0", + "phpstan/phpdoc-parser": "^0.4" }, "require-dev": { "doctrine/coding-standard": "^8.1", @@ -1939,6 +2042,7 @@ "ext-pdo_sqlite": "*", "jackalope/jackalope-doctrine-dbal": "^1.1.5", "ocramius/proxy-manager": "^1.0|^2.0", + "phpstan/phpstan": "^0.12.65", "phpunit/phpunit": "^8.0||^9.0", "psr/container": "^1.0", "symfony/dependency-injection": "^3.0|^4.0|^5.0", @@ -1958,7 +2062,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.10-dev" + "dev-master": "3.12-dev" } }, "autoload": { @@ -1991,7 +2095,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/serializer/issues", - "source": "https://github.com/schmittjoh/serializer/tree/3.10.0" + "source": "https://github.com/schmittjoh/serializer/tree/3.12.2" }, "funding": [ { @@ -1999,32 +2103,33 @@ "type": "github" } ], - "time": "2020-10-29T20:24:00+00:00" + "time": "2021-03-23T12:37:04+00:00" }, { "name": "jms/serializer-bundle", - "version": "3.7.0", + "version": "3.9.1", "source": { "type": "git", "url": "https://github.com/schmittjoh/JMSSerializerBundle.git", - "reference": "0ee8b75bfc484a342aa0471e3c6d9ad96fb430cf" + "reference": "2fbf2385668dd715d030567fd41e181bbf41fb42" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/JMSSerializerBundle/zipball/0ee8b75bfc484a342aa0471e3c6d9ad96fb430cf", - "reference": "0ee8b75bfc484a342aa0471e3c6d9ad96fb430cf", + "url": "https://api.github.com/repos/schmittjoh/JMSSerializerBundle/zipball/2fbf2385668dd715d030567fd41e181bbf41fb42", + "reference": "2fbf2385668dd715d030567fd41e181bbf41fb42", "shasum": "" }, "require": { - "jms/metadata": "^2.3", + "jms/metadata": "^2.5", "jms/serializer": "^3.0", - "php": "^7.2", + "php": "^7.2 || ^8.0", "symfony/dependency-injection": "^3.3 || ^4.0 || ^5.0", "symfony/framework-bundle": "^3.0 || ^4.0 || ^5.0" }, "require-dev": { + "doctrine/coding-standard": "^8.1", "doctrine/orm": "^2.4", - "phpunit/phpunit": "^6.0|^7.0", + "phpunit/phpunit": "^8.0 || ^9.0", "symfony/expression-language": "^3.0 || ^4.0 || ^5.0", "symfony/finder": "^3.0 || ^4.0 || ^5.0", "symfony/form": "^3.0 || ^4.0 || ^5.0", @@ -2035,12 +2140,13 @@ }, "suggest": { "jms/di-extra-bundle": "Required to get lazy loading (de)serialization visitors, ^1.3", + "symfony/expression-language": "Required for opcache preloading, ^3.0 || ^4.0 || ^5.0", "symfony/finder": "Required for cache warmup, supported versions ^3.0|^4.0" }, "type": "symfony-bundle", "extra": { "branch-alias": { - "dev-master": "3.7-dev" + "dev-master": "3.9-dev" } }, "autoload": { @@ -2075,7 +2181,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/JMSSerializerBundle/issues", - "source": "https://github.com/schmittjoh/JMSSerializerBundle/tree/master" + "source": "https://github.com/schmittjoh/JMSSerializerBundle/tree/3.9.1" }, "funding": [ { @@ -2083,7 +2189,7 @@ "type": "github" } ], - "time": "2020-06-28T11:26:21+00:00" + "time": "2021-03-23T12:21:23+00:00" }, { "name": "kadet/functional", @@ -2288,24 +2394,26 @@ }, { "name": "laminas/laminas-zendframework-bridge", - "version": "1.1.1", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-zendframework-bridge.git", - "reference": "6ede70583e101030bcace4dcddd648f760ddf642" + "reference": "6cccbddfcfc742eb02158d6137ca5687d92cee32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/6ede70583e101030bcace4dcddd648f760ddf642", - "reference": "6ede70583e101030bcace4dcddd648f760ddf642", + "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/6cccbddfcfc742eb02158d6137ca5687d92cee32", + "reference": "6cccbddfcfc742eb02158d6137ca5687d92cee32", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0 || ^8.0" + "php": "^7.3 || ^8.0" }, "require-dev": { "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3", - "squizlabs/php_codesniffer": "^3.5" + "psalm/plugin-phpunit": "^0.15.1", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.6" }, "type": "library", "extra": { @@ -2344,20 +2452,20 @@ "type": "community_bridge" } ], - "time": "2020-09-14T14:23:00+00:00" + "time": "2021-02-25T21:54:58+00:00" }, { "name": "monolog/monolog", - "version": "1.25.5", + "version": "1.26.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "1817faadd1846cd08be9a49e905dc68823bc38c0" + "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1817faadd1846cd08be9a49e905dc68823bc38c0", - "reference": "1817faadd1846cd08be9a49e905dc68823bc38c0", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/2209ddd84e7ef1256b7af205d0717fb62cfc9c33", + "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33", "shasum": "" }, "require": { @@ -2373,7 +2481,7 @@ "graylog2/gelf-php": "~1.0", "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", - "php-parallel-lint/php-parallel-lint": "^1.0", + "phpstan/phpstan": "^0.12.59", "phpunit/phpunit": "~4.5", "ruflin/elastica": ">=0.90 <3.0", "sentry/sentry": "^0.13", @@ -2393,11 +2501,6 @@ "sentry/sentry": "Allow sending log messages to a Sentry server" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, "autoload": { "psr-4": { "Monolog\\": "src/Monolog" @@ -2423,7 +2526,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/1.25.5" + "source": "https://github.com/Seldaek/monolog/tree/1.26.0" }, "funding": [ { @@ -2435,25 +2538,25 @@ "type": "tidelift" } ], - "time": "2020-07-23T08:35:51+00:00" + "time": "2020-12-14T12:56:38+00:00" }, { "name": "nelmio/api-doc-bundle", - "version": "v3.7.4", + "version": "v3.8.2", "source": { "type": "git", "url": "https://github.com/nelmio/NelmioApiDocBundle.git", - "reference": "290df23dc0060c4daaed95a7f37845f16a287ebd" + "reference": "e57ede23ed765c86a4440b4cd4fde46ff7d67483" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nelmio/NelmioApiDocBundle/zipball/290df23dc0060c4daaed95a7f37845f16a287ebd", - "reference": "290df23dc0060c4daaed95a7f37845f16a287ebd", + "url": "https://api.github.com/repos/nelmio/NelmioApiDocBundle/zipball/e57ede23ed765c86a4440b4cd4fde46ff7d67483", + "reference": "e57ede23ed765c86a4440b4cd4fde46ff7d67483", "shasum": "" }, "require": { "exsyst/swagger": "^0.4.1", - "php": "^7.1", + "php": ">=7.1.3", "phpdocumentor/reflection-docblock": "^3.1|^4.0|^5.0", "symfony/framework-bundle": "^3.4|^4.0|^5.0", "symfony/options-resolver": "^3.4.4|^4.0|^5.0", @@ -2467,7 +2570,7 @@ "api-platform/core": "^2.1.2", "doctrine/annotations": "^1.2", "doctrine/common": "^2.4", - "friendsofsymfony/rest-bundle": "^2.0|^3.0@beta", + "friendsofsymfony/rest-bundle": "^2.0|^3.0", "jms/serializer": "^1.14|^3.0", "jms/serializer-bundle": "^2.3|^3.0", "sensio/framework-extra-bundle": "^3.0.13|^4.0|^5.0", @@ -2477,6 +2580,7 @@ "symfony/config": "^3.4|^4.0|^5.0", "symfony/console": "^3.4|^4.0|^5.0", "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", "symfony/form": "^3.4|^4.0|^5.0", "symfony/phpunit-bridge": "^3.4.24|^4.0|^5.0", "symfony/property-access": "^3.4|^4.0|^5.0", @@ -2528,9 +2632,9 @@ ], "support": { "issues": "https://github.com/nelmio/NelmioApiDocBundle/issues", - "source": "https://github.com/nelmio/NelmioApiDocBundle/tree/v3.7.4" + "source": "https://github.com/nelmio/NelmioApiDocBundle/tree/v3.8.2" }, - "time": "2020-09-29T10:30:21+00:00" + "time": "2020-12-29T09:27:09+00:00" }, { "name": "nesbot/carbon", @@ -2898,6 +3002,56 @@ }, "time": "2020-09-17T18:55:26+00:00" }, + { + "name": "phpstan/phpdoc-parser", + "version": "0.4.14", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "cf4fc7d2aeca6910fba061901ffd7d107ccfdbcc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/cf4fc7d2aeca6910fba061901ffd7d107ccfdbcc", + "reference": "cf4fc7d2aeca6910fba061901ffd7d107ccfdbcc", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phing/phing": "^2.16.3", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12.60", + "phpstan/phpstan-strict-rules": "^0.12.5", + "phpunit/phpunit": "^7.5.20", + "symfony/process": "^5.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.4-dev" + } + }, + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/0.4.14" + }, + "time": "2021-03-19T10:54:14+00:00" + }, { "name": "psr/cache", "version": "1.0.1", @@ -2949,27 +3103,22 @@ }, { "name": "psr/container", - "version": "1.0.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=7.2.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, "autoload": { "psr-4": { "Psr\\Container\\": "src/" @@ -2982,7 +3131,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common Container Interface (PHP FIG PSR-11)", @@ -2996,9 +3145,9 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/master" + "source": "https://github.com/php-fig/container/tree/1.1.1" }, - "time": "2017-02-14T16:28:37+00:00" + "time": "2021-03-05T17:36:06+00:00" }, { "name": "psr/http-factory", @@ -3474,30 +3623,31 @@ }, { "name": "spiral/roadrunner", - "version": "v1.8.4", + "version": "v1.9.2", "source": { "type": "git", "url": "https://github.com/spiral/roadrunner.git", - "reference": "561003b0b66a4f767782552a9282d824b08831be" + "reference": "b934cc5e46e8b8ce92cacc4fe0094603992706f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spiral/roadrunner/zipball/561003b0b66a4f767782552a9282d824b08831be", - "reference": "561003b0b66a4f767782552a9282d824b08831be", + "url": "https://api.github.com/repos/spiral/roadrunner/zipball/b934cc5e46e8b8ce92cacc4fe0094603992706f2", + "reference": "b934cc5e46e8b8ce92cacc4fe0094603992706f2", "shasum": "" }, "require": { + "composer/package-versions-deprecated": "^1.8", "ext-curl": "*", "ext-json": "*", - "laminas/laminas-diactoros": "^1.3 || ^2.0", - "php": "^7.2", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.0", + "laminas/laminas-diactoros": "^1.3.6 || ^2.0", + "php": "^7.2 || ^8.0", + "psr/http-factory": "^1.0.1", + "psr/http-message": "^1.0.1", "spiral/goridge": "^2.4.2", "symfony/console": "^2.5.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" }, "require-dev": { - "phpstan/phpstan": "~0.12" + "phpstan/phpstan": "~0.12.34" }, "bin": [ "bin/rr" @@ -3525,22 +3675,22 @@ "description": "High-performance PHP application server, load-balancer and process manager written in Golang", "support": { "issues": "https://github.com/spiral/roadrunner/issues", - "source": "https://github.com/spiral/roadrunner/tree/v1.8.4" + "source": "https://github.com/spiral/roadrunner/tree/v1.9.2" }, - "time": "2020-10-21T11:03:49+00:00" + "time": "2021-01-14T16:04:43+00:00" }, { "name": "symfony/asset", - "version": "v4.4.17", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/asset.git", - "reference": "627761b47f94affdd8405e65245a8e1bbb810399" + "reference": "f2204a526c34945b1614cde033692983b6102eb8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset/zipball/627761b47f94affdd8405e65245a8e1bbb810399", - "reference": "627761b47f94affdd8405e65245a8e1bbb810399", + "url": "https://api.github.com/repos/symfony/asset/zipball/f2204a526c34945b1614cde033692983b6102eb8", + "reference": "f2204a526c34945b1614cde033692983b6102eb8", "shasum": "" }, "require": { @@ -3576,10 +3726,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Asset Component", + "description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/asset/tree/v4.4.17" + "source": "https://github.com/symfony/asset/tree/v4.4.20" }, "funding": [ { @@ -3595,51 +3745,51 @@ "type": "tidelift" } ], - "time": "2020-10-24T11:50:19+00:00" + "time": "2021-01-27T09:09:26+00:00" }, { "name": "symfony/cache", - "version": "v4.4.17", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "6d330ca81ce5c98f22224c980507a7f7a7df82e8" + "reference": "b7ff54be3f3eb1ce09643692f0c309b1b27bc992" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/6d330ca81ce5c98f22224c980507a7f7a7df82e8", - "reference": "6d330ca81ce5c98f22224c980507a7f7a7df82e8", + "url": "https://api.github.com/repos/symfony/cache/zipball/b7ff54be3f3eb1ce09643692f0c309b1b27bc992", + "reference": "b7ff54be3f3eb1ce09643692f0c309b1b27bc992", "shasum": "" }, "require": { "php": ">=7.1.3", - "psr/cache": "~1.0", + "psr/cache": "^1.0|^2.0", "psr/log": "~1.0", "symfony/cache-contracts": "^1.1.7|^2", "symfony/service-contracts": "^1.1|^2", "symfony/var-exporter": "^4.2|^5.0" }, "conflict": { - "doctrine/dbal": "<2.5", + "doctrine/dbal": "<2.6", "symfony/dependency-injection": "<3.4", - "symfony/http-kernel": "<4.4", + "symfony/http-kernel": "<4.4|>=5.0", "symfony/var-dumper": "<4.4" }, "provide": { - "psr/cache-implementation": "1.0", + "psr/cache-implementation": "1.0|2.0", "psr/simple-cache-implementation": "1.0", - "symfony/cache-implementation": "1.0" + "symfony/cache-implementation": "1.0|2.0" }, "require-dev": { "cache/integration-tests": "dev-master", "doctrine/cache": "^1.6", - "doctrine/dbal": "^2.5|^3.0", + "doctrine/dbal": "^2.6|^3.0", "predis/predis": "^1.1", "psr/simple-cache": "^1.0", "symfony/config": "^4.2|^5.0", "symfony/dependency-injection": "^3.4|^4.1|^5.0", "symfony/filesystem": "^4.4|^5.0", - "symfony/http-kernel": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", "symfony/var-dumper": "^4.4|^5.0" }, "type": "library", @@ -3665,14 +3815,14 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Cache component with PSR-6, PSR-16, and tags", + "description": "Provides an extended PSR-6, PSR-16 (and tags) implementation", "homepage": "https://symfony.com", "keywords": [ "caching", "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v4.4.17" + "source": "https://github.com/symfony/cache/tree/v4.4.21" }, "funding": [ { @@ -3688,7 +3838,7 @@ "type": "tidelift" } ], - "time": "2020-11-16T17:15:10+00:00" + "time": "2021-03-14T19:28:18+00:00" }, { "name": "symfony/cache-contracts", @@ -3771,16 +3921,16 @@ }, { "name": "symfony/config", - "version": "v4.4.17", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "4da4a6b07cc7d8d7d3e29842bc9c20401d555065" + "reference": "98606c6fa1a8f55ff964ccdd704275bf5b9f71b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/4da4a6b07cc7d8d7d3e29842bc9c20401d555065", - "reference": "4da4a6b07cc7d8d7d3e29842bc9c20401d555065", + "url": "https://api.github.com/repos/symfony/config/zipball/98606c6fa1a8f55ff964ccdd704275bf5b9f71b3", + "reference": "98606c6fa1a8f55ff964ccdd704275bf5b9f71b3", "shasum": "" }, "require": { @@ -3824,10 +3974,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Config Component", + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v4.4.17" + "source": "https://github.com/symfony/config/tree/v4.4.20" }, "funding": [ { @@ -3843,20 +3993,20 @@ "type": "tidelift" } ], - "time": "2020-11-16T11:15:53+00:00" + "time": "2021-02-22T15:36:50+00:00" }, { "name": "symfony/console", - "version": "v4.4.17", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c8e37f6928c19816437a4dd7bf16e3bd79941470" + "reference": "1ba4560dbbb9fcf5ae28b61f71f49c678086cf23" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c8e37f6928c19816437a4dd7bf16e3bd79941470", - "reference": "c8e37f6928c19816437a4dd7bf16e3bd79941470", + "url": "https://api.github.com/repos/symfony/console/zipball/1ba4560dbbb9fcf5ae28b61f71f49c678086cf23", + "reference": "1ba4560dbbb9fcf5ae28b61f71f49c678086cf23", "shasum": "" }, "require": { @@ -3913,10 +4063,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Console Component", + "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/console/tree/v4.4.17" + "source": "https://github.com/symfony/console/tree/v4.4.21" }, "funding": [ { @@ -3932,20 +4082,20 @@ "type": "tidelift" } ], - "time": "2020-11-28T10:15:42+00:00" + "time": "2021-03-26T09:23:24+00:00" }, { "name": "symfony/debug", - "version": "v4.4.17", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "65fe7b49868378319b82da3035fb30801b931c47" + "reference": "157bbec4fd773bae53c5483c50951a5530a2cc16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/65fe7b49868378319b82da3035fb30801b931c47", - "reference": "65fe7b49868378319b82da3035fb30801b931c47", + "url": "https://api.github.com/repos/symfony/debug/zipball/157bbec4fd773bae53c5483c50951a5530a2cc16", + "reference": "157bbec4fd773bae53c5483c50951a5530a2cc16", "shasum": "" }, "require": { @@ -3982,10 +4132,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Debug Component", + "description": "Provides tools to ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/debug/tree/v4.4.17" + "source": "https://github.com/symfony/debug/tree/v4.4.20" }, "funding": [ { @@ -4001,20 +4151,20 @@ "type": "tidelift" } ], - "time": "2020-10-28T20:42:29+00:00" + "time": "2021-01-28T16:54:48+00:00" }, { "name": "symfony/dependency-injection", - "version": "v4.4.17", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "7126a3a25466a29b844c21394aabf6e7cf717b24" + "reference": "b5f97557faa48ead4671bc311cfca423d476e93e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/7126a3a25466a29b844c21394aabf6e7cf717b24", - "reference": "7126a3a25466a29b844c21394aabf6e7cf717b24", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/b5f97557faa48ead4671bc311cfca423d476e93e", + "reference": "b5f97557faa48ead4671bc311cfca423d476e93e", "shasum": "" }, "require": { @@ -4030,7 +4180,7 @@ }, "provide": { "psr/container-implementation": "1.0", - "symfony/service-implementation": "1.0" + "symfony/service-implementation": "1.0|2.0" }, "require-dev": { "symfony/config": "^4.3", @@ -4067,10 +4217,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony DependencyInjection Component", + "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v4.4.17" + "source": "https://github.com/symfony/dependency-injection/tree/v4.4.21" }, "funding": [ { @@ -4086,20 +4236,20 @@ "type": "tidelift" } ], - "time": "2020-11-27T15:54:06+00:00" + "time": "2021-03-05T18:16:26+00:00" }, { "name": "symfony/doctrine-bridge", - "version": "v4.4.17", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "cc9cc380f51c3ab7ad396fad8b30fc184894e6c1" + "reference": "e643bddb38277b4a1c2973d1489768c6e6c0db80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/cc9cc380f51c3ab7ad396fad8b30fc184894e6c1", - "reference": "cc9cc380f51c3ab7ad396fad8b30fc184894e6c1", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/e643bddb38277b4a1c2973d1489768c6e6c0db80", + "reference": "e643bddb38277b4a1c2973d1489768c6e6c0db80", "shasum": "" }, "require": { @@ -4121,11 +4271,11 @@ }, "require-dev": { "composer/package-versions-deprecated": "^1.8", - "doctrine/annotations": "~1.7", + "doctrine/annotations": "^1.10.4", "doctrine/cache": "~1.6", "doctrine/collections": "~1.0", "doctrine/data-fixtures": "^1.1", - "doctrine/dbal": "~2.4|^3.0", + "doctrine/dbal": "^2.6|^3.0", "doctrine/orm": "^2.6.3", "symfony/config": "^4.2|^5.0", "symfony/dependency-injection": "^3.4|^4.0|^5.0", @@ -4173,10 +4323,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Doctrine Bridge", + "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v4.4.17" + "source": "https://github.com/symfony/doctrine-bridge/tree/v4.4.21" }, "funding": [ { @@ -4192,20 +4342,20 @@ "type": "tidelift" } ], - "time": "2020-11-09T19:21:10+00:00" + "time": "2021-03-09T16:20:30+00:00" }, { "name": "symfony/dotenv", - "version": "v4.4.17", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "6dd958a0c30bdf816ddef5052655a06d87fa343c" + "reference": "4952e5ce9e6df3d737b9e9c337bddf781180a213" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/6dd958a0c30bdf816ddef5052655a06d87fa343c", - "reference": "6dd958a0c30bdf816ddef5052655a06d87fa343c", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/4952e5ce9e6df3d737b9e9c337bddf781180a213", + "reference": "4952e5ce9e6df3d737b9e9c337bddf781180a213", "shasum": "" }, "require": { @@ -4245,7 +4395,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v4.4.17" + "source": "https://github.com/symfony/dotenv/tree/v4.4.20" }, "funding": [ { @@ -4261,20 +4411,20 @@ "type": "tidelift" } ], - "time": "2020-11-14T17:10:20+00:00" + "time": "2021-01-27T09:09:26+00:00" }, { "name": "symfony/error-handler", - "version": "v4.4.17", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "b0887cf8fc692eef2a4cf11cee3c5f5eb93fcfdf" + "reference": "48e81a375525872e788c2418430f54150d935810" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/b0887cf8fc692eef2a4cf11cee3c5f5eb93fcfdf", - "reference": "b0887cf8fc692eef2a4cf11cee3c5f5eb93fcfdf", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/48e81a375525872e788c2418430f54150d935810", + "reference": "48e81a375525872e788c2418430f54150d935810", "shasum": "" }, "require": { @@ -4311,10 +4461,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony ErrorHandler Component", + "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v4.4.17" + "source": "https://github.com/symfony/error-handler/tree/v4.4.21" }, "funding": [ { @@ -4330,20 +4480,20 @@ "type": "tidelift" } ], - "time": "2020-10-28T20:42:29+00:00" + "time": "2021-03-08T10:28:40+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.4.17", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "f029d6f21eac61ab23198e7aca40e7638e8c8924" + "reference": "c352647244bd376bf7d31efbd5401f13f50dad0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/f029d6f21eac61ab23198e7aca40e7638e8c8924", - "reference": "f029d6f21eac61ab23198e7aca40e7638e8c8924", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/c352647244bd376bf7d31efbd5401f13f50dad0c", + "reference": "c352647244bd376bf7d31efbd5401f13f50dad0c", "shasum": "" }, "require": { @@ -4394,10 +4544,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony EventDispatcher Component", + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.17" + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.20" }, "funding": [ { @@ -4413,7 +4563,7 @@ "type": "tidelift" } ], - "time": "2020-10-31T22:44:29+00:00" + "time": "2021-01-27T09:09:26+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -4496,16 +4646,16 @@ }, { "name": "symfony/filesystem", - "version": "v4.4.17", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "17b83e36a911aefa2cfe04bbf6328ec4c040c1b2" + "reference": "940826c465be2690c9fae91b2793481e5cbd6834" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/17b83e36a911aefa2cfe04bbf6328ec4c040c1b2", - "reference": "17b83e36a911aefa2cfe04bbf6328ec4c040c1b2", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/940826c465be2690c9fae91b2793481e5cbd6834", + "reference": "940826c465be2690c9fae91b2793481e5cbd6834", "shasum": "" }, "require": { @@ -4535,10 +4685,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Filesystem Component", + "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v4.4.17" + "source": "https://github.com/symfony/filesystem/tree/v4.4.21" }, "funding": [ { @@ -4554,20 +4704,20 @@ "type": "tidelift" } ], - "time": "2020-11-11T22:20:15+00:00" + "time": "2021-03-28T09:59:32+00:00" }, { "name": "symfony/finder", - "version": "v4.4.17", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "9f1d1d883b79a91ef320c0c6e803494e042ef36e" + "reference": "2543795ab1570df588b9bbd31e1a2bd7037b94f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/9f1d1d883b79a91ef320c0c6e803494e042ef36e", - "reference": "9f1d1d883b79a91ef320c0c6e803494e042ef36e", + "url": "https://api.github.com/repos/symfony/finder/zipball/2543795ab1570df588b9bbd31e1a2bd7037b94f6", + "reference": "2543795ab1570df588b9bbd31e1a2bd7037b94f6", "shasum": "" }, "require": { @@ -4596,10 +4746,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Finder Component", + "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v4.4.17" + "source": "https://github.com/symfony/finder/tree/v4.4.20" }, "funding": [ { @@ -4615,20 +4765,20 @@ "type": "tidelift" } ], - "time": "2020-11-17T19:45:34+00:00" + "time": "2021-02-12T10:48:09+00:00" }, { "name": "symfony/flex", - "version": "v1.10.0", + "version": "v1.12.2", "source": { "type": "git", "url": "https://github.com/symfony/flex.git", - "reference": "e38520236bdc911c2f219634b485bc328746e980" + "reference": "e472606b4b3173564f0edbca8f5d32b52fc4f2c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/flex/zipball/e38520236bdc911c2f219634b485bc328746e980", - "reference": "e38520236bdc911c2f219634b485bc328746e980", + "url": "https://api.github.com/repos/symfony/flex/zipball/e472606b4b3173564f0edbca8f5d32b52fc4f2c9", + "reference": "e472606b4b3173564f0edbca8f5d32b52fc4f2c9", "shasum": "" }, "require": { @@ -4638,13 +4788,14 @@ "require-dev": { "composer/composer": "^1.0.2|^2.0", "symfony/dotenv": "^4.4|^5.0", + "symfony/filesystem": "^4.4|^5.0", "symfony/phpunit-bridge": "^4.4|^5.0", "symfony/process": "^3.4|^4.4|^5.0" }, "type": "composer-plugin", "extra": { "branch-alias": { - "dev-main": "1.9-dev" + "dev-main": "1.12-dev" }, "class": "Symfony\\Flex\\Flex" }, @@ -4666,7 +4817,7 @@ "description": "Composer plugin for Symfony", "support": { "issues": "https://github.com/symfony/flex/issues", - "source": "https://github.com/symfony/flex/tree/v1.10.0" + "source": "https://github.com/symfony/flex/tree/v1.12.2" }, "funding": [ { @@ -4682,20 +4833,20 @@ "type": "tidelift" } ], - "time": "2020-11-05T10:56:45+00:00" + "time": "2021-02-16T14:05:05+00:00" }, { "name": "symfony/framework-bundle", - "version": "v4.4.17", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "3aea107a3cf50c351a492ab855caa6b2fd0f66a2" + "reference": "fc72fbb0f9a69d2eb5d94cc8c231176265db680a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/3aea107a3cf50c351a492ab855caa6b2fd0f66a2", - "reference": "3aea107a3cf50c351a492ab855caa6b2fd0f66a2", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/fc72fbb0f9a69d2eb5d94cc8c231176265db680a", + "reference": "fc72fbb0f9a69d2eb5d94cc8c231176265db680a", "shasum": "" }, "require": { @@ -4710,16 +4861,16 @@ "symfony/http-foundation": "^4.4|^5.0", "symfony/http-kernel": "^4.4", "symfony/polyfill-mbstring": "~1.0", - "symfony/routing": "^4.4|^5.0" + "symfony/routing": "^4.4.12|^5.1.4" }, "conflict": { "doctrine/persistence": "<1.3", - "phpdocumentor/reflection-docblock": "<3.0", - "phpdocumentor/type-resolver": "<0.2.1", + "phpdocumentor/reflection-docblock": "<3.0|>=3.2.0,<3.2.2", + "phpdocumentor/type-resolver": "<0.3.0|1.3.*", "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", "symfony/asset": "<3.4", "symfony/browser-kit": "<4.3", - "symfony/console": "<4.3", + "symfony/console": "<4.4.21", "symfony/dom-crawler": "<4.3", "symfony/dotenv": "<4.3.6", "symfony/form": "<4.3.5", @@ -4740,13 +4891,14 @@ "symfony/workflow": "<4.3.6" }, "require-dev": { - "doctrine/annotations": "~1.7", + "doctrine/annotations": "^1.10.4", "doctrine/cache": "~1.0", + "doctrine/persistence": "^1.3|^2.0", "paragonie/sodium_compat": "^1.8", - "phpdocumentor/reflection-docblock": "^3.0|^4.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "symfony/asset": "^3.4|^4.0|^5.0", "symfony/browser-kit": "^4.3|^5.0", - "symfony/console": "^4.3.4|^5.0", + "symfony/console": "^4.4.21|^5.0", "symfony/css-selector": "^3.4|^4.0|^5.0", "symfony/dom-crawler": "^4.3|^5.0", "symfony/dotenv": "^4.3.6|^5.0", @@ -4760,6 +4912,7 @@ "symfony/polyfill-intl-icu": "~1.0", "symfony/process": "^3.4|^4.0|^5.0", "symfony/property-info": "^3.4|^4.0|^5.0", + "symfony/security-core": "^3.4|^4.4|^5.2", "symfony/security-csrf": "^3.4|^4.0|^5.0", "symfony/security-http": "^3.4|^4.0|^5.0", "symfony/serializer": "^4.4|^5.0", @@ -4771,7 +4924,7 @@ "symfony/web-link": "^4.4|^5.0", "symfony/workflow": "^4.3.6|^5.0", "symfony/yaml": "^3.4|^4.0|^5.0", - "twig/twig": "^1.41|^2.10|^3.0" + "twig/twig": "^1.43|^2.13|^3.0.4" }, "suggest": { "ext-apcu": "For best performance of the system caches", @@ -4806,10 +4959,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony FrameworkBundle", + "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v4.4.17" + "source": "https://github.com/symfony/framework-bundle/tree/v4.4.21" }, "funding": [ { @@ -4825,7 +4978,7 @@ "type": "tidelift" } ], - "time": "2020-11-27T14:11:20+00:00" + "time": "2021-03-18T09:22:03+00:00" }, { "name": "symfony/http-client-contracts", @@ -4908,22 +5061,23 @@ }, { "name": "symfony/http-foundation", - "version": "v4.4.17", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "9eeb37ec0ff3049c782ca67041648e28ddd75a94" + "reference": "02d968647fe61b2f419a8dc70c468a9d30a48d3a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9eeb37ec0ff3049c782ca67041648e28ddd75a94", - "reference": "9eeb37ec0ff3049c782ca67041648e28ddd75a94", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/02d968647fe61b2f419a8dc70c468a9d30a48d3a", + "reference": "02d968647fe61b2f419a8dc70c468a9d30a48d3a", "shasum": "" }, "require": { "php": ">=7.1.3", "symfony/mime": "^4.3|^5.0", - "symfony/polyfill-mbstring": "~1.1" + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php80": "^1.15" }, "require-dev": { "predis/predis": "~1.0", @@ -4952,10 +5106,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony HttpFoundation Component", + "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v4.4.17" + "source": "https://github.com/symfony/http-foundation/tree/v4.4.20" }, "funding": [ { @@ -4971,20 +5125,20 @@ "type": "tidelift" } ], - "time": "2020-11-03T11:58:18+00:00" + "time": "2021-02-25T17:11:33+00:00" }, { "name": "symfony/http-kernel", - "version": "v4.4.17", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "9f5605ee05406d8afa40dc4f2954c6a61de3a984" + "reference": "0248214120d00c5f44f1cd5d9ad65f0b38459333" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/9f5605ee05406d8afa40dc4f2954c6a61de3a984", - "reference": "9f5605ee05406d8afa40dc4f2954c6a61de3a984", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/0248214120d00c5f44f1cd5d9ad65f0b38459333", + "reference": "0248214120d00c5f44f1cd5d9ad65f0b38459333", "shasum": "" }, "require": { @@ -5004,13 +5158,13 @@ "symfony/console": ">=5", "symfony/dependency-injection": "<4.3", "symfony/translation": "<4.2", - "twig/twig": "<1.34|<2.4,>=2" + "twig/twig": "<1.43|<2.13,>=2" }, "provide": { "psr/log-implementation": "1.0" }, "require-dev": { - "psr/cache": "~1.0", + "psr/cache": "^1.0|^2.0|^3.0", "symfony/browser-kit": "^4.3|^5.0", "symfony/config": "^3.4|^4.0|^5.0", "symfony/console": "^3.4|^4.0", @@ -5025,7 +5179,7 @@ "symfony/templating": "^3.4|^4.0|^5.0", "symfony/translation": "^4.2|^5.0", "symfony/translation-contracts": "^1.1|^2", - "twig/twig": "^1.34|^2.4|^3.0" + "twig/twig": "^1.43|^2.13|^3.0.4" }, "suggest": { "symfony/browser-kit": "", @@ -5056,10 +5210,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony HttpKernel Component", + "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v4.4.17" + "source": "https://github.com/symfony/http-kernel/tree/v4.4.21" }, "funding": [ { @@ -5075,20 +5229,20 @@ "type": "tidelift" } ], - "time": "2020-11-29T09:23:08+00:00" + "time": "2021-03-29T05:11:04+00:00" }, { "name": "symfony/inflector", - "version": "v4.4.17", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/inflector.git", - "reference": "a2ca868d7fc02800db67d1e1b6e5c83882d2aaa6" + "reference": "9455097d23776a4a10c817d903271bc1ce7596ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/inflector/zipball/a2ca868d7fc02800db67d1e1b6e5c83882d2aaa6", - "reference": "a2ca868d7fc02800db67d1e1b6e5c83882d2aaa6", + "url": "https://api.github.com/repos/symfony/inflector/zipball/9455097d23776a4a10c817d903271bc1ce7596ff", + "reference": "9455097d23776a4a10c817d903271bc1ce7596ff", "shasum": "" }, "require": { @@ -5118,7 +5272,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Inflector Component", + "description": "Converts words between their singular and plural forms (English only)", "homepage": "https://symfony.com", "keywords": [ "inflection", @@ -5129,7 +5283,7 @@ "words" ], "support": { - "source": "https://github.com/symfony/inflector/tree/v4.4.17" + "source": "https://github.com/symfony/inflector/tree/v4.4.21" }, "funding": [ { @@ -5145,20 +5299,20 @@ "type": "tidelift" } ], - "time": "2020-10-24T11:50:19+00:00" + "time": "2021-03-17T16:19:54+00:00" }, { "name": "symfony/mime", - "version": "v4.4.17", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "4148b752f7e961931887410513ce3d9e267d25f2" + "reference": "50d7a1d569edad1f1321c59123c4c322c8daff7c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/4148b752f7e961931887410513ce3d9e267d25f2", - "reference": "4148b752f7e961931887410513ce3d9e267d25f2", + "url": "https://api.github.com/repos/symfony/mime/zipball/50d7a1d569edad1f1321c59123c4c322c8daff7c", + "reference": "50d7a1d569edad1f1321c59123c4c322c8daff7c", "shasum": "" }, "require": { @@ -5167,10 +5321,11 @@ "symfony/polyfill-mbstring": "^1.0" }, "conflict": { + "egulias/email-validator": "~3.0.0", "symfony/mailer": "<4.4" }, "require-dev": { - "egulias/email-validator": "^2.1.10", + "egulias/email-validator": "^2.1.10|^3.1", "symfony/dependency-injection": "^3.4|^4.1|^5.0" }, "type": "library", @@ -5196,14 +5351,14 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "A library to manipulate MIME messages", + "description": "Allows manipulating MIME messages", "homepage": "https://symfony.com", "keywords": [ "mime", "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v4.4.17" + "source": "https://github.com/symfony/mime/tree/v4.4.21" }, "funding": [ { @@ -5219,20 +5374,20 @@ "type": "tidelift" } ], - "time": "2020-10-28T20:42:29+00:00" + "time": "2021-03-12T08:47:38+00:00" }, { "name": "symfony/monolog-bridge", - "version": "v4.4.17", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "0ac6b8e8c742ae75e8840feb1852fdf01d02d3ed" + "reference": "3741314b95e8d0c11a485dce562898f5f67f455c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/0ac6b8e8c742ae75e8840feb1852fdf01d02d3ed", - "reference": "0ac6b8e8c742ae75e8840feb1852fdf01d02d3ed", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/3741314b95e8d0c11a485dce562898f5f67f455c", + "reference": "3741314b95e8d0c11a485dce562898f5f67f455c", "shasum": "" }, "require": { @@ -5279,10 +5434,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Monolog Bridge", + "description": "Provides integration for Monolog with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/monolog-bridge/tree/v4.4.17" + "source": "https://github.com/symfony/monolog-bridge/tree/v4.4.21" }, "funding": [ { @@ -5298,34 +5453,34 @@ "type": "tidelift" } ], - "time": "2020-10-28T20:42:29+00:00" + "time": "2021-03-05T17:58:50+00:00" }, { "name": "symfony/monolog-bundle", - "version": "v3.6.0", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bundle.git", - "reference": "e495f5c7e4e672ffef4357d4a4d85f010802f940" + "reference": "4054b2e940a25195ae15f0a49ab0c51718922eb4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/e495f5c7e4e672ffef4357d4a4d85f010802f940", - "reference": "e495f5c7e4e672ffef4357d4a4d85f010802f940", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/4054b2e940a25195ae15f0a49ab0c51718922eb4", + "reference": "4054b2e940a25195ae15f0a49ab0c51718922eb4", "shasum": "" }, "require": { "monolog/monolog": "~1.22 || ~2.0", - "php": ">=5.6", - "symfony/config": "~3.4 || ~4.0 || ^5.0", - "symfony/dependency-injection": "~3.4.10 || ^4.0.10 || ^5.0", - "symfony/http-kernel": "~3.4 || ~4.0 || ^5.0", - "symfony/monolog-bridge": "~3.4 || ~4.0 || ^5.0" + "php": ">=7.1.3", + "symfony/config": "~4.4 || ^5.0", + "symfony/dependency-injection": "^4.4 || ^5.0", + "symfony/http-kernel": "~4.4 || ^5.0", + "symfony/monolog-bridge": "~4.4 || ^5.0" }, "require-dev": { - "symfony/console": "~3.4 || ~4.0 || ^5.0", - "symfony/phpunit-bridge": "^4.4 || ^5.0", - "symfony/yaml": "~3.4 || ~4.0 || ^5.0" + "symfony/console": "~4.4 || ^5.0", + "symfony/phpunit-bridge": "^5.1", + "symfony/yaml": "~4.4 || ^5.0" }, "type": "symfony-bundle", "extra": { @@ -5352,18 +5507,18 @@ }, { "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony MonologBundle", - "homepage": "http://symfony.com", + "homepage": "https://symfony.com", "keywords": [ "log", "logging" ], "support": { "issues": "https://github.com/symfony/monolog-bundle/issues", - "source": "https://github.com/symfony/monolog-bundle/tree/v3.6.0" + "source": "https://github.com/symfony/monolog-bundle/tree/v3.7.0" }, "funding": [ { @@ -5379,20 +5534,20 @@ "type": "tidelift" } ], - "time": "2020-10-06T15:12:11+00:00" + "time": "2021-03-31T07:20:47+00:00" }, { "name": "symfony/options-resolver", - "version": "v4.4.17", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "157a252222251310fe50c71012b4e72f01325850" + "reference": "cd8c6a2778d5f8b5e8fc4b7abdf126790b5d5095" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/157a252222251310fe50c71012b4e72f01325850", - "reference": "157a252222251310fe50c71012b4e72f01325850", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/cd8c6a2778d5f8b5e8fc4b7abdf126790b5d5095", + "reference": "cd8c6a2778d5f8b5e8fc4b7abdf126790b5d5095", "shasum": "" }, "require": { @@ -5421,7 +5576,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony OptionsResolver Component", + "description": "Provides an improved replacement for the array_replace PHP function", "homepage": "https://symfony.com", "keywords": [ "config", @@ -5429,7 +5584,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v4.4.17" + "source": "https://github.com/symfony/options-resolver/tree/v4.4.20" }, "funding": [ { @@ -5445,7 +5600,7 @@ "type": "tidelift" } ], - "time": "2020-10-24T11:50:19+00:00" + "time": "2021-01-27T09:09:26+00:00" }, { "name": "symfony/orm-pack", @@ -5496,16 +5651,16 @@ }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.20.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "3b75acd829741c768bc8b1f84eb33265e7cc5117" + "reference": "2d63434d922daf7da8dd863e7907e67ee3031483" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/3b75acd829741c768bc8b1f84eb33265e7cc5117", - "reference": "3b75acd829741c768bc8b1f84eb33265e7cc5117", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/2d63434d922daf7da8dd863e7907e67ee3031483", + "reference": "2d63434d922daf7da8dd863e7907e67ee3031483", "shasum": "" }, "require": { @@ -5519,7 +5674,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5563,7 +5718,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.22.1" }, "funding": [ { @@ -5579,20 +5734,20 @@ "type": "tidelift" } ], - "time": "2020-10-23T14:02:19+00:00" + "time": "2021-01-22T09:19:47+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.20.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "727d1096295d807c309fb01a851577302394c897" + "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/727d1096295d807c309fb01a851577302394c897", - "reference": "727d1096295d807c309fb01a851577302394c897", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/43a0283138253ed1d48d352ab6d0bdb3f809f248", + "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248", "shasum": "" }, "require": { @@ -5604,7 +5759,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5647,7 +5802,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.1" }, "funding": [ { @@ -5663,20 +5818,20 @@ "type": "tidelift" } ], - "time": "2020-10-23T14:02:19+00:00" + "time": "2021-01-22T09:19:47+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.20.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "39d483bdf39be819deabf04ec872eb0b2410b531" + "reference": "5232de97ee3b75b0360528dae24e73db49566ab1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/39d483bdf39be819deabf04ec872eb0b2410b531", - "reference": "39d483bdf39be819deabf04ec872eb0b2410b531", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/5232de97ee3b75b0360528dae24e73db49566ab1", + "reference": "5232de97ee3b75b0360528dae24e73db49566ab1", "shasum": "" }, "require": { @@ -5688,7 +5843,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5727,7 +5882,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.1" }, "funding": [ { @@ -5743,20 +5898,20 @@ "type": "tidelift" } ], - "time": "2020-10-23T14:02:19+00:00" + "time": "2021-01-22T09:19:47+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.20.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930" + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cede45fcdfabdd6043b3592e83678e42ec69e930", - "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", "shasum": "" }, "require": { @@ -5765,7 +5920,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5803,7 +5958,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.1" }, "funding": [ { @@ -5819,20 +5974,20 @@ "type": "tidelift" } ], - "time": "2020-10-23T14:02:19+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.20.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "8ff431c517be11c78c48a39a66d37431e26a6bed" + "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/8ff431c517be11c78c48a39a66d37431e26a6bed", - "reference": "8ff431c517be11c78c48a39a66d37431e26a6bed", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", + "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", "shasum": "" }, "require": { @@ -5841,7 +5996,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5882,7 +6037,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.1" }, "funding": [ { @@ -5898,20 +6053,20 @@ "type": "tidelift" } ], - "time": "2020-10-23T14:02:19+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.20.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de" + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/e70aa8b064c5b72d3df2abd5ab1e90464ad009de", - "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91", + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91", "shasum": "" }, "require": { @@ -5920,7 +6075,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5965,7 +6120,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1" }, "funding": [ { @@ -5981,7 +6136,7 @@ "type": "tidelift" } ], - "time": "2020-10-23T14:02:19+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/profiler-pack", @@ -6030,16 +6185,16 @@ }, { "name": "symfony/property-info", - "version": "v4.4.17", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "b355ee4a241094f72b8f96709a83619b8be064b2" + "reference": "67845c335482cea0dd52497ae1314ce7a4978c74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/b355ee4a241094f72b8f96709a83619b8be064b2", - "reference": "b355ee4a241094f72b8f96709a83619b8be064b2", + "url": "https://api.github.com/repos/symfony/property-info/zipball/67845c335482cea0dd52497ae1314ce7a4978c74", + "reference": "67845c335482cea0dd52497ae1314ce7a4978c74", "shasum": "" }, "require": { @@ -6047,12 +6202,12 @@ "symfony/inflector": "^3.4|^4.0|^5.0" }, "conflict": { - "phpdocumentor/reflection-docblock": "<3.0||>=3.2.0,<3.2.2", - "phpdocumentor/type-resolver": "<0.3.0", + "phpdocumentor/reflection-docblock": "<3.0|>=3.2.0,<3.2.2", + "phpdocumentor/type-resolver": "<0.3.0|1.3.*", "symfony/dependency-injection": "<3.4" }, "require-dev": { - "doctrine/annotations": "~1.7", + "doctrine/annotations": "^1.10.4", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "symfony/cache": "^3.4|^4.0|^5.0", "symfony/dependency-injection": "^3.4|^4.0|^5.0", @@ -6087,7 +6242,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Property Info Component", + "description": "Extracts information about PHP class' properties using metadata of popular sources", "homepage": "https://symfony.com", "keywords": [ "doctrine", @@ -6098,7 +6253,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v4.4.17" + "source": "https://github.com/symfony/property-info/tree/v4.4.20" }, "funding": [ { @@ -6114,20 +6269,20 @@ "type": "tidelift" } ], - "time": "2020-10-28T20:42:29+00:00" + "time": "2021-02-16T12:45:26+00:00" }, { "name": "symfony/psr-http-message-bridge", - "version": "v2.0.2", + "version": "v2.1.0", "source": { "type": "git", "url": "https://github.com/symfony/psr-http-message-bridge.git", - "reference": "51a21cb3ba3927d4b4bf8f25cc55763351af5f2e" + "reference": "81db2d4ae86e9f0049828d9343a72b9523884e5d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/51a21cb3ba3927d4b4bf8f25cc55763351af5f2e", - "reference": "51a21cb3ba3927d4b4bf8f25cc55763351af5f2e", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/81db2d4ae86e9f0049828d9343a72b9523884e5d", + "reference": "81db2d4ae86e9f0049828d9343a72b9523884e5d", "shasum": "" }, "require": { @@ -6137,7 +6292,13 @@ }, "require-dev": { "nyholm/psr7": "^1.1", - "symfony/phpunit-bridge": "^4.4 || ^5.0" + "psr/log": "^1.1", + "symfony/browser-kit": "^4.4 || ^5.0", + "symfony/config": "^4.4 || ^5.0", + "symfony/event-dispatcher": "^4.4 || ^5.0", + "symfony/framework-bundle": "^4.4 || ^5.0", + "symfony/http-kernel": "^4.4 || ^5.0", + "symfony/phpunit-bridge": "^4.4.19 || ^5.2" }, "suggest": { "nyholm/psr7": "For a super lightweight PSR-7/17 implementation" @@ -6145,7 +6306,7 @@ "type": "symfony-bridge", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "2.1-dev" } }, "autoload": { @@ -6180,7 +6341,7 @@ ], "support": { "issues": "https://github.com/symfony/psr-http-message-bridge/issues", - "source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.0.2" + "source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.1.0" }, "funding": [ { @@ -6196,20 +6357,20 @@ "type": "tidelift" } ], - "time": "2020-09-29T08:17:46+00:00" + "time": "2021-02-17T10:35:25+00:00" }, { "name": "symfony/routing", - "version": "v4.4.17", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "08712c5dd5041c03e997e13892f45884faccd868" + "reference": "69919991c845b34626664ddc9b3aef9d09d2a5df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/08712c5dd5041c03e997e13892f45884faccd868", - "reference": "08712c5dd5041c03e997e13892f45884faccd868", + "url": "https://api.github.com/repos/symfony/routing/zipball/69919991c845b34626664ddc9b3aef9d09d2a5df", + "reference": "69919991c845b34626664ddc9b3aef9d09d2a5df", "shasum": "" }, "require": { @@ -6221,7 +6382,7 @@ "symfony/yaml": "<3.4" }, "require-dev": { - "doctrine/annotations": "~1.2", + "doctrine/annotations": "^1.10.4", "psr/log": "~1.0", "symfony/config": "^4.2|^5.0", "symfony/dependency-injection": "^3.4|^4.0|^5.0", @@ -6259,7 +6420,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Routing Component", + "description": "Maps an HTTP request to a set of configuration variables", "homepage": "https://symfony.com", "keywords": [ "router", @@ -6268,7 +6429,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v4.4.17" + "source": "https://github.com/symfony/routing/tree/v4.4.20" }, "funding": [ { @@ -6284,7 +6445,7 @@ "type": "tidelift" } ], - "time": "2020-11-24T13:31:32+00:00" + "time": "2021-02-22T15:37:04+00:00" }, { "name": "symfony/service-contracts", @@ -6367,16 +6528,16 @@ }, { "name": "symfony/stopwatch", - "version": "v4.4.17", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "c7a594108ed01c89555c4e1bb123b4a54aee2595" + "reference": "c5572f6494fc20668a73b77684d8dc77e534d8cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/c7a594108ed01c89555c4e1bb123b4a54aee2595", - "reference": "c7a594108ed01c89555c4e1bb123b4a54aee2595", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/c5572f6494fc20668a73b77684d8dc77e534d8cf", + "reference": "c5572f6494fc20668a73b77684d8dc77e534d8cf", "shasum": "" }, "require": { @@ -6406,10 +6567,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Stopwatch Component", + "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v4.4.17" + "source": "https://github.com/symfony/stopwatch/tree/v4.4.20" }, "funding": [ { @@ -6425,20 +6586,20 @@ "type": "tidelift" } ], - "time": "2020-10-31T22:44:29+00:00" + "time": "2021-01-27T09:09:26+00:00" }, { "name": "symfony/translation", - "version": "v4.4.17", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "84821e6a14a637e817f25d11147388695b6f790a" + "reference": "eb8f5428cc3b40d6dffe303b195b084f1c5fbd14" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/84821e6a14a637e817f25d11147388695b6f790a", - "reference": "84821e6a14a637e817f25d11147388695b6f790a", + "url": "https://api.github.com/repos/symfony/translation/zipball/eb8f5428cc3b40d6dffe303b195b084f1c5fbd14", + "reference": "eb8f5428cc3b40d6dffe303b195b084f1c5fbd14", "shasum": "" }, "require": { @@ -6453,7 +6614,7 @@ "symfony/yaml": "<3.4" }, "provide": { - "symfony/translation-implementation": "1.0" + "symfony/translation-implementation": "1.0|2.0" }, "require-dev": { "psr/log": "~1.0", @@ -6494,10 +6655,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Translation Component", + "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v4.4.17" + "source": "https://github.com/symfony/translation/tree/v4.4.21" }, "funding": [ { @@ -6513,7 +6674,7 @@ "type": "tidelift" } ], - "time": "2020-11-27T06:35:49+00:00" + "time": "2021-03-23T16:25:01+00:00" }, { "name": "symfony/translation-contracts", @@ -6595,22 +6756,22 @@ }, { "name": "symfony/twig-bridge", - "version": "v4.4.17", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "7d119d2cffb4d11a42690205c2427625c80a060e" + "reference": "f5d0492a38c5325d9c322d406dbe95bc26fc530d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/7d119d2cffb4d11a42690205c2427625c80a060e", - "reference": "7d119d2cffb4d11a42690205c2427625c80a060e", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/f5d0492a38c5325d9c322d406dbe95bc26fc530d", + "reference": "f5d0492a38c5325d9c322d406dbe95bc26fc530d", "shasum": "" }, "require": { "php": ">=7.1.3", "symfony/translation-contracts": "^1.1|^2", - "twig/twig": "^1.41|^2.10|^3.0" + "twig/twig": "^1.43|^2.13|^3.0.4" }, "conflict": { "symfony/console": "<3.4", @@ -6620,7 +6781,7 @@ "symfony/workflow": "<4.3" }, "require-dev": { - "egulias/email-validator": "^2.1.10", + "egulias/email-validator": "^2.1.10|^3", "symfony/asset": "^3.4|^4.0|^5.0", "symfony/console": "^3.4|^4.0|^5.0", "symfony/dependency-injection": "^3.4|^4.0|^5.0", @@ -6630,6 +6791,7 @@ "symfony/form": "^4.4.17", "symfony/http-foundation": "^4.3|^5.0", "symfony/http-kernel": "^4.4", + "symfony/intl": "^4.4|^5.0", "symfony/mime": "^4.3|^5.0", "symfony/polyfill-intl-icu": "~1.0", "symfony/routing": "^3.4|^4.0|^5.0", @@ -6643,9 +6805,9 @@ "symfony/web-link": "^4.4|^5.0", "symfony/workflow": "^4.3|^5.0", "symfony/yaml": "^3.4|^4.0|^5.0", - "twig/cssinliner-extra": "^2.12", - "twig/inky-extra": "^2.12", - "twig/markdown-extra": "^2.12" + "twig/cssinliner-extra": "^2.12|^3", + "twig/inky-extra": "^2.12|^3", + "twig/markdown-extra": "^2.12|^3" }, "suggest": { "symfony/asset": "For using the AssetExtension", @@ -6687,10 +6849,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Twig Bridge", + "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v4.4.17" + "source": "https://github.com/symfony/twig-bridge/tree/v4.4.21" }, "funding": [ { @@ -6706,20 +6868,20 @@ "type": "tidelift" } ], - "time": "2020-11-17T16:25:11+00:00" + "time": "2021-03-16T08:08:39+00:00" }, { "name": "symfony/twig-bundle", - "version": "v4.4.17", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "9acacb72d30ee1ea0331762906a129a66a9d9883" + "reference": "7cee73b45e3bd963a0ab4184f1041dcdc85b6e86" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/9acacb72d30ee1ea0331762906a129a66a9d9883", - "reference": "9acacb72d30ee1ea0331762906a129a66a9d9883", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/7cee73b45e3bd963a0ab4184f1041dcdc85b6e86", + "reference": "7cee73b45e3bd963a0ab4184f1041dcdc85b6e86", "shasum": "" }, "require": { @@ -6728,7 +6890,7 @@ "symfony/http-kernel": "^4.4", "symfony/polyfill-ctype": "~1.8", "symfony/twig-bridge": "^4.4|^5.0", - "twig/twig": "^1.41|^2.10|^3.0" + "twig/twig": "^1.43|^2.13|^3.0.4" }, "conflict": { "symfony/dependency-injection": "<4.1", @@ -6736,7 +6898,7 @@ "symfony/translation": "<4.2" }, "require-dev": { - "doctrine/annotations": "~1.7", + "doctrine/annotations": "^1.10.4", "doctrine/cache": "~1.0", "symfony/asset": "^3.4|^4.0|^5.0", "symfony/dependency-injection": "^4.2.5|^5.0", @@ -6774,10 +6936,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony TwigBundle", + "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v4.4.17" + "source": "https://github.com/symfony/twig-bundle/tree/v4.4.20" }, "funding": [ { @@ -6793,20 +6955,20 @@ "type": "tidelift" } ], - "time": "2020-10-24T11:50:19+00:00" + "time": "2021-01-27T09:09:26+00:00" }, { "name": "symfony/var-dumper", - "version": "v4.4.17", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "65c6f1e848cda840ef7278686c8e30a7cc353c93" + "reference": "0da0e174f728996f5d5072d6a9f0a42259dbc806" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/65c6f1e848cda840ef7278686c8e30a7cc353c93", - "reference": "65c6f1e848cda840ef7278686c8e30a7cc353c93", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/0da0e174f728996f5d5072d6a9f0a42259dbc806", + "reference": "0da0e174f728996f5d5072d6a9f0a42259dbc806", "shasum": "" }, "require": { @@ -6823,7 +6985,7 @@ "ext-iconv": "*", "symfony/console": "^3.4|^4.0|^5.0", "symfony/process": "^4.4|^5.0", - "twig/twig": "^1.34|^2.4|^3.0" + "twig/twig": "^1.43|^2.13|^3.0.4" }, "suggest": { "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", @@ -6859,14 +7021,14 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony mechanism for exploring and dumping PHP variables", + "description": "Provides mechanisms for walking through any arbitrary PHP variable", "homepage": "https://symfony.com", "keywords": [ "debug", "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v4.4.17" + "source": "https://github.com/symfony/var-dumper/tree/v4.4.21" }, "funding": [ { @@ -6882,20 +7044,20 @@ "type": "tidelift" } ], - "time": "2020-11-24T09:55:37+00:00" + "time": "2021-03-27T19:49:03+00:00" }, { "name": "symfony/var-exporter", - "version": "v4.4.17", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "f04b7d187b120e0a44c18a2d479c2dd0abe99d9c" + "reference": "3a3ea598bba6901d20b58c2579f68700089244ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/f04b7d187b120e0a44c18a2d479c2dd0abe99d9c", - "reference": "f04b7d187b120e0a44c18a2d479c2dd0abe99d9c", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/3a3ea598bba6901d20b58c2579f68700089244ed", + "reference": "3a3ea598bba6901d20b58c2579f68700089244ed", "shasum": "" }, "require": { @@ -6927,7 +7089,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "A blend of var_export() + serialize() to turn any serializable data structure to plain PHP code", + "description": "Allows exporting any serializable PHP data structure to plain PHP code", "homepage": "https://symfony.com", "keywords": [ "clone", @@ -6938,7 +7100,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v4.4.17" + "source": "https://github.com/symfony/var-exporter/tree/v4.4.20" }, "funding": [ { @@ -6954,20 +7116,20 @@ "type": "tidelift" } ], - "time": "2020-10-28T20:42:29+00:00" + "time": "2021-01-27T09:09:26+00:00" }, { "name": "symfony/web-profiler-bundle", - "version": "v4.4.17", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "cd980f0df4ae7696d18fd908503fc61ae67ac48d" + "reference": "bd848a0c0f3e7229e329adeea10e8945f70cb4c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/cd980f0df4ae7696d18fd908503fc61ae67ac48d", - "reference": "cd980f0df4ae7696d18fd908503fc61ae67ac48d", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/bd848a0c0f3e7229e329adeea10e8945f70cb4c9", + "reference": "bd848a0c0f3e7229e329adeea10e8945f70cb4c9", "shasum": "" }, "require": { @@ -6977,7 +7139,7 @@ "symfony/http-kernel": "^4.4", "symfony/routing": "^4.3|^5.0", "symfony/twig-bundle": "^4.2|^5.0", - "twig/twig": "^1.41|^2.10|^3.0" + "twig/twig": "^1.43|^2.13|^3.0.4" }, "conflict": { "symfony/form": "<4.3", @@ -7013,10 +7175,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony WebProfilerBundle", + "description": "Provides a development tool that gives detailed information about the execution of any request", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v4.4.17" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v4.4.21" }, "funding": [ { @@ -7032,20 +7194,20 @@ "type": "tidelift" } ], - "time": "2020-10-28T20:42:29+00:00" + "time": "2021-03-15T15:12:10+00:00" }, { "name": "symfony/yaml", - "version": "v4.4.17", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "7531361cf38e4816821b4a12a42542b3c6143ad1" + "reference": "3871c720871029f008928244e56cf43497da7e9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/7531361cf38e4816821b4a12a42542b3c6143ad1", - "reference": "7531361cf38e4816821b4a12a42542b3c6143ad1", + "url": "https://api.github.com/repos/symfony/yaml/zipball/3871c720871029f008928244e56cf43497da7e9d", + "reference": "3871c720871029f008928244e56cf43497da7e9d", "shasum": "" }, "require": { @@ -7084,10 +7246,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Yaml Component", + "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v4.4.17" + "source": "https://github.com/symfony/yaml/tree/v4.4.21" }, "funding": [ { @@ -7103,7 +7265,7 @@ "type": "tidelift" } ], - "time": "2020-11-24T12:28:30+00:00" + "time": "2021-03-05T17:58:50+00:00" }, { "name": "tightenco/collect", @@ -7161,16 +7323,16 @@ }, { "name": "twig/twig", - "version": "v3.1.1", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "b02fa41f3783a2616eccef7b92fbc2343ffed737" + "reference": "1f3b7e2c06cc05d42936a8ad508ff1db7975cdc5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/b02fa41f3783a2616eccef7b92fbc2343ffed737", - "reference": "b02fa41f3783a2616eccef7b92fbc2343ffed737", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/1f3b7e2c06cc05d42936a8ad508ff1db7975cdc5", + "reference": "1f3b7e2c06cc05d42936a8ad508ff1db7975cdc5", "shasum": "" }, "require": { @@ -7185,7 +7347,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "3.3-dev" } }, "autoload": { @@ -7221,7 +7383,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.1.1" + "source": "https://github.com/twigphp/Twig/tree/v3.3.0" }, "funding": [ { @@ -7233,34 +7395,39 @@ "type": "tidelift" } ], - "time": "2020-10-27T19:28:23+00:00" + "time": "2021-02-08T09:54:36+00:00" }, { "name": "webmozart/assert", - "version": "1.9.1", + "version": "1.10.0", "source": { "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" + "url": "https://github.com/webmozarts/assert.git", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0 || ^8.0", + "php": "^7.2 || ^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<3.9.1" + "vimeo/psalm": "<4.6.1 || 4.6.2" }, "require-dev": { - "phpunit/phpunit": "^4.8.36 || ^7.5.13" + "phpunit/phpunit": "^8.5.13" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" @@ -7283,10 +7450,10 @@ "validate" ], "support": { - "issues": "https://github.com/webmozart/assert/issues", - "source": "https://github.com/webmozart/assert/tree/master" + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.10.0" }, - "time": "2020-07-08T17:02:28+00:00" + "time": "2021-03-09T10:59:23+00:00" }, { "name": "zendframework/zend-code", @@ -7415,27 +7582,26 @@ }, { "name": "zircote/swagger-php", - "version": "2.0.16", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/zircote/swagger-php.git", - "reference": "a25c1bfe508e5f27d5f618648449593a79cbe406" + "reference": "5b26395e0e652ca8fc8e2327659f670422eedccd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zircote/swagger-php/zipball/a25c1bfe508e5f27d5f618648449593a79cbe406", - "reference": "a25c1bfe508e5f27d5f618648449593a79cbe406", + "url": "https://api.github.com/repos/zircote/swagger-php/zipball/5b26395e0e652ca8fc8e2327659f670422eedccd", + "reference": "5b26395e0e652ca8fc8e2327659f670422eedccd", "shasum": "" }, "require": { - "doctrine/annotations": "*", - "php": ">=5.6", - "symfony/finder": ">=2.2" + "doctrine/annotations": "^1.7", + "php": ">=7.2", + "symfony/finder": ">=3.4" }, "require-dev": { - "phpunit/phpunit": ">=4.8.35 <=5.6", - "squizlabs/php_codesniffer": ">=2.7", - "zendframework/zend-form": "<2.8" + "phpunit/phpunit": "^8 || ^9", + "squizlabs/php_codesniffer": ">=2.7" }, "bin": [ "bin/swagger" @@ -7475,9 +7641,9 @@ ], "support": { "issues": "https://github.com/zircote/swagger-php/issues", - "source": "https://github.com/zircote/swagger-php/tree/2.0.16" + "source": "https://github.com/zircote/swagger-php/tree/2.1.0" }, - "time": "2020-05-10T13:42:24+00:00" + "time": "2020-11-29T21:40:13+00:00" } ], "packages-dev": [], diff --git a/api/dev.Dockerfile b/api/dev.Dockerfile index 51fb1d1..fbe361e 100644 --- a/api/dev.Dockerfile +++ b/api/dev.Dockerfile @@ -3,16 +3,18 @@ FROM php:7.4-fpm-alpine ENV APP_ENV=dev ENV DATABASE_URL="sqlite:///var/db/app.db" -RUN apk add --no-cache autoconf openssl-dev g++ make pcre-dev icu-dev zlib-dev libzip-dev git && \ - docker-php-ext-install bcmath intl opcache zip sockets; +COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ + +# Composer +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +RUN install-php-extensions bcmath intl opcache zip sockets xdebug-^3.0; +RUN apk add git; # XDebug -RUN pecl install xdebug-3.0.0 && docker-php-ext-enable xdebug RUN echo "xdebug.mode=debug" >> $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini && \ echo "xdebug.discover_client_host=On" >> $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini; -RUN apk del --purge autoconf g++ make - # Blackfire RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \ && curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/amd64/$version \ @@ -22,9 +24,6 @@ RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \ && printf "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8707\n" > $PHP_INI_DIR/conf.d/blackfire.ini \ && rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz -#Composer -COPY --from=composer:latest /usr/bin/composer /usr/bin/composer - # Timezone RUN ln -snf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime && \ echo "date.timezone = Europe/Warsaw" >> /usr/local/etc/php/conf.d/datetime.ini; diff --git a/api/symfony.lock b/api/symfony.lock index a73e0f8..ddc7fe1 100644 --- a/api/symfony.lock +++ b/api/symfony.lock @@ -41,6 +41,9 @@ "doctrine/dbal": { "version": "v2.8.0" }, + "doctrine/deprecations": { + "version": "v0.5.3" + }, "doctrine/doctrine-bundle": { "version": "2.0", "recipe": { @@ -144,6 +147,9 @@ "jdorn/sql-formatter": { "version": "v1.2.17" }, + "jean85/pretty-package-versions": { + "version": "2.0.3" + }, "jms/metadata": { "version": "1.7.0" }, @@ -212,6 +218,9 @@ "phpdocumentor/type-resolver": { "version": "0.4.0" }, + "phpstan/phpdoc-parser": { + "version": "0.4.14" + }, "psr/cache": { "version": "1.0.1" }, diff --git a/docker/php/.env b/docker/php/.env index ef3fd93..f643a2f 100644 --- a/docker/php/.env +++ b/docker/php/.env @@ -1 +1 @@ -PHP_IDE_CONFIG=serverName=czydojade +PHP_IDE_CONFIG=serverName=cojedzie -- 2.45.2 From 674c25cf4c10ebb2d60375239e6efeb47b9c783e Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Wed, 31 Mar 2021 21:38:18 +0200 Subject: [PATCH 66/77] #50 - Update Symfony to 5.2 --- api/composer.json | 19 +- api/composer.lock | 2191 ++++++++--------- api/config/bundles.php | 1 - api/src/Controller/Api/v1/StopsController.php | 2 +- .../WithDestinationsDatabaseHandler.php | 2 +- api/src/Model/Destination.php | 2 +- api/src/Model/Line.php | 2 +- api/src/Model/Stop.php | 2 +- api/src/Model/StopGroup.php | 3 +- api/src/Model/Track.php | 2 +- api/src/Model/Trip.php | 2 +- .../Database/GenericLineRepository.php | 11 +- .../Database/GenericOperatorRepository.php | 2 +- .../Database/GenericScheduleRepository.php | 7 +- .../Database/GenericStopRepository.php | 2 +- .../Database/GenericTrackRepository.php | 6 +- .../Database/GenericTripRepository.php | 2 +- api/src/Provider/DepartureRepository.php | 2 - .../Dummy/DummyDepartureRepository.php | 2 - .../Provider/Dummy/DummyMessageRepository.php | 4 +- .../Provider/Dummy/DummyStopRepository.php | 2 +- api/src/Provider/FluentRepository.php | 2 +- api/src/Provider/MessageRepository.php | 4 +- api/src/Provider/OperatorRepository.php | 3 - api/src/Provider/ScheduleRepository.php | 2 +- api/src/Provider/StopRepository.php | 3 - api/src/Provider/TrackRepository.php | 3 +- .../ZtmGdanskDataUpdateSubscriber.php | 6 +- .../ZtmGdanskDepartureRepository.php | 4 +- .../ZtmGdansk/ZtmGdanskMessageRepository.php | 6 +- api/src/Serialization/CarbonHandler.php | 2 +- .../LaravelCollectionHandler.php | 4 +- api/src/Service/AggregateConverter.php | 2 +- api/src/Service/EntityReferenceFactory.php | 2 +- api/src/Service/IterableUtils.php | 2 +- api/src/Service/ProviderResolver.php | 2 +- api/symfony.lock | 46 +- 37 files changed, 1102 insertions(+), 1259 deletions(-) diff --git a/api/composer.json b/api/composer.json index cab8897..3ea61f5 100644 --- a/api/composer.json +++ b/api/composer.json @@ -10,25 +10,24 @@ "ext-json": "*", "baldinof/roadrunner-bundle": "^1.3", "cerbero/json-objects": "^1.1", - "doctrine/doctrine-cache-bundle": "^1.4", "jms/serializer-bundle": "^3.5", "kadet/functional": "dev-master", "nelmio/api-doc-bundle": "^3.5", - "nesbot/carbon": "^1.33", + "nesbot/carbon": "^2.46.0", "ocramius/proxy-manager": "^2.0", "sensio/framework-extra-bundle": "^5.2", "spiral/roadrunner": "^1.8", - "symfony/asset": "^4.4", - "symfony/console": "^4.4", - "symfony/dotenv": "^4.4", + "symfony/asset": "^5.2", + "symfony/console": "^5.2", + "symfony/dotenv": "^5.2", "symfony/flex": "^1.1", - "symfony/framework-bundle": "^4.4", + "symfony/framework-bundle": "^5.2", "symfony/monolog-bundle": "^3.3", "symfony/orm-pack": "^1.0", "symfony/profiler-pack": "^1.0", - "symfony/twig-bundle": "^4.4", - "symfony/yaml": "^4.4", - "tightenco/collect": "^5.6" + "symfony/twig-bundle": "^5.2", + "symfony/yaml": "^5.2", + "illuminate/collections": "^8.35" }, "config": { "preferred-install": { @@ -79,7 +78,7 @@ "extra": { "symfony": { "allow-contrib": true, - "require": "4.4.*" + "require": "5.2.*" } }, "repositories": [ diff --git a/api/composer.lock b/api/composer.lock index b5b35d6..8562678 100644 --- a/api/composer.lock +++ b/api/composer.lock @@ -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": "b29e467a46157fea720fdc35c6921f47", + "content-hash": "4c087fa5970989805008ea426fdd2221", "packages": [ { "name": "baldinof/roadrunner-bundle", @@ -533,43 +533,31 @@ }, { "name": "doctrine/common", - "version": "2.13.3", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/common.git", - "reference": "f3812c026e557892c34ef37f6ab808a6b567da7f" + "reference": "2afde5a9844126bc311cd5f548b5475e75f800d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/common/zipball/f3812c026e557892c34ef37f6ab808a6b567da7f", - "reference": "f3812c026e557892c34ef37f6ab808a6b567da7f", + "url": "https://api.github.com/repos/doctrine/common/zipball/2afde5a9844126bc311cd5f548b5475e75f800d3", + "reference": "2afde5a9844126bc311cd5f548b5475e75f800d3", "shasum": "" }, "require": { - "doctrine/annotations": "^1.0", - "doctrine/cache": "^1.0", - "doctrine/collections": "^1.0", - "doctrine/event-manager": "^1.0", - "doctrine/inflector": "^1.0", - "doctrine/lexer": "^1.0", - "doctrine/persistence": "^1.3.3", - "doctrine/reflection": "^1.0", + "doctrine/persistence": "^2.0", "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^1.0", - "phpstan/phpstan": "^0.11", - "phpstan/phpstan-phpunit": "^0.11", - "phpunit/phpunit": "^7.0", + "doctrine/coding-standard": "^6.0 || ^8.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpunit/phpunit": "^7.5.20 || ^8.5 || ^9.0", "squizlabs/php_codesniffer": "^3.0", "symfony/phpunit-bridge": "^4.0.5" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.11.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Common\\": "lib/Doctrine/Common" @@ -605,7 +593,7 @@ "email": "ocramius@gmail.com" } ], - "description": "PHP Doctrine Common project is a library that provides additional functionality that other Doctrine projects depend on such as better reflection support, persistence interfaces, proxies, event system and much more.", + "description": "PHP Doctrine Common project is a library that provides additional functionality that other Doctrine projects depend on such as better reflection support, proxies and much more.", "homepage": "https://www.doctrine-project.org/projects/common.html", "keywords": [ "common", @@ -614,7 +602,7 @@ ], "support": { "issues": "https://github.com/doctrine/common/issues", - "source": "https://github.com/doctrine/common/tree/2.13.x" + "source": "https://github.com/doctrine/common/tree/3.1.1" }, "funding": [ { @@ -630,7 +618,7 @@ "type": "tidelift" } ], - "time": "2020-06-05T16:46:05+00:00" + "time": "2021-01-20T19:58:05+00:00" }, { "name": "doctrine/dbal", @@ -891,102 +879,6 @@ ], "time": "2021-03-16T16:24:04+00:00" }, - { - "name": "doctrine/doctrine-cache-bundle", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/DoctrineCacheBundle.git", - "reference": "6bee2f9b339847e8a984427353670bad4e7bdccb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineCacheBundle/zipball/6bee2f9b339847e8a984427353670bad4e7bdccb", - "reference": "6bee2f9b339847e8a984427353670bad4e7bdccb", - "shasum": "" - }, - "require": { - "doctrine/cache": "^1.4.2", - "doctrine/inflector": "^1.0", - "php": "^7.1", - "symfony/doctrine-bridge": "^3.4|^4.0" - }, - "require-dev": { - "instaclick/coding-standard": "~1.1", - "instaclick/object-calisthenics-sniffs": "dev-master", - "instaclick/symfony2-coding-standard": "dev-remaster", - "phpunit/phpunit": "^7.0", - "predis/predis": "~0.8", - "satooshi/php-coveralls": "^1.0", - "squizlabs/php_codesniffer": "~1.5", - "symfony/console": "^3.4|^4.0", - "symfony/finder": "^3.4|^4.0", - "symfony/framework-bundle": "^3.4|^4.0", - "symfony/phpunit-bridge": "^3.4|^4.0", - "symfony/security-acl": "^2.8", - "symfony/validator": "^3.4|^4.0", - "symfony/yaml": "^3.4|^4.0" - }, - "suggest": { - "symfony/security-acl": "For using this bundle to cache ACLs" - }, - "type": "symfony-bundle", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Bundle\\DoctrineCacheBundle\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Fabio B. Silva", - "email": "fabio.bat.silva@gmail.com" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@hotmail.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Doctrine Project", - "homepage": "http://www.doctrine-project.org/" - } - ], - "description": "Symfony Bundle for Doctrine Cache", - "homepage": "https://www.doctrine-project.org", - "keywords": [ - "cache", - "caching" - ], - "support": { - "issues": "https://github.com/doctrine/DoctrineCacheBundle/issues", - "source": "https://github.com/doctrine/DoctrineCacheBundle/tree/1.4.0" - }, - "abandoned": true, - "time": "2019-11-29T11:22:01+00:00" - }, { "name": "doctrine/doctrine-migrations-bundle", "version": "2.2.2", @@ -1169,16 +1061,16 @@ }, { "name": "doctrine/inflector", - "version": "1.4.3", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "4650c8b30c753a76bf44fb2ed00117d6f367490c" + "reference": "9cf661f4eb38f7c881cac67c75ea9b00bf97b210" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/4650c8b30c753a76bf44fb2ed00117d6f367490c", - "reference": "4650c8b30c753a76bf44fb2ed00117d6f367490c", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/9cf661f4eb38f7c881cac67c75ea9b00bf97b210", + "reference": "9cf661f4eb38f7c881cac67c75ea9b00bf97b210", "shasum": "" }, "require": { @@ -1199,7 +1091,6 @@ }, "autoload": { "psr-4": { - "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector", "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" } }, @@ -1245,7 +1136,7 @@ ], "support": { "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/1.4.x" + "source": "https://github.com/doctrine/inflector/tree/2.0.x" }, "funding": [ { @@ -1261,7 +1152,7 @@ "type": "tidelift" } ], - "time": "2020-05-29T07:19:59+00:00" + "time": "2020-05-29T15:13:26+00:00" }, { "name": "doctrine/instantiator", @@ -1514,16 +1405,16 @@ }, { "name": "doctrine/orm", - "version": "2.7.5", + "version": "2.8.2", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "01187c9260cd085529ddd1273665217cae659640" + "reference": "ebae57eb9637acd8252b398df3121b120688ed5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/01187c9260cd085529ddd1273665217cae659640", - "reference": "01187c9260cd085529ddd1273665217cae659640", + "url": "https://api.github.com/repos/doctrine/orm/zipball/ebae57eb9637acd8252b398df3121b120688ed5c", + "reference": "ebae57eb9637acd8252b398df3121b120688ed5c", "shasum": "" }, "require": { @@ -1531,23 +1422,23 @@ "doctrine/annotations": "^1.11.1", "doctrine/cache": "^1.9.1", "doctrine/collections": "^1.5", - "doctrine/common": "^2.11 || ^3.0", - "doctrine/dbal": "^2.9.3", + "doctrine/common": "^3.0.3", + "doctrine/dbal": "^2.10.0", "doctrine/event-manager": "^1.1", - "doctrine/inflector": "^1.0", + "doctrine/inflector": "^1.4|^2.0", "doctrine/instantiator": "^1.3", "doctrine/lexer": "^1.0", - "doctrine/persistence": "^1.3.3 || ^2.0", + "doctrine/persistence": "^2.0", "ext-pdo": "*", - "php": "^7.1", + "php": "^7.2|^8.0", "symfony/console": "^3.0|^4.0|^5.0" }, "require-dev": { - "doctrine/coding-standard": "^6.0", + "doctrine/coding-standard": "^8.0", "phpstan/phpstan": "^0.12.18", - "phpunit/phpunit": "^8.0", + "phpunit/phpunit": "^8.5|^9.4", "symfony/yaml": "^3.4|^4.0|^5.0", - "vimeo/psalm": "^3.11" + "vimeo/psalm": "4.1.1" }, "suggest": { "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" @@ -1600,22 +1491,22 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/2.7.5" + "source": "https://github.com/doctrine/orm/tree/2.8.2" }, - "time": "2020-12-03T08:52:14+00:00" + "time": "2021-02-16T22:10:18+00:00" }, { "name": "doctrine/persistence", - "version": "1.3.8", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/persistence.git", - "reference": "7a6eac9fb6f61bba91328f15aa7547f4806ca288" + "reference": "9899c16934053880876b920a3b8b02ed2337ac1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/persistence/zipball/7a6eac9fb6f61bba91328f15aa7547f4806ca288", - "reference": "7a6eac9fb6f61bba91328f15aa7547f4806ca288", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/9899c16934053880876b920a3b8b02ed2337ac1d", + "reference": "9899c16934053880876b920a3b8b02ed2337ac1d", "shasum": "" }, "require": { @@ -1623,24 +1514,20 @@ "doctrine/cache": "^1.0", "doctrine/collections": "^1.0", "doctrine/event-manager": "^1.0", - "doctrine/reflection": "^1.2", "php": "^7.1 || ^8.0" }, "conflict": { "doctrine/common": "<2.10@dev" }, "require-dev": { - "doctrine/coding-standard": "^6.0", - "phpstan/phpstan": "^0.11", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "composer/package-versions-deprecated": "^1.11", + "doctrine/coding-standard": "^6.0 || ^8.0", + "doctrine/common": "^3.0", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^7.5.20 || ^8.0 || ^9.0", "vimeo/psalm": "^3.11" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Common\\": "lib/Doctrine/Common", @@ -1688,106 +1575,9 @@ ], "support": { "issues": "https://github.com/doctrine/persistence/issues", - "source": "https://github.com/doctrine/persistence/tree/1.3.x" + "source": "https://github.com/doctrine/persistence/tree/2.1.0" }, - "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%2Fpersistence", - "type": "tidelift" - } - ], - "time": "2020-06-20T12:56:16+00:00" - }, - { - "name": "doctrine/reflection", - "version": "1.2.2", - "source": { - "type": "git", - "url": "https://github.com/doctrine/reflection.git", - "reference": "fa587178be682efe90d005e3a322590d6ebb59a5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/reflection/zipball/fa587178be682efe90d005e3a322590d6ebb59a5", - "reference": "fa587178be682efe90d005e3a322590d6ebb59a5", - "shasum": "" - }, - "require": { - "doctrine/annotations": "^1.0", - "ext-tokenizer": "*", - "php": "^7.1 || ^8.0" - }, - "conflict": { - "doctrine/common": "<2.9" - }, - "require-dev": { - "doctrine/coding-standard": "^6.0 || ^8.2.0", - "doctrine/common": "^2.10", - "phpstan/phpstan": "^0.11.0 || ^0.12.20", - "phpstan/phpstan-phpunit": "^0.11.0 || ^0.12.16", - "phpunit/phpunit": "^7.5 || ^9.1.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Common\\": "lib/Doctrine/Common" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - }, - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - } - ], - "description": "The Doctrine Reflection project is a simple library used by the various Doctrine projects which adds some additional functionality on top of the reflection functionality that comes with PHP. It allows you to get the reflection information about classes, methods and properties statically.", - "homepage": "https://www.doctrine-project.org/projects/reflection.html", - "keywords": [ - "reflection", - "static" - ], - "support": { - "issues": "https://github.com/doctrine/reflection/issues", - "source": "https://github.com/doctrine/reflection/tree/1.2.2" - }, - "abandoned": "roave/better-reflection", - "time": "2020-10-27T21:46:55+00:00" + "time": "2020-10-24T22:13:54+00:00" }, { "name": "doctrine/sql-formatter", @@ -1889,6 +1679,154 @@ }, "time": "2020-11-19T17:14:18+00:00" }, + { + "name": "illuminate/collections", + "version": "v8.35.1", + "source": { + "type": "git", + "url": "https://github.com/illuminate/collections.git", + "reference": "0a7a96520928b61df1750b4e1909588f10ae2abe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/collections/zipball/0a7a96520928b61df1750b4e1909588f10ae2abe", + "reference": "0a7a96520928b61df1750b4e1909588f10ae2abe", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^8.0", + "illuminate/macroable": "^8.0", + "php": "^7.3|^8.0" + }, + "suggest": { + "symfony/var-dumper": "Required to use the dump method (^5.1.4)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Support\\": "" + }, + "files": [ + "helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Collections package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2021-03-25T14:54:04+00:00" + }, + { + "name": "illuminate/contracts", + "version": "v8.35.1", + "source": { + "type": "git", + "url": "https://github.com/illuminate/contracts.git", + "reference": "121cea1d8b8772bc7fee99c71ecf0f57c1d77b3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/contracts/zipball/121cea1d8b8772bc7fee99c71ecf0f57c1d77b3b", + "reference": "121cea1d8b8772bc7fee99c71ecf0f57c1d77b3b", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0", + "psr/container": "^1.0", + "psr/simple-cache": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Contracts\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Contracts package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2021-03-12T14:45:30+00:00" + }, + { + "name": "illuminate/macroable", + "version": "v8.35.1", + "source": { + "type": "git", + "url": "https://github.com/illuminate/macroable.git", + "reference": "300aa13c086f25116b5f3cde3ca54ff5c822fb05" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/macroable/zipball/300aa13c086f25116b5f3cde3ca54ff5c822fb05", + "reference": "300aa13c086f25116b5f3cde3ca54ff5c822fb05", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Support\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Macroable package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2020-10-27T15:20:30+00:00" + }, { "name": "jean85/pretty-package-versions", "version": "2.0.3", @@ -2229,69 +2167,6 @@ "description": "Functional library for PHP", "time": "2018-09-08T09:28:23+00:00" }, - { - "name": "kylekatarnls/update-helper", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/kylekatarnls/update-helper.git", - "reference": "429be50660ed8a196e0798e5939760f168ec8ce9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/kylekatarnls/update-helper/zipball/429be50660ed8a196e0798e5939760f168ec8ce9", - "reference": "429be50660ed8a196e0798e5939760f168ec8ce9", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.1.0 || ^2.0.0", - "php": ">=5.3.0" - }, - "require-dev": { - "codeclimate/php-test-reporter": "dev-master", - "composer/composer": "2.0.x-dev || ^2.0.0-dev", - "phpunit/phpunit": ">=4.8.35 <6.0" - }, - "type": "composer-plugin", - "extra": { - "class": "UpdateHelper\\ComposerPlugin" - }, - "autoload": { - "psr-0": { - "UpdateHelper\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kyle", - "email": "kylekatarnls@gmail.com" - } - ], - "description": "Update helper", - "support": { - "issues": "https://github.com/kylekatarnls/update-helper/issues", - "source": "https://github.com/kylekatarnls/update-helper/tree/1.2.1" - }, - "funding": [ - { - "url": "https://github.com/kylekatarnls", - "type": "github" - }, - { - "url": "https://opencollective.com/Carbon", - "type": "open_collective" - }, - { - "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", - "type": "tidelift" - } - ], - "time": "2020-04-07T20:44:10+00:00" - }, { "name": "laminas/laminas-diactoros", "version": "2.5.0", @@ -2456,21 +2331,21 @@ }, { "name": "monolog/monolog", - "version": "1.26.0", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33" + "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/2209ddd84e7ef1256b7af205d0717fb62cfc9c33", - "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1cb1cde8e8dd0f70cc0fe51354a59acad9302084", + "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084", "shasum": "" }, "require": { - "php": ">=5.3.0", - "psr/log": "~1.0" + "php": ">=7.2", + "psr/log": "^1.0.1" }, "provide": { "psr/log-implementation": "1.0.0" @@ -2478,29 +2353,39 @@ "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", - "graylog2/gelf-php": "~1.0", + "elasticsearch/elasticsearch": "^7", + "graylog2/gelf-php": "^1.4.2", + "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", + "phpspec/prophecy": "^1.6.1", "phpstan/phpstan": "^0.12.59", - "phpunit/phpunit": "~4.5", - "ruflin/elastica": ">=0.90 <3.0", - "sentry/sentry": "^0.13", + "phpunit/phpunit": "^8.5", + "predis/predis": "^1.1", + "rollbar/rollbar": "^1.3", + "ruflin/elastica": ">=0.90 <7.0.1", "swiftmailer/swiftmailer": "^5.3|^6.0" }, "suggest": { "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", - "ext-mongo": "Allow sending log messages to a MongoDB server", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", "php-console/php-console": "Allow sending log messages to Google Chrome", "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server", - "sentry/sentry": "Allow sending log messages to a Sentry server" + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, "autoload": { "psr-4": { "Monolog\\": "src/Monolog" @@ -2514,11 +2399,11 @@ { "name": "Jordi Boggiano", "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "homepage": "https://seld.be" } ], "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "http://github.com/Seldaek/monolog", + "homepage": "https://github.com/Seldaek/monolog", "keywords": [ "log", "logging", @@ -2526,7 +2411,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/1.26.0" + "source": "https://github.com/Seldaek/monolog/tree/2.2.0" }, "funding": [ { @@ -2538,7 +2423,7 @@ "type": "tidelift" } ], - "time": "2020-12-14T12:56:38+00:00" + "time": "2020-12-14T13:15:25+00:00" }, { "name": "nelmio/api-doc-bundle", @@ -2638,43 +2523,57 @@ }, { "name": "nesbot/carbon", - "version": "1.39.1", + "version": "2.46.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "4be0c005164249208ce1b5ca633cd57bdd42ff33" + "reference": "2fd2c4a77d58a4e95234c8a61c5df1f157a91bf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/4be0c005164249208ce1b5ca633cd57bdd42ff33", - "reference": "4be0c005164249208ce1b5ca633cd57bdd42ff33", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/2fd2c4a77d58a4e95234c8a61c5df1f157a91bf4", + "reference": "2fd2c4a77d58a4e95234c8a61c5df1f157a91bf4", "shasum": "" }, "require": { - "kylekatarnls/update-helper": "^1.1", - "php": ">=5.3.9", - "symfony/translation": "~2.6 || ~3.0 || ~4.0" + "ext-json": "*", + "php": "^7.1.8 || ^8.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/translation": "^3.4 || ^4.0 || ^5.0" }, "require-dev": { - "composer/composer": "^1.2", - "friendsofphp/php-cs-fixer": "~2", - "phpunit/phpunit": "^4.8.35 || ^5.7" + "doctrine/orm": "^2.7", + "friendsofphp/php-cs-fixer": "^2.14 || ^3.0", + "kylekatarnls/multi-tester": "^2.0", + "phpmd/phpmd": "^2.9", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12.54", + "phpunit/phpunit": "^7.5.20 || ^8.5.14", + "squizlabs/php_codesniffer": "^3.4" }, "bin": [ - "bin/upgrade-carbon" + "bin/carbon" ], "type": "library", "extra": { - "update-helper": "Carbon\\Upgrade", + "branch-alias": { + "dev-master": "2.x-dev", + "dev-3.x": "3.x-dev" + }, "laravel": { "providers": [ "Carbon\\Laravel\\ServiceProvider" ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] } }, "autoload": { "psr-4": { - "": "src/" + "Carbon\\": "src/Carbon/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2686,9 +2585,13 @@ "name": "Brian Nesbitt", "email": "brian@nesbot.com", "homepage": "http://nesbot.com" + }, + { + "name": "kylekatarnls", + "homepage": "http://github.com/kylekatarnls" } ], - "description": "A simple API extension for DateTime.", + "description": "An API extension for DateTime that supports 281 different languages.", "homepage": "http://carbon.nesbot.com", "keywords": [ "date", @@ -2699,7 +2602,17 @@ "issues": "https://github.com/briannesbitt/Carbon/issues", "source": "https://github.com/briannesbitt/Carbon" }, - "time": "2019-10-14T05:51:36+00:00" + "funding": [ + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } + ], + "time": "2021-02-24T17:30:44+00:00" }, { "name": "ocramius/proxy-manager", @@ -3149,6 +3062,56 @@ }, "time": "2021-03-05T17:36:06+00:00" }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, { "name": "psr/http-factory", "version": "1.0.1", @@ -3421,6 +3384,57 @@ }, "time": "2020-03-23T09:12:05+00:00" }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/master" + }, + "time": "2017-10-23T01:57:42+00:00" + }, { "name": "salsify/json-streaming-parser", "version": "v8.2.0", @@ -3681,24 +3695,25 @@ }, { "name": "symfony/asset", - "version": "v4.4.20", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/asset.git", - "reference": "f2204a526c34945b1614cde033692983b6102eb8" + "reference": "54a42aa50f9359d1184bf7e954521b45ca3d5828" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset/zipball/f2204a526c34945b1614cde033692983b6102eb8", - "reference": "f2204a526c34945b1614cde033692983b6102eb8", + "url": "https://api.github.com/repos/symfony/asset/zipball/54a42aa50f9359d1184bf7e954521b45ca3d5828", + "reference": "54a42aa50f9359d1184bf7e954521b45ca3d5828", "shasum": "" }, "require": { - "php": ">=7.1.3" + "php": ">=7.2.5" }, "require-dev": { - "symfony/http-foundation": "^3.4|^4.0|^5.0", - "symfony/http-kernel": "^3.4|^4.0|^5.0" + "symfony/http-client": "^4.4|^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/http-kernel": "^4.4|^5.0" }, "suggest": { "symfony/http-foundation": "" @@ -3729,7 +3744,7 @@ "description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/asset/tree/v4.4.20" + "source": "https://github.com/symfony/asset/tree/v5.2.4" }, "funding": [ { @@ -3745,34 +3760,35 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-01-27T10:01:46+00:00" }, { "name": "symfony/cache", - "version": "v4.4.21", + "version": "v5.2.6", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "b7ff54be3f3eb1ce09643692f0c309b1b27bc992" + "reference": "093d69bb10c959553c8beb828b8d4ea250a247dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/b7ff54be3f3eb1ce09643692f0c309b1b27bc992", - "reference": "b7ff54be3f3eb1ce09643692f0c309b1b27bc992", + "url": "https://api.github.com/repos/symfony/cache/zipball/093d69bb10c959553c8beb828b8d4ea250a247dd", + "reference": "093d69bb10c959553c8beb828b8d4ea250a247dd", "shasum": "" }, "require": { - "php": ">=7.1.3", + "php": ">=7.2.5", "psr/cache": "^1.0|^2.0", - "psr/log": "~1.0", + "psr/log": "^1.1", "symfony/cache-contracts": "^1.1.7|^2", + "symfony/polyfill-php80": "^1.15", "symfony/service-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.2|^5.0" + "symfony/var-exporter": "^4.4|^5.0" }, "conflict": { - "doctrine/dbal": "<2.6", - "symfony/dependency-injection": "<3.4", - "symfony/http-kernel": "<4.4|>=5.0", + "doctrine/dbal": "<2.10", + "symfony/dependency-injection": "<4.4", + "symfony/http-kernel": "<4.4", "symfony/var-dumper": "<4.4" }, "provide": { @@ -3783,13 +3799,14 @@ "require-dev": { "cache/integration-tests": "dev-master", "doctrine/cache": "^1.6", - "doctrine/dbal": "^2.6|^3.0", + "doctrine/dbal": "^2.10|^3.0", "predis/predis": "^1.1", "psr/simple-cache": "^1.0", - "symfony/config": "^4.2|^5.0", - "symfony/dependency-injection": "^3.4|^4.1|^5.0", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", "symfony/filesystem": "^4.4|^5.0", - "symfony/http-kernel": "^4.4", + "symfony/http-kernel": "^4.4|^5.0", + "symfony/messenger": "^4.4|^5.0", "symfony/var-dumper": "^4.4|^5.0" }, "type": "library", @@ -3822,7 +3839,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v4.4.21" + "source": "https://github.com/symfony/cache/tree/v5.2.6" }, "funding": [ { @@ -3838,7 +3855,7 @@ "type": "tidelift" } ], - "time": "2021-03-14T19:28:18+00:00" + "time": "2021-03-16T09:10:13+00:00" }, { "name": "symfony/cache-contracts", @@ -3921,32 +3938,34 @@ }, { "name": "symfony/config", - "version": "v4.4.20", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "98606c6fa1a8f55ff964ccdd704275bf5b9f71b3" + "reference": "212d54675bf203ff8aef7d8cee8eecfb72f4a263" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/98606c6fa1a8f55ff964ccdd704275bf5b9f71b3", - "reference": "98606c6fa1a8f55ff964ccdd704275bf5b9f71b3", + "url": "https://api.github.com/repos/symfony/config/zipball/212d54675bf203ff8aef7d8cee8eecfb72f4a263", + "reference": "212d54675bf203ff8aef7d8cee8eecfb72f4a263", "shasum": "" }, "require": { - "php": ">=7.1.3", - "symfony/filesystem": "^3.4|^4.0|^5.0", - "symfony/polyfill-ctype": "~1.8" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/filesystem": "^4.4|^5.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.15" }, "conflict": { - "symfony/finder": "<3.4" + "symfony/finder": "<4.4" }, "require-dev": { - "symfony/event-dispatcher": "^3.4|^4.0|^5.0", - "symfony/finder": "^3.4|^4.0|^5.0", - "symfony/messenger": "^4.1|^5.0", + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/finder": "^4.4|^5.0", + "symfony/messenger": "^4.4|^5.0", "symfony/service-contracts": "^1.1|^2", - "symfony/yaml": "^3.4|^4.0|^5.0" + "symfony/yaml": "^4.4|^5.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -3977,7 +3996,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v4.4.20" + "source": "https://github.com/symfony/config/tree/v5.2.4" }, "funding": [ { @@ -3993,46 +4012,48 @@ "type": "tidelift" } ], - "time": "2021-02-22T15:36:50+00:00" + "time": "2021-02-23T23:58:19+00:00" }, { "name": "symfony/console", - "version": "v4.4.21", + "version": "v5.2.6", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "1ba4560dbbb9fcf5ae28b61f71f49c678086cf23" + "reference": "35f039df40a3b335ebf310f244cb242b3a83ac8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/1ba4560dbbb9fcf5ae28b61f71f49c678086cf23", - "reference": "1ba4560dbbb9fcf5ae28b61f71f49c678086cf23", + "url": "https://api.github.com/repos/symfony/console/zipball/35f039df40a3b335ebf310f244cb242b3a83ac8d", + "reference": "35f039df40a3b335ebf310f244cb242b3a83ac8d", "shasum": "" }, "require": { - "php": ">=7.1.3", + "php": ">=7.2.5", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php73": "^1.8", "symfony/polyfill-php80": "^1.15", - "symfony/service-contracts": "^1.1|^2" + "symfony/service-contracts": "^1.1|^2", + "symfony/string": "^5.1" }, "conflict": { - "symfony/dependency-injection": "<3.4", - "symfony/event-dispatcher": "<4.3|>=5", + "symfony/dependency-injection": "<4.4", + "symfony/dotenv": "<5.1", + "symfony/event-dispatcher": "<4.4", "symfony/lock": "<4.4", - "symfony/process": "<3.3" + "symfony/process": "<4.4" }, "provide": { "psr/log-implementation": "1.0" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "^3.4|^4.0|^5.0", - "symfony/dependency-injection": "^3.4|^4.0|^5.0", - "symfony/event-dispatcher": "^4.3", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/event-dispatcher": "^4.4|^5.0", "symfony/lock": "^4.4|^5.0", - "symfony/process": "^3.4|^4.0|^5.0", - "symfony/var-dumper": "^4.3|^5.0" + "symfony/process": "^4.4|^5.0", + "symfony/var-dumper": "^4.4|^5.0" }, "suggest": { "psr/log": "For using the console logger", @@ -4065,8 +4086,14 @@ ], "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command line", + "console", + "terminal" + ], "support": { - "source": "https://github.com/symfony/console/tree/v4.4.21" + "source": "https://github.com/symfony/console/tree/v5.2.6" }, "funding": [ { @@ -4082,110 +4109,43 @@ "type": "tidelift" } ], - "time": "2021-03-26T09:23:24+00:00" - }, - { - "name": "symfony/debug", - "version": "v4.4.20", - "source": { - "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "157bbec4fd773bae53c5483c50951a5530a2cc16" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/157bbec4fd773bae53c5483c50951a5530a2cc16", - "reference": "157bbec4fd773bae53c5483c50951a5530a2cc16", - "shasum": "" - }, - "require": { - "php": ">=7.1.3", - "psr/log": "~1.0", - "symfony/polyfill-php80": "^1.15" - }, - "conflict": { - "symfony/http-kernel": "<3.4" - }, - "require-dev": { - "symfony/http-kernel": "^3.4|^4.0|^5.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Debug\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides tools to ease debugging PHP code", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/debug/tree/v4.4.20" - }, - "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": "2021-01-28T16:54:48+00:00" + "time": "2021-03-28T09:42:18+00:00" }, { "name": "symfony/dependency-injection", - "version": "v4.4.21", + "version": "v5.2.6", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "b5f97557faa48ead4671bc311cfca423d476e93e" + "reference": "1e66194bed2a69fa395d26bf1067e5e34483afac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/b5f97557faa48ead4671bc311cfca423d476e93e", - "reference": "b5f97557faa48ead4671bc311cfca423d476e93e", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/1e66194bed2a69fa395d26bf1067e5e34483afac", + "reference": "1e66194bed2a69fa395d26bf1067e5e34483afac", "shasum": "" }, "require": { - "php": ">=7.1.3", + "php": ">=7.2.5", "psr/container": "^1.0", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php80": "^1.15", "symfony/service-contracts": "^1.1.6|^2" }, "conflict": { - "symfony/config": "<4.3|>=5.0", - "symfony/finder": "<3.4", - "symfony/proxy-manager-bridge": "<3.4", - "symfony/yaml": "<3.4" + "symfony/config": "<5.1", + "symfony/finder": "<4.4", + "symfony/proxy-manager-bridge": "<4.4", + "symfony/yaml": "<4.4" }, "provide": { "psr/container-implementation": "1.0", "symfony/service-implementation": "1.0|2.0" }, "require-dev": { - "symfony/config": "^4.3", - "symfony/expression-language": "^3.4|^4.0|^5.0", - "symfony/yaml": "^3.4|^4.0|^5.0" + "symfony/config": "^5.1", + "symfony/expression-language": "^4.4|^5.0", + "symfony/yaml": "^4.4|^5.0" }, "suggest": { "symfony/config": "", @@ -4220,7 +4180,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v4.4.21" + "source": "https://github.com/symfony/dependency-injection/tree/v5.2.6" }, "funding": [ { @@ -4236,38 +4196,110 @@ "type": "tidelift" } ], - "time": "2021-03-05T18:16:26+00:00" + "time": "2021-03-22T11:10:24+00:00" }, { - "name": "symfony/doctrine-bridge", - "version": "v4.4.21", + "name": "symfony/deprecation-contracts", + "version": "v2.2.0", "source": { "type": "git", - "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "e643bddb38277b4a1c2973d1489768c6e6c0db80" + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/e643bddb38277b4a1c2973d1489768c6e6c0db80", - "reference": "e643bddb38277b4a1c2973d1489768c6e6c0db80", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5fa56b4074d1ae755beb55617ddafe6f5d78f665", + "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "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": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/master" + }, + "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-09-07T11:33:47+00:00" + }, + { + "name": "symfony/doctrine-bridge", + "version": "v5.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/doctrine-bridge.git", + "reference": "72b6d743c6108e2b8d15ab94e1a8a224c4d0d144" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/72b6d743c6108e2b8d15ab94e1a8a224c4d0d144", + "reference": "72b6d743c6108e2b8d15ab94e1a8a224c4d0d144", "shasum": "" }, "require": { "doctrine/event-manager": "~1.0", - "doctrine/persistence": "^1.3|^2", - "php": ">=7.1.3", + "doctrine/persistence": "^2", + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.15", "symfony/service-contracts": "^1.1|^2" }, "conflict": { - "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", - "symfony/dependency-injection": "<3.4", - "symfony/form": "<4.4", - "symfony/http-kernel": "<4.3.7", - "symfony/messenger": "<4.3", - "symfony/security-core": "<4.4", - "symfony/validator": "<4.4.2|<5.0.2,>=5.0" + "doctrine/dbal": "<2.10", + "phpunit/phpunit": "<5.4.3", + "symfony/dependency-injection": "<4.4", + "symfony/form": "<5.1", + "symfony/http-kernel": "<5", + "symfony/messenger": "<4.4", + "symfony/property-info": "<5", + "symfony/security-bundle": "<5", + "symfony/security-core": "<5", + "symfony/validator": "<5.2" }, "require-dev": { "composer/package-versions-deprecated": "^1.8", @@ -4275,22 +4307,25 @@ "doctrine/cache": "~1.6", "doctrine/collections": "~1.0", "doctrine/data-fixtures": "^1.1", - "doctrine/dbal": "^2.6|^3.0", - "doctrine/orm": "^2.6.3", - "symfony/config": "^4.2|^5.0", - "symfony/dependency-injection": "^3.4|^4.0|^5.0", - "symfony/expression-language": "^3.4|^4.0|^5.0", - "symfony/form": "^4.4.11|^5.0.11", - "symfony/http-kernel": "^4.3.7", + "doctrine/dbal": "^2.10|^3.0", + "doctrine/orm": "^2.7.3", + "symfony/cache": "^5.1", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/doctrine-messenger": "^5.1", + "symfony/expression-language": "^4.4|^5.0", + "symfony/form": "^5.1.3", + "symfony/http-kernel": "^5.0", "symfony/messenger": "^4.4|^5.0", - "symfony/property-access": "^3.4|^4.0|^5.0", - "symfony/property-info": "^3.4|^4.0|^5.0", - "symfony/proxy-manager-bridge": "^3.4|^4.0|^5.0", - "symfony/security-core": "^4.4|^5.0", - "symfony/stopwatch": "^3.4|^4.0|^5.0", - "symfony/translation": "^3.4|^4.0|^5.0", - "symfony/validator": "^4.4.2|^5.0.2", - "symfony/var-dumper": "^3.4|^4.0|^5.0" + "symfony/property-access": "^4.4|^5.0", + "symfony/property-info": "^5.0", + "symfony/proxy-manager-bridge": "^4.4|^5.0", + "symfony/security-core": "^5.0", + "symfony/stopwatch": "^4.4|^5.0", + "symfony/translation": "^4.4|^5.0", + "symfony/uid": "^5.1", + "symfony/validator": "^5.2", + "symfony/var-dumper": "^4.4|^5.0" }, "suggest": { "doctrine/data-fixtures": "", @@ -4326,7 +4361,7 @@ "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v4.4.21" + "source": "https://github.com/symfony/doctrine-bridge/tree/v5.2.6" }, "funding": [ { @@ -4342,27 +4377,28 @@ "type": "tidelift" } ], - "time": "2021-03-09T16:20:30+00:00" + "time": "2021-03-10T22:10:15+00:00" }, { "name": "symfony/dotenv", - "version": "v4.4.20", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "4952e5ce9e6df3d737b9e9c337bddf781180a213" + "reference": "783f12027c6b40ab0e93d6136d9f642d1d67cd6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/4952e5ce9e6df3d737b9e9c337bddf781180a213", - "reference": "4952e5ce9e6df3d737b9e9c337bddf781180a213", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/783f12027c6b40ab0e93d6136d9f642d1d67cd6b", + "reference": "783f12027c6b40ab0e93d6136d9f642d1d67cd6b", "shasum": "" }, "require": { - "php": ">=7.1.3" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1" }, "require-dev": { - "symfony/process": "^3.4.2|^4.0|^5.0" + "symfony/process": "^4.4|^5.0" }, "type": "library", "autoload": { @@ -4395,7 +4431,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v4.4.20" + "source": "https://github.com/symfony/dotenv/tree/v5.2.4" }, "funding": [ { @@ -4411,30 +4447,30 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-01-27T10:01:46+00:00" }, { "name": "symfony/error-handler", - "version": "v4.4.21", + "version": "v5.2.6", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "48e81a375525872e788c2418430f54150d935810" + "reference": "bdb7fb4188da7f4211e4b88350ba0dfdad002b03" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/48e81a375525872e788c2418430f54150d935810", - "reference": "48e81a375525872e788c2418430f54150d935810", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/bdb7fb4188da7f4211e4b88350ba0dfdad002b03", + "reference": "bdb7fb4188da7f4211e4b88350ba0dfdad002b03", "shasum": "" }, "require": { - "php": ">=7.1.3", - "psr/log": "~1.0", - "symfony/debug": "^4.4.5", + "php": ">=7.2.5", + "psr/log": "^1.0", "symfony/polyfill-php80": "^1.15", "symfony/var-dumper": "^4.4|^5.0" }, "require-dev": { + "symfony/deprecation-contracts": "^2.1", "symfony/http-kernel": "^4.4|^5.0", "symfony/serializer": "^4.4|^5.0" }, @@ -4464,7 +4500,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v4.4.21" + "source": "https://github.com/symfony/error-handler/tree/v5.2.6" }, "funding": [ { @@ -4480,42 +4516,44 @@ "type": "tidelift" } ], - "time": "2021-03-08T10:28:40+00:00" + "time": "2021-03-16T09:07:47+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.4.20", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "c352647244bd376bf7d31efbd5401f13f50dad0c" + "reference": "d08d6ec121a425897951900ab692b612a61d6240" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/c352647244bd376bf7d31efbd5401f13f50dad0c", - "reference": "c352647244bd376bf7d31efbd5401f13f50dad0c", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d08d6ec121a425897951900ab692b612a61d6240", + "reference": "d08d6ec121a425897951900ab692b612a61d6240", "shasum": "" }, "require": { - "php": ">=7.1.3", - "symfony/event-dispatcher-contracts": "^1.1" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/event-dispatcher-contracts": "^2", + "symfony/polyfill-php80": "^1.15" }, "conflict": { - "symfony/dependency-injection": "<3.4" + "symfony/dependency-injection": "<4.4" }, "provide": { "psr/event-dispatcher-implementation": "1.0", - "symfony/event-dispatcher-implementation": "1.1" + "symfony/event-dispatcher-implementation": "2.0" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "^3.4|^4.0|^5.0", - "symfony/dependency-injection": "^3.4|^4.0|^5.0", - "symfony/error-handler": "~3.4|~4.4", - "symfony/expression-language": "^3.4|^4.0|^5.0", - "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/error-handler": "^4.4|^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/http-foundation": "^4.4|^5.0", "symfony/service-contracts": "^1.1|^2", - "symfony/stopwatch": "^3.4|^4.0|^5.0" + "symfony/stopwatch": "^4.4|^5.0" }, "suggest": { "symfony/dependency-injection": "", @@ -4547,7 +4585,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.20" + "source": "https://github.com/symfony/event-dispatcher/tree/v5.2.4" }, "funding": [ { @@ -4563,33 +4601,33 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-02-18T17:12:37+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v1.1.9", + "version": "v2.2.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "84e23fdcd2517bf37aecbd16967e83f0caee25a7" + "reference": "0ba7d54483095a198fa51781bc608d17e84dffa2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/84e23fdcd2517bf37aecbd16967e83f0caee25a7", - "reference": "84e23fdcd2517bf37aecbd16967e83f0caee25a7", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/0ba7d54483095a198fa51781bc608d17e84dffa2", + "reference": "0ba7d54483095a198fa51781bc608d17e84dffa2", "shasum": "" }, "require": { - "php": ">=7.1.3" + "php": ">=7.2.5", + "psr/event-dispatcher": "^1" }, "suggest": { - "psr/event-dispatcher": "", "symfony/event-dispatcher-implementation": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "2.2-dev" }, "thanks": { "name": "symfony/contracts", @@ -4626,7 +4664,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.9" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.2.0" }, "funding": [ { @@ -4642,24 +4680,24 @@ "type": "tidelift" } ], - "time": "2020-07-06T13:19:58+00:00" + "time": "2020-09-07T11:33:47+00:00" }, { "name": "symfony/filesystem", - "version": "v4.4.21", + "version": "v5.2.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "940826c465be2690c9fae91b2793481e5cbd6834" + "reference": "8c86a82f51658188119e62cff0a050a12d09836f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/940826c465be2690c9fae91b2793481e5cbd6834", - "reference": "940826c465be2690c9fae91b2793481e5cbd6834", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/8c86a82f51658188119e62cff0a050a12d09836f", + "reference": "8c86a82f51658188119e62cff0a050a12d09836f", "shasum": "" }, "require": { - "php": ">=7.1.3", + "php": ">=7.2.5", "symfony/polyfill-ctype": "~1.8" }, "type": "library", @@ -4688,7 +4726,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v4.4.21" + "source": "https://github.com/symfony/filesystem/tree/v5.2.6" }, "funding": [ { @@ -4704,24 +4742,24 @@ "type": "tidelift" } ], - "time": "2021-03-28T09:59:32+00:00" + "time": "2021-03-28T14:30:26+00:00" }, { "name": "symfony/finder", - "version": "v4.4.20", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "2543795ab1570df588b9bbd31e1a2bd7037b94f6" + "reference": "0d639a0943822626290d169965804f79400e6a04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/2543795ab1570df588b9bbd31e1a2bd7037b94f6", - "reference": "2543795ab1570df588b9bbd31e1a2bd7037b94f6", + "url": "https://api.github.com/repos/symfony/finder/zipball/0d639a0943822626290d169965804f79400e6a04", + "reference": "0d639a0943822626290d169965804f79400e6a04", "shasum": "" }, "require": { - "php": ">=7.1.3" + "php": ">=7.2.5" }, "type": "library", "autoload": { @@ -4749,7 +4787,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v4.4.20" + "source": "https://github.com/symfony/finder/tree/v5.2.4" }, "funding": [ { @@ -4765,7 +4803,7 @@ "type": "tidelift" } ], - "time": "2021-02-12T10:48:09+00:00" + "time": "2021-02-15T18:55:04+00:00" }, { "name": "symfony/flex", @@ -4837,58 +4875,61 @@ }, { "name": "symfony/framework-bundle", - "version": "v4.4.21", + "version": "v5.2.6", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "fc72fbb0f9a69d2eb5d94cc8c231176265db680a" + "reference": "8889da18c6faa76c6149a90e6542be4afe723f2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/fc72fbb0f9a69d2eb5d94cc8c231176265db680a", - "reference": "fc72fbb0f9a69d2eb5d94cc8c231176265db680a", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/8889da18c6faa76c6149a90e6542be4afe723f2f", + "reference": "8889da18c6faa76c6149a90e6542be4afe723f2f", "shasum": "" }, "require": { "ext-xml": "*", - "php": ">=7.1.3", - "symfony/cache": "^4.4|^5.0", - "symfony/config": "^4.3.4|^5.0", - "symfony/dependency-injection": "^4.4.1|^5.0.1", + "php": ">=7.2.5", + "symfony/cache": "^5.2", + "symfony/config": "^5.0", + "symfony/dependency-injection": "^5.2", + "symfony/deprecation-contracts": "^2.1", "symfony/error-handler": "^4.4.1|^5.0.1", - "symfony/filesystem": "^3.4|^4.0|^5.0", - "symfony/finder": "^3.4|^4.0|^5.0", - "symfony/http-foundation": "^4.4|^5.0", - "symfony/http-kernel": "^4.4", + "symfony/event-dispatcher": "^5.1", + "symfony/filesystem": "^4.4|^5.0", + "symfony/finder": "^4.4|^5.0", + "symfony/http-foundation": "^5.2.1", + "symfony/http-kernel": "^5.2.1", "symfony/polyfill-mbstring": "~1.0", - "symfony/routing": "^4.4.12|^5.1.4" + "symfony/polyfill-php80": "^1.15", + "symfony/routing": "^5.2" }, "conflict": { "doctrine/persistence": "<1.3", - "phpdocumentor/reflection-docblock": "<3.0|>=3.2.0,<3.2.2", - "phpdocumentor/type-resolver": "<0.3.0|1.3.*", - "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", - "symfony/asset": "<3.4", - "symfony/browser-kit": "<4.3", - "symfony/console": "<4.4.21", - "symfony/dom-crawler": "<4.3", - "symfony/dotenv": "<4.3.6", - "symfony/form": "<4.3.5", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "phpunit/phpunit": "<5.4.3", + "symfony/asset": "<5.1", + "symfony/browser-kit": "<4.4", + "symfony/console": "<5.2.5", + "symfony/dom-crawler": "<4.4", + "symfony/dotenv": "<5.1", + "symfony/form": "<5.2", "symfony/http-client": "<4.4", "symfony/lock": "<4.4", - "symfony/mailer": "<4.4", + "symfony/mailer": "<5.2", "symfony/messenger": "<4.4", "symfony/mime": "<4.4", - "symfony/property-info": "<3.4", - "symfony/security-bundle": "<4.4", - "symfony/serializer": "<4.4", - "symfony/stopwatch": "<3.4", - "symfony/translation": "<4.4", - "symfony/twig-bridge": "<4.1.1", + "symfony/property-access": "<5.2", + "symfony/property-info": "<4.4", + "symfony/serializer": "<5.2", + "symfony/stopwatch": "<4.4", + "symfony/translation": "<5.0", + "symfony/twig-bridge": "<4.4", "symfony/twig-bundle": "<4.4", - "symfony/validator": "<4.4", + "symfony/validator": "<5.2", "symfony/web-profiler-bundle": "<4.4", - "symfony/workflow": "<4.3.6" + "symfony/workflow": "<5.2" }, "require-dev": { "doctrine/annotations": "^1.10.4", @@ -4896,35 +4937,36 @@ "doctrine/persistence": "^1.3|^2.0", "paragonie/sodium_compat": "^1.8", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/asset": "^3.4|^4.0|^5.0", - "symfony/browser-kit": "^4.3|^5.0", - "symfony/console": "^4.4.21|^5.0", - "symfony/css-selector": "^3.4|^4.0|^5.0", - "symfony/dom-crawler": "^4.3|^5.0", - "symfony/dotenv": "^4.3.6|^5.0", - "symfony/expression-language": "^3.4|^4.0|^5.0", - "symfony/form": "^4.3.5|^5.0", + "symfony/asset": "^5.1", + "symfony/browser-kit": "^4.4|^5.0", + "symfony/console": "^5.2", + "symfony/css-selector": "^4.4|^5.0", + "symfony/dom-crawler": "^4.4|^5.0", + "symfony/dotenv": "^5.1", + "symfony/expression-language": "^4.4|^5.0", + "symfony/form": "^5.2", "symfony/http-client": "^4.4|^5.0", "symfony/lock": "^4.4|^5.0", - "symfony/mailer": "^4.4|^5.0", - "symfony/messenger": "^4.4|^5.0", + "symfony/mailer": "^5.2", + "symfony/messenger": "^5.2", "symfony/mime": "^4.4|^5.0", "symfony/polyfill-intl-icu": "~1.0", - "symfony/process": "^3.4|^4.0|^5.0", - "symfony/property-info": "^3.4|^4.0|^5.0", - "symfony/security-core": "^3.4|^4.4|^5.2", - "symfony/security-csrf": "^3.4|^4.0|^5.0", - "symfony/security-http": "^3.4|^4.0|^5.0", - "symfony/serializer": "^4.4|^5.0", - "symfony/stopwatch": "^3.4|^4.0|^5.0", - "symfony/templating": "^3.4|^4.0|^5.0", - "symfony/translation": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0", + "symfony/property-info": "^4.4|^5.0", + "symfony/security-bundle": "^5.1", + "symfony/security-core": "^4.4|^5.2", + "symfony/security-csrf": "^4.4|^5.0", + "symfony/security-http": "^4.4|^5.0", + "symfony/serializer": "^5.2", + "symfony/stopwatch": "^4.4|^5.0", + "symfony/string": "^5.0", + "symfony/translation": "^5.0", "symfony/twig-bundle": "^4.4|^5.0", - "symfony/validator": "^4.4|^5.0", + "symfony/validator": "^5.2", "symfony/web-link": "^4.4|^5.0", - "symfony/workflow": "^4.3.6|^5.0", - "symfony/yaml": "^3.4|^4.0|^5.0", - "twig/twig": "^1.43|^2.13|^3.0.4" + "symfony/workflow": "^5.2", + "symfony/yaml": "^4.4|^5.0", + "twig/twig": "^2.10|^3.0" }, "suggest": { "ext-apcu": "For best performance of the system caches", @@ -4962,7 +5004,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v4.4.21" + "source": "https://github.com/symfony/framework-bundle/tree/v5.2.6" }, "funding": [ { @@ -4978,7 +5020,7 @@ "type": "tidelift" } ], - "time": "2021-03-18T09:22:03+00:00" + "time": "2021-03-22T14:43:01+00:00" }, { "name": "symfony/http-client-contracts", @@ -5061,27 +5103,32 @@ }, { "name": "symfony/http-foundation", - "version": "v4.4.20", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "02d968647fe61b2f419a8dc70c468a9d30a48d3a" + "reference": "54499baea7f7418bce7b5ec92770fd0799e8e9bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/02d968647fe61b2f419a8dc70c468a9d30a48d3a", - "reference": "02d968647fe61b2f419a8dc70c468a9d30a48d3a", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/54499baea7f7418bce7b5ec92770fd0799e8e9bf", + "reference": "54499baea7f7418bce7b5ec92770fd0799e8e9bf", "shasum": "" }, "require": { - "php": ">=7.1.3", - "symfony/mime": "^4.3|^5.0", + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-mbstring": "~1.1", "symfony/polyfill-php80": "^1.15" }, "require-dev": { "predis/predis": "~1.0", - "symfony/expression-language": "^3.4|^4.0|^5.0" + "symfony/cache": "^4.4|^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0" + }, + "suggest": { + "symfony/mime": "To use the file extension guesser" }, "type": "library", "autoload": { @@ -5109,7 +5156,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v4.4.20" + "source": "https://github.com/symfony/http-foundation/tree/v5.2.4" }, "funding": [ { @@ -5125,27 +5172,28 @@ "type": "tidelift" } ], - "time": "2021-02-25T17:11:33+00:00" + "time": "2021-02-25T17:16:57+00:00" }, { "name": "symfony/http-kernel", - "version": "v4.4.21", + "version": "v5.2.6", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "0248214120d00c5f44f1cd5d9ad65f0b38459333" + "reference": "f34de4c61ca46df73857f7f36b9a3805bdd7e3b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/0248214120d00c5f44f1cd5d9ad65f0b38459333", - "reference": "0248214120d00c5f44f1cd5d9ad65f0b38459333", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f34de4c61ca46df73857f7f36b9a3805bdd7e3b2", + "reference": "f34de4c61ca46df73857f7f36b9a3805bdd7e3b2", "shasum": "" }, "require": { - "php": ">=7.1.3", + "php": ">=7.2.5", "psr/log": "~1.0", - "symfony/error-handler": "^4.4", - "symfony/event-dispatcher": "^4.4", + "symfony/deprecation-contracts": "^2.1", + "symfony/error-handler": "^4.4|^5.0", + "symfony/event-dispatcher": "^5.0", "symfony/http-client-contracts": "^1.1|^2", "symfony/http-foundation": "^4.4|^5.0", "symfony/polyfill-ctype": "^1.8", @@ -5153,33 +5201,40 @@ "symfony/polyfill-php80": "^1.15" }, "conflict": { - "symfony/browser-kit": "<4.3", - "symfony/config": "<3.4", - "symfony/console": ">=5", - "symfony/dependency-injection": "<4.3", - "symfony/translation": "<4.2", - "twig/twig": "<1.43|<2.13,>=2" + "symfony/browser-kit": "<4.4", + "symfony/cache": "<5.0", + "symfony/config": "<5.0", + "symfony/console": "<4.4", + "symfony/dependency-injection": "<5.1.8", + "symfony/doctrine-bridge": "<5.0", + "symfony/form": "<5.0", + "symfony/http-client": "<5.0", + "symfony/mailer": "<5.0", + "symfony/messenger": "<5.0", + "symfony/translation": "<5.0", + "symfony/twig-bridge": "<5.0", + "symfony/validator": "<5.0", + "twig/twig": "<2.13" }, "provide": { "psr/log-implementation": "1.0" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", - "symfony/browser-kit": "^4.3|^5.0", - "symfony/config": "^3.4|^4.0|^5.0", - "symfony/console": "^3.4|^4.0", - "symfony/css-selector": "^3.4|^4.0|^5.0", - "symfony/dependency-injection": "^4.3|^5.0", - "symfony/dom-crawler": "^3.4|^4.0|^5.0", - "symfony/expression-language": "^3.4|^4.0|^5.0", - "symfony/finder": "^3.4|^4.0|^5.0", - "symfony/process": "^3.4|^4.0|^5.0", - "symfony/routing": "^3.4|^4.0|^5.0", - "symfony/stopwatch": "^3.4|^4.0|^5.0", - "symfony/templating": "^3.4|^4.0|^5.0", - "symfony/translation": "^4.2|^5.0", + "symfony/browser-kit": "^4.4|^5.0", + "symfony/config": "^5.0", + "symfony/console": "^4.4|^5.0", + "symfony/css-selector": "^4.4|^5.0", + "symfony/dependency-injection": "^5.1.8", + "symfony/dom-crawler": "^4.4|^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/finder": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0", + "symfony/routing": "^4.4|^5.0", + "symfony/stopwatch": "^4.4|^5.0", + "symfony/translation": "^4.4|^5.0", "symfony/translation-contracts": "^1.1|^2", - "twig/twig": "^1.43|^2.13|^3.0.4" + "twig/twig": "^2.13|^3.0.4" }, "suggest": { "symfony/browser-kit": "", @@ -5213,7 +5268,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v4.4.21" + "source": "https://github.com/symfony/http-kernel/tree/v5.2.6" }, "funding": [ { @@ -5229,182 +5284,40 @@ "type": "tidelift" } ], - "time": "2021-03-29T05:11:04+00:00" - }, - { - "name": "symfony/inflector", - "version": "v4.4.21", - "source": { - "type": "git", - "url": "https://github.com/symfony/inflector.git", - "reference": "9455097d23776a4a10c817d903271bc1ce7596ff" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/inflector/zipball/9455097d23776a4a10c817d903271bc1ce7596ff", - "reference": "9455097d23776a4a10c817d903271bc1ce7596ff", - "shasum": "" - }, - "require": { - "php": ">=7.1.3", - "symfony/polyfill-ctype": "~1.8" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Inflector\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Converts words between their singular and plural forms (English only)", - "homepage": "https://symfony.com", - "keywords": [ - "inflection", - "pluralize", - "singularize", - "string", - "symfony", - "words" - ], - "support": { - "source": "https://github.com/symfony/inflector/tree/v4.4.21" - }, - "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": "2021-03-17T16:19:54+00:00" - }, - { - "name": "symfony/mime", - "version": "v4.4.21", - "source": { - "type": "git", - "url": "https://github.com/symfony/mime.git", - "reference": "50d7a1d569edad1f1321c59123c4c322c8daff7c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/50d7a1d569edad1f1321c59123c4c322c8daff7c", - "reference": "50d7a1d569edad1f1321c59123c4c322c8daff7c", - "shasum": "" - }, - "require": { - "php": ">=7.1.3", - "symfony/polyfill-intl-idn": "^1.10", - "symfony/polyfill-mbstring": "^1.0" - }, - "conflict": { - "egulias/email-validator": "~3.0.0", - "symfony/mailer": "<4.4" - }, - "require-dev": { - "egulias/email-validator": "^2.1.10|^3.1", - "symfony/dependency-injection": "^3.4|^4.1|^5.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Mime\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Allows manipulating MIME messages", - "homepage": "https://symfony.com", - "keywords": [ - "mime", - "mime-type" - ], - "support": { - "source": "https://github.com/symfony/mime/tree/v4.4.21" - }, - "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": "2021-03-12T08:47:38+00:00" + "time": "2021-03-29T05:16:58+00:00" }, { "name": "symfony/monolog-bridge", - "version": "v4.4.21", + "version": "v5.2.5", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "3741314b95e8d0c11a485dce562898f5f67f455c" + "reference": "8a330ab86c4bdf3983b26abf64bf85574edf0d52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/3741314b95e8d0c11a485dce562898f5f67f455c", - "reference": "3741314b95e8d0c11a485dce562898f5f67f455c", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/8a330ab86c4bdf3983b26abf64bf85574edf0d52", + "reference": "8a330ab86c4bdf3983b26abf64bf85574edf0d52", "shasum": "" }, "require": { - "monolog/monolog": "^1.25.1", - "php": ">=7.1.3", - "symfony/http-kernel": "^4.3", + "monolog/monolog": "^1.25.1|^2", + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/http-kernel": "^4.4|^5.0", "symfony/service-contracts": "^1.1|^2" }, "conflict": { - "symfony/console": "<3.4", - "symfony/http-foundation": "<3.4" + "symfony/console": "<4.4", + "symfony/http-foundation": "<4.4" }, "require-dev": { - "symfony/console": "^3.4|^4.0|^5.0", + "symfony/console": "^4.4|^5.0", "symfony/http-client": "^4.4|^5.0", - "symfony/security-core": "^3.4|^4.0|^5.0", - "symfony/var-dumper": "^3.4|^4.0|^5.0" + "symfony/mailer": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0", + "symfony/security-core": "^4.4|^5.0", + "symfony/var-dumper": "^4.4|^5.0" }, "suggest": { "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings.", @@ -5437,7 +5350,7 @@ "description": "Provides integration for Monolog with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/monolog-bridge/tree/v4.4.21" + "source": "https://github.com/symfony/monolog-bridge/tree/v5.2.5" }, "funding": [ { @@ -5453,7 +5366,7 @@ "type": "tidelift" } ], - "time": "2021-03-05T17:58:50+00:00" + "time": "2021-03-06T07:59:01+00:00" }, { "name": "symfony/monolog-bundle", @@ -5538,20 +5451,23 @@ }, { "name": "symfony/options-resolver", - "version": "v4.4.20", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "cd8c6a2778d5f8b5e8fc4b7abdf126790b5d5095" + "reference": "5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/cd8c6a2778d5f8b5e8fc4b7abdf126790b5d5095", - "reference": "cd8c6a2778d5f8b5e8fc4b7abdf126790b5d5095", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce", + "reference": "5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce", "shasum": "" }, "require": { - "php": ">=7.1.3" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php73": "~1.0", + "symfony/polyfill-php80": "^1.15" }, "type": "library", "autoload": { @@ -5584,7 +5500,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v4.4.20" + "source": "https://github.com/symfony/options-resolver/tree/v5.2.4" }, "funding": [ { @@ -5600,25 +5516,24 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-01-27T12:56:27+00:00" }, { "name": "symfony/orm-pack", - "version": "v1.2.0", + "version": "v1.1.0", "source": { "type": "git", "url": "https://github.com/symfony/orm-pack.git", - "reference": "21ac491414b5815e5ebb7425908c1d1568d2e775" + "reference": "7dd2ed9ba6d7af79f90bdc77522605d40463e533" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/orm-pack/zipball/21ac491414b5815e5ebb7425908c1d1568d2e775", - "reference": "21ac491414b5815e5ebb7425908c1d1568d2e775", + "url": "https://api.github.com/repos/symfony/orm-pack/zipball/7dd2ed9ba6d7af79f90bdc77522605d40463e533", + "reference": "7dd2ed9ba6d7af79f90bdc77522605d40463e533", "shasum": "" }, "require": { "composer/package-versions-deprecated": "*", - "doctrine/common": "^2", "doctrine/doctrine-bundle": "^2", "doctrine/doctrine-migrations-bundle": "^2", "doctrine/orm": "^2" @@ -5631,7 +5546,7 @@ "description": "A pack for the Doctrine ORM", "support": { "issues": "https://github.com/symfony/orm-pack/issues", - "source": "https://github.com/symfony/orm-pack/tree/v1.2.0" + "source": "https://github.com/symfony/orm-pack/tree/master" }, "funding": [ { @@ -5647,26 +5562,24 @@ "type": "tidelift" } ], - "time": "2020-08-31T10:20:18+00:00" + "time": "2020-07-08T14:31:54+00:00" }, { - "name": "symfony/polyfill-intl-idn", + "name": "symfony/polyfill-intl-grapheme", "version": "v1.22.1", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "2d63434d922daf7da8dd863e7907e67ee3031483" + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "5601e09b69f26c1828b13b6bb87cb07cddba3170" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/2d63434d922daf7da8dd863e7907e67ee3031483", - "reference": "2d63434d922daf7da8dd863e7907e67ee3031483", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/5601e09b69f26c1828b13b6bb87cb07cddba3170", + "reference": "5601e09b69f26c1828b13b6bb87cb07cddba3170", "shasum": "" }, "require": { - "php": ">=7.1", - "symfony/polyfill-intl-normalizer": "^1.10", - "symfony/polyfill-php72": "^1.10" + "php": ">=7.1" }, "suggest": { "ext-intl": "For best performance" @@ -5683,7 +5596,7 @@ }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" }, "files": [ "bootstrap.php" @@ -5695,30 +5608,26 @@ ], "authors": [ { - "name": "Laurent Bassin", - "email": "laurent@bassin.info" - }, - { - "name": "Trevor Rowbotham", - "email": "trevor.rowbotham@pm.me" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "description": "Symfony polyfill for intl's grapheme_* functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "idn", + "grapheme", "intl", "polyfill", "portable", "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.22.1" }, "funding": [ { @@ -5900,82 +5809,6 @@ ], "time": "2021-01-22T09:19:47+00:00" }, - { - "name": "symfony/polyfill-php72", - "version": "v1.22.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "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.2+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.1" - }, - "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": "2021-01-07T16:49:33+00:00" - }, { "name": "symfony/polyfill-php73", "version": "v1.22.1", @@ -6185,33 +6018,35 @@ }, { "name": "symfony/property-info", - "version": "v4.4.20", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "67845c335482cea0dd52497ae1314ce7a4978c74" + "reference": "7185bbc74e6f49c3f1b5936b4d9e4ca133921189" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/67845c335482cea0dd52497ae1314ce7a4978c74", - "reference": "67845c335482cea0dd52497ae1314ce7a4978c74", + "url": "https://api.github.com/repos/symfony/property-info/zipball/7185bbc74e6f49c3f1b5936b4d9e4ca133921189", + "reference": "7185bbc74e6f49c3f1b5936b4d9e4ca133921189", "shasum": "" }, "require": { - "php": ">=7.1.3", - "symfony/inflector": "^3.4|^4.0|^5.0" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php80": "^1.15", + "symfony/string": "^5.1" }, "conflict": { - "phpdocumentor/reflection-docblock": "<3.0|>=3.2.0,<3.2.2", - "phpdocumentor/type-resolver": "<0.3.0|1.3.*", - "symfony/dependency-injection": "<3.4" + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/dependency-injection": "<4.4" }, "require-dev": { "doctrine/annotations": "^1.10.4", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/cache": "^3.4|^4.0|^5.0", - "symfony/dependency-injection": "^3.4|^4.0|^5.0", - "symfony/serializer": "^3.4|^4.0|^5.0" + "symfony/cache": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" }, "suggest": { "phpdocumentor/reflection-docblock": "To use the PHPDoc", @@ -6253,7 +6088,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v4.4.20" + "source": "https://github.com/symfony/property-info/tree/v5.2.4" }, "funding": [ { @@ -6269,7 +6104,7 @@ "type": "tidelift" } ], - "time": "2021-02-16T12:45:26+00:00" + "time": "2021-02-17T15:24:54+00:00" }, { "name": "symfony/psr-http-message-bridge", @@ -6361,34 +6196,36 @@ }, { "name": "symfony/routing", - "version": "v4.4.20", + "version": "v5.2.6", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "69919991c845b34626664ddc9b3aef9d09d2a5df" + "reference": "31fba555f178afd04d54fd26953501b2c3f0c6e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/69919991c845b34626664ddc9b3aef9d09d2a5df", - "reference": "69919991c845b34626664ddc9b3aef9d09d2a5df", + "url": "https://api.github.com/repos/symfony/routing/zipball/31fba555f178afd04d54fd26953501b2c3f0c6e6", + "reference": "31fba555f178afd04d54fd26953501b2c3f0c6e6", "shasum": "" }, "require": { - "php": ">=7.1.3" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php80": "^1.15" }, "conflict": { - "symfony/config": "<4.2", - "symfony/dependency-injection": "<3.4", - "symfony/yaml": "<3.4" + "symfony/config": "<5.0", + "symfony/dependency-injection": "<4.4", + "symfony/yaml": "<4.4" }, "require-dev": { "doctrine/annotations": "^1.10.4", "psr/log": "~1.0", - "symfony/config": "^4.2|^5.0", - "symfony/dependency-injection": "^3.4|^4.0|^5.0", - "symfony/expression-language": "^3.4|^4.0|^5.0", - "symfony/http-foundation": "^3.4|^4.0|^5.0", - "symfony/yaml": "^3.4|^4.0|^5.0" + "symfony/config": "^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/yaml": "^4.4|^5.0" }, "suggest": { "doctrine/annotations": "For using the annotation loader", @@ -6429,7 +6266,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v4.4.20" + "source": "https://github.com/symfony/routing/tree/v5.2.6" }, "funding": [ { @@ -6445,7 +6282,7 @@ "type": "tidelift" } ], - "time": "2021-02-22T15:37:04+00:00" + "time": "2021-03-14T13:53:33+00:00" }, { "name": "symfony/service-contracts", @@ -6528,20 +6365,20 @@ }, { "name": "symfony/stopwatch", - "version": "v4.4.20", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "c5572f6494fc20668a73b77684d8dc77e534d8cf" + "reference": "b12274acfab9d9850c52583d136a24398cdf1a0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/c5572f6494fc20668a73b77684d8dc77e534d8cf", - "reference": "c5572f6494fc20668a73b77684d8dc77e534d8cf", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/b12274acfab9d9850c52583d136a24398cdf1a0c", + "reference": "b12274acfab9d9850c52583d136a24398cdf1a0c", "shasum": "" }, "require": { - "php": ">=7.1.3", + "php": ">=7.2.5", "symfony/service-contracts": "^1.0|^2" }, "type": "library", @@ -6570,7 +6407,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v4.4.20" + "source": "https://github.com/symfony/stopwatch/tree/v5.2.4" }, "funding": [ { @@ -6586,46 +6423,131 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-01-27T10:15:41+00:00" }, { - "name": "symfony/translation", - "version": "v4.4.21", + "name": "symfony/string", + "version": "v5.2.6", "source": { "type": "git", - "url": "https://github.com/symfony/translation.git", - "reference": "eb8f5428cc3b40d6dffe303b195b084f1c5fbd14" + "url": "https://github.com/symfony/string.git", + "reference": "ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/eb8f5428cc3b40d6dffe303b195b084f1c5fbd14", - "reference": "eb8f5428cc3b40d6dffe303b195b084f1c5fbd14", + "url": "https://api.github.com/repos/symfony/string/zipball/ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572", + "reference": "ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572", "shasum": "" }, "require": { - "php": ">=7.1.3", + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", "symfony/polyfill-mbstring": "~1.0", - "symfony/translation-contracts": "^1.1.6|^2" + "symfony/polyfill-php80": "~1.15" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "files": [ + "Resources/functions.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v5.2.6" + }, + "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": "2021-03-17T17:12:15+00:00" + }, + { + "name": "symfony/translation", + "version": "v5.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "2cc7f45d96db9adfcf89adf4401d9dfed509f4e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/2cc7f45d96db9adfcf89adf4401d9dfed509f4e1", + "reference": "2cc7f45d96db9adfcf89adf4401d9dfed509f4e1", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.15", + "symfony/translation-contracts": "^2.3" }, "conflict": { - "symfony/config": "<3.4", - "symfony/dependency-injection": "<3.4", - "symfony/http-kernel": "<4.4", - "symfony/yaml": "<3.4" + "symfony/config": "<4.4", + "symfony/dependency-injection": "<5.0", + "symfony/http-kernel": "<5.0", + "symfony/twig-bundle": "<5.0", + "symfony/yaml": "<4.4" }, "provide": { - "symfony/translation-implementation": "1.0|2.0" + "symfony/translation-implementation": "2.3" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "^3.4|^4.0|^5.0", - "symfony/console": "^3.4|^4.0|^5.0", - "symfony/dependency-injection": "^3.4|^4.0|^5.0", - "symfony/finder": "~2.8|~3.0|~4.0|^5.0", - "symfony/http-kernel": "^4.4", - "symfony/intl": "^3.4|^4.0|^5.0", + "symfony/config": "^4.4|^5.0", + "symfony/console": "^4.4|^5.0", + "symfony/dependency-injection": "^5.0", + "symfony/finder": "^4.4|^5.0", + "symfony/http-kernel": "^5.0", + "symfony/intl": "^4.4|^5.0", "symfony/service-contracts": "^1.1.2|^2", - "symfony/yaml": "^3.4|^4.0|^5.0" + "symfony/yaml": "^4.4|^5.0" }, "suggest": { "psr/log-implementation": "To use logging capability in translator", @@ -6634,6 +6556,9 @@ }, "type": "library", "autoload": { + "files": [ + "Resources/functions.php" + ], "psr-4": { "Symfony\\Component\\Translation\\": "" }, @@ -6658,7 +6583,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v4.4.21" + "source": "https://github.com/symfony/translation/tree/v5.2.6" }, "funding": [ { @@ -6674,7 +6599,7 @@ "type": "tidelift" } ], - "time": "2021-03-23T16:25:01+00:00" + "time": "2021-03-23T19:33:48+00:00" }, { "name": "symfony/translation-contracts", @@ -6756,55 +6681,60 @@ }, { "name": "symfony/twig-bridge", - "version": "v4.4.21", + "version": "v5.2.6", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "f5d0492a38c5325d9c322d406dbe95bc26fc530d" + "reference": "a65d8d38c66f147f29b73d53d14e8c9a983653b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/f5d0492a38c5325d9c322d406dbe95bc26fc530d", - "reference": "f5d0492a38c5325d9c322d406dbe95bc26fc530d", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/a65d8d38c66f147f29b73d53d14e8c9a983653b8", + "reference": "a65d8d38c66f147f29b73d53d14e8c9a983653b8", "shasum": "" }, "require": { - "php": ">=7.1.3", + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.15", "symfony/translation-contracts": "^1.1|^2", - "twig/twig": "^1.43|^2.13|^3.0.4" + "twig/twig": "^2.13|^3.0.4" }, "conflict": { - "symfony/console": "<3.4", - "symfony/form": "<4.4", - "symfony/http-foundation": "<4.3", - "symfony/translation": "<4.2", - "symfony/workflow": "<4.3" + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/console": "<4.4", + "symfony/form": "<5.1", + "symfony/http-foundation": "<4.4", + "symfony/http-kernel": "<4.4", + "symfony/translation": "<5.2", + "symfony/workflow": "<5.2" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3", - "symfony/asset": "^3.4|^4.0|^5.0", - "symfony/console": "^3.4|^4.0|^5.0", - "symfony/dependency-injection": "^3.4|^4.0|^5.0", - "symfony/error-handler": "^4.4|^5.0", - "symfony/expression-language": "^3.4|^4.0|^5.0", - "symfony/finder": "^3.4|^4.0|^5.0", - "symfony/form": "^4.4.17", - "symfony/http-foundation": "^4.3|^5.0", - "symfony/http-kernel": "^4.4", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/asset": "^4.4|^5.0", + "symfony/console": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/finder": "^4.4|^5.0", + "symfony/form": "^5.1.9", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/http-kernel": "^4.4|^5.0", "symfony/intl": "^4.4|^5.0", - "symfony/mime": "^4.3|^5.0", + "symfony/mime": "^5.2", "symfony/polyfill-intl-icu": "~1.0", - "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/property-info": "^4.4|^5.1", + "symfony/routing": "^4.4|^5.0", "symfony/security-acl": "^2.8|^3.0", - "symfony/security-core": "^3.0|^4.0|^5.0", - "symfony/security-csrf": "^3.4|^4.0|^5.0", - "symfony/security-http": "^3.4|^4.0|^5.0", - "symfony/stopwatch": "^3.4|^4.0|^5.0", - "symfony/templating": "^3.4|^4.0|^5.0", - "symfony/translation": "^4.2.1|^5.0", + "symfony/security-core": "^4.4|^5.0", + "symfony/security-csrf": "^4.4|^5.0", + "symfony/security-http": "^4.4|^5.0", + "symfony/serializer": "^5.2", + "symfony/stopwatch": "^4.4|^5.0", + "symfony/translation": "^5.2", "symfony/web-link": "^4.4|^5.0", - "symfony/workflow": "^4.3|^5.0", - "symfony/yaml": "^3.4|^4.0|^5.0", + "symfony/workflow": "^5.2", + "symfony/yaml": "^4.4|^5.0", "twig/cssinliner-extra": "^2.12|^3", "twig/inky-extra": "^2.12|^3", "twig/markdown-extra": "^2.12|^3" @@ -6820,7 +6750,6 @@ "symfony/security-csrf": "For using the CsrfExtension", "symfony/security-http": "For using the LogoutUrlExtension", "symfony/stopwatch": "For using the StopwatchExtension", - "symfony/templating": "For using the TwigEngine", "symfony/translation": "For using the TranslationExtension", "symfony/var-dumper": "For using the DumpExtension", "symfony/web-link": "For using the WebLinkExtension", @@ -6852,7 +6781,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v4.4.21" + "source": "https://github.com/symfony/twig-bridge/tree/v5.2.6" }, "funding": [ { @@ -6868,50 +6797,50 @@ "type": "tidelift" } ], - "time": "2021-03-16T08:08:39+00:00" + "time": "2021-03-16T09:10:13+00:00" }, { "name": "symfony/twig-bundle", - "version": "v4.4.20", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "7cee73b45e3bd963a0ab4184f1041dcdc85b6e86" + "reference": "5ebbb5f0e8bfaa0b4b37cb25ff97f83b18caf221" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/7cee73b45e3bd963a0ab4184f1041dcdc85b6e86", - "reference": "7cee73b45e3bd963a0ab4184f1041dcdc85b6e86", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/5ebbb5f0e8bfaa0b4b37cb25ff97f83b18caf221", + "reference": "5ebbb5f0e8bfaa0b4b37cb25ff97f83b18caf221", "shasum": "" }, "require": { - "php": ">=7.1.3", - "symfony/http-foundation": "^4.3|^5.0", - "symfony/http-kernel": "^4.4", + "php": ">=7.2.5", + "symfony/config": "^4.4|^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/http-kernel": "^5.0", "symfony/polyfill-ctype": "~1.8", - "symfony/twig-bridge": "^4.4|^5.0", - "twig/twig": "^1.43|^2.13|^3.0.4" + "symfony/twig-bridge": "^5.0", + "twig/twig": "^2.13|^3.0.4" }, "conflict": { - "symfony/dependency-injection": "<4.1", - "symfony/framework-bundle": "<4.4", - "symfony/translation": "<4.2" + "symfony/dependency-injection": "<5.2", + "symfony/framework-bundle": "<5.0", + "symfony/translation": "<5.0" }, "require-dev": { "doctrine/annotations": "^1.10.4", "doctrine/cache": "~1.0", - "symfony/asset": "^3.4|^4.0|^5.0", - "symfony/dependency-injection": "^4.2.5|^5.0", - "symfony/expression-language": "^3.4|^4.0|^5.0", - "symfony/finder": "^3.4|^4.0|^5.0", - "symfony/form": "^3.4|^4.0|^5.0", - "symfony/framework-bundle": "^4.4|^5.0", - "symfony/routing": "^3.4|^4.0|^5.0", - "symfony/stopwatch": "^3.4|^4.0|^5.0", - "symfony/templating": "^3.4|^4.0|^5.0", - "symfony/translation": "^4.2|^5.0", - "symfony/web-link": "^3.4|^4.0|^5.0", - "symfony/yaml": "^3.4|^4.0|^5.0" + "symfony/asset": "^4.4|^5.0", + "symfony/dependency-injection": "^5.2", + "symfony/expression-language": "^4.4|^5.0", + "symfony/finder": "^4.4|^5.0", + "symfony/form": "^4.4|^5.0", + "symfony/framework-bundle": "^5.0", + "symfony/routing": "^4.4|^5.0", + "symfony/stopwatch": "^4.4|^5.0", + "symfony/translation": "^5.0", + "symfony/web-link": "^4.4|^5.0", + "symfony/yaml": "^4.4|^5.0" }, "type": "symfony-bundle", "autoload": { @@ -6939,7 +6868,7 @@ "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v4.4.20" + "source": "https://github.com/symfony/twig-bundle/tree/v5.2.4" }, "funding": [ { @@ -6955,37 +6884,36 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-01-27T10:15:41+00:00" }, { "name": "symfony/var-dumper", - "version": "v4.4.21", + "version": "v5.2.6", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "0da0e174f728996f5d5072d6a9f0a42259dbc806" + "reference": "89412a68ea2e675b4e44f260a5666729f77f668e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/0da0e174f728996f5d5072d6a9f0a42259dbc806", - "reference": "0da0e174f728996f5d5072d6a9f0a42259dbc806", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/89412a68ea2e675b4e44f260a5666729f77f668e", + "reference": "89412a68ea2e675b4e44f260a5666729f77f668e", "shasum": "" }, "require": { - "php": ">=7.1.3", + "php": ">=7.2.5", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php72": "~1.5", "symfony/polyfill-php80": "^1.15" }, "conflict": { - "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", - "symfony/console": "<3.4" + "phpunit/phpunit": "<5.4.3", + "symfony/console": "<4.4" }, "require-dev": { "ext-iconv": "*", - "symfony/console": "^3.4|^4.0|^5.0", + "symfony/console": "^4.4|^5.0", "symfony/process": "^4.4|^5.0", - "twig/twig": "^1.43|^2.13|^3.0.4" + "twig/twig": "^2.13|^3.0.4" }, "suggest": { "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", @@ -7028,7 +6956,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v4.4.21" + "source": "https://github.com/symfony/var-dumper/tree/v5.2.6" }, "funding": [ { @@ -7044,24 +6972,25 @@ "type": "tidelift" } ], - "time": "2021-03-27T19:49:03+00:00" + "time": "2021-03-28T09:42:18+00:00" }, { "name": "symfony/var-exporter", - "version": "v4.4.20", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "3a3ea598bba6901d20b58c2579f68700089244ed" + "reference": "5aed4875ab514c8cb9b6ff4772baa25fa4c10307" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/3a3ea598bba6901d20b58c2579f68700089244ed", - "reference": "3a3ea598bba6901d20b58c2579f68700089244ed", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/5aed4875ab514c8cb9b6ff4772baa25fa4c10307", + "reference": "5aed4875ab514c8cb9b6ff4772baa25fa4c10307", "shasum": "" }, "require": { - "php": ">=7.1.3" + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.15" }, "require-dev": { "symfony/var-dumper": "^4.4.9|^5.0.9" @@ -7100,7 +7029,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v4.4.20" + "source": "https://github.com/symfony/var-exporter/tree/v5.2.4" }, "funding": [ { @@ -7116,41 +7045,41 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-01-27T10:01:46+00:00" }, { "name": "symfony/web-profiler-bundle", - "version": "v4.4.21", + "version": "v5.2.6", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "bd848a0c0f3e7229e329adeea10e8945f70cb4c9" + "reference": "58e5be2aa69041ff35250537190d9ec29136782a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/bd848a0c0f3e7229e329adeea10e8945f70cb4c9", - "reference": "bd848a0c0f3e7229e329adeea10e8945f70cb4c9", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/58e5be2aa69041ff35250537190d9ec29136782a", + "reference": "58e5be2aa69041ff35250537190d9ec29136782a", "shasum": "" }, "require": { - "php": ">=7.1.3", - "symfony/config": "^4.2|^5.0", - "symfony/framework-bundle": "^4.4|^5.0", - "symfony/http-kernel": "^4.4", - "symfony/routing": "^4.3|^5.0", - "symfony/twig-bundle": "^4.2|^5.0", - "twig/twig": "^1.43|^2.13|^3.0.4" + "php": ">=7.2.5", + "symfony/config": "^4.4|^5.0", + "symfony/framework-bundle": "^5.1", + "symfony/http-kernel": "^5.2", + "symfony/routing": "^4.4|^5.0", + "symfony/twig-bundle": "^4.4|^5.0", + "twig/twig": "^2.13|^3.0.4" }, "conflict": { - "symfony/form": "<4.3", - "symfony/messenger": "<4.2" + "symfony/dependency-injection": "<5.2", + "symfony/form": "<4.4", + "symfony/messenger": "<4.4" }, "require-dev": { - "symfony/browser-kit": "^4.3|^5.0", - "symfony/console": "^4.3|^5.0", - "symfony/css-selector": "^3.4|^4.0|^5.0", - "symfony/dependency-injection": "^3.4|^4.0|^5.0", - "symfony/stopwatch": "^3.4|^4.0|^5.0" + "symfony/browser-kit": "^4.4|^5.0", + "symfony/console": "^4.4|^5.0", + "symfony/css-selector": "^4.4|^5.0", + "symfony/stopwatch": "^4.4|^5.0" }, "type": "symfony-bundle", "autoload": { @@ -7178,7 +7107,7 @@ "description": "Provides a development tool that gives detailed information about the execution of any request", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v4.4.21" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v5.2.6" }, "funding": [ { @@ -7194,35 +7123,39 @@ "type": "tidelift" } ], - "time": "2021-03-15T15:12:10+00:00" + "time": "2021-03-16T09:10:13+00:00" }, { "name": "symfony/yaml", - "version": "v4.4.21", + "version": "v5.2.5", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "3871c720871029f008928244e56cf43497da7e9d" + "reference": "298a08ddda623485208506fcee08817807a251dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/3871c720871029f008928244e56cf43497da7e9d", - "reference": "3871c720871029f008928244e56cf43497da7e9d", + "url": "https://api.github.com/repos/symfony/yaml/zipball/298a08ddda623485208506fcee08817807a251dd", + "reference": "298a08ddda623485208506fcee08817807a251dd", "shasum": "" }, "require": { - "php": ">=7.1.3", + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/console": "<3.4" + "symfony/console": "<4.4" }, "require-dev": { - "symfony/console": "^3.4|^4.0|^5.0" + "symfony/console": "^4.4|^5.0" }, "suggest": { "symfony/console": "For validating YAML files using the lint command" }, + "bin": [ + "Resources/bin/yaml-lint" + ], "type": "library", "autoload": { "psr-4": { @@ -7249,7 +7182,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v4.4.21" + "source": "https://github.com/symfony/yaml/tree/v5.2.5" }, "funding": [ { @@ -7265,61 +7198,7 @@ "type": "tidelift" } ], - "time": "2021-03-05T17:58:50+00:00" - }, - { - "name": "tightenco/collect", - "version": "v5.8.38", - "source": { - "type": "git", - "url": "https://github.com/tighten/collect.git", - "reference": "c93a7039e6207ad533a09109838fe80933fcc72c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/tighten/collect/zipball/c93a7039e6207ad533a09109838fe80933fcc72c", - "reference": "c93a7039e6207ad533a09109838fe80933fcc72c", - "shasum": "" - }, - "require": { - "php": "^7.1.3", - "symfony/var-dumper": ">=3.4 <5" - }, - "require-dev": { - "mockery/mockery": "^1.0", - "nesbot/carbon": "^1.26.3", - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "autoload": { - "files": [ - "src/Collect/Support/helpers.php", - "src/Collect/Support/alias.php" - ], - "psr-4": { - "Tightenco\\Collect\\": "src/Collect" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylorotwell@gmail.com" - } - ], - "description": "Collect - Illuminate Collections as a separate package.", - "keywords": [ - "collection", - "laravel" - ], - "support": { - "issues": "https://github.com/tighten/collect/issues", - "source": "https://github.com/tighten/collect/tree/v5.8.38" - }, - "time": "2019-09-17T18:57:01+00:00" + "time": "2021-03-06T07:59:01+00:00" }, { "name": "twig/twig", diff --git a/api/config/bundles.php b/api/config/bundles.php index 3e39222..de8a66b 100644 --- a/api/config/bundles.php +++ b/api/config/bundles.php @@ -4,7 +4,6 @@ return [ Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true], Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], - Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle::class => ['all' => true], Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], diff --git a/api/src/Controller/Api/v1/StopsController.php b/api/src/Controller/Api/v1/StopsController.php index 2b83043..c78190d 100644 --- a/api/src/Controller/Api/v1/StopsController.php +++ b/api/src/Controller/Api/v1/StopsController.php @@ -12,11 +12,11 @@ use App\Modifier\RelatedFilter; use App\Modifier\With; use App\Provider\StopRepository; use App\Provider\TrackRepository; +use Illuminate\Support\Collection; use Nelmio\ApiDocBundle\Annotation\Model; use Swagger\Annotations as SWG; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; -use Tightenco\Collect\Support\Collection; /** * Class StopsController diff --git a/api/src/Handler/Database/WithDestinationsDatabaseHandler.php b/api/src/Handler/Database/WithDestinationsDatabaseHandler.php index eeb1dfb..8c1df7c 100644 --- a/api/src/Handler/Database/WithDestinationsDatabaseHandler.php +++ b/api/src/Handler/Database/WithDestinationsDatabaseHandler.php @@ -11,9 +11,9 @@ use App\Service\CacheableConverter; use App\Service\Converter; use App\Service\IdUtils; use Doctrine\ORM\EntityManagerInterface; +use Illuminate\Support\Collection; use Kadet\Functional as f; use Kadet\Functional\Transforms as t; -use Tightenco\Collect\Support\Collection; class WithDestinationsDatabaseHandler implements PostProcessingHandler { diff --git a/api/src/Model/Destination.php b/api/src/Model/Destination.php index 45d22c1..889c7e1 100644 --- a/api/src/Model/Destination.php +++ b/api/src/Model/Destination.php @@ -2,10 +2,10 @@ namespace App\Model; +use Illuminate\Support\Collection; use JMS\Serializer\Annotation as Serializer; use Nelmio\ApiDocBundle\Annotation\Model; use Swagger\Annotations as SWG; -use Tightenco\Collect\Support\Collection; class Destination implements Fillable { diff --git a/api/src/Model/Line.php b/api/src/Model/Line.php index f905b7d..2661f1e 100644 --- a/api/src/Model/Line.php +++ b/api/src/Model/Line.php @@ -2,10 +2,10 @@ namespace App\Model; +use Illuminate\Support\Collection; use JMS\Serializer\Annotation as Serializer; use Nelmio\ApiDocBundle\Annotation\Model; use Swagger\Annotations as SWG; -use Tightenco\Collect\Support\Collection; class Line implements Fillable, Referable { diff --git a/api/src/Model/Stop.php b/api/src/Model/Stop.php index 0d294db..bac6e78 100644 --- a/api/src/Model/Stop.php +++ b/api/src/Model/Stop.php @@ -2,10 +2,10 @@ namespace App\Model; +use Illuminate\Support\Collection; use JMS\Serializer\Annotation as Serializer; use Nelmio\ApiDocBundle\Annotation\Model; use Swagger\Annotations as SWG; -use Tightenco\Collect\Support\Collection; /** * Class Stop diff --git a/api/src/Model/StopGroup.php b/api/src/Model/StopGroup.php index a2ef876..6ed17ff 100644 --- a/api/src/Model/StopGroup.php +++ b/api/src/Model/StopGroup.php @@ -2,11 +2,10 @@ namespace App\Model; +use Illuminate\Support\Collection; use JMS\Serializer\Annotation as Serializer; use Nelmio\ApiDocBundle\Annotation\Model; use Swagger\Annotations as SWG; -use Tightenco\Collect\Support\Collection; -use App\Model\Stop; /** * Class StopGroup diff --git a/api/src/Model/Track.php b/api/src/Model/Track.php index acb26f0..bcbed78 100644 --- a/api/src/Model/Track.php +++ b/api/src/Model/Track.php @@ -2,10 +2,10 @@ namespace App\Model; +use Illuminate\Support\Collection; use JMS\Serializer\Annotation as Serializer; use Nelmio\ApiDocBundle\Annotation\Model; use Swagger\Annotations as SWG; -use Tightenco\Collect\Support\Collection; class Track implements Referable, Fillable { diff --git a/api/src/Model/Trip.php b/api/src/Model/Trip.php index f9da46f..cd160eb 100644 --- a/api/src/Model/Trip.php +++ b/api/src/Model/Trip.php @@ -3,8 +3,8 @@ namespace App\Model; use App\Serialization\SerializeAs; +use Illuminate\Support\Collection; use JMS\Serializer\Annotation as Serializer; -use Tightenco\Collect\Support\Collection; class Trip implements Referable, Fillable { diff --git a/api/src/Provider/Database/GenericLineRepository.php b/api/src/Provider/Database/GenericLineRepository.php index 9ca147d..31dd9e0 100644 --- a/api/src/Provider/Database/GenericLineRepository.php +++ b/api/src/Provider/Database/GenericLineRepository.php @@ -3,17 +3,10 @@ namespace App\Provider\Database; use App\Entity\LineEntity; -use App\Event\HandleDatabaseModifierEvent; -use App\Handler\Database\LimitDatabaseHandler; -use App\Handler\Database\IdFilterDatabaseHandler; -use App\Handler\ModifierHandler; use App\Model\Line; -use App\Modifier\Limit; -use App\Modifier\IdFilter; -use App\Provider\LineRepository; use App\Modifier\Modifier; -use Tightenco\Collect\Support\Collection; -use Kadet\Functional as f; +use App\Provider\LineRepository; +use Illuminate\Support\Collection; class GenericLineRepository extends DatabaseRepository implements LineRepository { diff --git a/api/src/Provider/Database/GenericOperatorRepository.php b/api/src/Provider/Database/GenericOperatorRepository.php index 2af85f7..a3aafa7 100644 --- a/api/src/Provider/Database/GenericOperatorRepository.php +++ b/api/src/Provider/Database/GenericOperatorRepository.php @@ -6,7 +6,7 @@ use App\Entity\OperatorEntity; use App\Model\Operator; use App\Modifier\Modifier; use App\Provider\OperatorRepository; -use Tightenco\Collect\Support\Collection; +use Illuminate\Support\Collection; class GenericOperatorRepository extends DatabaseRepository implements OperatorRepository { diff --git a/api/src/Provider/Database/GenericScheduleRepository.php b/api/src/Provider/Database/GenericScheduleRepository.php index 10c4bdd..b3b5165 100644 --- a/api/src/Provider/Database/GenericScheduleRepository.php +++ b/api/src/Provider/Database/GenericScheduleRepository.php @@ -3,20 +3,15 @@ namespace App\Provider\Database; use App\Entity\StopEntity; -use App\Entity\TrackStopEntity; use App\Entity\TrackEntity; -use App\Entity\TripEntity; use App\Entity\TripStopEntity; use App\Model\Departure; -use App\Model\Line; use App\Model\ScheduledStop; use App\Model\Stop; -use App\Model\Vehicle; use App\Modifier\Modifier; use App\Provider\ScheduleRepository; use Carbon\Carbon; -use Tightenco\Collect\Support\Collection; -use function Kadet\Functional\ref; +use Illuminate\Support\Collection; class GenericScheduleRepository extends DatabaseRepository implements ScheduleRepository { diff --git a/api/src/Provider/Database/GenericStopRepository.php b/api/src/Provider/Database/GenericStopRepository.php index 7610402..e609a6f 100644 --- a/api/src/Provider/Database/GenericStopRepository.php +++ b/api/src/Provider/Database/GenericStopRepository.php @@ -9,7 +9,7 @@ use App\Model\Stop; use App\Modifier\Modifier; use App\Modifier\With; use App\Provider\StopRepository; -use Tightenco\Collect\Support\Collection; +use Illuminate\Support\Collection; class GenericStopRepository extends DatabaseRepository implements StopRepository { diff --git a/api/src/Provider/Database/GenericTrackRepository.php b/api/src/Provider/Database/GenericTrackRepository.php index f25d7f2..c877b75 100644 --- a/api/src/Provider/Database/GenericTrackRepository.php +++ b/api/src/Provider/Database/GenericTrackRepository.php @@ -2,13 +2,13 @@ namespace App\Provider\Database; -use App\Entity\TrackStopEntity; use App\Entity\TrackEntity; +use App\Entity\TrackStopEntity; +use App\Model\Track; use App\Model\TrackStop; use App\Modifier\Modifier; -use App\Model\Track; use App\Provider\TrackRepository; -use Tightenco\Collect\Support\Collection; +use Illuminate\Support\Collection; class GenericTrackRepository extends DatabaseRepository implements TrackRepository { diff --git a/api/src/Provider/Database/GenericTripRepository.php b/api/src/Provider/Database/GenericTripRepository.php index 2a10b33..1117329 100644 --- a/api/src/Provider/Database/GenericTripRepository.php +++ b/api/src/Provider/Database/GenericTripRepository.php @@ -6,7 +6,7 @@ use App\Entity\TripEntity; use App\Model\Trip; use App\Modifier\Modifier; use App\Provider\TripRepository; -use Tightenco\Collect\Support\Collection; +use Illuminate\Support\Collection; class GenericTripRepository extends DatabaseRepository implements TripRepository { diff --git a/api/src/Provider/DepartureRepository.php b/api/src/Provider/DepartureRepository.php index a6ea1f4..89d66ef 100644 --- a/api/src/Provider/DepartureRepository.php +++ b/api/src/Provider/DepartureRepository.php @@ -4,9 +4,7 @@ namespace App\Provider; -use App\Model\Stop; use App\Modifier\Modifier; -use Tightenco\Collect\Support\Collection; interface DepartureRepository extends Repository { diff --git a/api/src/Provider/Dummy/DummyDepartureRepository.php b/api/src/Provider/Dummy/DummyDepartureRepository.php index d265ce6..fd6ebc0 100644 --- a/api/src/Provider/Dummy/DummyDepartureRepository.php +++ b/api/src/Provider/Dummy/DummyDepartureRepository.php @@ -4,13 +4,11 @@ namespace App\Provider\Dummy; use App\Model\Departure; use App\Model\Line; -use App\Model\Stop; use App\Model\Vehicle; use App\Modifier\Modifier; use App\Provider\DepartureRepository; use App\Service\Proxy\ReferenceFactory; use Carbon\Carbon; -use Tightenco\Collect\Support\Collection; class DummyDepartureRepository implements DepartureRepository { diff --git a/api/src/Provider/Dummy/DummyMessageRepository.php b/api/src/Provider/Dummy/DummyMessageRepository.php index 86ee2f0..8a0d0a7 100644 --- a/api/src/Provider/Dummy/DummyMessageRepository.php +++ b/api/src/Provider/Dummy/DummyMessageRepository.php @@ -6,7 +6,7 @@ use App\Model\Message; use App\Model\Stop; use App\Provider\MessageRepository; use Carbon\Carbon; -use Tightenco\Collect\Support\Collection; +use Illuminate\Support\Collection; class DummyMessageRepository implements MessageRepository { @@ -30,4 +30,4 @@ class DummyMessageRepository implements MessageRepository { return $this->getAll(); } -} \ No newline at end of file +} diff --git a/api/src/Provider/Dummy/DummyStopRepository.php b/api/src/Provider/Dummy/DummyStopRepository.php index 959d5bd..04cec66 100644 --- a/api/src/Provider/Dummy/DummyStopRepository.php +++ b/api/src/Provider/Dummy/DummyStopRepository.php @@ -6,7 +6,7 @@ use App\Model\Stop; use App\Modifier\Modifier; use App\Provider\StopRepository; use App\Service\Proxy\ReferenceFactory; -use Tightenco\Collect\Support\Collection; +use Illuminate\Support\Collection; use Kadet\Functional as f; class DummyStopRepository implements StopRepository diff --git a/api/src/Provider/FluentRepository.php b/api/src/Provider/FluentRepository.php index a02831c..dad83ea 100644 --- a/api/src/Provider/FluentRepository.php +++ b/api/src/Provider/FluentRepository.php @@ -3,7 +3,7 @@ namespace App\Provider; use App\Modifier\Modifier; -use Tightenco\Collect\Support\Collection; +use Illuminate\Support\Collection; interface FluentRepository extends Repository { diff --git a/api/src/Provider/MessageRepository.php b/api/src/Provider/MessageRepository.php index dd8fbba..2c8239b 100644 --- a/api/src/Provider/MessageRepository.php +++ b/api/src/Provider/MessageRepository.php @@ -5,10 +5,10 @@ namespace App\Provider; use App\Model\Stop; -use Tightenco\Collect\Support\Collection; +use Illuminate\Support\Collection; interface MessageRepository { public function getAll(): Collection; public function getForStop(Stop $stop): Collection; -} \ No newline at end of file +} diff --git a/api/src/Provider/OperatorRepository.php b/api/src/Provider/OperatorRepository.php index 70d88c7..bd6b21f 100644 --- a/api/src/Provider/OperatorRepository.php +++ b/api/src/Provider/OperatorRepository.php @@ -4,9 +4,6 @@ namespace App\Provider; -use App\Model\Operator; -use Tightenco\Collect\Support\Collection; - interface OperatorRepository extends FluentRepository { } diff --git a/api/src/Provider/ScheduleRepository.php b/api/src/Provider/ScheduleRepository.php index e650d22..ba5376e 100644 --- a/api/src/Provider/ScheduleRepository.php +++ b/api/src/Provider/ScheduleRepository.php @@ -4,7 +4,7 @@ namespace App\Provider; use App\Model\Stop; use Carbon\Carbon; -use Tightenco\Collect\Support\Collection; +use Illuminate\Support\Collection; interface ScheduleRepository extends FluentRepository { diff --git a/api/src/Provider/StopRepository.php b/api/src/Provider/StopRepository.php index bf6aa3f..0c8e5e5 100644 --- a/api/src/Provider/StopRepository.php +++ b/api/src/Provider/StopRepository.php @@ -4,9 +4,6 @@ namespace App\Provider; -use App\Model\Stop; -use Tightenco\Collect\Support\Collection; - interface StopRepository extends FluentRepository { } diff --git a/api/src/Provider/TrackRepository.php b/api/src/Provider/TrackRepository.php index 2b66a36..dbf4ac7 100644 --- a/api/src/Provider/TrackRepository.php +++ b/api/src/Provider/TrackRepository.php @@ -2,9 +2,8 @@ namespace App\Provider; -use App\Model\Track; use App\Modifier\Modifier; -use Tightenco\Collect\Support\Collection; +use Illuminate\Support\Collection; interface TrackRepository extends FluentRepository { diff --git a/api/src/Provider/ZtmGdansk/ZtmGdanskDataUpdateSubscriber.php b/api/src/Provider/ZtmGdansk/ZtmGdanskDataUpdateSubscriber.php index 38bf725..fbf0129 100644 --- a/api/src/Provider/ZtmGdansk/ZtmGdanskDataUpdateSubscriber.php +++ b/api/src/Provider/ZtmGdansk/ZtmGdanskDataUpdateSubscriber.php @@ -6,8 +6,8 @@ use App\Entity\LineEntity; use App\Entity\OperatorEntity; use App\Entity\ProviderEntity; use App\Entity\StopEntity; -use App\Entity\TrackStopEntity; use App\Entity\TrackEntity; +use App\Entity\TrackStopEntity; use App\Entity\TripEntity; use App\Entity\TripStopEntity; use App\Event\DataUpdateEvent; @@ -17,10 +17,10 @@ use App\Service\IdUtils; use Carbon\Carbon; use Cerbero\JsonObjects\JsonObjects; use Doctrine\ORM\EntityManagerInterface; -use Symfony\Component\Console\Helper\ProgressBar; +use Illuminate\Support\Collection; use Psr\Log\LoggerInterface; +use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Tightenco\Collect\Support\Collection; use function Kadet\Functional\ref; use function Kadet\Functional\Transforms\property; diff --git a/api/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php b/api/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php index 8e8dbc4..a7a8fcd 100644 --- a/api/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php +++ b/api/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php @@ -13,7 +13,6 @@ use App\Modifier\Limit; use App\Modifier\Modifier; use App\Modifier\RelatedFilter; use App\Modifier\With; -use App\Provider\Database\GenericScheduleRepository; use App\Provider\DepartureRepository; use App\Provider\LineRepository; use App\Provider\ScheduleRepository; @@ -21,8 +20,7 @@ use App\Service\IterableUtils; use App\Service\ModifierUtils; use App\Service\Proxy\ReferenceFactory; use Carbon\Carbon; -use JMS\Serializer\Tests\Fixtures\Discriminator\Car; -use Tightenco\Collect\Support\Collection; +use Illuminate\Support\Collection; use Kadet\Functional\Transforms as t; use function App\Functions\setup; use function Kadet\Functional\ref; diff --git a/api/src/Provider/ZtmGdansk/ZtmGdanskMessageRepository.php b/api/src/Provider/ZtmGdansk/ZtmGdanskMessageRepository.php index d87b5f7..b79f2d8 100644 --- a/api/src/Provider/ZtmGdansk/ZtmGdanskMessageRepository.php +++ b/api/src/Provider/ZtmGdansk/ZtmGdanskMessageRepository.php @@ -7,11 +7,9 @@ namespace App\Provider\ZtmGdansk; use App\Model\Message; use App\Model\Stop; use App\Provider\MessageRepository; -use App\Provider\ZtmGdansk\ZtmGdanskProvider; -use App\Service\IdUtils; use Carbon\Carbon; +use Illuminate\Support\Collection; use Symfony\Component\Cache\Adapter\AdapterInterface; -use Tightenco\Collect\Support\Collection; class ZtmGdanskMessageRepository implements MessageRepository { @@ -69,4 +67,4 @@ class ZtmGdanskMessageRepository implements MessageRepository return $item->get(); } -} \ No newline at end of file +} diff --git a/api/src/Serialization/CarbonHandler.php b/api/src/Serialization/CarbonHandler.php index 84c48dd..1f47f75 100644 --- a/api/src/Serialization/CarbonHandler.php +++ b/api/src/Serialization/CarbonHandler.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace App\Serialization; use Carbon\Carbon; +use Illuminate\Support\Collection; use JMS\Serializer\DeserializationContext; use JMS\Serializer\GraphNavigatorInterface; use JMS\Serializer\Handler\DateHandler; @@ -12,7 +13,6 @@ use JMS\Serializer\Handler\SubscribingHandlerInterface; use JMS\Serializer\SerializationContext; use JMS\Serializer\Visitor\DeserializationVisitorInterface; use JMS\Serializer\Visitor\SerializationVisitorInterface; -use Tightenco\Collect\Support\Collection; /** * Class LaravelCollectionHandler diff --git a/api/src/Serialization/LaravelCollectionHandler.php b/api/src/Serialization/LaravelCollectionHandler.php index dd97dd6..2cc2ff9 100644 --- a/api/src/Serialization/LaravelCollectionHandler.php +++ b/api/src/Serialization/LaravelCollectionHandler.php @@ -4,13 +4,13 @@ declare(strict_types=1); namespace App\Serialization; +use Illuminate\Support\Collection; use JMS\Serializer\DeserializationContext; use JMS\Serializer\GraphNavigatorInterface; use JMS\Serializer\Handler\SubscribingHandlerInterface; use JMS\Serializer\SerializationContext; use JMS\Serializer\Visitor\DeserializationVisitorInterface; use JMS\Serializer\Visitor\SerializationVisitorInterface; -use Tightenco\Collect\Support\Collection; /** * Class LaravelCollectionHandler @@ -84,4 +84,4 @@ final class LaravelCollectionHandler implements SubscribingHandlerInterface return new Collection($visitor->visitArray($data, $type)); } -} \ No newline at end of file +} diff --git a/api/src/Service/AggregateConverter.php b/api/src/Service/AggregateConverter.php index 1b22c84..6957415 100644 --- a/api/src/Service/AggregateConverter.php +++ b/api/src/Service/AggregateConverter.php @@ -2,7 +2,7 @@ namespace App\Service; -use Tightenco\Collect\Support\Collection; +use Illuminate\Support\Collection; use function Kadet\Functional\Predicates\instance; class AggregateConverter implements Converter, CacheableConverter diff --git a/api/src/Service/EntityReferenceFactory.php b/api/src/Service/EntityReferenceFactory.php index 6a5d5fd..6a3f072 100644 --- a/api/src/Service/EntityReferenceFactory.php +++ b/api/src/Service/EntityReferenceFactory.php @@ -12,7 +12,7 @@ use App\Model\Referable; use App\Model\Stop; use App\Model\Track; use Doctrine\ORM\EntityManagerInterface; -use Tightenco\Collect\Support\Collection; +use Illuminate\Support\Collection; use function Kadet\Functional\partial; use function Kadet\Functional\ref; use const Kadet\Functional\_; diff --git a/api/src/Service/IterableUtils.php b/api/src/Service/IterableUtils.php index 5018060..883cf62 100644 --- a/api/src/Service/IterableUtils.php +++ b/api/src/Service/IterableUtils.php @@ -3,7 +3,7 @@ namespace App\Service; use Doctrine\Common\Collections\ArrayCollection; -use Tightenco\Collect\Support\Collection; +use Illuminate\Support\Collection; final class IterableUtils { diff --git a/api/src/Service/ProviderResolver.php b/api/src/Service/ProviderResolver.php index 29a0193..a23e2b8 100644 --- a/api/src/Service/ProviderResolver.php +++ b/api/src/Service/ProviderResolver.php @@ -6,9 +6,9 @@ namespace App\Service; use App\Exception\NonExistentServiceException; use App\Provider\Dummy\DummyProvider; use App\Provider\Provider; +use Illuminate\Support\Collection; use Kadet\Functional\Predicates as p; use Kadet\Functional\Transforms as t; -use Tightenco\Collect\Support\Collection; class ProviderResolver { diff --git a/api/symfony.lock b/api/symfony.lock index ddc7fe1..97ab9dc 100644 --- a/api/symfony.lock +++ b/api/symfony.lock @@ -59,9 +59,6 @@ "src/Repository/.gitignore" ] }, - "doctrine/doctrine-cache-bundle": { - "version": "1.3.3" - }, "doctrine/doctrine-migrations-bundle": { "version": "2.2", "recipe": { @@ -96,9 +93,6 @@ "doctrine/persistence": { "version": "v1.0.0" }, - "doctrine/reflection": { - "version": "v1.0.0" - }, "doctrine/sql-formatter": { "version": "1.1.1" }, @@ -144,6 +138,15 @@ "hoa/zformat": { "version": "1.17.01.10" }, + "illuminate/collections": { + "version": "v8.35.1" + }, + "illuminate/contracts": { + "version": "v8.35.1" + }, + "illuminate/macroable": { + "version": "v8.35.1" + }, "jdorn/sql-formatter": { "version": "v1.2.17" }, @@ -173,9 +176,6 @@ "kadet/functional": { "version": "dev-master" }, - "kylekatarnls/update-helper": { - "version": "1.2.0" - }, "laminas/laminas-diactoros": { "version": "2.5.0" }, @@ -227,6 +227,9 @@ "psr/container": { "version": "1.0.0" }, + "psr/event-dispatcher": { + "version": "1.0.0" + }, "psr/http-factory": { "version": "1.0.1" }, @@ -284,12 +287,12 @@ "ref": "e3868d2f4a5104f19f844fe551099a00c6562527" } }, - "symfony/debug": { - "version": "v4.1.3" - }, "symfony/dependency-injection": { "version": "v4.1.3" }, + "symfony/deprecation-contracts": { + "version": "v2.2.0" + }, "symfony/doctrine-bridge": { "version": "v4.1.4" }, @@ -353,12 +356,6 @@ "symfony/http-kernel": { "version": "v4.1.3" }, - "symfony/inflector": { - "version": "v4.1.3" - }, - "symfony/mime": { - "version": "v5.0.2" - }, "symfony/monolog-bridge": { "version": "v4.1.4" }, @@ -377,8 +374,8 @@ "symfony/orm-pack": { "version": "v1.0.5" }, - "symfony/polyfill-intl-idn": { - "version": "v1.13.1" + "symfony/polyfill-intl-grapheme": { + "version": "v1.22.1" }, "symfony/polyfill-intl-normalizer": { "version": "v1.20.0" @@ -386,9 +383,6 @@ "symfony/polyfill-mbstring": { "version": "v1.9.0" }, - "symfony/polyfill-php72": { - "version": "v1.20.0" - }, "symfony/polyfill-php73": { "version": "v1.13.1" }, @@ -428,6 +422,9 @@ "symfony/stopwatch": { "version": "v4.1.12" }, + "symfony/string": { + "version": "v5.2.6" + }, "symfony/translation": { "version": "3.3", "recipe": { @@ -480,9 +477,6 @@ "symfony/yaml": { "version": "v4.1.3" }, - "tightenco/collect": { - "version": "v5.6.33" - }, "twig/twig": { "version": "v2.5.0" }, -- 2.45.2 From 86ccaad923156d22f6ac96849f568a66fe92521e Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Thu, 8 Apr 2021 20:53:38 +0200 Subject: [PATCH 67/77] #50 - Fix spacing issues --- front/src/components/ui/dialog.ts | 4 ++++ front/templates/main.html | 8 ++++---- front/templates/picker/stop.html | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/front/src/components/ui/dialog.ts b/front/src/components/ui/dialog.ts index 365102d..f15f135 100644 --- a/front/src/components/ui/dialog.ts +++ b/front/src/components/ui/dialog.ts @@ -100,6 +100,10 @@ export default class UiDialog extends Vue { const isInWrapper = this.$parent.$options.name == 'portalTarget'; if (typeof this.reference === 'string') { + if (this.reference[0] === '#') { + return document.getElementById(this.reference.substr(1)); + } + if (this.refs) { return this.refs[this.reference]; } diff --git a/front/templates/main.html b/front/templates/main.html index 141a79c..ae6af29 100644 --- a/front/templates/main.html +++ b/front/templates/main.html @@ -7,7 +7,7 @@ <ui-icon icon="messages" fixed-width class="mr-2"></ui-icon> Komunikaty <span class="ml-2 badge badge-pill badge-dark">{{ messages.count }}</span> </h2> - <button class="btn btn-action flex-space-left" ref="settings-messages" + <button class="btn btn-action flex-space-left" ref="settings-messages" id="settings-messages" @click="visibility.messages = !visibility.messages"> <tooltip>ustawienia</tooltip> <ui-icon icon="settings" fixed-width></ui-icon> @@ -25,7 +25,7 @@ </button> <portal to="popups"> - <ui-dialog reference="settings-messages" v-if="visibility.messages" arrow placement="left-start" + <ui-dialog reference="#settings-messages" v-if="visibility.messages" arrow placement="left-start" @leave="visibility.messages = false"> <settings-messages></settings-messages> </ui-dialog> @@ -42,7 +42,7 @@ <span class="text">Odjazdy</span> </h2> - <button class="btn btn-action flex-space-left" ref="settings-departures" + <button class="btn btn-action flex-space-left" ref="settings-departures" id="settings-departures" @click="visibility.departures = !visibility.departures"> <tooltip>ustawienia</tooltip> <ui-icon icon="settings" fixed-width></ui-icon> @@ -52,7 +52,7 @@ <ui-icon icon="refresh" :spin="departures.state === 'fetching'" fixed-width></ui-icon> </button> <portal to="popups"> - <ui-dialog reference="settings-departures" v-if="visibility.departures" + <ui-dialog reference="#settings-departures" v-if="visibility.departures" @leave="visibility.departures = false" arrow placement="left-start"> <settings-departures></settings-departures> </ui-dialog> diff --git a/front/templates/picker/stop.html b/front/templates/picker/stop.html index 626dc17..21d1f2d 100644 --- a/front/templates/picker/stop.html +++ b/front/templates/picker/stop.html @@ -1,6 +1,6 @@ <div> <div class="d-flex"> - <div class="d-flex position-relative" style="min-width: 0"> + <div class="d-flex position-relative" style="min-width: 0; flex: 1 1 auto;"> <slot name="primary-action" /> <div class="overflow-hidden align-self-center"> <stop :stop="stop" /> -- 2.45.2 From 6e9bafd04374286f00f237258024f7e71ea3d719 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Fri, 9 Apr 2021 18:36:23 +0200 Subject: [PATCH 68/77] #50 - Ability to run update on separate worker process --- api/.env | 4 + api/bin/docker-entrypoint.sh | 3 + api/composer.json | 17 +- api/composer.lock | 486 +++++++++++++++++- api/config/bundles.php | 1 + api/config/packages/messenger.yaml | 13 + api/dev.Dockerfile | 1 - api/src/Command/UpdateCommand.php | 34 +- api/src/Message/UpdateDataMessage.php | 7 + .../UpdateDataMessageHandler.php | 34 ++ api/src/Output/LoggerOutput.php | 30 ++ api/src/Service/DataUpdater.php | 19 +- api/symfony.lock | 33 ++ 13 files changed, 638 insertions(+), 44 deletions(-) create mode 100644 api/bin/docker-entrypoint.sh create mode 100644 api/config/packages/messenger.yaml create mode 100644 api/src/Message/UpdateDataMessage.php create mode 100644 api/src/MessageHandler/UpdateDataMessageHandler.php create mode 100644 api/src/Output/LoggerOutput.php diff --git a/api/.env b/api/.env index 8e84d99..c2d60f7 100644 --- a/api/.env +++ b/api/.env @@ -16,3 +16,7 @@ APP_SECRET=494a9d1f8cc383f16075f4d5e54ae1a2 DATABASE_URL="sqlite:///%kernel.project_dir%/var/app.db" # DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=5.7" ###< doctrine/doctrine-bundle ### + +###> symfony/messenger ### +MESSENGER_TRANSPORT_DSN="doctrine://default" +###< symfony/messenger ### diff --git a/api/bin/docker-entrypoint.sh b/api/bin/docker-entrypoint.sh new file mode 100644 index 0000000..214eb4c --- /dev/null +++ b/api/bin/docker-entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +exec "$@" diff --git a/api/composer.json b/api/composer.json index 3ea61f5..18f4cc4 100644 --- a/api/composer.json +++ b/api/composer.json @@ -4,12 +4,13 @@ "type": "project", "license": "MIT with Commons Clause", "require": { - "php": "^7.1.3", + "php": "^7.4", "ext-ctype": "*", "ext-iconv": "*", "ext-json": "*", "baldinof/roadrunner-bundle": "^1.3", "cerbero/json-objects": "^1.1", + "illuminate/collections": "^8.35", "jms/serializer-bundle": "^3.5", "kadet/functional": "dev-master", "nelmio/api-doc-bundle": "^3.5", @@ -19,15 +20,18 @@ "spiral/roadrunner": "^1.8", "symfony/asset": "^5.2", "symfony/console": "^5.2", - "symfony/dotenv": "^5.2", + "symfony/doctrine-messenger": "5.2.*", "symfony/flex": "^1.1", "symfony/framework-bundle": "^5.2", + "symfony/messenger": "5.2.*", "symfony/monolog-bundle": "^3.3", "symfony/orm-pack": "^1.0", "symfony/profiler-pack": "^1.0", "symfony/twig-bundle": "^5.2", "symfony/yaml": "^5.2", - "illuminate/collections": "^8.35" + "symfony/dotenv": "5.2.*", + "symfony/amqp-messenger": "5.2.*", + "symfony/redis-messenger": "5.2.*" }, "config": { "preferred-install": { @@ -36,7 +40,7 @@ "sort-packages": true, "secure-http": false, "platform": { - "php": "7.3.12" + "php": "7.4.15" } }, "autoload": { @@ -86,5 +90,8 @@ "type": "vcs", "url": "https://git.kadet.net/kadet/functional-php.git" } - ] + ], + "require-dev": { + "symfony/maker-bundle": "^1.30" + } } diff --git a/api/composer.lock b/api/composer.lock index 8562678..a8bc93c 100644 --- a/api/composer.lock +++ b/api/composer.lock @@ -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": "4c087fa5970989805008ea426fdd2221", + "content-hash": "3703fdd98d8c7ed6539721bde9035bba", "packages": [ { "name": "baldinof/roadrunner-bundle", @@ -3693,6 +3693,75 @@ }, "time": "2021-01-14T16:04:43+00:00" }, + { + "name": "symfony/amqp-messenger", + "version": "v5.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/amqp-messenger.git", + "reference": "cf309a35ed08caa77886ee6a352b8491c7681424" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/amqp-messenger/zipball/cf309a35ed08caa77886ee6a352b8491c7681424", + "reference": "cf309a35ed08caa77886ee6a352b8491c7681424", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/messenger": "^5.1" + }, + "require-dev": { + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0", + "symfony/property-access": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Component\\Messenger\\Bridge\\Amqp\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony AMQP extension Messenger Bridge", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/amqp-messenger/tree/v5.2.4" + }, + "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": "2021-01-27T11:19:04+00:00" + }, { "name": "symfony/asset", "version": "v5.2.4", @@ -4380,30 +4449,38 @@ "time": "2021-03-10T22:10:15+00:00" }, { - "name": "symfony/dotenv", - "version": "v5.2.4", + "name": "symfony/doctrine-messenger", + "version": "v5.2.5", "source": { "type": "git", - "url": "https://github.com/symfony/dotenv.git", - "reference": "783f12027c6b40ab0e93d6136d9f642d1d67cd6b" + "url": "https://github.com/symfony/doctrine-messenger.git", + "reference": "10136ef0e31ca9839254bd909ef42421b61bc118" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/783f12027c6b40ab0e93d6136d9f642d1d67cd6b", - "reference": "783f12027c6b40ab0e93d6136d9f642d1d67cd6b", + "url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/10136ef0e31ca9839254bd909ef42421b61bc118", + "reference": "10136ef0e31ca9839254bd909ef42421b61bc118", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1" + "symfony/messenger": "^5.1", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "doctrine/dbal": "<2.10", + "doctrine/persistence": "<1.3" }, "require-dev": { - "symfony/process": "^4.4|^5.0" + "doctrine/dbal": "^2.10|^3.0", + "doctrine/persistence": "^1.3|^2", + "symfony/property-access": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" }, - "type": "library", + "type": "symfony-bridge", "autoload": { "psr-4": { - "Symfony\\Component\\Dotenv\\": "" + "Symfony\\Component\\Messenger\\Bridge\\Doctrine\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -4423,15 +4500,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Registers environment variables from a .env file", + "description": "Symfony Doctrine Messenger Bridge", "homepage": "https://symfony.com", - "keywords": [ - "dotenv", - "env", - "environment" - ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v5.2.4" + "source": "https://github.com/symfony/doctrine-messenger/tree/v5.2.5" }, "funding": [ { @@ -4447,7 +4519,7 @@ "type": "tidelift" } ], - "time": "2021-01-27T10:01:46+00:00" + "time": "2021-03-05T12:14:19+00:00" }, { "name": "symfony/error-handler", @@ -5286,6 +5358,94 @@ ], "time": "2021-03-29T05:16:58+00:00" }, + { + "name": "symfony/messenger", + "version": "v5.2.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/messenger.git", + "reference": "bc012fde3b96cfa3adf22f4d8a2e17860dc24a65" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/messenger/zipball/bc012fde3b96cfa3adf22f4d8a2e17860dc24a65", + "reference": "bc012fde3b96cfa3adf22f4d8a2e17860dc24a65", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/log": "~1.0", + "symfony/amqp-messenger": "^5.1", + "symfony/deprecation-contracts": "^2.1", + "symfony/doctrine-messenger": "^5.1", + "symfony/polyfill-php80": "^1.15", + "symfony/redis-messenger": "^5.1" + }, + "conflict": { + "symfony/event-dispatcher": "<4.4", + "symfony/framework-bundle": "<4.4", + "symfony/http-kernel": "<4.4" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/console": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/http-kernel": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0", + "symfony/property-access": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^4.4|^5.0", + "symfony/validator": "^4.4|^5.0" + }, + "suggest": { + "enqueue/messenger-adapter": "For using the php-enqueue library as a transport." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Messenger\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Samuel Roze", + "email": "samuel.roze@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps applications send and receive messages to/from other applications or via message queues", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/messenger/tree/v5.2.5" + }, + "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": "2021-03-06T07:59:01+00:00" + }, { "name": "symfony/monolog-bridge", "version": "v5.2.5", @@ -6194,6 +6354,73 @@ ], "time": "2021-02-17T10:35:25+00:00" }, + { + "name": "symfony/redis-messenger", + "version": "v5.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/redis-messenger.git", + "reference": "7e68914bf35cda948ee4d9081b8eaed9fd783fe5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/redis-messenger/zipball/7e68914bf35cda948ee4d9081b8eaed9fd783fe5", + "reference": "7e68914bf35cda948ee4d9081b8eaed9fd783fe5", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/messenger": "^5.1" + }, + "require-dev": { + "symfony/property-access": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Component\\Messenger\\Bridge\\Redis\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Redis extension Messenger Bridge", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/redis-messenger/tree/v5.2.4" + }, + "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": "2021-01-27T11:24:50+00:00" + }, { "name": "symfony/routing", "version": "v5.2.6", @@ -7525,7 +7752,222 @@ "time": "2020-11-29T21:40:13+00:00" } ], - "packages-dev": [], + "packages-dev": [ + { + "name": "nikic/php-parser", + "version": "v4.10.4", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c6d052fc58cb876152f89f532b95a8d7907e7f0e", + "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.4" + }, + "time": "2020-12-20T10:01:03+00:00" + }, + { + "name": "symfony/dotenv", + "version": "v5.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/dotenv.git", + "reference": "783f12027c6b40ab0e93d6136d9f642d1d67cd6b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/783f12027c6b40ab0e93d6136d9f642d1d67cd6b", + "reference": "783f12027c6b40ab0e93d6136d9f642d1d67cd6b", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1" + }, + "require-dev": { + "symfony/process": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Dotenv\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Registers environment variables from a .env file", + "homepage": "https://symfony.com", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "source": "https://github.com/symfony/dotenv/tree/v5.2.4" + }, + "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": "2021-01-27T10:01:46+00:00" + }, + { + "name": "symfony/maker-bundle", + "version": "v1.30.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/maker-bundle.git", + "reference": "a395a85aa4ded6c1fa3da118d60329b64b6c2acd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/a395a85aa4ded6c1fa3da118d60329b64b6c2acd", + "reference": "a395a85aa4ded6c1fa3da118d60329b64b6c2acd", + "shasum": "" + }, + "require": { + "doctrine/inflector": "^1.2|^2.0", + "nikic/php-parser": "^4.0", + "php": ">=7.1.3", + "symfony/config": "^4.0|^5.0", + "symfony/console": "^4.0|^5.0", + "symfony/dependency-injection": "^4.0|^5.0", + "symfony/deprecation-contracts": "^2.2", + "symfony/filesystem": "^4.0|^5.0", + "symfony/finder": "^4.0|^5.0", + "symfony/framework-bundle": "^4.0|^5.0", + "symfony/http-kernel": "^4.0|^5.0" + }, + "require-dev": { + "composer/semver": "^3.0@dev", + "doctrine/doctrine-bundle": "^1.8|^2.0", + "doctrine/orm": "^2.3", + "friendsofphp/php-cs-fixer": "^2.8", + "friendsoftwig/twigcs": "^4.1.0|^5.0.0", + "symfony/http-client": "^4.3|^5.0", + "symfony/phpunit-bridge": "^4.3|^5.0", + "symfony/process": "^4.0|^5.0", + "symfony/security-core": "^4.0|^5.0", + "symfony/yaml": "^4.0|^5.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-main": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\MakerBundle\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Maker helps you create empty commands, controllers, form classes, tests and more so you can forget about writing boilerplate code.", + "homepage": "https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html", + "keywords": [ + "code generator", + "generator", + "scaffold", + "scaffolding" + ], + "support": { + "issues": "https://github.com/symfony/maker-bundle/issues", + "source": "https://github.com/symfony/maker-bundle/tree/v1.30.2" + }, + "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": "2021-03-23T13:53:38+00:00" + } + ], "aliases": [], "minimum-stability": "stable", "stability-flags": { @@ -7534,14 +7976,14 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.1.3", + "php": "^7.4", "ext-ctype": "*", "ext-iconv": "*", "ext-json": "*" }, "platform-dev": [], "platform-overrides": { - "php": "7.3.12" + "php": "7.4.15" }, "plugin-api-version": "2.0.0" } diff --git a/api/config/bundles.php b/api/config/bundles.php index de8a66b..f42212d 100644 --- a/api/config/bundles.php +++ b/api/config/bundles.php @@ -11,4 +11,5 @@ return [ JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true], Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], Baldinof\RoadRunnerBundle\BaldinofRoadRunnerBundle::class => ['all' => true], + Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], ]; diff --git a/api/config/packages/messenger.yaml b/api/config/packages/messenger.yaml new file mode 100644 index 0000000..82536a4 --- /dev/null +++ b/api/config/packages/messenger.yaml @@ -0,0 +1,13 @@ +framework: + messenger: + # Uncomment this (and the failed transport below) to send failed messages to this transport for later handling. + # failure_transport: failed + + transports: + # https://symfony.com/doc/current/messenger.html#transport-configuration + async: '%env(MESSENGER_TRANSPORT_DSN)%' + # failed: 'doctrine://default?queue_name=failed' + sync: 'sync://' + + routing: + 'App\Message\UpdateDataMessage': async diff --git a/api/dev.Dockerfile b/api/dev.Dockerfile index fbe361e..2e8e9d7 100644 --- a/api/dev.Dockerfile +++ b/api/dev.Dockerfile @@ -1,6 +1,5 @@ FROM php:7.4-fpm-alpine -ENV APP_ENV=dev ENV DATABASE_URL="sqlite:///var/db/app.db" COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ diff --git a/api/src/Command/UpdateCommand.php b/api/src/Command/UpdateCommand.php index 54be5aa..5890fd4 100644 --- a/api/src/Command/UpdateCommand.php +++ b/api/src/Command/UpdateCommand.php @@ -2,29 +2,47 @@ namespace App\Command; +use App\Message\UpdateDataMessage; use App\Service\DataUpdater; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Messenger\MessageBusInterface; class UpdateCommand extends Command { /** @var DataUpdater */ private $updater; + /** @var MessageBusInterface */ + private $bus; - /** - * UpdateCommand constructor. - * - * @param $updater - */ - public function __construct(DataUpdater $updater) + public function __construct(DataUpdater $updater, MessageBusInterface $bus) { parent::__construct('app:update'); + $this->updater = $updater; + $this->bus = $bus; + } + + protected function configure() + { + $this->addOption( + 'async', 'a', + InputOption::VALUE_NONE, + 'Run in worker process via message queue.' + ); } protected function execute(InputInterface $input, OutputInterface $output) { - $this->updater->update($output); + if ($input->getOption('async')) { + $this->bus->dispatch(new UpdateDataMessage()); + $output->writeln("Update request sent to message queue."); + } else { + $this->updater->update($output); + } + + return Command::SUCCESS; } -} \ No newline at end of file +} diff --git a/api/src/Message/UpdateDataMessage.php b/api/src/Message/UpdateDataMessage.php new file mode 100644 index 0000000..173ded5 --- /dev/null +++ b/api/src/Message/UpdateDataMessage.php @@ -0,0 +1,7 @@ +<?php + +namespace App\Message; + +final class UpdateDataMessage +{ +} diff --git a/api/src/MessageHandler/UpdateDataMessageHandler.php b/api/src/MessageHandler/UpdateDataMessageHandler.php new file mode 100644 index 0000000..7f19e4f --- /dev/null +++ b/api/src/MessageHandler/UpdateDataMessageHandler.php @@ -0,0 +1,34 @@ +<?php + +namespace App\MessageHandler; + +use App\Message\UpdateDataMessage; +use App\Output\LoggerOutput; +use App\Service\DataUpdater; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; +use Symfony\Component\Messenger\Handler\MessageHandlerInterface; + +final class UpdateDataMessageHandler implements MessageHandlerInterface, LoggerAwareInterface +{ + use LoggerAwareTrait; + + /** @var DataUpdater */ + private $updater; + + public function __construct(DataUpdater $updater) + { + $this->updater = $updater; + } + + public function __invoke(UpdateDataMessage $message) + { + try { + $this->updater->update(new LoggerOutput($this->logger)); + } catch (\Exception $exception) { + $this->logger->critical($exception->getMessage(), [ + 'backtrace' => $exception->getTraceAsString() + ]); + } + } +} diff --git a/api/src/Output/LoggerOutput.php b/api/src/Output/LoggerOutput.php new file mode 100644 index 0000000..8421cf7 --- /dev/null +++ b/api/src/Output/LoggerOutput.php @@ -0,0 +1,30 @@ +<?php + + +namespace App\Output; + +use Psr\Log\LoggerInterface; +use Symfony\Component\Console\Formatter\OutputFormatterInterface; +use Symfony\Component\Console\Output\Output; + +class LoggerOutput extends Output +{ + /** @var LoggerInterface */ + private $logger; + + public function __construct( + LoggerInterface $logger, + ?int $verbosity = self::VERBOSITY_NORMAL, + bool $decorated = false, + OutputFormatterInterface $formatter = null + ) { + parent::__construct($verbosity, $decorated, $formatter); + + $this->logger = $logger; + } + + protected function doWrite(string $message, bool $newline) + { + $this->logger->info($message); + } +} diff --git a/api/src/Service/DataUpdater.php b/api/src/Service/DataUpdater.php index a31bba0..1839b92 100644 --- a/api/src/Service/DataUpdater.php +++ b/api/src/Service/DataUpdater.php @@ -5,6 +5,7 @@ namespace App\Service; use App\Event\DataUpdateEvent; use Doctrine\DBAL\Schema\Table; use Doctrine\ORM\EntityManagerInterface; +use Kadet\Functional as f; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; @@ -18,11 +19,6 @@ class DataUpdater /** @var EntityManagerInterface */ private $em; - /** - * DataUpdater constructor. - * - * @param EventDispatcherInterface $dispatcher - */ public function __construct(EventDispatcherInterface $dispatcher, EntityManagerInterface $em) { $this->dispatcher = $dispatcher; @@ -41,11 +37,13 @@ class DataUpdater copy($path, $backup); try { - collect($schema->listTables())->reject(function (Table $schema) { - return $schema->getName() === 'migration_versions'; - })->each([$schema, 'dropAndCreateTable']); + collect($schema->listTables()) + ->reject(f\ref([$this, 'shouldTableBePreserved'])) + ->each(f\ref([$schema, 'dropAndCreateTable'])) + ; $this->dispatcher->dispatch(new DataUpdateEvent($output), DataUpdateEvent::NAME); + unlink($backup); } catch (\Throwable $exception) { $connection->close(); @@ -56,4 +54,9 @@ class DataUpdater throw $exception; } } + + private function shouldTableBePreserved(Table $schema) + { + return in_array($schema->getName(), ['migration_versions', 'messenger_messages']); + } } diff --git a/api/symfony.lock b/api/symfony.lock index 97ab9dc..e8f3e9c 100644 --- a/api/symfony.lock +++ b/api/symfony.lock @@ -197,6 +197,9 @@ "nesbot/carbon": { "version": "1.33.0" }, + "nikic/php-parser": { + "version": "v4.10.4" + }, "ocramius/package-versions": { "version": "1.3.0" }, @@ -266,6 +269,9 @@ "spiral/roadrunner": { "version": "v1.8.4" }, + "symfony/amqp-messenger": { + "version": "v5.2.4" + }, "symfony/asset": { "version": "v4.1.4" }, @@ -296,6 +302,9 @@ "symfony/doctrine-bridge": { "version": "v4.1.4" }, + "symfony/doctrine-messenger": { + "version": "v5.2.5" + }, "symfony/dotenv": { "version": "v4.1.3" }, @@ -356,6 +365,27 @@ "symfony/http-kernel": { "version": "v4.1.3" }, + "symfony/maker-bundle": { + "version": "1.0", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "master", + "version": "1.0", + "ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f" + } + }, + "symfony/messenger": { + "version": "4.3", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "master", + "version": "4.3", + "ref": "e9a414b113ceadbf4e52abe37bf8f1b443f06ccb" + }, + "files": [ + "config/packages/messenger.yaml" + ] + }, "symfony/monolog-bridge": { "version": "v4.1.4" }, @@ -401,6 +431,9 @@ "symfony/psr-http-message-bridge": { "version": "v2.0.2" }, + "symfony/redis-messenger": { + "version": "v5.2.4" + }, "symfony/routing": { "version": "4.0", "recipe": { -- 2.45.2 From b27838815360e8bdb422d9b685abca9dac818cdc Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Fri, 9 Apr 2021 21:52:51 +0200 Subject: [PATCH 69/77] #50 - Messenger configuration --- api/.env | 2 +- api/config/packages/messenger.yaml | 20 +++++++++----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/api/.env b/api/.env index c2d60f7..9af5833 100644 --- a/api/.env +++ b/api/.env @@ -18,5 +18,5 @@ DATABASE_URL="sqlite:///%kernel.project_dir%/var/app.db" ###< doctrine/doctrine-bundle ### ###> symfony/messenger ### -MESSENGER_TRANSPORT_DSN="doctrine://default" +APP_EVENT_QUEUE_DSN="doctrine://default" ###< symfony/messenger ### diff --git a/api/config/packages/messenger.yaml b/api/config/packages/messenger.yaml index 82536a4..2de8b54 100644 --- a/api/config/packages/messenger.yaml +++ b/api/config/packages/messenger.yaml @@ -1,13 +1,11 @@ +parameters: + env(APP_EVENT_QUEUE): "doctrine://default" + framework: - messenger: - # Uncomment this (and the failed transport below) to send failed messages to this transport for later handling. - # failure_transport: failed + messenger: + transports: + main: '%env(resolve:APP_EVENT_QUEUE)%' + sync: 'sync://' - transports: - # https://symfony.com/doc/current/messenger.html#transport-configuration - async: '%env(MESSENGER_TRANSPORT_DSN)%' - # failed: 'doctrine://default?queue_name=failed' - sync: 'sync://' - - routing: - 'App\Message\UpdateDataMessage': async + routing: + 'App\Message\UpdateDataMessage': main -- 2.45.2 From a07f4add1f3e8b26f099706275009ebe42077fdc Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sun, 11 Apr 2021 19:00:06 +0200 Subject: [PATCH 70/77] #50 - Refactor Dockerfiles for better cacheability --- api/{dev.Dockerfile => Dockerfile} | 2 -- api/fpm.Dockerfile | 25 ----------------- api/rr.Dockerfile | 25 ----------------- docker-compose.yml | 6 ++-- docker/{php => api}/.env | 0 docker/api/fpm.Dockerfile | 29 +++++++++++++++++++ docker/{php => api}/log.conf | 0 docker/api/rr.Dockerfile | 37 ++++++++++++++++++++++++ docker/worker/Dockerfile | 45 ++++++++++++++++++++++++++++++ docker/worker/supervisord.conf | 2 ++ front/Dockerfile | 2 ++ 11 files changed, 118 insertions(+), 55 deletions(-) rename api/{dev.Dockerfile => Dockerfile} (99%) delete mode 100644 api/fpm.Dockerfile delete mode 100644 api/rr.Dockerfile rename docker/{php => api}/.env (100%) create mode 100644 docker/api/fpm.Dockerfile rename docker/{php => api}/log.conf (100%) create mode 100644 docker/api/rr.Dockerfile create mode 100644 docker/worker/Dockerfile create mode 100644 docker/worker/supervisord.conf diff --git a/api/dev.Dockerfile b/api/Dockerfile similarity index 99% rename from api/dev.Dockerfile rename to api/Dockerfile index 2e8e9d7..acf47c7 100644 --- a/api/dev.Dockerfile +++ b/api/Dockerfile @@ -3,8 +3,6 @@ FROM php:7.4-fpm-alpine ENV DATABASE_URL="sqlite:///var/db/app.db" COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ - -# Composer COPY --from=composer:latest /usr/bin/composer /usr/bin/composer RUN install-php-extensions bcmath intl opcache zip sockets xdebug-^3.0; diff --git a/api/fpm.Dockerfile b/api/fpm.Dockerfile deleted file mode 100644 index f5955a5..0000000 --- a/api/fpm.Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM php:7.4-fpm-alpine - -ENV APP_ENV=prod -ENV DATABASE_URL="sqlite:////var/db/app.db" -ENV PATH=$PATH:/usr/src/app/bin - -RUN apk add --no-cache autoconf openssl-dev g++ make pcre-dev icu-dev zlib-dev libzip-dev git && \ - docker-php-ext-install bcmath intl opcache zip sockets && \ - apk del --purge autoconf g++ make; - -COPY --from=composer:latest /usr/bin/composer /usr/bin/composer -COPY . . - -RUN composer install --no-dev --no-scripts --no-plugins --prefer-dist --no-progress --no-interaction && \ - composer dump-autoload --optimize && \ - composer check-platform-reqs && \ - php bin/console cache:warmup - -# Timezone -RUN ln -snf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime && - echo "date.timezone = Europe/Warsaw" >> /usr/local/etc/php/conf.d/datetime.ini; - -WORKDIR /var/www - -CMD ["./bin/docker-init.sh", "php-fpm"] diff --git a/api/rr.Dockerfile b/api/rr.Dockerfile deleted file mode 100644 index 56fa7e2..0000000 --- a/api/rr.Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM php:7.4-alpine - -ENV APP_ENV=prod -ENV DATABASE_URL="sqlite:////var/db/app.db" -ENV PATH=$PATH:/usr/src/app/bin - -RUN apk add --no-cache autoconf openssl-dev g++ make pcre-dev icu-dev zlib-dev libzip-dev git && \ - docker-php-ext-install bcmath intl opcache zip sockets && \ - apk del --purge autoconf g++ make - -WORKDIR /usr/src/app - -COPY --from=composer:latest /usr/bin/composer /usr/bin/composer -COPY . . - -RUN composer install --no-dev --no-scripts --no-plugins --prefer-dist --no-progress --no-interaction -RUN ./vendor/bin/rr get-binary --location /usr/local/bin - -RUN composer dump-autoload --optimize && \ - composer check-platform-reqs && \ - php bin/console cache:warmup - -EXPOSE 8080 - -CMD ["./bin/docker-init.sh", "rr", "serve"] diff --git a/docker-compose.yml b/docker-compose.yml index 7fe3baa..f16cebd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,12 +13,12 @@ services: api: build: context: ./api - dockerfile: dev.Dockerfile + dockerfile: Dockerfile env_file: - - ./docker/php/.env + - ./docker/api/.env volumes: - ./api:/var/www:cached - - ./docker/php/log.conf:/usr/local/etc/php-fpm.d/zz-log.conf + - ./docker/api/log.conf:/usr/local/etc/php-fpm.d/zz-log.conf frontend: image: node:15.2.1 diff --git a/docker/php/.env b/docker/api/.env similarity index 100% rename from docker/php/.env rename to docker/api/.env diff --git a/docker/api/fpm.Dockerfile b/docker/api/fpm.Dockerfile new file mode 100644 index 0000000..d683658 --- /dev/null +++ b/docker/api/fpm.Dockerfile @@ -0,0 +1,29 @@ +FROM php:7.4-fpm-alpine + +LABEL maintainer="Kacper Donat <kacper@kadet.net>" + +COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +WORKDIR /var/www + +RUN install-php-extensions bcmath intl opcache zip sockets; + +COPY composer.json composer.lock ./ + +RUN apk add git && \ + composer install --no-dev --no-scripts --no-plugins --prefer-dist --no-progress --no-interaction && \ + composer dump-autoload --optimize && \ + composer check-platform-reqs && \ + composer clear-cache && \ + apk del --purge git + +COPY . . + +ENV APP_ENV=prod +ENV DATABASE_URL="sqlite:////var/db/app.db" +ENV PATH=$PATH:/var/www/bin + +RUN composer run-script post-install-cmd + +CMD ["./bin/docker-init.sh", "php-fpm"] diff --git a/docker/php/log.conf b/docker/api/log.conf similarity index 100% rename from docker/php/log.conf rename to docker/api/log.conf diff --git a/docker/api/rr.Dockerfile b/docker/api/rr.Dockerfile new file mode 100644 index 0000000..2fc23a0 --- /dev/null +++ b/docker/api/rr.Dockerfile @@ -0,0 +1,37 @@ +FROM php:7.4-alpinpe + +LABEL maintainer="Kacper Donat <kacper@kadet.net>" + +COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +WORKDIR /var/www + +RUN install-php-extensions bcmath intl opcache zip sockets; + +COPY composer.json composer.lock ./ + +RUN apk add git && \ + composer install --no-dev --no-scripts --no-plugins --prefer-dist --no-progress --no-interaction && \ + composer dump-autoload --optimize && \ + composer check-platform-reqs && \ + composer clear-cache && \ + apk del --purge git + +# this touch is needed because get-binary calls the autoloader +RUN mkdir -p ./src/Functions && \ + touch src/Functions/index.php && \ + ./vendor/bin/rr get-binary --location /usr/local/bin + +COPY . . + +ENV APP_ENV=prod +ENV DATABASE_URL="sqlite:////var/db/app.db" +ENV PATH=$PATH:/var/www/bin + +RUN composer run-script post-install-cmd +RUN mkdir /var/db + +EXPOSE 8080 + +CMD ["./bin/docker-init.sh", "rr", "serve"] diff --git a/docker/worker/Dockerfile b/docker/worker/Dockerfile new file mode 100644 index 0000000..058edf9 --- /dev/null +++ b/docker/worker/Dockerfile @@ -0,0 +1,45 @@ +FROM php:7.4-cli-alpine + +LABEL maintainer="Kacper Donat <kacper@kadet.net>" + +COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +RUN apk add supervisor && \ + { \ + echo '[supervisord]'; \ + echo 'nodaemon=true'; \ + echo ; \ + echo '[program:messenger-consumer]'; \ + echo 'command=php /var/www/bin/console messenger:consume main -vv --time-limit=86400 --limit=10'; \ + echo 'startsecs=0'; \ + echo 'start=true'; \ + echo 'autorestart=true'; \ + echo 'stdout_logfile=/dev/stdout'; \ + echo 'stderr_logfile=/dev/stderr'; \ + echo 'stdout_logfile_maxbytes=0'; \ + echo 'stderr_logfile_maxbytes=0'; \ + } | tee /etc/supervisord.conf; + +WORKDIR /var/www + +RUN install-php-extensions bcmath intl opcache zip sockets; + +COPY composer.json composer.lock ./ + +RUN apk add git && \ + composer install --no-dev --no-scripts --no-plugins --prefer-dist --no-progress --no-interaction && \ + composer dump-autoload --optimize && \ + composer check-platform-reqs && \ + composer clear-cache && \ + apk del --purge git + +COPY . . + +ENV APP_ENV=prod +ENV DATABASE_URL="sqlite:////var/db/app.db" +ENV PATH=$PATH:/var/www/bin + +RUN composer run-script post-install-cmd + +CMD ["supervisord", "-c", "/etc/supervisord.conf"] diff --git a/docker/worker/supervisord.conf b/docker/worker/supervisord.conf new file mode 100644 index 0000000..54296b8 --- /dev/null +++ b/docker/worker/supervisord.conf @@ -0,0 +1,2 @@ +[supervisord] +nodaemon=true diff --git a/front/Dockerfile b/front/Dockerfile index f7a57df..4231ba4 100644 --- a/front/Dockerfile +++ b/front/Dockerfile @@ -23,6 +23,8 @@ RUN yarn install --production FROM node:15.2.1-slim +LABEL maintainer="Kacper Donat <kacper@kadet.net>" + WORKDIR /app COPY --from=build /app/build/ build -- 2.45.2 From f23f96f4c3921cce2f49024ec7d413f80b613bf2 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Wed, 14 Apr 2021 18:38:30 +0200 Subject: [PATCH 71/77] #50 - Split build directory from docker-compose related files Files related with building distribution images now have it's own directory. Files for development using docker-compose are now placed in .docker-compose directory as they are non-essentials. --- {docker => .docker-compose}/api/.env | 0 {docker => .docker-compose}/api/log.conf | 0 .../nginx/cojedzie.conf | 0 {docker => build}/api/fpm.Dockerfile | 0 {docker => build}/api/rr.Dockerfile | 0 build/standalone/rr.Dockerfile | 31 ++++++++++++++++++ {docker => build}/worker/Dockerfile | 32 +++++++++---------- docker-compose.yml | 6 ++-- docker/worker/supervisord.conf | 2 -- 9 files changed, 50 insertions(+), 21 deletions(-) rename {docker => .docker-compose}/api/.env (100%) rename {docker => .docker-compose}/api/log.conf (100%) rename {docker => .docker-compose}/nginx/cojedzie.conf (100%) rename {docker => build}/api/fpm.Dockerfile (100%) rename {docker => build}/api/rr.Dockerfile (100%) create mode 100644 build/standalone/rr.Dockerfile rename {docker => build}/worker/Dockerfile (100%) delete mode 100644 docker/worker/supervisord.conf diff --git a/docker/api/.env b/.docker-compose/api/.env similarity index 100% rename from docker/api/.env rename to .docker-compose/api/.env diff --git a/docker/api/log.conf b/.docker-compose/api/log.conf similarity index 100% rename from docker/api/log.conf rename to .docker-compose/api/log.conf diff --git a/docker/nginx/cojedzie.conf b/.docker-compose/nginx/cojedzie.conf similarity index 100% rename from docker/nginx/cojedzie.conf rename to .docker-compose/nginx/cojedzie.conf diff --git a/docker/api/fpm.Dockerfile b/build/api/fpm.Dockerfile similarity index 100% rename from docker/api/fpm.Dockerfile rename to build/api/fpm.Dockerfile diff --git a/docker/api/rr.Dockerfile b/build/api/rr.Dockerfile similarity index 100% rename from docker/api/rr.Dockerfile rename to build/api/rr.Dockerfile diff --git a/build/standalone/rr.Dockerfile b/build/standalone/rr.Dockerfile new file mode 100644 index 0000000..d68903e --- /dev/null +++ b/build/standalone/rr.Dockerfile @@ -0,0 +1,31 @@ +ARG COJEDZIE_VER=latest + +FROM cojedzie/api:${COJEDZIE_VER}-rr + +RUN apk add supervisor && \ + { \ + echo '[supervisord]'; \ + echo 'nodaemon=true'; \ + echo ; \ + echo '[program:roadrunner]'; \ + echo 'command=rr serve'; \ + echo 'startsecs=0'; \ + echo 'start=true'; \ + echo 'autorestart=true'; \ + echo 'stdout_logfile=/dev/stdout'; \ + echo 'stderr_logfile=/dev/stderr'; \ + echo 'stdout_logfile_maxbytes=0'; \ + echo 'stderr_logfile_maxbytes=0'; \ + echo ; \ + echo '[program:messenger-consumer]'; \ + echo 'command=php /var/www/bin/console messenger:consume main -vv --time-limit=86400 --limit=10'; \ + echo 'startsecs=0'; \ + echo 'start=true'; \ + echo 'autorestart=true'; \ + echo 'stdout_logfile=/dev/stdout'; \ + echo 'stderr_logfile=/dev/stderr'; \ + echo 'stdout_logfile_maxbytes=0'; \ + echo 'stderr_logfile_maxbytes=0'; \ + } | tee /etc/supervisord.conf; + +CMD ["./bin/docker-init.sh", "supervisord", "-c", "/etc/supervisord.conf"] diff --git a/docker/worker/Dockerfile b/build/worker/Dockerfile similarity index 100% rename from docker/worker/Dockerfile rename to build/worker/Dockerfile index 058edf9..76d78b5 100644 --- a/docker/worker/Dockerfile +++ b/build/worker/Dockerfile @@ -5,22 +5,6 @@ LABEL maintainer="Kacper Donat <kacper@kadet.net>" COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ COPY --from=composer:latest /usr/bin/composer /usr/bin/composer -RUN apk add supervisor && \ - { \ - echo '[supervisord]'; \ - echo 'nodaemon=true'; \ - echo ; \ - echo '[program:messenger-consumer]'; \ - echo 'command=php /var/www/bin/console messenger:consume main -vv --time-limit=86400 --limit=10'; \ - echo 'startsecs=0'; \ - echo 'start=true'; \ - echo 'autorestart=true'; \ - echo 'stdout_logfile=/dev/stdout'; \ - echo 'stderr_logfile=/dev/stderr'; \ - echo 'stdout_logfile_maxbytes=0'; \ - echo 'stderr_logfile_maxbytes=0'; \ - } | tee /etc/supervisord.conf; - WORKDIR /var/www RUN install-php-extensions bcmath intl opcache zip sockets; @@ -42,4 +26,20 @@ ENV PATH=$PATH:/var/www/bin RUN composer run-script post-install-cmd +RUN apk add supervisor && \ + { \ + echo '[supervisord]'; \ + echo 'nodaemon=true'; \ + echo ; \ + echo '[program:messenger-consumer]'; \ + echo 'command=php /var/www/bin/console messenger:consume main -vv --time-limit=86400 --limit=10'; \ + echo 'startsecs=0'; \ + echo 'start=true'; \ + echo 'autorestart=true'; \ + echo 'stdout_logfile=/dev/stdout'; \ + echo 'stderr_logfile=/dev/stderr'; \ + echo 'stdout_logfile_maxbytes=0'; \ + echo 'stderr_logfile_maxbytes=0'; \ + } | tee /etc/supervisord.conf; + CMD ["supervisord", "-c", "/etc/supervisord.conf"] diff --git a/docker-compose.yml b/docker-compose.yml index f16cebd..6eec0da 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,17 +8,17 @@ services: volumes: - ./front:/var/www/front:cached - ./api:/var/www/api:cached - - ./docker/nginx/cojedzie.conf:/etc/nginx/conf.d/cojedzie.conf + - .docker-compose/nginx/cojedzie.conf:/etc/nginx/conf.d/cojedzie.conf api: build: context: ./api dockerfile: Dockerfile env_file: - - ./docker/api/.env + - .docker-compose/api/.env volumes: - ./api:/var/www:cached - - ./docker/api/log.conf:/usr/local/etc/php-fpm.d/zz-log.conf + - .docker-compose/api/log.conf:/usr/local/etc/php-fpm.d/zz-log.conf frontend: image: node:15.2.1 diff --git a/docker/worker/supervisord.conf b/docker/worker/supervisord.conf deleted file mode 100644 index 54296b8..0000000 --- a/docker/worker/supervisord.conf +++ /dev/null @@ -1,2 +0,0 @@ -[supervisord] -nodaemon=true -- 2.45.2 From aae70c0f92c1fa9bbe8a568d5c34026a595cb547 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Thu, 15 Apr 2021 21:02:56 +0200 Subject: [PATCH 72/77] #50 - Add release script --- README.md | 14 ++- build/api/rr.Dockerfile | 2 +- {front => build/front}/Dockerfile | 0 build/release.sh | 154 ++++++++++++++++++++++++++++++ 4 files changed, 164 insertions(+), 6 deletions(-) rename {front => build/front}/Dockerfile (100%) create mode 100755 build/release.sh diff --git a/README.md b/README.md index ef893b0..7bcd15a 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,19 @@ aims to be the central hub for all public transport information you will need. You can use the app at [cojedzie.pl](https://cojedzie.pl). -# Available cities -For now tricity is the only available data source. - -# Contributing +## Contributing Want to contribute? -# License + +## Roadmap +Co Jedzie is in active development, roadmap of the project can be found on [trello]. This roadmap is regularly updated +and represents current state of the project. Feel free to take a look. + +## License This project is [fair-code](https://faircode.io/) licensed under [MIT with Commons Clause](./LICENSE.md). Basically, Co Jedzie is free and code is available to everyone, but it's not allowed to make money directly with it. Note that data collected from available data sources is licensed by their respective owners, thus it may be available under different terms than the project itself and may require additional permissions to use. + +[trello]: https://trello.com/b/QXqDvmoG/co-jedzie diff --git a/build/api/rr.Dockerfile b/build/api/rr.Dockerfile index 2fc23a0..bcdf906 100644 --- a/build/api/rr.Dockerfile +++ b/build/api/rr.Dockerfile @@ -1,4 +1,4 @@ -FROM php:7.4-alpinpe +FROM php:7.4-alpine LABEL maintainer="Kacper Donat <kacper@kadet.net>" diff --git a/front/Dockerfile b/build/front/Dockerfile similarity index 100% rename from front/Dockerfile rename to build/front/Dockerfile diff --git a/build/release.sh b/build/release.sh new file mode 100755 index 0000000..62171a4 --- /dev/null +++ b/build/release.sh @@ -0,0 +1,154 @@ +#!/bin/bash + +TAGS=$* +BUILD=$(dirname $0) +ROOT=$BUILD/.. + +REGISTRY="docker.io" +TAGS=() +DRY=0 +PUSH=0 + +BUILT_TAGS=() + +export DOCKER_BUILDKIT=1 + +usage () { + echo "usage: $0 [-h|--help] [-d|--dry] [-r|--registry registry] [-t|--tag tag] [-p|--push] -- images..."; +} + +run () { + if [[ $DRY == 1 ]]; then + echo "$@" + else + "$@" + fi +} + +# usage: build [-d|--default] [-v|--variant variant] <image> <context> +build () { + ARGS=() + IS_DEFAULT=0 + SUFFIX="" + VARIANT="" + + options=$(getopt -l "default,variant:" -o "dv:" -- "$@") + eval set -- "$options" + + while true; + do + case "$1" in + -d|--default) + IS_DEFAULT=1 + shift + ;; + -v|--variant) + VARIANT="$2" + shift 2 + ;; + --) + shift + break + ;; + *) + echo "build: unknown option $1" + exit 1 + esac + done + + IMAGE=$1 + CONTEXT=$2 + shift 2; + + # check for variant + if [[ -z "$VARIANT" ]]; then + ARGS+=("-f" "$BUILD/$IMAGE/Dockerfile") + else + ARGS+=("-f" "$BUILD/$IMAGE/$VARIANT.Dockerfile") + SUFFIX="-$VARIANT" + fi + + for TAG in "${TAGS[@]}"; do + ARGS+=("-t" "$REGISTRY/cojedzie/$IMAGE:$TAG$SUFFIX") + BUILT_TAGS+=("$REGISTRY/cojedzie/$IMAGE:$TAG$SUFFIX") + + if [[ $IS_DEFAULT == 1 ]]; then + ARGS+=("-t" "$REGISTRY/cojedzie/$IMAGE:$TAG") + BUILT_TAGS+=("$REGISTRY/cojedzie/$IMAGE:$TAG") + fi + done + + run docker build $CONTEXT "${ARGS[@]}" "$@" +} + +options=$(getopt -l "help,dry,registry:,tag:,push" -o "hdr:t:p" -- "$@") +eval set -- "$options" + +while true; +do + case "$1" in + -h|--help) + usage + exit 0 + ;; + -t|--tag) + TAGS+=("$2") + shift 2 + ;; + -p|--push) + PUSH=1 + shift + ;; + -r|--registry) + REGISTRY="$2" + shift 2 + ;; + -d|--dry) + DRY=1 + shift + ;; + --) + shift + break; + esac +done + +# set default tags if user have not provided any +if [ ${#TAGS[@]} -eq 0 ]; then + TAGS=("latest") +fi + +if [ $# -eq 0 ]; then + set -- api standalone worker front +fi + +while [ $# -gt 0 ] +do + case "$1" in + api) + build api $ROOT/api/ --variant rr --default + build api $ROOT/api/ --variant fpm + ;; + standalone) + build standalone $ROOT/api/ --variant rr --default + ;; + worker) + build worker $ROOT/api/ + ;; + front) + build front $ROOT/front/ + ;; + *) + >&2 echo "$1 is not a valid image to build" + esac + shift +done + +if [ $PUSH -eq 1 ]; then + for TAG in "${BUILT_TAGS[@]}"; do + docker push $TAG + done +else + echo "Created tags:" + printf " - %s\n" "${BUILT_TAGS[@]}" +fi -- 2.45.2 From 3fc98af139e3f776f971c5047ec73d57c9152077 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Thu, 15 Apr 2021 22:34:01 +0200 Subject: [PATCH 73/77] #50 - Create base image for sharing common code --- build/api/fpm.Dockerfile | 19 ++++++----------- build/api/rr.Dockerfile | 25 ++++++---------------- build/base/Dockerfile | 28 ++++++++++++++++++++++++ build/release.sh | 39 +++++++++++++++++++++++----------- build/standalone/rr.Dockerfile | 5 +++-- build/worker/Dockerfile | 21 +++++++----------- 6 files changed, 80 insertions(+), 57 deletions(-) create mode 100644 build/base/Dockerfile diff --git a/build/api/fpm.Dockerfile b/build/api/fpm.Dockerfile index d683658..3e1a422 100644 --- a/build/api/fpm.Dockerfile +++ b/build/api/fpm.Dockerfile @@ -1,29 +1,24 @@ +ARG BASE_VERSION=latest +ARG REGISTRY=docker.io + +FROM $REGISTRY/cojedzie/base:$BASE_VERSION as base + FROM php:7.4-fpm-alpine LABEL maintainer="Kacper Donat <kacper@kadet.net>" COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ -COPY --from=composer:latest /usr/bin/composer /usr/bin/composer WORKDIR /var/www RUN install-php-extensions bcmath intl opcache zip sockets; -COPY composer.json composer.lock ./ - -RUN apk add git && \ - composer install --no-dev --no-scripts --no-plugins --prefer-dist --no-progress --no-interaction && \ - composer dump-autoload --optimize && \ - composer check-platform-reqs && \ - composer clear-cache && \ - apk del --purge git - -COPY . . +COPY --from=base /var/www /var/www ENV APP_ENV=prod ENV DATABASE_URL="sqlite:////var/db/app.db" ENV PATH=$PATH:/var/www/bin -RUN composer run-script post-install-cmd +VOLUME /var/db CMD ["./bin/docker-init.sh", "php-fpm"] diff --git a/build/api/rr.Dockerfile b/build/api/rr.Dockerfile index bcdf906..854d3b2 100644 --- a/build/api/rr.Dockerfile +++ b/build/api/rr.Dockerfile @@ -1,36 +1,25 @@ +ARG BASE_VERSION=latest +ARG REGISTRY=docker.io + +FROM $REGISTRY/cojedzie/base:$BASE_VERSION as base + FROM php:7.4-alpine LABEL maintainer="Kacper Donat <kacper@kadet.net>" COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ -COPY --from=composer:latest /usr/bin/composer /usr/bin/composer WORKDIR /var/www RUN install-php-extensions bcmath intl opcache zip sockets; -COPY composer.json composer.lock ./ - -RUN apk add git && \ - composer install --no-dev --no-scripts --no-plugins --prefer-dist --no-progress --no-interaction && \ - composer dump-autoload --optimize && \ - composer check-platform-reqs && \ - composer clear-cache && \ - apk del --purge git - -# this touch is needed because get-binary calls the autoloader -RUN mkdir -p ./src/Functions && \ - touch src/Functions/index.php && \ - ./vendor/bin/rr get-binary --location /usr/local/bin - -COPY . . +COPY --from=base /var/www /var/www ENV APP_ENV=prod ENV DATABASE_URL="sqlite:////var/db/app.db" ENV PATH=$PATH:/var/www/bin -RUN composer run-script post-install-cmd -RUN mkdir /var/db +VOLUME /var/db EXPOSE 8080 diff --git a/build/base/Dockerfile b/build/base/Dockerfile new file mode 100644 index 0000000..5d6dcef --- /dev/null +++ b/build/base/Dockerfile @@ -0,0 +1,28 @@ +FROM php:7.4-alpine + +LABEL maintainer="Kacper Donat <kacper@kadet.net>" + +COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +WORKDIR /var/www + +RUN install-php-extensions bcmath intl opcache zip sockets; + +COPY composer.json composer.lock ./ + +RUN apk add git && \ + composer install --no-dev --no-scripts --no-plugins --prefer-dist --no-progress --no-interaction && \ + composer dump-autoload --optimize && \ + composer check-platform-reqs && \ + composer clear-cache && \ + apk del --purge git + +COPY . . + +ENV APP_ENV=prod + +RUN composer run-script post-install-cmd + +# This image is not meant to be run, just to prepare all required files +CMD ["/bin/false"] diff --git a/build/release.sh b/build/release.sh index 62171a4..ba72706 100755 --- a/build/release.sh +++ b/build/release.sh @@ -8,13 +8,14 @@ REGISTRY="docker.io" TAGS=() DRY=0 PUSH=0 +BUILD_BASE=1 BUILT_TAGS=() export DOCKER_BUILDKIT=1 usage () { - echo "usage: $0 [-h|--help] [-d|--dry] [-r|--registry registry] [-t|--tag tag] [-p|--push] -- images..."; + echo "usage: $0 [-h|--help] [-d|--dry] [--no-base|-B] [-p|--push] [-r|--registry registry] [-t|--tag tag] -- images..."; } run () { @@ -25,14 +26,15 @@ run () { fi } -# usage: build [-d|--default] [-v|--variant variant] <image> <context> +# usage: build [-d|--default] [-v|--variant variant] [-R|--no-register] <image> <context> build () { ARGS=() IS_DEFAULT=0 SUFFIX="" VARIANT="" + REGISTER=1 - options=$(getopt -l "default,variant:" -o "dv:" -- "$@") + options=$(getopt -l "default,variant:,no-register" -o "dv:R" -- "$@") eval set -- "$options" while true; @@ -46,6 +48,10 @@ build () { VARIANT="$2" shift 2 ;; + -R|--no-register) + REGISTER=0 + shift + ;; --) shift break @@ -70,18 +76,19 @@ build () { for TAG in "${TAGS[@]}"; do ARGS+=("-t" "$REGISTRY/cojedzie/$IMAGE:$TAG$SUFFIX") - BUILT_TAGS+=("$REGISTRY/cojedzie/$IMAGE:$TAG$SUFFIX") + [[ $REGISTER -eq 1 ]] && BUILT_TAGS+=("$REGISTRY/cojedzie/$IMAGE:$TAG$SUFFIX") if [[ $IS_DEFAULT == 1 ]]; then ARGS+=("-t" "$REGISTRY/cojedzie/$IMAGE:$TAG") - BUILT_TAGS+=("$REGISTRY/cojedzie/$IMAGE:$TAG") + [[ $REGISTER -eq 1 ]] && BUILT_TAGS+=("$REGISTRY/cojedzie/$IMAGE:$TAG") fi done - run docker build $CONTEXT "${ARGS[@]}" "$@" + echo "Building $IMAGE $VARIANT" + run docker build --build-arg "BASE_VERSION=${TAGS[0]}" --build-arg "REGISTRY=$REGISTRY" "$CONTEXT" "${ARGS[@]}" "$@" } -options=$(getopt -l "help,dry,registry:,tag:,push" -o "hdr:t:p" -- "$@") +options=$(getopt -l "help,dry,registry:,tag:,push,no-base" -o "hdr:t:pB" -- "$@") eval set -- "$options" while true; @@ -99,6 +106,10 @@ do PUSH=1 shift ;; + -B|--no-base) + BUILD_BASE=0 + shift + ;; -r|--registry) REGISTRY="$2" shift 2 @@ -122,21 +133,25 @@ if [ $# -eq 0 ]; then set -- api standalone worker front fi +if [ $BUILD_BASE -eq 1 ]; then + build --no-register base $ROOT/api/ || exit 1 +fi + while [ $# -gt 0 ] do case "$1" in api) - build api $ROOT/api/ --variant rr --default - build api $ROOT/api/ --variant fpm + build api $ROOT/api/ --variant rr --default || exit 1 + build api $ROOT/api/ --variant fpm || exit 1 ;; standalone) - build standalone $ROOT/api/ --variant rr --default + build standalone $ROOT/api/ --variant rr --default || exit 1 ;; worker) - build worker $ROOT/api/ + build worker $ROOT/api/ || exit 1 ;; front) - build front $ROOT/front/ + build front $ROOT/front/ || exit 1 ;; *) >&2 echo "$1 is not a valid image to build" diff --git a/build/standalone/rr.Dockerfile b/build/standalone/rr.Dockerfile index d68903e..0fcd071 100644 --- a/build/standalone/rr.Dockerfile +++ b/build/standalone/rr.Dockerfile @@ -1,6 +1,7 @@ -ARG COJEDZIE_VER=latest +ARG BASE_VERSION=latest +ARG REGISTRY=docker.io -FROM cojedzie/api:${COJEDZIE_VER}-rr +FROM ${REGISTRY}/cojedzie/api:${BASE_VERSION}-rr RUN apk add supervisor && \ { \ diff --git a/build/worker/Dockerfile b/build/worker/Dockerfile index 76d78b5..eeb7cee 100644 --- a/build/worker/Dockerfile +++ b/build/worker/Dockerfile @@ -1,31 +1,24 @@ +ARG BASE_VERSION=latest +ARG REGISTRY=docker.io + +FROM $REGISTRY/cojedzie/base:$BASE_VERSION as base + FROM php:7.4-cli-alpine LABEL maintainer="Kacper Donat <kacper@kadet.net>" COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ -COPY --from=composer:latest /usr/bin/composer /usr/bin/composer WORKDIR /var/www RUN install-php-extensions bcmath intl opcache zip sockets; -COPY composer.json composer.lock ./ - -RUN apk add git && \ - composer install --no-dev --no-scripts --no-plugins --prefer-dist --no-progress --no-interaction && \ - composer dump-autoload --optimize && \ - composer check-platform-reqs && \ - composer clear-cache && \ - apk del --purge git - -COPY . . +COPY --from=base /var/www /var/www ENV APP_ENV=prod ENV DATABASE_URL="sqlite:////var/db/app.db" ENV PATH=$PATH:/var/www/bin -RUN composer run-script post-install-cmd - RUN apk add supervisor && \ { \ echo '[supervisord]'; \ @@ -42,4 +35,6 @@ RUN apk add supervisor && \ echo 'stderr_logfile_maxbytes=0'; \ } | tee /etc/supervisord.conf; +VOLUME /var/db + CMD ["supervisord", "-c", "/etc/supervisord.conf"] -- 2.45.2 From a3b4a220c692bce2de0d0d4d33fb5f49f5fb976d Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Sat, 17 Apr 2021 15:23:45 +0200 Subject: [PATCH 74/77] #50 - Create base images with variants corresponding to PHP image variants --- build/api/fpm.Dockerfile | 20 +----------------- build/api/rr.Dockerfile | 22 +++----------------- build/base/Dockerfile | 2 ++ build/base/cli.Dockerfile | 27 ++++++++++++++++++++++++ build/base/fpm.Dockerfile | 27 ++++++++++++++++++++++++ build/release.sh | 10 +++++---- build/standalone/rr.Dockerfile | 16 +++++++++----- build/standalone/supervisord-init.sh | 7 +++++++ build/worker/Dockerfile | 31 ++++++++-------------------- build/worker/supervisord-init.sh | 7 +++++++ 10 files changed, 100 insertions(+), 69 deletions(-) create mode 100644 build/base/cli.Dockerfile create mode 100644 build/base/fpm.Dockerfile create mode 100755 build/standalone/supervisord-init.sh create mode 100755 build/worker/supervisord-init.sh diff --git a/build/api/fpm.Dockerfile b/build/api/fpm.Dockerfile index 3e1a422..4f23641 100644 --- a/build/api/fpm.Dockerfile +++ b/build/api/fpm.Dockerfile @@ -1,24 +1,6 @@ ARG BASE_VERSION=latest ARG REGISTRY=docker.io -FROM $REGISTRY/cojedzie/base:$BASE_VERSION as base - -FROM php:7.4-fpm-alpine - -LABEL maintainer="Kacper Donat <kacper@kadet.net>" - -COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ - -WORKDIR /var/www - -RUN install-php-extensions bcmath intl opcache zip sockets; - -COPY --from=base /var/www /var/www - -ENV APP_ENV=prod -ENV DATABASE_URL="sqlite:////var/db/app.db" -ENV PATH=$PATH:/var/www/bin - -VOLUME /var/db +FROM $REGISTRY/cojedzie/base:${BASE_VERSION}-fpm as base CMD ["./bin/docker-init.sh", "php-fpm"] diff --git a/build/api/rr.Dockerfile b/build/api/rr.Dockerfile index 854d3b2..5fe6e2b 100644 --- a/build/api/rr.Dockerfile +++ b/build/api/rr.Dockerfile @@ -1,26 +1,10 @@ ARG BASE_VERSION=latest ARG REGISTRY=docker.io -FROM $REGISTRY/cojedzie/base:$BASE_VERSION as base +FROM $REGISTRY/cojedzie/base:${BASE_VERSION} as base -FROM php:7.4-alpine - -LABEL maintainer="Kacper Donat <kacper@kadet.net>" - -COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ - -WORKDIR /var/www - -RUN install-php-extensions bcmath intl opcache zip sockets; - -COPY --from=base /var/www /var/www - -ENV APP_ENV=prod -ENV DATABASE_URL="sqlite:////var/db/app.db" -ENV PATH=$PATH:/var/www/bin - -VOLUME /var/db +COPY --from=spiralscout/roadrunner:1.9.2 /usr/bin/rr /usr/bin/rr EXPOSE 8080 -CMD ["./bin/docker-init.sh", "rr", "serve"] +CMD ["./bin/docker-init.sh", "rr", "serve", "-v"] diff --git a/build/base/Dockerfile b/build/base/Dockerfile index 5d6dcef..818a928 100644 --- a/build/base/Dockerfile +++ b/build/base/Dockerfile @@ -24,5 +24,7 @@ ENV APP_ENV=prod RUN composer run-script post-install-cmd +VOLUME /var/db + # This image is not meant to be run, just to prepare all required files CMD ["/bin/false"] diff --git a/build/base/cli.Dockerfile b/build/base/cli.Dockerfile new file mode 100644 index 0000000..72552b6 --- /dev/null +++ b/build/base/cli.Dockerfile @@ -0,0 +1,27 @@ +ARG BASE_VERSION=latest +ARG REGISTRY=docker.io + +FROM $REGISTRY/cojedzie/base:$BASE_VERSION as base + +FROM php:7.4-cli-alpine + +LABEL maintainer="Kacper Donat <kacper@kadet.net>" + +COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ + +WORKDIR /var/www + +RUN install-php-extensions bcmath intl opcache zip sockets; + +COPY composer.json composer.lock ./ + +COPY --from=base /var/www /var/www + +ENV APP_ENV=prod +ENV DATABASE_URL="sqlite:////var/db/app.db" +ENV PATH=$PATH:/var/www/bin + +VOLUME /var/db + +# This image is not meant to be run, just to prepare all required files +CMD ["/bin/false"] diff --git a/build/base/fpm.Dockerfile b/build/base/fpm.Dockerfile new file mode 100644 index 0000000..06bd388 --- /dev/null +++ b/build/base/fpm.Dockerfile @@ -0,0 +1,27 @@ +ARG BASE_VERSION=latest +ARG REGISTRY=docker.io + +FROM $REGISTRY/cojedzie/base:$BASE_VERSION as base + +FROM php:7.4-fpm-alpine + +LABEL maintainer="Kacper Donat <kacper@kadet.net>" + +COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ + +WORKDIR /var/www + +RUN install-php-extensions bcmath intl opcache zip sockets; + +COPY composer.json composer.lock ./ + +COPY --from=base /var/www /var/www + +ENV APP_ENV=prod +ENV DATABASE_URL="sqlite:////var/db/app.db" +ENV PATH=$PATH:/var/www/bin + +VOLUME /var/db + +# This image is not meant to be run, just to prepare all required files +CMD ["/bin/false"] diff --git a/build/release.sh b/build/release.sh index ba72706..9dcf916 100755 --- a/build/release.sh +++ b/build/release.sh @@ -135,20 +135,22 @@ fi if [ $BUILD_BASE -eq 1 ]; then build --no-register base $ROOT/api/ || exit 1 + build --no-register --variant fpm base $ROOT/api/ || exit 1 + build --no-register --variant cli base $ROOT/api/ || exit 1 fi while [ $# -gt 0 ] do case "$1" in api) - build api $ROOT/api/ --variant rr --default || exit 1 - build api $ROOT/api/ --variant fpm || exit 1 + build api $BUILD/api/ --variant rr --default || exit 1 + build api $BUILD/api/ --variant fpm || exit 1 ;; standalone) - build standalone $ROOT/api/ --variant rr --default || exit 1 + build standalone $BUILD/standalone/ --variant rr --default || exit 1 ;; worker) - build worker $ROOT/api/ || exit 1 + build worker $BUILD/worker/ || exit 1 ;; front) build front $ROOT/front/ || exit 1 diff --git a/build/standalone/rr.Dockerfile b/build/standalone/rr.Dockerfile index 0fcd071..a41406d 100644 --- a/build/standalone/rr.Dockerfile +++ b/build/standalone/rr.Dockerfile @@ -3,13 +3,14 @@ ARG REGISTRY=docker.io FROM ${REGISTRY}/cojedzie/api:${BASE_VERSION}-rr -RUN apk add supervisor && \ +# escape=` +RUN apk add supervisor gettext && \ { \ echo '[supervisord]'; \ echo 'nodaemon=true'; \ echo ; \ echo '[program:roadrunner]'; \ - echo 'command=rr serve'; \ + echo 'command=rr serve -v'; \ echo 'startsecs=0'; \ echo 'start=true'; \ echo 'autorestart=true'; \ @@ -19,7 +20,7 @@ RUN apk add supervisor && \ echo 'stderr_logfile_maxbytes=0'; \ echo ; \ echo '[program:messenger-consumer]'; \ - echo 'command=php /var/www/bin/console messenger:consume main -vv --time-limit=86400 --limit=10'; \ + echo 'command=php /var/www/bin/console messenger:consume $COJEDZIE_WORKER_OPTS $COJEDZIE_WORKER_QUEUES'; \ echo 'startsecs=0'; \ echo 'start=true'; \ echo 'autorestart=true'; \ @@ -27,6 +28,11 @@ RUN apk add supervisor && \ echo 'stderr_logfile=/dev/stderr'; \ echo 'stdout_logfile_maxbytes=0'; \ echo 'stderr_logfile_maxbytes=0'; \ - } | tee /etc/supervisord.conf; + } | tee /etc/supervisord.conf.tpl; -CMD ["./bin/docker-init.sh", "supervisord", "-c", "/etc/supervisord.conf"] +COPY ./supervisord-init.sh ./bin/ + +ENV COJEDZIE_WORKER_QUEUES=main +ENV COJEDZIE_WORKER_OPTS="-vv --time-limit=86400 --limit=10 --memory-limit=128M" + +CMD ["./bin/supervisord-init.sh", "supervisord", "-c", "/etc/supervisord.conf"] diff --git a/build/standalone/supervisord-init.sh b/build/standalone/supervisord-init.sh new file mode 100755 index 0000000..a61b86e --- /dev/null +++ b/build/standalone/supervisord-init.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ -f /etc/supervisord.conf.tpl ]; then + envsubst < /etc/supervisord.conf.tpl > /etc/supervisord.conf +fi + +exec "$@" diff --git a/build/worker/Dockerfile b/build/worker/Dockerfile index eeb7cee..1fe0fc3 100644 --- a/build/worker/Dockerfile +++ b/build/worker/Dockerfile @@ -1,31 +1,15 @@ ARG BASE_VERSION=latest ARG REGISTRY=docker.io -FROM $REGISTRY/cojedzie/base:$BASE_VERSION as base +FROM $REGISTRY/cojedzie/base:${BASE_VERSION}-cli -FROM php:7.4-cli-alpine - -LABEL maintainer="Kacper Donat <kacper@kadet.net>" - -COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ - -WORKDIR /var/www - -RUN install-php-extensions bcmath intl opcache zip sockets; - -COPY --from=base /var/www /var/www - -ENV APP_ENV=prod -ENV DATABASE_URL="sqlite:////var/db/app.db" -ENV PATH=$PATH:/var/www/bin - -RUN apk add supervisor && \ +RUN apk add supervisor gettext && \ { \ echo '[supervisord]'; \ echo 'nodaemon=true'; \ echo ; \ echo '[program:messenger-consumer]'; \ - echo 'command=php /var/www/bin/console messenger:consume main -vv --time-limit=86400 --limit=10'; \ + echo 'command=php /var/www/bin/console messenger:consume $COJEDZIE_WORKER_OPTS $COJEDZIE_WORKER_QUEUES'; \ echo 'startsecs=0'; \ echo 'start=true'; \ echo 'autorestart=true'; \ @@ -33,8 +17,11 @@ RUN apk add supervisor && \ echo 'stderr_logfile=/dev/stderr'; \ echo 'stdout_logfile_maxbytes=0'; \ echo 'stderr_logfile_maxbytes=0'; \ - } | tee /etc/supervisord.conf; + } | tee /etc/supervisord.conf.tpl; -VOLUME /var/db +COPY ./supervisord-init.sh ./bin/ -CMD ["supervisord", "-c", "/etc/supervisord.conf"] +ENV COJEDZIE_WORKER_QUEUES=main +ENV COJEDZIE_WORKER_OPTS="-vv --time-limit=86400 --limit=10 --memory-limit=128M" + +CMD ["./bin/supervisord-init.sh", "supervisord", "-c", "/etc/supervisord.conf"] diff --git a/build/worker/supervisord-init.sh b/build/worker/supervisord-init.sh new file mode 100755 index 0000000..a61b86e --- /dev/null +++ b/build/worker/supervisord-init.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ -f /etc/supervisord.conf.tpl ]; then + envsubst < /etc/supervisord.conf.tpl > /etc/supervisord.conf +fi + +exec "$@" -- 2.45.2 From 7e0f31726fa6657e1bd9863c487f49d5624202b1 Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Tue, 20 Apr 2021 23:07:44 +0200 Subject: [PATCH 75/77] #50 - Add contribution guidelines and CLA --- CLA.md | 71 +++++++++++++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 38 +++++++++++++++++++++++ README.md | 19 ++++++++---- api/CONTRIBUTING.md | 3 ++ front/CONTRIBUTING.md | 3 ++ 5 files changed, 128 insertions(+), 6 deletions(-) create mode 100644 CLA.md create mode 100644 CONTRIBUTING.md create mode 100644 api/CONTRIBUTING.md create mode 100644 front/CONTRIBUTING.md diff --git a/CLA.md b/CLA.md new file mode 100644 index 0000000..4a8ef42 --- /dev/null +++ b/CLA.md @@ -0,0 +1,71 @@ +# Co Jedzie Individual Contributor License Agreement + +Adapted from http://www.apache.org/licenses/icla.txt © The Apache Software Foundation + +Thank you for your interest in Co Jedzie (the **"Project"**) by Kacper Donat (the **"Author"**). In order to clarify the +intellectual property license granted with Contributions from any person or entity, the Author must have a Contributor +License Agreement ("CLA") on file that has been signed by each Contributor, indicating agreement to the license terms +below. This license is for your protection as a Contributor as well as the protection of the Author and its users; it +does not change your rights to use your own Contributions for any other purpose. + +You accept and agree to the following terms and conditions for Your present and future Contributions submitted to the +Author. In return, the Author shall not use Your Contributions in a way that is contrary to the public benefit or +inconsistent with its bylaws in effect at the time of the Contribution. Except for the license granted herein to the +Author and recipients of software distributed by the Author, You reserve all right, title, and interest in and to Your +Contributions. + +1. Definitions. + - **"You"** (or **"Your"**) shall mean the copyright owner or legal entity authorized by the copyright owner that is + making this Agreement with the Author. For legal entities, the entity making a Contribution and all other entities + that control, are controlled by, or are under common control with that entity are considered to be a single + Contributor. For the purposes of this definition, **"control"** means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or + more of the outstanding shares, or (iii) beneficial ownership of such entity. + + - **"Contribution"** shall mean any original work of authorship, including any modifications or additions to an existing + work, that is intentionally submitted by You to the Author for inclusion in, or documentation of, any of the products + owned or managed by the Author (the **"Work"**). For the purposes of this definition, **"submitted"** means any form + of electronic, verbal, or written communication sent to the Author or its representatives, including but not limited + to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed + by, or on behalf of, the Author for the purpose of discussing and improving the Work, but excluding communication that + is conspicuously marked or otherwise designated in writing by You as **"Not a Contribution."** + +2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to the Author and + to recipients of software distributed by the Author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, + irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, + sublicense, re-license, and distribute Your Contributions and such derivative works. + +3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to the Author and to + recipients of software distributed by the Author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, + irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, + and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are + necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which + such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity ( + including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have + contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity + under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed. + +4. You represent that you are legally entitled to grant the above license. If your employer(s) has rights to + intellectual property that you create that includes your Contributions, you represent that you have received + permission to make Contributions on behalf of that employer, that your employer has waived such rights for your + Contributions to the Author, or that your employer has executed a separate Corporate CLA with the Author. + +5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of + others). You represent that Your Contribution submissions include complete details of any third-party license or + other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware + and which are associated with any part of Your Contributions. + +6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. + You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in + writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + express or implied, including, without limitation, any warranties or conditions of TITLE, NON- INFRINGEMENT, + MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + +7. Should You wish to submit work that is not Your original creation, You may submit it to the Author separately from + any Contribution, identifying the complete details of its source and of any license or other restriction (including, + but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and + conspicuously marking the work as "Submitted on behalf of a third-party: [named here]". + +8. You agree to notify the Author of any facts or circumstances of which you become aware that would make these + representations inaccurate in any respect. + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..040b0b0 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,38 @@ +# How to contribute? + +Thanks for your interest in the project! + +## I'd like to propose some feature / change... + +Cool! Go ahead, [create an issue] and describe your proposal so anyone can see it. You can also vote on features that +you want the most. + +## I've found a bug! + +Well, less cool! Before creating an issue, please check if the bug remains after hard refreshing (usually `ctrl+F5`) the +application. If the answer is yes, or this is not the first encounter of it please [create an issue] and describe the +problem. If you can, please attach screenshots (especially if this is visual bug), and console logs (especially for +connection problems) - this will help to reproduce the problem. + +## I've got some spare resources on my server... +Soon you will be able to help the project by hosting your own API node that will be available for clients to use. +More details to come soon. + +## I want to contribute some code... + +That's great! If you want to make changes to API (which is responsible for collecting and supplying applicaiton with +data) please check the [API contribution guidelines], if you are interested in UI side of the app please read the +[frontend contribution guidelines]. + +### Contributor License Agreement + +Unfortunately due to this project nature and license I need you to sign [Contributor License Agreement] - the nice thing +is that it can be done with simple push of a button! **You still will have full copyright to your contribution** but +basically you consent that you are entitled to code you are submitting and also to allow me to license this project on +other terms if needed to, for example, local governments. If you don't want to sign - I understand - but I won't be able +to accept your contribution :( + +[Contributor License Agreement]: ./CLA.md +[create an issue]: https://github.com/cojedzie/cojedzie/issues/new +[API contribution guidelines]: ./api/CONTRIBUTING.md +[frontend contribution guidelines]: ./front/CONTRIBUTING.md diff --git a/README.md b/README.md index 7bcd15a..be9b2a7 100644 --- a/README.md +++ b/README.md @@ -7,19 +7,26 @@ aims to be the central hub for all public transport information you will need. You can use the app at [cojedzie.pl](https://cojedzie.pl). -## Contributing -Want to contribute? - - ## Roadmap Co Jedzie is in active development, roadmap of the project can be found on [trello]. This roadmap is regularly updated -and represents current state of the project. Feel free to take a look. +and represents current state of the project. Feel free to take a look. + +### Contributing to roadmap +If you have found a bug or want to propose some changes feel free to create an [issue] explaining your proposal or +problem. Issue management and discussion would be done on the github, but planning will be carried away to the [trello] +trello with linked issue. + +## Contributing +Wan't to contribute? Nice! Please see [CONTRIBUTING.md] ## License This project is [fair-code](https://faircode.io/) licensed under [MIT with Commons Clause](./LICENSE.md). Basically, Co -Jedzie is free and code is available to everyone, but it's not allowed to make money directly with it. +Jedzie is free and code is available to everyone, but it's not allowed to make money directly with it without +authors permission. Note that data collected from available data sources is licensed by their respective owners, thus it may be available under different terms than the project itself and may require additional permissions to use. [trello]: https://trello.com/b/QXqDvmoG/co-jedzie +[issue]: https://github.com/cojedzie/cojedzie/issues/new +[CONTRIBUTING.md]: ./CONTRIBUTING.md diff --git a/api/CONTRIBUTING.md b/api/CONTRIBUTING.md new file mode 100644 index 0000000..6ca8468 --- /dev/null +++ b/api/CONTRIBUTING.md @@ -0,0 +1,3 @@ +# Contributing guidelines + +TBD diff --git a/front/CONTRIBUTING.md b/front/CONTRIBUTING.md new file mode 100644 index 0000000..6ca8468 --- /dev/null +++ b/front/CONTRIBUTING.md @@ -0,0 +1,3 @@ +# Contributing guidelines + +TBD -- 2.45.2 From 5ff422a5f7cf681054ca20db492db5430cf4fb2e Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Wed, 21 Apr 2021 21:29:07 +0200 Subject: [PATCH 76/77] #50 - Add cleanup after request for RoadRunner --- .docker-compose/nginx/cojedzie-rr.conf | 31 +++++++++++++ api/Dockerfile | 2 - api/rr.Dockerfile | 29 +++++++++++++ .../WithDestinationsDatabaseHandler.php | 2 +- .../Provider/ZtmGdansk/ZtmGdanskProvider.php | 17 ++++++-- api/src/Service/AggregateConverter.php | 4 +- api/src/Service/CacheableConverter.php | 5 ++- api/src/Service/EntityConverter.php | 6 +-- .../Subscriber/RequestCleanupSubscriber.php | 39 +++++++++++++++++ docker-compose.rr.yml | 43 +++++++++++++++++++ 10 files changed, 163 insertions(+), 15 deletions(-) create mode 100644 .docker-compose/nginx/cojedzie-rr.conf create mode 100644 api/rr.Dockerfile create mode 100644 api/src/Subscriber/RequestCleanupSubscriber.php create mode 100644 docker-compose.rr.yml diff --git a/.docker-compose/nginx/cojedzie-rr.conf b/.docker-compose/nginx/cojedzie-rr.conf new file mode 100644 index 0000000..9664cb5 --- /dev/null +++ b/.docker-compose/nginx/cojedzie-rr.conf @@ -0,0 +1,31 @@ +server { + root /var/www/front/public/; + + server_name cojedzie.localhost; + + location /_profiler/ { + try_files $uri $uri/ @api; + } + + location /bundles/ { + try_files $uri $uri/ @api; + } + + location /api/ { + try_files $uri $uri/ @api; + } + + location / { + try_files $uri $uri/ @frontend; + } + + location @frontend { + proxy_pass http://frontend:3000; + proxy_intercept_errors on; + } + + location @api { + proxy_pass http://api:8080; + proxy_intercept_errors on; + } +} diff --git a/api/Dockerfile b/api/Dockerfile index acf47c7..710ad89 100644 --- a/api/Dockerfile +++ b/api/Dockerfile @@ -1,7 +1,5 @@ FROM php:7.4-fpm-alpine -ENV DATABASE_URL="sqlite:///var/db/app.db" - COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ COPY --from=composer:latest /usr/bin/composer /usr/bin/composer diff --git a/api/rr.Dockerfile b/api/rr.Dockerfile new file mode 100644 index 0000000..0f6dd9e --- /dev/null +++ b/api/rr.Dockerfile @@ -0,0 +1,29 @@ +FROM cojedzie/api:latest-rr + +COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +RUN install-php-extensions xdebug-^3.0; +RUN apk add git; + +# XDebug +RUN echo "xdebug.mode=debug" >> $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini && \ + echo "xdebug.client_host=172.17.0.1" >> $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini && \ + echo "xdebug.start_with_request=On" >> $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini; + +# Blackfire +RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \ + && curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/amd64/$version \ + && mkdir -p /tmp/blackfire \ + && tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \ + && mv /tmp/blackfire/blackfire-*.so $(php -r "echo ini_get ('extension_dir');")/blackfire.so \ + && printf "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8707\n" > $PHP_INI_DIR/conf.d/blackfire.ini \ + && rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz + +# Timezone +RUN ln -snf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime && \ + echo "date.timezone = Europe/Warsaw" >> /usr/local/etc/php/conf.d/datetime.ini; + +WORKDIR /var/www + +EXPOSE 9001 diff --git a/api/src/Handler/Database/WithDestinationsDatabaseHandler.php b/api/src/Handler/Database/WithDestinationsDatabaseHandler.php index 8c1df7c..b159371 100644 --- a/api/src/Handler/Database/WithDestinationsDatabaseHandler.php +++ b/api/src/Handler/Database/WithDestinationsDatabaseHandler.php @@ -29,7 +29,7 @@ class WithDestinationsDatabaseHandler implements PostProcessingHandler if ($this->converter instanceof CacheableConverter) { $this->converter = clone $this->converter; - $this->converter->flushCache(); + $this->converter->reset(); } } diff --git a/api/src/Provider/ZtmGdansk/ZtmGdanskProvider.php b/api/src/Provider/ZtmGdansk/ZtmGdanskProvider.php index 0428860..35035ea 100644 --- a/api/src/Provider/ZtmGdansk/ZtmGdanskProvider.php +++ b/api/src/Provider/ZtmGdansk/ZtmGdanskProvider.php @@ -28,11 +28,11 @@ class ZtmGdanskProvider implements Provider private $stops; private $tracks; private $messages; - - /** @var ProviderEntity */ - private $entity; private $trips; + private ProviderEntity $entity; + private EntityManagerInterface $em; + public function getName(): string { return 'MZKZG - Trójmiasto'; @@ -68,7 +68,9 @@ class ZtmGdanskProvider implements Provider ZtmGdanskMessageRepository $messages, ReferenceFactory $referenceFactory ) { - $provider = $em->getReference(ProviderEntity::class, $this->getIdentifier()); + $this->em = $em; + + $provider = $this->refreshProviderEntity(); $lines = $lines->withProvider($provider); $stops = $stops->withProvider($provider); @@ -117,6 +119,13 @@ class ZtmGdanskProvider implements Provider public function getLastUpdate(): ?Carbon { + $this->refreshProviderEntity(); + return $this->entity->getUpdateDate(); } + + private function refreshProviderEntity(): ProviderEntity + { + return $this->entity = $this->em->getReference(ProviderEntity::class, $this->getIdentifier()); + } } diff --git a/api/src/Service/AggregateConverter.php b/api/src/Service/AggregateConverter.php index 6957415..f56b1ed 100644 --- a/api/src/Service/AggregateConverter.php +++ b/api/src/Service/AggregateConverter.php @@ -45,7 +45,7 @@ class AggregateConverter implements Converter, CacheableConverter return clone $this->cachedConverters; } - public function flushCache() + public function reset() { $this->ensureCachedConverters(); @@ -53,7 +53,7 @@ class AggregateConverter implements Converter, CacheableConverter ->cachedConverters ->filter(instance(CacheableConverter::class)) ->each(function (CacheableConverter $converter) { - $converter->flushCache(); + $converter->reset(); }) ; } diff --git a/api/src/Service/CacheableConverter.php b/api/src/Service/CacheableConverter.php index cf590df..e67996c 100644 --- a/api/src/Service/CacheableConverter.php +++ b/api/src/Service/CacheableConverter.php @@ -2,7 +2,8 @@ namespace App\Service; -interface CacheableConverter extends Converter +use Symfony\Contracts\Service\ResetInterface; + +interface CacheableConverter extends Converter, ResetInterface { - public function flushCache(); } diff --git a/api/src/Service/EntityConverter.php b/api/src/Service/EntityConverter.php index 1104077..75e265a 100644 --- a/api/src/Service/EntityConverter.php +++ b/api/src/Service/EntityConverter.php @@ -2,14 +2,12 @@ namespace App\Service; -use App\Entity\{Entity, LineEntity, OperatorEntity, StopEntity, TrackEntity, TripEntity, TripStopEntity}; +use App\Entity\{Entity, LineEntity, OperatorEntity, StopEntity, TrackEntity, TripEntity}; use App\Model\{Line, Location, Operator, ScheduledStop, Stop, Track, Trip}; use App\Service\Proxy\ReferenceFactory; use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\Proxy\Proxy; -use Kadet\Functional as f; use Kadet\Functional\Transforms as t; -use const Kadet\Functional\_; final class EntityConverter implements Converter, RecursiveConverter, CacheableConverter { @@ -177,7 +175,7 @@ final class EntityConverter implements Converter, RecursiveConverter, CacheableC return $entity instanceof Entity; } - public function flushCache() + public function reset() { $this->cache = []; } diff --git a/api/src/Subscriber/RequestCleanupSubscriber.php b/api/src/Subscriber/RequestCleanupSubscriber.php new file mode 100644 index 0000000..ac84b85 --- /dev/null +++ b/api/src/Subscriber/RequestCleanupSubscriber.php @@ -0,0 +1,39 @@ +<?php + +namespace App\Subscriber; + +use App\Service\Converter; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\Event\TerminateEvent; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Contracts\Service\ResetInterface; + +class RequestCleanupSubscriber implements EventSubscriberInterface +{ + /** @var ContainerInterface */ + private ContainerInterface $container; + private Converter $converter; + + public function __construct(ContainerInterface $container, Converter $converter) + { + $this->container = $container; + $this->converter = $converter; + } + + public static function getSubscribedEvents() + { + return [ + KernelEvents::TERMINATE => ['onTerminate'] + ]; + } + + public function onTerminate(TerminateEvent $event) + { + $this->container->get('doctrine')->reset(); + + if ($this->converter instanceof ResetInterface) { + $this->converter->reset(); + } + } +} diff --git a/docker-compose.rr.yml b/docker-compose.rr.yml new file mode 100644 index 0000000..1b7b518 --- /dev/null +++ b/docker-compose.rr.yml @@ -0,0 +1,43 @@ +version: '3.4' + +services: + nginx: + image: nginx:latest + ports: + - "8080:80" + volumes: + - ./front:/var/www/front:cached + - ./api:/var/www/api:cached + - .docker-compose/nginx/cojedzie-rr.conf:/etc/nginx/conf.d/cojedzie-rr.conf + + api: + build: + context: ./api + dockerfile: rr.Dockerfile + env_file: + - .docker-compose/api/.env + - api/.env.local + environment: + - TRUSTED_PROXIES=172.0.0.0/8 + ports: + - 8888:8080 + volumes: + - ./api:/var/www:cached + - .docker-compose/api/log.conf:/usr/local/etc/php-fpm.d/zz-log.conf + command: ["rr", "serve", "-c", ".rr.yaml"] + + frontend: + image: node:15.2.1 + working_dir: /app + environment: + - APP_API=http://nginx/api + volumes: + - ./front:/app + command: ["node", "build/server.js"] + + blackfire: + image: blackfire/blackfire + ports: ["8707"] + environment: + - BLACKFIRE_SERVER_ID + - BLACKFIRE_SERVER_TOKEN -- 2.45.2 From 3777c45c1601fc7e58ec14dc0a6f031b74ffffaf Mon Sep 17 00:00:00 2001 From: Kacper Donat <kadet1090@gmail.com> Date: Thu, 22 Apr 2021 15:55:05 +0200 Subject: [PATCH 77/77] #50 - Add missing DATABSE_URL to base Dockerimage --- build/base/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/base/Dockerfile b/build/base/Dockerfile index 818a928..0e343ab 100644 --- a/build/base/Dockerfile +++ b/build/base/Dockerfile @@ -21,6 +21,8 @@ RUN apk add git && \ COPY . . ENV APP_ENV=prod +ENV DATABASE_URL="sqlite:////var/db/app.db" +ENV PATH=$PATH:/var/www/bin RUN composer run-script post-install-cmd -- 2.45.2