diff --git a/.copilot/categories-analysis.md b/.copilot/categories-analysis.md new file mode 100644 index 00000000..6dfb52f9 --- /dev/null +++ b/.copilot/categories-analysis.md @@ -0,0 +1,49 @@ +Current DB & Models Analysis — 2026-02-10 + +Summary +- `content_types` is the master namespace (see screenshot). Rows: e.g. id=1 Photography (slug `photography`), id=2 Wallpapers, id=3 Skins, id=544 Members. +- `categories` references `content_types` through `content_type_id`; hierarchical parent/child relation via `parent_id`. + +Observed DB columns (categories) +- id, content_type_id, parent_id, name, slug, description, image, is_active, sort_order, created_at, updated_at, deleted_at + +Models verified +- `ContentType` (app/Models/ContentType.php) + - hasMany `categories()` and `rootCategories()` + - uses `slug` for route binding + - Status: OK and aligns with DB + +- `Category` (app/Models/Category.php) + - belongsTo `contentType()` + - self-referential `parent()` / `children()` (ordered by `sort_order`, then `name`) + - `descendants()` recursive helper + - `seo()` relation, `artworks()` pivot + - scopes: `active()`, `roots()` + - accessors: `full_slug_path`, `url`, `canonical_url`, `breadcrumbs` + - slug validation enforced in `boot()` (lowercase; only a-z0-9- and dashes) + - Status: OK and consistent with screenshots + +Key behaviors and checks +- URL formation: `$category->url` -> `/{content_type.slug}/{category_path}`; canonical URL -> `https://skinbase.org{url}` +- Slug policy: generation with `Str::slug()` + model validation. Do not bypass. +- Ordering: use `children()` (sort_order then name) for deterministic menus. +- Soft deletes: model uses `SoftDeletes`; be explicit when you need trashed categories. +- Eager-loading: `full_slug_path` walks parents — eager-load `parent` (or ancestors) to avoid N+1 when computing multiple paths. + +Copilot / Dev rules (short checklist) +- Always look up content types by `slug`, not by numeric ID. +- Use `->roots()->active()->with('children')` for public category lists. +- Use `$category->url` and `$category->canonical_url` for links and canonical tags. +- Maintain slug rules: lowercase, only `a-z0-9-`. +- When reparenting categories, consider invalidating any cached derived paths for descendants. +- Avoid using legacy `artworks_categories` directly in new controllers; create an adapter if you must read old data. + +Suggested next steps +- Add a PHPUnit test asserting slug validation and `url` generation for nested categories. +- (Optional) Generate a small ER diagram showing `content_types -> categories -> artwork_category`. + +Files referenced +- [app/Models/ContentType.php](app/Models/ContentType.php) +- [app/Models/Category.php](app/Models/Category.php) + +If you want, I can now add the PHPUnit test or generate the ER diagram. diff --git a/.env.example b/.env.example index 026add8e..41fd0ce4 100644 --- a/.env.example +++ b/.env.example @@ -45,6 +45,150 @@ BROADCAST_CONNECTION=log FILESYSTEM_DISK=local QUEUE_CONNECTION=database +# Upload UI feature flag (legacy upload remains default unless explicitly enabled) +SKINBASE_UPLOADS_V2=false + +# Draft abuse prevention controls +SKINBASE_MAX_DRAFTS=10 +SKINBASE_MAX_DRAFT_STORAGE_MB=1024 +SKINBASE_DUPLICATE_HASH_POLICY=block + +# Vision / AI auto-tagging (local defaults) +VISION_ENABLED=true +VISION_QUEUE=default +VISION_IMAGE_VARIANT=md + +# CLIP service (set base URL to enable CLIP calls) +CLIP_BASE_URL= +CLIP_ANALYZE_ENDPOINT=/analyze +CLIP_TIMEOUT_SECONDS=8 +CLIP_CONNECT_TIMEOUT_SECONDS=2 +CLIP_HTTP_RETRIES=1 +CLIP_HTTP_RETRY_DELAY_MS=200 +CLIP_EMBED_ENDPOINT=/embed +CLIP_EMBED_TIMEOUT_SECONDS=8 +CLIP_EMBED_CONNECT_TIMEOUT_SECONDS=2 +CLIP_EMBED_HTTP_RETRIES=1 +CLIP_EMBED_HTTP_RETRY_DELAY_MS=200 + +# Similar artworks / embedding pipeline +RECOMMENDATIONS_QUEUE=${VISION_QUEUE} +RECOMMENDATIONS_EMBEDDING_ENABLED=true +RECOMMENDATIONS_EMBEDDING_MODEL=clip +RECOMMENDATIONS_EMBEDDING_MODEL_VERSION=v1 +RECOMMENDATIONS_ALGO_VERSION=clip-cosine-v1 +RECOMMENDATIONS_AB_ALGO_VERSIONS=clip-cosine-v1 +RECOMMENDATIONS_MIN_DIM=64 +RECOMMENDATIONS_MAX_DIM=4096 +RECOMMENDATIONS_BACKFILL_BATCH=200 + +# Personalized discovery foundation (Phase 8) +DISCOVERY_QUEUE=${RECOMMENDATIONS_QUEUE} +DISCOVERY_PROFILE_VERSION=profile-v1 +DISCOVERY_EVENT_VERSION=event-v1 +DISCOVERY_ALGO_VERSION=${RECOMMENDATIONS_ALGO_VERSION} +DISCOVERY_CACHE_VERSION=cache-v1 +DISCOVERY_DECAY_HALF_LIFE_HOURS=72 +DISCOVERY_WEIGHT_VIEW=1 +DISCOVERY_WEIGHT_CLICK=2 +DISCOVERY_WEIGHT_FAVORITE=4 +DISCOVERY_WEIGHT_DOWNLOAD=3 +DISCOVERY_CACHE_TTL_MINUTES=60 +DISCOVERY_RANKING_WEIGHTS_VERSION=rank-w-v1 +DISCOVERY_RANKING_W1=0.65 +DISCOVERY_RANKING_W2=0.20 +DISCOVERY_RANKING_W3=0.10 +DISCOVERY_RANKING_W4=0.05 +DISCOVERY_RANKING_WEIGHTS_VERSION_CLIP_COSINE_V1=rank-w-v1 +DISCOVERY_RANKING_W1_CLIP_COSINE_V1=0.65 +DISCOVERY_RANKING_W2_CLIP_COSINE_V1=0.20 +DISCOVERY_RANKING_W3_CLIP_COSINE_V1=0.10 +DISCOVERY_RANKING_W4_CLIP_COSINE_V1=0.05 +DISCOVERY_RANKING_WEIGHTS_VERSION_CLIP_COSINE_V2=rank-w-v2-prod-1 +DISCOVERY_RANKING_W1_CLIP_COSINE_V2=0.52 +DISCOVERY_RANKING_W2_CLIP_COSINE_V2=0.23 +DISCOVERY_RANKING_W3_CLIP_COSINE_V2=0.15 +DISCOVERY_RANKING_W4_CLIP_COSINE_V2=0.10 +DISCOVERY_ROLLOUT_ENABLED=false +DISCOVERY_ROLLOUT_BASELINE_ALGO_VERSION=clip-cosine-v1 +DISCOVERY_ROLLOUT_CANDIDATE_ALGO_VERSION=clip-cosine-v2 +DISCOVERY_ROLLOUT_ACTIVE_GATE=g10 +DISCOVERY_ROLLOUT_GATE_10_PERCENT=10 +DISCOVERY_ROLLOUT_GATE_50_PERCENT=50 +DISCOVERY_ROLLOUT_GATE_100_PERCENT=100 +DISCOVERY_FORCE_ALGO_VERSION= +DISCOVERY_ROLLOUT_WARN_CTR_DROP_PCT=3 +DISCOVERY_ROLLOUT_ROLLBACK_CTR_DROP_PCT=5 +DISCOVERY_ROLLOUT_WARN_LONG_DWELL_DROP_PCT=4 +DISCOVERY_ROLLOUT_ROLLBACK_LONG_DWELL_DROP_PCT=8 +DISCOVERY_ROLLOUT_WARN_DIVERSITY_CONCENTRATION_RISE_PCT=10 +DISCOVERY_ROLLOUT_ROLLBACK_DIVERSITY_CONCENTRATION_RISE_PCT=15 +DISCOVERY_EVAL_WEIGHT_CTR=0.45 +DISCOVERY_EVAL_WEIGHT_SAVE_RATE=0.35 +DISCOVERY_EVAL_WEIGHT_LONG_DWELL=0.25 +DISCOVERY_EVAL_WEIGHT_BOUNCE_PENALTY=0.15 +DISCOVERY_EVAL_SAVE_RATE_INFORMATIONAL=true + +# YOLO service (optional) +YOLO_ENABLED=true +YOLO_BASE_URL= +YOLO_ANALYZE_ENDPOINT=/analyze +YOLO_TIMEOUT_SECONDS=8 +YOLO_CONNECT_TIMEOUT_SECONDS=2 +YOLO_HTTP_RETRIES=1 +YOLO_HTTP_RETRY_DELAY_MS=200 +YOLO_PHOTOGRAPHY_ONLY=true + +# ----------------------------------------------------------------------------- +# Production examples (uncomment and adjust) +# ----------------------------------------------------------------------------- +# VISION_ENABLED=true +# VISION_QUEUE=vision +# VISION_IMAGE_VARIANT=md +# +# CLIP_BASE_URL=https://clip.internal +# CLIP_ANALYZE_ENDPOINT=/analyze +# CLIP_TIMEOUT_SECONDS=5 +# CLIP_CONNECT_TIMEOUT_SECONDS=1 +# CLIP_HTTP_RETRIES=1 +# CLIP_HTTP_RETRY_DELAY_MS=150 +# CLIP_EMBED_ENDPOINT=/embed +# CLIP_EMBED_TIMEOUT_SECONDS=5 +# CLIP_EMBED_CONNECT_TIMEOUT_SECONDS=1 +# CLIP_EMBED_HTTP_RETRIES=1 +# CLIP_EMBED_HTTP_RETRY_DELAY_MS=150 +# RECOMMENDATIONS_QUEUE=vision +# RECOMMENDATIONS_EMBEDDING_ENABLED=true +# RECOMMENDATIONS_EMBEDDING_MODEL=clip +# RECOMMENDATIONS_EMBEDDING_MODEL_VERSION=v1 +# RECOMMENDATIONS_ALGO_VERSION=clip-cosine-v1 +# RECOMMENDATIONS_AB_ALGO_VERSIONS=clip-cosine-v1,clip-cosine-v2 +# RECOMMENDATIONS_BACKFILL_BATCH=250 +# DISCOVERY_QUEUE=vision +# DISCOVERY_PROFILE_VERSION=profile-v1 +# DISCOVERY_EVENT_VERSION=event-v1 +# DISCOVERY_ALGO_VERSION=clip-cosine-v1 +# DISCOVERY_CACHE_VERSION=cache-v1 +# DISCOVERY_DECAY_HALF_LIFE_HOURS=72 +# DISCOVERY_WEIGHT_VIEW=1 +# DISCOVERY_WEIGHT_CLICK=2 +# DISCOVERY_WEIGHT_FAVORITE=4 +# DISCOVERY_WEIGHT_DOWNLOAD=3 +# DISCOVERY_RANKING_WEIGHTS_VERSION=rank-w-v1 +# DISCOVERY_RANKING_W1=0.65 +# DISCOVERY_RANKING_W2=0.20 +# DISCOVERY_RANKING_W3=0.10 +# DISCOVERY_RANKING_W4=0.05 +# +# YOLO_ENABLED=true +# YOLO_BASE_URL=https://yolo.internal +# YOLO_ANALYZE_ENDPOINT=/analyze +# YOLO_TIMEOUT_SECONDS=5 +# YOLO_CONNECT_TIMEOUT_SECONDS=1 +# YOLO_HTTP_RETRIES=1 +# YOLO_HTTP_RETRY_DELAY_MS=150 +# YOLO_PHOTOGRAPHY_ONLY=true + CACHE_STORE=database # CACHE_PREFIX= diff --git a/README.md b/README.md index 0165a773..eded3fb6 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,372 @@ In order to ensure that the Laravel community is welcoming to all, please review If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed. +## Vision & AI Auto-Tagging Integration + +## Upload UI Feature Flag (`uploads.v2`) + +The new React upload wizard is behind a feature flag and is **disabled by default**. + +- Flag env var: `SKINBASE_UPLOADS_V2` +- Config key: `features.uploads_v2` +- Client flags source: `window.SKINBASE_FLAGS` + +### Default behavior + +- `SKINBASE_UPLOADS_V2=false` → legacy upload UI is rendered. +- `SKINBASE_UPLOADS_V2=true` → `UploadWizard` is rendered. + +### Setup + +In `.env` (or `.env.example` for project defaults): + +```dotenv +SKINBASE_UPLOADS_V2=false +``` + +Enable explicitly when ready: + +```dotenv +SKINBASE_UPLOADS_V2=true +``` + +After changing env values, clear/reload config as usual: + +```bash +php artisan config:clear +``` + +The system intentionally keeps legacy upload as the default until the flag is explicitly turned on. + +## Upload Moderation UI Flow + +Admin moderation for draft uploads is available through a dedicated queue page. + +- Page route: `/admin/uploads/moderation` +- Access: authenticated users with `role=admin` or `role=moderator` +- Data source: `GET /api/admin/uploads/pending` + +### Queue behavior + +1. The page loads pending draft uploads (`moderation_status=pending`). +2. Moderators can enter an optional note per upload. +3. Approve action calls: + + - `POST /api/admin/uploads/{id}/approve` + - Sets moderation to approved and records moderator + timestamp. + +4. Reject action calls: + + - `POST /api/admin/uploads/{id}/reject` + - Sets upload status/processing state to rejected and stores note. + +### Publish gate + +- Normal users can publish only when `moderation_status=approved`. +- Admin users can publish with override behavior. + +## Similar Artworks Analytics (A/B Evaluation) + +The artwork page similar-items block emits two event types: + +- `impression` (block rendered) +- `click` (item clicked) + +Events are stored in `similar_artwork_events` and aggregated daily into `similar_artwork_daily_metrics` by `algo_version`. + +- Ingest endpoint: `POST /api/analytics/similar-artworks` +- Aggregation command: `php artisan analytics:aggregate-similar-artworks --date=YYYY-MM-DD` +- Scheduler: runs daily at `03:10` + +## Personalized Discovery Foundation (Phase 8) + +This foundation adds versioned, async-only ingestion and profile normalization for personalized discovery. + +- Tables: + - `user_interest_profiles` + - `user_discovery_events` + - `user_recommendation_cache` +- Ingest endpoint: `POST /api/discovery/events` (auth required) +- Supported event types: `view`, `click`, `favorite`, `download` +- Processing model: non-blocking queue job (`IngestUserDiscoveryEventJob`) +- Normalization: recency-decay + score normalization in `UserInterestProfileService` + +No feed ranking/UI behavior is introduced in this foundation step. + +### Feed Endpoint Skeleton + +The backend now exposes a personalized feed API skeleton: + +- Endpoint: `GET /api/v1/feed` (auth required) +- Query params: + - `limit` (1-50, default 24) + - `cursor` (opaque cursor token for pagination) + - `algo_version` (optional override) +- Response includes `data` items and `meta.next_cursor` for cursor pagination. + +Behavior: + +- Reads `user_recommendation_cache` by `user_id + algo_version`. +- On cache miss/stale, returns immediate fallback results and dispatches async regeneration job. +- Regeneration runs in queue (`RegenerateUserRecommendationCacheJob`) and writes refreshed cache. +- Includes cold-start fallback (`popular + similar`) and a diversity guard to avoid near-duplicates. + +## Feed Analytics Instrumentation + +Feed analytics now track: + +- `feed_impression` +- `feed_click` + +Payload dimensions: + +- `user_id` (derived from auth session) +- `artwork_id` +- `position` +- `algo_version` +- `source` (`personalized`, `cold_start`, `fallback`) + +Optional: + +- `dwell_seconds` (for click dwell bucket metrics) + +Endpoints: + +- Ingest: `POST /api/analytics/feed` (auth required) +- Daily aggregation: `php artisan analytics:aggregate-feed --date=YYYY-MM-DD` +- Admin report: `GET /api/admin/reports/feed-performance` + +Daily metrics include CTR, save-rate, and dwell buckets. + +For non-blocking client transport, use `navigator.sendBeacon` with `fetch(..., { keepalive: true })` fallback. +Reference helper: `resources/js/lib/feedAnalytics.js`. + +## Phase 8B: Ranking Weight Tuning (Manual + Data-Driven) + +Discovery ranking now supports versioned blend weights per `algo_version` in `config/discovery.php`. + +- Blend terms: `w1` interest, `w2` recency, `w3` popularity, `w4` novelty +- Per-algo sets: `discovery.ranking.algo_weight_sets` +- Safe rollout: deterministic traffic split by `algo_version` with config gates (`g10`, `g50`, `g100`) +- Emergency rollback: `DISCOVERY_FORCE_ALGO_VERSION=clip-cosine-v1` + +Offline evaluator and A/B helper: + +- Evaluate objective across one/all algos: + - `php artisan analytics:evaluate-feed-weights --from=YYYY-MM-DD --to=YYYY-MM-DD` + - Optional: `--algo=clip-cosine-v1` +- Baseline vs candidate comparison: + - `php artisan analytics:compare-feed-ab clip-cosine-v1 clip-cosine-v2 --from=YYYY-MM-DD --to=YYYY-MM-DD` + +Objective score uses `feed_daily_metrics` and configurable objective weights in `discovery.evaluation.objective_weights`. + +Temporary production policy: set `DISCOVERY_EVAL_SAVE_RATE_INFORMATIONAL=true` to keep `save_rate` visible but excluded from objective score until save-event ingestion is verified. + +Operational runbook: `docs/feed-rollout-runbook.md`. + +## Operations / Runbooks + +- Upload UI v2 rollout, post-deploy monitoring, and rollback: `docs/ui/upload-v2-rollout-runbook.md` +- Feed rollout and rollback: `docs/feed-rollout-runbook.md` + +No automatic tuning is enabled in this phase. + +Skinbase uses asynchronous AI tagging via `AutoTagArtworkJob`. +The job calls external vision services (CLIP and optional YOLO), normalizes tags, and attaches them through `TagService` as AI tags with confidence values. + +### Critical Safety Rule + +⚠️ **Publish must never depend on vision services.** + +- Upload/publish flow dispatches AI tagging to queue after publish work. +- Vision failures, timeouts, or service outages must not block artwork publish. +- If AI tagging fails, artwork remains published and can be tagged later (retry/manual/batch). + +### Environment Variables (Vision) + +Set these in `.env` (all are optional; defaults are in `config/vision.php`): + +#### Global + +- `VISION_ENABLED` (default: `true`) + - Master switch for all AI auto-tagging. +- `VISION_QUEUE` (default: `default`) + - Queue name used by `AutoTagArtworkJob`. +- `VISION_IMAGE_VARIANT` (default: `md`) + - Derivative variant sent to vision services (e.g. `md`, `lg`). + +#### CLIP + +- `CLIP_BASE_URL` (default: empty) + - Base URL for CLIP service (example: `https://clip.internal`). + - If empty, CLIP call is skipped. +- `CLIP_ANALYZE_ENDPOINT` (default: `/analyze`) + - Path appended to `CLIP_BASE_URL`. +- `CLIP_TIMEOUT_SECONDS` (default: `8`) + - Request timeout for CLIP calls. +- `CLIP_CONNECT_TIMEOUT_SECONDS` (default: `2`) + - Connection timeout for CLIP calls. +- `CLIP_HTTP_RETRIES` (default: `1`) + - HTTP retry attempts for CLIP requests. +- `CLIP_HTTP_RETRY_DELAY_MS` (default: `200`) + - Delay between CLIP retries. + +#### YOLO (optional) + +- `YOLO_ENABLED` (default: `true`) + - Enables YOLO integration. +- `YOLO_BASE_URL` (default: empty) + - Base URL for YOLO service. If empty, YOLO call is skipped. +- `YOLO_ANALYZE_ENDPOINT` (default: `/analyze`) + - Path appended to `YOLO_BASE_URL`. +- `YOLO_TIMEOUT_SECONDS` (default: `8`) + - Request timeout for YOLO calls. +- `YOLO_CONNECT_TIMEOUT_SECONDS` (default: `2`) + - Connection timeout for YOLO calls. +- `YOLO_HTTP_RETRIES` (default: `1`) + - HTTP retry attempts for YOLO requests. +- `YOLO_HTTP_RETRY_DELAY_MS` (default: `200`) + - Delay between YOLO retries. +- `YOLO_PHOTOGRAPHY_ONLY` (default: `true`) + - When `true`, YOLO is called only for artworks in photography content type. + +### Expected CLIP Response Format + +CLIP `/analyze` should return tags as either a direct list or under `tags` / `data`: + +```json +[ + { "tag": "cyberpunk", "confidence": 0.42 }, + { "tag": "city", "confidence": 0.31 } +] +``` + +Also accepted: + +```json +{ + "tags": [ + { "tag": "cyberpunk", "confidence": 0.42 } + ] +} +``` + +or + +```json +{ + "data": [ + { "tag": "cyberpunk", "confidence": 0.42 } + ] +} +``` + +### Expected YOLO Response Format + +YOLO may return the same tag list format as CLIP, or object detections: + +```json +{ + "objects": [ + { "label": "person", "confidence": 0.91 }, + { "label": "camera", "confidence": 0.67 } + ] +} +``` + +`label` values are converted to tags, confidence is preserved when present. + +### AutoTagArtworkJob Behavior + +- Calls CLIP `/analyze` when `VISION_ENABLED=true` and `CLIP_BASE_URL` is set. +- Optionally calls YOLO based on `YOLO_ENABLED` and `YOLO_PHOTOGRAPHY_ONLY`. +- Merges CLIP + YOLO tags and keeps highest confidence for duplicates. +- Normalizes tags before attach (lowercase, cleanup, slug-safe format). +- Uses `TagService::attachAiTags()` to store pivot data: + - `source = ai` + - `confidence = ` +- Runs with queue retry + timeout safety (`tries`, `backoff`, `timeout`). +- Logs failures with reference/context for troubleshooting. +- On non-retriable response scenarios (e.g. 4xx), job exits safely without blocking publish. + +### Queue / Worker Requirements (`VISION_QUEUE`) + +- Ensure a worker is running for the configured queue. +- Example worker command: + +```bash +php artisan queue:work --queue=default +``` + +- If `VISION_QUEUE=vision`, run worker for that queue: + +```bash +php artisan queue:work --queue=vision +``` + +- In production, use Supervisor/systemd/Horizon to keep workers alive. +- Without an active worker, auto-tagging jobs remain queued and will not execute. + +### Local vs Production Notes + +#### Local development + +- For fully offline local work, set `VISION_ENABLED=false`. +- Or set only `CLIP_BASE_URL`/`YOLO_BASE_URL` you can reach locally. +- Prefer short timeouts to avoid slow dev feedback loops. + +#### Production + +- Use internal/private service endpoints for CLIP/YOLO when possible. +- Keep conservative timeouts and low retry counts to prevent queue congestion. +- Monitor failed jobs and logs for vision service reliability. +- Scale queue workers based on upload volume and service latency. + +### Verify Setup (Health + Test Call) + +After configuring env vars and restarting workers, verify in this order: + +Quick helper (PowerShell): + +```powershell +pwsh -File ./scripts/vision-smoke.ps1 +``` + +Optional flags: + +```powershell +pwsh -File ./scripts/vision-smoke.ps1 -EnvFile ".env" -SampleImageUrl "https://files.skinbase.org/img/aa/bb/cc/md.webp" +pwsh -File ./scripts/vision-smoke.ps1 -SkipAnalyze +``` + +1. Confirm queue worker is consuming `VISION_QUEUE`. + +```bash +php artisan queue:work --queue=default +``` + +1. Check CLIP/YOLO health endpoints (replace host/port as needed): + +```bash +curl -fsS "$CLIP_BASE_URL/health" +curl -fsS "$YOLO_BASE_URL/health" +``` + +1. Make a direct analyze test call (CLIP example): + +```bash +curl -X POST "$CLIP_BASE_URL$CLIP_ANALYZE_ENDPOINT" \ + -H "Content-Type: application/json" \ + -d '{"image_url":"https://files.skinbase.org/img/aa/bb/cc/md.webp"}' +``` + +1. Trigger an upload/publish and confirm: + +- Publish response succeeds even if CLIP/YOLO is down. +- `AutoTagArtworkJob` is queued/executed asynchronously. +- AI tags appear on the artwork when services are healthy. +- Failures are logged, but publish is unaffected. + ## License The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). diff --git a/app/Banner.php b/app/Banner.php index 2b32e884..de8e61b1 100644 --- a/app/Banner.php +++ b/app/Banner.php @@ -6,11 +6,11 @@ class Banner { public static function ShowResponsiveAd() { - echo '
'; - echo ''; - echo ''; - echo ''; - echo '
'; + #echo '
'; + #echo ''; + #echo ''; + #echo ''; + #echo '
'; } public static function ShowBanner300x250() diff --git a/app/Console/Commands/AggregateFeedAnalyticsCommand.php b/app/Console/Commands/AggregateFeedAnalyticsCommand.php new file mode 100644 index 00000000..05d60803 --- /dev/null +++ b/app/Console/Commands/AggregateFeedAnalyticsCommand.php @@ -0,0 +1,106 @@ +option('date') + ? (string) $this->option('date') + : now()->subDay()->toDateString(); + + $rows = DB::table('feed_events') + ->selectRaw('algo_version, source') + ->selectRaw("SUM(CASE WHEN event_type = 'feed_impression' THEN 1 ELSE 0 END) AS impressions") + ->selectRaw("SUM(CASE WHEN event_type = 'feed_click' THEN 1 ELSE 0 END) AS clicks") + ->selectRaw("SUM(CASE WHEN event_type = 'feed_click' AND dwell_seconds IS NOT NULL AND dwell_seconds < 5 THEN 1 ELSE 0 END) AS dwell_0_5") + ->selectRaw("SUM(CASE WHEN event_type = 'feed_click' AND dwell_seconds >= 5 AND dwell_seconds < 30 THEN 1 ELSE 0 END) AS dwell_5_30") + ->selectRaw("SUM(CASE WHEN event_type = 'feed_click' AND dwell_seconds >= 30 AND dwell_seconds < 120 THEN 1 ELSE 0 END) AS dwell_30_120") + ->selectRaw("SUM(CASE WHEN event_type = 'feed_click' AND dwell_seconds >= 120 THEN 1 ELSE 0 END) AS dwell_120_plus") + ->whereDate('event_date', $date) + ->groupBy('algo_version', 'source') + ->get(); + + foreach ($rows as $row) { + $algoVersion = (string) $row->algo_version; + $source = (string) $row->source; + $impressions = (int) ($row->impressions ?? 0); + $clicks = (int) ($row->clicks ?? 0); + + $saves = $this->countSavesForGroup($date, $algoVersion, $source); + + $ctr = $impressions > 0 ? $clicks / $impressions : 0.0; + $saveRate = $clicks > 0 ? $saves / $clicks : 0.0; + + DB::table('feed_daily_metrics')->updateOrInsert( + [ + 'metric_date' => $date, + 'algo_version' => $algoVersion, + 'source' => $source, + ], + [ + 'impressions' => $impressions, + 'clicks' => $clicks, + 'saves' => $saves, + 'ctr' => $ctr, + 'save_rate' => $saveRate, + 'dwell_0_5' => (int) ($row->dwell_0_5 ?? 0), + 'dwell_5_30' => (int) ($row->dwell_5_30 ?? 0), + 'dwell_30_120' => (int) ($row->dwell_30_120 ?? 0), + 'dwell_120_plus' => (int) ($row->dwell_120_plus ?? 0), + 'updated_at' => now(), + 'created_at' => now(), + ] + ); + } + + $this->info("Aggregated feed analytics for {$date}."); + + return self::SUCCESS; + } + + private function countSavesForGroup(string $date, string $algoVersion, string $source): int + { + /** @var Collection $clickedPairs */ + $clickedPairs = DB::table('feed_events') + ->select('user_id', 'artwork_id') + ->whereDate('event_date', $date) + ->where('event_type', 'feed_click') + ->where('algo_version', $algoVersion) + ->where('source', $source) + ->groupBy('user_id', 'artwork_id') + ->get(); + + if ($clickedPairs->isEmpty()) { + return 0; + } + + $saves = 0; + foreach ($clickedPairs as $pair) { + $hasSave = DB::table('user_discovery_events') + ->whereDate('event_date', $date) + ->where('user_id', (int) $pair->user_id) + ->where('artwork_id', (int) $pair->artwork_id) + ->where('algo_version', $algoVersion) + ->whereIn('event_type', ['favorite', 'download']) + ->exists(); + + if ($hasSave) { + $saves++; + } + } + + return $saves; + } +} diff --git a/app/Console/Commands/AggregateSimilarArtworkAnalyticsCommand.php b/app/Console/Commands/AggregateSimilarArtworkAnalyticsCommand.php new file mode 100644 index 00000000..7c35d5a5 --- /dev/null +++ b/app/Console/Commands/AggregateSimilarArtworkAnalyticsCommand.php @@ -0,0 +1,54 @@ +option('date') + ? (string) $this->option('date') + : now()->subDay()->toDateString(); + + $rows = DB::table('similar_artwork_events') + ->selectRaw('algo_version') + ->selectRaw("SUM(CASE WHEN event_type = 'impression' THEN 1 ELSE 0 END) AS impressions") + ->selectRaw("SUM(CASE WHEN event_type = 'click' THEN 1 ELSE 0 END) AS clicks") + ->whereDate('event_date', $date) + ->groupBy('algo_version') + ->get(); + + foreach ($rows as $row) { + $impressions = (int) ($row->impressions ?? 0); + $clicks = (int) ($row->clicks ?? 0); + $ctr = $impressions > 0 ? $clicks / $impressions : 0.0; + + DB::table('similar_artwork_daily_metrics')->updateOrInsert( + [ + 'metric_date' => $date, + 'algo_version' => (string) $row->algo_version, + ], + [ + 'impressions' => $impressions, + 'clicks' => $clicks, + 'ctr' => $ctr, + 'updated_at' => now(), + 'created_at' => now(), + ] + ); + } + + $this->info("Aggregated similar artwork analytics for {$date}."); + + return self::SUCCESS; + } +} diff --git a/app/Console/Commands/AvatarsMigrate.php b/app/Console/Commands/AvatarsMigrate.php new file mode 100644 index 00000000..45f893d1 --- /dev/null +++ b/app/Console/Commands/AvatarsMigrate.php @@ -0,0 +1,83 @@ +service = $service; + } + + public function handle() + { + $this->info('Starting avatar migration...'); + + // Try to read legacy data from user_profiles.avatar_legacy or users.avatar_legacy or users.icon + $rows = DB::table('user_profiles')->select('user_id', 'avatar_legacy')->whereNotNull('avatar_legacy')->get(); + + if ($rows->isEmpty()) { + // fallback to users table + $rows = DB::table('users')->select('user_id', 'icon as avatar_legacy')->whereNotNull('icon')->get(); + } + + $count = 0; + foreach ($rows as $row) { + $userId = $row->user_id; + $legacy = $row->avatar_legacy ?? null; + if (!$legacy) { + continue; + } + + // Try common legacy paths + $candidates = [ + public_path('user-picture/' . $legacy), + public_path('avatar/' . $userId . '/' . $legacy), + storage_path('app/public/user-picture/' . $legacy), + storage_path('app/public/avatar/' . $userId . '/' . $legacy), + ]; + + $found = false; + foreach ($candidates as $p) { + if (file_exists($p) && is_readable($p)) { + $this->info("Processing user {$userId} from {$p}"); + $hash = $this->service->storeFromLegacyFile($userId, $p); + if ($hash) { + $this->info(" -> migrated, hash={$hash}"); + $count++; + $found = true; + break; + } + } + } + + if (!$found) { + $this->warn("Legacy file not found for user {$userId}, filename={$legacy}"); + } + } + + $this->info("Migration complete. Processed: {$count}"); + return 0; + } +} diff --git a/app/Console/Commands/BackfillArtworkEmbeddingsCommand.php b/app/Console/Commands/BackfillArtworkEmbeddingsCommand.php new file mode 100644 index 00000000..847ed512 --- /dev/null +++ b/app/Console/Commands/BackfillArtworkEmbeddingsCommand.php @@ -0,0 +1,28 @@ +option('after-id')); + $batch = max(1, min((int) $this->option('batch'), 1000)); + $force = (bool) $this->option('force'); + + BackfillArtworkEmbeddingsJob::dispatch($afterId, $batch, $force); + + $this->info("Queued artwork embedding backfill (after_id={$afterId}, batch={$batch}, force=" . ($force ? 'yes' : 'no') . ').'); + + return self::SUCCESS; + } +} diff --git a/app/Console/Commands/CompareFeedAbCommand.php b/app/Console/Commands/CompareFeedAbCommand.php new file mode 100644 index 00000000..45339fca --- /dev/null +++ b/app/Console/Commands/CompareFeedAbCommand.php @@ -0,0 +1,71 @@ +option('from') ?: now()->subDays(29)->toDateString()); + $to = (string) ($this->option('to') ?: now()->toDateString()); + + if ($from > $to) { + $this->error('Invalid range: --from must be <= --to'); + return self::FAILURE; + } + + $baseline = (string) $this->argument('baseline'); + $candidate = (string) $this->argument('candidate'); + + $comparison = $this->evaluator->compareBaselineCandidate($baseline, $candidate, $from, $to); + + if ((bool) $this->option('json')) { + $this->line((string) json_encode($comparison, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + return self::SUCCESS; + } + + $this->table( + ['algo_version', 'ctr', 'save_rate', 'long_dwell_share', 'bounce_rate', 'objective_score'], + [[ + (string) $comparison['baseline']['algo_version'], + (float) $comparison['baseline']['ctr'], + (float) $comparison['baseline']['save_rate'], + (float) $comparison['baseline']['long_dwell_share'], + (float) $comparison['baseline']['bounce_rate'], + (float) $comparison['baseline']['objective_score'], + ], [ + (string) $comparison['candidate']['algo_version'], + (float) $comparison['candidate']['ctr'], + (float) $comparison['candidate']['save_rate'], + (float) $comparison['candidate']['long_dwell_share'], + (float) $comparison['candidate']['bounce_rate'], + (float) $comparison['candidate']['objective_score'], + ]] + ); + + $delta = (array) $comparison['delta']; + $this->line('Δ objective_score: ' . (string) $delta['objective_score']); + $this->line('Δ objective_lift_pct: ' . (string) ($delta['objective_lift_pct'] ?? 'n/a')); + + return self::SUCCESS; + } +} diff --git a/app/Console/Commands/EvaluateFeedWeightsCommand.php b/app/Console/Commands/EvaluateFeedWeightsCommand.php new file mode 100644 index 00000000..d91ebcef --- /dev/null +++ b/app/Console/Commands/EvaluateFeedWeightsCommand.php @@ -0,0 +1,81 @@ +option('from') ?: now()->subDays(29)->toDateString()); + $to = (string) ($this->option('to') ?: now()->toDateString()); + $algo = $this->option('algo') ? (string) $this->option('algo') : null; + + if ($from > $to) { + $this->error('Invalid range: --from must be <= --to'); + return self::FAILURE; + } + + if ($algo !== null && $algo !== '') { + $result = $this->evaluator->evaluateAlgo($algo, $from, $to); + + if ((bool) $this->option('json')) { + $this->line((string) json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + } else { + $this->table( + ['algo_version', 'ctr', 'save_rate', 'long_dwell_share', 'bounce_rate', 'objective_score'], + [[ + (string) $result['algo_version'], + (float) $result['ctr'], + (float) $result['save_rate'], + (float) $result['long_dwell_share'], + (float) $result['bounce_rate'], + (float) $result['objective_score'], + ]] + ); + } + + return self::SUCCESS; + } + + $results = $this->evaluator->evaluateAll($from, $to); + + if ((bool) $this->option('json')) { + $this->line((string) json_encode($results, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + return self::SUCCESS; + } + + $rows = array_map(static fn (array $row): array => [ + (string) $row['algo_version'], + (float) $row['ctr'], + (float) $row['save_rate'], + (float) $row['long_dwell_share'], + (float) $row['bounce_rate'], + (float) $row['objective_score'], + ], $results); + + $this->table( + ['algo_version', 'ctr', 'save_rate', 'long_dwell_share', 'bounce_rate', 'objective_score'], + $rows + ); + + return self::SUCCESS; + } +} diff --git a/app/Console/Commands/ImportLegacyUsers.php b/app/Console/Commands/ImportLegacyUsers.php index 344a6e0b..d870703e 100644 --- a/app/Console/Commands/ImportLegacyUsers.php +++ b/app/Console/Commands/ImportLegacyUsers.php @@ -102,7 +102,7 @@ class ImportLegacyUsers extends Command DB::table('user_profiles')->insert([ 'user_id' => $legacyId, - 'bio' => $row->about_me ?: $row->description ?: null, + 'about' => $row->about_me ?: $row->description ?: null, 'avatar' => $row->picture ?: null, 'cover_image' => $row->cover_art ?: null, 'country' => $row->country ?: null, @@ -115,15 +115,7 @@ class ImportLegacyUsers extends Command 'updated_at' => $now, ]); - if (!empty($row->web)) { - DB::table('user_social_links')->insert([ - 'user_id' => $legacyId, - 'platform' => 'website', - 'url' => $row->web, - 'created_at' => $now, - 'updated_at' => $now, - ]); - } + // Do not duplicate `website` into `user_social_links` — keep canonical site in `user_profiles.website`. DB::table('user_statistics')->insert([ 'user_id' => $legacyId, diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index ea51b4d7..46f875ea 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -6,6 +6,12 @@ use Illuminate\Foundation\Console\Kernel as ConsoleKernel; use App\Console\Commands\ImportLegacyUsers; use App\Console\Commands\ImportCategories; use App\Console\Commands\MigrateFeaturedWorks; +use App\Console\Commands\BackfillArtworkEmbeddingsCommand; +use App\Console\Commands\AggregateSimilarArtworkAnalyticsCommand; +use App\Console\Commands\AggregateFeedAnalyticsCommand; +use App\Console\Commands\EvaluateFeedWeightsCommand; +use App\Console\Commands\CompareFeedAbCommand; +use App\Uploads\Commands\CleanupUploadsCommand; class Kernel extends ConsoleKernel { @@ -18,7 +24,14 @@ class Kernel extends ConsoleKernel ImportLegacyUsers::class, ImportCategories::class, MigrateFeaturedWorks::class, + \App\Console\Commands\AvatarsMigrate::class, \App\Console\Commands\ResetAllUserPasswords::class, + CleanupUploadsCommand::class, + BackfillArtworkEmbeddingsCommand::class, + AggregateSimilarArtworkAnalyticsCommand::class, + AggregateFeedAnalyticsCommand::class, + EvaluateFeedWeightsCommand::class, + CompareFeedAbCommand::class, ]; /** @@ -26,7 +39,9 @@ class Kernel extends ConsoleKernel */ protected function schedule(\Illuminate\Console\Scheduling\Schedule $schedule): void { - // $schedule->command('inspire')->hourly(); + $schedule->command('uploads:cleanup')->dailyAt('03:00'); + $schedule->command('analytics:aggregate-similar-artworks')->dailyAt('03:10'); + $schedule->command('analytics:aggregate-feed')->dailyAt('03:20'); } /** diff --git a/app/DTOs/Artworks/ArtworkDraftResult.php b/app/DTOs/Artworks/ArtworkDraftResult.php new file mode 100644 index 00000000..9e5467fa --- /dev/null +++ b/app/DTOs/Artworks/ArtworkDraftResult.php @@ -0,0 +1,14 @@ +validate([ + 'from' => ['nullable', 'date_format:Y-m-d'], + 'to' => ['nullable', 'date_format:Y-m-d'], + 'limit' => ['nullable', 'integer', 'min:1', 'max:1000'], + ]); + + $from = (string) ($validated['from'] ?? now()->subDays(29)->toDateString()); + $to = (string) ($validated['to'] ?? now()->toDateString()); + $limit = (int) ($validated['limit'] ?? 100); + + if ($from > $to) { + return response()->json([ + 'message' => 'Invalid date range: from must be before or equal to to.', + ], Response::HTTP_UNPROCESSABLE_ENTITY); + } + + $rows = DB::table('feed_daily_metrics') + ->selectRaw('algo_version, source') + ->selectRaw('SUM(impressions) as impressions') + ->selectRaw('SUM(clicks) as clicks') + ->selectRaw('SUM(saves) as saves') + ->selectRaw('SUM(dwell_0_5) as dwell_0_5') + ->selectRaw('SUM(dwell_5_30) as dwell_5_30') + ->selectRaw('SUM(dwell_30_120) as dwell_30_120') + ->selectRaw('SUM(dwell_120_plus) as dwell_120_plus') + ->whereBetween('metric_date', [$from, $to]) + ->groupBy('algo_version', 'source') + ->orderBy('algo_version') + ->orderBy('source') + ->get(); + + $byAlgoSource = $rows->map(static function ($row): array { + $impressions = (int) ($row->impressions ?? 0); + $clicks = (int) ($row->clicks ?? 0); + $saves = (int) ($row->saves ?? 0); + + return [ + 'algo_version' => (string) $row->algo_version, + 'source' => (string) $row->source, + 'impressions' => $impressions, + 'clicks' => $clicks, + 'saves' => $saves, + 'ctr' => round($impressions > 0 ? $clicks / $impressions : 0.0, 6), + 'save_rate' => round($clicks > 0 ? $saves / $clicks : 0.0, 6), + 'dwell_buckets' => [ + '0_5' => (int) ($row->dwell_0_5 ?? 0), + '5_30' => (int) ($row->dwell_5_30 ?? 0), + '30_120' => (int) ($row->dwell_30_120 ?? 0), + '120_plus' => (int) ($row->dwell_120_plus ?? 0), + ], + ]; + })->values(); + + $topClickedArtworks = DB::table('feed_events as e') + ->leftJoin('artworks as a', 'a.id', '=', 'e.artwork_id') + ->selectRaw('e.algo_version') + ->selectRaw('e.source') + ->selectRaw('e.artwork_id') + ->selectRaw('a.title as artwork_title') + ->selectRaw("SUM(CASE WHEN e.event_type = 'feed_impression' THEN 1 ELSE 0 END) AS impressions") + ->selectRaw("SUM(CASE WHEN e.event_type = 'feed_click' THEN 1 ELSE 0 END) AS clicks") + ->whereBetween('e.event_date', [$from, $to]) + ->groupBy('e.algo_version', 'e.source', 'e.artwork_id', 'a.title') + ->get() + ->map(static function ($row): array { + $impressions = (int) ($row->impressions ?? 0); + $clicks = (int) ($row->clicks ?? 0); + + return [ + 'algo_version' => (string) $row->algo_version, + 'source' => (string) $row->source, + 'artwork_id' => (int) $row->artwork_id, + 'artwork_title' => (string) ($row->artwork_title ?? ''), + 'impressions' => $impressions, + 'clicks' => $clicks, + 'ctr' => round($impressions > 0 ? $clicks / $impressions : 0.0, 6), + ]; + }) + ->sort(static function (array $a, array $b): int { + $clickCompare = $b['clicks'] <=> $a['clicks']; + if ($clickCompare !== 0) { + return $clickCompare; + } + + return $b['ctr'] <=> $a['ctr']; + }) + ->take($limit) + ->values(); + + return response()->json([ + 'meta' => [ + 'from' => $from, + 'to' => $to, + 'generated_at' => now()->toISOString(), + 'limit' => $limit, + ], + 'by_algo_source' => $byAlgoSource, + 'top_clicked_artworks' => $topClickedArtworks, + ], Response::HTTP_OK); + } +} diff --git a/app/Http/Controllers/Api/Admin/SimilarArtworkReportController.php b/app/Http/Controllers/Api/Admin/SimilarArtworkReportController.php new file mode 100644 index 00000000..5b39f503 --- /dev/null +++ b/app/Http/Controllers/Api/Admin/SimilarArtworkReportController.php @@ -0,0 +1,114 @@ +validate([ + 'from' => ['nullable', 'date_format:Y-m-d'], + 'to' => ['nullable', 'date_format:Y-m-d'], + 'limit' => ['nullable', 'integer', 'min:1', 'max:1000'], + ]); + + $from = (string) ($validated['from'] ?? now()->subDays(29)->toDateString()); + $to = (string) ($validated['to'] ?? now()->toDateString()); + $limit = (int) ($validated['limit'] ?? 100); + + if ($from > $to) { + return response()->json([ + 'message' => 'Invalid date range: from must be before or equal to to.', + ], Response::HTTP_UNPROCESSABLE_ENTITY); + } + + $byAlgoRows = DB::table('similar_artwork_events') + ->selectRaw('algo_version') + ->selectRaw("SUM(CASE WHEN event_type = 'impression' THEN 1 ELSE 0 END) AS impressions") + ->selectRaw("SUM(CASE WHEN event_type = 'click' THEN 1 ELSE 0 END) AS clicks") + ->whereBetween('event_date', [$from, $to]) + ->groupBy('algo_version') + ->orderBy('algo_version') + ->get(); + + $byAlgo = $byAlgoRows->map(static function ($row): array { + $impressions = (int) ($row->impressions ?? 0); + $clicks = (int) ($row->clicks ?? 0); + $ctr = $impressions > 0 ? $clicks / $impressions : 0.0; + + return [ + 'algo_version' => (string) $row->algo_version, + 'impressions' => $impressions, + 'clicks' => $clicks, + 'ctr' => round($ctr, 6), + ]; + })->values(); + + $pairRows = DB::table('similar_artwork_events as e') + ->leftJoin('artworks as source', 'source.id', '=', 'e.source_artwork_id') + ->leftJoin('artworks as similar', 'similar.id', '=', 'e.similar_artwork_id') + ->selectRaw('e.algo_version') + ->selectRaw('e.source_artwork_id') + ->selectRaw('e.similar_artwork_id') + ->selectRaw('source.title as source_title') + ->selectRaw('similar.title as similar_title') + ->selectRaw("SUM(CASE WHEN e.event_type = 'impression' THEN 1 ELSE 0 END) AS impressions") + ->selectRaw("SUM(CASE WHEN e.event_type = 'click' THEN 1 ELSE 0 END) AS clicks") + ->whereBetween('e.event_date', [$from, $to]) + ->whereNotNull('e.similar_artwork_id') + ->groupBy('e.algo_version', 'e.source_artwork_id', 'e.similar_artwork_id', 'source.title', 'similar.title') + ->get(); + + $topSimilarities = $pairRows + ->map(static function ($row): array { + $impressions = (int) ($row->impressions ?? 0); + $clicks = (int) ($row->clicks ?? 0); + $ctr = $impressions > 0 ? $clicks / $impressions : 0.0; + + return [ + 'algo_version' => (string) $row->algo_version, + 'source_artwork_id' => (int) $row->source_artwork_id, + 'source_title' => (string) ($row->source_title ?? ''), + 'similar_artwork_id' => (int) $row->similar_artwork_id, + 'similar_title' => (string) ($row->similar_title ?? ''), + 'impressions' => $impressions, + 'clicks' => $clicks, + 'ctr' => round($ctr, 6), + ]; + }) + ->sort(function (array $a, array $b): int { + $ctrCompare = $b['ctr'] <=> $a['ctr']; + if ($ctrCompare !== 0) { + return $ctrCompare; + } + + $clickCompare = $b['clicks'] <=> $a['clicks']; + if ($clickCompare !== 0) { + return $clickCompare; + } + + return $b['impressions'] <=> $a['impressions']; + }) + ->take($limit) + ->values(); + + return response()->json([ + 'meta' => [ + 'from' => $from, + 'to' => $to, + 'generated_at' => now()->toISOString(), + 'limit' => $limit, + ], + 'by_algo_version' => $byAlgo, + 'top_similarities' => $topSimilarities, + ], Response::HTTP_OK); + } +} diff --git a/app/Http/Controllers/Api/Admin/UploadModerationController.php b/app/Http/Controllers/Api/Admin/UploadModerationController.php new file mode 100644 index 00000000..e62aa453 --- /dev/null +++ b/app/Http/Controllers/Api/Admin/UploadModerationController.php @@ -0,0 +1,83 @@ +where('status', 'draft') + ->where('moderation_status', 'pending') + ->orderBy('created_at') + ->get([ + 'id', + 'user_id', + 'type', + 'status', + 'processing_state', + 'title', + 'preview_path', + 'created_at', + 'moderation_status', + ]); + + return response()->json([ + 'data' => $uploads, + ], Response::HTTP_OK); + } + + public function approve(string $id, Request $request): JsonResponse + { + $upload = Upload::query()->find($id); + + if (! $upload) { + return response()->json(['message' => 'Upload not found.'], Response::HTTP_NOT_FOUND); + } + + $upload->moderation_status = 'approved'; + $upload->moderated_at = now(); + $upload->moderated_by = (int) $request->user()->id; + $upload->moderation_note = $request->input('note'); + $upload->save(); + + return response()->json([ + 'success' => true, + 'id' => (string) $upload->id, + 'moderation_status' => (string) $upload->moderation_status, + ], Response::HTTP_OK); + } + + public function reject(string $id, Request $request): JsonResponse + { + $upload = Upload::query()->find($id); + + if (! $upload) { + return response()->json(['message' => 'Upload not found.'], Response::HTTP_NOT_FOUND); + } + + $upload->moderation_status = 'rejected'; + $upload->status = 'rejected'; + $upload->processing_state = 'rejected'; + $upload->moderated_at = now(); + $upload->moderated_by = (int) $request->user()->id; + $upload->moderation_note = (string) $request->input('note', ''); + $upload->save(); + + return response()->json([ + 'success' => true, + 'id' => (string) $upload->id, + 'status' => (string) $upload->status, + 'processing_state' => (string) $upload->processing_state, + 'moderation_status' => (string) $upload->moderation_status, + ], Response::HTTP_OK); + } +} diff --git a/app/Http/Controllers/Api/ArtworkController.php b/app/Http/Controllers/Api/ArtworkController.php index 6be78885..5da22066 100644 --- a/app/Http/Controllers/Api/ArtworkController.php +++ b/app/Http/Controllers/Api/ArtworkController.php @@ -2,11 +2,14 @@ namespace App\Http\Controllers\Api; use App\Http\Controllers\Controller; +use App\Http\Requests\Artworks\ArtworkCreateRequest; use App\Http\Resources\ArtworkListResource; use App\Http\Resources\ArtworkResource; use App\Services\ArtworkService; +use App\Services\Artworks\ArtworkDraftService; use App\Models\Category; use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\Response; class ArtworkController extends Controller { @@ -17,6 +20,27 @@ class ArtworkController extends Controller $this->service = $service; } + /** + * POST /api/artworks + * Creates a draft artwork placeholder for the upload pipeline. + */ + public function store(ArtworkCreateRequest $request, ArtworkDraftService $drafts) + { + $user = $request->user(); + $data = $request->validated(); + + $result = $drafts->createDraft( + (int) $user->id, + (string) $data['title'], + isset($data['description']) ? (string) $data['description'] : null + ); + + return response()->json([ + 'artwork_id' => $result->artworkId, + 'status' => $result->status, + ], Response::HTTP_CREATED); + } + /** * GET /api/v1/artworks/{slug} * Returns a single public artwork resource by slug. diff --git a/app/Http/Controllers/Api/ArtworkTagController.php b/app/Http/Controllers/Api/ArtworkTagController.php new file mode 100644 index 00000000..dda3b9cd --- /dev/null +++ b/app/Http/Controllers/Api/ArtworkTagController.php @@ -0,0 +1,165 @@ +findOrFail($id); + $this->authorizeOrNotFound(request()->user(), $artwork); + + $queueConnection = (string) config('queue.default', 'sync'); + $visionEnabled = (bool) config('vision.enabled', true); + + $queuedCount = 0; + $failedCount = 0; + + if (in_array($queueConnection, ['database', 'redis'], true)) { + try { + $queuedCount = (int) DB::table('jobs') + ->where('payload', 'like', '%AutoTagArtworkJob%') + ->where('payload', 'like', '%' . $artwork->id . '%') + ->count(); + } catch (\Throwable) { + $queuedCount = 0; + } + + try { + $failedCount = (int) DB::table('failed_jobs') + ->where('payload', 'like', '%AutoTagArtworkJob%') + ->where('payload', 'like', '%' . $artwork->id . '%') + ->count(); + } catch (\Throwable) { + $failedCount = 0; + } + } + + $triggered = false; + $shouldTrigger = request()->boolean('trigger', false); + if ($shouldTrigger && $visionEnabled && ! empty($artwork->hash) && $queuedCount === 0) { + AutoTagArtworkJob::dispatch((int) $artwork->id, (string) $artwork->hash); + $triggered = true; + $queuedCount = max(1, $queuedCount); + } + + $tags = $artwork->tags() + ->select('tags.id', 'tags.name', 'tags.slug') + ->withPivot(['source', 'confidence']) + ->orderByDesc('artwork_tag.confidence') + ->get() + ->map(static function ($tag): array { + $source = (string) ($tag->pivot->source ?? 'manual'); + return [ + 'id' => (int) $tag->id, + 'name' => (string) $tag->name, + 'slug' => (string) $tag->slug, + 'source' => $source, + 'confidence' => (float) ($tag->pivot->confidence ?? 0), + 'is_ai' => $source === 'ai', + ]; + }) + ->values(); + + return response()->json([ + 'vision_enabled' => $visionEnabled, + 'tags' => $tags, + 'ai_tags' => $tags->where('is_ai', true)->values(), + 'debug' => [ + 'queue_connection' => $queueConnection, + 'queued_jobs' => $queuedCount, + 'failed_jobs' => $failedCount, + 'triggered' => $triggered, + 'ai_tag_count' => (int) $tags->where('is_ai', true)->count(), + 'total_tag_count' => (int) $tags->count(), + ], + ]); + } + + public function store(int $id, ArtworkTagsStoreRequest $request): JsonResponse + { + $artwork = Artwork::query()->findOrFail($id); + $this->authorizeOrNotFound($request->user(), $artwork); + + try { + $payload = $request->validated(); + $this->tags->attachUserTags($artwork, $payload['tags']); + + return response()->json(['ok' => true], Response::HTTP_CREATED); + } catch (\Throwable $e) { + $ref = (string) Str::uuid(); + logger()->error('Artwork tag attach failed', ['ref' => $ref, 'artwork_id' => $artwork->id, 'user_id' => $request->user()?->id, 'exception' => $e]); + return response()->json([ + 'message' => 'Unable to update tags right now.', + 'ref' => $ref, + ], Response::HTTP_UNPROCESSABLE_ENTITY); + } + } + + public function update(int $id, ArtworkTagsUpdateRequest $request): JsonResponse + { + $artwork = Artwork::query()->findOrFail($id); + $this->authorizeOrNotFound($request->user(), $artwork); + + try { + $payload = $request->validated(); + $this->tags->syncTags($artwork, $payload['tags']); + return response()->json(['ok' => true]); + } catch (\Throwable $e) { + $ref = (string) Str::uuid(); + logger()->error('Artwork tag sync failed', ['ref' => $ref, 'artwork_id' => $artwork->id, 'user_id' => $request->user()?->id, 'exception' => $e]); + return response()->json([ + 'message' => 'Unable to update tags right now.', + 'ref' => $ref, + ], Response::HTTP_UNPROCESSABLE_ENTITY); + } + } + + public function destroy(int $id, Tag $tag): JsonResponse + { + $artwork = Artwork::query()->findOrFail($id); + $this->authorizeOrNotFound(request()->user(), $artwork); + + try { + $this->tags->detachTags($artwork, [$tag->id]); + return response()->json(['ok' => true]); + } catch (\Throwable $e) { + $ref = (string) Str::uuid(); + logger()->error('Artwork tag detach failed', ['ref' => $ref, 'artwork_id' => $artwork->id, 'tag_id' => $tag->id, 'user_id' => request()->user()?->id, 'exception' => $e]); + return response()->json([ + 'message' => 'Unable to update tags right now.', + 'ref' => $ref, + ], Response::HTTP_UNPROCESSABLE_ENTITY); + } + } + + private function authorizeOrNotFound($user, Artwork $artwork): void + { + if (! $user) { + abort(404); + } + + if (! $user->can('updateTags', $artwork)) { + abort(404); + } + } +} diff --git a/app/Http/Controllers/Api/DiscoveryEventController.php b/app/Http/Controllers/Api/DiscoveryEventController.php new file mode 100644 index 00000000..b6563c69 --- /dev/null +++ b/app/Http/Controllers/Api/DiscoveryEventController.php @@ -0,0 +1,49 @@ +validate([ + 'event_id' => ['nullable', 'uuid'], + 'event_type' => ['required', 'string', 'in:view,click,favorite,download'], + 'artwork_id' => ['required', 'integer', 'exists:artworks,id'], + 'occurred_at' => ['nullable', 'date'], + 'algo_version' => ['nullable', 'string', 'max:64'], + 'meta' => ['nullable', 'array'], + ]); + + $eventId = (string) ($payload['event_id'] ?? (string) Str::uuid()); + $algoVersion = (string) ($payload['algo_version'] ?? config('discovery.algo_version', 'clip-cosine-v1')); + $occurredAt = isset($payload['occurred_at']) + ? (string) $payload['occurred_at'] + : now()->toIso8601String(); + + IngestUserDiscoveryEventJob::dispatch( + eventId: $eventId, + userId: (int) $request->user()->id, + artworkId: (int) $payload['artwork_id'], + eventType: (string) $payload['event_type'], + algoVersion: $algoVersion, + occurredAt: $occurredAt, + meta: (array) ($payload['meta'] ?? []) + )->onQueue((string) config('discovery.queue', 'default')); + + return response()->json([ + 'queued' => true, + 'event_id' => $eventId, + 'algo_version' => $algoVersion, + ], Response::HTTP_ACCEPTED); + } +} diff --git a/app/Http/Controllers/Api/FeedAnalyticsController.php b/app/Http/Controllers/Api/FeedAnalyticsController.php new file mode 100644 index 00000000..a6cb3ba4 --- /dev/null +++ b/app/Http/Controllers/Api/FeedAnalyticsController.php @@ -0,0 +1,45 @@ +validate([ + 'event_type' => ['required', 'string', 'in:feed_impression,feed_click'], + 'artwork_id' => ['required', 'integer', 'exists:artworks,id'], + 'position' => ['nullable', 'integer', 'min:1', 'max:500'], + 'algo_version' => ['required', 'string', 'max:64'], + 'source' => ['required', 'string', 'in:personalized,cold_start,fallback'], + 'dwell_seconds' => ['nullable', 'integer', 'min:0', 'max:86400'], + 'occurred_at' => ['nullable', 'date'], + ]); + + $occurredAt = isset($payload['occurred_at']) ? now()->parse((string) $payload['occurred_at']) : now(); + + DB::table('feed_events')->insert([ + 'event_date' => $occurredAt->toDateString(), + 'event_type' => (string) $payload['event_type'], + 'user_id' => (int) $request->user()->id, + 'artwork_id' => (int) $payload['artwork_id'], + 'position' => isset($payload['position']) ? (int) $payload['position'] : null, + 'algo_version' => (string) $payload['algo_version'], + 'source' => (string) $payload['source'], + 'dwell_seconds' => isset($payload['dwell_seconds']) ? (int) $payload['dwell_seconds'] : null, + 'occurred_at' => $occurredAt, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + return response()->json(['success' => true], Response::HTTP_OK); + } +} diff --git a/app/Http/Controllers/Api/FeedController.php b/app/Http/Controllers/Api/FeedController.php new file mode 100644 index 00000000..e52bc439 --- /dev/null +++ b/app/Http/Controllers/Api/FeedController.php @@ -0,0 +1,35 @@ +validate([ + 'limit' => ['nullable', 'integer', 'min:1', 'max:50'], + 'cursor' => ['nullable', 'string', 'max:512'], + 'algo_version' => ['nullable', 'string', 'max:64'], + ]); + + $result = $this->feedService->getFeed( + userId: (int) $request->user()->id, + limit: isset($payload['limit']) ? (int) $payload['limit'] : 24, + cursor: isset($payload['cursor']) ? (string) $payload['cursor'] : null, + algoVersion: isset($payload['algo_version']) ? (string) $payload['algo_version'] : null + ); + + return response()->json($result); + } +} diff --git a/app/Http/Controllers/Api/SimilarArtworkAnalyticsController.php b/app/Http/Controllers/Api/SimilarArtworkAnalyticsController.php new file mode 100644 index 00000000..c2109e7b --- /dev/null +++ b/app/Http/Controllers/Api/SimilarArtworkAnalyticsController.php @@ -0,0 +1,41 @@ +validate([ + 'event_type' => ['required', 'string', 'in:impression,click'], + 'algo_version' => ['required', 'string', 'max:64'], + 'source_artwork_id' => ['required', 'integer', 'exists:artworks,id'], + 'similar_artwork_id' => ['nullable', 'integer', 'exists:artworks,id'], + 'position' => ['nullable', 'integer', 'min:1', 'max:100'], + 'items_count' => ['nullable', 'integer', 'min:0', 'max:100'], + ]); + + DB::table('similar_artwork_events')->insert([ + 'event_date' => now()->toDateString(), + 'event_type' => (string) $payload['event_type'], + 'algo_version' => (string) $payload['algo_version'], + 'source_artwork_id' => (int) $payload['source_artwork_id'], + 'similar_artwork_id' => isset($payload['similar_artwork_id']) ? (int) $payload['similar_artwork_id'] : null, + 'position' => isset($payload['position']) ? (int) $payload['position'] : null, + 'items_count' => isset($payload['items_count']) ? (int) $payload['items_count'] : null, + 'occurred_at' => now(), + 'created_at' => now(), + 'updated_at' => now(), + ]); + + return response()->json(['success' => true], Response::HTTP_OK); + } +} diff --git a/app/Http/Controllers/Api/TagController.php b/app/Http/Controllers/Api/TagController.php new file mode 100644 index 00000000..3b629d2d --- /dev/null +++ b/app/Http/Controllers/Api/TagController.php @@ -0,0 +1,52 @@ +validated()['q'] ?? ''); + $q = trim($q); + + $query = Tag::query()->where('is_active', true); + if ($q !== '') { + $query->where(function ($sub) use ($q): void { + $sub->where('name', 'like', $q . '%') + ->orWhere('slug', 'like', $q . '%'); + }); + } + + $tags = $query + ->orderByDesc('usage_count') + ->limit(20) + ->get(['id', 'name', 'slug', 'usage_count']); + + return response()->json([ + 'data' => $tags, + ]); + } + + public function popular(PopularTagsRequest $request): JsonResponse + { + $limit = (int) ($request->validated()['limit'] ?? 20); + + $tags = Tag::query() + ->where('is_active', true) + ->orderByDesc('usage_count') + ->limit($limit) + ->get(['id', 'name', 'slug', 'usage_count']); + + return response()->json([ + 'data' => $tags, + ]); + } +} diff --git a/app/Http/Controllers/Api/UploadController.php b/app/Http/Controllers/Api/UploadController.php new file mode 100644 index 00000000..a3cee011 --- /dev/null +++ b/app/Http/Controllers/Api/UploadController.php @@ -0,0 +1,547 @@ +user(); + + try { + $quota->enforce($user->id); + } catch (Throwable $e) { + return response()->json([ + 'message' => $e->getMessage(), + ], Response::HTTP_TOO_MANY_REQUESTS); + } + + $result = $pipeline->initSession($user->id, (string) $request->ip()); + + $audit->log($user->id, 'upload_init_issued', (string) $request->ip(), [ + 'session_id' => $result->sessionId, + ]); + + return response()->json([ + 'session_id' => $result->sessionId, + 'upload_token' => $result->token, + 'status' => $result->status, + ], Response::HTTP_OK); + } + + public function finish( + UploadFinishRequest $request, + UploadPipelineService $pipeline, + UploadSessionRepository $sessions, + UploadAuditService $audit + ) { + $user = $request->user(); + $sessionId = (string) $request->validated('session_id'); + $artworkId = (int) $request->validated('artwork_id'); + + $session = $sessions->getOrFail($sessionId); + + $request->artwork(); + + $validated = $pipeline->validateAndHash($sessionId); + if (! $validated->validation->ok || ! $validated->hash) { + return response()->json([ + 'message' => 'Upload validation failed.', + 'reason' => $validated->validation->reason, + ], Response::HTTP_UNPROCESSABLE_ENTITY); + } + + $scan = $pipeline->scan($sessionId); + if (! $scan->ok) { + return response()->json([ + 'message' => 'Upload scan failed.', + 'reason' => $scan->reason, + ], Response::HTTP_UNPROCESSABLE_ENTITY); + } + + try { + $status = DB::transaction(function () use ($pipeline, $sessionId, $validated, $artworkId) { + if ((bool) config('uploads.queue_derivatives', false)) { + GenerateDerivativesJob::dispatch($sessionId, $validated->hash, $artworkId)->afterCommit(); + return 'queued'; + } + + $pipeline->processAndPublish($sessionId, $validated->hash, $artworkId); + + // Derivatives are available now; dispatch AI auto-tagging. + AutoTagArtworkJob::dispatch($artworkId, $validated->hash)->afterCommit(); + GenerateArtworkEmbeddingJob::dispatch($artworkId, $validated->hash)->afterCommit(); + return UploadSessionStatus::PROCESSED; + }); + + $audit->log($user->id, 'upload_finished', $session->ip, [ + 'session_id' => $sessionId, + 'hash' => $validated->hash, + 'artwork_id' => $artworkId, + 'status' => $status, + ]); + + return response()->json([ + 'artwork_id' => $artworkId, + 'status' => $status, + ], Response::HTTP_OK); + } catch (Throwable $e) { + Log::error('Upload finish failed', [ + 'session_id' => $sessionId, + 'artwork_id' => $artworkId, + 'error' => $e->getMessage(), + ]); + + return response()->json([ + 'message' => 'Upload finish failed.', + ], Response::HTTP_INTERNAL_SERVER_ERROR); + } + } + + public function chunk(UploadChunkRequest $request, UploadChunkService $chunks) + { + $user = $request->user(); + $chunkFile = $request->file('chunk'); + + // Debug: log uploaded file object details to help diagnose missing chunk + try { + if (! $chunkFile) { + logger()->warning('Chunk upload: no file present on request', [ + 'session_id' => (string) $request->input('session_id'), + 'headers' => $request->headers->all(), + ]); + } else { + logger()->warning('Chunk upload file details', [ + 'session_id' => (string) $request->input('session_id'), + 'client_name' => $chunkFile->getClientOriginalName() ?? null, + 'client_size' => $chunkFile->getSize() ?? null, + 'error' => $chunkFile->getError(), + 'realpath' => $chunkFile->getRealPath(), + ]); + } + } catch (\Throwable $e) { + logger()->warning('Chunk upload debug logging failed', ['error' => $e->getMessage()]); + } + + try { + // Use getPathname() — this returns the PHP temp filename even when + // getRealPath() may be false (platform/stream wrappers can cause + // getRealPath() to return false). getPathname() is safe for reading + // the uploaded chunk file. + $chunkPath = $chunkFile ? $chunkFile->getPathname() : ''; + + $result = $chunks->appendChunk( + (string) $request->input('session_id'), + (string) $chunkPath, + (int) $request->input('offset'), + (int) $request->input('chunk_size'), + (int) $request->input('total_size'), + (int) $user->id, + (string) $request->ip() + ); + + return response()->json([ + 'session_id' => $result->sessionId, + 'status' => $result->status, + 'received_bytes' => $result->receivedBytes, + 'total_bytes' => $result->totalBytes, + 'progress' => $result->progress, + ], Response::HTTP_OK); + } catch (\Throwable $e) { + logger()->warning('Upload chunk failed', [ + 'session_id' => (string) $request->input('session_id'), + 'error' => $e->getMessage(), + ]); + + // Include the underlying error message in the response during debugging + // so the frontend can show a useful description. Remove or hide this + // in production if you prefer more generic errors. + return response()->json([ + 'message' => 'Upload chunk failed.', + 'error' => $e->getMessage(), + ], Response::HTTP_UNPROCESSABLE_ENTITY); + } + } + + public function status(string $id, UploadStatusRequest $request, UploadStatusService $statusService, UploadAuditService $audit) + { + $user = $request->user(); + $payload = $statusService->get($id); + + $audit->log($user->id, 'upload_status_checked', (string) $request->ip(), [ + 'session_id' => $id, + 'status' => $payload['status'], + ]); + + return response()->json([ + 'session_id' => $payload['session_id'], + 'status' => $payload['status'], + 'progress' => $payload['progress'], + 'failure_reason' => $payload['failure_reason'], + 'received_bytes' => $payload['received_bytes'] ?? 0, + ], Response::HTTP_OK); + } + + public function cancel(UploadCancelRequest $request, UploadCancelService $cancel) + { + $user = $request->user(); + + try { + $result = $cancel->cancel( + (string) $request->input('session_id'), + (int) $user->id, + (string) $request->ip() + ); + + return response()->json([ + 'session_id' => $result['session_id'], + 'status' => $result['status'], + ], Response::HTTP_OK); + } catch (\Throwable $e) { + logger()->warning('Upload cancel failed', [ + 'session_id' => (string) $request->input('session_id'), + 'error' => $e->getMessage(), + ]); + + return response()->json([ + 'message' => 'Upload cancel failed.', + ], Response::HTTP_INTERNAL_SERVER_ERROR); + } + } + + /** + * Preload an upload draft: validate main file, create draft and store files. + * + * Returns JSON: { upload_id, status, expires_at } + */ + public function preload(Request $request, UploadDraftServiceInterface $draftService, ArchiveInspectorService $archiveInspector, DraftQuotaService $draftQuotaService) + { + $user = $request->user(); + + $request->validate([ + 'main' => ['required', 'file'], + 'screenshots' => ['sometimes', 'array'], + 'screenshots.*' => ['file', 'image', 'max:5120'], + ]); + + $main = $request->file('main'); + + // Detect type from mime + $mime = (string) $main->getClientMimeType(); + $type = null; + if (str_starts_with($mime, 'image/')) { + $type = 'image'; + } elseif (in_array($mime, ['application/zip', 'application/x-zip-compressed', 'application/x-tar', 'application/x-gzip', 'application/x-rar-compressed', 'application/octet-stream'])) { + $type = 'archive'; + } + + if ($type === null) { + return response()->json([ + 'message' => 'Invalid main file type.', + 'errors' => [ + 'main' => ['The main file must be an image or archive.'], + ], + ], Response::HTTP_UNPROCESSABLE_ENTITY); + } + + if ($type === 'archive') { + $validator = Validator::make($request->all(), [ + 'screenshots' => ['required', 'array', 'min:1'], + 'screenshots.*' => ['file', 'image', 'max:5120'], + ]); + + if ($validator->fails()) { + return response()->json([ + 'message' => 'The given data was invalid.', + 'errors' => $validator->errors(), + ], Response::HTTP_UNPROCESSABLE_ENTITY); + } + + $inspection = $archiveInspector->inspect((string) $main->getPathname()); + if (! $inspection->valid) { + return response()->json([ + 'message' => 'Archive inspection failed.', + 'reason' => $inspection->reason, + 'stats' => $inspection->stats, + ], Response::HTTP_UNPROCESSABLE_ENTITY); + } + } + + $incomingFiles = [$main]; + if ($type === 'archive' && $request->hasFile('screenshots')) { + foreach ($request->file('screenshots') as $screenshot) { + $incomingFiles[] = $screenshot; + } + } + + $mainHash = $draftService->calculateHash((string) $main->getPathname()); + + try { + $warnings = $draftQuotaService->assertCanCreateDraft($user, [ + 'files' => $incomingFiles, + 'main_hash' => $mainHash, + ]); + } catch (DraftQuotaException $e) { + return response()->json([ + 'message' => $e->machineCode(), + 'code' => $e->machineCode(), + ], $e->httpStatus()); + } + + // Create draft record (meta-only) and store main file via service + $draft = $draftService->createDraft(['user_id' => $user->id, 'type' => $type]); + + try { + $mainInfo = $draftService->storeMainFile($draft['id'], $main); + + // If archive, allow optional screenshots to be uploaded in the same request + if ($type === 'archive' && $request->hasFile('screenshots')) { + foreach ($request->file('screenshots') as $ss) { + try { + $draftService->storeScreenshot($draft['id'], $ss); + } catch (Throwable $e) { + // Keep controller thin: log and continue + logger()->warning('Screenshot store failed during preload', ['error' => $e->getMessage(), 'draft' => $draft['id']]); + } + } + } + + // Set expiration (default 7 days) and return info + $ttlDays = (int) config('uploads.draft_ttl_days', 7); + $expiresAt = Carbon::now()->addDays($ttlDays); + $draftService->setExpiration($draft['id'], $expiresAt); + + VirusScanJob::dispatch($draft['id']); + + $response = [ + 'upload_id' => $draft['id'], + 'status' => 'draft', + 'expires_at' => $expiresAt->toISOString(), + ]; + + if (! empty($warnings)) { + $response['warnings'] = array_values($warnings); + } + + return response()->json($response, Response::HTTP_OK); + } catch (Throwable $e) { + logger()->error('Upload preload failed', ['error' => $e->getMessage()]); + return response()->json(['message' => 'Preload failed.'], Response::HTTP_INTERNAL_SERVER_ERROR); + } + } + + public function autosave(string $id, Request $request) + { + $user = $request->user(); + + $upload = DB::table('uploads')->where('id', $id)->first(); + if (! $upload) { + return response()->json(['message' => 'Upload draft not found.'], Response::HTTP_NOT_FOUND); + } + + if ((int) $upload->user_id !== (int) $user->id) { + return response()->json(['message' => 'Forbidden.'], Response::HTTP_FORBIDDEN); + } + + if ((string) $upload->status !== 'draft') { + return response()->json([ + 'message' => 'Only draft uploads can be autosaved.', + ], Response::HTTP_UNPROCESSABLE_ENTITY); + } + + $validated = $request->validate([ + 'title' => ['nullable', 'string', 'max:255'], + 'category_id' => ['nullable', 'exists:categories,id'], + 'description' => ['nullable', 'string'], + 'tags' => ['nullable', 'array'], + 'license' => ['nullable', 'string'], + 'nsfw' => ['nullable', 'boolean'], + ]); + + $updates = []; + foreach (['title', 'category_id', 'description', 'tags', 'license', 'nsfw'] as $field) { + if (array_key_exists($field, $validated)) { + $updates[$field] = $validated[$field]; + } + } + + $dirty = []; + foreach ($updates as $field => $value) { + $current = $upload->{$field} ?? null; + + if ($field === 'tags') { + $current = $current ? json_decode((string) $current, true) : null; + } + + if ($field === 'nsfw') { + $current = is_null($current) ? null : (bool) $current; + $value = is_null($value) ? null : (bool) $value; + } + + if ($current !== $value) { + $dirty[$field] = $value; + } + } + + if (array_key_exists('tags', $dirty)) { + $dirty['tags'] = json_encode($dirty['tags']); + } + + if (! empty($dirty)) { + $dirty['updated_at'] = now(); + DB::table('uploads')->where('id', $id)->update($dirty); + $upload = DB::table('uploads')->where('id', $id)->first(); + } + + return response()->json([ + 'success' => true, + 'updated_at' => (string) ($upload->updated_at ?? now()->toDateTimeString()), + ], Response::HTTP_OK); + } + + public function processingStatus(string $id, Request $request) + { + $user = $request->user(); + + $upload = DB::table('uploads')->where('id', $id)->first(); + if (! $upload) { + return response()->json(['message' => 'Upload not found.'], Response::HTTP_NOT_FOUND); + } + + if ((int) $upload->user_id !== (int) $user->id) { + return response()->json(['message' => 'Forbidden.'], Response::HTTP_FORBIDDEN); + } + + $status = (string) ($upload->status ?? 'draft'); + $isScanned = (bool) ($upload->is_scanned ?? false); + $previewReady = ! empty($upload->preview_path); + $hasTags = (bool) ($upload->has_tags ?? false); + $processingState = (string) ($upload->processing_state ?? 'pending_scan'); + + return response()->json([ + 'id' => (string) $upload->id, + 'status' => $status, + 'is_scanned' => $isScanned, + 'preview_ready' => $previewReady, + 'has_tags' => $hasTags, + 'processing_state' => $processingState, + ], Response::HTTP_OK); + } + + public function publish(string $id, Request $request, PublishService $publishService) + { + $user = $request->user(); + + $validated = $request->validate([ + 'title' => ['nullable', 'string', 'max:150'], + 'description' => ['nullable', 'string'], + ]); + + if (ctype_digit($id)) { + $artworkId = (int) $id; + $artwork = Artwork::query()->find($artworkId); + if (! $artwork) { + return response()->json(['message' => 'Artwork not found.'], Response::HTTP_NOT_FOUND); + } + + if ((int) $artwork->user_id !== (int) $user->id) { + return response()->json(['message' => 'Forbidden.'], Response::HTTP_FORBIDDEN); + } + + $title = trim((string) ($validated['title'] ?? $artwork->title ?? '')); + if ($title === '') { + $title = 'Untitled artwork'; + } + + $slugBase = Str::slug($title); + if ($slugBase === '') { + $slugBase = 'artwork'; + } + + $slug = $slugBase; + $suffix = 2; + while (Artwork::query()->where('slug', $slug)->where('id', '!=', $artwork->id)->exists()) { + $slug = $slugBase . '-' . $suffix; + $suffix++; + } + + $artwork->title = $title; + if (array_key_exists('description', $validated)) { + $artwork->description = $validated['description']; + } + $artwork->slug = $slug; + $artwork->is_public = true; + $artwork->is_approved = true; + $artwork->published_at = now(); + $artwork->save(); + + return response()->json([ + 'success' => true, + 'artwork_id' => (int) $artwork->id, + 'status' => 'published', + 'slug' => (string) $artwork->slug, + 'published_at' => optional($artwork->published_at)->toISOString(), + ], Response::HTTP_OK); + } + + try { + $upload = $publishService->publish($id, $user); + + return response()->json([ + 'success' => true, + 'upload_id' => (string) $upload->id, + 'status' => (string) $upload->status, + 'published_at' => optional($upload->published_at)->toISOString(), + ], Response::HTTP_OK); + } catch (UploadOwnershipException $e) { + return response()->json(['message' => $e->getMessage()], Response::HTTP_FORBIDDEN); + } catch (UploadNotFoundException $e) { + return response()->json(['message' => $e->getMessage()], Response::HTTP_NOT_FOUND); + } catch (UploadPublishValidationException $e) { + return response()->json(['message' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY); + } + } +} diff --git a/app/Http/Controllers/ArtworkController.php b/app/Http/Controllers/ArtworkController.php index 5f1d67d0..f7e8267a 100644 --- a/app/Http/Controllers/ArtworkController.php +++ b/app/Http/Controllers/ArtworkController.php @@ -1,9 +1,12 @@ is_public || ! $artwork->is_approved || $artwork->trashed()) { + // Manually resolve artwork by slug when provided. The route may bind + // the 'artwork' parameter to an Artwork model or pass the slug string. + $foundArtwork = null; + $artworkSlug = null; + if ($artwork instanceof Artwork) { + $foundArtwork = $artwork; + $artworkSlug = $artwork->slug; + } elseif ($artwork) { + $artworkSlug = (string) $artwork; + $foundArtwork = Artwork::where('slug', $artworkSlug)->first(); + } + + // If no artwork was found, treat the request as a category path. + // The route places the artwork slug in the last segment, so include it + // when forwarding to CategoryPageController to support arbitrary-depth paths + if (! $foundArtwork) { + $combinedPath = $categoryPath; + if ($artworkSlug) { + $combinedPath = trim($categoryPath . '/' . $artworkSlug, '/'); + } + return app(CategoryPageController::class)->show(request(), $contentTypeSlug, $combinedPath); + } + + if (! $foundArtwork->is_public || ! $foundArtwork->is_approved || $foundArtwork->trashed()) { abort(404); } - return view('artworks.show', ['artwork' => $artwork]); + $foundArtwork->loadMissing(['categories.contentType', 'user']); + + $defaultAlgoVersion = (string) config('recommendations.embedding.algo_version', 'clip-cosine-v1'); + $selectedAlgoVersion = $this->selectAlgoVersionForRequest($request, $defaultAlgoVersion); + + $similarService = app(SimilarArtworksService::class); + $similarArtworks = $similarService->forArtwork((int) $foundArtwork->id, 12, $selectedAlgoVersion); + + if ($similarArtworks->isEmpty() && $selectedAlgoVersion !== $defaultAlgoVersion) { + $similarArtworks = $similarService->forArtwork((int) $foundArtwork->id, 12, $defaultAlgoVersion); + $selectedAlgoVersion = $defaultAlgoVersion; + } + + $similarArtworks->each(static function (Artwork $item): void { + $item->loadMissing(['categories.contentType', 'user']); + }); + + $similarItems = $similarArtworks + ->map(function (Artwork $item): ?array { + $category = $item->categories->first(); + $contentType = $category?->contentType; + + if (! $category || ! $contentType || empty($item->slug)) { + return null; + } + + return [ + 'id' => (int) $item->id, + 'title' => (string) $item->title, + 'author' => (string) optional($item->user)->name, + 'thumb' => (string) ($item->thumb_url ?? $item->thumb ?? '/gfx/sb_join.jpg'), + 'thumb_srcset' => (string) ($item->thumb_srcset ?? ''), + 'url' => route('artworks.show', [ + 'contentTypeSlug' => (string) $contentType->slug, + 'categoryPath' => (string) $category->slug, + 'artwork' => (string) $item->slug, + ]), + ]; + }) + ->filter() + ->values(); + + return view('artworks.show', [ + 'artwork' => $foundArtwork, + 'similarItems' => $similarItems, + 'similarAlgoVersion' => $selectedAlgoVersion, + ]); + } + + private function selectAlgoVersionForRequest(Request $request, string $default): string + { + $configured = (array) config('recommendations.ab.algo_versions', []); + $versions = array_values(array_filter(array_map(static fn ($value): string => trim((string) $value), $configured))); + + if ($versions === []) { + return $default; + } + + if (! in_array($default, $versions, true)) { + array_unshift($versions, $default); + $versions = array_values(array_unique($versions)); + } + + $forced = trim((string) $request->query('algo_version', '')); + if ($forced !== '' && in_array($forced, $versions, true)) { + return $forced; + } + + if (count($versions) === 1) { + return $versions[0]; + } + + $visitorKey = $request->user()?->id + ? 'u:' . (string) $request->user()->id + : 's:' . (string) $request->session()->getId(); + + $bucket = abs(crc32($visitorKey)) % count($versions); + + return $versions[$bucket] ?? $default; } } diff --git a/app/Http/Controllers/AvatarController.php b/app/Http/Controllers/AvatarController.php new file mode 100644 index 00000000..b80150de --- /dev/null +++ b/app/Http/Controllers/AvatarController.php @@ -0,0 +1,47 @@ +service = $service; + } + + /** + * Handle avatar upload request. + */ + public function upload(Request $request) + { + $user = Auth::user(); + if (!$user) { + return response()->json(['error' => 'Unauthorized'], 401); + } + + $rules = [ + 'avatar' => 'required|image|max:2048|mimes:jpg,jpeg,png,webp', + ]; + + $validator = Validator::make($request->all(), $rules); + if ($validator->fails()) { + return response()->json(['errors' => $validator->errors()], 422); + } + + $file = $request->file('avatar'); + + try { + $hash = $this->service->storeFromUploadedFile($user->id, $file); + return response()->json(['success' => true, 'hash' => $hash], 200); + } catch (\Exception $e) { + return response()->json(['error' => 'Processing failed', 'message' => $e->getMessage()], 500); + } + } +} diff --git a/app/Http/Controllers/CategoryPageController.php b/app/Http/Controllers/CategoryPageController.php index 32756ad6..3bee4994 100644 --- a/app/Http/Controllers/CategoryPageController.php +++ b/app/Http/Controllers/CategoryPageController.php @@ -5,12 +5,13 @@ namespace App\Http\Controllers; use App\Models\Category; use App\Models\ContentType; use App\Models\Artwork; +use App\Services\ArtworkService; use Illuminate\Http\Request; use Illuminate\Pagination\LengthAwarePaginator; class CategoryPageController extends Controller { - public function show(Request $request, string $contentTypeSlug, string $categoryPath = null) + public function show(Request $request, string $contentTypeSlug, ?string $categoryPath = null) { $contentType = ContentType::where('slug', strtolower($contentTypeSlug))->first(); if (! $contentType) { @@ -24,38 +25,51 @@ class CategoryPageController extends Controller $page_title = $contentType->name; $page_meta_description = $contentType->description ?? ($contentType->name . ' artworks on Skinbase'); + // Load artworks for this content type (show gallery on the root page) + $perPage = 40; + $artworks = Artwork::whereHas('categories', function ($q) use ($contentType) { + $q->where('categories.content_type_id', $contentType->id); + }) + ->published()->public() + ->with([ + 'user:id,name', + 'categories' => function ($q) { + $q->select('categories.id', 'categories.content_type_id', 'categories.parent_id', 'categories.name', 'categories.slug', 'categories.sort_order') + ->with(['parent:id,parent_id,content_type_id,name,slug', 'contentType:id,slug,name']); + }, + ]) + ->orderBy('published_at', 'desc') + ->paginate($perPage) + ->withQueryString(); + return view('legacy.content-type', compact( 'contentType', 'rootCategories', + 'artworks', 'page_title', 'page_meta_description' )); } $segments = array_filter(explode('/', $categoryPath)); - if (empty($segments)) { + $slugs = array_values(array_map('strtolower', $segments)); + if (empty($slugs)) { return redirect('/browse-categories'); } - // Traverse categories by slug path within the content type - $current = Category::where('content_type_id', $contentType->id) - ->whereNull('parent_id') - ->where('slug', strtolower(array_shift($segments))) - ->first(); + // If the first slug exists but under a different content type, redirect to its canonical URL + $firstSlug = $slugs[0]; + $globalRoot = Category::whereNull('parent_id')->where('slug', $firstSlug)->first(); + if ($globalRoot && $globalRoot->contentType && $globalRoot->contentType->slug !== strtolower($contentType->slug)) { + $redirectPath = '/' . $globalRoot->contentType->slug . '/' . implode('/', $slugs); + return redirect($redirectPath, 301); + } - - if (! $current) { + // Resolve category by path using the helper that validates parent chain and content type + $category = Category::findByPath($contentType->slug, $slugs); + if (! $category) { abort(404); } - - foreach ($segments as $slug) { - $current = $current->children()->where('slug', strtolower($slug))->first(); - if (! $current) { - abort(404); - } - } - - $category = $current; $subcategories = $category->children()->orderBy('sort_order')->orderBy('name')->get(); $rootCategories = $contentType->rootCategories()->orderBy('sort_order')->orderBy('name')->get(); @@ -71,21 +85,23 @@ class CategoryPageController extends Controller $category->load('children'); $gather($category); - // Load artworks that are attached to any of these categories - $query = Artwork::whereHas('categories', function ($q) use ($collected) { - $q->whereIn('categories.id', $collected); - })->published()->public(); - - // Paginate results + // Load artworks via ArtworkService to support arbitrary-depth category paths $perPage = 40; - $artworks = $query->orderBy('published_at', 'desc') - ->paginate($perPage) - ->withQueryString(); + try { + $service = app(ArtworkService::class); + // service expects an array with contentType slug first, then category slugs + $pathSlugs = array_merge([strtolower($contentTypeSlug)], $slugs); + $artworks = $service->getArtworksByCategoryPath($pathSlugs, $perPage); + } catch (\Throwable $e) { + abort(404); + } $page_title = $category->name; $page_meta_description = $category->description ?? ($contentType->name . ' artworks on Skinbase'); $page_meta_keywords = strtolower($contentType->slug) . ', skinbase, artworks, wallpapers, skins, photography'; + // resolved category and breadcrumbs are used by the view + return view('legacy.category-slug', compact( 'contentType', 'category', diff --git a/app/Http/Controllers/ContentRouterController.php b/app/Http/Controllers/ContentRouterController.php new file mode 100644 index 00000000..f4130e57 --- /dev/null +++ b/app/Http/Controllers/ContentRouterController.php @@ -0,0 +1,45 @@ +show($request, $contentTypeSlug, $normalizedCategoryPath, $artwork); + } + + $path = $categoryPath; + + // If no path provided, render the content-type landing (root) page + if (empty($path)) { + // Special-case photography root to use legacy controller + if (strtolower($contentTypeSlug) === 'photography') { + return app(\App\Http\Controllers\Legacy\PhotographyController::class)->index($request); + } + + return app(\App\Http\Controllers\CategoryPageController::class)->show($request, $contentTypeSlug, null); + } + + $segments = array_values(array_filter(explode('/', $path))); + if (empty($segments)) { + return app(\App\Http\Controllers\CategoryPageController::class)->show($request, $contentTypeSlug, null); + } + + // Treat the last segment as an artwork slug candidate and delegate to ArtworkController::show + $artworkSlug = array_pop($segments); + $categoryPath = implode('/', $segments); + + return app(ArtworkController::class)->show($request, $contentTypeSlug, $categoryPath, $artworkSlug); + } +} diff --git a/app/Http/Controllers/Dashboard/ArtworkController.php b/app/Http/Controllers/Dashboard/ArtworkController.php index bb0451d7..895b196e 100644 --- a/app/Http/Controllers/Dashboard/ArtworkController.php +++ b/app/Http/Controllers/Dashboard/ArtworkController.php @@ -3,8 +3,9 @@ namespace App\Http\Controllers\Dashboard; use App\Http\Controllers\Controller; +use App\Http\Requests\Dashboard\ArtworkEditRequest; +use App\Http\Requests\Dashboard\ArtworkDestroyRequest; use App\Http\Requests\Dashboard\UpdateArtworkRequest; -use App\Models\Artwork; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; @@ -25,10 +26,9 @@ class ArtworkController extends Controller ]); } - public function edit(Request $request, int $id): View + public function edit(ArtworkEditRequest $request, int $id): View { - $artwork = $request->user()->artworks()->whereKey($id)->firstOrFail(); - $this->authorize('update', $artwork); + $artwork = $request->artwork(); return view('artworks.edit', [ 'artwork' => $artwork, @@ -38,8 +38,7 @@ class ArtworkController extends Controller public function update(UpdateArtworkRequest $request, int $id): RedirectResponse { - $artwork = $request->user()->artworks()->whereKey($id)->firstOrFail(); - $this->authorize('update', $artwork); + $artwork = $request->artwork(); $data = $request->validated(); @@ -83,10 +82,9 @@ class ArtworkController extends Controller ->with('status', 'Artwork updated.'); } - public function destroy(Request $request, int $id): RedirectResponse + public function destroy(ArtworkDestroyRequest $request, int $id): RedirectResponse { - $artwork = $request->user()->artworks()->whereKey($id)->firstOrFail(); - $this->authorize('delete', $artwork); + $artwork = $request->artwork(); // Best-effort remove stored file. if (! empty($artwork->file_path) && Storage::disk('public')->exists($artwork->file_path)) { diff --git a/app/Http/Controllers/Legacy/PhotographyController.php b/app/Http/Controllers/Legacy/PhotographyController.php index b804f274..4c0d1d3b 100644 --- a/app/Http/Controllers/Legacy/PhotographyController.php +++ b/app/Http/Controllers/Legacy/PhotographyController.php @@ -21,61 +21,105 @@ class PhotographyController extends Controller public function index(Request $request) { // Legacy group mapping: Photography => id 3 - $group = 'Photography'; - $id = 3; + // Determine the requested content type from the first URL segment (photography|wallpapers|skins) + $segment = strtolower($request->segment(1) ?? 'photography'); + $contentSlug = in_array($segment, ['photography','wallpapers','skins','other']) ? $segment : 'photography'; - // Fetch legacy category info if available - $category = null; - try { - if (Schema::hasTable('artworks_categories')) { - $category = DB::table('artworks_categories') - ->select('category_name', 'rootid', 'section_id', 'description', 'category_id') - ->where('category_id', $id) - ->first(); + // Human-friendly group name (used by legacy templates) + $group = ucfirst($contentSlug); + + // Try to load legacy category id only for photography (legacy mapping); otherwise prefer authoritative ContentType + $id = null; + if ($contentSlug === 'photography') { + $id = 3; // legacy root id for photography in oldSite (kept for backward compatibility) } - } catch (\Throwable $e) { + + // Fetch legacy category info if available (only when we have an id) $category = null; - } - - $page_title = $category->category_name ?? 'Photography'; - $tidy = $category->description ?? null; - - $perPage = 40; - - // Use ArtworkService to get artworks for the content type 'photography' - try { - $artworks = $this->artworks->getArtworksByContentType('photography', $perPage); - } catch (\Throwable $e) { - $artworks = collect(); - } - - // Load subcategories (legacy) if available - $subcategories = collect(); - try { - if (Schema::hasTable('artworks_categories')) { - $subcategories = DB::table('artworks_categories')->select('category_id','category_name')->where('rootid', $id)->orderBy('category_name')->get(); - if ($subcategories->count() == 0 && !empty($category->rootid)) { - $subcategories = DB::table('artworks_categories')->select('category_id','category_name')->where('rootid', $category->rootid)->orderBy('category_name')->get(); + try { + if ($id !== null && Schema::hasTable('artworks_categories')) { + $category = DB::table('artworks_categories') + ->select('category_name', 'rootid', 'section_id', 'description', 'category_id') + ->where('category_id', $id) + ->first(); } + } catch (\Throwable $e) { + $category = null; } - } catch (\Throwable $e) { - $subcategories = collect(); - } - // Fallback to authoritative categories table when legacy table is missing/empty - if (! $subcategories || $subcategories->count() === 0) { - $ct = ContentType::where('slug', 'photography')->first(); - if ($ct) { - $subcategories = $ct->rootCategories() - ->orderBy('sort_order') - ->orderBy('name') - ->get() - ->map(fn ($c) => (object) ['category_id' => $c->id, 'category_name' => $c->name]); - } else { + // Page title and description: prefer legacy category when present, otherwise use ContentType data + $ct = ContentType::where('slug', $contentSlug)->first(); + $page_title = $category->category_name ?? ($ct->name ?? ucfirst($contentSlug)); + $tidy = $category->description ?? ($ct->description ?? null); + + $perPage = 40; + + // Load artworks for the requested content type using standard pagination + try { + $artQuery = \App\Models\Artwork::public() + ->published() + ->whereHas('categories', function ($q) use ($ct) { + $q->where('categories.content_type_id', $ct->id); + }) + ->with([ + 'user:id,name', + 'categories' => function ($q) { + $q->select('categories.id', 'categories.content_type_id', 'categories.parent_id', 'categories.name', 'categories.slug', 'categories.sort_order') + ->with(['parent:id,parent_id,content_type_id,name,slug', 'contentType:id,slug,name']); + }, + ]) + ->orderByDesc('published_at'); + + $artworks = $artQuery->paginate($perPage)->withQueryString(); + } catch (\Throwable $e) { + // Return an empty paginator so views using ->links() / ->firstItem() work + $artworks = new \Illuminate\Pagination\LengthAwarePaginator([], 0, $perPage, 1, [ + 'path' => url()->current(), + ]); + } + + // Load subcategories: prefer legacy table when id present and data exists, otherwise use ContentType root categories + $subcategories = collect(); + try { + if ($id !== null && Schema::hasTable('artworks_categories')) { + $subcategories = DB::table('artworks_categories')->select('category_id','category_name')->where('rootid', $id)->orderBy('category_name')->get(); + if ($subcategories->count() == 0 && !empty($category->rootid)) { + $subcategories = DB::table('artworks_categories')->select('category_id','category_name')->where('rootid', $category->rootid)->orderBy('category_name')->get(); + } + } + } catch (\Throwable $e) { $subcategories = collect(); } - } - return view('legacy.photography', compact('page_title','tidy','group','artworks','subcategories','id')); + if (! $subcategories || $subcategories->count() === 0) { + if ($ct) { + $subcategories = $ct->rootCategories() + ->orderBy('sort_order') + ->orderBy('name') + ->get() + ->map(fn ($c) => (object) ['category_id' => $c->id, 'category_name' => $c->name, 'slug' => $c->slug]); + } else { + $subcategories = collect(); + } + } + + // Coerce collections to a paginator so the view's pagination helpers work + if ($artworks instanceof \Illuminate\Database\Eloquent\Collection || $artworks instanceof \Illuminate\Support\Collection) { + $page = (int) ($request->query('page', 1)); + $artworks = new \Illuminate\Pagination\LengthAwarePaginator($artworks->values()->all(), $artworks->count(), $perPage, $page, [ + 'path' => url()->current(), + 'query' => request()->query(), + ]); + } + + // Prepare variables for the modern content-type view + $contentType = ContentType::where('slug', $contentSlug)->first(); + $rootCategories = $contentType + ? $contentType->rootCategories()->orderBy('sort_order')->orderBy('name')->get() + : collect(); + + $page_meta_description = $tidy; + + return view('legacy.content-type', compact('contentType','rootCategories','artworks','page_title','page_meta_description','subcategories','id')); } } diff --git a/app/Http/Controllers/Legacy/UserController.php b/app/Http/Controllers/Legacy/UserController.php index 8f199c01..a8a35464 100644 --- a/app/Http/Controllers/Legacy/UserController.php +++ b/app/Http/Controllers/Legacy/UserController.php @@ -37,29 +37,46 @@ class UserController extends Controller $request->session()->flash('error', 'Password not changed.'); } } else { - $data = $request->only(['real_name','web','country_code','signature','description','about_me']); - $user->real_name = $data['real_name'] ?? $user->real_name; - $user->web = $data['web'] ?? $user->web; - $user->country_code = $data['country_code'] ?? $user->country_code; - $user->signature = $data['signature'] ?? $user->signature; - $user->description = $data['description'] ?? $user->description; - $user->about_me = $data['about_me'] ?? $user->about_me; + // Map legacy form fields into the modern schema. + $data = $request->only(['name','web','country_code','signature','description','about_me']); + + // Core user column: `name` + if (isset($data['name'])) { + $user->name = $data['name'] ?? $user->name; + } + + // Collect other profile updates to persist into `user_profiles` when available + $profileUpdates = []; + if (!empty($data['web'])) $profileUpdates['website'] = $data['web']; + if (!empty($data['signature'])) $profileUpdates['signature'] = $data['signature']; + if (!empty($data['description'])) $profileUpdates['description'] = $data['description']; + if (!empty($data['about_me'])) $profileUpdates['about'] = $data['about_me']; + if (!empty($data['country_code'])) $profileUpdates['country_code'] = $data['country_code']; $d1 = $request->input('date1'); $d2 = $request->input('date2'); $d3 = $request->input('date3'); if ($d1 && $d2 && $d3) { - $user->birth = sprintf('%04d-%02d-%02d', (int)$d3, (int)$d2, (int)$d1); + $profileUpdates['birthdate'] = sprintf('%04d-%02d-%02d', (int)$d3, (int)$d2, (int)$d1); } - $user->gender = $request->input('gender', $user->gender); - $user->mlist = $request->has('newsletter') ? 1 : 0; - $user->friend_upload_notice = $request->has('friend_upload_notice') ? 1 : 0; + $userGender = $request->input('gender', $user->gender); + if (!empty($userGender)) { + $g = strtolower($userGender); + $map = ['m' => 'M', 'f' => 'F', 'n' => 'X', 'x' => 'X']; + $profileUpdates['gender'] = $map[$g] ?? strtoupper($userGender); + } + $profileUpdates['mlist'] = $request->has('newsletter') ? 1 : 0; + $profileUpdates['friend_upload_notice'] = $request->has('friend_upload_notice') ? 1 : 0; + + // Files: avatar/photo/emoticon if ($request->hasFile('avatar')) { $f = $request->file('avatar'); $name = $user->id . '.' . $f->getClientOriginalExtension(); $f->move(public_path('avatar'), $name); + // store filename in profile avatar (legacy field) — modern avatar pipeline will later migrate + $profileUpdates['avatar'] = $name; $user->icon = $name; } @@ -67,6 +84,7 @@ class UserController extends Controller $f = $request->file('personal_picture'); $name = $user->id . '.' . $f->getClientOriginalExtension(); $f->move(public_path('user-picture'), $name); + $profileUpdates['cover_image'] = $name; $user->picture = $name; } @@ -77,25 +95,28 @@ class UserController extends Controller $user->eicon = $name; } + // Save core user fields $user->save(); + + // Persist profile updates into `user_profiles` when available, otherwise fallback to `users` table + try { + if (!empty($profileUpdates) && Schema::hasTable('user_profiles')) { + DB::table('user_profiles')->updateOrInsert(['user_id' => $user->id], $profileUpdates + ['updated_at' => now(), 'created_at' => now()]); + } elseif (!empty($profileUpdates)) { + DB::table('users')->where('id', $user->id)->update($profileUpdates); + } + } catch (\Throwable $e) { + // ignore persistence errors for legacy path + } + $request->session()->flash('status', 'Profile updated.'); } } - // Prepare birth date parts for the legacy form + // Prepare birth date parts for the legacy form (initialized — parsed after merging profiles) $birthDay = null; $birthMonth = null; $birthYear = null; - if (! empty($user->birth)) { - try { - $dt = Carbon::parse($user->birth); - $birthDay = $dt->format('d'); - $birthMonth = $dt->format('m'); - $birthYear = $dt->format('Y'); - } catch (\Throwable $e) { - // ignore parse errors - } - } // Load country list if available (legacy table names) $countries = collect(); @@ -109,6 +130,50 @@ class UserController extends Controller $countries = collect(); } + // Merge modern `user_profiles` and `user_social_links` into the user object for the view + try { + if (Schema::hasTable('user_profiles')) { + $profile = DB::table('user_profiles')->where('user_id', $user->id)->first(); + if ($profile) { + // map modern profile fields onto the legacy user properties/helpers used by the view + if (isset($profile->website)) $user->homepage = $profile->website; + if (isset($profile->about)) $user->about_me = $profile->about; + if (isset($profile->birthdate)) $user->birth = $profile->birthdate; + if (isset($profile->gender)) $user->gender = $profile->gender; + if (isset($profile->country_code)) $user->country_code = $profile->country_code; + if (isset($profile->avatar)) $user->icon = $profile->avatar; + if (isset($profile->cover_image)) $user->picture = $profile->cover_image; + if (isset($profile->signature)) $user->signature = $profile->signature; + if (isset($profile->description)) $user->description = $profile->description; + } + } + } catch (\Throwable $e) { + // ignore profile merge errors + } + + try { + if (Schema::hasTable('user_social_links')) { + $social = DB::table('user_social_links')->where('user_id', $user->id)->first(); + if ($social) { + $user->social = $social; + } + } + } catch (\Throwable $e) { + // ignore social links errors + } + + // Parse birth date parts after merging `user_profiles` so profile birthdate is used + if (! empty($user->birth)) { + try { + $dt = Carbon::parse($user->birth); + $birthDay = $dt->format('d'); + $birthMonth = $dt->format('m'); + $birthYear = $dt->format('Y'); + } catch (\Throwable $e) { + // ignore parse errors + } + } + return view('legacy.user', [ 'user' => $user, 'birthDay' => $birthDay, diff --git a/app/Http/Controllers/ManageController.php b/app/Http/Controllers/ManageController.php index 611cc6ce..f8f53576 100644 --- a/app/Http/Controllers/ManageController.php +++ b/app/Http/Controllers/ManageController.php @@ -2,8 +2,9 @@ namespace App\Http\Controllers; -use App\Models\Artwork; -use App\Models\ArtworkCategory; +use App\Http\Requests\Manage\ManageArtworkEditRequest; +use App\Http\Requests\Manage\ManageArtworkUpdateRequest; +use App\Http\Requests\Manage\ManageArtworkDestroyRequest; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\DB; @@ -38,13 +39,9 @@ class ManageController extends Controller ]); } - public function edit(Request $request, $id) + public function edit(ManageArtworkEditRequest $request, $id) { - $userId = $request->user()->id; - $artwork = DB::table('artworks')->where('id', (int)$id)->where('user_id', $userId)->first(); - if (! $artwork) { - abort(404); - } + $artwork = $request->artwork(); // If artworks no longer have a single `category` column, fetch pivot selection $selectedCategory = DB::table('artwork_category')->where('artwork_id', (int)$id)->value('category_id'); @@ -63,22 +60,10 @@ class ManageController extends Controller ]); } - public function update(Request $request, $id) + public function update(ManageArtworkUpdateRequest $request, $id) { - $userId = $request->user()->id; - $existing = DB::table('artworks')->where('id', (int)$id)->where('user_id', $userId)->first(); - - if (! $existing) { - abort(404); - } - - $data = $request->validate([ - 'name' => 'required|string|max:255', - 'section' => 'nullable|integer', - 'description' => 'nullable|string', - 'artwork' => 'nullable|file|image', - 'attachment' => 'nullable|file', - ]); + $existing = $request->artwork(); + $data = $request->validated(); $update = [ 'name' => $data['name'], 'description' => $data['description'] ?? $existing->description, @@ -100,7 +85,7 @@ class ManageController extends Controller $update['fname'] = basename($attPath); } - DB::table('artworks')->where('id', (int)$id)->where('user_id', $userId)->update($update); + DB::table('artworks')->where('id', (int)$id)->update($update); // Update pivot: set single category selection for this artwork if (isset($data['section'])) { @@ -114,13 +99,9 @@ class ManageController extends Controller return redirect()->route('manage')->with('status', 'Artwork was successfully updated.'); } - public function destroy(Request $request, $id) + public function destroy(ManageArtworkDestroyRequest $request, $id) { - $userId = $request->user()->id; - $artwork = DB::table('artworks')->where('id', (int)$id)->where('user_id', $userId)->first(); - if (! $artwork) { - abort(404); - } + $artwork = $request->artwork(); // delete files if present (stored in new storage location) if (!empty($artwork->fname)) { @@ -130,7 +111,7 @@ class ManageController extends Controller Storage::delete('public/uploads/artworks/' . $artwork->picture); } - DB::table('artworks')->where('id', (int)$id)->where('user_id', $userId)->delete(); + DB::table('artworks')->where('id', (int)$id)->delete(); return redirect()->route('manage')->with('status', 'Artwork deleted.'); } diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index 19f9c9bc..d2d80cb6 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -8,6 +8,8 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Redirect; use Illuminate\View\View; +use Illuminate\Support\Facades\Hash; +use Illuminate\Validation\Rules\Password as PasswordRule; class ProfileController extends Controller { @@ -24,17 +26,124 @@ class ProfileController extends Controller /** * Update the user's profile information. */ - public function update(ProfileUpdateRequest $request): RedirectResponse + public function update(ProfileUpdateRequest $request, \App\Services\AvatarService $avatarService): RedirectResponse { - $request->user()->fill($request->validated()); + $user = $request->user(); - if ($request->user()->isDirty('email')) { - $request->user()->email_verified_at = null; + // Core fields + $validated = $request->validated(); + + logger()->debug('Profile update validated data', $validated); + + // Username is read-only and must not be changed here. + // Use `name` for the real/display name field. + if (isset($validated['name'])) { + $user->name = $validated['name']; } - $request->user()->save(); + // Only allow setting email when we don't have one yet (legacy users) + if (!empty($validated['email']) && empty($user->email)) { + $user->email = $validated['email']; + $user->email_verified_at = null; + } - return Redirect::route('profile.edit')->with('status', 'profile-updated'); + $user->save(); + + // Profile fields - target columns in `user_profiles` per spec + $profileUpdates = []; + if (!empty($validated['about'])) $profileUpdates['about'] = $validated['about']; + + // website / legacy homepage + if (!empty($validated['web'])) { + $profileUpdates['website'] = $validated['web']; + } elseif (!empty($validated['homepage'])) { + $profileUpdates['website'] = $validated['homepage']; + } + + // Birthday -> store as birthdate + $day = $validated['day'] ?? null; + $month = $validated['month'] ?? null; + $year = $validated['year'] ?? null; + if ($year && $month && $day) { + $profileUpdates['birthdate'] = sprintf('%04d-%02d-%02d', (int)$year, (int)$month, (int)$day); + } + + // Gender normalization -> store as provided normalized value + if (!empty($validated['gender'])) { + $g = strtolower($validated['gender']); + $map = ['m' => 'M', 'f' => 'F', 'n' => 'X', 'x' => 'X']; + $profileUpdates['gender'] = $map[$g] ?? strtoupper($validated['gender']); + } + + if (!empty($validated['country'])) $profileUpdates['country_code'] = $validated['country']; + + // Mailing and notify flags: normalize true/false when saving + if (array_key_exists('mailing', $validated)) { + $profileUpdates['mlist'] = filter_var($validated['mailing'], FILTER_VALIDATE_BOOLEAN) ? 1 : 0; + } + if (array_key_exists('notify', $validated)) { + $profileUpdates['friend_upload_notice'] = filter_var($validated['notify'], FILTER_VALIDATE_BOOLEAN) ? 1 : 0; + } + + // signature/description should be stored in their own columns + if (isset($validated['signature'])) $profileUpdates['signature'] = $validated['signature']; + if (isset($validated['description'])) $profileUpdates['description'] = $validated['description']; + + // 'about' direct field (ensure explicit about wins when provided) + if (isset($validated['about'])) $profileUpdates['about'] = $validated['about']; + + // Files: avatar -> use AvatarService, emoticon and photo -> store to public disk + if ($request->hasFile('avatar')) { + try { + $hash = $avatarService->storeFromUploadedFile($user->id, $request->file('avatar')); + // store returned hash into profile avatar column + if (!empty($hash)) { + $profileUpdates['avatar'] = $hash; + } + } catch (\Exception $e) { + return Redirect::back()->with('error', 'Avatar processing failed: ' . $e->getMessage()); + } + } + + if ($request->hasFile('emoticon')) { + $file = $request->file('emoticon'); + $fname = $file->getClientOriginalName(); + $path = \Illuminate\Support\Facades\Storage::disk('public')->putFileAs('user-emoticons/'.$user->id, $file, $fname); + try { + \Illuminate\Support\Facades\DB::table('users')->where('id', $user->id)->update(['eicon' => $fname]); + } catch (\Exception $e) {} + } + + if ($request->hasFile('photo')) { + $file = $request->file('photo'); + $fname = $file->getClientOriginalName(); + $path = \Illuminate\Support\Facades\Storage::disk('public')->putFileAs('user-picture/'.$user->id, $file, $fname); + // store cover image filename in user_profiles.cover_image (fallback to users.picture) + if (\Illuminate\Support\Facades\Schema::hasTable('user_profiles')) { + $profileUpdates['cover_image'] = $fname; + } else { + try { + \Illuminate\Support\Facades\DB::table('users')->where('id', $user->id)->update(['picture' => $fname]); + } catch (\Exception $e) {} + } + } + + // Persist profile updates now that files (avatar/cover) have been handled + try { + if (\Illuminate\Support\Facades\Schema::hasTable('user_profiles')) { + if (!empty($profileUpdates)) { + \Illuminate\Support\Facades\DB::table('user_profiles')->updateOrInsert(['user_id' => $user->id], $profileUpdates); + } + } else { + if (!empty($profileUpdates)) { + \Illuminate\Support\Facades\DB::table('users')->where('id', $user->id)->update($profileUpdates); + } + } + } catch (\Exception $e) { + logger()->error('Profile update error: '.$e->getMessage()); + } + + return Redirect::to('/user')->with('status', 'profile-updated'); } /** @@ -58,4 +167,21 @@ class ProfileController extends Controller return Redirect::to('/'); } + + /** + * Update the user's password. + */ + public function password(Request $request): RedirectResponse + { + $request->validate([ + 'current_password' => ['required', 'current_password'], + 'password' => ['required', 'confirmed', PasswordRule::min(8)], + ]); + + $user = $request->user(); + $user->password = Hash::make($request->input('password')); + $user->save(); + + return Redirect::to('/user')->with('status', 'password-updated'); + } } diff --git a/app/Http/Controllers/Web/TagController.php b/app/Http/Controllers/Web/TagController.php new file mode 100644 index 00000000..cb9fc431 --- /dev/null +++ b/app/Http/Controllers/Web/TagController.php @@ -0,0 +1,29 @@ +artworks() + ->public() + ->published() + ->leftJoin('artwork_stats', 'artwork_stats.artwork_id', '=', 'artworks.id') + ->orderByDesc('artwork_stats.views') + ->orderByDesc('artworks.published_at') + ->select('artworks.*') + ->paginate(24); + + return view('tags.show', [ + 'tag' => $tag, + 'artworks' => $artworks, + ]); + } +} diff --git a/app/Http/Middleware/EnsureAdminOrModerator.php b/app/Http/Middleware/EnsureAdminOrModerator.php new file mode 100644 index 00000000..ae7c577a --- /dev/null +++ b/app/Http/Middleware/EnsureAdminOrModerator.php @@ -0,0 +1,24 @@ +user(); + $role = strtolower((string) ($user->role ?? '')); + + if (! in_array($role, ['admin', 'moderator'], true)) { + abort(Response::HTTP_FORBIDDEN, 'Forbidden.'); + } + + return $next($request); + } +} diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php new file mode 100644 index 00000000..179df07b --- /dev/null +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -0,0 +1,33 @@ + [ + 'user' => $request->user() ? [ + 'id' => $request->user()->id, + 'name' => $request->user()->name, + ] : null, + ], + 'cdn' => [ + 'files_url' => config('cdn.files_url'), + ], + ]); + } +} diff --git a/app/Http/Requests/Artworks/ArtworkCreateRequest.php b/app/Http/Requests/Artworks/ArtworkCreateRequest.php new file mode 100644 index 00000000..4606e64c --- /dev/null +++ b/app/Http/Requests/Artworks/ArtworkCreateRequest.php @@ -0,0 +1,46 @@ +user()) { + $this->logUnauthorized('missing_user'); + $this->denyAsNotFound(); + } + + return true; + } + + public function rules(): array + { + return [ + 'title' => 'required|string|max:150', + 'description' => 'nullable|string', + 'category' => 'nullable|string|max:120', + 'tags' => 'nullable|string|max:200', + 'license' => 'nullable|boolean', + ]; + } + + private function denyAsNotFound(): void + { + throw new NotFoundHttpException(); + } + + private function logUnauthorized(string $reason): void + { + logger()->warning('Artwork create unauthorized access', [ + 'reason' => $reason, + 'user_id' => $this->user()?->id, + 'ip' => $this->ip(), + ]); + } +} diff --git a/app/Http/Requests/Artworks/ArtworkTagsStoreRequest.php b/app/Http/Requests/Artworks/ArtworkTagsStoreRequest.php new file mode 100644 index 00000000..762dfdaf --- /dev/null +++ b/app/Http/Requests/Artworks/ArtworkTagsStoreRequest.php @@ -0,0 +1,28 @@ +user()) { + throw new NotFoundHttpException(); + } + + return true; + } + + public function rules(): array + { + return [ + 'tags' => 'required|array|max:15', + 'tags.*' => 'required|string|max:64', + ]; + } +} diff --git a/app/Http/Requests/Artworks/ArtworkTagsUpdateRequest.php b/app/Http/Requests/Artworks/ArtworkTagsUpdateRequest.php new file mode 100644 index 00000000..e97e6f29 --- /dev/null +++ b/app/Http/Requests/Artworks/ArtworkTagsUpdateRequest.php @@ -0,0 +1,28 @@ +user()) { + throw new NotFoundHttpException(); + } + + return true; + } + + public function rules(): array + { + return [ + 'tags' => 'required|array|max:15', + 'tags.*' => 'required|string|max:64', + ]; + } +} diff --git a/app/Http/Requests/Dashboard/ArtworkDestroyRequest.php b/app/Http/Requests/Dashboard/ArtworkDestroyRequest.php new file mode 100644 index 00000000..668969ae --- /dev/null +++ b/app/Http/Requests/Dashboard/ArtworkDestroyRequest.php @@ -0,0 +1,68 @@ +user(); + if (! $user) { + $this->logUnauthorized('missing_user'); + $this->denyAsNotFound(); + } + + $id = (int) $this->route('id'); + if ($id <= 0) { + $this->logUnauthorized('missing_artwork_id'); + $this->denyAsNotFound(); + } + + $artwork = Artwork::query()->whereKey($id)->first(); + if (! $artwork || (int) $artwork->user_id !== (int) $user->id) { + $this->logUnauthorized('artwork_not_owned_or_missing'); + $this->denyAsNotFound(); + } + + $this->artwork = $artwork; + + return true; + } + + public function rules(): array + { + return []; + } + + public function artwork(): Artwork + { + if (! $this->artwork) { + $this->denyAsNotFound(); + } + + return $this->artwork; + } + + private function denyAsNotFound(): void + { + throw new NotFoundHttpException(); + } + + private function logUnauthorized(string $reason): void + { + logger()->warning('Dashboard artwork delete unauthorized access', [ + 'reason' => $reason, + 'artwork_id' => $this->route('id'), + 'user_id' => $this->user()?->id, + 'ip' => $this->ip(), + ]); + } +} diff --git a/app/Http/Requests/Dashboard/ArtworkEditRequest.php b/app/Http/Requests/Dashboard/ArtworkEditRequest.php new file mode 100644 index 00000000..d1e2a898 --- /dev/null +++ b/app/Http/Requests/Dashboard/ArtworkEditRequest.php @@ -0,0 +1,68 @@ +user(); + if (! $user) { + $this->logUnauthorized('missing_user'); + $this->denyAsNotFound(); + } + + $id = (int) $this->route('id'); + if ($id <= 0) { + $this->logUnauthorized('missing_artwork_id'); + $this->denyAsNotFound(); + } + + $artwork = Artwork::query()->whereKey($id)->first(); + if (! $artwork || (int) $artwork->user_id !== (int) $user->id) { + $this->logUnauthorized('artwork_not_owned_or_missing'); + $this->denyAsNotFound(); + } + + $this->artwork = $artwork; + + return true; + } + + public function rules(): array + { + return []; + } + + public function artwork(): Artwork + { + if (! $this->artwork) { + $this->denyAsNotFound(); + } + + return $this->artwork; + } + + private function denyAsNotFound(): void + { + throw new NotFoundHttpException(); + } + + private function logUnauthorized(string $reason): void + { + logger()->warning('Dashboard artwork edit unauthorized access', [ + 'reason' => $reason, + 'artwork_id' => $this->route('id'), + 'user_id' => $this->user()?->id, + 'ip' => $this->ip(), + ]); + } +} diff --git a/app/Http/Requests/Dashboard/UpdateArtworkRequest.php b/app/Http/Requests/Dashboard/UpdateArtworkRequest.php index 6ea0abd5..f36c68ec 100644 --- a/app/Http/Requests/Dashboard/UpdateArtworkRequest.php +++ b/app/Http/Requests/Dashboard/UpdateArtworkRequest.php @@ -2,13 +2,36 @@ namespace App\Http\Requests\Dashboard; +use App\Models\Artwork; use Illuminate\Foundation\Http\FormRequest; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class UpdateArtworkRequest extends FormRequest { + private ?Artwork $artwork = null; + public function authorize(): bool { - // Authorization is enforced in the controller via ArtworkPolicy. + $user = $this->user(); + if (! $user) { + $this->logUnauthorized('missing_user'); + $this->denyAsNotFound(); + } + + $id = (int) $this->route('id'); + if ($id <= 0) { + $this->logUnauthorized('missing_artwork_id'); + $this->denyAsNotFound(); + } + + $artwork = Artwork::query()->whereKey($id)->first(); + if (! $artwork || (int) $artwork->user_id !== (int) $user->id) { + $this->logUnauthorized('artwork_not_owned_or_missing'); + $this->denyAsNotFound(); + } + + $this->artwork = $artwork; + return true; } @@ -21,4 +44,28 @@ class UpdateArtworkRequest extends FormRequest 'file' => 'nullable|image|max:102400', ]; } + + public function artwork(): Artwork + { + if (! $this->artwork) { + $this->denyAsNotFound(); + } + + return $this->artwork; + } + + private function denyAsNotFound(): void + { + throw new NotFoundHttpException(); + } + + private function logUnauthorized(string $reason): void + { + logger()->warning('Dashboard artwork update unauthorized access', [ + 'reason' => $reason, + 'artwork_id' => $this->route('id'), + 'user_id' => $this->user()?->id, + 'ip' => $this->ip(), + ]); + } } diff --git a/app/Http/Requests/Manage/ManageArtworkDestroyRequest.php b/app/Http/Requests/Manage/ManageArtworkDestroyRequest.php new file mode 100644 index 00000000..237b52a0 --- /dev/null +++ b/app/Http/Requests/Manage/ManageArtworkDestroyRequest.php @@ -0,0 +1,68 @@ +user(); + if (! $user) { + $this->logUnauthorized('missing_user'); + $this->denyAsNotFound(); + } + + $id = (int) $this->route('id'); + if ($id <= 0) { + $this->logUnauthorized('missing_artwork_id'); + $this->denyAsNotFound(); + } + + $artwork = DB::table('artworks')->where('id', $id)->first(); + if (! $artwork || (int) $artwork->user_id !== (int) $user->id) { + $this->logUnauthorized('artwork_not_owned_or_missing'); + $this->denyAsNotFound(); + } + + $this->artwork = $artwork; + + return true; + } + + public function rules(): array + { + return []; + } + + public function artwork(): object + { + if (! $this->artwork) { + $this->denyAsNotFound(); + } + + return $this->artwork; + } + + private function denyAsNotFound(): void + { + throw new NotFoundHttpException(); + } + + private function logUnauthorized(string $reason): void + { + logger()->warning('Manage artwork delete unauthorized access', [ + 'reason' => $reason, + 'artwork_id' => $this->route('id'), + 'user_id' => $this->user()?->id, + 'ip' => $this->ip(), + ]); + } +} diff --git a/app/Http/Requests/Manage/ManageArtworkEditRequest.php b/app/Http/Requests/Manage/ManageArtworkEditRequest.php new file mode 100644 index 00000000..7df8b5a2 --- /dev/null +++ b/app/Http/Requests/Manage/ManageArtworkEditRequest.php @@ -0,0 +1,68 @@ +user(); + if (! $user) { + $this->logUnauthorized('missing_user'); + $this->denyAsNotFound(); + } + + $id = (int) $this->route('id'); + if ($id <= 0) { + $this->logUnauthorized('missing_artwork_id'); + $this->denyAsNotFound(); + } + + $artwork = DB::table('artworks')->where('id', $id)->first(); + if (! $artwork || (int) $artwork->user_id !== (int) $user->id) { + $this->logUnauthorized('artwork_not_owned_or_missing'); + $this->denyAsNotFound(); + } + + $this->artwork = $artwork; + + return true; + } + + public function rules(): array + { + return []; + } + + public function artwork(): object + { + if (! $this->artwork) { + $this->denyAsNotFound(); + } + + return $this->artwork; + } + + private function denyAsNotFound(): void + { + throw new NotFoundHttpException(); + } + + private function logUnauthorized(string $reason): void + { + logger()->warning('Manage artwork edit unauthorized access', [ + 'reason' => $reason, + 'artwork_id' => $this->route('id'), + 'user_id' => $this->user()?->id, + 'ip' => $this->ip(), + ]); + } +} diff --git a/app/Http/Requests/Manage/ManageArtworkUpdateRequest.php b/app/Http/Requests/Manage/ManageArtworkUpdateRequest.php new file mode 100644 index 00000000..186d8054 --- /dev/null +++ b/app/Http/Requests/Manage/ManageArtworkUpdateRequest.php @@ -0,0 +1,74 @@ +user(); + if (! $user) { + $this->logUnauthorized('missing_user'); + $this->denyAsNotFound(); + } + + $id = (int) $this->route('id'); + if ($id <= 0) { + $this->logUnauthorized('missing_artwork_id'); + $this->denyAsNotFound(); + } + + $artwork = DB::table('artworks')->where('id', $id)->first(); + if (! $artwork || (int) $artwork->user_id !== (int) $user->id) { + $this->logUnauthorized('artwork_not_owned_or_missing'); + $this->denyAsNotFound(); + } + + $this->artwork = $artwork; + + return true; + } + + public function rules(): array + { + return [ + 'name' => 'required|string|max:255', + 'section' => 'nullable|integer', + 'description' => 'nullable|string', + 'artwork' => 'nullable|file|image', + 'attachment' => 'nullable|file', + ]; + } + + public function artwork(): object + { + if (! $this->artwork) { + $this->denyAsNotFound(); + } + + return $this->artwork; + } + + private function denyAsNotFound(): void + { + throw new NotFoundHttpException(); + } + + private function logUnauthorized(string $reason): void + { + logger()->warning('Manage artwork update unauthorized access', [ + 'reason' => $reason, + 'artwork_id' => $this->route('id'), + 'user_id' => $this->user()?->id, + 'ip' => $this->ip(), + ]); + } +} diff --git a/app/Http/Requests/ProfileUpdateRequest.php b/app/Http/Requests/ProfileUpdateRequest.php index 3622a8f3..588d90dd 100644 --- a/app/Http/Requests/ProfileUpdateRequest.php +++ b/app/Http/Requests/ProfileUpdateRequest.php @@ -16,7 +16,7 @@ class ProfileUpdateRequest extends FormRequest public function rules(): array { return [ - 'name' => ['required', 'string', 'max:255'], + 'username' => ['sometimes', 'string', 'max:255'], 'email' => [ 'required', 'string', @@ -25,6 +25,21 @@ class ProfileUpdateRequest extends FormRequest 'max:255', Rule::unique(User::class)->ignore($this->user()->id), ], + 'name' => ['nullable', 'string', 'max:255'], + 'web' => ['nullable', 'url', 'max:255'], + 'day' => ['nullable', 'numeric', 'between:1,31'], + 'month' => ['nullable', 'numeric', 'between:1,12'], + 'year' => ['nullable', 'numeric', 'digits:4'], + 'gender' => ['nullable', 'in:m,f,n,M,F,N,X,x'], + 'country' => ['nullable', 'string', 'max:10'], + 'mailing' => ['nullable', 'boolean'], + 'notify' => ['nullable', 'boolean'], + 'about' => ['nullable', 'string'], + 'signature' => ['nullable', 'string'], + 'description' => ['nullable', 'string'], + 'avatar' => ['nullable', 'image', 'max:2048', 'mimes:jpg,jpeg,png,webp'], + 'emoticon' => ['nullable', 'image', 'max:2048', 'mimes:jpg,jpeg,png,webp'], + 'photo' => ['nullable', 'image', 'max:2048', 'mimes:jpg,jpeg,png,webp'], ]; } } diff --git a/app/Http/Requests/Tags/PopularTagsRequest.php b/app/Http/Requests/Tags/PopularTagsRequest.php new file mode 100644 index 00000000..745c2826 --- /dev/null +++ b/app/Http/Requests/Tags/PopularTagsRequest.php @@ -0,0 +1,27 @@ +user()) { + throw new NotFoundHttpException(); + } + + return true; + } + + public function rules(): array + { + return [ + 'limit' => 'nullable|integer|min:1|max:50', + ]; + } +} diff --git a/app/Http/Requests/Tags/TagSearchRequest.php b/app/Http/Requests/Tags/TagSearchRequest.php new file mode 100644 index 00000000..75960e5c --- /dev/null +++ b/app/Http/Requests/Tags/TagSearchRequest.php @@ -0,0 +1,27 @@ +user()) { + throw new NotFoundHttpException(); + } + + return true; + } + + public function rules(): array + { + return [ + 'q' => 'nullable|string|max:64', + ]; + } +} diff --git a/app/Http/Requests/Uploads/UploadCancelRequest.php b/app/Http/Requests/Uploads/UploadCancelRequest.php new file mode 100644 index 00000000..8027f507 --- /dev/null +++ b/app/Http/Requests/Uploads/UploadCancelRequest.php @@ -0,0 +1,83 @@ +user(); + if (! $user) { + $this->logUnauthorized('missing_user'); + $this->denyAsNotFound(); + } + + $sessionId = (string) $this->input('session_id'); + if ($sessionId === '') { + $this->logUnauthorized('missing_session_id'); + $this->denyAsNotFound(); + } + + $token = $this->header('X-Upload-Token') ?: $this->input('upload_token'); + if (! $token) { + $this->logUnauthorized('missing_token'); + $this->denyAsNotFound(); + } + + $sessions = $this->container->make(UploadSessionRepository::class); + $session = $sessions->get($sessionId); + if (! $session || $session->userId !== $user->id) { + $this->logUnauthorized('not_owned_or_missing'); + $this->denyAsNotFound(); + } + + $tokens = $this->container->make(UploadTokenService::class); + $payload = $tokens->get((string) $token); + if (! $payload) { + $this->logUnauthorized('invalid_token'); + $this->denyAsNotFound(); + } + + if (($payload['session_id'] ?? null) !== $sessionId) { + $this->logUnauthorized('token_session_mismatch'); + $this->denyAsNotFound(); + } + + if ((int) ($payload['user_id'] ?? 0) !== (int) $user->id) { + $this->logUnauthorized('token_user_mismatch'); + $this->denyAsNotFound(); + } + + return true; + } + + public function rules(): array + { + return [ + 'session_id' => 'required|uuid', + 'upload_token' => 'nullable|string|min:40|max:200', + ]; + } + + private function denyAsNotFound(): void + { + throw new NotFoundHttpException(); + } + + private function logUnauthorized(string $reason): void + { + logger()->warning('Upload cancel unauthorized access', [ + 'reason' => $reason, + 'session_id' => (string) $this->input('session_id'), + 'user_id' => $this->user()?->id, + 'ip' => $this->ip(), + ]); + } +} diff --git a/app/Http/Requests/Uploads/UploadChunkRequest.php b/app/Http/Requests/Uploads/UploadChunkRequest.php new file mode 100644 index 00000000..4da808fd --- /dev/null +++ b/app/Http/Requests/Uploads/UploadChunkRequest.php @@ -0,0 +1,91 @@ +user(); + if (! $user) { + $this->logUnauthorized('missing_user'); + $this->denyAsNotFound(); + } + + $sessionId = (string) $this->input('session_id'); + if ($sessionId === '') { + $this->logUnauthorized('missing_session_id'); + $this->denyAsNotFound(); + } + + $token = $this->header('X-Upload-Token') ?: $this->input('upload_token'); + if (! $token) { + $this->logUnauthorized('missing_token'); + $this->denyAsNotFound(); + } + + $sessions = $this->container->make(UploadSessionRepository::class); + $session = $sessions->get($sessionId); + if (! $session || $session->userId !== $user->id) { + $this->logUnauthorized('not_owned_or_missing'); + $this->denyAsNotFound(); + } + + $tokens = $this->container->make(UploadTokenService::class); + $payload = $tokens->get((string) $token); + if (! $payload) { + $this->logUnauthorized('invalid_token'); + $this->denyAsNotFound(); + } + + if (($payload['session_id'] ?? null) !== $sessionId) { + $this->logUnauthorized('token_session_mismatch'); + $this->denyAsNotFound(); + } + + if ((int) ($payload['user_id'] ?? 0) !== (int) $user->id) { + $this->logUnauthorized('token_user_mismatch'); + $this->denyAsNotFound(); + } + + return true; + } + + public function rules(): array + { + $maxBytes = (int) config('uploads.chunk.max_bytes', 0); + $maxKb = $maxBytes > 0 ? (int) ceil($maxBytes / 1024) : 5120; + $chunkSizeRule = $maxBytes > 0 ? 'required|integer|min:1|max:' . $maxBytes : 'required|integer|min:1'; + + return [ + 'session_id' => 'required|uuid', + 'offset' => 'required|integer|min:0', + 'total_size' => 'required|integer|min:1', + 'chunk_size' => $chunkSizeRule, + 'chunk' => 'required|file|max:' . $maxKb, + 'upload_token' => 'nullable|string|min:40|max:200', + ]; + } + + private function denyAsNotFound(): void + { + throw new NotFoundHttpException(); + } + + private function logUnauthorized(string $reason): void + { + logger()->warning('Upload chunk unauthorized access', [ + 'reason' => $reason, + 'session_id' => (string) $this->input('session_id'), + 'user_id' => $this->user()?->id, + 'ip' => $this->ip(), + ]); + } +} diff --git a/app/Http/Requests/Uploads/UploadFinishRequest.php b/app/Http/Requests/Uploads/UploadFinishRequest.php new file mode 100644 index 00000000..b0553fbf --- /dev/null +++ b/app/Http/Requests/Uploads/UploadFinishRequest.php @@ -0,0 +1,108 @@ +user(); + if (! $user) { + $this->logUnauthorized('missing_user'); + $this->denyAsNotFound(); + } + + $sessionId = (string) $this->input('session_id'); + if ($sessionId === '') { + $this->logUnauthorized('missing_session_id'); + $this->denyAsNotFound(); + } + + $sessions = $this->container->make(UploadSessionRepository::class); + $session = $sessions->get($sessionId); + if (! $session || $session->userId !== $user->id) { + $this->logUnauthorized('not_owned_or_missing'); + $this->denyAsNotFound(); + } + + $token = $this->header('X-Upload-Token') ?: $this->input('upload_token'); + if ($token) { + $tokens = $this->container->make(UploadTokenService::class); + $payload = $tokens->get((string) $token); + if (! $payload) { + $this->logUnauthorized('invalid_token'); + $this->denyAsNotFound(); + } + + if (($payload['session_id'] ?? null) !== $sessionId) { + $this->logUnauthorized('token_session_mismatch'); + $this->denyAsNotFound(); + } + + if ((int) ($payload['user_id'] ?? 0) !== (int) $user->id) { + $this->logUnauthorized('token_user_mismatch'); + $this->denyAsNotFound(); + } + } + + $artworkId = (int) $this->input('artwork_id'); + if ($artworkId <= 0) { + $this->logUnauthorized('missing_artwork_id'); + $this->denyAsNotFound(); + } + + $artwork = Artwork::query()->find($artworkId); + if (! $artwork || (int) $artwork->user_id !== (int) $user->id) { + $this->logUnauthorized('artwork_not_owned_or_missing'); + $this->denyAsNotFound(); + } + + $this->artwork = $artwork; + + return true; + } + + public function rules(): array + { + return [ + 'session_id' => 'required|uuid', + 'artwork_id' => 'required|integer', + 'upload_token' => 'nullable|string|min:40|max:200', + ]; + } + + public function artwork(): Artwork + { + if (! $this->artwork) { + $this->denyAsNotFound(); + } + + return $this->artwork; + } + + private function denyAsNotFound(): void + { + throw new NotFoundHttpException(); + } + + private function logUnauthorized(string $reason): void + { + logger()->warning('Upload finish unauthorized access', [ + 'reason' => $reason, + 'session_id' => (string) $this->input('session_id'), + 'artwork_id' => $this->input('artwork_id'), + 'user_id' => $this->user()?->id, + 'ip' => $this->ip(), + ]); + } +} diff --git a/app/Http/Requests/Uploads/UploadInitRequest.php b/app/Http/Requests/Uploads/UploadInitRequest.php new file mode 100644 index 00000000..870ef5ec --- /dev/null +++ b/app/Http/Requests/Uploads/UploadInitRequest.php @@ -0,0 +1,22 @@ +user(); + } + + public function rules(): array + { + return [ + 'client' => 'nullable|string|max:64', + ]; + } +} diff --git a/app/Http/Requests/Uploads/UploadStatusRequest.php b/app/Http/Requests/Uploads/UploadStatusRequest.php new file mode 100644 index 00000000..a7f01009 --- /dev/null +++ b/app/Http/Requests/Uploads/UploadStatusRequest.php @@ -0,0 +1,87 @@ +user(); + if (! $user) { + $this->logUnauthorized('missing_user'); + $this->denyAsNotFound(); + } + + $sessionId = (string) $this->route('id'); + if ($sessionId === '') { + $this->logUnauthorized('missing_session_id'); + $this->denyAsNotFound(); + } + + $sessions = $this->container->make(UploadSessionRepository::class); + $session = $sessions->get($sessionId); + if (! $session || $session->userId !== $user->id) { + $this->logUnauthorized('not_owned_or_missing'); + $this->denyAsNotFound(); + } + + $token = $this->header('X-Upload-Token') ?: $this->input('upload_token'); + if ($token) { + $tokens = $this->container->make(UploadTokenService::class); + $payload = $tokens->get((string) $token); + if (! $payload) { + $this->logUnauthorized('invalid_token'); + $this->denyAsNotFound(); + } + + if (($payload['session_id'] ?? null) !== $sessionId) { + $this->logUnauthorized('token_session_mismatch'); + $this->denyAsNotFound(); + } + + if ((int) ($payload['user_id'] ?? 0) !== (int) $user->id) { + $this->logUnauthorized('token_user_mismatch'); + $this->denyAsNotFound(); + } + } + + return true; + } + + private function denyAsNotFound(): void + { + throw new NotFoundHttpException(); + } + + private function logUnauthorized(string $reason): void + { + logger()->warning('Upload status unauthorized access', [ + 'reason' => $reason, + 'session_id' => (string) $this->route('id'), + 'user_id' => $this->user()?->id, + 'ip' => $this->ip(), + ]); + } + + public function rules(): array + { + return [ + 'id' => 'required|uuid', + 'upload_token' => 'nullable|string|min:40|max:200', + ]; + } + + protected function prepareForValidation(): void + { + $this->merge([ + 'id' => $this->route('id'), + ]); + } +} diff --git a/app/Http/Resources/ArtworkListResource.php b/app/Http/Resources/ArtworkListResource.php index 3914d1fa..77d29662 100644 --- a/app/Http/Resources/ArtworkListResource.php +++ b/app/Http/Resources/ArtworkListResource.php @@ -2,8 +2,8 @@ namespace App\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; -use Illuminate\Support\Facades\Storage; use Illuminate\Http\Resources\MissingValue; +use App\Services\ThumbnailService; class ArtworkListResource extends JsonResource { @@ -48,6 +48,8 @@ class ArtworkListResource extends JsonResource $categoryPath = $primaryCategory->full_slug_path ?? null; } $slugVal = $get('slug'); + $hash = (string) ($get('hash') ?? ''); + $thumbExt = (string) ($get('thumb_ext') ?? ''); $webUrl = $contentTypeSlug && $categoryPath && $slugVal ? '/' . strtolower($contentTypeSlug) . '/' . strtolower($categoryPath) . '/' . $slugVal : null; @@ -60,7 +62,7 @@ class ArtworkListResource extends JsonResource 'width' => $get('width'), 'height' => $get('height'), ], - 'thumbnail_url' => $this->when(! empty($get('file_path')), fn() => Storage::url($get('file_path'))), + 'thumbnail_url' => $this->when(! empty($hash) && ! empty($thumbExt), fn() => ThumbnailService::fromHash($hash, $thumbExt, 'md')), 'author' => $this->whenLoaded('user', function () { return [ 'name' => $this->user->name ?? null, diff --git a/app/Http/Resources/ArtworkResource.php b/app/Http/Resources/ArtworkResource.php index e85db886..fb23ff1b 100644 --- a/app/Http/Resources/ArtworkResource.php +++ b/app/Http/Resources/ArtworkResource.php @@ -2,7 +2,6 @@ namespace App\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; -use Illuminate\Support\Facades\Storage; use Illuminate\Http\Resources\MissingValue; class ArtworkResource extends JsonResource @@ -32,6 +31,21 @@ class ArtworkResource extends JsonResource } return null; }; + $hash = (string) ($get('hash') ?? ''); + $fileExt = (string) ($get('file_ext') ?? ''); + $filesBase = rtrim((string) config('cdn.files_url', ''), '/'); + + $buildOriginalUrl = static function (string $hashValue, string $extValue) use ($filesBase): ?string { + $normalizedHash = strtolower((string) preg_replace('/[^a-f0-9]/', '', $hashValue)); + $normalizedExt = strtolower((string) preg_replace('/[^a-z0-9]/', '', $extValue)); + if ($normalizedHash === '' || $normalizedExt === '') return null; + $h1 = substr($normalizedHash, 0, 2); + $h2 = substr($normalizedHash, 2, 2); + if ($h1 === '' || $h2 === '' || $filesBase === '') return null; + + return sprintf('%s/originals/%s/%s/%s.%s', $filesBase, $h1, $h2, $normalizedHash, $normalizedExt); + }; + return [ 'slug' => $get('slug'), 'title' => $get('title'), @@ -39,10 +53,10 @@ class ArtworkResource extends JsonResource 'width' => $get('width'), 'height' => $get('height'), - // File URLs: produce public URLs without exposing internal file_path + // File URLs are derived from hash/ext (no DB path dependency) 'file' => [ 'name' => $get('file_name') ?? null, - 'url' => $this->when(! empty($get('file_path')), fn() => Storage::url($get('file_path'))), + 'url' => $this->when(! empty($hash) && ! empty($fileExt), fn() => $buildOriginalUrl($hash, $fileExt)), 'size' => $get('file_size') ?? null, 'mime_type' => $get('mime_type') ?? null, ], diff --git a/app/Jobs/AutoTagArtworkJob.php b/app/Jobs/AutoTagArtworkJob.php new file mode 100644 index 00000000..440a0692 --- /dev/null +++ b/app/Jobs/AutoTagArtworkJob.php @@ -0,0 +1,441 @@ +onQueue($queue); + } + } + + public function backoff(): array + { + return [2, 10, 30]; + } + + public function handle(TagService $tagService, TagNormalizer $normalizer): void + { + if (! (bool) config('vision.enabled', true)) { + return; + } + + $artwork = Artwork::query()->with(['categories.contentType'])->find($this->artworkId); + if (! $artwork) { + return; + } + + $imageUrl = $this->buildImageUrl($this->hash); + if ($imageUrl === null) { + return; + } + + $processingKey = $this->processingKey($this->artworkId, $this->hash); + if (! $this->acquireProcessingLock($processingKey)) { + return; + } + + $ref = (string) Str::uuid(); + + try { + $clipTags = $this->callClip($imageUrl, $ref); + + $yoloTags = []; + if ($this->shouldRunYolo($artwork)) { + $yoloTags = $this->callYolo($imageUrl, $ref); + } + + $merged = $this->mergeTags($clipTags, $yoloTags); + if ($merged === []) { + $this->markProcessed($this->processedKey($this->artworkId, $this->hash)); + return; + } + + // Normalize explicitly (requirement), then attach via TagService (source=ai + confidence). + $payload = []; + foreach ($merged as $row) { + $tag = $normalizer->normalize((string) ($row['tag'] ?? '')); + if ($tag === '') { + continue; + } + $payload[] = [ + 'tag' => $tag, + 'confidence' => isset($row['confidence']) && is_numeric($row['confidence']) ? (float) $row['confidence'] : null, + ]; + } + + $tagService->attachAiTags($artwork, $payload); + + $this->markProcessed($this->processedKey($this->artworkId, $this->hash)); + } catch (\Throwable $e) { + Log::error('AutoTagArtworkJob failed', [ + 'ref' => $ref, + 'artwork_id' => $this->artworkId, + 'hash' => $this->hash, + 'attempt' => $this->attempts(), + 'error' => $e->getMessage(), + ]); + + // Retry-safe: allow queue retry on transient failures. + throw $e; + } finally { + $this->releaseProcessingLock($processingKey); + } + } + + private function buildImageUrl(string $hash): ?string + { + $base = (string) config('cdn.files_url'); + $base = rtrim($base, '/'); + if ($base === '') { + return null; + } + + $variant = (string) config('vision.image_variant', 'md'); + $variant = $variant !== '' ? $variant : 'md'; + + // Matches the upload public path layout used for derivatives (img/aa/bb/cc/variant.webp). + $clean = strtolower((string) preg_replace('/[^a-z0-9]/', '', $hash)); + $clean = str_pad($clean, 6, '0'); + $segments = [substr($clean, 0, 2) ?: '00', substr($clean, 2, 2) ?: '00', substr($clean, 4, 2) ?: '00']; + $path = 'img/' . implode('/', $segments) . '/' . $variant . '.webp'; + + return $base . '/' . $path; + } + + /** + * @return array + */ + private function callClip(string $imageUrl, string $ref): array + { + $base = trim((string) config('vision.clip.base_url', '')); + if ($base === '') { + return []; + } + + $endpoint = (string) config('vision.clip.endpoint', '/analyze'); + $url = rtrim($base, '/') . '/' . ltrim($endpoint, '/'); + + $timeout = (int) config('vision.clip.timeout_seconds', 8); + $connectTimeout = (int) config('vision.clip.connect_timeout_seconds', 2); + $retries = (int) config('vision.clip.retries', 1); + $delay = (int) config('vision.clip.retry_delay_ms', 200); + + try { + $response = Http::acceptJson() + ->connectTimeout(max(1, $connectTimeout)) + ->timeout(max(1, $timeout)) + ->retry(max(0, $retries), max(0, $delay), throw: false) + ->post($url, [ + 'url' => $imageUrl, + 'image_url' => $imageUrl, + 'limit' => 8, + 'artwork_id' => $this->artworkId, + 'hash' => $this->hash, + ]); + } catch (\Throwable $e) { + Log::warning('CLIP analyze request failed', ['ref' => $ref, 'artwork_id' => $this->artworkId, 'error' => $e->getMessage()]); + throw $e; + } + + if ($response->serverError()) { + Log::warning('CLIP analyze server error', ['ref' => $ref, 'status' => $response->status(), 'body' => $this->safeBody($response->body())]); + throw new \RuntimeException('CLIP server error: ' . $response->status()); + } + + if (! $response->ok()) { + Log::warning('CLIP analyze non-ok response', ['ref' => $ref, 'status' => $response->status(), 'body' => $this->safeBody($response->body())]); + + // Fallback: try uploading the local derivative file to the gateway's file upload + // endpoint (`/analyze/all/file`) if the gateway cannot fetch the public URL. + try { + $variant = (string) config('vision.image_variant', 'md'); + $row = DB::table('artwork_files') + ->where('artwork_id', $this->artworkId) + ->where('variant', $variant) + ->first(); + + if ($row && ! empty($row->path)) { + $storageRoot = rtrim((string) config('uploads.storage_root', ''), DIRECTORY_SEPARATOR); + $absolute = $storageRoot . DIRECTORY_SEPARATOR . str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $row->path); + if (is_file($absolute) && is_readable($absolute)) { + $uploadUrl = rtrim($base, '/') . '/analyze/all/file'; + try { + $attach = file_get_contents($absolute); + if ($attach !== false) { + $uploadResp = Http::attach('file', $attach, basename($absolute)) + ->post($uploadUrl, ['limit' => 5]); + + if ($uploadResp->ok()) { + return $this->extractTagList($uploadResp->json()); + } + Log::warning('CLIP upload fallback non-ok', ['ref' => $ref, 'status' => $uploadResp->status(), 'body' => $this->safeBody($uploadResp->body())]); + } + } catch (\Throwable $e) { + Log::warning('CLIP upload fallback failed', ['ref' => $ref, 'error' => $e->getMessage()]); + } + } + } + } catch (\Throwable $e) { + Log::warning('CLIP fallback check failed', ['ref' => $ref, 'error' => $e->getMessage()]); + } + + return []; + } + + return $this->extractTagList($response->json()); + } + + /** + * @return array + */ + private function callYolo(string $imageUrl, string $ref): array + { + if (! (bool) config('vision.yolo.enabled', true)) { + return []; + } + + $base = trim((string) config('vision.yolo.base_url', '')); + if ($base === '') { + return []; + } + + $endpoint = (string) config('vision.yolo.endpoint', '/analyze'); + $url = rtrim($base, '/') . '/' . ltrim($endpoint, '/'); + + $timeout = (int) config('vision.yolo.timeout_seconds', 8); + $connectTimeout = (int) config('vision.yolo.connect_timeout_seconds', 2); + $retries = (int) config('vision.yolo.retries', 1); + $delay = (int) config('vision.yolo.retry_delay_ms', 200); + + try { + $response = Http::acceptJson() + ->connectTimeout(max(1, $connectTimeout)) + ->timeout(max(1, $timeout)) + ->retry(max(0, $retries), max(0, $delay), throw: false) + ->post($url, [ + 'url' => $imageUrl, + 'image_url' => $imageUrl, + 'conf' => 0.25, + 'artwork_id' => $this->artworkId, + 'hash' => $this->hash, + ]); + } catch (\Throwable $e) { + Log::warning('YOLO analyze request failed', ['ref' => $ref, 'artwork_id' => $this->artworkId, 'error' => $e->getMessage()]); + throw $e; + } + + if ($response->serverError()) { + Log::warning('YOLO analyze server error', ['ref' => $ref, 'status' => $response->status(), 'body' => $this->safeBody($response->body())]); + throw new \RuntimeException('YOLO server error: ' . $response->status()); + } + + if (! $response->ok()) { + Log::warning('YOLO analyze non-ok response', ['ref' => $ref, 'status' => $response->status(), 'body' => $this->safeBody($response->body())]); + return []; + } + + return $this->extractTagList($response->json()); + } + + private function shouldRunYolo(Artwork $artwork): bool + { + if (! (bool) config('vision.yolo.enabled', true)) { + return false; + } + + if (! (bool) config('vision.yolo.photography_only', true)) { + return true; + } + + foreach ($artwork->categories as $category) { + $slug = strtolower((string) ($category->contentType?->slug ?? '')); + if ($slug === 'photography') { + return true; + } + } + + return false; + } + + /** + * @param mixed $json + * @return array + */ + private function extractTagList(mixed $json): array + { + if (is_array($json) && $this->isListOfTags($json)) { + return $json; + } + + if (is_array($json) && isset($json['tags']) && is_array($json['tags']) && $this->isListOfTags($json['tags'])) { + return $json['tags']; + } + + if (is_array($json) && isset($json['data']) && is_array($json['data']) && $this->isListOfTags($json['data'])) { + return $json['data']; + } + + // Common YOLO-style response: objects: [{label, confidence}] + if (is_array($json) && isset($json['objects']) && is_array($json['objects'])) { + $out = []; + foreach ($json['objects'] as $obj) { + if (! is_array($obj)) { + continue; + } + $label = (string) ($obj['label'] ?? $obj['tag'] ?? ''); + if ($label === '') { + continue; + } + $out[] = ['tag' => $label, 'confidence' => $obj['confidence'] ?? null]; + } + return $out; + } + + return []; + } + + /** + * @param array $arr + */ + private function isListOfTags(array $arr): bool + { + if ($arr === []) { + return true; + } + + foreach ($arr as $row) { + if (! is_array($row)) { + return false; + } + if (! array_key_exists('tag', $row)) { + return false; + } + } + + return true; + } + + /** + * @param array $a + * @param array $b + * @return array + */ + private function mergeTags(array $a, array $b): array + { + $byTag = []; + foreach (array_merge($a, $b) as $row) { + $tag = (string) ($row['tag'] ?? ''); + if ($tag === '') { + continue; + } + $conf = $row['confidence'] ?? null; + $conf = is_numeric($conf) ? (float) $conf : null; + + // Keep highest confidence for duplicates. + if (! isset($byTag[$tag])) { + $byTag[$tag] = ['tag' => $tag, 'confidence' => $conf]; + continue; + } + + $existing = $byTag[$tag]['confidence']; + if ($existing === null || ($conf !== null && $conf > (float) $existing)) { + $byTag[$tag]['confidence'] = $conf; + } + } + + return array_values($byTag); + } + + private function processingKey(int $artworkId, string $hash): string + { + return 'autotag:processing:' . $artworkId . ':' . $hash; + } + + private function processedKey(int $artworkId, string $hash): string + { + return 'autotag:processed:' . $artworkId . ':' . $hash; + } + + private function acquireProcessingLock(string $key): bool + { + try { + $didSet = Redis::setnx($key, 1); + if ($didSet) { + Redis::expire($key, 1800); + } + return (bool) $didSet; + } catch (\Throwable $e) { + // If Redis is unavailable, proceed without dedupe. + return true; + } + } + + private function releaseProcessingLock(string $key): void + { + try { + Redis::del($key); + } catch (\Throwable $e) { + // ignore + } + } + + private function markProcessed(string $key): void + { + try { + Redis::setex($key, 604800, 1); // 7 days + } catch (\Throwable $e) { + // ignore + } + } + + private function safeBody(string $body): string + { + $body = trim($body); + if ($body === '') { + return ''; + } + + return Str::limit($body, 800); + } +} diff --git a/app/Jobs/BackfillArtworkEmbeddingsJob.php b/app/Jobs/BackfillArtworkEmbeddingsJob.php new file mode 100644 index 00000000..503d7367 --- /dev/null +++ b/app/Jobs/BackfillArtworkEmbeddingsJob.php @@ -0,0 +1,61 @@ +onQueue($queue); + } + } + + public function handle(): void + { + $batch = max(1, min($this->batchSize, 1000)); + + $artworks = Artwork::query() + ->where('id', '>', $this->afterId) + ->whereNotNull('hash') + ->orderBy('id') + ->limit($batch) + ->get(['id', 'hash']); + + if ($artworks->isEmpty()) { + return; + } + + foreach ($artworks as $artwork) { + GenerateArtworkEmbeddingJob::dispatch((int) $artwork->id, (string) $artwork->hash, $this->force); + } + + if ($artworks->count() === $batch) { + $lastId = (int) $artworks->last()->id; + self::dispatch($lastId, $batch, $this->force); + } + } +} diff --git a/app/Jobs/GenerateArtworkEmbeddingJob.php b/app/Jobs/GenerateArtworkEmbeddingJob.php new file mode 100644 index 00000000..a787dd4e --- /dev/null +++ b/app/Jobs/GenerateArtworkEmbeddingJob.php @@ -0,0 +1,178 @@ +onQueue($queue); + } + } + + public function backoff(): array + { + return [2, 10, 30]; + } + + public function handle(ArtworkEmbeddingClient $client): void + { + if (! (bool) config('recommendations.embedding.enabled', true)) { + return; + } + + $artwork = Artwork::query()->find($this->artworkId); + if (! $artwork) { + return; + } + + $sourceHash = strtolower((string) preg_replace('/[^a-z0-9]/', '', (string) ($this->sourceHash ?? $artwork->hash ?? ''))); + if ($sourceHash === '') { + return; + } + + $model = (string) config('recommendations.embedding.model', 'clip'); + $modelVersion = (string) config('recommendations.embedding.model_version', 'v1'); + $algoVersion = (string) config('recommendations.embedding.algo_version', 'clip-cosine-v1'); + + if (! $this->force) { + $existing = ArtworkEmbedding::query() + ->where('artwork_id', $artwork->id) + ->where('model', $model) + ->where('model_version', $modelVersion) + ->first(); + + if ($existing && (string) ($existing->source_hash ?? '') === $sourceHash) { + return; + } + } + + $lockKey = $this->lockKey($artwork->id, $model, $modelVersion); + if (! $this->acquireLock($lockKey)) { + return; + } + + try { + $imageUrl = $this->buildImageUrl($sourceHash); + if ($imageUrl === null) { + return; + } + + $vector = $client->embed($imageUrl, (int) $artwork->id, $sourceHash); + if ($vector === []) { + return; + } + + $normalized = $this->normalize($vector); + + ArtworkEmbedding::query()->updateOrCreate( + [ + 'artwork_id' => (int) $artwork->id, + 'model' => $model, + 'model_version' => $modelVersion, + ], + [ + 'algo_version' => $algoVersion, + 'dim' => count($normalized), + 'embedding_json' => json_encode($normalized, JSON_THROW_ON_ERROR), + 'source_hash' => $sourceHash, + 'is_normalized' => true, + 'generated_at' => now(), + 'meta' => [ + 'source' => 'clip', + 'image_variant' => (string) config('vision.image_variant', 'md'), + ], + ] + ); + } finally { + $this->releaseLock($lockKey); + } + } + + /** + * @param array $vector + * @return array + */ + private function normalize(array $vector): array + { + $sumSquares = 0.0; + foreach ($vector as $value) { + $sumSquares += ($value * $value); + } + + if ($sumSquares <= 0.0) { + return $vector; + } + + $norm = sqrt($sumSquares); + return array_map(static fn (float $value): float => $value / $norm, $vector); + } + + private function buildImageUrl(string $hash): ?string + { + $base = rtrim((string) config('cdn.files_url', ''), '/'); + if ($base === '') { + return null; + } + + $variant = (string) config('vision.image_variant', 'md'); + $clean = strtolower((string) preg_replace('/[^a-z0-9]/', '', $hash)); + $clean = str_pad($clean, 6, '0'); + $segments = [substr($clean, 0, 2) ?: '00', substr($clean, 2, 2) ?: '00', substr($clean, 4, 2) ?: '00']; + + return $base . '/img/' . implode('/', $segments) . '/' . $variant . '.webp'; + } + + private function lockKey(int $artworkId, string $model, string $version): string + { + return 'artwork-embedding:lock:' . $artworkId . ':' . $model . ':' . $version; + } + + private function acquireLock(string $key): bool + { + try { + $didSet = Redis::setnx($key, 1); + if ($didSet) { + Redis::expire($key, 1800); + } + return (bool) $didSet; + } catch (\Throwable) { + return true; + } + } + + private function releaseLock(string $key): void + { + try { + Redis::del($key); + } catch (\Throwable) { + // ignore + } + } +} diff --git a/app/Jobs/GenerateDerivativesJob.php b/app/Jobs/GenerateDerivativesJob.php new file mode 100644 index 00000000..3732b6bf --- /dev/null +++ b/app/Jobs/GenerateDerivativesJob.php @@ -0,0 +1,38 @@ +processAndPublish($this->sessionId, $this->hash, $this->artworkId); + + // Auto-tagging is async and must never block publish. + AutoTagArtworkJob::dispatch($this->artworkId, $this->hash)->afterCommit(); + GenerateArtworkEmbeddingJob::dispatch($this->artworkId, $this->hash)->afterCommit(); + } +} diff --git a/app/Jobs/IngestUserDiscoveryEventJob.php b/app/Jobs/IngestUserDiscoveryEventJob.php new file mode 100644 index 00000000..c1711254 --- /dev/null +++ b/app/Jobs/IngestUserDiscoveryEventJob.php @@ -0,0 +1,122 @@ + */ + public array $backoff = [5, 30, 120]; + + /** + * @param array $meta + */ + public function __construct( + public readonly string $eventId, + public readonly int $userId, + public readonly int $artworkId, + public readonly string $eventType, + public readonly string $algoVersion, + public readonly string $occurredAt, + public readonly array $meta = [] + ) { + } + + public function handle(UserInterestProfileService $profileService): void + { + $idempotencyKey = sprintf('discovery:event:processed:%s', $this->eventId); + + try { + $didSet = false; + try { + $didSet = (bool) Redis::setnx($idempotencyKey, 1); + if ($didSet) { + Redis::expire($idempotencyKey, 86400 * 2); + } + } catch (\Throwable $e) { + Log::warning('Redis unavailable for discovery ingestion; proceeding without redis dedupe', [ + 'event_id' => $this->eventId, + 'error' => $e->getMessage(), + ]); + $didSet = true; + } + + if (! $didSet) { + return; + } + + $occurredAt = CarbonImmutable::parse($this->occurredAt); + $eventVersion = (string) config('discovery.event_version', 'event-v1'); + $eventWeight = (float) ((array) config('discovery.weights', []))[$this->eventType] ?? 1.0; + + $categoryId = DB::table('artwork_category') + ->where('artwork_id', $this->artworkId) + ->orderBy('category_id') + ->value('category_id'); + + $insertPayload = [ + 'event_id' => $this->eventId, + 'user_id' => $this->userId, + 'artwork_id' => $this->artworkId, + 'category_id' => $categoryId !== null ? (int) $categoryId : null, + 'event_type' => $this->eventType, + 'event_version' => $eventVersion, + 'algo_version' => $this->algoVersion, + 'weight' => $eventWeight, + 'event_date' => $occurredAt->toDateString(), + 'occurred_at' => $occurredAt->toDateTimeString(), + 'created_at' => now(), + 'updated_at' => now(), + ]; + + if (Schema::hasColumn('user_discovery_events', 'meta')) { + $insertPayload['meta'] = $this->meta; + } elseif (Schema::hasColumn('user_discovery_events', 'metadata')) { + $insertPayload['metadata'] = json_encode($this->meta, JSON_UNESCAPED_SLASHES); + } + + DB::table('user_discovery_events')->insertOrIgnore($insertPayload); + + $profileService->applyEvent( + userId: $this->userId, + eventType: $this->eventType, + artworkId: $this->artworkId, + categoryId: $categoryId !== null ? (int) $categoryId : null, + occurredAt: $occurredAt, + eventId: $this->eventId, + algoVersion: $this->algoVersion, + eventMeta: $this->meta + ); + } catch (\Throwable $e) { + Log::error('IngestUserDiscoveryEventJob failed', [ + 'event_id' => $this->eventId, + 'user_id' => $this->userId, + 'artwork_id' => $this->artworkId, + 'event_type' => $this->eventType, + 'error' => $e->getMessage(), + ]); + + throw $e; + } + } +} diff --git a/app/Jobs/RegenerateUserRecommendationCacheJob.php b/app/Jobs/RegenerateUserRecommendationCacheJob.php new file mode 100644 index 00000000..b2624862 --- /dev/null +++ b/app/Jobs/RegenerateUserRecommendationCacheJob.php @@ -0,0 +1,47 @@ + */ + public array $backoff = [10, 60, 180]; + + public function __construct( + public readonly int $userId, + public readonly string $algoVersion + ) { + } + + public function handle(PersonalizedFeedService $feedService): void + { + try { + $feedService->regenerateCacheForUser($this->userId, $this->algoVersion); + } catch (\Throwable $e) { + Log::error('RegenerateUserRecommendationCacheJob failed', [ + 'user_id' => $this->userId, + 'algo_version' => $this->algoVersion, + 'error' => $e->getMessage(), + ]); + + throw $e; + } + } +} diff --git a/app/Models/Artwork.php b/app/Models/Artwork.php index e3fff1ee..a7cf81ee 100644 --- a/app/Models/Artwork.php +++ b/app/Models/Artwork.php @@ -9,6 +9,8 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasOne; +use App\Services\ThumbnailService; +use Illuminate\Support\Facades\DB; /** * App\Models\Artwork @@ -74,13 +76,8 @@ class Artwork extends Model return null; } - $size = array_key_exists($size, self::THUMB_SIZES) ? $size : 'md'; - $h = $this->hash; - $h1 = substr($h, 0, 2); - $h2 = substr($h, 2, 2); - $ext = $this->thumb_ext; - - return "https://files.skinbase.org/{$size}/{$h1}/{$h2}/{$h}.{$ext}"; + $sizeKey = array_key_exists($size, self::THUMB_SIZES) ? $size : 'md'; + return ThumbnailService::fromHash($this->hash, $this->thumb_ext, $sizeKey); } /** @@ -99,6 +96,19 @@ class Artwork extends Model return $this->thumbUrl('md'); } + /** + * Backwards-compatible alias used by legacy views: `$art->thumbnail_url`. + * Prefer CDN thumbnail URL, then legacy `thumb` accessor, finally a placeholder. + */ + public function getThumbnailUrlAttribute(): ?string + { + $url = $this->getThumbUrlAttribute(); + if (!empty($url)) return $url; + $thumb = $this->getThumbAttribute(); + if (!empty($thumb)) return $thumb; + return '/images/placeholder.jpg'; + } + /** * Provide a responsive `srcset` for legacy views. */ @@ -132,6 +142,12 @@ class Artwork extends Model return $this->belongsToMany(Category::class, 'artwork_category', 'artwork_id', 'category_id'); } + public function tags(): BelongsToMany + { + return $this->belongsToMany(Tag::class, 'artwork_tag', 'artwork_id', 'tag_id') + ->withPivot(['source', 'confidence']); + } + public function comments(): HasMany { return $this->hasMany(ArtworkComment::class); @@ -142,6 +158,16 @@ class Artwork extends Model return $this->hasMany(ArtworkDownload::class); } + public function embeddings(): HasMany + { + return $this->hasMany(ArtworkEmbedding::class, 'artwork_id'); + } + + public function similarities(): HasMany + { + return $this->hasMany(ArtworkSimilarity::class, 'artwork_id'); + } + public function features(): HasMany { return $this->hasMany(ArtworkFeature::class, 'artwork_id'); @@ -175,4 +201,24 @@ class Artwork extends Model { return 'slug'; } + + protected static function booted(): void + { + static::deleting(function (Artwork $artwork): void { + if (! method_exists($artwork, 'isForceDeleting') || ! $artwork->isForceDeleting()) { + return; + } + + // Cleanup pivot rows and decrement usage counts on force delete. + $tagIds = DB::table('artwork_tag')->where('artwork_id', $artwork->id)->pluck('tag_id')->all(); + if ($tagIds === []) { + return; + } + + DB::table('artwork_tag')->where('artwork_id', $artwork->id)->delete(); + DB::table('tags') + ->whereIn('id', $tagIds) + ->update(['usage_count' => DB::raw('CASE WHEN usage_count > 0 THEN usage_count - 1 ELSE 0 END')]); + }); + } } diff --git a/app/Models/ArtworkEmbedding.php b/app/Models/ArtworkEmbedding.php new file mode 100644 index 00000000..03619c51 --- /dev/null +++ b/app/Models/ArtworkEmbedding.php @@ -0,0 +1,37 @@ + 'boolean', + 'generated_at' => 'datetime', + 'meta' => 'array', + ]; + + public function artwork(): BelongsTo + { + return $this->belongsTo(Artwork::class, 'artwork_id'); + } +} diff --git a/app/Models/ArtworkSimilarity.php b/app/Models/ArtworkSimilarity.php new file mode 100644 index 00000000..d62663e0 --- /dev/null +++ b/app/Models/ArtworkSimilarity.php @@ -0,0 +1,42 @@ + 'integer', + 'score' => 'float', + 'generated_at' => 'datetime', + 'meta' => 'array', + ]; + + public function artwork(): BelongsTo + { + return $this->belongsTo(Artwork::class, 'artwork_id'); + } + + public function similarArtwork(): BelongsTo + { + return $this->belongsTo(Artwork::class, 'similar_artwork_id'); + } +} diff --git a/app/Models/Category.php b/app/Models/Category.php index aedc940d..342d9141 100644 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -113,4 +113,50 @@ class Category extends Model { return 'slug'; } + + /** + * Resolve a category by a content-type slug and a category path (e.g. "audio/winamp"). + * This will locate the category with the final slug and verify its parent chain + * matches the provided path and that the category belongs to the given content type. + * + * @param string $contentTypeSlug + * @param string|array $categoryPath + * @return Category|null + */ + public static function findByPath(string $contentTypeSlug, $categoryPath): ?Category + { + $parts = is_array($categoryPath) + ? array_values(array_map('strtolower', array_filter($categoryPath))) + : array_values(array_map('strtolower', array_filter(explode('/', (string) $categoryPath)))); + + if (empty($parts)) { + return null; + } + + $last = end($parts); + + $category = static::where('slug', $last) + ->whereHas('contentType', function ($q) use ($contentTypeSlug) { + $q->where('slug', strtolower($contentTypeSlug)); + }) + ->first(); + + if (! $category) { + return null; + } + + // Verify parent chain matches the preceding parts in the path + $idx = count($parts) - 2; + $current = $category; + while ($idx >= 0) { + $parent = $current->parent; + if (! $parent || $parent->slug !== $parts[$idx]) { + return null; + } + $current = $parent; + $idx--; + } + + return $category; + } } diff --git a/app/Models/ContentType.php b/app/Models/ContentType.php index e7e0cf2a..f1fe5ee6 100644 --- a/app/Models/ContentType.php +++ b/app/Models/ContentType.php @@ -4,6 +4,9 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Builder as EloquentBuilder; + +use App\Models\Artwork; class ContentType extends Model { @@ -19,6 +22,18 @@ class ContentType extends Model return $this->categories()->whereNull('parent_id'); } + /** + * Return an Eloquent builder for Artworks that belong to this content type. + * This traverses the pivot `artwork_category` via the `categories` relation. + * Note: not a direct Eloquent relation (uses whereHas) so it can be queried/eager-loaded manually. + */ + public function artworks(): EloquentBuilder + { + return Artwork::whereHas('categories', function ($q) { + $q->where('content_type_id', $this->id); + }); + } + public function getRouteKeyName(): string { return 'slug'; diff --git a/app/Models/Tag.php b/app/Models/Tag.php new file mode 100644 index 00000000..795cfae8 --- /dev/null +++ b/app/Models/Tag.php @@ -0,0 +1,39 @@ + 'integer', + 'is_active' => 'boolean', + ]; + + public function artworks(): BelongsToMany + { + return $this->belongsToMany(Artwork::class, 'artwork_tag', 'tag_id', 'artwork_id') + ->withPivot(['source', 'confidence']); + } + + public function getRouteKeyName(): string + { + return 'slug'; + } +} diff --git a/app/Models/Upload.php b/app/Models/Upload.php new file mode 100644 index 00000000..96fcf494 --- /dev/null +++ b/app/Models/Upload.php @@ -0,0 +1,51 @@ + 'array', + 'nsfw' => 'boolean', + 'is_scanned' => 'boolean', + 'has_tags' => 'boolean', + 'published_at' => 'datetime', + 'expires_at' => 'datetime', + 'moderated_at' => 'datetime', + ]; +} diff --git a/app/Models/User.php b/app/Models/User.php index 6dc83b2c..fc76f6cf 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -23,6 +23,7 @@ class User extends Authenticatable 'name', 'email', 'password', + 'role', ]; /** @@ -53,4 +54,19 @@ class User extends Authenticatable { return $this->hasMany(Artwork::class); } + + public function hasRole(string $role): bool + { + return strtolower((string) ($this->role ?? '')) === strtolower($role); + } + + public function isAdmin(): bool + { + return $this->hasRole('admin'); + } + + public function isModerator(): bool + { + return $this->hasRole('moderator'); + } } diff --git a/app/Models/UserDiscoveryEvent.php b/app/Models/UserDiscoveryEvent.php new file mode 100644 index 00000000..3b1a3a09 --- /dev/null +++ b/app/Models/UserDiscoveryEvent.php @@ -0,0 +1,39 @@ + 'datetime', + 'meta' => 'array', + 'weight' => 'float', + ]; + + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } + + public function artwork(): BelongsTo + { + return $this->belongsTo(Artwork::class); + } + + public function category(): BelongsTo + { + return $this->belongsTo(Category::class); + } +} diff --git a/app/Models/UserInterestProfile.php b/app/Models/UserInterestProfile.php new file mode 100644 index 00000000..62c718e8 --- /dev/null +++ b/app/Models/UserInterestProfile.php @@ -0,0 +1,31 @@ + 'array', + 'normalized_scores_json' => 'array', + 'last_event_at' => 'datetime', + 'half_life_hours' => 'float', + 'total_weight' => 'float', + ]; + + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } +} diff --git a/app/Models/UserProfile.php b/app/Models/UserProfile.php new file mode 100644 index 00000000..46c06ce4 --- /dev/null +++ b/app/Models/UserProfile.php @@ -0,0 +1,69 @@ + 'date', + 'avatar_updated_at' => 'datetime', + ]; + + public $timestamps = true; + + public function user(): BelongsTo + { + return $this->belongsTo(User::class, 'user_id'); + } + + /** + * Return a public URL for the avatar when stored on the `public` disk under `avatars/`. + */ + public function getAvatarUrlAttribute(): ?string + { + if (empty($this->avatar)) { + return null; + } + + // If the stored value already looks like a full URL, return it. + if (preg_match('#^https?://#i', $this->avatar)) { + return $this->avatar; + } + + // Prefer `public` disk and avatars folder. + $path = 'avatars/' . ltrim($this->avatar, '/'); + if (Storage::disk('public')->exists($path)) { + return Storage::disk('public')->url($path); + } + + // Fallback: return null if not found + return null; + } +} diff --git a/app/Models/UserRecommendationCache.php b/app/Models/UserRecommendationCache.php new file mode 100644 index 00000000..12ba4d18 --- /dev/null +++ b/app/Models/UserRecommendationCache.php @@ -0,0 +1,29 @@ + 'array', + 'generated_at' => 'datetime', + 'expires_at' => 'datetime', + ]; + + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } +} diff --git a/app/Policies/ArtworkPolicy.php b/app/Policies/ArtworkPolicy.php index eae9ee97..bcb1506e 100644 --- a/app/Policies/ArtworkPolicy.php +++ b/app/Policies/ArtworkPolicy.php @@ -40,6 +40,25 @@ class ArtworkPolicy return false; } + protected function isModerator(User $user): bool + { + foreach (['is_moderator', 'is_mod', 'moderator'] as $prop) { + if (isset($user->{$prop})) { + return (bool) $user->{$prop}; + } + } + + if (method_exists($user, 'hasRole')) { + return (bool) ($user->hasRole('moderator') || $user->hasRole('mod')); + } + + if (method_exists($user, 'isModerator')) { + return (bool) $user->isModerator(); + } + + return false; + } + /** * Public view: only approved + public + not-deleted artworks. */ @@ -64,6 +83,14 @@ class ArtworkPolicy return $user->id === $artwork->user_id; } + /** + * Tag edits: owner or moderator or admin (admin handled by before()). + */ + public function updateTags(User $user, Artwork $artwork): bool + { + return $user->id === $artwork->user_id || $this->isModerator($user); + } + /** * Owner can delete their own artwork (soft delete). */ diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 452e6b65..1155fb19 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,7 +2,15 @@ namespace App\Providers; +use Illuminate\Cache\RateLimiting\Limit; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\RateLimiter; use Illuminate\Support\ServiceProvider; +use App\Services\Upload\Contracts\UploadDraftServiceInterface; +use App\Services\Upload\UploadDraftService; +use Illuminate\Support\Facades\View; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Auth; class AppServiceProvider extends ServiceProvider { @@ -11,7 +19,10 @@ class AppServiceProvider extends ServiceProvider */ public function register(): void { - // + // Bind UploadDraftService interface to implementation + $this->app->singleton(UploadDraftServiceInterface::class, function ($app) { + return new UploadDraftService($app->make('filesystem')); + }); } /** @@ -19,6 +30,93 @@ class AppServiceProvider extends ServiceProvider */ public function boot(): void { - // + $this->configureUploadRateLimiters(); + + // Provide toolbar counts and user info to layout views (port of legacy toolbar logic) + View::composer(['layouts.nova', 'layouts.nova.*'], function ($view) { + $uploadCount = $favCount = $msgCount = $noticeCount = 0; + $avatar = null; + $displayName = null; + $userId = null; + + if (Auth::check()) { + $userId = Auth::id(); + try { + $uploadCount = DB::table('artworks')->where('user_id', $userId)->count(); + } catch (\Throwable $e) { + $uploadCount = 0; + } + + try { + // legacy table name fallback handled elsewhere; here we look for user_favorites or favourites + $favCount = DB::table('user_favorites')->where('user_id', $userId)->count(); + } catch (\Throwable $e) { + try { + $favCount = DB::table('favourites')->where('user_id', $userId)->count(); + } catch (\Throwable $e) { + $favCount = 0; + } + } + + try { + $msgCount = DB::table('messages')->where('reciever_id', $userId)->whereNull('read_at')->count(); + } catch (\Throwable $e) { + $msgCount = 0; + } + + try { + $noticeCount = DB::table('notification')->where('user_id', $userId)->where('new', 1)->count(); + } catch (\Throwable $e) { + $noticeCount = 0; + } + + try { + $profile = DB::table('user_profiles')->where('user_id', $userId)->first(); + $avatar = $profile->avatar ?? null; + } catch (\Throwable $e) { + $avatar = null; + } + + $displayName = Auth::user()->name ?: (Auth::user()->username ?? ''); + } + + $view->with(compact('userId','uploadCount', 'favCount', 'msgCount', 'noticeCount', 'avatar', 'displayName')); + }); + } + + private function configureUploadRateLimiters(): void + { + RateLimiter::for('uploads-init', function (Request $request): array { + return $this->buildUploadLimits($request, 'init'); + }); + + RateLimiter::for('uploads-finish', function (Request $request): array { + return $this->buildUploadLimits($request, 'finish'); + }); + + RateLimiter::for('uploads-status', function (Request $request): array { + return $this->buildUploadLimits($request, 'status'); + }); + } + + private function buildUploadLimits(Request $request, string $key): array + { + $config = (array) config('uploads.rate_limits.' . $key, []); + $decay = (int) config('uploads.rate_limits.decay_minutes', 1); + $perUser = (int) ($config['per_user'] ?? 0); + $perIp = (int) ($config['per_ip'] ?? 0); + + $limits = []; + + if ($perUser > 0) { + $userId = $request->user()?->id ?? 'guest'; + $limits[] = Limit::perMinutes($decay, $perUser)->by('u:' . $userId); + } + + if ($perIp > 0) { + $limits[] = Limit::perMinutes($decay, $perIp)->by('ip:' . $request->ip()); + } + + return $limits; } } diff --git a/app/Repositories/Uploads/ArtworkFileRepository.php b/app/Repositories/Uploads/ArtworkFileRepository.php new file mode 100644 index 00000000..965f609d --- /dev/null +++ b/app/Repositories/Uploads/ArtworkFileRepository.php @@ -0,0 +1,18 @@ +updateOrInsert( + ['artwork_id' => $artworkId, 'variant' => $variant], + ['path' => $path, 'mime' => $mime, 'size' => $size] + ); + } +} diff --git a/app/Repositories/Uploads/AuditLogRepository.php b/app/Repositories/Uploads/AuditLogRepository.php new file mode 100644 index 00000000..c91a12ad --- /dev/null +++ b/app/Repositories/Uploads/AuditLogRepository.php @@ -0,0 +1,21 @@ +insert([ + 'user_id' => $userId, + 'action' => $action, + 'ip' => $ip, + 'meta' => empty($meta) ? null : json_encode($meta, JSON_THROW_ON_ERROR), + 'created_at' => now()->toDateTimeString(), + ]); + } +} diff --git a/app/Repositories/Uploads/UploadSessionRepository.php b/app/Repositories/Uploads/UploadSessionRepository.php new file mode 100644 index 00000000..dcd90daa --- /dev/null +++ b/app/Repositories/Uploads/UploadSessionRepository.php @@ -0,0 +1,113 @@ +insert([ + 'id' => $id, + 'user_id' => $userId, + 'temp_path' => $tempPath, + 'status' => $status, + 'ip' => $ip, + 'created_at' => $createdAt->toDateTimeString(), + 'progress' => 0, + 'failure_reason' => null, + ]); + + return new UploadSessionData($id, $userId, $tempPath, $status, $ip, $createdAt, 0, null); + } + + public function get(string $id): ?UploadSessionData + { + $row = DB::table('uploads_sessions')->where('id', $id)->first(); + + if (! $row) { + return null; + } + + return new UploadSessionData( + (string) $row->id, + (int) $row->user_id, + (string) $row->temp_path, + (string) $row->status, + (string) $row->ip, + CarbonImmutable::parse($row->created_at), + (int) ($row->progress ?? 0), + $row->failure_reason ? (string) $row->failure_reason : null + ); + } + + public function getOrFail(string $id): UploadSessionData + { + $session = $this->get($id); + + if (! $session) { + throw new RuntimeException('Upload session not found.'); + } + + return $session; + } + + public function updateStatus(string $id, string $status): void + { + DB::table('uploads_sessions')->where('id', $id)->update([ + 'status' => $status, + ]); + } + + public function updateProgress(string $id, int $progress): void + { + DB::table('uploads_sessions')->where('id', $id)->update([ + 'progress' => max(0, min(100, $progress)), + ]); + } + + public function updateFailureReason(string $id, ?string $reason): void + { + DB::table('uploads_sessions')->where('id', $id)->update([ + 'failure_reason' => $reason, + ]); + } + + public function updateTempPath(string $id, string $tempPath): void + { + DB::table('uploads_sessions')->where('id', $id)->update([ + 'temp_path' => $tempPath, + ]); + } + + public function countActiveForUser(int $userId): int + { + $terminal = [ + UploadSessionStatus::PROCESSED, + UploadSessionStatus::QUARANTINED, + UploadSessionStatus::CANCELLED, + ]; + + return (int) DB::table('uploads_sessions') + ->where('user_id', $userId) + ->whereNotIn('status', $terminal) + ->count(); + } + + public function countForUserSince(int $userId, CarbonImmutable $since): int + { + return (int) DB::table('uploads_sessions') + ->where('user_id', $userId) + ->where('created_at', '>=', $since->toDateTimeString()) + ->count(); + } +} diff --git a/app/Services/Artworks/ArtworkDraftService.php b/app/Services/Artworks/ArtworkDraftService.php new file mode 100644 index 00000000..7c18c374 --- /dev/null +++ b/app/Services/Artworks/ArtworkDraftService.php @@ -0,0 +1,55 @@ +uniqueSlug($title); + + $artwork = Artwork::create([ + 'user_id' => $userId, + 'title' => $title, + 'slug' => $slug, + 'description' => $description, + 'file_name' => 'pending', + 'file_path' => '', + 'file_size' => 0, + 'mime_type' => 'application/octet-stream', + 'width' => 1, + 'height' => 1, + 'is_public' => false, + 'is_approved' => false, + 'published_at' => null, + ]); + + return new ArtworkDraftResult((int) $artwork->id, 'draft'); + }); + } + + private function uniqueSlug(string $title): string + { + $base = Str::slug($title); + $base = $base !== '' ? $base : 'artwork'; + + for ($i = 0; $i < 5; $i++) { + $suffix = Str::lower(Str::random(6)); + $slug = Str::limit($base . '-' . $suffix, 160, ''); + + if (! Artwork::where('slug', $slug)->exists()) { + return $slug; + } + } + + return Str::limit($base . '-' . Str::uuid()->toString(), 160, ''); + } +} diff --git a/app/Services/AvatarService.php b/app/Services/AvatarService.php new file mode 100644 index 00000000..1430ab98 --- /dev/null +++ b/app/Services/AvatarService.php @@ -0,0 +1,169 @@ + 32, + 'sm' => 64, + 'md' => 128, + 'lg' => 256, + 'xl' => 512, + ]; + + protected $quality = 85; + + public function __construct() + { + // Guard: if Intervention Image is not installed, defer error until actual use + if (class_exists(\Intervention\Image\ImageManagerStatic::class)) { + try { + Image::configure(['driver' => extension_loaded('gd') ? 'gd' : 'imagick']); + $this->imageAvailable = true; + } catch (\Throwable $e) { + // If configuration fails, treat as unavailable and log for diagnostics + logger()->warning('Intervention Image present but configuration failed: '.$e->getMessage()); + $this->imageAvailable = false; + } + } else { + $this->imageAvailable = false; + } + } + + /** + * Process an uploaded file for a user and store webp sizes. + * Returns the computed sha1 hash. + * + * @param int $userId + * @param UploadedFile $file + * @return string sha1 hash + */ + public function storeFromUploadedFile(int $userId, UploadedFile $file): string + { + if (! $this->imageAvailable) { + throw new RuntimeException('Intervention Image is not available. If you just installed the package, restart your PHP process (php artisan serve or PHP-FPM) and run `composer dump-autoload -o`.'); + } + + // Load image and re-encode to webp after validating + try { + $img = Image::make($file->getRealPath()); + } catch (\Throwable $e) { + throw new RuntimeException('Failed to read uploaded image: '.$e->getMessage()); + } + + // Ensure square center crop per spec + $max = max($img->width(), $img->height()); + $img->fit($max, $max); + + $basePath = "avatars/{$userId}"; + Storage::disk('public')->makeDirectory($basePath); + + // Save original as webp + $originalData = (string) $img->encode('webp', $this->quality); + Storage::disk('public')->put($basePath . '/original.webp', $originalData); + + // Generate sizes + foreach ($this->sizes as $name => $size) { + $resized = $img->resize($size, $size, function ($constraint) { + $constraint->upsize(); + })->encode('webp', $this->quality); + Storage::disk('public')->put("{$basePath}/{$size}.webp", (string)$resized); + } + + $hash = sha1($originalData); + $mime = 'image/webp'; + + // Persist metadata to user_profiles if exists, otherwise users table fallbacks + if (SchemaHasTable('user_profiles')) { + DB::table('user_profiles')->where('user_id', $userId)->update([ + 'avatar_hash' => $hash, + 'avatar_updated_at' => Carbon::now(), + 'avatar_mime' => $mime, + ]); + } else { + DB::table('users')->where('id', $userId)->update([ + 'avatar_hash' => $hash, + 'avatar_updated_at' => Carbon::now(), + 'avatar_mime' => $mime, + ]); + } + + return $hash; + } + + /** + * Process a legacy file path for a user (path-to-file). + * Returns sha1 or null when missing. + * + * @param int $userId + * @param string $path Absolute filesystem path + * @return string|null + */ + public function storeFromLegacyFile(int $userId, string $path): ?string + { + if (!file_exists($path) || !is_readable($path)) { + return null; + } + + try { + $img = Image::make($path); + } catch (\Exception $e) { + return null; + } + + $max = max($img->width(), $img->height()); + $img->fit($max, $max); + + $basePath = "avatars/{$userId}"; + Storage::disk('public')->makeDirectory($basePath); + + $originalData = (string) $img->encode('webp', $this->quality); + Storage::disk('public')->put($basePath . '/original.webp', $originalData); + + foreach ($this->sizes as $name => $size) { + $resized = $img->resize($size, $size, function ($constraint) { + $constraint->upsize(); + })->encode('webp', $this->quality); + Storage::disk('public')->put("{$basePath}/{$size}.webp", (string)$resized); + } + + $hash = sha1($originalData); + $mime = 'image/webp'; + + if (SchemaHasTable('user_profiles')) { + DB::table('user_profiles')->where('user_id', $userId)->update([ + 'avatar_hash' => $hash, + 'avatar_updated_at' => Carbon::now(), + 'avatar_mime' => $mime, + ]); + } else { + DB::table('users')->where('id', $userId)->update([ + 'avatar_hash' => $hash, + 'avatar_updated_at' => Carbon::now(), + 'avatar_mime' => $mime, + ]); + } + + return $hash; + } +} + +/** + * Helper: check for table existence without importing Schema facade repeatedly + */ +function SchemaHasTable(string $name): bool +{ + try { + return \Illuminate\Support\Facades\Schema::hasTable($name); + } catch (\Throwable $e) { + return false; + } +} diff --git a/app/Services/Recommendations/FeedOfflineEvaluationService.php b/app/Services/Recommendations/FeedOfflineEvaluationService.php new file mode 100644 index 00000000..44367135 --- /dev/null +++ b/app/Services/Recommendations/FeedOfflineEvaluationService.php @@ -0,0 +1,139 @@ + + */ + public function evaluateAlgo(string $algoVersion, string $from, string $to): array + { + $row = DB::table('feed_daily_metrics') + ->selectRaw('SUM(impressions) as impressions') + ->selectRaw('SUM(clicks) as clicks') + ->selectRaw('SUM(saves) as saves') + ->selectRaw('SUM(dwell_0_5) as dwell_0_5') + ->selectRaw('SUM(dwell_5_30) as dwell_5_30') + ->selectRaw('SUM(dwell_30_120) as dwell_30_120') + ->selectRaw('SUM(dwell_120_plus) as dwell_120_plus') + ->where('algo_version', $algoVersion) + ->whereBetween('metric_date', [$from, $to]) + ->first(); + + $impressions = (int) ($row->impressions ?? 0); + $clicks = (int) ($row->clicks ?? 0); + $saves = (int) ($row->saves ?? 0); + + $dwell05 = (int) ($row->dwell_0_5 ?? 0); + $dwell530 = (int) ($row->dwell_5_30 ?? 0); + $dwell30120 = (int) ($row->dwell_30_120 ?? 0); + $dwell120Plus = (int) ($row->dwell_120_plus ?? 0); + + $ctr = $impressions > 0 ? $clicks / $impressions : 0.0; + $saveRate = $clicks > 0 ? $saves / $clicks : 0.0; + $longDwellShare = $clicks > 0 ? ($dwell30120 + $dwell120Plus) / $clicks : 0.0; + $bounceRate = $clicks > 0 ? $dwell05 / $clicks : 0.0; + + $objectiveWeights = (array) config('discovery.evaluation.objective_weights', []); + $wCtr = (float) ($objectiveWeights['ctr'] ?? 0.45); + $wSave = (float) ($objectiveWeights['save_rate'] ?? 0.35); + $wLong = (float) ($objectiveWeights['long_dwell_share'] ?? 0.25); + $wBouncePenalty = (float) ($objectiveWeights['bounce_rate_penalty'] ?? 0.15); + + $saveRateInformational = (bool) config('discovery.evaluation.save_rate_informational', true); + if ($saveRateInformational) { + $wSave = 0.0; + } + + $normalizationSum = $wCtr + $wSave + $wLong + $wBouncePenalty; + if ($normalizationSum > 0.0) { + $wCtr /= $normalizationSum; + $wSave /= $normalizationSum; + $wLong /= $normalizationSum; + $wBouncePenalty /= $normalizationSum; + } + + $objectiveScore = ($wCtr * $ctr) + + ($wSave * $saveRate) + + ($wLong * $longDwellShare) + - ($wBouncePenalty * $bounceRate); + + return [ + 'algo_version' => $algoVersion, + 'from' => $from, + 'to' => $to, + 'impressions' => $impressions, + 'clicks' => $clicks, + 'saves' => $saves, + 'ctr' => round($ctr, 6), + 'save_rate' => round($saveRate, 6), + 'long_dwell_share' => round($longDwellShare, 6), + 'bounce_rate' => round($bounceRate, 6), + 'dwell_buckets' => [ + '0_5' => $dwell05, + '5_30' => $dwell530, + '30_120' => $dwell30120, + '120_plus' => $dwell120Plus, + ], + 'objective_score' => round($objectiveScore, 6), + ]; + } + + /** + * @return array> + */ + public function evaluateAll(string $from, string $to): array + { + $algoVersions = DB::table('feed_daily_metrics') + ->select('algo_version') + ->whereBetween('metric_date', [$from, $to]) + ->distinct() + ->orderBy('algo_version') + ->pluck('algo_version') + ->map(static fn (mixed $v): string => (string) $v) + ->all(); + + $out = []; + foreach ($algoVersions as $algoVersion) { + $out[] = $this->evaluateAlgo($algoVersion, $from, $to); + } + + usort($out, static fn (array $a, array $b): int => $b['objective_score'] <=> $a['objective_score']); + + return $out; + } + + /** + * @return array + */ + public function compareBaselineCandidate(string $baselineAlgoVersion, string $candidateAlgoVersion, string $from, string $to): array + { + $baseline = $this->evaluateAlgo($baselineAlgoVersion, $from, $to); + $candidate = $this->evaluateAlgo($candidateAlgoVersion, $from, $to); + + $deltaObjective = (float) $candidate['objective_score'] - (float) $baseline['objective_score']; + $objectiveLiftPct = (float) $baseline['objective_score'] !== 0.0 + ? ($deltaObjective / (float) $baseline['objective_score']) * 100.0 + : null; + + return [ + 'from' => $from, + 'to' => $to, + 'baseline' => $baseline, + 'candidate' => $candidate, + 'delta' => [ + 'objective_score' => round($deltaObjective, 6), + 'objective_lift_pct' => $objectiveLiftPct !== null ? round($objectiveLiftPct, 4) : null, + 'ctr' => round((float) $candidate['ctr'] - (float) $baseline['ctr'], 6), + 'save_rate' => round((float) $candidate['save_rate'] - (float) $baseline['save_rate'], 6), + 'long_dwell_share' => round((float) $candidate['long_dwell_share'] - (float) $baseline['long_dwell_share'], 6), + 'bounce_rate' => round((float) $candidate['bounce_rate'] - (float) $baseline['bounce_rate'], 6), + ], + ]; + } +} diff --git a/app/Services/Recommendations/PersonalizedFeedService.php b/app/Services/Recommendations/PersonalizedFeedService.php new file mode 100644 index 00000000..0ad3942f --- /dev/null +++ b/app/Services/Recommendations/PersonalizedFeedService.php @@ -0,0 +1,567 @@ +resolveAlgoVersion($algoVersion, $userId); + $weightSet = $this->resolveRankingWeights($resolvedAlgoVersion); + $offset = $this->decodeCursorToOffset($cursor); + + $cache = UserRecommendationCache::query() + ->where('user_id', $userId) + ->where('algo_version', $resolvedAlgoVersion) + ->first(); + + $cacheItems = $this->extractCacheItems($cache); + $isFresh = $cache !== null && $cache->expires_at !== null && $cache->expires_at->isFuture(); + + $cacheStatus = 'hit'; + if ($cache === null) { + $cacheStatus = 'miss'; + } elseif (! $isFresh) { + $cacheStatus = 'stale'; + } + + if ($cache === null || ! $isFresh) { + RegenerateUserRecommendationCacheJob::dispatch($userId, $resolvedAlgoVersion) + ->onQueue((string) config('discovery.queue', 'default')); + } + + $items = $cacheItems; + if ($items === []) { + $items = $this->buildColdStartRecommendations($resolvedAlgoVersion, 240, 'fallback'); + $cacheStatus = $cacheStatus . '-fallback'; + } + + return $this->buildFeedPageResponse( + items: $items, + offset: $offset, + limit: $safeLimit, + algoVersion: $resolvedAlgoVersion, + weightVersion: (string) $weightSet['version'], + cacheStatus: $cacheStatus, + generatedAt: $cache?->generated_at?->toIso8601String() + ); + } + + public function regenerateCacheForUser(int $userId, ?string $algoVersion = null): void + { + $resolvedAlgoVersion = $this->resolveAlgoVersion($algoVersion, $userId); + $cacheVersion = (string) config('discovery.cache_version', 'cache-v1'); + $ttlMinutes = max(1, (int) config('discovery.cache_ttl_minutes', 60)); + + $items = $this->buildRecommendations($userId, $resolvedAlgoVersion, 240); + $generatedAt = now(); + $expiresAt = now()->addMinutes($ttlMinutes); + + UserRecommendationCache::query()->updateOrCreate( + [ + 'user_id' => $userId, + 'algo_version' => $resolvedAlgoVersion, + ], + [ + 'cache_version' => $cacheVersion, + 'recommendations_json' => [ + 'items' => $items, + 'algo_version' => $resolvedAlgoVersion, + 'weight_version' => (string) $this->resolveRankingWeights($resolvedAlgoVersion)['version'], + 'generated_at' => $generatedAt->toIso8601String(), + ], + 'generated_at' => $generatedAt, + 'expires_at' => $expiresAt, + ] + ); + } + + /** + * @return array + */ + public function buildRecommendations(int $userId, string $algoVersion, int $maxItems = 240): array + { + $profileVersion = (string) config('discovery.profile_version', 'profile-v1'); + + $profile = UserInterestProfile::query() + ->where('user_id', $userId) + ->where('profile_version', $profileVersion) + ->where('algo_version', $algoVersion) + ->first(); + + $normalized = $profile !== null ? (array) ($profile->normalized_scores_json ?? []) : []; + $personalized = $this->buildProfileBasedRecommendations($normalized, $maxItems, $algoVersion); + + if ($personalized === []) { + return $this->buildColdStartRecommendations($algoVersion, $maxItems, 'cold_start'); + } + + $fallback = $this->buildColdStartRecommendations($algoVersion, $maxItems, 'fallback'); + + $combined = []; + foreach (array_merge($personalized, $fallback) as $item) { + $artworkId = (int) ($item['artwork_id'] ?? 0); + if ($artworkId <= 0) { + continue; + } + + if (! isset($combined[$artworkId])) { + $combined[$artworkId] = [ + 'artwork_id' => $artworkId, + 'score' => (float) ($item['score'] ?? 0.0), + 'source' => (string) ($item['source'] ?? 'mixed'), + ]; + continue; + } + + if ((float) $item['score'] > (float) $combined[$artworkId]['score']) { + $combined[$artworkId]['score'] = (float) $item['score']; + $combined[$artworkId]['source'] = (string) ($item['source'] ?? $combined[$artworkId]['source']); + } + } + + $candidates = array_values($combined); + usort($candidates, static fn (array $a, array $b): int => $b['score'] <=> $a['score']); + + return $this->applyDiversityGuard($candidates, $algoVersion, $maxItems); + } + + /** + * @param array $normalizedScores + * @return array + */ + private function buildProfileBasedRecommendations(array $normalizedScores, int $maxItems, string $algoVersion): array + { + $weightSet = $this->resolveRankingWeights($algoVersion); + $w1 = (float) $weightSet['w1']; + $w2 = (float) $weightSet['w2']; + $w3 = (float) $weightSet['w3']; + $w4 = (float) $weightSet['w4']; + + $categoryAffinities = []; + foreach ($normalizedScores as $key => $score) { + if (! is_numeric($score)) { + continue; + } + + if (! str_starts_with((string) $key, 'category:')) { + continue; + } + + $categoryId = (int) str_replace('category:', '', (string) $key); + if ($categoryId <= 0) { + continue; + } + + $categoryAffinities[$categoryId] = (float) $score; + } + + if ($categoryAffinities === []) { + return []; + } + + $rows = DB::table('artworks') + ->join('artwork_category', 'artwork_category.artwork_id', '=', 'artworks.id') + ->leftJoin('artwork_stats', 'artwork_stats.artwork_id', '=', 'artworks.id') + ->whereIn('artwork_category.category_id', array_keys($categoryAffinities)) + ->whereNull('artworks.deleted_at') + ->where('artworks.is_public', true) + ->where('artworks.is_approved', true) + ->whereNotNull('artworks.published_at') + ->where('artworks.published_at', '<=', now()) + ->orderByDesc('artworks.published_at') + ->limit(max(200, $maxItems * 8)) + ->get([ + 'artworks.id', + 'artworks.published_at', + 'artwork_category.category_id', + DB::raw('COALESCE(artwork_stats.views, 0) as views'), + ]); + + $scored = []; + foreach ($rows as $row) { + $artworkId = (int) $row->id; + $categoryId = (int) $row->category_id; + $affinity = (float) ($categoryAffinities[$categoryId] ?? 0.0); + if ($affinity <= 0.0) { + continue; + } + + $publishedAt = CarbonImmutable::parse((string) $row->published_at); + $ageDays = max(0.0, (float) $publishedAt->diffInSeconds(now()) / 86400); + $recency = exp(-$ageDays / 30.0); + $popularity = log(1 + max(0, (int) $row->views)) / 10.0; + $novelty = max(0.0, 1.0 - min(1.0, $popularity)); + + // Phase 8B blend with versioned weights (manual tuning, no auto-tuning yet). + $score = ($w1 * $affinity) + ($w2 * $recency) + ($w3 * $popularity) + ($w4 * $novelty); + + if (! isset($scored[$artworkId]) || $score > $scored[$artworkId]['score']) { + $scored[$artworkId] = [ + 'artwork_id' => $artworkId, + 'score' => $score, + 'source' => 'personalized', + ]; + } + } + + $candidates = array_values($scored); + usort($candidates, static fn (array $a, array $b): int => $b['score'] <=> $a['score']); + + return $this->applyDiversityGuard($candidates, $algoVersion, $maxItems); + } + + /** + * @return array + */ + private function buildColdStartRecommendations(string $algoVersion, int $maxItems, string $sourceLabel = 'cold_start'): array + { + $popularIds = DB::table('artworks') + ->leftJoin('artwork_stats', 'artwork_stats.artwork_id', '=', 'artworks.id') + ->whereNull('artworks.deleted_at') + ->where('artworks.is_public', true) + ->where('artworks.is_approved', true) + ->whereNotNull('artworks.published_at') + ->where('artworks.published_at', '<=', now()) + ->orderByDesc('artwork_stats.views') + ->orderByDesc('artwork_stats.downloads') + ->orderByDesc('artworks.published_at') + ->limit(max(40, $maxItems)) + ->pluck('artworks.id') + ->map(static fn (mixed $id): int => (int) $id) + ->all(); + + $seedIds = array_slice($popularIds, 0, 12); + + $similarIds = []; + if ($seedIds !== []) { + $similarIds = DB::table('artwork_similarities') + ->where('algo_version', $algoVersion) + ->whereIn('artwork_id', $seedIds) + ->orderBy('rank') + ->orderByDesc('score') + ->limit(max(80, $maxItems * 2)) + ->pluck('similar_artwork_id') + ->map(static fn (mixed $id): int => (int) $id) + ->all(); + } + + $candidates = []; + foreach ($popularIds as $index => $artworkId) { + $candidates[] = [ + 'artwork_id' => $artworkId, + 'score' => max(0.0, 1.0 - ($index * 0.003)), + 'source' => $sourceLabel, + ]; + } + + foreach ($similarIds as $index => $artworkId) { + $candidates[] = [ + 'artwork_id' => $artworkId, + 'score' => max(0.0, 0.75 - ($index * 0.002)), + 'source' => $sourceLabel, + ]; + } + + usort($candidates, static fn (array $a, array $b): int => $b['score'] <=> $a['score']); + + return $this->applyDiversityGuard($candidates, $algoVersion, $maxItems); + } + + /** + * @param array $candidates + * @return array + */ + private function applyDiversityGuard(array $candidates, string $algoVersion, int $maxItems): array + { + if ($candidates === []) { + return []; + } + + $uniqueCandidates = []; + foreach ($candidates as $candidate) { + $artworkId = (int) ($candidate['artwork_id'] ?? 0); + if ($artworkId <= 0 || isset($uniqueCandidates[$artworkId])) { + continue; + } + + $uniqueCandidates[$artworkId] = [ + 'artwork_id' => $artworkId, + 'score' => (float) ($candidate['score'] ?? 0.0), + 'source' => (string) ($candidate['source'] ?? 'mixed'), + ]; + } + + $flattened = array_values($uniqueCandidates); + $candidateIds = array_map(static fn (array $item): int => (int) $item['artwork_id'], $flattened); + + $nearDuplicatePairs = DB::table('artwork_similarities') + ->where('algo_version', $algoVersion) + ->where('score', '>=', 0.97) + ->whereIn('artwork_id', $candidateIds) + ->whereIn('similar_artwork_id', $candidateIds) + ->get(['artwork_id', 'similar_artwork_id']); + + $adjacency = []; + foreach ($nearDuplicatePairs as $pair) { + $left = (int) $pair->artwork_id; + $right = (int) $pair->similar_artwork_id; + + if ($left === $right) { + continue; + } + + $adjacency[$left][$right] = true; + $adjacency[$right][$left] = true; + } + + $selected = []; + $selectedSet = []; + + foreach ($flattened as $candidate) { + $id = (int) $candidate['artwork_id']; + + $isNearDuplicate = false; + foreach ($selectedSet as $selectedId => $value) { + if (($adjacency[$id][$selectedId] ?? false) || ($adjacency[$selectedId][$id] ?? false)) { + $isNearDuplicate = true; + break; + } + } + + if ($isNearDuplicate) { + continue; + } + + $selected[] = [ + 'artwork_id' => $id, + 'score' => round((float) $candidate['score'], 6), + 'source' => (string) $candidate['source'], + ]; + $selectedSet[$id] = true; + + if (count($selected) >= $maxItems) { + break; + } + } + + return $selected; + } + + /** + * @param array $items + */ + private function buildFeedPageResponse( + array $items, + int $offset, + int $limit, + string $algoVersion, + string $weightVersion, + string $cacheStatus, + ?string $generatedAt + ): array { + $safeOffset = max(0, $offset); + $pageItems = array_slice($items, $safeOffset, $limit); + + $ids = array_values(array_unique(array_map( + static fn (array $item): int => (int) ($item['artwork_id'] ?? 0), + $pageItems + ))); + + /** @var Collection $artworks */ + $artworks = Artwork::query() + ->with(['user:id,name']) + ->whereIn('id', $ids) + ->public() + ->published() + ->get() + ->keyBy('id'); + + $responseItems = []; + foreach ($pageItems as $item) { + $artworkId = (int) ($item['artwork_id'] ?? 0); + $artwork = $artworks->get($artworkId); + if ($artwork === null) { + continue; + } + + $responseItems[] = [ + 'id' => $artwork->id, + 'slug' => $artwork->slug, + 'title' => $artwork->title, + 'thumbnail_url' => $artwork->thumb_url, + 'author' => $artwork->user?->name, + 'score' => (float) ($item['score'] ?? 0.0), + 'source' => (string) ($item['source'] ?? 'mixed'), + ]; + } + + $nextOffset = $safeOffset + $limit; + $hasNext = $nextOffset < count($items); + + return [ + 'data' => $responseItems, + 'meta' => [ + 'algo_version' => $algoVersion, + 'weight_version' => $weightVersion, + 'cursor' => $this->encodeOffsetToCursor($safeOffset), + 'next_cursor' => $hasNext ? $this->encodeOffsetToCursor($nextOffset) : null, + 'limit' => $limit, + 'cache_status' => $cacheStatus, + 'generated_at' => $generatedAt, + 'total_candidates' => count($items), + ], + ]; + } + + private function resolveAlgoVersion(?string $algoVersion = null, ?int $userId = null): string + { + if ($algoVersion !== null && $algoVersion !== '') { + return $algoVersion; + } + + $forcedAlgoVersion = trim((string) config('discovery.rollout.force_algo_version', '')); + if ($forcedAlgoVersion !== '') { + return $forcedAlgoVersion; + } + + $defaultAlgoVersion = (string) config('discovery.algo_version', 'clip-cosine-v1'); + $rolloutEnabled = (bool) config('discovery.rollout.enabled', false); + if (! $rolloutEnabled || $userId === null || $userId <= 0) { + return $defaultAlgoVersion; + } + + $baselineAlgoVersion = (string) config('discovery.rollout.baseline_algo_version', $defaultAlgoVersion); + $candidateAlgoVersion = (string) config('discovery.rollout.candidate_algo_version', $defaultAlgoVersion); + if ($candidateAlgoVersion === '' || $candidateAlgoVersion === $baselineAlgoVersion) { + return $baselineAlgoVersion; + } + + $activeGate = (string) config('discovery.rollout.active_gate', 'g10'); + $gates = (array) config('discovery.rollout.gates', []); + $gate = (array) ($gates[$activeGate] ?? []); + $rolloutPercentage = (int) ($gate['percentage'] ?? 0); + $rolloutPercentage = max(0, min(100, $rolloutPercentage)); + + if ($rolloutPercentage <= 0) { + return $baselineAlgoVersion; + } + + if ($rolloutPercentage >= 100) { + return $candidateAlgoVersion; + } + + $bucket = abs((int) crc32((string) $userId)) % 100; + + return $bucket < $rolloutPercentage + ? $candidateAlgoVersion + : $baselineAlgoVersion; + } + + /** + * @return array{version:string,w1:float,w2:float,w3:float,w4:float} + */ + public function resolveRankingWeights(string $algoVersion): array + { + $defaults = (array) config('discovery.ranking.default_weights', []); + $byAlgo = (array) config('discovery.ranking.algo_weight_sets', []); + $override = (array) ($byAlgo[$algoVersion] ?? []); + + $resolved = array_merge($defaults, $override); + + $weights = [ + 'version' => (string) ($resolved['version'] ?? 'rank-w-v1'), + 'w1' => max(0.0, (float) ($resolved['w1'] ?? 0.65)), + 'w2' => max(0.0, (float) ($resolved['w2'] ?? 0.20)), + 'w3' => max(0.0, (float) ($resolved['w3'] ?? 0.10)), + 'w4' => max(0.0, (float) ($resolved['w4'] ?? 0.05)), + ]; + + $sum = $weights['w1'] + $weights['w2'] + $weights['w3'] + $weights['w4']; + if ($sum > 0.0) { + $weights['w1'] /= $sum; + $weights['w2'] /= $sum; + $weights['w3'] /= $sum; + $weights['w4'] /= $sum; + } + + return $weights; + } + + private function decodeCursorToOffset(?string $cursor): int + { + if ($cursor === null || $cursor === '') { + return 0; + } + + $decoded = base64_decode(strtr($cursor, '-_', '+/'), true); + if ($decoded === false) { + return 0; + } + + $json = json_decode($decoded, true); + if (! is_array($json)) { + return 0; + } + + return max(0, (int) Arr::get($json, 'offset', 0)); + } + + private function encodeOffsetToCursor(int $offset): string + { + $payload = json_encode(['offset' => max(0, $offset)]); + if (! is_string($payload)) { + return ''; + } + + return rtrim(strtr(base64_encode($payload), '+/', '-_'), '='); + } + + /** + * @return array + */ + private function extractCacheItems(?UserRecommendationCache $cache): array + { + if ($cache === null) { + return []; + } + + $raw = (array) ($cache->recommendations_json ?? []); + $items = $raw['items'] ?? null; + if (! is_array($items)) { + return []; + } + + $typed = []; + foreach ($items as $item) { + if (! is_array($item)) { + continue; + } + + $artworkId = (int) ($item['artwork_id'] ?? 0); + if ($artworkId <= 0) { + continue; + } + + $typed[] = [ + 'artwork_id' => $artworkId, + 'score' => (float) ($item['score'] ?? 0.0), + 'source' => (string) ($item['source'] ?? 'mixed'), + ]; + } + + return $typed; + } +} diff --git a/app/Services/Recommendations/SimilarArtworksService.php b/app/Services/Recommendations/SimilarArtworksService.php new file mode 100644 index 00000000..85d2c5c8 --- /dev/null +++ b/app/Services/Recommendations/SimilarArtworksService.php @@ -0,0 +1,45 @@ + + */ + public function forArtwork(int $artworkId, int $limit = 12, ?string $algoVersion = null): Collection + { + $effectiveAlgo = $algoVersion ?: (string) config('recommendations.embedding.algo_version', 'clip-cosine-v1'); + + $ids = DB::table('artwork_similarities') + ->where('artwork_id', $artworkId) + ->where('algo_version', $effectiveAlgo) + ->orderBy('rank') + ->limit(max(1, min($limit, 50))) + ->pluck('similar_artwork_id') + ->map(static fn ($id) => (int) $id) + ->all(); + + if ($ids === []) { + return collect(); + } + + $artworks = Artwork::query() + ->whereIn('id', $ids) + ->public() + ->published() + ->get(); + + $byId = $artworks->keyBy('id'); + + return collect($ids) + ->map(static fn (int $id) => $byId->get($id)) + ->filter(); + } +} diff --git a/app/Services/Recommendations/UserInterestProfileService.php b/app/Services/Recommendations/UserInterestProfileService.php new file mode 100644 index 00000000..f7c23f2a --- /dev/null +++ b/app/Services/Recommendations/UserInterestProfileService.php @@ -0,0 +1,162 @@ + $eventMeta + */ + public function applyEvent( + int $userId, + string $eventType, + int $artworkId, + ?int $categoryId, + CarbonInterface $occurredAt, + string $eventId, + string $algoVersion, + array $eventMeta = [] + ): void { + $profileVersion = (string) config('discovery.profile_version', 'profile-v1'); + $halfLifeHours = (float) config('discovery.decay.half_life_hours', 72); + $weightMap = (array) config('discovery.weights', []); + $eventWeight = (float) ($weightMap[$eventType] ?? 1.0); + + DB::transaction(function () use ( + $userId, + $categoryId, + $artworkId, + $occurredAt, + $eventId, + $algoVersion, + $profileVersion, + $halfLifeHours, + $eventWeight, + $eventMeta + ): void { + $profile = UserInterestProfile::query() + ->where('user_id', $userId) + ->where('profile_version', $profileVersion) + ->where('algo_version', $algoVersion) + ->lockForUpdate() + ->first(); + + $rawScores = $profile !== null ? (array) ($profile->raw_scores_json ?? []) : []; + $lastEventAt = $profile?->last_event_at; + + if ($lastEventAt !== null && $occurredAt->greaterThan($lastEventAt)) { + $hours = max(0.0, (float) $lastEventAt->diffInSeconds($occurredAt) / 3600); + $rawScores = $this->applyRecencyDecay($rawScores, $hours, $halfLifeHours); + } + + $interestKey = $categoryId !== null + ? sprintf('category:%d', $categoryId) + : sprintf('artwork:%d', $artworkId); + + $rawScores[$interestKey] = (float) ($rawScores[$interestKey] ?? 0.0) + $eventWeight; + + $rawScores = array_filter( + $rawScores, + static fn (mixed $value): bool => is_numeric($value) && (float) $value > 0.000001 + ); + + $normalizedScores = $this->normalizeScores($rawScores); + $totalWeight = array_sum($rawScores); + + $payload = [ + 'user_id' => $userId, + 'profile_version' => $profileVersion, + 'algo_version' => $algoVersion, + 'raw_scores_json' => $rawScores, + 'normalized_scores_json' => $normalizedScores, + 'total_weight' => $totalWeight, + 'event_count' => $profile !== null ? ((int) $profile->event_count + 1) : 1, + 'last_event_at' => $lastEventAt === null || $occurredAt->greaterThan($lastEventAt) + ? $occurredAt + : $lastEventAt, + 'half_life_hours' => $halfLifeHours, + 'updated_from_event_id' => $eventId, + 'updated_at' => now(), + ]; + + if ($profile === null) { + $payload['created_at'] = now(); + UserInterestProfile::query()->create($payload); + return; + } + + $profile->fill($payload); + $profile->save(); + }, 3); + } + + /** + * @param array $scores + * @return array + */ + public function applyRecencyDecay(array $scores, float $hoursElapsed, float $halfLifeHours): array + { + if ($hoursElapsed <= 0 || $halfLifeHours <= 0) { + return $this->castToFloatScores($scores); + } + + $decayFactor = exp(-log(2) * ($hoursElapsed / $halfLifeHours)); + $output = []; + + foreach ($scores as $key => $score) { + if (! is_numeric($score)) { + continue; + } + + $decayed = (float) $score * $decayFactor; + if ($decayed > 0.000001) { + $output[(string) $key] = $decayed; + } + } + + return $output; + } + + /** + * @param array $scores + * @return array + */ + public function normalizeScores(array $scores): array + { + $typedScores = $this->castToFloatScores($scores); + $sum = array_sum($typedScores); + + if ($sum <= 0.0) { + return []; + } + + $normalized = []; + foreach ($typedScores as $key => $score) { + $normalized[$key] = $score / $sum; + } + + return $normalized; + } + + /** + * @param array $scores + * @return array + */ + private function castToFloatScores(array $scores): array + { + $output = []; + foreach ($scores as $key => $score) { + if (is_numeric($score) && (float) $score > 0.0) { + $output[(string) $key] = (float) $score; + } + } + + return $output; + } +} diff --git a/app/Services/TagNormalizer.php b/app/Services/TagNormalizer.php new file mode 100644 index 00000000..65f2f4ab --- /dev/null +++ b/app/Services/TagNormalizer.php @@ -0,0 +1,39 @@ + hyphens and collapse repeats. + $value = str_replace(' ', '-', $value); + $value = (string) preg_replace('/\-+/u', '-', $value); + $value = trim($value, "-\t\n\r\0\x0B"); + + $maxLength = (int) config('tags.max_length', 32); + if ($maxLength > 0 && mb_strlen($value, 'UTF-8') > $maxLength) { + $value = mb_substr($value, 0, $maxLength, 'UTF-8'); + $value = rtrim($value, '-'); + } + + return $value; + } +} diff --git a/app/Services/TagService.php b/app/Services/TagService.php new file mode 100644 index 00000000..596e3235 --- /dev/null +++ b/app/Services/TagService.php @@ -0,0 +1,329 @@ +normalizer->normalize($rawTag); + $this->validateNormalizedTag($normalized); + + // Keep tags normalized in both name and slug (spec: normalize all tags). + // Unique(slug) + Unique(name) prevents duplicates. + return Tag::query()->firstOrCreate( + ['slug' => $normalized], + ['name' => $normalized, 'usage_count' => 0, 'is_active' => true] + ); + } + + /** + * @param array $tags + */ + public function attachUserTags(Artwork $artwork, array $tags): void + { + $normalized = $this->normalizeUserTags($tags); + if ($normalized === []) { + return; + } + + DB::transaction(function () use ($artwork, $normalized): void { + $tagIdsBySlug = []; + foreach ($normalized as $tag) { + $model = $this->createOrFindTag($tag); + $tagIdsBySlug[$model->slug] = $model->id; + } + + $tagIds = array_values($tagIdsBySlug); + + $existing = DB::table('artwork_tag') + ->where('artwork_id', $artwork->id) + ->whereIn('tag_id', $tagIds) + ->pluck('source', 'tag_id') + ->all(); + + $toAttach = []; + $toUpdate = []; + $newlyAttachedTagIds = []; + + foreach ($tagIds as $tagId) { + $source = $existing[$tagId] ?? null; + + if ($source === null) { + $toAttach[$tagId] = ['source' => 'user', 'confidence' => null, 'created_at' => now()]; + $newlyAttachedTagIds[] = $tagId; + continue; + } + + if ($source !== 'user') { + // User tags take precedence over AI/system. + $toUpdate[$tagId] = ['source' => 'user', 'confidence' => null]; + } + } + + if ($toAttach !== []) { + $artwork->tags()->syncWithoutDetaching($toAttach); + $this->incrementUsageCounts($newlyAttachedTagIds); + } + + foreach ($toUpdate as $tagId => $payload) { + $artwork->tags()->updateExistingPivot($tagId, $payload); + } + }); + } + + /** + * @param array $aiTags + */ + public function attachAiTags(Artwork $artwork, array $aiTags): void + { + if ($aiTags === []) { + return; + } + + DB::transaction(function () use ($artwork, $aiTags): void { + $payloads = []; + $newlyAttachedTagIds = []; + + foreach ($aiTags as $row) { + $raw = (string) ($row['tag'] ?? ''); + $confidence = $row['confidence'] ?? null; + + $normalized = $this->normalizer->normalize($raw); + if ($normalized === '') { + continue; + } + + // AI tagging must be optional: invalid/banned tags are skipped (not fatal). + try { + $this->validateNormalizedTag($normalized); + } catch (ValidationException $e) { + continue; + } + + $tag = $this->createOrFindTag($normalized); + + $existingSource = DB::table('artwork_tag') + ->where('artwork_id', $artwork->id) + ->where('tag_id', $tag->id) + ->value('source'); + + if ($existingSource === 'user') { + continue; + } + + if ($existingSource === null) { + $payloads[$tag->id] = [ + 'source' => 'ai', + 'confidence' => is_numeric($confidence) ? (float) $confidence : null, + 'created_at' => now(), + ]; + $newlyAttachedTagIds[] = $tag->id; + continue; + } + + if ($existingSource === 'ai') { + $artwork->tags()->updateExistingPivot($tag->id, [ + 'confidence' => is_numeric($confidence) ? (float) $confidence : null, + ]); + } + } + + if ($payloads !== []) { + $artwork->tags()->syncWithoutDetaching($payloads); + $this->incrementUsageCounts($newlyAttachedTagIds); + } + }); + } + + public function detachTags(Artwork $artwork, array $tagSlugsOrIds): void + { + if ($tagSlugsOrIds === []) { + return; + } + + $tagIds = Tag::query() + ->whereIn('id', array_filter($tagSlugsOrIds, 'is_numeric')) + ->orWhereIn('slug', array_filter($tagSlugsOrIds, fn ($v) => is_string($v) && $v !== '')) + ->pluck('id') + ->all(); + + if ($tagIds === []) { + return; + } + + DB::transaction(function () use ($artwork, $tagIds): void { + $existing = DB::table('artwork_tag') + ->where('artwork_id', $artwork->id) + ->whereIn('tag_id', $tagIds) + ->pluck('tag_id') + ->all(); + + if ($existing === []) { + return; + } + + $artwork->tags()->detach($existing); + $this->decrementUsageCounts($existing); + }); + } + + /** + * Sync user tags (PUT semantics): replaces the set of user-origin tags. + * + * @param array $tags + */ + public function syncTags(Artwork $artwork, array $tags): void + { + $normalized = $this->normalizeUserTags($tags); + + DB::transaction(function () use ($artwork, $normalized): void { + $desiredTagIds = []; + foreach ($normalized as $tag) { + $model = $this->createOrFindTag($tag); + $desiredTagIds[] = $model->id; + } + + $desiredTagIds = array_values(array_unique($desiredTagIds)); + + $currentUserTagIds = DB::table('artwork_tag') + ->where('artwork_id', $artwork->id) + ->where('source', 'user') + ->pluck('tag_id') + ->all(); + + $toDetach = array_values(array_diff($currentUserTagIds, $desiredTagIds)); + $toAttach = array_values(array_diff($desiredTagIds, $currentUserTagIds)); + + if ($toDetach !== []) { + $artwork->tags()->detach($toDetach); + $this->decrementUsageCounts($toDetach); + } + + if ($toAttach !== []) { + $payload = []; + foreach ($toAttach as $tagId) { + $payload[$tagId] = ['source' => 'user', 'confidence' => null, 'created_at' => now()]; + } + $artwork->tags()->syncWithoutDetaching($payload); + $this->incrementUsageCounts($toAttach); + } + + // Ensure desired tags are marked as user (user precedence). + if ($desiredTagIds !== []) { + $existingNonUser = DB::table('artwork_tag') + ->where('artwork_id', $artwork->id) + ->whereIn('tag_id', $desiredTagIds) + ->where('source', '!=', 'user') + ->pluck('tag_id') + ->all(); + + foreach ($existingNonUser as $tagId) { + $artwork->tags()->updateExistingPivot($tagId, ['source' => 'user', 'confidence' => null]); + } + } + }); + } + + public function updateUsageCount(Tag $tag): void + { + $count = (int) DB::table('artwork_tag')->where('tag_id', $tag->id)->count(); + $tag->forceFill(['usage_count' => $count])->save(); + } + + /** + * @param array $tags + * @return array + */ + private function normalizeUserTags(array $tags): array + { + $max = (int) config('tags.max_user_tags', 15); + if (count($tags) > $max) { + throw ValidationException::withMessages([ + 'tags' => ["Too many tags (max {$max})."], + ]); + } + + $normalized = []; + foreach ($tags as $tag) { + $value = $this->normalizer->normalize((string) $tag); + if ($value === '') { + continue; + } + $this->validateNormalizedTag($value); + $normalized[] = $value; + } + + $normalized = array_values(array_unique($normalized)); + return $normalized; + } + + private function validateNormalizedTag(string $normalized): void + { + if ($normalized === '') { + throw ValidationException::withMessages([ + 'tags' => ['Invalid tag.'], + ]); + } + + $banned = array_map('strval', (array) config('tags.banned', [])); + if ($banned !== [] && in_array($normalized, $banned, true)) { + throw ValidationException::withMessages([ + 'tags' => ['Tag is not allowed.'], + ]); + } + + $patterns = (array) config('tags.banned_regex', []); + foreach ($patterns as $pattern) { + $pattern = (string) $pattern; + if ($pattern === '') { + continue; + } + if (@preg_match($pattern, $normalized) === 1) { + throw ValidationException::withMessages([ + 'tags' => ['Tag is not allowed.'], + ]); + } + } + } + + /** + * @param array $tagIds + */ + private function incrementUsageCounts(array $tagIds): void + { + if ($tagIds === []) { + return; + } + + Tag::query()->whereIn('id', $tagIds)->increment('usage_count'); + } + + /** + * @param array $tagIds + */ + private function decrementUsageCounts(array $tagIds): void + { + if ($tagIds === []) { + return; + } + + // Never allow negative counts. + DB::table('tags') + ->whereIn('id', $tagIds) + ->update(['usage_count' => DB::raw('CASE WHEN usage_count > 0 THEN usage_count - 1 ELSE 0 END')]); + } +} diff --git a/app/Services/ThumbnailService.php b/app/Services/ThumbnailService.php index ea9d96f0..83d7dd36 100644 --- a/app/Services/ThumbnailService.php +++ b/app/Services/ThumbnailService.php @@ -5,7 +5,8 @@ use Illuminate\Support\Facades\Storage; class ThumbnailService { - protected const CDN_HOST = 'http://files.skinbase.org'; + // Use the thumbnails CDN host (HTTPS) + protected const CDN_HOST = 'https://files.skinbase.org'; protected const VALID_SIZES = ['sm','md','lg','xl']; diff --git a/app/Services/Upload/Contracts/UploadDraftServiceInterface.php b/app/Services/Upload/Contracts/UploadDraftServiceInterface.php new file mode 100644 index 00000000..db6a5ce5 --- /dev/null +++ b/app/Services/Upload/Contracts/UploadDraftServiceInterface.php @@ -0,0 +1,51 @@ + string, 'path' => string, 'meta' => array] + */ + public function createDraft(array $attributes = []): array; + + /** + * Store the main uploaded file for the draft. + * + * @param string $draftId + * @param UploadedFile $file + * @return array Metadata about stored file (path, size, mime, hash) + */ + public function storeMainFile(string $draftId, UploadedFile $file): array; + + /** + * Store a screenshot/preview image for the draft. + * + * @param string $draftId + * @param UploadedFile $file + * @return array Metadata about stored screenshot + */ + public function storeScreenshot(string $draftId, UploadedFile $file): array; + + /** + * Calculate a content hash for a local file path or storage path. + * + * @param string $filePath + * @return string + */ + public function calculateHash(string $filePath): string; + + /** + * Set an expiration timestamp for the draft. + * + * @param string $draftId + * @param \Carbon\Carbon|null $expiresAt + * @return bool + */ + public function setExpiration(string $draftId, ?\Carbon\Carbon $expiresAt = null): bool; +} diff --git a/app/Services/Upload/PreviewService.php b/app/Services/Upload/PreviewService.php new file mode 100644 index 00000000..e7d7706a --- /dev/null +++ b/app/Services/Upload/PreviewService.php @@ -0,0 +1,79 @@ +manager = extension_loaded('gd') ? ImageManager::gd() : ImageManager::imagick(); + } catch (\Throwable $e) { + $this->manager = null; + } + } + + public function generateFromImage(string $uploadId, string $sourcePath): array + { + if ($this->manager === null) { + throw new RuntimeException('PreviewService requires Intervention Image.'); + } + + $disk = Storage::disk('local'); + if (! $disk->exists($sourcePath)) { + return $this->generatePlaceholder($uploadId); + } + + $absolute = $disk->path($sourcePath); + $previewPath = "tmp/drafts/{$uploadId}/preview.webp"; + $thumbPath = "tmp/drafts/{$uploadId}/thumb.webp"; + + $preview = $this->manager->read($absolute)->scaleDown(1280, 1280); + $thumb = $this->manager->read($absolute)->cover(320, 320); + + $previewEncoded = (string) $preview->encode(new \Intervention\Image\Encoders\WebpEncoder(85)); + $thumbEncoded = (string) $thumb->encode(new \Intervention\Image\Encoders\WebpEncoder(82)); + + $disk->put($previewPath, $previewEncoded); + $disk->put($thumbPath, $thumbEncoded); + + return [ + 'preview_path' => $previewPath, + 'thumb_path' => $thumbPath, + ]; + } + + public function generateFromArchive(string $uploadId, ?string $screenshotPath = null): array + { + if ($screenshotPath !== null && Storage::disk('local')->exists($screenshotPath)) { + return $this->generateFromImage($uploadId, $screenshotPath); + } + + return $this->generatePlaceholder($uploadId); + } + + public function generatePlaceholder(string $uploadId): array + { + $disk = Storage::disk('local'); + $previewPath = "tmp/drafts/{$uploadId}/preview.webp"; + $thumbPath = "tmp/drafts/{$uploadId}/thumb.webp"; + + // 1x1 transparent webp + $tinyWebp = base64_decode('UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAAAfQ//73v/+BiOh/AAA='); + $disk->put($previewPath, $tinyWebp ?: ''); + $disk->put($thumbPath, $tinyWebp ?: ''); + + return [ + 'preview_path' => $previewPath, + 'thumb_path' => $thumbPath, + ]; + } +} diff --git a/app/Services/Upload/TagAnalysisService.php b/app/Services/Upload/TagAnalysisService.php new file mode 100644 index 00000000..ffe59f28 --- /dev/null +++ b/app/Services/Upload/TagAnalysisService.php @@ -0,0 +1,105 @@ + + */ + public function analyze(string $filename, ?string $previewPath, ?string $categoryContext): array + { + $results = []; + + foreach ($this->extractFilenameTags($filename) as $tag) { + $results[] = [ + 'tag' => $tag, + 'confidence' => 0.72, + 'source' => 'filename', + ]; + } + + if ($previewPath !== null && $previewPath !== '') { + // Stub AI output for now (real model integration can replace this later) + $results[] = [ + 'tag' => 'ai-detected', + 'confidence' => 0.66, + 'source' => 'ai', + ]; + $results[] = [ + 'tag' => 'visual-content', + 'confidence' => 0.61, + 'source' => 'ai', + ]; + } + + if ($categoryContext !== null && $categoryContext !== '') { + $normalized = $this->normalizer->normalize($categoryContext); + if ($normalized !== '') { + $results[] = [ + 'tag' => $normalized, + 'confidence' => 0.60, + 'source' => 'manual', + ]; + } + } + + return $this->dedupe($results); + } + + /** + * @return array + */ + private function extractFilenameTags(string $filename): array + { + $base = pathinfo($filename, PATHINFO_FILENAME) ?: $filename; + $parts = preg_split('/[\s._\-]+/', mb_strtolower($base, 'UTF-8')) ?: []; + + $tags = []; + foreach ($parts as $part) { + $normalized = $this->normalizer->normalize((string) $part); + if ($normalized !== '' && mb_strlen($normalized, 'UTF-8') >= 3) { + $tags[] = $normalized; + } + } + + return array_values(array_unique($tags)); + } + + /** + * @param array $rows + * @return array + */ + private function dedupe(array $rows): array + { + $best = []; + + foreach ($rows as $row) { + $tag = $this->normalizer->normalize((string) ($row['tag'] ?? '')); + if ($tag === '') { + continue; + } + + $confidence = (float) ($row['confidence'] ?? 0.0); + $source = (string) ($row['source'] ?? 'manual'); + + if (! isset($best[$tag]) || $best[$tag]['confidence'] < $confidence) { + $best[$tag] = [ + 'tag' => $tag, + 'confidence' => max(0.0, min(1.0, $confidence)), + 'source' => in_array($source, ['ai', 'filename', 'manual'], true) ? $source : 'manual', + ]; + } + } + + return array_values($best); + } +} diff --git a/app/Services/Upload/UploadDraftService.php b/app/Services/Upload/UploadDraftService.php new file mode 100644 index 00000000..80fd6c6f --- /dev/null +++ b/app/Services/Upload/UploadDraftService.php @@ -0,0 +1,191 @@ +filesystem = $filesystem; + $this->diskName = $diskName; + $this->disk = $this->filesystem->disk($this->diskName); + } + + public function createDraft(array $attributes = []): array + { + $id = (string) Str::uuid(); + $path = trim($this->basePath, '/') . '/' . $id; + + if (! $this->disk->exists($path)) { + $this->disk->makeDirectory($path); + } + + $meta = array_merge(['id' => $id, 'created_at' => Carbon::now()->toISOString()], $attributes); + + DB::table('uploads')->insert([ + 'id' => $id, + 'user_id' => (int) ($attributes['user_id'] ?? 0), + 'type' => (string) ($attributes['type'] ?? 'image'), + 'status' => 'draft', + 'moderation_status' => 'pending', + 'processing_state' => 'pending_scan', + 'expires_at' => null, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + $this->writeMeta($id, $meta); + + return ['id' => $id, 'path' => $path, 'meta' => $meta]; + } + + public function storeMainFile(string $draftId, UploadedFile $file): array + { + $dir = trim($this->basePath, '/') . '/' . $draftId . '/main'; + if (! $this->disk->exists($dir)) { + $this->disk->makeDirectory($dir); + } + + $filename = time() . '_' . preg_replace('/[^A-Za-z0-9_\.-]/', '_', $file->getClientOriginalName()); + $storedPath = $this->disk->putFileAs($dir, $file, $filename); + + $size = $this->safeSize($storedPath, $file); + $mime = $file->getClientMimeType() ?? $this->safeMimeType($storedPath); + $hash = $this->calculateHash($file->getRealPath() ?: $storedPath); + + $info = ['path' => $storedPath, 'size' => $size, 'mime' => $mime, 'hash' => $hash]; + + $meta = $this->readMeta($draftId); + $meta['main_file'] = $info; + $this->writeMeta($draftId, $meta); + + DB::table('upload_files')->insert([ + 'upload_id' => $draftId, + 'path' => $storedPath, + 'type' => 'main', + 'hash' => $hash, + 'size' => $size, + 'mime' => $mime, + 'created_at' => now(), + ]); + + return $info; + } + + public function storeScreenshot(string $draftId, UploadedFile $file): array + { + $dir = trim($this->basePath, '/') . '/' . $draftId . '/screenshots'; + if (! $this->disk->exists($dir)) { + $this->disk->makeDirectory($dir); + } + + $filename = time() . '_' . preg_replace('/[^A-Za-z0-9_\.-]/', '_', $file->getClientOriginalName()); + $storedPath = $this->disk->putFileAs($dir, $file, $filename); + + $size = $this->safeSize($storedPath, $file); + $mime = $file->getClientMimeType() ?? $this->safeMimeType($storedPath); + $hash = $this->calculateHash($file->getRealPath() ?: $storedPath); + + $info = ['path' => $storedPath, 'size' => $size, 'mime' => $mime, 'hash' => $hash]; + + $meta = $this->readMeta($draftId); + $meta['screenshots'][] = $info; + $this->writeMeta($draftId, $meta); + + DB::table('upload_files')->insert([ + 'upload_id' => $draftId, + 'path' => $storedPath, + 'type' => 'screenshot', + 'hash' => $hash, + 'size' => $size, + 'mime' => $mime, + 'created_at' => now(), + ]); + + return $info; + } + + public function calculateHash(string $filePath): string + { + // If path points to a local filesystem file + if (is_file($filePath)) { + return hash_file('sha256', $filePath); + } + + // If path is a storage-relative path + if ($this->disk->exists($filePath)) { + $contents = $this->disk->get($filePath); + return hash('sha256', $contents); + } + + throw new \RuntimeException('File not found for hashing: ' . $filePath); + } + + public function setExpiration(string $draftId, ?Carbon $expiresAt = null): bool + { + $meta = $this->readMeta($draftId); + $meta['expires_at'] = $expiresAt?->toISOString(); + $this->writeMeta($draftId, $meta); + + DB::table('uploads')->where('id', $draftId)->update([ + 'expires_at' => $expiresAt, + 'updated_at' => now(), + ]); + + return true; + } + + protected function metaPath(string $draftId): string + { + return trim($this->basePath, '/') . '/' . $draftId . '/meta.json'; + } + + protected function readMeta(string $draftId): array + { + $path = $this->metaPath($draftId); + if (! $this->disk->exists($path)) { + return []; + } + + $raw = $this->disk->get($path); + $decoded = json_decode($raw, true); + return is_array($decoded) ? $decoded : []; + } + + protected function writeMeta(string $draftId, array $meta): void + { + $path = $this->metaPath($draftId); + $this->disk->put($path, json_encode($meta, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + } + + protected function safeSize(string $storedPath, UploadedFile $file): int + { + try { + return $this->disk->size($storedPath); + } catch (\Throwable $e) { + return (int) $file->getSize(); + } + } + + protected function safeMimeType(string $storedPath): ?string + { + try { + return $this->disk->mimeType($storedPath); + } catch (\Throwable $e) { + return null; + } + } +} diff --git a/app/Services/Uploads/UploadAuditService.php b/app/Services/Uploads/UploadAuditService.php new file mode 100644 index 00000000..fe30850d --- /dev/null +++ b/app/Services/Uploads/UploadAuditService.php @@ -0,0 +1,19 @@ +repository->log($userId, $action, $ip, $meta); + } +} diff --git a/app/Services/Uploads/UploadCancelService.php b/app/Services/Uploads/UploadCancelService.php new file mode 100644 index 00000000..30edf736 --- /dev/null +++ b/app/Services/Uploads/UploadCancelService.php @@ -0,0 +1,84 @@ +sessions->getOrFail($sessionId); + + $lockSeconds = (int) config('uploads.chunk.lock_seconds', 10); + $lockWait = (int) config('uploads.chunk.lock_wait_seconds', 5); + $lock = Cache::lock('uploads:cancel:' . $sessionId, $lockSeconds); + + try { + $lock->block($lockWait); + } catch (\Throwable $e) { + $this->audit->log($userId, 'upload_cancel_locked', $ip, [ + 'session_id' => $sessionId, + ]); + throw new RuntimeException('Upload is busy. Please retry.'); + } + + try { + if (in_array($session->status, [UploadSessionStatus::CANCELLED, UploadSessionStatus::PROCESSED, UploadSessionStatus::QUARANTINED], true)) { + $this->audit->log($userId, 'upload_cancel_noop', $ip, [ + 'session_id' => $sessionId, + 'status' => $session->status, + ]); + + return [ + 'session_id' => $sessionId, + 'status' => $session->status, + ]; + } + + $this->safeDeleteTmp($session->tempPath); + + $this->sessions->updateStatus($sessionId, UploadSessionStatus::CANCELLED); + $this->sessions->updateProgress($sessionId, 0); + $this->sessions->updateFailureReason($sessionId, 'cancelled'); + + $this->audit->log($userId, 'upload_cancelled', $ip, [ + 'session_id' => $sessionId, + ]); + + return [ + 'session_id' => $sessionId, + 'status' => UploadSessionStatus::CANCELLED, + ]; + } finally { + optional($lock)->release(); + } + } + + private function safeDeleteTmp(string $path): void + { + $tmpRoot = $this->storage->sectionPath('tmp'); + $realRoot = realpath($tmpRoot); + $realPath = realpath($path); + + if (! $realRoot || ! $realPath || strpos($realPath, $realRoot) !== 0) { + return; + } + + if (File::exists($realPath)) { + File::delete($realPath); + } + } +} diff --git a/app/Services/Uploads/UploadChunkService.php b/app/Services/Uploads/UploadChunkService.php new file mode 100644 index 00000000..91d6c85d --- /dev/null +++ b/app/Services/Uploads/UploadChunkService.php @@ -0,0 +1,204 @@ +sessions->getOrFail($sessionId); + + $this->ensureTmpPath($session->tempPath); + $this->ensureWritable($session->tempPath); + $this->ensureChunkReadable($chunkPath, $chunkSize); + $this->ensureLimits($totalSize, $chunkSize); + + $lockSeconds = (int) config('uploads.chunk.lock_seconds', 10); + $lockWait = (int) config('uploads.chunk.lock_wait_seconds', 5); + $lock = Cache::lock('uploads:chunk:' . $sessionId, $lockSeconds); + + try { + $lock->block($lockWait); + } catch (\Throwable $e) { + $this->audit->log($userId, 'upload_chunk_locked', $ip, [ + 'session_id' => $sessionId, + ]); + throw new RuntimeException('Upload is busy. Please retry.'); + } + + try { + $currentSize = (int) filesize($session->tempPath); + + if ($offset > $currentSize) { + $this->audit->log($userId, 'upload_chunk_offset_mismatch', $ip, [ + 'session_id' => $sessionId, + 'offset' => $offset, + 'current_size' => $currentSize, + ]); + throw new RuntimeException('Invalid chunk offset.'); + } + + if ($offset < $currentSize) { + if ($offset + $chunkSize <= $currentSize) { + return $this->finalizeResult($sessionId, $totalSize, $currentSize); + } + + $this->audit->log($userId, 'upload_chunk_overlap', $ip, [ + 'session_id' => $sessionId, + 'offset' => $offset, + 'current_size' => $currentSize, + ]); + throw new RuntimeException('Chunk overlap detected.'); + } + + $written = $this->appendToFile($session->tempPath, $chunkPath, $offset, $chunkSize); + $newSize = $currentSize + $written; + + if ($newSize > $totalSize) { + $this->audit->log($userId, 'upload_chunk_size_exceeded', $ip, [ + 'session_id' => $sessionId, + 'new_size' => $newSize, + 'total_size' => $totalSize, + ]); + throw new RuntimeException('Upload exceeded expected size.'); + } + + $this->sessions->updateStatus($sessionId, UploadSessionStatus::TMP); + $result = $this->finalizeResult($sessionId, $totalSize, $newSize); + + $this->audit->log($userId, 'upload_chunk_appended', $ip, [ + 'session_id' => $sessionId, + 'received_bytes' => $newSize, + 'total_size' => $totalSize, + 'progress' => $result->progress, + ]); + + return $result; + } finally { + optional($lock)->release(); + } + } + + private function finalizeResult(string $sessionId, int $totalSize, int $currentSize): UploadChunkResult + { + $progress = $totalSize > 0 ? (int) floor(($currentSize / $totalSize) * 100) : 0; + $progress = min(90, max(0, $progress)); + $this->sessions->updateProgress($sessionId, $progress); + + return new UploadChunkResult( + $sessionId, + UploadSessionStatus::TMP, + $currentSize, + $totalSize, + $progress + ); + } + + private function ensureTmpPath(string $path): void + { + $tmpRoot = $this->storage->sectionPath('tmp'); + $realRoot = realpath($tmpRoot); + $realPath = realpath($path); + + if (! $realRoot || ! $realPath || strpos($realPath, $realRoot) !== 0) { + throw new RuntimeException('Invalid temp path.'); + } + } + + private function ensureWritable(string $path): void + { + if (! File::exists($path)) { + File::put($path, ''); + } + + if (! is_writable($path)) { + throw new RuntimeException('Upload path not writable.'); + } + } + + private function ensureLimits(int $totalSize, int $chunkSize): void + { + $maxBytes = (int) config('uploads.max_size_mb', 0) * 1024 * 1024; + if ($maxBytes > 0 && $totalSize > $maxBytes) { + throw new RuntimeException('Upload exceeds max size.'); + } + + $maxChunk = (int) config('uploads.chunk.max_bytes', 0); + if ($maxChunk > 0 && $chunkSize > $maxChunk) { + throw new RuntimeException('Chunk exceeds max size.'); + } + } + + private function ensureChunkReadable(string $chunkPath, int $chunkSize): void + { + $exists = is_file($chunkPath); + $readable = $exists ? is_readable($chunkPath) : false; + $actualSize = $exists ? (int) @filesize($chunkPath) : null; + + if (! $exists || ! $readable) { + logger()->warning('Upload chunk unreadable or missing', [ + 'chunk_path' => $chunkPath, + 'expected_size' => $chunkSize, + 'exists' => $exists, + 'readable' => $readable, + 'actual_size' => $actualSize, + ]); + throw new RuntimeException('Upload chunk missing.'); + } + + if ($actualSize !== $chunkSize) { + logger()->warning('Upload chunk size mismatch', [ + 'chunk_path' => $chunkPath, + 'expected_size' => $chunkSize, + 'actual_size' => $actualSize, + ]); + throw new RuntimeException('Chunk size mismatch.'); + } + } + + private function appendToFile(string $targetPath, string $chunkPath, int $offset, int $chunkSize): int + { + $in = fopen($chunkPath, 'rb'); + if (! $in) { + throw new RuntimeException('Unable to read upload chunk.'); + } + + $out = fopen($targetPath, 'c+b'); + if (! $out) { + fclose($in); + throw new RuntimeException('Unable to write upload chunk.'); + } + + if (fseek($out, $offset) !== 0) { + fclose($in); + fclose($out); + throw new RuntimeException('Failed to seek in upload file.'); + } + + $written = stream_copy_to_stream($in, $out, $chunkSize); + fflush($out); + fclose($in); + fclose($out); + + if ($written === false || (int) $written !== $chunkSize) { + throw new RuntimeException('Incomplete chunk write.'); + } + + return (int) $written; + } +} diff --git a/app/Services/Uploads/UploadDerivativesService.php b/app/Services/Uploads/UploadDerivativesService.php new file mode 100644 index 00000000..70b6c059 --- /dev/null +++ b/app/Services/Uploads/UploadDerivativesService.php @@ -0,0 +1,89 @@ +manager = extension_loaded('gd') ? ImageManager::gd() : ImageManager::imagick(); + $this->imageAvailable = true; + } catch (\Throwable $e) { + logger()->warning('Intervention Image present but configuration failed: ' . $e->getMessage()); + $this->imageAvailable = false; + $this->manager = null; + } + } + + public function storeOriginal(string $sourcePath, string $hash): string + { + $this->assertImageAvailable(); + + $dir = $this->storage->ensureHashDirectory('originals', $hash); + $target = $dir . DIRECTORY_SEPARATOR . 'orig.webp'; + $quality = (int) config('uploads.quality', 85); + + /** @var InterventionImageInterface $img */ + $img = $this->manager->read($sourcePath); + $encoder = new \Intervention\Image\Encoders\WebpEncoder($quality); + $encoded = (string) $img->encode($encoder); + File::put($target, $encoded); + + return $target; + } + + public function generatePublicDerivatives(string $sourcePath, string $hash): array + { + $this->assertImageAvailable(); + $quality = (int) config('uploads.quality', 85); + $variants = (array) config('uploads.derivatives', []); + $dir = $this->storage->publicHashDirectory($hash); + $written = []; + + foreach ($variants as $variant => $options) { + $variant = (string) $variant; + $path = $dir . DIRECTORY_SEPARATOR . $variant . '.webp'; + + /** @var InterventionImageInterface $img */ + $img = $this->manager->read($sourcePath); + + if (isset($options['size'])) { + $size = (int) $options['size']; + $out = $img->cover($size, $size); + } else { + $max = (int) ($options['max'] ?? 0); + if ($max <= 0) { + $max = 2560; + } + + $out = $img->scaleDown($max, $max); + } + + $encoder = new \Intervention\Image\Encoders\WebpEncoder($quality); + $encoded = (string) $out->encode($encoder); + File::put($path, $encoded); + $written[$variant] = $path; + } + + return $written; + } + + private function assertImageAvailable(): void + { + if (! $this->imageAvailable) { + throw new RuntimeException('Intervention Image is not available.'); + } + } +} diff --git a/app/Services/Uploads/UploadHashService.php b/app/Services/Uploads/UploadHashService.php new file mode 100644 index 00000000..040fbc17 --- /dev/null +++ b/app/Services/Uploads/UploadHashService.php @@ -0,0 +1,21 @@ +storage->ensureSection('tmp'); + $filename = Str::uuid()->toString() . '.upload'; + $tempPath = $dir . DIRECTORY_SEPARATOR . $filename; + + File::put($tempPath, ''); + + $sessionId = (string) Str::uuid(); + $session = $this->sessions->create($sessionId, $userId, $tempPath, UploadSessionStatus::INIT, $ip); + $token = $this->tokens->generate($sessionId, $userId); + + $this->audit->log($userId, 'upload_init', $ip, [ + 'session_id' => $sessionId, + ]); + + return new UploadInitResult($session->id, $token, $session->status); + } + + public function receiveToTmp(UploadedFile $file, int $userId, string $ip): UploadSessionData + { + $stored = $this->storage->storeUploadedFile($file, 'tmp'); + $sessionId = (string) Str::uuid(); + $session = $this->sessions->create($sessionId, $userId, $stored->path, UploadSessionStatus::TMP, $ip); + $this->sessions->updateProgress($sessionId, 10); + + $this->audit->log($userId, 'upload_received', $ip, [ + 'session_id' => $sessionId, + 'size' => $stored->size, + ]); + + return $session; + } + + public function validateAndHash(string $sessionId): UploadValidatedFile + { + $session = $this->sessions->getOrFail($sessionId); + $validation = $this->validator->validate($session->tempPath); + + if (! $validation->ok) { + $this->quarantine($session, $validation->reason); + return new UploadValidatedFile($validation, null); + } + + $hash = $this->hasher->hashFile($session->tempPath); + $this->sessions->updateStatus($sessionId, UploadSessionStatus::VALIDATED); + $this->sessions->updateProgress($sessionId, 30); + $this->audit->log($session->userId, 'upload_validated', $session->ip, [ + 'session_id' => $sessionId, + 'hash' => $hash, + ]); + + return new UploadValidatedFile($validation, $hash); + } + + public function scan(string $sessionId): UploadScanResult + { + $session = $this->sessions->getOrFail($sessionId); + $result = $this->scanner->scan($session->tempPath); + + if (! $result->ok) { + $this->quarantine($session, $result->reason); + return $result; + } + + $this->sessions->updateStatus($sessionId, UploadSessionStatus::SCANNED); + $this->sessions->updateProgress($sessionId, 50); + $this->audit->log($session->userId, 'upload_scanned', $session->ip, [ + 'session_id' => $sessionId, + ]); + + return $result; + } + + public function processAndPublish(string $sessionId, string $hash, int $artworkId): array + { + $session = $this->sessions->getOrFail($sessionId); + + $originalPath = $this->derivatives->storeOriginal($session->tempPath, $hash); + $originalRelative = $this->storage->sectionRelativePath('originals', $hash, 'orig.webp'); + $this->artworkFiles->upsert($artworkId, 'orig', $originalRelative, 'image/webp', (int) filesize($originalPath)); + + $publicAbsolute = $this->derivatives->generatePublicDerivatives($session->tempPath, $hash); + $publicRelative = []; + + foreach ($publicAbsolute as $variant => $absolutePath) { + $filename = $variant . '.webp'; + $relativePath = $this->storage->publicRelativePath($hash, $filename); + $this->artworkFiles->upsert($artworkId, $variant, $relativePath, 'image/webp', (int) filesize($absolutePath)); + $publicRelative[$variant] = $relativePath; + } + + $dimensions = @getimagesize($session->tempPath); + $width = is_array($dimensions) && isset($dimensions[0]) ? (int) $dimensions[0] : 1; + $height = is_array($dimensions) && isset($dimensions[1]) ? (int) $dimensions[1] : 1; + + Artwork::query()->whereKey($artworkId)->update([ + 'file_name' => basename($originalRelative), + 'file_path' => '', + 'file_size' => (int) filesize($originalPath), + 'mime_type' => 'image/webp', + 'hash' => $hash, + 'file_ext' => 'webp', + 'thumb_ext' => 'webp', + 'width' => max(1, $width), + 'height' => max(1, $height), + ]); + + $this->sessions->updateStatus($sessionId, UploadSessionStatus::PROCESSED); + $this->sessions->updateProgress($sessionId, 100); + $this->audit->log($session->userId, 'upload_processed', $session->ip, [ + 'session_id' => $sessionId, + 'hash' => $hash, + 'artwork_id' => $artworkId, + ]); + + return [ + 'orig' => $originalRelative, + 'public' => $publicRelative, + ]; + } + + private function quarantine(UploadSessionData $session, string $reason): void + { + $newPath = $this->storage->moveToSection($session->tempPath, 'quarantine'); + $this->sessions->updateTempPath($session->id, $newPath); + $this->sessions->updateStatus($session->id, UploadSessionStatus::QUARANTINED); + $this->sessions->updateFailureReason($session->id, $reason); + $this->sessions->updateProgress($session->id, 0); + $this->audit->log($session->userId, 'upload_quarantined', $session->ip, [ + 'session_id' => $session->id, + 'reason' => $reason, + ]); + } +} diff --git a/app/Services/Uploads/UploadQuotaService.php b/app/Services/Uploads/UploadQuotaService.php new file mode 100644 index 00000000..aec8700d --- /dev/null +++ b/app/Services/Uploads/UploadQuotaService.php @@ -0,0 +1,36 @@ + 0) { + $active = $this->sessions->countActiveForUser($userId); + if ($active >= $activeLimit) { + throw new RuntimeException('Upload limit reached.'); + } + } + + $dailyLimit = (int) config('uploads.quotas.max_daily_sessions', 0); + if ($dailyLimit > 0) { + $since = CarbonImmutable::now()->startOfDay(); + $daily = $this->sessions->countForUserSince($userId, $since); + if ($daily >= $dailyLimit) { + throw new RuntimeException('Daily upload limit reached.'); + } + } + } +} diff --git a/app/Services/Uploads/UploadScanService.php b/app/Services/Uploads/UploadScanService.php new file mode 100644 index 00000000..ef2e7164 --- /dev/null +++ b/app/Services/Uploads/UploadScanService.php @@ -0,0 +1,45 @@ +buildCommand($command, $path); + $process = new Process($command); + $process->run(); + + if ($process->isSuccessful()) { + return UploadScanResult::clean(); + } + + if ($process->getExitCode() === 1) { + return UploadScanResult::infected(trim($process->getOutput())); + } + + throw new RuntimeException('Upload scan failed: ' . trim($process->getErrorOutput())); + } + + private function buildCommand(array $command, string $path): array + { + return array_map(static function (string $part) use ($path): string { + return $part === '{path}' ? $path : $part; + }, $command); + } +} diff --git a/app/Services/Uploads/UploadSessionStatus.php b/app/Services/Uploads/UploadSessionStatus.php new file mode 100644 index 00000000..6fdb91ab --- /dev/null +++ b/app/Services/Uploads/UploadSessionStatus.php @@ -0,0 +1,16 @@ +sessions->getOrFail($sessionId); + $receivedBytes = $this->safeFileSize($session->tempPath); + + return [ + 'session_id' => $session->id, + 'status' => $session->status, + 'progress' => $session->progress, + 'failure_reason' => $session->failureReason, + 'user_id' => $session->userId, + 'received_bytes' => $receivedBytes, + ]; + } + + private function safeFileSize(string $path): int + { + $tmpRoot = $this->storage->sectionPath('tmp'); + $realRoot = realpath($tmpRoot); + $realPath = realpath($path); + + if (! $realRoot || ! $realPath || strpos($realPath, $realRoot) !== 0) { + return 0; + } + + if (! File::exists($realPath)) { + return 0; + } + + return (int) File::size($realPath); + } +} diff --git a/app/Services/Uploads/UploadStorageService.php b/app/Services/Uploads/UploadStorageService.php new file mode 100644 index 00000000..3d035f3b --- /dev/null +++ b/app/Services/Uploads/UploadStorageService.php @@ -0,0 +1,136 @@ +sectionPath($section); + + if (! File::exists($path)) { + File::makeDirectory($path, 0755, true); + } + + return $path; + } + + public function storeUploadedFile(UploadedFile $file, string $section): UploadStoredFile + { + $dir = $this->ensureSection($section); + $extension = $this->safeExtension($file); + $filename = Str::uuid()->toString() . ($extension !== '' ? '.' . $extension : ''); + + $file->move($dir, $filename); + + $path = $dir . DIRECTORY_SEPARATOR . $filename; + + return UploadStoredFile::fromPath($path); + } + + public function moveToSection(string $path, string $section): string + { + if (! is_file($path)) { + throw new RuntimeException('Source file not found for move.'); + } + + $dir = $this->ensureSection($section); + $extension = (string) pathinfo($path, PATHINFO_EXTENSION); + $filename = Str::uuid()->toString() . ($extension !== '' ? '.' . $extension : ''); + $target = $dir . DIRECTORY_SEPARATOR . $filename; + + File::move($path, $target); + + return $target; + } + + public function ensureHashDirectory(string $section, string $hash): string + { + $segments = $this->hashSegments($hash); + $dir = $this->sectionPath($section) . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $segments); + + if (! File::exists($dir)) { + File::makeDirectory($dir, 0755, true); + } + + return $dir; + } + + public function publicHashDirectory(string $hash): string + { + $prefix = trim((string) config('uploads.public_img_prefix', 'img'), DIRECTORY_SEPARATOR); + $base = $this->sectionPath('public') . DIRECTORY_SEPARATOR . $prefix; + + if (! File::exists($base)) { + File::makeDirectory($base, 0755, true); + } + + $segments = $this->hashSegments($hash); + $dir = $base . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $segments); + + if (! File::exists($dir)) { + File::makeDirectory($dir, 0755, true); + } + + return $dir; + } + + public function publicRelativePath(string $hash, string $filename): string + { + $prefix = trim((string) config('uploads.public_img_prefix', 'img'), DIRECTORY_SEPARATOR); + $segments = $this->hashSegments($hash); + + return $prefix . '/' . implode('/', $segments) . '/' . ltrim($filename, '/'); + } + + public function sectionRelativePath(string $section, string $hash, string $filename): string + { + $segments = $this->hashSegments($hash); + $section = trim($section, DIRECTORY_SEPARATOR); + + return $section . '/' . implode('/', $segments) . '/' . ltrim($filename, '/'); + } + + private function safeExtension(UploadedFile $file): string + { + $extension = (string) $file->guessExtension(); + $extension = strtolower($extension); + + return preg_match('/^[a-z0-9]+$/', $extension) ? $extension : ''; + } + + private function hashSegments(string $hash): array + { + $hash = strtolower($hash); + $hash = preg_replace('/[^a-z0-9]/', '', $hash) ?? ''; + $hash = str_pad($hash, 6, '0'); + + $segments = [ + substr($hash, 0, 2), + substr($hash, 2, 2), + substr($hash, 4, 2), + ]; + + return array_map(static fn (string $part): string => $part === '' ? '00' : $part, $segments); + } +} diff --git a/app/Services/Uploads/UploadTokenService.php b/app/Services/Uploads/UploadTokenService.php new file mode 100644 index 00000000..8f9a4aad --- /dev/null +++ b/app/Services/Uploads/UploadTokenService.php @@ -0,0 +1,36 @@ +cacheKey($token), [ + 'session_id' => $sessionId, + 'user_id' => $userId, + ], now()->addMinutes($ttl)); + + return $token; + } + + public function get(string $token): ?array + { + $data = Cache::get($this->cacheKey($token)); + + return is_array($data) ? $data : null; + } + + private function cacheKey(string $token): string + { + return 'uploads:token:' . $token; + } +} diff --git a/app/Services/Uploads/UploadValidationService.php b/app/Services/Uploads/UploadValidationService.php new file mode 100644 index 00000000..590b4829 --- /dev/null +++ b/app/Services/Uploads/UploadValidationService.php @@ -0,0 +1,112 @@ +maxSizeBytes(); + if ($maxBytes > 0 && $size > $maxBytes) { + return UploadValidationResult::fail('file_too_large', null, null, null, $size); + } + + $mime = $this->detectMime($path); + if ($mime === '' || ! in_array($mime, $this->allowedMimes(), true)) { + return UploadValidationResult::fail('mime_not_allowed', null, null, $mime, $size); + } + + $info = @getimagesize($path); + if (! $info || empty($info[0]) || empty($info[1])) { + return UploadValidationResult::fail('invalid_image', null, null, $mime, $size); + } + + $width = (int) $info[0]; + $height = (int) $info[1]; + $maxPixels = $this->maxPixels(); + if ($maxPixels > 0 && ($width > $maxPixels || $height > $maxPixels)) { + return UploadValidationResult::fail('image_too_large', $width, $height, $mime, $size); + } + + $data = @file_get_contents($path); + if ($data === false) { + return UploadValidationResult::fail('file_unreadable', $width, $height, $mime, $size); + } + + $image = @imagecreatefromstring($data); + if ($image === false) { + return UploadValidationResult::fail('decode_failed', $width, $height, $mime, $size); + } + + $reencodeOk = $this->reencodeTest($image, $mime); + imagedestroy($image); + + if (! $reencodeOk) { + return UploadValidationResult::fail('reencode_failed', $width, $height, $mime, $size); + } + + return UploadValidationResult::ok($width, $height, $mime, $size); + } + + private function maxSizeBytes(): int + { + return (int) config('uploads.max_size_mb', 0) * 1024 * 1024; + } + + private function maxPixels(): int + { + return (int) config('uploads.max_pixels', 0); + } + + private function allowedMimes(): array + { + $allowed = (array) config('uploads.allowed_mimes', []); + if ((bool) config('uploads.allow_gif', false)) { + $allowed[] = 'image/gif'; + } + + return array_values(array_unique($allowed)); + } + + private function detectMime(string $path): string + { + $finfo = new \finfo(FILEINFO_MIME_TYPE); + $mime = $finfo->file($path); + + return $mime ? (string) $mime : ''; + } + + private function reencodeTest($image, string $mime): bool + { + ob_start(); + $result = false; + + switch ($mime) { + case 'image/jpeg': + $result = function_exists('imagejpeg') ? imagejpeg($image, null, 80) : false; + break; + case 'image/png': + $result = function_exists('imagepng') ? imagepng($image, null, 6) : false; + break; + case 'image/webp': + $result = function_exists('imagewebp') ? imagewebp($image, null, 80) : false; + break; + case 'image/gif': + $result = function_exists('imagegif') ? imagegif($image) : false; + break; + } + + $data = ob_get_clean(); + + return (bool) $result && is_string($data) && $data !== ''; + } +} diff --git a/app/Services/Vision/ArtworkEmbeddingClient.php b/app/Services/Vision/ArtworkEmbeddingClient.php new file mode 100644 index 00000000..f64b6f77 --- /dev/null +++ b/app/Services/Vision/ArtworkEmbeddingClient.php @@ -0,0 +1,95 @@ + + */ + public function embed(string $imageUrl, int $artworkId, string $sourceHash): array + { + $base = trim((string) config('vision.clip.base_url', '')); + if ($base === '') { + return []; + } + + $endpoint = (string) config('recommendations.embedding.endpoint', '/embed'); + $url = rtrim($base, '/') . '/' . ltrim($endpoint, '/'); + + $timeout = (int) config('recommendations.embedding.timeout_seconds', 8); + $connectTimeout = (int) config('recommendations.embedding.connect_timeout_seconds', 2); + $retries = (int) config('recommendations.embedding.retries', 1); + $delay = (int) config('recommendations.embedding.retry_delay_ms', 200); + + $response = Http::acceptJson() + ->connectTimeout(max(1, $connectTimeout)) + ->timeout(max(1, $timeout)) + ->retry(max(0, $retries), max(0, $delay), throw: false) + ->post($url, [ + 'image_url' => $imageUrl, + 'artwork_id' => $artworkId, + 'hash' => $sourceHash, + ]); + + if (! $response->ok()) { + return []; + } + + return $this->extractEmbedding($response->json()); + } + + /** + * @param mixed $json + * @return array + */ + private function extractEmbedding(mixed $json): array + { + $candidate = null; + + if (is_array($json) && $this->isNumericVector($json)) { + $candidate = $json; + } elseif (is_array($json) && isset($json['embedding']) && is_array($json['embedding'])) { + $candidate = $json['embedding']; + } elseif (is_array($json) && isset($json['data']['embedding']) && is_array($json['data']['embedding'])) { + $candidate = $json['data']['embedding']; + } + + if (! is_array($candidate) || ! $this->isNumericVector($candidate)) { + return []; + } + + $vector = array_map(static fn ($value): float => (float) $value, $candidate); + $dim = count($vector); + + $minDim = (int) config('recommendations.embedding.min_dim', 64); + $maxDim = (int) config('recommendations.embedding.max_dim', 4096); + if ($dim < $minDim || $dim > $maxDim) { + return []; + } + + return $vector; + } + + /** + * @param array $arr + */ + private function isNumericVector(array $arr): bool + { + if ($arr === []) { + return false; + } + + foreach ($arr as $value) { + if (! is_numeric($value)) { + return false; + } + } + + return true; + } +} diff --git a/app/Uploads/Commands/CleanupUploadsCommand.php b/app/Uploads/Commands/CleanupUploadsCommand.php new file mode 100644 index 00000000..0a00c911 --- /dev/null +++ b/app/Uploads/Commands/CleanupUploadsCommand.php @@ -0,0 +1,25 @@ +option('limit'); + $deleted = $cleanupService->cleanupStaleDrafts($limit); + + $this->info("Uploads cleanup deleted {$deleted} draft(s)."); + + return self::SUCCESS; + } +} diff --git a/app/Uploads/Exceptions/DraftQuotaException.php b/app/Uploads/Exceptions/DraftQuotaException.php new file mode 100644 index 00000000..5ee3ed54 --- /dev/null +++ b/app/Uploads/Exceptions/DraftQuotaException.php @@ -0,0 +1,42 @@ +machineCode; + } + + public function httpStatus(): int + { + return $this->httpStatus; + } + + public static function draftLimit(): self + { + return new self('draft_limit', 429); + } + + public static function storageLimit(): self + { + return new self('storage_limit', 413); + } + + public static function duplicateUpload(): self + { + return new self('duplicate_upload', 422); + } +} diff --git a/app/Uploads/Exceptions/UploadNotFoundException.php b/app/Uploads/Exceptions/UploadNotFoundException.php new file mode 100644 index 00000000..730b7de4 --- /dev/null +++ b/app/Uploads/Exceptions/UploadNotFoundException.php @@ -0,0 +1,11 @@ +where('id', $this->uploadId)->first(); + if (! $upload) { + return; + } + + if ((string) $upload->status !== 'draft' || ! (bool) $upload->is_scanned) { + return; + } + + $this->advanceProcessingState('generating_preview', ['pending_scan', 'scanning', 'generating_preview']); + + $previewData = null; + + if ((string) $upload->type === 'image') { + $main = DB::table('upload_files') + ->where('upload_id', $this->uploadId) + ->where('type', 'main') + ->orderBy('id') + ->first(['path']); + + if (! $main || ! Storage::disk('local')->exists((string) $main->path)) { + return; + } + + $previewData = $previewService->generateFromImage($this->uploadId, (string) $main->path); + } elseif ((string) $upload->type === 'archive') { + $screenshot = DB::table('upload_files') + ->where('upload_id', $this->uploadId) + ->where('type', 'screenshot') + ->orderBy('id') + ->first(['path']); + + $previewData = $previewService->generateFromArchive($this->uploadId, $screenshot?->path ? (string) $screenshot->path : null); + } else { + return; + } + + $previewPath = (string) ($previewData['preview_path'] ?? ''); + if ($previewPath === '') { + return; + } + + DB::table('uploads')->where('id', $this->uploadId)->update([ + 'preview_path' => $previewPath, + 'updated_at' => now(), + ]); + + $this->advanceProcessingState('analyzing_tags', ['pending_scan', 'scanning', 'generating_preview', 'analyzing_tags']); + + DB::table('upload_files') + ->where('upload_id', $this->uploadId) + ->where('type', 'preview') + ->delete(); + + DB::table('upload_files')->insert([ + 'upload_id' => $this->uploadId, + 'path' => $previewPath, + 'type' => 'preview', + 'hash' => null, + 'size' => Storage::disk('local')->exists($previewPath) ? Storage::disk('local')->size($previewPath) : null, + 'mime' => 'image/webp', + 'created_at' => now(), + ]); + + TagAnalysisJob::dispatch($this->uploadId); + } + + /** + * @param array $allowedCurrentStates + */ + private function advanceProcessingState(string $targetState, array $allowedCurrentStates): void + { + DB::table('uploads') + ->where('id', $this->uploadId) + ->where('status', 'draft') + ->where(function ($query) use ($allowedCurrentStates): void { + $query->whereNull('processing_state') + ->orWhereIn('processing_state', $allowedCurrentStates); + }) + ->update([ + 'processing_state' => $targetState, + 'updated_at' => now(), + ]); + } +} diff --git a/app/Uploads/Jobs/TagAnalysisJob.php b/app/Uploads/Jobs/TagAnalysisJob.php new file mode 100644 index 00000000..0eab1265 --- /dev/null +++ b/app/Uploads/Jobs/TagAnalysisJob.php @@ -0,0 +1,127 @@ +where('id', $this->uploadId)->first(); + if (! $upload) { + return; + } + + if ((string) $upload->status !== 'draft') { + return; + } + + if (! (bool) $upload->is_scanned) { + return; + } + + if (empty($upload->preview_path)) { + return; + } + + $this->advanceProcessingState('analyzing_tags', ['pending_scan', 'scanning', 'generating_preview', 'analyzing_tags']); + + $main = DB::table('upload_files') + ->where('upload_id', $this->uploadId) + ->where('type', 'main') + ->orderBy('id') + ->first(['path']); + + $filename = $main ? basename((string) $main->path) : ''; + $categoryContext = null; + + if (! empty($upload->category_id)) { + $category = DB::table('categories')->where('id', (int) $upload->category_id)->first(['name', 'slug']); + if ($category) { + $categoryContext = (string) ($category->name ?: $category->slug); + } + } + + $tags = $analysis->analyze($filename, (string) $upload->preview_path, $categoryContext); + + DB::transaction(function () use ($tags): void { + DB::table('upload_tags')->where('upload_id', $this->uploadId)->delete(); + + foreach ($tags as $row) { + $tagName = (string) ($row['tag'] ?? ''); + if ($tagName === '') { + continue; + } + + $slug = $tagName; + $tag = DB::table('tags')->where('slug', $slug)->first(['id']); + if (! $tag) { + $tagId = DB::table('tags')->insertGetId([ + 'name' => $tagName, + 'slug' => $slug, + 'usage_count' => 0, + 'is_active' => true, + 'created_at' => now(), + 'updated_at' => now(), + ]); + } else { + $tagId = (int) $tag->id; + } + + DB::table('upload_tags')->insert([ + 'upload_id' => $this->uploadId, + 'tag_id' => $tagId, + 'confidence' => (float) ($row['confidence'] ?? 0.0), + 'source' => (string) ($row['source'] ?? 'manual'), + 'created_at' => now(), + 'updated_at' => now(), + ]); + } + + DB::table('uploads')->where('id', $this->uploadId)->update([ + 'has_tags' => true, + 'processing_state' => DB::raw("CASE WHEN processing_state IN ('ready','published','rejected') THEN processing_state ELSE 'ready' END"), + 'updated_at' => now(), + ]); + }); + } + + /** + * @param array $allowedCurrentStates + */ + private function advanceProcessingState(string $targetState, array $allowedCurrentStates): void + { + DB::table('uploads') + ->where('id', $this->uploadId) + ->where('status', 'draft') + ->where(function ($query) use ($allowedCurrentStates): void { + $query->whereNull('processing_state') + ->orWhereIn('processing_state', $allowedCurrentStates); + }) + ->update([ + 'processing_state' => $targetState, + 'updated_at' => now(), + ]); + } +} diff --git a/app/Uploads/Jobs/VirusScanJob.php b/app/Uploads/Jobs/VirusScanJob.php new file mode 100644 index 00000000..0a4b636b --- /dev/null +++ b/app/Uploads/Jobs/VirusScanJob.php @@ -0,0 +1,93 @@ +where('id', $this->uploadId)->first(); + if (! $upload || (string) $upload->status !== 'draft') { + return; + } + + $this->advanceProcessingState('scanning', ['pending_scan', 'scanning']); + + $files = DB::table('upload_files') + ->where('upload_id', $this->uploadId) + ->whereIn('type', ['main', 'screenshot']) + ->get(['path']); + + foreach ($files as $file) { + $path = (string) ($file->path ?? ''); + if ($path === '' || ! Storage::disk('local')->exists($path)) { + continue; + } + + $absolute = Storage::disk('local')->path($path); + $result = $scanner->scan($absolute); + + if (! $result->ok) { + DB::table('uploads')->where('id', $this->uploadId)->update([ + 'status' => 'rejected', + 'processing_state' => 'rejected', + 'updated_at' => now(), + ]); + + Storage::disk('local')->deleteDirectory('tmp/drafts/' . $this->uploadId); + return; + } + } + + DB::table('uploads')->where('id', $this->uploadId)->update([ + 'is_scanned' => true, + 'updated_at' => now(), + ]); + + $this->advanceProcessingState('generating_preview', ['pending_scan', 'scanning', 'generating_preview']); + + PreviewGenerationJob::dispatch($this->uploadId); + } + + /** + * @param array $allowedCurrentStates + */ + private function advanceProcessingState(string $targetState, array $allowedCurrentStates): void + { + DB::table('uploads') + ->where('id', $this->uploadId) + ->where('status', 'draft') + ->where(function ($query) use ($allowedCurrentStates): void { + $query->whereNull('processing_state') + ->orWhereIn('processing_state', $allowedCurrentStates); + }) + ->update([ + 'processing_state' => $targetState, + 'updated_at' => now(), + ]); + } +} diff --git a/app/Uploads/Services/ArchiveInspectorService.php b/app/Uploads/Services/ArchiveInspectorService.php new file mode 100644 index 00000000..d825a0f2 --- /dev/null +++ b/app/Uploads/Services/ArchiveInspectorService.php @@ -0,0 +1,205 @@ + */ + private const BLOCKED_EXTENSIONS = [ + 'php', + 'exe', + 'sh', + 'bat', + 'js', + 'ps1', + 'cmd', + 'vbs', + 'jar', + 'elf', + ]; + + public function inspect(string $archivePath): \App\Uploads\Services\InspectionResult + { + $zip = new ZipArchive(); + $opened = $zip->open($archivePath); + + if ($opened !== true) { + throw new RuntimeException('Unable to read archive metadata.'); + } + + $files = 0; + $maxDepth = 0; + $totalUncompressed = 0; + $totalCompressed = 0; + + for ($index = 0; $index < $zip->numFiles; $index++) { + $stat = $zip->statIndex($index); + if (! is_array($stat)) { + continue; + } + + $entryName = (string) ($stat['name'] ?? ''); + $uncompressedSize = (int) ($stat['size'] ?? 0); + $compressedSize = (int) ($stat['comp_size'] ?? 0); + $isDirectory = str_ends_with($entryName, '/'); + + $pathCheck = $this->validatePath($entryName); + if ($pathCheck !== null) { + return $this->closeAndFail($zip, $pathCheck, $files, $maxDepth, $totalUncompressed, $totalCompressed); + } + + if ($this->isSymlink($zip, $index)) { + return $this->closeAndFail($zip, 'Archive contains a symlink entry.', $files, $maxDepth, $totalUncompressed, $totalCompressed); + } + + $depth = $this->depthForEntry($entryName, $isDirectory); + $maxDepth = max($maxDepth, $depth); + + if ($maxDepth > self::MAX_DEPTH) { + return $this->closeAndFail($zip, 'Archive directory depth exceeds 5.', $files, $maxDepth, $totalUncompressed, $totalCompressed); + } + + if (! $isDirectory) { + $files++; + + if ($files > self::MAX_FILES) { + return $this->closeAndFail($zip, 'Archive file count exceeds 5000.', $files, $maxDepth, $totalUncompressed, $totalCompressed); + } + + $extension = strtolower((string) pathinfo($entryName, PATHINFO_EXTENSION)); + if (in_array($extension, self::BLOCKED_EXTENSIONS, true)) { + return $this->closeAndFail($zip, 'Archive contains blocked executable/script file.', $files, $maxDepth, $totalUncompressed, $totalCompressed); + } + + $totalUncompressed += max(0, $uncompressedSize); + $totalCompressed += max(0, $compressedSize); + + if ($totalUncompressed > self::MAX_UNCOMPRESSED_BYTES) { + return $this->closeAndFail($zip, 'Archive uncompressed size exceeds 500 MB.', $files, $maxDepth, $totalUncompressed, $totalCompressed); + } + + $ratio = $this->compressionRatio($totalUncompressed, $totalCompressed); + if ($ratio > self::MAX_RATIO) { + return $this->closeAndFail($zip, 'Archive compression ratio exceeds safety threshold.', $files, $maxDepth, $totalUncompressed, $totalCompressed); + } + } + } + + $stats = $this->stats($files, $maxDepth, $totalUncompressed, $totalCompressed); + $zip->close(); + + return \App\Uploads\Services\InspectionResult::pass($stats); + } + + private function validatePath(string $entryName): ?string + { + $normalized = str_replace('\\', '/', $entryName); + + if ($normalized === '' || str_contains($normalized, "\0")) { + return 'Archive contains invalid entry path.'; + } + + if ( + strlen($entryName) >= 3 + && ctype_alpha($entryName[0]) + && $entryName[1] === ':' + && in_array($entryName[2], ['\\', '/'], true) + ) { + return 'Archive entry contains drive-letter absolute path.'; + } + + if (str_starts_with($normalized, '/') || str_starts_with($normalized, '\\')) { + return 'Archive entry contains absolute path.'; + } + + if (str_contains($entryName, '../') || str_contains($entryName, '..\\') || str_contains($normalized, '../')) { + return 'Archive entry contains path traversal sequence.'; + } + + $segments = array_filter(explode('/', trim($normalized, '/')), static fn (string $segment): bool => $segment !== ''); + foreach ($segments as $segment) { + if ($segment === '..') { + return 'Archive entry contains parent traversal segment.'; + } + } + + return null; + } + + private function isSymlink(ZipArchive $zip, int $index): bool + { + $attributes = 0; + $opsys = 0; + + if (! $zip->getExternalAttributesIndex($index, $opsys, $attributes)) { + return false; + } + + if ($opsys !== ZipArchive::OPSYS_UNIX) { + return false; + } + + $mode = ($attributes >> 16) & 0xF000; + + return $mode === 0xA000; + } + + private function depthForEntry(string $entryName, bool $isDirectory): int + { + $normalized = trim(str_replace('\\', '/', $entryName), '/'); + if ($normalized === '') { + return 0; + } + + $segments = array_values(array_filter(explode('/', $normalized), static fn (string $segment): bool => $segment !== '')); + if ($segments === []) { + return 0; + } + + return max(0, count($segments) - ($isDirectory ? 0 : 1)); + } + + private function compressionRatio(int $uncompressed, int $compressed): float + { + if ($uncompressed <= 0) { + return 0.0; + } + + if ($compressed <= 0) { + return (float) $uncompressed; + } + + return $uncompressed / $compressed; + } + + /** + * @return array{files:int,depth:int,size:int,ratio:float} + */ + private function stats(int $files, int $depth, int $size, int $compressed): array + { + return [ + 'files' => $files, + 'depth' => $depth, + 'size' => $size, + 'ratio' => $this->compressionRatio($size, $compressed), + ]; + } + + private function closeAndFail(ZipArchive $zip, string $reason, int $files, int $depth, int $size, int $compressed): \App\Uploads\Services\InspectionResult + { + $stats = $this->stats($files, $depth, $size, $compressed); + $zip->close(); + + return \App\Uploads\Services\InspectionResult::fail($reason, $stats); + } +} diff --git a/app/Uploads/Services/CleanupService.php b/app/Uploads/Services/CleanupService.php new file mode 100644 index 00000000..87e83a54 --- /dev/null +++ b/app/Uploads/Services/CleanupService.php @@ -0,0 +1,55 @@ +copy()->subDay(); + + $drafts = DB::table('uploads') + ->select(['id']) + ->where('status', 'draft') + ->where(function ($query) use ($now, $inactiveThreshold): void { + $query->where('expires_at', '<', $now) + ->orWhere(function ($inner) use ($inactiveThreshold): void { + $inner->where('updated_at', '<', $inactiveThreshold) + ->where('status', '!=', 'published'); + }); + }) + ->orderBy('updated_at') + ->limit($limit) + ->get(); + + if ($drafts->isEmpty()) { + Log::info('Upload cleanup completed', ['deleted' => 0]); + return 0; + } + + $deleted = 0; + + DB::transaction(function () use ($drafts, &$deleted): void { + foreach ($drafts as $draft) { + $uploadId = (string) $draft->id; + + DB::table('uploads')->where('id', $uploadId)->delete(); + Storage::disk('local')->deleteDirectory('tmp/drafts/' . $uploadId); + + $deleted++; + } + }); + + Log::info('Upload cleanup completed', ['deleted' => $deleted]); + + return $deleted; + } +} diff --git a/app/Uploads/Services/DraftQuotaService.php b/app/Uploads/Services/DraftQuotaService.php new file mode 100644 index 00000000..d710ea0e --- /dev/null +++ b/app/Uploads/Services/DraftQuotaService.php @@ -0,0 +1,89 @@ +, main_hash:string} $incomingFiles + * @return array + */ + public function assertCanCreateDraft(User $user, array $incomingFiles): array + { + $maxDrafts = max(1, (int) config('uploads.draft_quota.max_drafts_per_user', 10)); + $maxStorageMb = max(1, (int) config('uploads.draft_quota.max_draft_storage_mb_per_user', 1024)); + $maxStorageBytes = $maxStorageMb * 1024 * 1024; + $policy = (string) config('uploads.draft_quota.duplicate_hash_policy', 'block'); + $warnings = []; + + $draftCount = DB::table('uploads') + ->where('user_id', (int) $user->id) + ->where('status', 'draft') + ->count(); + + if ($draftCount >= $maxDrafts) { + throw DraftQuotaException::draftLimit(); + } + + $currentDraftStorage = (int) DB::table('upload_files as uf') + ->join('uploads as u', 'u.id', '=', 'uf.upload_id') + ->where('u.user_id', (int) $user->id) + ->where('u.status', 'draft') + ->sum(DB::raw('COALESCE(uf.size, 0)')); + + $incomingSize = $this->incomingSizeBytes((array) ($incomingFiles['files'] ?? [])); + + if (($currentDraftStorage + $incomingSize) > $maxStorageBytes) { + throw DraftQuotaException::storageLimit(); + } + + $mainHash = strtolower(trim((string) ($incomingFiles['main_hash'] ?? ''))); + if ($mainHash !== '' && $this->publishedMainHashExists($mainHash)) { + if ($policy === 'warn') { + $warnings[] = 'duplicate_hash'; + } else { + throw DraftQuotaException::duplicateUpload(); + } + } + + return $warnings; + } + + /** + * @param array $files + */ + private function incomingSizeBytes(array $files): int + { + $total = 0; + + foreach ($files as $file) { + if (! $file instanceof UploadedFile) { + continue; + } + + $size = $file->getSize(); + if (is_numeric($size)) { + $total += (int) $size; + } + } + + return max(0, $total); + } + + private function publishedMainHashExists(string $hash): bool + { + return DB::table('upload_files as uf') + ->join('uploads as u', 'u.id', '=', 'uf.upload_id') + ->where('uf.type', 'main') + ->where('uf.hash', $hash) + ->where('u.status', 'published') + ->exists(); + } +} diff --git a/app/Uploads/Services/FileMoveService.php b/app/Uploads/Services/FileMoveService.php new file mode 100644 index 00000000..b516043e --- /dev/null +++ b/app/Uploads/Services/FileMoveService.php @@ -0,0 +1,49 @@ +exists($sourceRelativeDir)) { + throw new RuntimeException('Draft directory not found.'); + } + + $targetRelativeDir = trim($targetRelativeDir, '/'); + $stagingRelativeDir = $targetRelativeDir . '.__staging'; + + if ($disk->exists($targetRelativeDir)) { + throw new RuntimeException('Target publish directory already exists.'); + } + + if ($disk->exists($stagingRelativeDir)) { + $disk->deleteDirectory($stagingRelativeDir); + } + + $sourceAbs = $disk->path($sourceRelativeDir); + $stagingAbs = $disk->path($stagingRelativeDir); + $targetAbs = $disk->path($targetRelativeDir); + + if (! File::copyDirectory($sourceAbs, $stagingAbs)) { + throw new RuntimeException('Failed to stage files for publish.'); + } + + if (! File::moveDirectory($stagingAbs, $targetAbs, false)) { + $disk->deleteDirectory($stagingRelativeDir); + throw new RuntimeException('Failed to move staged files to final location.'); + } + } +} diff --git a/app/Uploads/Services/InspectionResult.php b/app/Uploads/Services/InspectionResult.php new file mode 100644 index 00000000..d7a63b75 --- /dev/null +++ b/app/Uploads/Services/InspectionResult.php @@ -0,0 +1,46 @@ + $this->valid, + 'reason' => $this->reason, + 'stats' => $this->stats, + ]; + } +} diff --git a/app/Uploads/Services/PublishService.php b/app/Uploads/Services/PublishService.php new file mode 100644 index 00000000..4a3df86d --- /dev/null +++ b/app/Uploads/Services/PublishService.php @@ -0,0 +1,140 @@ +find($uploadId); + if (! $upload) { + throw new UploadNotFoundException('Upload not found.'); + } + + $this->validateBeforePublish($upload, $user); + + $mainFile = DB::table('upload_files') + ->where('upload_id', $uploadId) + ->where('type', 'main') + ->orderBy('id') + ->first(['path', 'hash']); + + if (! $mainFile || empty($mainFile->hash)) { + throw new UploadPublishValidationException('Main file hash is missing.'); + } + + $hash = strtolower((string) preg_replace('/[^a-z0-9]/', '', (string) $mainFile->hash)); + if ($hash === '' || strlen($hash) < 4) { + throw new UploadPublishValidationException('Invalid main file hash.'); + } + + $aa = substr($hash, 0, 2); + $bb = substr($hash, 2, 2); + $targetDir = "files/artworks/{$aa}/{$bb}/{$hash}"; + + $tempPrefix = 'tmp/drafts/' . $uploadId . '/'; + $promoted = false; + + try { + DB::beginTransaction(); + + $this->fileMoveService->promoteDraft($uploadId, $targetDir); + $promoted = true; + + $files = DB::table('upload_files')->where('upload_id', $uploadId)->get(['id', 'path']); + foreach ($files as $file) { + $oldPath = (string) $file->path; + if (str_starts_with($oldPath, $tempPrefix)) { + $newPath = $targetDir . '/' . ltrim(substr($oldPath, strlen($tempPrefix)), '/'); + DB::table('upload_files')->where('id', $file->id)->update(['path' => $newPath]); + } + } + + $upload->status = 'published'; + $upload->processing_state = 'published'; + if (empty($upload->slug)) { + $upload->slug = $this->slugService->makeSlug((string) ($upload->title ?? '')); + } + $upload->published_at = now(); + $upload->final_path = $targetDir; + $upload->save(); + + DB::commit(); + } catch (\Throwable $e) { + DB::rollBack(); + + if ($promoted) { + Storage::disk('local')->deleteDirectory($targetDir); + } + + throw $e; + } + + Storage::disk('local')->deleteDirectory('tmp/drafts/' . $uploadId); + + return Upload::query()->findOrFail($uploadId); + } + + private function validateBeforePublish(Upload $upload, User $user): void + { + if ((int) $upload->user_id !== (int) $user->id) { + throw new UploadOwnershipException('You do not own this upload.'); + } + + $role = strtolower((string) ($user->role ?? '')); + $isAdmin = $role === 'admin'; + + if (! $isAdmin && (string) ($upload->moderation_status ?? 'pending') !== 'approved') { + throw new UploadPublishValidationException('Upload requires moderation approval before publish.'); + } + + if ((string) $upload->status !== 'draft') { + throw new UploadPublishValidationException('Only draft uploads can be published.'); + } + + if (! (bool) $upload->is_scanned) { + throw new UploadPublishValidationException('Upload must be scanned before publish.'); + } + + if (empty($upload->preview_path)) { + throw new UploadPublishValidationException('Preview is required before publish.'); + } + + if (! (bool) $upload->has_tags) { + throw new UploadPublishValidationException('Tag analysis must complete before publish.'); + } + + if (empty($upload->title) || empty($upload->category_id)) { + throw new UploadPublishValidationException('Title and category are required before publish.'); + } + + if ((string) $upload->type === 'archive') { + $hasScreenshot = DB::table('upload_files') + ->where('upload_id', (string) $upload->id) + ->where('type', 'screenshot') + ->exists(); + + if (! $hasScreenshot) { + throw new UploadPublishValidationException('Archive uploads require at least one screenshot.'); + } + } + } +} diff --git a/app/Uploads/Services/SlugService.php b/app/Uploads/Services/SlugService.php new file mode 100644 index 00000000..dd67d875 --- /dev/null +++ b/app/Uploads/Services/SlugService.php @@ -0,0 +1,37 @@ +publishedSlugExists($candidate)) { + $candidate = $base . '-' . $suffix; + $suffix++; + } + + return $candidate; + } + + private function publishedSlugExists(string $slug): bool + { + return DB::table('uploads') + ->where('status', 'published') + ->where('slug', $slug) + ->exists(); + } +} diff --git a/bootstrap/app.php b/bootstrap/app.php index c3928c57..745f6899 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -12,7 +12,13 @@ return Application::configure(basePath: dirname(__DIR__)) health: '/up', ) ->withMiddleware(function (Middleware $middleware): void { - // + $middleware->web(append: [ + \App\Http\Middleware\HandleInertiaRequests::class, + ]); + + $middleware->alias([ + 'admin.moderation' => \App\Http\Middleware\EnsureAdminOrModerator::class, + ]); }) ->withExceptions(function (Exceptions $exceptions): void { // diff --git a/composer.json b/composer.json index c636a00b..be0ee1f0 100644 --- a/composer.json +++ b/composer.json @@ -10,6 +10,8 @@ "license": "MIT", "require": { "php": "^8.2", + "intervention/image": "^3.11", + "inertiajs/inertia-laravel": "^1.0", "laravel/framework": "^12.0", "laravel/tinker": "^2.10.1" }, diff --git a/composer.lock b/composer.lock index 128eeef4..67542c77 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "77e9cb13ddd5d3584f5743ca484b7d65", + "content-hash": "2c96d87d3df9f5da68d6593ba44cb150", "packages": [ { "name": "brick/math", - "version": "0.14.1", + "version": "0.14.8", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "f05858549e5f9d7bb45875a75583240a38a281d0" + "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/f05858549e5f9d7bb45875a75583240a38a281d0", - "reference": "f05858549e5f9d7bb45875a75583240a38a281d0", + "url": "https://api.github.com/repos/brick/math/zipball/63422359a44b7f06cae63c3b429b59e8efcc0629", + "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629", "shasum": "" }, "require": { @@ -56,7 +56,7 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.14.1" + "source": "https://github.com/brick/math/tree/0.14.8" }, "funding": [ { @@ -64,7 +64,7 @@ "type": "github" } ], - "time": "2025-11-24T14:40:29+00:00" + "time": "2026-02-10T14:33:43+00:00" }, { "name": "carbonphp/carbon-doctrine-types", @@ -1053,17 +1053,230 @@ "time": "2025-08-22T14:27:06+00:00" }, { - "name": "laravel/framework", - "version": "v12.49.0", + "name": "inertiajs/inertia-laravel", + "version": "v1.3.4", "source": { "type": "git", - "url": "https://github.com/laravel/framework.git", - "reference": "4bde4530545111d8bdd1de6f545fa8824039fcb5" + "url": "https://github.com/inertiajs/inertia-laravel.git", + "reference": "8d52a6753bead9b01a699d40bd142a72668c2a11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/4bde4530545111d8bdd1de6f545fa8824039fcb5", - "reference": "4bde4530545111d8bdd1de6f545fa8824039fcb5", + "url": "https://api.github.com/repos/inertiajs/inertia-laravel/zipball/8d52a6753bead9b01a699d40bd142a72668c2a11", + "reference": "8d52a6753bead9b01a699d40bd142a72668c2a11", + "shasum": "" + }, + "require": { + "ext-json": "*", + "laravel/framework": "^8.74|^9.0|^10.0|^11.0|^12.0", + "php": "^7.3|~8.0.0|~8.1.0|~8.2.0|~8.3.0|~8.4.0", + "symfony/console": "^5.3|^6.0|^7.0" + }, + "require-dev": { + "mockery/mockery": "^1.3.3", + "orchestra/testbench": "^6.45|^7.44|^8.25|^9.3|^10.0", + "phpunit/phpunit": "^8.0|^9.5.8|^10.4|^11.5" + }, + "suggest": { + "ext-pcntl": "Recommended when running the Inertia SSR server via the `inertia:start-ssr` artisan command." + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Inertia\\ServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "files": [ + "./helpers.php" + ], + "psr-4": { + "Inertia\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Reinink", + "email": "jonathan@reinink.ca", + "homepage": "https://reinink.ca" + } + ], + "description": "The Laravel adapter for Inertia.js.", + "keywords": [ + "inertia", + "laravel" + ], + "support": { + "issues": "https://github.com/inertiajs/inertia-laravel/issues", + "source": "https://github.com/inertiajs/inertia-laravel/tree/v1.3.4" + }, + "time": "2025-12-15T14:57:37+00:00" + }, + { + "name": "intervention/gif", + "version": "4.2.4", + "source": { + "type": "git", + "url": "https://github.com/Intervention/gif.git", + "reference": "c3598a16ebe7690cd55640c44144a9df383ea73c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Intervention/gif/zipball/c3598a16ebe7690cd55640c44144a9df383ea73c", + "reference": "c3598a16ebe7690cd55640c44144a9df383ea73c", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^10.0 || ^11.0 || ^12.0", + "slevomat/coding-standard": "~8.0", + "squizlabs/php_codesniffer": "^3.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Intervention\\Gif\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Oliver Vogel", + "email": "oliver@intervention.io", + "homepage": "https://intervention.io/" + } + ], + "description": "Native PHP GIF Encoder/Decoder", + "homepage": "https://github.com/intervention/gif", + "keywords": [ + "animation", + "gd", + "gif", + "image" + ], + "support": { + "issues": "https://github.com/Intervention/gif/issues", + "source": "https://github.com/Intervention/gif/tree/4.2.4" + }, + "funding": [ + { + "url": "https://paypal.me/interventionio", + "type": "custom" + }, + { + "url": "https://github.com/Intervention", + "type": "github" + }, + { + "url": "https://ko-fi.com/interventionphp", + "type": "ko_fi" + } + ], + "time": "2026-01-04T09:27:23+00:00" + }, + { + "name": "intervention/image", + "version": "3.11.6", + "source": { + "type": "git", + "url": "https://github.com/Intervention/image.git", + "reference": "5f6d27d9fd56312c47f347929e7ac15345c605a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Intervention/image/zipball/5f6d27d9fd56312c47f347929e7ac15345c605a1", + "reference": "5f6d27d9fd56312c47f347929e7ac15345c605a1", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "intervention/gif": "^4.2", + "php": "^8.1" + }, + "require-dev": { + "mockery/mockery": "^1.6", + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^10.0 || ^11.0 || ^12.0", + "slevomat/coding-standard": "~8.0", + "squizlabs/php_codesniffer": "^3.8" + }, + "suggest": { + "ext-exif": "Recommended to be able to read EXIF data properly." + }, + "type": "library", + "autoload": { + "psr-4": { + "Intervention\\Image\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Oliver Vogel", + "email": "oliver@intervention.io", + "homepage": "https://intervention.io" + } + ], + "description": "PHP Image Processing", + "homepage": "https://image.intervention.io", + "keywords": [ + "gd", + "image", + "imagick", + "resize", + "thumbnail", + "watermark" + ], + "support": { + "issues": "https://github.com/Intervention/image/issues", + "source": "https://github.com/Intervention/image/tree/3.11.6" + }, + "funding": [ + { + "url": "https://paypal.me/interventionio", + "type": "custom" + }, + { + "url": "https://github.com/Intervention", + "type": "github" + }, + { + "url": "https://ko-fi.com/interventionphp", + "type": "ko_fi" + } + ], + "time": "2025-12-17T13:38:29+00:00" + }, + { + "name": "laravel/framework", + "version": "v12.51.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/framework.git", + "reference": "ce4de3feb211e47c4f959d309ccf8a2733b1bc16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/framework/zipball/ce4de3feb211e47c4f959d309ccf8a2733b1bc16", + "reference": "ce4de3feb211e47c4f959d309ccf8a2733b1bc16", "shasum": "" }, "require": { @@ -1272,34 +1485,34 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2026-01-28T03:40:49+00:00" + "time": "2026-02-10T18:20:19+00:00" }, { "name": "laravel/prompts", - "version": "v0.3.11", + "version": "v0.3.13", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "dd2a2ed95acacbcccd32fd98dee4c946ae7a7217" + "reference": "ed8c466571b37e977532fb2fd3c272c784d7050d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/dd2a2ed95acacbcccd32fd98dee4c946ae7a7217", - "reference": "dd2a2ed95acacbcccd32fd98dee4c946ae7a7217", + "url": "https://api.github.com/repos/laravel/prompts/zipball/ed8c466571b37e977532fb2fd3c272c784d7050d", + "reference": "ed8c466571b37e977532fb2fd3c272c784d7050d", "shasum": "" }, "require": { "composer-runtime-api": "^2.2", "ext-mbstring": "*", "php": "^8.1", - "symfony/console": "^6.2|^7.0" + "symfony/console": "^6.2|^7.0|^8.0" }, "conflict": { "illuminate/console": ">=10.17.0 <10.25.0", "laravel/framework": ">=10.17.0 <10.25.0" }, "require-dev": { - "illuminate/collections": "^10.0|^11.0|^12.0", + "illuminate/collections": "^10.0|^11.0|^12.0|^13.0", "mockery/mockery": "^1.5", "pestphp/pest": "^2.3|^3.4|^4.0", "phpstan/phpstan": "^1.12.28", @@ -1329,33 +1542,33 @@ "description": "Add beautiful and user-friendly forms to your command-line applications.", "support": { "issues": "https://github.com/laravel/prompts/issues", - "source": "https://github.com/laravel/prompts/tree/v0.3.11" + "source": "https://github.com/laravel/prompts/tree/v0.3.13" }, - "time": "2026-01-27T02:55:06+00:00" + "time": "2026-02-06T12:17:10+00:00" }, { "name": "laravel/serializable-closure", - "version": "v2.0.8", + "version": "v2.0.9", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b" + "reference": "8f631589ab07b7b52fead814965f5a800459cb3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/7581a4407012f5f53365e11bafc520fd7f36bc9b", - "reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/8f631589ab07b7b52fead814965f5a800459cb3e", + "reference": "8f631589ab07b7b52fead814965f5a800459cb3e", "shasum": "" }, "require": { "php": "^8.1" }, "require-dev": { - "illuminate/support": "^10.0|^11.0|^12.0", + "illuminate/support": "^10.0|^11.0|^12.0|^13.0", "nesbot/carbon": "^2.67|^3.0", "pestphp/pest": "^2.36|^3.0|^4.0", "phpstan/phpstan": "^2.0", - "symfony/var-dumper": "^6.2.0|^7.0.0" + "symfony/var-dumper": "^6.2.0|^7.0.0|^8.0.0" }, "type": "library", "extra": { @@ -1392,20 +1605,20 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2026-01-08T16:22:46+00:00" + "time": "2026-02-03T06:55:34+00:00" }, { "name": "laravel/tinker", - "version": "v2.11.0", + "version": "v2.11.1", "source": { "type": "git", "url": "https://github.com/laravel/tinker.git", - "reference": "3d34b97c9a1747a81a3fde90482c092bd8b66468" + "reference": "c9f80cc835649b5c1842898fb043f8cc098dd741" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/tinker/zipball/3d34b97c9a1747a81a3fde90482c092bd8b66468", - "reference": "3d34b97c9a1747a81a3fde90482c092bd8b66468", + "url": "https://api.github.com/repos/laravel/tinker/zipball/c9f80cc835649b5c1842898fb043f8cc098dd741", + "reference": "c9f80cc835649b5c1842898fb043f8cc098dd741", "shasum": "" }, "require": { @@ -1456,9 +1669,9 @@ ], "support": { "issues": "https://github.com/laravel/tinker/issues", - "source": "https://github.com/laravel/tinker/tree/v2.11.0" + "source": "https://github.com/laravel/tinker/tree/v2.11.1" }, - "time": "2025-12-19T19:16:45+00:00" + "time": "2026-02-06T14:12:35+00:00" }, { "name": "league/commonmark", @@ -2124,16 +2337,16 @@ }, { "name": "nesbot/carbon", - "version": "3.11.0", + "version": "3.11.1", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "bdb375400dcd162624531666db4799b36b64e4a1" + "reference": "f438fcc98f92babee98381d399c65336f3a3827f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/bdb375400dcd162624531666db4799b36b64e4a1", - "reference": "bdb375400dcd162624531666db4799b36b64e4a1", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/f438fcc98f92babee98381d399c65336f3a3827f", + "reference": "f438fcc98f92babee98381d399c65336f3a3827f", "shasum": "" }, "require": { @@ -2157,7 +2370,7 @@ "phpstan/extension-installer": "^1.4.3", "phpstan/phpstan": "^2.1.22", "phpunit/phpunit": "^10.5.53", - "squizlabs/php_codesniffer": "^3.13.4" + "squizlabs/php_codesniffer": "^3.13.4 || ^4.0.0" }, "bin": [ "bin/carbon" @@ -2200,14 +2413,14 @@ } ], "description": "An API extension for DateTime that supports 281 different languages.", - "homepage": "https://carbon.nesbot.com", + "homepage": "https://carbonphp.github.io/carbon/", "keywords": [ "date", "datetime", "time" ], "support": { - "docs": "https://carbon.nesbot.com/docs", + "docs": "https://carbonphp.github.io/carbon/guide/getting-started/introduction.html", "issues": "https://github.com/CarbonPHP/carbon/issues", "source": "https://github.com/CarbonPHP/carbon" }, @@ -2225,20 +2438,20 @@ "type": "tidelift" } ], - "time": "2025-12-02T21:04:28+00:00" + "time": "2026-01-29T09:26:29+00:00" }, { "name": "nette/schema", - "version": "v1.3.3", + "version": "v1.3.4", "source": { "type": "git", "url": "https://github.com/nette/schema.git", - "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004" + "reference": "086497a2f34b82fede9b5a41cc8e131d087cd8f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/2befc2f42d7c715fd9d95efc31b1081e5d765004", - "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004", + "url": "https://api.github.com/repos/nette/schema/zipball/086497a2f34b82fede9b5a41cc8e131d087cd8f7", + "reference": "086497a2f34b82fede9b5a41cc8e131d087cd8f7", "shasum": "" }, "require": { @@ -2246,8 +2459,8 @@ "php": "8.1 - 8.5" }, "require-dev": { - "nette/tester": "^2.5.2", - "phpstan/phpstan-nette": "^2.0@stable", + "nette/tester": "^2.6", + "phpstan/phpstan": "^2.0@stable", "tracy/tracy": "^2.8" }, "type": "library", @@ -2288,22 +2501,22 @@ ], "support": { "issues": "https://github.com/nette/schema/issues", - "source": "https://github.com/nette/schema/tree/v1.3.3" + "source": "https://github.com/nette/schema/tree/v1.3.4" }, - "time": "2025-10-30T22:57:59+00:00" + "time": "2026-02-08T02:54:00+00:00" }, { "name": "nette/utils", - "version": "v4.1.1", + "version": "v4.1.2", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "c99059c0315591f1a0db7ad6002000288ab8dc72" + "reference": "f76b5dc3d6c6d3043c8d937df2698515b99cbaf5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/c99059c0315591f1a0db7ad6002000288ab8dc72", - "reference": "c99059c0315591f1a0db7ad6002000288ab8dc72", + "url": "https://api.github.com/repos/nette/utils/zipball/f76b5dc3d6c6d3043c8d937df2698515b99cbaf5", + "reference": "f76b5dc3d6c6d3043c8d937df2698515b99cbaf5", "shasum": "" }, "require": { @@ -2316,7 +2529,7 @@ "require-dev": { "jetbrains/phpstorm-attributes": "^1.2", "nette/tester": "^2.5", - "phpstan/phpstan-nette": "^2.0@stable", + "phpstan/phpstan": "^2.0@stable", "tracy/tracy": "^2.9" }, "suggest": { @@ -2377,9 +2590,9 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.1.1" + "source": "https://github.com/nette/utils/tree/v4.1.2" }, - "time": "2025-12-22T12:14:32+00:00" + "time": "2026-02-03T17:21:09+00:00" }, { "name": "nikic/php-parser", @@ -3015,16 +3228,16 @@ }, { "name": "psy/psysh", - "version": "v0.12.18", + "version": "v0.12.20", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "ddff0ac01beddc251786fe70367cd8bbdb258196" + "reference": "19678eb6b952a03b8a1d96ecee9edba518bb0373" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/ddff0ac01beddc251786fe70367cd8bbdb258196", - "reference": "ddff0ac01beddc251786fe70367cd8bbdb258196", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/19678eb6b952a03b8a1d96ecee9edba518bb0373", + "reference": "19678eb6b952a03b8a1d96ecee9edba518bb0373", "shasum": "" }, "require": { @@ -3088,9 +3301,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.12.18" + "source": "https://github.com/bobthecow/psysh/tree/v0.12.20" }, - "time": "2025-12-17T14:35:46+00:00" + "time": "2026-02-11T15:05:28+00:00" }, { "name": "ralouphie/getallheaders", @@ -5999,16 +6212,16 @@ "packages-dev": [ { "name": "brianium/paratest", - "version": "v7.16.1", + "version": "v7.17.0", "source": { "type": "git", "url": "https://github.com/paratestphp/paratest.git", - "reference": "f0fdfd8e654e0d38bc2ba756a6cabe7be287390b" + "reference": "53cb90a6aa3ef3840458781600628ade058a18b9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/f0fdfd8e654e0d38bc2ba756a6cabe7be287390b", - "reference": "f0fdfd8e654e0d38bc2ba756a6cabe7be287390b", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/53cb90a6aa3ef3840458781600628ade058a18b9", + "reference": "53cb90a6aa3ef3840458781600628ade058a18b9", "shasum": "" }, "require": { @@ -6022,7 +6235,7 @@ "phpunit/php-code-coverage": "^12.5.2", "phpunit/php-file-iterator": "^6", "phpunit/php-timer": "^8", - "phpunit/phpunit": "^12.5.4", + "phpunit/phpunit": "^12.5.8", "sebastian/environment": "^8.0.3", "symfony/console": "^7.3.4 || ^8.0.0", "symfony/process": "^7.3.4 || ^8.0.0" @@ -6032,10 +6245,10 @@ "ext-pcntl": "*", "ext-pcov": "*", "ext-posix": "*", - "phpstan/phpstan": "^2.1.33", + "phpstan/phpstan": "^2.1.38", "phpstan/phpstan-deprecation-rules": "^2.0.3", - "phpstan/phpstan-phpunit": "^2.0.11", - "phpstan/phpstan-strict-rules": "^2.0.7", + "phpstan/phpstan-phpunit": "^2.0.12", + "phpstan/phpstan-strict-rules": "^2.0.8", "symfony/filesystem": "^7.3.2 || ^8.0.0" }, "bin": [ @@ -6076,7 +6289,7 @@ ], "support": { "issues": "https://github.com/paratestphp/paratest/issues", - "source": "https://github.com/paratestphp/paratest/tree/v7.16.1" + "source": "https://github.com/paratestphp/paratest/tree/v7.17.0" }, "funding": [ { @@ -6088,33 +6301,33 @@ "type": "paypal" } ], - "time": "2026-01-08T07:23:06+00:00" + "time": "2026-02-05T09:14:44+00:00" }, { "name": "doctrine/deprecations", - "version": "1.1.5", + "version": "1.1.6", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "conflict": { - "phpunit/phpunit": "<=7.5 || >=13" + "phpunit/phpunit": "<=7.5 || >=14" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^12 || ^13", - "phpstan/phpstan": "1.4.10 || 2.1.11", + "doctrine/coding-standard": "^9 || ^12 || ^14", + "phpstan/phpstan": "1.4.10 || 2.1.30", "phpstan/phpstan-phpunit": "^1.0 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0", "psr/log": "^1 || ^2 || ^3" }, "suggest": { @@ -6134,9 +6347,9 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.5" + "source": "https://github.com/doctrine/deprecations/tree/1.1.6" }, - "time": "2025-04-07T20:06:18+00:00" + "time": "2026-02-07T07:09:04+00:00" }, { "name": "fakerphp/faker", @@ -6548,16 +6761,16 @@ }, { "name": "laravel/boost", - "version": "v2.0.4", + "version": "v2.1.2", "source": { "type": "git", "url": "https://github.com/laravel/boost.git", - "reference": "6f7a9f70c1b2cc5fcef1585e8aa04b8546f150e9" + "reference": "81ecf79e82c979efd92afaeac012605cc7b2f31f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/boost/zipball/6f7a9f70c1b2cc5fcef1585e8aa04b8546f150e9", - "reference": "6f7a9f70c1b2cc5fcef1585e8aa04b8546f150e9", + "url": "https://api.github.com/repos/laravel/boost/zipball/81ecf79e82c979efd92afaeac012605cc7b2f31f", + "reference": "81ecf79e82c979efd92afaeac012605cc7b2f31f", "shasum": "" }, "require": { @@ -6610,7 +6823,7 @@ "issues": "https://github.com/laravel/boost/issues", "source": "https://github.com/laravel/boost" }, - "time": "2026-01-28T13:53:50+00:00" + "time": "2026-02-10T17:40:45+00:00" }, { "name": "laravel/breeze", @@ -6675,35 +6888,35 @@ }, { "name": "laravel/mcp", - "version": "v0.5.3", + "version": "v0.5.6", "source": { "type": "git", "url": "https://github.com/laravel/mcp.git", - "reference": "39b9791b989927642137dd5b55dde0529f1614f9" + "reference": "87905978bf2a230d6c01f8d03e172249e37917f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/mcp/zipball/39b9791b989927642137dd5b55dde0529f1614f9", - "reference": "39b9791b989927642137dd5b55dde0529f1614f9", + "url": "https://api.github.com/repos/laravel/mcp/zipball/87905978bf2a230d6c01f8d03e172249e37917f7", + "reference": "87905978bf2a230d6c01f8d03e172249e37917f7", "shasum": "" }, "require": { "ext-json": "*", "ext-mbstring": "*", - "illuminate/console": "^10.49.0|^11.45.3|^12.41.1", - "illuminate/container": "^10.49.0|^11.45.3|^12.41.1", - "illuminate/contracts": "^10.49.0|^11.45.3|^12.41.1", - "illuminate/http": "^10.49.0|^11.45.3|^12.41.1", - "illuminate/json-schema": "^12.41.1", - "illuminate/routing": "^10.49.0|^11.45.3|^12.41.1", - "illuminate/support": "^10.49.0|^11.45.3|^12.41.1", - "illuminate/validation": "^10.49.0|^11.45.3|^12.41.1", - "php": "^8.1" + "illuminate/console": "^11.45.3|^12.41.1|^13.0", + "illuminate/container": "^11.45.3|^12.41.1|^13.0", + "illuminate/contracts": "^11.45.3|^12.41.1|^13.0", + "illuminate/http": "^11.45.3|^12.41.1|^13.0", + "illuminate/json-schema": "^12.41.1|^13.0", + "illuminate/routing": "^11.45.3|^12.41.1|^13.0", + "illuminate/support": "^11.45.3|^12.41.1|^13.0", + "illuminate/validation": "^11.45.3|^12.41.1|^13.0", + "php": "^8.2" }, "require-dev": { "laravel/pint": "^1.20", - "orchestra/testbench": "^8.36|^9.15|^10.8", - "pestphp/pest": "^2.36.0|^3.8.4|^4.1.0", + "orchestra/testbench": "^9.15|^10.8|^11.0", + "pestphp/pest": "^3.8.5|^4.3.2", "phpstan/phpstan": "^2.1.27", "rector/rector": "^2.2.4" }, @@ -6744,41 +6957,42 @@ "issues": "https://github.com/laravel/mcp/issues", "source": "https://github.com/laravel/mcp" }, - "time": "2026-01-26T10:25:21+00:00" + "time": "2026-02-09T22:08:43+00:00" }, { "name": "laravel/pail", - "version": "v1.2.4", + "version": "v1.2.6", "source": { "type": "git", "url": "https://github.com/laravel/pail.git", - "reference": "49f92285ff5d6fc09816e976a004f8dec6a0ea30" + "reference": "aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pail/zipball/49f92285ff5d6fc09816e976a004f8dec6a0ea30", - "reference": "49f92285ff5d6fc09816e976a004f8dec6a0ea30", + "url": "https://api.github.com/repos/laravel/pail/zipball/aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf", + "reference": "aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf", "shasum": "" }, "require": { "ext-mbstring": "*", - "illuminate/console": "^10.24|^11.0|^12.0", - "illuminate/contracts": "^10.24|^11.0|^12.0", - "illuminate/log": "^10.24|^11.0|^12.0", - "illuminate/process": "^10.24|^11.0|^12.0", - "illuminate/support": "^10.24|^11.0|^12.0", + "illuminate/console": "^10.24|^11.0|^12.0|^13.0", + "illuminate/contracts": "^10.24|^11.0|^12.0|^13.0", + "illuminate/log": "^10.24|^11.0|^12.0|^13.0", + "illuminate/process": "^10.24|^11.0|^12.0|^13.0", + "illuminate/support": "^10.24|^11.0|^12.0|^13.0", "nunomaduro/termwind": "^1.15|^2.0", "php": "^8.2", - "symfony/console": "^6.0|^7.0" + "symfony/console": "^6.0|^7.0|^8.0" }, "require-dev": { - "laravel/framework": "^10.24|^11.0|^12.0", + "laravel/framework": "^10.24|^11.0|^12.0|^13.0", "laravel/pint": "^1.13", - "orchestra/testbench-core": "^8.13|^9.17|^10.8", + "orchestra/testbench-core": "^8.13|^9.17|^10.8|^11.0", "pestphp/pest": "^2.20|^3.0|^4.0", "pestphp/pest-plugin-type-coverage": "^2.3|^3.0|^4.0", "phpstan/phpstan": "^1.12.27", - "symfony/var-dumper": "^6.3|^7.0" + "symfony/var-dumper": "^6.3|^7.0|^8.0", + "symfony/yaml": "^6.3|^7.0|^8.0" }, "type": "library", "extra": { @@ -6823,20 +7037,20 @@ "issues": "https://github.com/laravel/pail/issues", "source": "https://github.com/laravel/pail" }, - "time": "2025-11-20T16:29:35+00:00" + "time": "2026-02-09T13:44:54+00:00" }, { "name": "laravel/pint", - "version": "v1.27.0", + "version": "v1.27.1", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "c67b4195b75491e4dfc6b00b1c78b68d86f54c90" + "reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/c67b4195b75491e4dfc6b00b1c78b68d86f54c90", - "reference": "c67b4195b75491e4dfc6b00b1c78b68d86f54c90", + "url": "https://api.github.com/repos/laravel/pint/zipball/54cca2de13790570c7b6f0f94f37896bee4abcb5", + "reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5", "shasum": "" }, "require": { @@ -6847,13 +7061,13 @@ "php": "^8.2.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.92.4", - "illuminate/view": "^12.44.0", - "larastan/larastan": "^3.8.1", - "laravel-zero/framework": "^12.0.4", + "friendsofphp/php-cs-fixer": "^3.93.1", + "illuminate/view": "^12.51.0", + "larastan/larastan": "^3.9.2", + "laravel-zero/framework": "^12.0.5", "mockery/mockery": "^1.6.12", "nunomaduro/termwind": "^2.3.3", - "pestphp/pest": "^3.8.4" + "pestphp/pest": "^3.8.5" }, "bin": [ "builds/pint" @@ -6890,7 +7104,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2026-01-05T16:49:17+00:00" + "time": "2026-02-10T20:00:20+00:00" }, { "name": "laravel/roster", @@ -6955,28 +7169,28 @@ }, { "name": "laravel/sail", - "version": "v1.52.0", + "version": "v1.53.0", "source": { "type": "git", "url": "https://github.com/laravel/sail.git", - "reference": "64ac7d8abb2dbcf2b76e61289451bae79066b0b3" + "reference": "e340eaa2bea9b99192570c48ed837155dbf24fbb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sail/zipball/64ac7d8abb2dbcf2b76e61289451bae79066b0b3", - "reference": "64ac7d8abb2dbcf2b76e61289451bae79066b0b3", + "url": "https://api.github.com/repos/laravel/sail/zipball/e340eaa2bea9b99192570c48ed837155dbf24fbb", + "reference": "e340eaa2bea9b99192570c48ed837155dbf24fbb", "shasum": "" }, "require": { - "illuminate/console": "^9.52.16|^10.0|^11.0|^12.0", - "illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0", - "illuminate/support": "^9.52.16|^10.0|^11.0|^12.0", + "illuminate/console": "^9.52.16|^10.0|^11.0|^12.0|^13.0", + "illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0|^13.0", + "illuminate/support": "^9.52.16|^10.0|^11.0|^12.0|^13.0", "php": "^8.0", - "symfony/console": "^6.0|^7.0", - "symfony/yaml": "^6.0|^7.0" + "symfony/console": "^6.0|^7.0|^8.0", + "symfony/yaml": "^6.0|^7.0|^8.0" }, "require-dev": { - "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", + "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0|^11.0", "phpstan/phpstan": "^2.0" }, "bin": [ @@ -7014,7 +7228,7 @@ "issues": "https://github.com/laravel/sail/issues", "source": "https://github.com/laravel/sail" }, - "time": "2026-01-01T02:46:03+00:00" + "time": "2026-02-06T12:16:02+00:00" }, { "name": "mockery/mockery", @@ -8230,16 +8444,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "12.5.2", + "version": "12.5.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "4a9739b51cbcb355f6e95659612f92e282a7077b" + "reference": "b015312f28dd75b75d3422ca37dff2cd1a565e8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4a9739b51cbcb355f6e95659612f92e282a7077b", - "reference": "4a9739b51cbcb355f6e95659612f92e282a7077b", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b015312f28dd75b75d3422ca37dff2cd1a565e8d", + "reference": "b015312f28dd75b75d3422ca37dff2cd1a565e8d", "shasum": "" }, "require": { @@ -8295,7 +8509,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.5.2" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.5.3" }, "funding": [ { @@ -8315,20 +8529,20 @@ "type": "tidelift" } ], - "time": "2025-12-24T07:03:04+00:00" + "time": "2026-02-06T06:01:44+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "6.0.0", + "version": "6.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "961bc913d42fe24a257bfff826a5068079ac7782" + "reference": "3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/961bc913d42fe24a257bfff826a5068079ac7782", - "reference": "961bc913d42fe24a257bfff826a5068079ac7782", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5", + "reference": "3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5", "shasum": "" }, "require": { @@ -8368,15 +8582,27 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.0" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator", + "type": "tidelift" } ], - "time": "2025-02-07T04:58:37+00:00" + "time": "2026-02-02T14:04:18+00:00" }, { "name": "phpunit/php-invoker", @@ -9694,24 +9920,24 @@ }, { "name": "ta-tikoma/phpunit-architecture-test", - "version": "0.8.5", + "version": "0.8.6", "source": { "type": "git", "url": "https://github.com/ta-tikoma/phpunit-architecture-test.git", - "reference": "cf6fb197b676ba716837c886baca842e4db29005" + "reference": "ad48430b92901fd7d003fdaf2d7b139f96c0906e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/cf6fb197b676ba716837c886baca842e4db29005", - "reference": "cf6fb197b676ba716837c886baca842e4db29005", + "url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/ad48430b92901fd7d003fdaf2d7b139f96c0906e", + "reference": "ad48430b92901fd7d003fdaf2d7b139f96c0906e", "shasum": "" }, "require": { "nikic/php-parser": "^4.18.0 || ^5.0.0", "php": "^8.1.0", - "phpdocumentor/reflection-docblock": "^5.3.0", - "phpunit/phpunit": "^10.5.5 || ^11.0.0 || ^12.0.0", - "symfony/finder": "^6.4.0 || ^7.0.0" + "phpdocumentor/reflection-docblock": "^5.3.0 || ^6.0.0", + "phpunit/phpunit": "^10.5.5 || ^11.0.0 || ^12.0.0", + "symfony/finder": "^6.4.0 || ^7.0.0 || ^8.0.0" }, "require-dev": { "laravel/pint": "^1.13.7", @@ -9747,9 +9973,9 @@ ], "support": { "issues": "https://github.com/ta-tikoma/phpunit-architecture-test/issues", - "source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.8.5" + "source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.8.6" }, - "time": "2025-04-20T20:23:40+00:00" + "time": "2026-01-30T07:16:00+00:00" }, { "name": "theseer/tokenizer", diff --git a/config/cdn.php b/config/cdn.php new file mode 100644 index 00000000..b1b1cd0c --- /dev/null +++ b/config/cdn.php @@ -0,0 +1,7 @@ + env('FILES_CDN_URL', 'https://files.skinbase.org'), +]; diff --git a/config/discovery.php b/config/discovery.php new file mode 100644 index 00000000..4179272e --- /dev/null +++ b/config/discovery.php @@ -0,0 +1,108 @@ + env('DISCOVERY_QUEUE', env('RECOMMENDATIONS_QUEUE', env('VISION_QUEUE', 'default'))), + + // Versioned from day one for safe future migrations/experiments. + 'profile_version' => env('DISCOVERY_PROFILE_VERSION', 'profile-v1'), + 'event_version' => env('DISCOVERY_EVENT_VERSION', 'event-v1'), + 'algo_version' => env('DISCOVERY_ALGO_VERSION', env('RECOMMENDATIONS_ALGO_VERSION', 'clip-cosine-v1')), + 'cache_version' => env('DISCOVERY_CACHE_VERSION', 'cache-v1'), + + 'decay' => [ + // Exponential half-life: score * 0.5 every N hours. + 'half_life_hours' => (float) env('DISCOVERY_DECAY_HALF_LIFE_HOURS', 72), + ], + + // Baseline event contribution weights. + 'weights' => [ + 'view' => (float) env('DISCOVERY_WEIGHT_VIEW', 1.0), + 'click' => (float) env('DISCOVERY_WEIGHT_CLICK', 2.0), + 'favorite' => (float) env('DISCOVERY_WEIGHT_FAVORITE', 4.0), + 'download' => (float) env('DISCOVERY_WEIGHT_DOWNLOAD', 3.0), + ], + + // Recommendation cache TTL in minutes (schema foundation only for now). + 'cache_ttl_minutes' => (int) env('DISCOVERY_CACHE_TTL_MINUTES', 60), + + // Phase 8B: versioned ranking blend weights. + // Blend components: w1=interest, w2=recency, w3=popularity, w4=novelty. + 'ranking' => [ + 'default_weights' => [ + 'version' => env('DISCOVERY_RANKING_WEIGHTS_VERSION', 'rank-w-v1'), + 'w1' => (float) env('DISCOVERY_RANKING_W1', 0.65), + 'w2' => (float) env('DISCOVERY_RANKING_W2', 0.20), + 'w3' => (float) env('DISCOVERY_RANKING_W3', 0.10), + 'w4' => (float) env('DISCOVERY_RANKING_W4', 0.05), + ], + + // Per-algo overrides for safe rollout by algo_version. + 'algo_weight_sets' => [ + 'clip-cosine-v1' => [ + 'version' => env('DISCOVERY_RANKING_WEIGHTS_VERSION_CLIP_COSINE_V1', 'rank-w-v1'), + 'w1' => (float) env('DISCOVERY_RANKING_W1_CLIP_COSINE_V1', 0.65), + 'w2' => (float) env('DISCOVERY_RANKING_W2_CLIP_COSINE_V1', 0.20), + 'w3' => (float) env('DISCOVERY_RANKING_W3_CLIP_COSINE_V1', 0.10), + 'w4' => (float) env('DISCOVERY_RANKING_W4_CLIP_COSINE_V1', 0.05), + ], + 'clip-cosine-v2' => [ + 'version' => env('DISCOVERY_RANKING_WEIGHTS_VERSION_CLIP_COSINE_V2', 'rank-w-v2-prod-1'), + 'w1' => (float) env('DISCOVERY_RANKING_W1_CLIP_COSINE_V2', 0.52), + 'w2' => (float) env('DISCOVERY_RANKING_W2_CLIP_COSINE_V2', 0.23), + 'w3' => (float) env('DISCOVERY_RANKING_W3_CLIP_COSINE_V2', 0.15), + 'w4' => (float) env('DISCOVERY_RANKING_W4_CLIP_COSINE_V2', 0.10), + ], + ], + ], + + // Phase 8 production rollout gates (deterministic user bucketing). + 'rollout' => [ + 'enabled' => (bool) env('DISCOVERY_ROLLOUT_ENABLED', false), + 'baseline_algo_version' => env('DISCOVERY_ROLLOUT_BASELINE_ALGO_VERSION', 'clip-cosine-v1'), + 'candidate_algo_version' => env('DISCOVERY_ROLLOUT_CANDIDATE_ALGO_VERSION', 'clip-cosine-v2'), + + // One of: g10, g50, g100. + 'active_gate' => env('DISCOVERY_ROLLOUT_ACTIVE_GATE', 'g10'), + 'gates' => [ + 'g10' => [ + 'name' => '10%', + 'percentage' => (int) env('DISCOVERY_ROLLOUT_GATE_10_PERCENT', 10), + ], + 'g50' => [ + 'name' => '50%', + 'percentage' => (int) env('DISCOVERY_ROLLOUT_GATE_50_PERCENT', 50), + ], + 'g100' => [ + 'name' => '100%', + 'percentage' => (int) env('DISCOVERY_ROLLOUT_GATE_100_PERCENT', 100), + ], + ], + + // Emergency rollback toggle: force all traffic to one algo_version. + 'force_algo_version' => env('DISCOVERY_FORCE_ALGO_VERSION', ''), + + // Guardrails (used operationally in runbook and dashboards). + 'monitoring_thresholds' => [ + 'ctr_warn_drop_pct' => (float) env('DISCOVERY_ROLLOUT_WARN_CTR_DROP_PCT', 3.0), + 'ctr_rollback_drop_pct' => (float) env('DISCOVERY_ROLLOUT_ROLLBACK_CTR_DROP_PCT', 5.0), + 'long_dwell_warn_drop_pct' => (float) env('DISCOVERY_ROLLOUT_WARN_LONG_DWELL_DROP_PCT', 4.0), + 'long_dwell_rollback_drop_pct' => (float) env('DISCOVERY_ROLLOUT_ROLLBACK_LONG_DWELL_DROP_PCT', 8.0), + 'diversity_warn_concentration_rise_pct' => (float) env('DISCOVERY_ROLLOUT_WARN_DIVERSITY_CONCENTRATION_RISE_PCT', 10.0), + 'diversity_rollback_concentration_rise_pct' => (float) env('DISCOVERY_ROLLOUT_ROLLBACK_DIVERSITY_CONCENTRATION_RISE_PCT', 15.0), + ], + ], + + // Offline evaluation objective weights (manual/data-driven tuning). + 'evaluation' => [ + 'objective_weights' => [ + 'ctr' => (float) env('DISCOVERY_EVAL_WEIGHT_CTR', 0.45), + 'save_rate' => (float) env('DISCOVERY_EVAL_WEIGHT_SAVE_RATE', 0.35), + 'long_dwell_share' => (float) env('DISCOVERY_EVAL_WEIGHT_LONG_DWELL', 0.25), + 'bounce_rate_penalty' => (float) env('DISCOVERY_EVAL_WEIGHT_BOUNCE_PENALTY', 0.15), + ], + // Temporary switch: keep save_rate visible but exclude it from objective score. + 'save_rate_informational' => (bool) env('DISCOVERY_EVAL_SAVE_RATE_INFORMATIONAL', true), + ], +]; diff --git a/config/features.php b/config/features.php new file mode 100644 index 00000000..103810c7 --- /dev/null +++ b/config/features.php @@ -0,0 +1,5 @@ + (bool) env('SKINBASE_UPLOADS_V2', true), +]; diff --git a/config/recommendations.php b/config/recommendations.php new file mode 100644 index 00000000..0480d084 --- /dev/null +++ b/config/recommendations.php @@ -0,0 +1,37 @@ + env('RECOMMENDATIONS_QUEUE', env('VISION_QUEUE', 'default')), + + 'embedding' => [ + 'enabled' => env('RECOMMENDATIONS_EMBEDDING_ENABLED', true), + 'model' => env('RECOMMENDATIONS_EMBEDDING_MODEL', 'clip'), + 'model_version' => env('RECOMMENDATIONS_EMBEDDING_MODEL_VERSION', 'v1'), + 'algo_version' => env('RECOMMENDATIONS_ALGO_VERSION', 'clip-cosine-v1'), + + // Preferred CLIP endpoint for embeddings. The service also accepts an embedding payload from the analyze endpoint response. + 'endpoint' => env('CLIP_EMBED_ENDPOINT', '/embed'), + 'timeout_seconds' => (int) env('CLIP_EMBED_TIMEOUT_SECONDS', 8), + 'connect_timeout_seconds' => (int) env('CLIP_EMBED_CONNECT_TIMEOUT_SECONDS', 2), + 'retries' => (int) env('CLIP_EMBED_HTTP_RETRIES', 1), + 'retry_delay_ms' => (int) env('CLIP_EMBED_HTTP_RETRY_DELAY_MS', 200), + + // Guardrails for malformed service responses. + 'min_dim' => (int) env('RECOMMENDATIONS_MIN_DIM', 64), + 'max_dim' => (int) env('RECOMMENDATIONS_MAX_DIM', 4096), + ], + + // Backfill chunk size for resumable queue fan-out. + 'backfill_batch_size' => (int) env('RECOMMENDATIONS_BACKFILL_BATCH', 200), + + // A/B support for recommendation ranking variants. + 'ab' => [ + 'algo_versions' => array_values(array_filter(array_map( + static fn (string $value): string => trim($value), + explode(',', (string) env('RECOMMENDATIONS_AB_ALGO_VERSIONS', env('RECOMMENDATIONS_ALGO_VERSION', 'clip-cosine-v1'))) + ))), + ], +]; diff --git a/config/services.php b/config/services.php index 6a90eb83..ca8621bd 100644 --- a/config/services.php +++ b/config/services.php @@ -35,4 +35,8 @@ return [ ], ], + 'image' => [ + 'driver' => env('IMAGE_DRIVER', 'gd'), + ], + ]; diff --git a/config/tags.php b/config/tags.php new file mode 100644 index 00000000..6c15ce58 --- /dev/null +++ b/config/tags.php @@ -0,0 +1,28 @@ + 32, + 'max_user_tags' => 15, + + // Exact-match banned tags after normalization. + 'banned' => [ + // e.g. 'nsfw', 'hate', 'spam' + ], + + // Optional regex patterns (PCRE) to block tags. + 'banned_regex' => [ + // e.g. '/\\b(?:badword1|badword2)\\b/i' + ], +]; diff --git a/config/uploads.php b/config/uploads.php new file mode 100644 index 00000000..18516f9a --- /dev/null +++ b/config/uploads.php @@ -0,0 +1,81 @@ + env('SKINBASE_STORAGE_ROOT', storage_path('app/artworks')), + + 'paths' => [ + 'tmp' => 'tmp', + 'quarantine' => 'quarantine', + 'originals' => 'originals', + 'public' => 'public', + ], + + 'public_img_prefix' => 'img', + + 'max_size_mb' => 50, + 'max_pixels' => 12000, + + 'allowed_mimes' => [ + 'image/jpeg', + 'image/png', + 'image/webp', + ], + + 'allow_gif' => env('UPLOAD_ALLOW_GIF', false), + + 'derivatives' => [ + 'thumb' => ['max' => 320], + 'sq' => ['size' => 512], + 'md' => ['max' => 1024], + 'lg' => ['max' => 1920], + 'xl' => ['max' => 2560], + ], + + 'quality' => 85, + + 'queue_derivatives' => env('UPLOAD_QUEUE_DERIVATIVES', false), + + 'rate_limits' => [ + 'decay_minutes' => env('UPLOAD_RATE_DECAY_MINUTES', 1), + 'init' => [ + 'per_user' => env('UPLOAD_RATE_INIT_USER', 10), + 'per_ip' => env('UPLOAD_RATE_INIT_IP', 30), + ], + 'finish' => [ + 'per_user' => env('UPLOAD_RATE_FINISH_USER', 6), + 'per_ip' => env('UPLOAD_RATE_FINISH_IP', 12), + ], + 'status' => [ + 'per_user' => env('UPLOAD_RATE_STATUS_USER', 60), + 'per_ip' => env('UPLOAD_RATE_STATUS_IP', 120), + ], + ], + + 'quotas' => [ + 'max_active_sessions' => env('UPLOAD_MAX_ACTIVE_SESSIONS', 100), + 'max_daily_sessions' => env('UPLOAD_MAX_DAILY_SESSIONS', 250), + ], + + 'draft_quota' => [ + 'max_drafts_per_user' => env('SKINBASE_MAX_DRAFTS', 10), + 'max_draft_storage_mb_per_user' => env('SKINBASE_MAX_DRAFT_STORAGE_MB', 1024), + 'duplicate_hash_policy' => env('SKINBASE_DUPLICATE_HASH_POLICY', 'block'), // block|warn + ], + + 'tokens' => [ + 'ttl_minutes' => env('UPLOAD_TOKEN_TTL_MINUTES', 60), + ], + + 'chunk' => [ + 'max_bytes' => env('UPLOAD_CHUNK_MAX_BYTES', 5242880), + 'lock_seconds' => env('UPLOAD_CHUNK_LOCK_SECONDS', 10), + 'lock_wait_seconds' => env('UPLOAD_CHUNK_LOCK_WAIT_SECONDS', 5), + ], + + 'scan' => [ + 'enabled' => env('UPLOAD_SCAN_ENABLED', false), + 'command' => env('UPLOAD_SCAN_COMMAND', []), + ], +]; diff --git a/config/vision.php b/config/vision.php new file mode 100644 index 00000000..96d8c4e6 --- /dev/null +++ b/config/vision.php @@ -0,0 +1,34 @@ + env('VISION_ENABLED', true), + + 'queue' => env('VISION_QUEUE', 'default'), + + 'clip' => [ + 'base_url' => env('CLIP_BASE_URL', ''), + 'endpoint' => env('CLIP_ANALYZE_ENDPOINT', '/analyze'), + 'timeout_seconds' => (int) env('CLIP_TIMEOUT_SECONDS', 8), + 'connect_timeout_seconds' => (int) env('CLIP_CONNECT_TIMEOUT_SECONDS', 2), + 'retries' => (int) env('CLIP_HTTP_RETRIES', 1), + 'retry_delay_ms' => (int) env('CLIP_HTTP_RETRY_DELAY_MS', 200), + ], + + 'yolo' => [ + 'enabled' => env('YOLO_ENABLED', true), + 'base_url' => env('YOLO_BASE_URL', ''), + 'endpoint' => env('YOLO_ANALYZE_ENDPOINT', '/analyze'), + 'timeout_seconds' => (int) env('YOLO_TIMEOUT_SECONDS', 8), + 'connect_timeout_seconds' => (int) env('YOLO_CONNECT_TIMEOUT_SECONDS', 2), + 'retries' => (int) env('YOLO_HTTP_RETRIES', 1), + 'retry_delay_ms' => (int) env('YOLO_HTTP_RETRY_DELAY_MS', 200), + + // Only run YOLO for photography content type. + 'photography_only' => env('YOLO_PHOTOGRAPHY_ONLY', true), + ], + + // Which derivative variant to send to vision services. + 'image_variant' => env('VISION_IMAGE_VARIANT', 'md'), +]; diff --git a/database/migrations/2026_02_08_000000_update_user_profiles_avatars.php b/database/migrations/2026_02_08_000000_update_user_profiles_avatars.php new file mode 100644 index 00000000..7df4d53d --- /dev/null +++ b/database/migrations/2026_02_08_000000_update_user_profiles_avatars.php @@ -0,0 +1,77 @@ +char('avatar_hash', 40)->nullable(); + } + if (!Schema::hasColumn('user_profiles', 'avatar_updated_at')) { + $table->dateTime('avatar_updated_at')->nullable(); + } + if (!Schema::hasColumn('user_profiles', 'avatar_mime')) { + $table->string('avatar_mime', 50)->nullable(); + } + }); + + // Attempt to rename legacy `avatar` column to `avatar_legacy` if it exists + if (Schema::hasColumn('user_profiles', 'avatar') && !Schema::hasColumn('user_profiles', 'avatar_legacy')) { + // Use DB statement to avoid requiring doctrine/dbal at runtime + try { + DB::statement('ALTER TABLE user_profiles CHANGE COLUMN `avatar` `avatar_legacy` VARCHAR(255) NULL'); + } catch (\Exception $e) { + // If the rename fails, we'll leave the legacy column as-is; migrations shouldn't break. + } + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + if (!Schema::hasTable('user_profiles')) { + return; + } + + Schema::table('user_profiles', function (Blueprint $table) { + if (Schema::hasColumn('user_profiles', 'avatar_hash')) { + $table->dropColumn('avatar_hash'); + } + if (Schema::hasColumn('user_profiles', 'avatar_updated_at')) { + $table->dropColumn('avatar_updated_at'); + } + if (Schema::hasColumn('user_profiles', 'avatar_mime')) { + $table->dropColumn('avatar_mime'); + } + }); + + // Attempt to rename back avatar_legacy to avatar + if (Schema::hasColumn('user_profiles', 'avatar_legacy') && !Schema::hasColumn('user_profiles', 'avatar')) { + try { + DB::statement('ALTER TABLE user_profiles CHANGE COLUMN `avatar_legacy` `avatar` VARCHAR(255) NULL'); + } catch (\Exception $e) { + } + } + } +} diff --git a/database/migrations/2026_02_08_000001_update_user_profiles_about_signature_description.php b/database/migrations/2026_02_08_000001_update_user_profiles_about_signature_description.php new file mode 100644 index 00000000..cef68fc7 --- /dev/null +++ b/database/migrations/2026_02_08_000001_update_user_profiles_about_signature_description.php @@ -0,0 +1,54 @@ +text('about')->nullable()->after('bio'); + } + if (! Schema::hasColumn('user_profiles', 'signature')) { + $table->text('signature')->nullable()->after('about'); + } + if (! Schema::hasColumn('user_profiles', 'description')) { + $table->text('description')->nullable()->after('signature'); + } + }); + + // Copy existing `bio` data into `about` (safe no-op if bio missing) + try { + if (Schema::hasColumn('user_profiles', 'bio') && Schema::hasColumn('user_profiles', 'about')) { + DB::statement('UPDATE `user_profiles` SET `about` = `bio` WHERE `about` IS NULL OR `about` = ""'); + } + } catch (\Throwable $e) { + // ignore copy errors + } + } + + public function down(): void + { + if (! Schema::hasTable('user_profiles')) { + return; + } + + Schema::table('user_profiles', function (Blueprint $table) { + if (Schema::hasColumn('user_profiles', 'description')) { + $table->dropColumn('description'); + } + if (Schema::hasColumn('user_profiles', 'signature')) { + $table->dropColumn('signature'); + } + // keep `about` on down migration to avoid data loss; do not drop it automatically + }); + } +}; diff --git a/database/migrations/2026_02_08_000002_enhance_user_profiles_metadata.php b/database/migrations/2026_02_08_000002_enhance_user_profiles_metadata.php new file mode 100644 index 00000000..aabdbc72 --- /dev/null +++ b/database/migrations/2026_02_08_000002_enhance_user_profiles_metadata.php @@ -0,0 +1,74 @@ +string('avatar_hash', 64)->nullable()->after('avatar'); + } + if (! Schema::hasColumn('user_profiles', 'avatar_mime')) { + $table->string('avatar_mime', 80)->nullable()->after('avatar_hash'); + } + if (! Schema::hasColumn('user_profiles', 'avatar_updated_at')) { + $table->timestamp('avatar_updated_at')->nullable()->after('avatar_mime'); + } + }); + + // Ensure `user_id` is indexed/unique and add a FK to `users(id)` when possible + try { + // Add unique index on user_id if it doesn't exist + DB::statement('ALTER TABLE `user_profiles` ADD UNIQUE INDEX `user_profiles_user_id_unique` (`user_id`)'); + } catch (\Throwable $e) { + // ignore if index exists or operation unsupported + } + + try { + // Add foreign key constraint to users.id if not present + DB::statement('ALTER TABLE `user_profiles` ADD CONSTRAINT `user_profiles_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE'); + } catch (\Throwable $e) { + // ignore if users table missing or constraint already present + } + } + + public function down(): void + { + if (! Schema::hasTable('user_profiles')) { + return; + } + + Schema::table('user_profiles', function (Blueprint $table) { + if (Schema::hasColumn('user_profiles', 'avatar_updated_at')) { + $table->dropColumn('avatar_updated_at'); + } + if (Schema::hasColumn('user_profiles', 'avatar_mime')) { + $table->dropColumn('avatar_mime'); + } + if (Schema::hasColumn('user_profiles', 'avatar_hash')) { + $table->dropColumn('avatar_hash'); + } + }); + + try { + DB::statement('ALTER TABLE `user_profiles` DROP FOREIGN KEY `user_profiles_user_id_foreign`'); + } catch (\Throwable $e) { + // ignore + } + + try { + DB::statement('ALTER TABLE `user_profiles` DROP INDEX `user_profiles_user_id_unique`'); + } catch (\Throwable $e) { + // ignore + } + } +}; diff --git a/database/migrations/2026_02_11_000001_create_uploads_sessions_table.php b/database/migrations/2026_02_11_000001_create_uploads_sessions_table.php new file mode 100644 index 00000000..e1b42a4d --- /dev/null +++ b/database/migrations/2026_02_11_000001_create_uploads_sessions_table.php @@ -0,0 +1,26 @@ +uuid('id')->primary(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->string('temp_path'); + $table->string('status', 32)->index(); + $table->string('ip', 64); + $table->timestamp('created_at')->useCurrent(); + + $table->index(['user_id', 'created_at'], 'idx_uploads_sessions_user_created'); + }); + } + + public function down(): void + { + Schema::dropIfExists('uploads_sessions'); + } +}; diff --git a/database/migrations/2026_02_11_000002_create_audit_logs_table.php b/database/migrations/2026_02_11_000002_create_audit_logs_table.php new file mode 100644 index 00000000..3770dc54 --- /dev/null +++ b/database/migrations/2026_02_11_000002_create_audit_logs_table.php @@ -0,0 +1,26 @@ +id(); + $table->foreignId('user_id')->nullable()->constrained()->nullOnDelete(); + $table->string('action', 64)->index(); + $table->string('ip', 64); + $table->json('meta')->nullable(); + $table->timestamp('created_at')->useCurrent(); + + $table->index(['user_id', 'created_at'], 'idx_audit_logs_user_created'); + }); + } + + public function down(): void + { + Schema::dropIfExists('audit_logs'); + } +}; diff --git a/database/migrations/2026_02_11_000003_create_artwork_files_table.php b/database/migrations/2026_02_11_000003_create_artwork_files_table.php new file mode 100644 index 00000000..4318fac3 --- /dev/null +++ b/database/migrations/2026_02_11_000003_create_artwork_files_table.php @@ -0,0 +1,27 @@ +unsignedBigInteger('artwork_id'); + $table->string('variant', 16); + $table->string('path'); + $table->string('mime', 64); + $table->unsignedBigInteger('size'); + + $table->primary(['artwork_id', 'variant']); + $table->index('variant'); + $table->foreign('artwork_id')->references('id')->on('artworks')->cascadeOnDelete(); + }); + } + + public function down(): void + { + Schema::dropIfExists('artwork_files'); + } +}; diff --git a/database/migrations/2026_02_11_000004_add_progress_and_failure_to_uploads_sessions_table.php b/database/migrations/2026_02_11_000004_add_progress_and_failure_to_uploads_sessions_table.php new file mode 100644 index 00000000..418a1d5b --- /dev/null +++ b/database/migrations/2026_02_11_000004_add_progress_and_failure_to_uploads_sessions_table.php @@ -0,0 +1,22 @@ +unsignedTinyInteger('progress')->default(0)->after('ip'); + $table->string('failure_reason', 255)->nullable()->after('progress'); + }); + } + + public function down(): void + { + Schema::table('uploads_sessions', function (Blueprint $table) { + $table->dropColumn(['progress', 'failure_reason']); + }); + } +}; diff --git a/database/migrations/2026_02_12_000001_create_tags_table.php b/database/migrations/2026_02_12_000001_create_tags_table.php new file mode 100644 index 00000000..c768542f --- /dev/null +++ b/database/migrations/2026_02_12_000001_create_tags_table.php @@ -0,0 +1,29 @@ +id(); + $table->string('name', 64); + $table->string('slug', 64)->unique(); + $table->unsignedBigInteger('usage_count')->default(0); + $table->boolean('is_active')->default(true); + $table->timestamps(); + + $table->unique('name'); + $table->index('usage_count'); + }); + } + + public function down(): void + { + Schema::dropIfExists('tags'); + } +}; diff --git a/database/migrations/2026_02_12_000002_create_artwork_tag_table.php b/database/migrations/2026_02_12_000002_create_artwork_tag_table.php new file mode 100644 index 00000000..b96f2dda --- /dev/null +++ b/database/migrations/2026_02_12_000002_create_artwork_tag_table.php @@ -0,0 +1,31 @@ +unsignedBigInteger('artwork_id'); + $table->unsignedBigInteger('tag_id'); + $table->enum('source', ['user', 'ai', 'system']); + $table->float('confidence')->nullable(); + $table->timestamp('created_at')->useCurrent(); + + $table->primary(['artwork_id', 'tag_id']); + $table->index('tag_id'); + + $table->foreign('artwork_id')->references('id')->on('artworks')->cascadeOnDelete(); + $table->foreign('tag_id')->references('id')->on('tags')->cascadeOnDelete(); + }); + } + + public function down(): void + { + Schema::dropIfExists('artwork_tag'); + } +}; diff --git a/database/migrations/2026_02_12_000003_create_tag_synonyms_table.php b/database/migrations/2026_02_12_000003_create_tag_synonyms_table.php new file mode 100644 index 00000000..f945f5ae --- /dev/null +++ b/database/migrations/2026_02_12_000003_create_tag_synonyms_table.php @@ -0,0 +1,26 @@ +id(); + $table->unsignedBigInteger('tag_id'); + $table->string('synonym', 64); + + $table->unique(['tag_id', 'synonym']); + $table->foreign('tag_id')->references('id')->on('tags')->cascadeOnDelete(); + }); + } + + public function down(): void + { + Schema::dropIfExists('tag_synonyms'); + } +}; diff --git a/database/migrations/2026_02_12_000004_create_uploads_table.php b/database/migrations/2026_02_12_000004_create_uploads_table.php new file mode 100644 index 00000000..e03c7b84 --- /dev/null +++ b/database/migrations/2026_02_12_000004_create_uploads_table.php @@ -0,0 +1,47 @@ +uuid('id')->primary(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->string('type', 32)->index(); // image, archive, etc. + $table->string('status', 32)->default('draft')->index(); + $table->string('title')->nullable(); + $table->string('slug')->nullable()->unique(); + $table->foreignId('category_id')->nullable()->constrained('categories')->nullOnDelete(); + $table->text('description')->nullable(); + $table->json('tags')->nullable(); + $table->string('license', 64)->nullable(); + $table->boolean('nsfw')->default(false); + $table->boolean('is_scanned')->default(false)->index(); + $table->boolean('has_tags')->default(false)->index(); + $table->string('preview_path')->nullable(); + $table->timestamp('published_at')->nullable()->index(); + $table->string('final_path')->nullable(); + $table->timestamp('expires_at')->nullable()->index(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down(): void + { + Schema::dropIfExists('uploads'); + } +}; diff --git a/database/migrations/2026_02_12_000005_create_upload_files_table.php b/database/migrations/2026_02_12_000005_create_upload_files_table.php new file mode 100644 index 00000000..be616424 --- /dev/null +++ b/database/migrations/2026_02_12_000005_create_upload_files_table.php @@ -0,0 +1,30 @@ +bigIncrements('id'); + $table->uuid('upload_id'); + $table->string('path'); + $table->string('type', 32)->index(); // main/screenshot/preview + $table->string('hash', 128)->nullable()->index(); + $table->unsignedBigInteger('size')->nullable(); + $table->string('mime')->nullable(); + $table->timestamp('created_at')->useCurrent(); + + $table->foreign('upload_id')->references('id')->on('uploads')->cascadeOnDelete(); + $table->index(['upload_id', 'type']); + }); + } + + public function down(): void + { + Schema::dropIfExists('upload_files'); + } +}; diff --git a/database/migrations/2026_02_12_000006_create_upload_tags_table.php b/database/migrations/2026_02_12_000006_create_upload_tags_table.php new file mode 100644 index 00000000..0709b303 --- /dev/null +++ b/database/migrations/2026_02_12_000006_create_upload_tags_table.php @@ -0,0 +1,28 @@ +bigIncrements('id'); + $table->uuid('upload_id'); + $table->foreignId('tag_id')->constrained()->cascadeOnDelete(); + $table->decimal('confidence', 5, 4)->nullable(); + $table->string('source', 24)->default('manual')->index(); // ai|filename|manual + $table->timestamps(); + + $table->foreign('upload_id')->references('id')->on('uploads')->cascadeOnDelete(); + $table->unique(['upload_id', 'tag_id']); + }); + } + + public function down(): void + { + Schema::dropIfExists('upload_tags'); + } +}; diff --git a/database/migrations/2026_02_13_000007_add_processing_state_to_uploads_table.php b/database/migrations/2026_02_13_000007_add_processing_state_to_uploads_table.php new file mode 100644 index 00000000..080f0991 --- /dev/null +++ b/database/migrations/2026_02_13_000007_add_processing_state_to_uploads_table.php @@ -0,0 +1,31 @@ +string('processing_state', 32) + ->default('pending_scan') + ->index() + ->after('status'); + }); + + DB::table('uploads') + ->whereNull('processing_state') + ->update(['processing_state' => 'pending_scan']); + } + + public function down(): void + { + Schema::table('uploads', function (Blueprint $table) { + $table->dropIndex(['processing_state']); + $table->dropColumn('processing_state'); + }); + } +}; diff --git a/database/migrations/2026_02_13_000008_add_moderation_fields_to_uploads_table.php b/database/migrations/2026_02_13_000008_add_moderation_fields_to_uploads_table.php new file mode 100644 index 00000000..18d22c24 --- /dev/null +++ b/database/migrations/2026_02_13_000008_add_moderation_fields_to_uploads_table.php @@ -0,0 +1,43 @@ +string('moderation_status', 16)->default('pending')->index(); + $table->timestamp('moderated_at')->nullable()->index(); + $table->foreignId('moderated_by')->nullable()->constrained('users')->nullOnDelete(); + $table->text('moderation_note')->nullable(); + }); + + DB::table('uploads') + ->where('status', 'published') + ->update([ + 'moderation_status' => 'approved', + 'updated_at' => now(), + ]); + + DB::table('uploads') + ->where('status', 'draft') + ->update([ + 'moderation_status' => 'pending', + 'updated_at' => now(), + ]); + } + + public function down(): void + { + Schema::table('uploads', function (Blueprint $table): void { + $table->dropConstrainedForeignId('moderated_by'); + $table->dropColumn('moderation_note'); + $table->dropColumn('moderated_at'); + $table->dropColumn('moderation_status'); + }); + } +}; diff --git a/database/migrations/2026_02_13_000009_create_artwork_embeddings_table.php b/database/migrations/2026_02_13_000009_create_artwork_embeddings_table.php new file mode 100644 index 00000000..2842cac0 --- /dev/null +++ b/database/migrations/2026_02_13_000009_create_artwork_embeddings_table.php @@ -0,0 +1,34 @@ +id(); + $table->foreignId('artwork_id')->constrained('artworks')->cascadeOnDelete(); + $table->string('model', 64); + $table->string('model_version', 64); + $table->string('algo_version', 64)->default('clip-cosine-v1')->index(); + $table->unsignedSmallInteger('dim'); + $table->longText('embedding_json'); + $table->string('source_hash', 128)->nullable()->index(); + $table->boolean('is_normalized')->default(true); + $table->timestamp('generated_at')->nullable()->index(); + $table->json('meta')->nullable(); + $table->timestamps(); + + $table->unique(['artwork_id', 'model', 'model_version'], 'artwork_embeddings_artwork_model_unique'); + $table->index(['model', 'model_version'], 'artwork_embeddings_model_lookup_idx'); + }); + } + + public function down(): void + { + Schema::dropIfExists('artwork_embeddings'); + } +}; diff --git a/database/migrations/2026_02_13_000010_create_artwork_similarities_table.php b/database/migrations/2026_02_13_000010_create_artwork_similarities_table.php new file mode 100644 index 00000000..9d31beff --- /dev/null +++ b/database/migrations/2026_02_13_000010_create_artwork_similarities_table.php @@ -0,0 +1,34 @@ +id(); + $table->foreignId('artwork_id')->constrained('artworks')->cascadeOnDelete(); + $table->foreignId('similar_artwork_id')->constrained('artworks')->cascadeOnDelete(); + $table->string('model', 64); + $table->string('model_version', 64); + $table->string('algo_version', 64)->default('clip-cosine-v1'); + $table->unsignedSmallInteger('rank'); + $table->decimal('score', 10, 7); + $table->timestamp('generated_at')->nullable()->index(); + $table->json('meta')->nullable(); + $table->timestamps(); + + $table->unique(['artwork_id', 'similar_artwork_id', 'algo_version'], 'artwork_similarities_unique_pair_algo'); + $table->index(['artwork_id', 'algo_version', 'rank', 'score'], 'artwork_similarities_page_read_idx'); + $table->index(['similar_artwork_id', 'algo_version'], 'artwork_similarities_reverse_idx'); + }); + } + + public function down(): void + { + Schema::dropIfExists('artwork_similarities'); + } +}; diff --git a/database/migrations/2026_02_14_000011_create_similar_artwork_analytics_tables.php b/database/migrations/2026_02_14_000011_create_similar_artwork_analytics_tables.php new file mode 100644 index 00000000..790d71f0 --- /dev/null +++ b/database/migrations/2026_02_14_000011_create_similar_artwork_analytics_tables.php @@ -0,0 +1,45 @@ +id(); + $table->date('event_date')->index(); + $table->string('event_type', 16)->index(); // impression|click + $table->string('algo_version', 64)->index(); + $table->foreignId('source_artwork_id')->constrained('artworks')->cascadeOnDelete(); + $table->foreignId('similar_artwork_id')->nullable()->constrained('artworks')->nullOnDelete(); + $table->unsignedSmallInteger('position')->nullable(); + $table->unsignedSmallInteger('items_count')->nullable(); + $table->timestamp('occurred_at')->nullable()->index(); + $table->timestamps(); + + $table->index(['event_date', 'algo_version', 'event_type'], 'similar_artwork_events_daily_idx'); + }); + + Schema::create('similar_artwork_daily_metrics', function (Blueprint $table): void { + $table->id(); + $table->date('metric_date'); + $table->string('algo_version', 64); + $table->unsignedInteger('impressions')->default(0); + $table->unsignedInteger('clicks')->default(0); + $table->decimal('ctr', 8, 6)->default(0); + $table->timestamps(); + + $table->unique(['metric_date', 'algo_version'], 'similar_artwork_daily_metrics_unique'); + $table->index(['metric_date', 'algo_version'], 'similar_artwork_daily_metrics_lookup_idx'); + }); + } + + public function down(): void + { + Schema::dropIfExists('similar_artwork_daily_metrics'); + Schema::dropIfExists('similar_artwork_events'); + } +}; diff --git a/database/migrations/2026_02_14_000012_create_discovery_foundation_tables.php b/database/migrations/2026_02_14_000012_create_discovery_foundation_tables.php new file mode 100644 index 00000000..9b58b187 --- /dev/null +++ b/database/migrations/2026_02_14_000012_create_discovery_foundation_tables.php @@ -0,0 +1,69 @@ +id(); + $table->foreignId('user_id')->constrained('users')->cascadeOnDelete(); + $table->string('profile_version', 32)->default('profile-v1'); + $table->string('algo_version', 64)->default('clip-cosine-v1'); + $table->json('raw_scores_json')->nullable(); + $table->json('normalized_scores_json')->nullable(); + $table->decimal('total_weight', 14, 6)->default(0); + $table->unsignedInteger('event_count')->default(0); + $table->timestamp('last_event_at')->nullable()->index(); + $table->double('half_life_hours')->default(72); + $table->uuid('updated_from_event_id')->nullable()->index(); + $table->timestamps(); + + $table->unique(['user_id', 'profile_version', 'algo_version'], 'user_interest_profiles_unique_key'); + $table->index(['algo_version', 'updated_at'], 'user_interest_profiles_algo_updated_idx'); + }); + + Schema::create('user_discovery_events', function (Blueprint $table): void { + $table->id(); + $table->uuid('event_id')->unique(); + $table->foreignId('user_id')->constrained('users')->cascadeOnDelete(); + $table->foreignId('artwork_id')->constrained('artworks')->cascadeOnDelete(); + $table->foreignId('category_id')->nullable()->constrained('categories')->nullOnDelete(); + $table->string('event_type', 16)->index(); // view|click|favorite|download + $table->string('event_version', 32)->default('event-v1')->index(); + $table->string('algo_version', 64)->default('clip-cosine-v1')->index(); + $table->decimal('weight', 10, 4)->default(1.0); + $table->date('event_date')->index(); + $table->timestamp('occurred_at')->nullable()->index(); + $table->json('meta')->nullable(); + $table->timestamps(); + + $table->index(['user_id', 'event_date', 'event_type'], 'user_discovery_events_user_date_type_idx'); + $table->index(['user_id', 'algo_version', 'occurred_at'], 'user_discovery_events_user_algo_time_idx'); + }); + + Schema::create('user_recommendation_cache', function (Blueprint $table): void { + $table->id(); + $table->foreignId('user_id')->constrained('users')->cascadeOnDelete(); + $table->string('algo_version', 64); + $table->string('cache_version', 32)->default('cache-v1'); + $table->json('recommendations_json')->nullable(); + $table->timestamp('generated_at')->nullable()->index(); + $table->timestamp('expires_at')->nullable()->index(); + $table->timestamps(); + + $table->unique(['user_id', 'algo_version'], 'user_recommendation_cache_user_algo_unique'); + $table->index(['algo_version', 'expires_at'], 'user_recommendation_cache_algo_expiry_idx'); + }); + } + + public function down(): void + { + Schema::dropIfExists('user_recommendation_cache'); + Schema::dropIfExists('user_discovery_events'); + Schema::dropIfExists('user_interest_profiles'); + } +}; diff --git a/database/migrations/2026_02_14_000013_create_feed_analytics_tables.php b/database/migrations/2026_02_14_000013_create_feed_analytics_tables.php new file mode 100644 index 00000000..3dcb4857 --- /dev/null +++ b/database/migrations/2026_02_14_000013_create_feed_analytics_tables.php @@ -0,0 +1,58 @@ +id(); + $table->date('event_date')->index(); + $table->string('event_type', 24)->index(); // feed_impression|feed_click + $table->foreignId('user_id')->constrained('users')->cascadeOnDelete(); + $table->foreignId('artwork_id')->constrained('artworks')->cascadeOnDelete(); + $table->unsignedSmallInteger('position')->nullable(); + $table->string('algo_version', 64)->index(); + $table->string('source', 24)->index(); // personalized|cold_start|fallback + $table->unsignedInteger('dwell_seconds')->nullable(); + $table->timestamp('occurred_at')->nullable()->index(); + $table->timestamps(); + + $table->index(['event_date', 'algo_version', 'source', 'event_type'], 'feed_events_daily_agg_idx'); + $table->index(['user_id', 'artwork_id', 'event_date'], 'feed_events_user_art_date_idx'); + }); + + Schema::create('feed_daily_metrics', function (Blueprint $table): void { + $table->id(); + $table->date('metric_date'); + $table->string('algo_version', 64); + $table->string('source', 24); + + $table->unsignedInteger('impressions')->default(0); + $table->unsignedInteger('clicks')->default(0); + $table->unsignedInteger('saves')->default(0); + + $table->decimal('ctr', 8, 6)->default(0); + $table->decimal('save_rate', 8, 6)->default(0); + + $table->unsignedInteger('dwell_0_5')->default(0); + $table->unsignedInteger('dwell_5_30')->default(0); + $table->unsignedInteger('dwell_30_120')->default(0); + $table->unsignedInteger('dwell_120_plus')->default(0); + + $table->timestamps(); + + $table->unique(['metric_date', 'algo_version', 'source'], 'feed_daily_metrics_unique_idx'); + $table->index(['metric_date', 'algo_version', 'source'], 'feed_daily_metrics_lookup_idx'); + }); + } + + public function down(): void + { + Schema::dropIfExists('feed_daily_metrics'); + Schema::dropIfExists('feed_events'); + } +}; diff --git a/docs/feed-rollout-runbook.md b/docs/feed-rollout-runbook.md new file mode 100644 index 00000000..4f75acd6 --- /dev/null +++ b/docs/feed-rollout-runbook.md @@ -0,0 +1,123 @@ +# Feed Rollout Runbook (clip-cosine-v2, prod set 1) + +## Scope + +- Candidate: `clip-cosine-v2` with weights `w1=0.52, w2=0.23, w3=0.15, w4=0.10` +- Baseline: `clip-cosine-v1` +- Rollout gates: `10% -> 50% -> 100%` +- Temporary policy: `save_rate` is informational only until save-event schema reliability is confirmed in production. + +## Pre-flight checks + +1. Confirm config values: + - `DISCOVERY_ROLLOUT_ENABLED=true` + - `DISCOVERY_ROLLOUT_BASELINE_ALGO_VERSION=clip-cosine-v1` + - `DISCOVERY_ROLLOUT_CANDIDATE_ALGO_VERSION=clip-cosine-v2` + - `DISCOVERY_ROLLOUT_ACTIVE_GATE=g10` + - `DISCOVERY_FORCE_ALGO_VERSION` is empty +2. Confirm candidate weights are active in `config/discovery.php` and env overrides. +3. Confirm ingestion health for discovery events: + - `event_id` populated for all new events + - `favorite` and `download` events present in `user_discovery_events` +4. Run daily aggregation: + - `php artisan analytics:aggregate-feed --date=YYYY-MM-DD` + +## Gate progression + +### Gate 1: 10% + +- Set: `DISCOVERY_ROLLOUT_ACTIVE_GATE=g10` +- Observe for at least 2-3 days with minimum sample volume. +- Required checks: + - CTR delta vs baseline + - Long-dwell-share delta vs baseline + - Diversity concentration delta vs baseline + - Save-rate trend (informational only) + +Promote to 50% only if no rollback trigger fires and no persistent warning trend is present. + +### Gate 2: 50% + +- Set: `DISCOVERY_ROLLOUT_ACTIVE_GATE=g50` +- Observe for 3-5 days with stable daily traffic. +- Apply same checks and thresholds. + +Promote to 100% only with at least 2 consecutive healthy days. + +### Gate 3: 100% + +- Set: `DISCOVERY_ROLLOUT_ACTIVE_GATE=g100` +- Keep baseline available for rapid rollback via force toggle. + +## Monitoring thresholds (candidate vs baseline) + +- CTR: + - Warning: drop >= 3% + - Rollback: drop >= 5% (or >= 10% in a single severe window) +- Long dwell share (`(dwell_30_120 + dwell_120_plus) / clicks`): + - Warning: drop >= 4% + - Rollback: drop >= 8% (or >= 12% in a single severe window) +- Diversity concentration (e.g. top-author/top-category share, near-duplicate concentration): + - Warning: rise >= 10% + - Rollback: rise >= 15% + +## Rollback actions + +### Immediate rollback (fastest) + +- Set `DISCOVERY_FORCE_ALGO_VERSION=clip-cosine-v1` +- Reload config/cache as needed in your deployment flow. +- Verify feed responses show `meta.algo_version=clip-cosine-v1`. + +### Standard rollback + +- Set `DISCOVERY_ROLLOUT_ACTIVE_GATE=g10` (or disable rollout) +- Keep candidate enabled only for controlled validation traffic. + +## Save-event schema note and fix + +Observed issue class in mixed environments: save-event writes can fail if discovery event schema differs from code expectations (e.g., `meta`/`metadata` drift, required `event_id`). + +Implemented fix path: + +- Ingestion now always writes `event_id` and inserts schema-aware metadata (`meta` if present, otherwise `metadata` if present). +- Keep `DISCOVERY_EVAL_SAVE_RATE_INFORMATIONAL=true` until production confirms stable save-event ingestion. + +Validation query examples: + +- Save events by day: + - `SELECT event_date, COUNT(*) FROM user_discovery_events WHERE event_type IN ('favorite','download') GROUP BY event_date ORDER BY event_date DESC;` +- Null/empty event id check: + - `SELECT COUNT(*) FROM user_discovery_events WHERE event_id IS NULL OR event_id = '';` + +## Daily operator checklist + +1. Run feed aggregation for the previous day. +2. Run evaluator and compare commands: + - `php artisan analytics:evaluate-feed-weights --from=YYYY-MM-DD --to=YYYY-MM-DD --json` + - `php artisan analytics:compare-feed-ab clip-cosine-v1 clip-cosine-v2 --from=YYYY-MM-DD --to=YYYY-MM-DD --json` +3. Record deltas for CTR, long_dwell_share, diversity concentration. +4. Record save_rate as informational only. +5. Decide: hold, promote gate, or rollback. + +## First 24h verification checklist + +1. Confirm rollout activation and gate state: + - `DISCOVERY_ROLLOUT_ENABLED=true` + - `DISCOVERY_ROLLOUT_ACTIVE_GATE=g10` + - `DISCOVERY_FORCE_ALGO_VERSION` empty +2. Verify both algos are receiving traffic in analytics: + - candidate (`clip-cosine-v2`) should be near 10% share (allow normal variance) + - baseline (`clip-cosine-v1`) remains dominant +3. Run aggregation/evaluation at least twice in first day (midday + end-of-day): + - `php artisan analytics:aggregate-feed --date=YYYY-MM-DD` + - `php artisan analytics:evaluate-feed-weights --from=YYYY-MM-DD --to=YYYY-MM-DD --json` + - `php artisan analytics:compare-feed-ab clip-cosine-v1 clip-cosine-v2 --from=YYYY-MM-DD --to=YYYY-MM-DD --json` +4. Check guardrails: + - CTR drop < rollback threshold + - long_dwell_share drop < rollback threshold + - diversity concentration rise < rollback threshold +5. Check save-event ingestion health: + - save events (`favorite`,`download`) are arriving in `user_discovery_events` + - `event_id` is always populated +6. If any rollback trigger is breached, apply emergency rollback preset immediately. diff --git a/docs/ui/tag-input.md b/docs/ui/tag-input.md new file mode 100644 index 00000000..6b3ee819 --- /dev/null +++ b/docs/ui/tag-input.md @@ -0,0 +1,101 @@ +# TagInput UI Component + +## Overview + +`TagInput` is the reusable tag entry component for Skinbase artwork flows. + +It is designed for: + +- Upload page +- Artwork edit page +- Admin moderation screens + +The component encapsulates all tag UX behavior (chips, search, keyboard flow, AI suggestions, status hints) so pages stay thin. + +## File Location + +- `resources/js/components/tags/TagInput.jsx` + +## Props + +| Prop | Type | Default | Description | +| --- | --- | --- | --- | +| `value` | `string \| string[]` | required | Controlled selected tags. Can be CSV string or array. | +| `onChange` | `(tags: string[]) => void` | required | Called whenever selected tags change. | +| `suggestedTags` | `Array` | `[]` | AI-suggested tags shown as clickable pills. | +| `disabled` | `boolean` | `false` | Disables input and interactions. | +| `maxTags` | `number` | `15` | Maximum number of selected tags. | +| `minLength` | `number` | `2` | Minimum normalized tag length. | +| `maxLength` | `number` | `32` | Maximum normalized tag length. | +| `placeholder` | `string` | `Type tags…` | Input placeholder text. | +| `searchEndpoint` | `string` | `/api/tags/search` | Search API endpoint. | +| `popularEndpoint` | `string` | `/api/tags/popular` | Popular tags endpoint when input is empty. | + +## Normalization + +Tags are normalized client-side before being added: + +- lowercase +- trim +- spaces → `-` +- remove unsupported characters +- collapse repeated separators +- max length = 32 + +Server-side normalization/validation still applies and remains authoritative. + +## Keyboard & Interaction + +- `Enter` → add tag +- `Comma` → add tag +- `Tab` → accept highlighted suggestion +- `Backspace` (empty input) → remove last tag +- `Escape` → close suggestion dropdown +- Paste CSV (`a, b, c`) → split and add valid tags + +## Accessibility + +- Suggestion dropdown uses `role="listbox"` +- Suggestions use `role="option"` +- Active item uses `aria-selected` +- Input uses `aria-expanded`, `aria-controls`, `aria-autocomplete` + +## API Usage + +The component performs debounced search (300ms): + +- `GET /api/tags/search?q=` +- `GET /api/tags/popular` (empty query) + +Behavior: + +- caches recent query results +- aborts outdated requests +- max 8 suggestions +- excludes already-selected tags +- shows non-blocking message when search fails + +## Upload Integration Example + +```jsx + { + dispatch({ type: 'SET_METADATA', payload: { tags: nextTags.join(', ') } }) + }} + suggestedTags={props.suggested_tags || []} + maxTags={15} + minLength={2} + maxLength={32} +/> +``` + +## Events & Save Strategy + +`TagInput` itself does not persist to backend on keystrokes. + +Persistence is done on save/publish boundary by page logic, e.g.: + +- `PUT /api/artworks/{id}/tags` + +This keeps UI responsive and avoids unnecessary API writes. diff --git a/docs/ui/upload-v2-rollout-runbook.md b/docs/ui/upload-v2-rollout-runbook.md new file mode 100644 index 00000000..31976777 --- /dev/null +++ b/docs/ui/upload-v2-rollout-runbook.md @@ -0,0 +1,130 @@ +# Upload UI v2 Rollout Runbook + +## Status + +- Upload UI v2 is production-ready. +- Feature flag posture: `uploads_v2` default ON. +- Emergency override remains available through `SKINBASE_UPLOADS_V2=false`. + +## Scope + +- Route: `/upload` +- UI: React/Inertia Upload Wizard v2 +- API endpoints in use: + - `POST /api/uploads/init` + - `POST /api/uploads/chunk` + - `POST /api/uploads/finish` + - `GET /api/uploads/{id}/status` + - `POST /api/uploads/{id}/publish` + - `POST /api/uploads/cancel` + +## Legacy Flow Policy + +- Current state: legacy upload flow remains in code behind feature flag branch. +- Removal decision: **scheduled removal** (not immediate deletion). +- Target window: remove legacy branch in the next hardening cycle after stable production operation. +- Suggested checkpoint gates before removal: + 1. 7 consecutive days with no Sev-1/Sev-2 upload regressions. + 2. Upload completion rate at or above pre-v2 baseline. + 3. No unresolved blockers in publish/cancel/status polling. + +## Rollout Checklist + +### 1) Staging + +- Set `SKINBASE_UPLOADS_V2=true` in staging env. +- Build and deploy current commit. +- Verify upload happy paths: + - image upload (jpg/png/webp) + - archive upload with required screenshots + - cancel in-progress upload + - publish after ready state +- Verify failure paths: + - invalid file type + - over-size files + - processing/publish API failure surfaces retry/reset correctly +- Verify analytics events emitted in browser: + - `upload_start` + - `upload_complete` + - `upload_publish` + - `upload_cancel` + - `upload_error` + +### 2) Production Enablement + +- Confirm production env has `SKINBASE_UPLOADS_V2=true` (or unset, default ON). +- Deploy release artifact. +- Run smoke tests on `/upload` with one image and one archive flow. +- Confirm endpoints respond with expected status codes under normal load. + +### 3) Post-Deploy Verification (0-24h) + +- Validate build artifact and route rendering: + - `/upload` renders v2 wizard UI + - no front-end boot errors in browser console +- Validate pipeline behavior: + - init/chunk/finish/status/publish/cancel all reachable + - status polling transitions to ready/publishable where expected +- Validate user outcomes: + - completion and publish rates are stable vs prior day baseline + - no spike in cancellation due to UI confusion + +## Post-Deploy Monitoring Plan + +### Key Metrics + +- Upload start volume (`upload_start`) +- Upload completion volume (`upload_complete`) +- Publish success volume (`upload_publish`) +- Error volume by stage (`upload_error.stage`) +- Cancel volume (`upload_cancel`) +- Derived funnel: + - start -> complete conversion + - complete -> publish conversion + - overall start -> publish conversion + +### Operational Signals + +- API error rates for `/api/uploads/*` +- p95 latency for `init`, `chunk`, `finish`, `status`, `publish` +- 4xx/5xx split by endpoint +- Client-side uncaught exceptions on `/upload` + +### Alert Thresholds (initial) + +- Critical rollback candidate: + - `upload_error` rate > 2x baseline for 15+ minutes, or + - publish failure rate > 5% sustained for 15+ minutes, or + - any endpoint 5xx rate > 3% sustained for 10+ minutes. +- Warning/observe: + - completion funnel drops > 10% vs trailing 7-day average. + +## Rollback Plan + +### Fast Toggle Rollback (preferred) + +1. Set `SKINBASE_UPLOADS_V2=false`. +2. Reload config/cache per deploy process. +3. Verify `/upload` serves legacy flow. +4. Continue API monitoring until error rates normalize. + +### Release Rollback (if needed) + +1. Roll back to prior release artifact. +2. Keep `SKINBASE_UPLOADS_V2=false` during stabilization. +3. Re-run smoke test for upload + publish. + +### Communication + +- Post incident update in release channel with: + - start time + - impact scope (upload, publish, cancel) + - rollback action taken + - follow-up issue link + +## Ownership and Next Actions + +- Owner: Upload frontend + API maintainers. +- First review checkpoint: 24h post deploy. +- Second checkpoint: 7 days post deploy for legacy removal go/no-go. +- If metrics remain healthy, create removal PR for legacy branch in `/upload` page component. diff --git a/package-lock.json b/package-lock.json index b23aad2d..b7069052 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,18 +4,29 @@ "requires": true, "packages": { "": { + "dependencies": { + "@inertiajs/core": "^1.0.4", + "@inertiajs/react": "^1.0.4", + "framer-motion": "^12.34.0", + "react": "^19.2.4", + "react-dom": "^19.2.4" + }, "devDependencies": { "@tailwindcss/forms": "^0.5.2", "@tailwindcss/vite": "^4.0.0", + "@testing-library/react": "^16.1.0", + "@testing-library/user-event": "^14.5.2", "alpinejs": "^3.4.2", "autoprefixer": "^10.4.2", "axios": "^1.11.0", "concurrently": "^9.0.1", + "jsdom": "^25.0.1", "laravel-vite-plugin": "^2.0.0", "postcss": "^8.4.31", "sass": "^1.70.0", "tailwindcss": "^3.1.0", - "vite": "^7.0.7" + "vite": "^7.0.7", + "vitest": "^2.1.8" } }, "node_modules/@alloc/quick-lru": { @@ -31,10 +42,176 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", - "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", "cpu": [ "ppc64" ], @@ -49,9 +226,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", - "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", "cpu": [ "arm" ], @@ -66,9 +243,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", - "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", "cpu": [ "arm64" ], @@ -83,9 +260,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", - "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", "cpu": [ "x64" ], @@ -100,9 +277,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", - "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", "cpu": [ "arm64" ], @@ -117,9 +294,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", - "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", "cpu": [ "x64" ], @@ -134,9 +311,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", - "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", "cpu": [ "arm64" ], @@ -151,9 +328,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", - "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", "cpu": [ "x64" ], @@ -168,9 +345,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", - "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", "cpu": [ "arm" ], @@ -185,9 +362,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", - "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", "cpu": [ "arm64" ], @@ -202,9 +379,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", - "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", "cpu": [ "ia32" ], @@ -219,9 +396,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", - "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", "cpu": [ "loong64" ], @@ -236,9 +413,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", - "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", "cpu": [ "mips64el" ], @@ -253,9 +430,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", - "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", "cpu": [ "ppc64" ], @@ -270,9 +447,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", - "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", "cpu": [ "riscv64" ], @@ -287,9 +464,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", - "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", "cpu": [ "s390x" ], @@ -304,9 +481,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", - "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", "cpu": [ "x64" ], @@ -321,9 +498,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", - "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", "cpu": [ "arm64" ], @@ -338,9 +515,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", - "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", "cpu": [ "x64" ], @@ -355,9 +532,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", - "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", "cpu": [ "arm64" ], @@ -372,9 +549,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", - "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", "cpu": [ "x64" ], @@ -389,9 +566,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", - "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", "cpu": [ "arm64" ], @@ -406,9 +583,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", - "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", "cpu": [ "x64" ], @@ -423,9 +600,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", - "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", "cpu": [ "arm64" ], @@ -440,9 +617,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", - "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", "cpu": [ "ia32" ], @@ -457,9 +634,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", - "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", "cpu": [ "x64" ], @@ -473,6 +650,31 @@ "node": ">=18" } }, + "node_modules/@inertiajs/core": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@inertiajs/core/-/core-1.3.0.tgz", + "integrity": "sha512-TJ8R1eUYY473m9DaKlCPRdHTdznFWTDuy5VvEzXg3t/hohbDQedLj46yn/uAqziJPEUZJrSftZzPI2NMzL9tQA==", + "license": "MIT", + "dependencies": { + "axios": "^1.6.0", + "deepmerge": "^4.0.0", + "nprogress": "^0.2.0", + "qs": "^6.9.0" + } + }, + "node_modules/@inertiajs/react": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@inertiajs/react/-/react-1.3.0.tgz", + "integrity": "sha512-K+PF23xP6jjMkubs8PbxT1MroSDdH1z3VTEGbO3685Xyf0QNwoNIF95hnyqJxlWaeG4fB0GAag40gh04fefRUA==", + "license": "MIT", + "dependencies": { + "@inertiajs/core": "1.3.0", + "lodash.isequal": "^4.5.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -872,9 +1074,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.0.tgz", - "integrity": "sha512-tPgXB6cDTndIe1ah7u6amCI1T0SsnlOuKgg10Xh3uizJk4e5M1JGaUMk7J4ciuAUcFpbOiNhm2XIjP9ON0dUqA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", + "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", "cpu": [ "arm" ], @@ -886,9 +1088,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.0.tgz", - "integrity": "sha512-sa4LyseLLXr1onr97StkU1Nb7fWcg6niokTwEVNOO7awaKaoRObQ54+V/hrF/BP1noMEaaAW6Fg2d/CfLiq3Mg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", + "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", "cpu": [ "arm64" ], @@ -900,9 +1102,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.0.tgz", - "integrity": "sha512-/NNIj9A7yLjKdmkx5dC2XQ9DmjIECpGpwHoGmA5E1AhU0fuICSqSWScPhN1yLCkEdkCwJIDu2xIeLPs60MNIVg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", + "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", "cpu": [ "arm64" ], @@ -914,9 +1116,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.0.tgz", - "integrity": "sha512-xoh8abqgPrPYPr7pTYipqnUi1V3em56JzE/HgDgitTqZBZ3yKCWI+7KUkceM6tNweyUKYru1UMi7FC060RyKwA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", + "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", "cpu": [ "x64" ], @@ -928,9 +1130,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.0.tgz", - "integrity": "sha512-PCkMh7fNahWSbA0OTUQ2OpYHpjZZr0hPr8lId8twD7a7SeWrvT3xJVyza+dQwXSSq4yEQTMoXgNOfMCsn8584g==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", + "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", "cpu": [ "arm64" ], @@ -942,9 +1144,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.0.tgz", - "integrity": "sha512-1j3stGx+qbhXql4OCDZhnK7b01s6rBKNybfsX+TNrEe9JNq4DLi1yGiR1xW+nL+FNVvI4D02PUnl6gJ/2y6WJA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", + "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", "cpu": [ "x64" ], @@ -956,9 +1158,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.0.tgz", - "integrity": "sha512-eyrr5W08Ms9uM0mLcKfM/Uzx7hjhz2bcjv8P2uynfj0yU8GGPdz8iYrBPhiLOZqahoAMB8ZiolRZPbbU2MAi6Q==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", + "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", "cpu": [ "arm" ], @@ -970,9 +1172,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.0.tgz", - "integrity": "sha512-Xds90ITXJCNyX9pDhqf85MKWUI4lqjiPAipJ8OLp8xqI2Ehk+TCVhF9rvOoN8xTbcafow3QOThkNnrM33uCFQA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", + "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", "cpu": [ "arm" ], @@ -984,9 +1186,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.0.tgz", - "integrity": "sha512-Xws2KA4CLvZmXjy46SQaXSejuKPhwVdaNinldoYfqruZBaJHqVo6hnRa8SDo9z7PBW5x84SH64+izmldCgbezw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", + "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", "cpu": [ "arm64" ], @@ -998,9 +1200,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.0.tgz", - "integrity": "sha512-hrKXKbX5FdaRJj7lTMusmvKbhMJSGWJ+w++4KmjiDhpTgNlhYobMvKfDoIWecy4O60K6yA4SnztGuNTQF+Lplw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", + "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", "cpu": [ "arm64" ], @@ -1012,9 +1214,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.0.tgz", - "integrity": "sha512-6A+nccfSDGKsPm00d3xKcrsBcbqzCTAukjwWK6rbuAnB2bHaL3r9720HBVZ/no7+FhZLz/U3GwwZZEh6tOSI8Q==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", + "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", "cpu": [ "loong64" ], @@ -1026,9 +1228,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.0.tgz", - "integrity": "sha512-4P1VyYUe6XAJtQH1Hh99THxr0GKMMwIXsRNOceLrJnaHTDgk1FTcTimDgneRJPvB3LqDQxUmroBclQ1S0cIJwQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", + "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", "cpu": [ "loong64" ], @@ -1040,9 +1242,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.0.tgz", - "integrity": "sha512-8Vv6pLuIZCMcgXre6c3nOPhE0gjz1+nZP6T+hwWjr7sVH8k0jRkH+XnfjjOTglyMBdSKBPPz54/y1gToSKwrSQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", + "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", "cpu": [ "ppc64" ], @@ -1054,9 +1256,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.0.tgz", - "integrity": "sha512-r1te1M0Sm2TBVD/RxBPC6RZVwNqUTwJTA7w+C/IW5v9Ssu6xmxWEi+iJQlpBhtUiT1raJ5b48pI8tBvEjEFnFA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", + "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", "cpu": [ "ppc64" ], @@ -1068,9 +1270,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.0.tgz", - "integrity": "sha512-say0uMU/RaPm3CDQLxUUTF2oNWL8ysvHkAjcCzV2znxBr23kFfaxocS9qJm+NdkRhF8wtdEEAJuYcLPhSPbjuQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", + "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", "cpu": [ "riscv64" ], @@ -1082,9 +1284,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.0.tgz", - "integrity": "sha512-/MU7/HizQGsnBREtRpcSbSV1zfkoxSTR7wLsRmBPQ8FwUj5sykrP1MyJTvsxP5KBq9SyE6kH8UQQQwa0ASeoQQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", + "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", "cpu": [ "riscv64" ], @@ -1096,9 +1298,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.0.tgz", - "integrity": "sha512-Q9eh+gUGILIHEaJf66aF6a414jQbDnn29zeu0eX3dHMuysnhTvsUvZTCAyZ6tJhUjnvzBKE4FtuaYxutxRZpOg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", + "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", "cpu": [ "s390x" ], @@ -1110,9 +1312,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.0.tgz", - "integrity": "sha512-OR5p5yG5OKSxHReWmwvM0P+VTPMwoBS45PXTMYaskKQqybkS3Kmugq1W+YbNWArF8/s7jQScgzXUhArzEQ7x0A==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", + "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", "cpu": [ "x64" ], @@ -1124,9 +1326,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.0.tgz", - "integrity": "sha512-XeatKzo4lHDsVEbm1XDHZlhYZZSQYym6dg2X/Ko0kSFgio+KXLsxwJQprnR48GvdIKDOpqWqssC3iBCjoMcMpw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", + "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", "cpu": [ "x64" ], @@ -1138,9 +1340,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.0.tgz", - "integrity": "sha512-Lu71y78F5qOfYmubYLHPcJm74GZLU6UJ4THkf/a1K7Tz2ycwC2VUbsqbJAXaR6Bx70SRdlVrt2+n5l7F0agTUw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", + "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", "cpu": [ "x64" ], @@ -1152,9 +1354,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.0.tgz", - "integrity": "sha512-v5xwKDWcu7qhAEcsUubiav7r+48Uk/ENWdr82MBZZRIm7zThSxCIVDfb3ZeRRq9yqk+oIzMdDo6fCcA5DHfMyA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", + "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", "cpu": [ "arm64" ], @@ -1166,9 +1368,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.0.tgz", - "integrity": "sha512-XnaaaSMGSI6Wk8F4KK3QP7GfuuhjGchElsVerCplUuxRIzdvZ7hRBpLR0omCmw+kI2RFJB80nenhOoGXlJ5TfQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", + "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", "cpu": [ "arm64" ], @@ -1180,9 +1382,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.0.tgz", - "integrity": "sha512-3K1lP+3BXY4t4VihLw5MEg6IZD3ojSYzqzBG571W3kNQe4G4CcFpSUQVgurYgib5d+YaCjeFow8QivWp8vuSvA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", + "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", "cpu": [ "ia32" ], @@ -1194,9 +1396,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.0.tgz", - "integrity": "sha512-MDk610P/vJGc5L5ImE4k5s+GZT3en0KoK1MKPXCRgzmksAMk79j4h3k1IerxTNqwDLxsGxStEZVBqG0gIqZqoA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", + "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", "cpu": [ "x64" ], @@ -1208,9 +1410,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.0.tgz", - "integrity": "sha512-Zv7v6q6aV+VslnpwzqKAmrk5JdVkLUzok2208ZXGipjb+msxBr/fJPZyeEXiFgH7k62Ak0SLIfxQRZQvTuf7rQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", + "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", "cpu": [ "x64" ], @@ -1520,6 +1722,77 @@ "dev": true, "license": "MIT" }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/react": { + "version": "16.3.2", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", + "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@testing-library/user-event": { + "version": "14.6.1", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", + "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1527,6 +1800,92 @@ "dev": true, "license": "MIT" }, + "node_modules/@vitest/expect": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.9.tgz", + "integrity": "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", + "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.9.tgz", + "integrity": "sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "2.1.9", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.9.tgz", + "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.9.tgz", + "integrity": "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz", + "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@vue/reactivity": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.5.tgz", @@ -1544,10 +1903,20 @@ "dev": true, "license": "MIT" }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/alpinejs": { - "version": "3.15.5", - "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.15.5.tgz", - "integrity": "sha512-l1R4em/uCUr7eJimcO/b0L1+H2tVcB1Y7cQ3d+pzwVnv0zWs7gw4MhwdsLjfLccWV2iH0ahlfaJWitNRFOZdvQ==", + "version": "3.15.8", + "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.15.8.tgz", + "integrity": "sha512-zxIfCRTBGvF1CCLIOMQOxAyBuqibxSEwS6Jm1a3HGA9rgrJVcjEWlwLcQTVGAWGS8YhAsTRLVrtQ5a5QT9bSSQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1621,17 +1990,37 @@ "dev": true, "license": "MIT" }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, "license": "MIT" }, "node_modules/autoprefixer": { - "version": "10.4.23", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.23.tgz", - "integrity": "sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==", + "version": "10.4.24", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz", + "integrity": "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==", "dev": true, "funding": [ { @@ -1650,7 +2039,7 @@ "license": "MIT", "dependencies": { "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001760", + "caniuse-lite": "^1.0.30001766", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" @@ -1666,14 +2055,13 @@ } }, "node_modules/axios": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.4.tgz", - "integrity": "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==", - "dev": true, + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", + "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, @@ -1747,11 +2135,20 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -1761,6 +2158,22 @@ "node": ">= 0.4" } }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -1772,9 +2185,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001766", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz", - "integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==", + "version": "1.0.30001769", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz", + "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==", "dev": true, "funding": [ { @@ -1792,6 +2205,23 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1822,42 +2252,30 @@ "node": ">=8" } }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, "funding": { "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" } }, "node_modules/cliui": { @@ -1899,7 +2317,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" @@ -1956,16 +2373,105 @@ "node": ">=4" } }, + "node_modules/cssstyle": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cssstyle/node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -1990,11 +2496,18 @@ "dev": true, "license": "MIT" }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -2006,9 +2519,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.282", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.282.tgz", - "integrity": "sha512-FCPkJtpst28UmFzd903iU7PdeVTfY0KAeJy+Lk0GLZRwgwYHn/irRcaCbQQOmr5Vytc/7rcavsYLvTM8RiHYhQ==", + "version": "1.5.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", + "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", "dev": true, "license": "ISC" }, @@ -2020,24 +2533,36 @@ "license": "MIT" }, "node_modules/enhanced-resolve": { - "version": "5.18.4", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz", - "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "tapable": "^2.3.0" }, "engines": { "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -2047,17 +2572,22 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -2070,7 +2600,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -2083,9 +2612,9 @@ } }, "node_modules/esbuild": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", - "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2096,32 +2625,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.2", - "@esbuild/android-arm": "0.27.2", - "@esbuild/android-arm64": "0.27.2", - "@esbuild/android-x64": "0.27.2", - "@esbuild/darwin-arm64": "0.27.2", - "@esbuild/darwin-x64": "0.27.2", - "@esbuild/freebsd-arm64": "0.27.2", - "@esbuild/freebsd-x64": "0.27.2", - "@esbuild/linux-arm": "0.27.2", - "@esbuild/linux-arm64": "0.27.2", - "@esbuild/linux-ia32": "0.27.2", - "@esbuild/linux-loong64": "0.27.2", - "@esbuild/linux-mips64el": "0.27.2", - "@esbuild/linux-ppc64": "0.27.2", - "@esbuild/linux-riscv64": "0.27.2", - "@esbuild/linux-s390x": "0.27.2", - "@esbuild/linux-x64": "0.27.2", - "@esbuild/netbsd-arm64": "0.27.2", - "@esbuild/netbsd-x64": "0.27.2", - "@esbuild/openbsd-arm64": "0.27.2", - "@esbuild/openbsd-x64": "0.27.2", - "@esbuild/openharmony-arm64": "0.27.2", - "@esbuild/sunos-x64": "0.27.2", - "@esbuild/win32-arm64": "0.27.2", - "@esbuild/win32-ia32": "0.27.2", - "@esbuild/win32-x64": "0.27.2" + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" } }, "node_modules/escalade": { @@ -2134,6 +2663,26 @@ "node": ">=6" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -2209,7 +2758,6 @@ "version": "1.15.11", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "dev": true, "funding": [ { "type": "individual", @@ -2230,7 +2778,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -2257,6 +2804,33 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/framer-motion": { + "version": "12.34.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.34.0.tgz", + "integrity": "sha512-+/H49owhzkzQyxtn7nZeF4kdH++I2FWrESQ184Zbcw5cEqNHYkE5yxWxcTLSj5lNx3NWdbIRy5FHqUvetD8FWg==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.34.0", + "motion-utils": "^12.29.2", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -2276,7 +2850,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2296,7 +2869,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -2321,7 +2893,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -2348,7 +2919,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -2378,7 +2948,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -2391,7 +2960,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -2407,7 +2975,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -2416,6 +2983,60 @@ "node": ">= 0.4" } }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/immutable": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz", @@ -2495,6 +3116,13 @@ "node": ">=0.12.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, "node_modules/jiti": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", @@ -2505,6 +3133,55 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/jsdom": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", + "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssstyle": "^4.1.0", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, "node_modules/laravel-vite-plugin": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-2.1.0.tgz", @@ -2806,6 +3483,38 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "license": "MIT" + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -2820,7 +3529,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -2867,7 +3575,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -2877,7 +3584,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -2896,6 +3602,28 @@ "mini-svg-data-uri": "cli.js" } }, + "node_modules/motion-dom": { + "version": "12.34.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.34.0.tgz", + "integrity": "sha512-Lql3NuEcScRDxTAO6GgUsRHBZOWI/3fnMlkMcH5NftzcN37zJta+bpbMAV9px4Nj057TuvRooMK7QrzMCgtz6Q==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.29.2" + } + }, + "node_modules/motion-utils": { + "version": "12.29.2", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.29.2.tgz", + "integrity": "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -2952,6 +3680,19 @@ "node": ">=0.10.0" } }, + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==", + "license": "MIT" + }, + "node_modules/nwsapi": { + "version": "2.2.23", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", + "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", + "dev": true, + "license": "MIT" + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -2972,6 +3713,31 @@ "node": ">= 6" } }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -2979,6 +3745,23 @@ "dev": true, "license": "MIT" }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -3182,13 +3965,67 @@ "dev": true, "license": "MIT" }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true, "license": "MIT" }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -3210,6 +4047,35 @@ ], "license": "MIT" }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -3221,29 +4087,17 @@ } }, "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">= 14.18.0" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/require-directory": { @@ -3289,9 +4143,9 @@ } }, "node_modules/rollup": { - "version": "4.57.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.0.tgz", - "integrity": "sha512-e5lPJi/aui4TO1LpAXIRLySmwXSE8k3b9zoGfd42p67wzxog4WHjiZF3M2uheQih4DGyc25QEV4yRBbpueNiUA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", + "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", "dev": true, "license": "MIT", "dependencies": { @@ -3305,34 +4159,41 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.57.0", - "@rollup/rollup-android-arm64": "4.57.0", - "@rollup/rollup-darwin-arm64": "4.57.0", - "@rollup/rollup-darwin-x64": "4.57.0", - "@rollup/rollup-freebsd-arm64": "4.57.0", - "@rollup/rollup-freebsd-x64": "4.57.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.57.0", - "@rollup/rollup-linux-arm-musleabihf": "4.57.0", - "@rollup/rollup-linux-arm64-gnu": "4.57.0", - "@rollup/rollup-linux-arm64-musl": "4.57.0", - "@rollup/rollup-linux-loong64-gnu": "4.57.0", - "@rollup/rollup-linux-loong64-musl": "4.57.0", - "@rollup/rollup-linux-ppc64-gnu": "4.57.0", - "@rollup/rollup-linux-ppc64-musl": "4.57.0", - "@rollup/rollup-linux-riscv64-gnu": "4.57.0", - "@rollup/rollup-linux-riscv64-musl": "4.57.0", - "@rollup/rollup-linux-s390x-gnu": "4.57.0", - "@rollup/rollup-linux-x64-gnu": "4.57.0", - "@rollup/rollup-linux-x64-musl": "4.57.0", - "@rollup/rollup-openbsd-x64": "4.57.0", - "@rollup/rollup-openharmony-arm64": "4.57.0", - "@rollup/rollup-win32-arm64-msvc": "4.57.0", - "@rollup/rollup-win32-ia32-msvc": "4.57.0", - "@rollup/rollup-win32-x64-gnu": "4.57.0", - "@rollup/rollup-win32-x64-msvc": "4.57.0", + "@rollup/rollup-android-arm-eabi": "4.57.1", + "@rollup/rollup-android-arm64": "4.57.1", + "@rollup/rollup-darwin-arm64": "4.57.1", + "@rollup/rollup-darwin-x64": "4.57.1", + "@rollup/rollup-freebsd-arm64": "4.57.1", + "@rollup/rollup-freebsd-x64": "4.57.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", + "@rollup/rollup-linux-arm-musleabihf": "4.57.1", + "@rollup/rollup-linux-arm64-gnu": "4.57.1", + "@rollup/rollup-linux-arm64-musl": "4.57.1", + "@rollup/rollup-linux-loong64-gnu": "4.57.1", + "@rollup/rollup-linux-loong64-musl": "4.57.1", + "@rollup/rollup-linux-ppc64-gnu": "4.57.1", + "@rollup/rollup-linux-ppc64-musl": "4.57.1", + "@rollup/rollup-linux-riscv64-gnu": "4.57.1", + "@rollup/rollup-linux-riscv64-musl": "4.57.1", + "@rollup/rollup-linux-s390x-gnu": "4.57.1", + "@rollup/rollup-linux-x64-gnu": "4.57.1", + "@rollup/rollup-linux-x64-musl": "4.57.1", + "@rollup/rollup-openbsd-x64": "4.57.1", + "@rollup/rollup-openharmony-arm64": "4.57.1", + "@rollup/rollup-win32-arm64-msvc": "4.57.1", + "@rollup/rollup-win32-ia32-msvc": "4.57.1", + "@rollup/rollup-win32-x64-gnu": "4.57.1", + "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" } }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "dev": true, + "license": "MIT" + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -3367,6 +4228,13 @@ "tslib": "^2.1.0" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, "node_modules/sass": { "version": "1.97.3", "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz", @@ -3388,35 +4256,24 @@ "@parcel/watcher": "^2.4.1" } }, - "node_modules/sass/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "readdirp": "^4.0.1" + "xmlchars": "^2.2.0" }, "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "node": ">=v12.22.7" } }, - "node_modules/sass/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" }, "node_modules/shell-quote": { "version": "1.8.3", @@ -3431,6 +4288,85 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -3441,6 +4377,20 @@ "node": ">=0.10.0" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -3521,6 +4471,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, "node_modules/tailwindcss": { "version": "3.4.19", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", @@ -3559,6 +4516,44 @@ "node": ">=14.0.0" } }, + "node_modules/tailwindcss/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/tailwindcss/node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/tailwindcss/node_modules/jiti": { "version": "1.21.7", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", @@ -3569,6 +4564,32 @@ "jiti": "bin/jiti.js" } }, + "node_modules/tailwindcss/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tailwindcss/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/tapable": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", @@ -3606,6 +4627,20 @@ "node": ">=0.8" } }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -3623,6 +4658,56 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "dev": true, + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -3636,6 +4721,32 @@ "node": ">=8.0" } }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -3657,7 +4768,6 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, "license": "0BSD" }, "node_modules/update-browserslist-db": { @@ -3773,6 +4883,519 @@ } } }, + "node_modules/vite-node": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.9.tgz", + "integrity": "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", + "pathe": "^1.1.2", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite-node/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/vite-node/node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, "node_modules/vite-plugin-full-reload": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/vite-plugin-full-reload/-/vite-plugin-full-reload-1.2.0.tgz", @@ -3797,6 +5420,667 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/vitest": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.9.tgz", + "integrity": "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "2.1.9", + "@vitest/mocker": "2.1.9", + "@vitest/pretty-format": "^2.1.9", + "@vitest/runner": "2.1.9", + "@vitest/snapshot": "2.1.9", + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "debug": "^4.3.7", + "expect-type": "^1.1.0", + "magic-string": "^0.30.12", + "pathe": "^1.1.2", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0", + "vite-node": "2.1.9", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "2.1.9", + "@vitest/ui": "2.1.9", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@vitest/mocker": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.9.tgz", + "integrity": "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/vitest/node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -3815,6 +6099,45 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index cd519551..02c4dc52 100644 --- a/package.json +++ b/package.json @@ -4,19 +4,31 @@ "type": "module", "scripts": { "build": "vite build", - "dev": "vite" + "dev": "vite", + "test:ui": "vitest run" }, "devDependencies": { "@tailwindcss/forms": "^0.5.2", "@tailwindcss/vite": "^4.0.0", + "@testing-library/react": "^16.1.0", + "@testing-library/user-event": "^14.5.2", "alpinejs": "^3.4.2", "autoprefixer": "^10.4.2", "axios": "^1.11.0", "concurrently": "^9.0.1", + "jsdom": "^25.0.1", "laravel-vite-plugin": "^2.0.0", "postcss": "^8.4.31", + "sass": "^1.70.0", "tailwindcss": "^3.1.0", "vite": "^7.0.7", - "sass": "^1.70.0" + "vitest": "^2.1.8" + }, + "dependencies": { + "@inertiajs/core": "^1.0.4", + "@inertiajs/react": "^1.0.4", + "framer-motion": "^12.34.0", + "react": "^19.2.4", + "react-dom": "^19.2.4" } } diff --git a/public/avatar/1.jpg b/public/avatar/1.jpg new file mode 100644 index 00000000..7a061d02 Binary files /dev/null and b/public/avatar/1.jpg differ diff --git a/public/css/toolbar.css b/public/css/toolbar.css index 9224a6e1..fed756bd 100644 --- a/public/css/toolbar.css +++ b/public/css/toolbar.css @@ -564,7 +564,9 @@ subLoginMenu ul { margin:0; padding:0; height:50px; - background:rgba(30,30,30,0.2); + background:rgba(30,30,30,0.2); + -webkit-backdrop-filter: blur(4px); + backdrop-filter: blur(4px); } .nav>li.menu_notice>a { @@ -583,10 +585,12 @@ subLoginMenu ul { } .navbar-skinbase { - background:rgba(16, 25, 33, 0.9); - border-bottom:solid 1px #000; - box-shadow:0 0 14px #333; - z-index:1000; + background: rgba(16, 25, 33, 0.6); + -webkit-backdrop-filter: blur(6px); + backdrop-filter: blur(6px); + border-bottom:solid 1px #000; + box-shadow:0 0 14px #333; + z-index:1000; } .dropdown:hover .dropdown-menu { @@ -671,10 +675,12 @@ subLoginMenu ul { } .navbar-skinbase .dropdown-menu { - background:rgba(16, 25, 33, 0.9); - border-bottom:solid 1px #000; - box-shadow:0 0 14px #333; - color:#fff; + background: rgba(16, 25, 33, 0.6); + -webkit-backdrop-filter: blur(6px); + backdrop-filter: blur(6px); + border-bottom:solid 1px #000; + box-shadow:0 0 14px #333; + color:#fff; } diff --git a/public/gfx/120x60_basehead.jpg b/public/gfx/120x60_basehead.jpg deleted file mode 100644 index 332d06c4..00000000 Binary files a/public/gfx/120x60_basehead.jpg and /dev/null differ diff --git a/public/gfx/120x90_basehead.jpg b/public/gfx/120x90_basehead.jpg deleted file mode 100644 index 0e676b02..00000000 Binary files a/public/gfx/120x90_basehead.jpg and /dev/null differ diff --git a/public/gfx/2012_wishes.png b/public/gfx/2012_wishes.png deleted file mode 100644 index 23173d9c..00000000 Binary files a/public/gfx/2012_wishes.png and /dev/null differ diff --git a/public/gfx/5th/baner1.jpg b/public/gfx/5th/baner1.jpg deleted file mode 100644 index c6f8e65b..00000000 Binary files a/public/gfx/5th/baner1.jpg and /dev/null differ diff --git a/public/gfx/5th/baner2.jpg b/public/gfx/5th/baner2.jpg deleted file mode 100644 index 32d5f196..00000000 Binary files a/public/gfx/5th/baner2.jpg and /dev/null differ diff --git a/public/gfx/5th/resized.jpg b/public/gfx/5th/resized.jpg deleted file mode 100644 index 88002c46..00000000 Binary files a/public/gfx/5th/resized.jpg and /dev/null differ diff --git a/public/gfx/5th/sb1.jpg b/public/gfx/5th/sb1.jpg deleted file mode 100644 index 4864261b..00000000 Binary files a/public/gfx/5th/sb1.jpg and /dev/null differ diff --git a/public/gfx/5th/wallz.jpg b/public/gfx/5th/wallz.jpg deleted file mode 100644 index 9401828e..00000000 Binary files a/public/gfx/5th/wallz.jpg and /dev/null differ diff --git a/public/gfx/6th.jpg b/public/gfx/6th.jpg deleted file mode 100644 index c6000276..00000000 Binary files a/public/gfx/6th.jpg and /dev/null differ diff --git a/public/gfx/AddIndexView.jpg b/public/gfx/AddIndexView.jpg deleted file mode 100644 index 5c0f8fe1..00000000 Binary files a/public/gfx/AddIndexView.jpg and /dev/null differ diff --git a/public/gfx/Bar5.gif b/public/gfx/Bar5.gif deleted file mode 100644 index ffb92562..00000000 Binary files a/public/gfx/Bar5.gif and /dev/null differ diff --git a/public/gfx/Bar6.gif b/public/gfx/Bar6.gif deleted file mode 100644 index 4c4b7a0f..00000000 Binary files a/public/gfx/Bar6.gif and /dev/null differ diff --git a/public/gfx/Bar7.gif b/public/gfx/Bar7.gif deleted file mode 100644 index 0ce4605e..00000000 Binary files a/public/gfx/Bar7.gif and /dev/null differ diff --git a/public/gfx/BaseHeadArtLogo_2012_white.png b/public/gfx/BaseHeadArtLogo_2012_white.png deleted file mode 100644 index 75c2a0e5..00000000 Binary files a/public/gfx/BaseHeadArtLogo_2012_white.png and /dev/null differ diff --git a/public/gfx/CHRISTMASSkinBase2008.jpg b/public/gfx/CHRISTMASSkinBase2008.jpg deleted file mode 100644 index deb42f58..00000000 Binary files a/public/gfx/CHRISTMASSkinBase2008.jpg and /dev/null differ diff --git a/public/gfx/Christmas_Photos.jpg b/public/gfx/Christmas_Photos.jpg deleted file mode 100644 index 6d4107f3..00000000 Binary files a/public/gfx/Christmas_Photos.jpg and /dev/null differ diff --git a/public/gfx/Christmas_Photos_2008.jpg b/public/gfx/Christmas_Photos_2008.jpg deleted file mode 100644 index 117aec9f..00000000 Binary files a/public/gfx/Christmas_Photos_2008.jpg and /dev/null differ diff --git a/public/gfx/DG8.GIF b/public/gfx/DG8.GIF deleted file mode 100644 index 89b7cc84..00000000 Binary files a/public/gfx/DG8.GIF and /dev/null differ diff --git a/public/gfx/DailySkin.gif b/public/gfx/DailySkin.gif deleted file mode 100644 index b0721e6a..00000000 Binary files a/public/gfx/DailySkin.gif and /dev/null differ diff --git a/public/gfx/DailySkin.jpg b/public/gfx/DailySkin.jpg deleted file mode 100644 index a1a84838..00000000 Binary files a/public/gfx/DailySkin.jpg and /dev/null differ diff --git a/public/gfx/Easter.jpg b/public/gfx/Easter.jpg deleted file mode 100644 index 0b1bb68f..00000000 Binary files a/public/gfx/Easter.jpg and /dev/null differ diff --git a/public/gfx/EditForm.gif b/public/gfx/EditForm.gif deleted file mode 100644 index 0e83feb7..00000000 Binary files a/public/gfx/EditForm.gif and /dev/null differ diff --git a/public/gfx/HolidaysComplogo.jpg b/public/gfx/HolidaysComplogo.jpg deleted file mode 100644 index 499959a5..00000000 Binary files a/public/gfx/HolidaysComplogo.jpg and /dev/null differ diff --git a/public/gfx/IT.jpg b/public/gfx/IT.jpg deleted file mode 100644 index 2c9a6d82..00000000 Binary files a/public/gfx/IT.jpg and /dev/null differ diff --git a/public/gfx/Login.gif b/public/gfx/Login.gif deleted file mode 100644 index bff7284e..00000000 Binary files a/public/gfx/Login.gif and /dev/null differ diff --git a/public/gfx/Login.jpg b/public/gfx/Login.jpg deleted file mode 100644 index baeac4b0..00000000 Binary files a/public/gfx/Login.jpg and /dev/null differ diff --git a/public/gfx/MainLogo.jpg b/public/gfx/MainLogo.jpg deleted file mode 100644 index 78e7dbdf..00000000 Binary files a/public/gfx/MainLogo.jpg and /dev/null differ diff --git a/public/gfx/MainTop.gif b/public/gfx/MainTop.gif deleted file mode 100644 index 7bcc9842..00000000 Binary files a/public/gfx/MainTop.gif and /dev/null differ diff --git a/public/gfx/Menu.jpg b/public/gfx/Menu.jpg deleted file mode 100644 index 2a15416c..00000000 Binary files a/public/gfx/Menu.jpg and /dev/null differ diff --git a/public/gfx/MsgBoardBottom.gif b/public/gfx/MsgBoardBottom.gif deleted file mode 100644 index 523195d6..00000000 Binary files a/public/gfx/MsgBoardBottom.gif and /dev/null differ diff --git a/public/gfx/MsgBoardMiddle.gif b/public/gfx/MsgBoardMiddle.gif deleted file mode 100644 index 3bfb7da4..00000000 Binary files a/public/gfx/MsgBoardMiddle.gif and /dev/null differ diff --git a/public/gfx/MsgBoardTop.gif b/public/gfx/MsgBoardTop.gif deleted file mode 100644 index 7c1a4050..00000000 Binary files a/public/gfx/MsgBoardTop.gif and /dev/null differ diff --git a/public/gfx/RSDX90x30.gif b/public/gfx/RSDX90x30.gif deleted file mode 100644 index 9a570b10..00000000 Binary files a/public/gfx/RSDX90x30.gif and /dev/null differ diff --git a/public/gfx/SB2.jpg b/public/gfx/SB2.jpg deleted file mode 100644 index c8bf7687..00000000 Binary files a/public/gfx/SB2.jpg and /dev/null differ diff --git a/public/gfx/SBPro_Christmas.jpg b/public/gfx/SBPro_Christmas.jpg deleted file mode 100644 index 351c316e..00000000 Binary files a/public/gfx/SBPro_Christmas.jpg and /dev/null differ diff --git a/public/gfx/SKinBaseLogo.jpg b/public/gfx/SKinBaseLogo.jpg deleted file mode 100644 index f1c3e058..00000000 Binary files a/public/gfx/SKinBaseLogo.jpg and /dev/null differ diff --git a/public/gfx/Search.jpg b/public/gfx/Search.jpg deleted file mode 100644 index 01ed44b9..00000000 Binary files a/public/gfx/Search.jpg and /dev/null differ diff --git a/public/gfx/SignupForm.gif b/public/gfx/SignupForm.gif deleted file mode 100644 index 9ec804e6..00000000 Binary files a/public/gfx/SignupForm.gif and /dev/null differ diff --git a/public/gfx/SkinBase.jpg b/public/gfx/SkinBase.jpg deleted file mode 100644 index b18eaa79..00000000 Binary files a/public/gfx/SkinBase.jpg and /dev/null differ diff --git a/public/gfx/SkinBase001.jpg b/public/gfx/SkinBase001.jpg deleted file mode 100644 index 24032847..00000000 Binary files a/public/gfx/SkinBase001.jpg and /dev/null differ diff --git a/public/gfx/SkinBase002.jpg b/public/gfx/SkinBase002.jpg deleted file mode 100644 index 33a8ead4..00000000 Binary files a/public/gfx/SkinBase002.jpg and /dev/null differ diff --git a/public/gfx/SkinBase003.jpg b/public/gfx/SkinBase003.jpg deleted file mode 100644 index dcd0bd37..00000000 Binary files a/public/gfx/SkinBase003.jpg and /dev/null differ diff --git a/public/gfx/anniversary/sb_7th.jpg b/public/gfx/anniversary/sb_7th.jpg deleted file mode 100644 index 8adeb535..00000000 Binary files a/public/gfx/anniversary/sb_7th.jpg and /dev/null differ diff --git a/public/gfx/around.jpg b/public/gfx/around.jpg deleted file mode 100644 index 2c772491..00000000 Binary files a/public/gfx/around.jpg and /dev/null differ diff --git a/public/gfx/arrow-snow.gif b/public/gfx/arrow-snow.gif deleted file mode 100644 index e37d39e4..00000000 Binary files a/public/gfx/arrow-snow.gif and /dev/null differ diff --git a/public/gfx/back.jpg b/public/gfx/back.jpg deleted file mode 100644 index 6bfb9285..00000000 Binary files a/public/gfx/back.jpg and /dev/null differ diff --git a/public/gfx/background.gif b/public/gfx/background.gif deleted file mode 100644 index aa806df6..00000000 Binary files a/public/gfx/background.gif and /dev/null differ diff --git a/public/gfx/background.jpg b/public/gfx/background.jpg deleted file mode 100644 index dae1e3eb..00000000 Binary files a/public/gfx/background.jpg and /dev/null differ diff --git a/public/gfx/background2.gif b/public/gfx/background2.gif deleted file mode 100644 index a84e9418..00000000 Binary files a/public/gfx/background2.gif and /dev/null differ diff --git a/public/gfx/banner_profile.jpg b/public/gfx/banner_profile.jpg deleted file mode 100644 index 75fbfb82..00000000 Binary files a/public/gfx/banner_profile.jpg and /dev/null differ diff --git a/public/gfx/bar1.gif b/public/gfx/bar1.gif deleted file mode 100644 index ffb92562..00000000 Binary files a/public/gfx/bar1.gif and /dev/null differ diff --git a/public/gfx/bar2.gif b/public/gfx/bar2.gif deleted file mode 100644 index e6d3351a..00000000 Binary files a/public/gfx/bar2.gif and /dev/null differ diff --git a/public/gfx/bar3.gif b/public/gfx/bar3.gif deleted file mode 100644 index b88077eb..00000000 Binary files a/public/gfx/bar3.gif and /dev/null differ diff --git a/public/gfx/bar4.gif b/public/gfx/bar4.gif deleted file mode 100644 index b88077eb..00000000 Binary files a/public/gfx/bar4.gif and /dev/null differ diff --git a/public/gfx/bar8.gif b/public/gfx/bar8.gif deleted file mode 100644 index b1dd9627..00000000 Binary files a/public/gfx/bar8.gif and /dev/null differ diff --git a/public/gfx/bar9.gif b/public/gfx/bar9.gif deleted file mode 100644 index 63b82280..00000000 Binary files a/public/gfx/bar9.gif and /dev/null differ diff --git a/public/gfx/bars.jpg b/public/gfx/bars.jpg deleted file mode 100644 index 52c3f8c9..00000000 Binary files a/public/gfx/bars.jpg and /dev/null differ diff --git a/public/gfx/base.gif b/public/gfx/base.gif deleted file mode 100644 index 68e450f4..00000000 Binary files a/public/gfx/base.gif and /dev/null differ diff --git a/public/gfx/basket.gif b/public/gfx/basket.gif deleted file mode 100644 index 52c64728..00000000 Binary files a/public/gfx/basket.gif and /dev/null differ diff --git a/public/gfx/bell.gif b/public/gfx/bell.gif deleted file mode 100644 index 18db6289..00000000 Binary files a/public/gfx/bell.gif and /dev/null differ diff --git a/public/gfx/biglogo.gif b/public/gfx/biglogo.gif deleted file mode 100644 index 0d87e245..00000000 Binary files a/public/gfx/biglogo.gif and /dev/null differ diff --git a/public/gfx/blankDot.gif b/public/gfx/blankDot.gif deleted file mode 100644 index 35d42e80..00000000 Binary files a/public/gfx/blankDot.gif and /dev/null differ diff --git a/public/gfx/bottom.jpg b/public/gfx/bottom.jpg deleted file mode 100644 index dc76de6e..00000000 Binary files a/public/gfx/bottom.jpg and /dev/null differ diff --git a/public/gfx/buttons.jpg b/public/gfx/buttons.jpg deleted file mode 100644 index 0cebab75..00000000 Binary files a/public/gfx/buttons.jpg and /dev/null differ diff --git a/public/gfx/categories-button.png b/public/gfx/categories-button.png deleted file mode 100644 index b18b11df..00000000 Binary files a/public/gfx/categories-button.png and /dev/null differ diff --git a/public/gfx/categories-button_over.png b/public/gfx/categories-button_over.png deleted file mode 100644 index b1be2f8e..00000000 Binary files a/public/gfx/categories-button_over.png and /dev/null differ diff --git a/public/gfx/chat_back.png b/public/gfx/chat_back.png deleted file mode 100644 index 5559f209..00000000 Binary files a/public/gfx/chat_back.png and /dev/null differ diff --git a/public/gfx/chat_back2.png b/public/gfx/chat_back2.png deleted file mode 100644 index d7257f21..00000000 Binary files a/public/gfx/chat_back2.png and /dev/null differ diff --git a/public/gfx/chat_back2_hover.png b/public/gfx/chat_back2_hover.png deleted file mode 100644 index 29eea674..00000000 Binary files a/public/gfx/chat_back2_hover.png and /dev/null differ diff --git a/public/gfx/chat_back_hover.png b/public/gfx/chat_back_hover.png deleted file mode 100644 index 5636db20..00000000 Binary files a/public/gfx/chat_back_hover.png and /dev/null differ diff --git a/public/gfx/contest_advert.gif b/public/gfx/contest_advert.gif deleted file mode 100644 index 00e28a06..00000000 Binary files a/public/gfx/contest_advert.gif and /dev/null differ diff --git a/public/gfx/d2.jpg b/public/gfx/d2.jpg deleted file mode 100644 index 5cbf927b..00000000 Binary files a/public/gfx/d2.jpg and /dev/null differ diff --git a/public/gfx/devart-button-tech13.gif b/public/gfx/devart-button-tech13.gif deleted file mode 100644 index 55f3777c..00000000 Binary files a/public/gfx/devart-button-tech13.gif and /dev/null differ diff --git a/public/gfx/dew.jpg b/public/gfx/dew.jpg deleted file mode 100644 index 96b61d07..00000000 Binary files a/public/gfx/dew.jpg and /dev/null differ diff --git a/public/gfx/dl-arr.png b/public/gfx/dl-arr.png deleted file mode 100644 index f92e99f5..00000000 Binary files a/public/gfx/dl-arr.png and /dev/null differ diff --git a/public/gfx/down-arr.gif b/public/gfx/down-arr.gif deleted file mode 100644 index 2cd4801a..00000000 Binary files a/public/gfx/down-arr.gif and /dev/null differ diff --git a/public/gfx/dropdown_slice.png b/public/gfx/dropdown_slice.png deleted file mode 100644 index 9c4d402a..00000000 Binary files a/public/gfx/dropdown_slice.png and /dev/null differ diff --git a/public/gfx/ds_blcorner.png b/public/gfx/ds_blcorner.png deleted file mode 100644 index 44048b8d..00000000 --- a/public/gfx/ds_blcorner.png +++ /dev/null @@ -1,3 +0,0 @@ -PNG - -uL \ No newline at end of file diff --git a/public/gfx/ds_bottom.png b/public/gfx/ds_bottom.png deleted file mode 100644 index 49111df3..00000000 Binary files a/public/gfx/ds_bottom.png and /dev/null differ diff --git a/public/gfx/ds_brcorner.png b/public/gfx/ds_brcorner.png deleted file mode 100644 index dd51352e..00000000 Binary files a/public/gfx/ds_brcorner.png and /dev/null differ diff --git a/public/gfx/ds_left.png b/public/gfx/ds_left.png deleted file mode 100644 index bf917837..00000000 Binary files a/public/gfx/ds_left.png and /dev/null differ diff --git a/public/gfx/ds_right.png b/public/gfx/ds_right.png deleted file mode 100644 index 27277b9e..00000000 Binary files a/public/gfx/ds_right.png and /dev/null differ diff --git a/public/gfx/dtobutton.gif b/public/gfx/dtobutton.gif deleted file mode 100644 index 6b154537..00000000 Binary files a/public/gfx/dtobutton.gif and /dev/null differ diff --git a/public/gfx/error691.gif b/public/gfx/error691.gif deleted file mode 100644 index 3ae908d7..00000000 Binary files a/public/gfx/error691.gif and /dev/null differ diff --git a/public/gfx/fallen_angel.jpg b/public/gfx/fallen_angel.jpg deleted file mode 100644 index bbfe0a9e..00000000 Binary files a/public/gfx/fallen_angel.jpg and /dev/null differ diff --git a/public/gfx/fileman/fm_01.gif b/public/gfx/fileman/fm_01.gif deleted file mode 100644 index f558b329..00000000 Binary files a/public/gfx/fileman/fm_01.gif and /dev/null differ diff --git a/public/gfx/fileman/fm_02.gif b/public/gfx/fileman/fm_02.gif deleted file mode 100644 index d1a822ed..00000000 Binary files a/public/gfx/fileman/fm_02.gif and /dev/null differ diff --git a/public/gfx/fileman/fm_03.gif b/public/gfx/fileman/fm_03.gif deleted file mode 100644 index be873968..00000000 Binary files a/public/gfx/fileman/fm_03.gif and /dev/null differ diff --git a/public/gfx/fileman/fm_logo.gif b/public/gfx/fileman/fm_logo.gif deleted file mode 100644 index 5c363fc6..00000000 Binary files a/public/gfx/fileman/fm_logo.gif and /dev/null differ diff --git a/public/gfx/flags_old/ASEAN.gif b/public/gfx/flags_old/ASEAN.gif deleted file mode 100644 index 2c2e871a..00000000 Binary files a/public/gfx/flags_old/ASEAN.gif and /dev/null differ diff --git a/public/gfx/flags_old/Alderney.gif b/public/gfx/flags_old/Alderney.gif deleted file mode 100644 index afcec8b6..00000000 Binary files a/public/gfx/flags_old/Alderney.gif and /dev/null differ diff --git a/public/gfx/flags_old/Algeria.gif b/public/gfx/flags_old/Algeria.gif deleted file mode 100644 index 47f50ba4..00000000 Binary files a/public/gfx/flags_old/Algeria.gif and /dev/null differ diff --git a/public/gfx/flags_old/AmericanSamoa.gif b/public/gfx/flags_old/AmericanSamoa.gif deleted file mode 100644 index 5607e907..00000000 Binary files a/public/gfx/flags_old/AmericanSamoa.gif and /dev/null differ diff --git a/public/gfx/flags_old/Angola.gif b/public/gfx/flags_old/Angola.gif deleted file mode 100644 index 8c9b5728..00000000 Binary files a/public/gfx/flags_old/Angola.gif and /dev/null differ diff --git a/public/gfx/flags_old/Antarctica.gif b/public/gfx/flags_old/Antarctica.gif deleted file mode 100644 index f955d25c..00000000 Binary files a/public/gfx/flags_old/Antarctica.gif and /dev/null differ diff --git a/public/gfx/flags_old/AntiguaBarbuda.gif b/public/gfx/flags_old/AntiguaBarbuda.gif deleted file mode 100644 index 04a6745c..00000000 Binary files a/public/gfx/flags_old/AntiguaBarbuda.gif and /dev/null differ diff --git a/public/gfx/flags_old/ArabLeague.gif b/public/gfx/flags_old/ArabLeague.gif deleted file mode 100644 index d018b04c..00000000 Binary files a/public/gfx/flags_old/ArabLeague.gif and /dev/null differ diff --git a/public/gfx/flags_old/Armenia.gif b/public/gfx/flags_old/Armenia.gif deleted file mode 100644 index 01d6ccf0..00000000 Binary files a/public/gfx/flags_old/Armenia.gif and /dev/null differ diff --git a/public/gfx/flags_old/Azerbaijan.gif b/public/gfx/flags_old/Azerbaijan.gif deleted file mode 100644 index b240f5fa..00000000 Binary files a/public/gfx/flags_old/Azerbaijan.gif and /dev/null differ diff --git a/public/gfx/flags_old/Bahrain.gif b/public/gfx/flags_old/Bahrain.gif deleted file mode 100644 index c0995e14..00000000 Binary files a/public/gfx/flags_old/Bahrain.gif and /dev/null differ diff --git a/public/gfx/flags_old/Bangladesh.gif b/public/gfx/flags_old/Bangladesh.gif deleted file mode 100644 index 984ebcbe..00000000 Binary files a/public/gfx/flags_old/Bangladesh.gif and /dev/null differ diff --git a/public/gfx/flags_old/Belarus.gif b/public/gfx/flags_old/Belarus.gif deleted file mode 100644 index cf5f83df..00000000 Binary files a/public/gfx/flags_old/Belarus.gif and /dev/null differ diff --git a/public/gfx/flags_old/Belize.gif b/public/gfx/flags_old/Belize.gif deleted file mode 100644 index 1a78d5c5..00000000 Binary files a/public/gfx/flags_old/Belize.gif and /dev/null differ diff --git a/public/gfx/flags_old/Benin.gif b/public/gfx/flags_old/Benin.gif deleted file mode 100644 index d43dc2c0..00000000 Binary files a/public/gfx/flags_old/Benin.gif and /dev/null differ diff --git a/public/gfx/flags_old/Bhutan.gif b/public/gfx/flags_old/Bhutan.gif deleted file mode 100644 index c0869fa4..00000000 Binary files a/public/gfx/flags_old/Bhutan.gif and /dev/null differ diff --git a/public/gfx/flags_old/Bolivia.gif b/public/gfx/flags_old/Bolivia.gif deleted file mode 100644 index f6d4030d..00000000 Binary files a/public/gfx/flags_old/Bolivia.gif and /dev/null differ diff --git a/public/gfx/flags_old/Botswana.gif b/public/gfx/flags_old/Botswana.gif deleted file mode 100644 index c2f360c6..00000000 Binary files a/public/gfx/flags_old/Botswana.gif and /dev/null differ diff --git a/public/gfx/flags_old/Brunei.gif b/public/gfx/flags_old/Brunei.gif deleted file mode 100644 index 86cd4141..00000000 Binary files a/public/gfx/flags_old/Brunei.gif and /dev/null differ diff --git a/public/gfx/flags_old/BurkinaFaso.gif b/public/gfx/flags_old/BurkinaFaso.gif deleted file mode 100644 index d4f07dd2..00000000 Binary files a/public/gfx/flags_old/BurkinaFaso.gif and /dev/null differ diff --git a/public/gfx/flags_old/Burundi.gif b/public/gfx/flags_old/Burundi.gif deleted file mode 100644 index 0c4f5f2d..00000000 Binary files a/public/gfx/flags_old/Burundi.gif and /dev/null differ diff --git a/public/gfx/flags_old/Cameroon.gif b/public/gfx/flags_old/Cameroon.gif deleted file mode 100644 index 6a715a04..00000000 Binary files a/public/gfx/flags_old/Cameroon.gif and /dev/null differ diff --git a/public/gfx/flags_old/CapeVerde.gif b/public/gfx/flags_old/CapeVerde.gif deleted file mode 100644 index edd63786..00000000 Binary files a/public/gfx/flags_old/CapeVerde.gif and /dev/null differ diff --git a/public/gfx/flags_old/CentralAfricanRepublic.gif b/public/gfx/flags_old/CentralAfricanRepublic.gif deleted file mode 100644 index 9fd89927..00000000 Binary files a/public/gfx/flags_old/CentralAfricanRepublic.gif and /dev/null differ diff --git a/public/gfx/flags_old/Chad.gif b/public/gfx/flags_old/Chad.gif deleted file mode 100644 index d5a3539f..00000000 Binary files a/public/gfx/flags_old/Chad.gif and /dev/null differ diff --git a/public/gfx/flags_old/Comoros.gif b/public/gfx/flags_old/Comoros.gif deleted file mode 100644 index d7ff76c7..00000000 Binary files a/public/gfx/flags_old/Comoros.gif and /dev/null differ diff --git a/public/gfx/flags_old/Congo-Brazzaville.gif b/public/gfx/flags_old/Congo-Brazzaville.gif deleted file mode 100644 index 13b47def..00000000 Binary files a/public/gfx/flags_old/Congo-Brazzaville.gif and /dev/null differ diff --git a/public/gfx/flags_old/Congo-Kinshasa.gif b/public/gfx/flags_old/Congo-Kinshasa.gif deleted file mode 100644 index 31c1b22a..00000000 Binary files a/public/gfx/flags_old/Congo-Kinshasa.gif and /dev/null differ diff --git a/public/gfx/flags_old/CookIslands.gif b/public/gfx/flags_old/CookIslands.gif deleted file mode 100644 index 4db3ae26..00000000 Binary files a/public/gfx/flags_old/CookIslands.gif and /dev/null differ diff --git a/public/gfx/flags_old/Cuba.gif b/public/gfx/flags_old/Cuba.gif deleted file mode 100644 index 5cca3d5d..00000000 Binary files a/public/gfx/flags_old/Cuba.gif and /dev/null differ diff --git a/public/gfx/flags_old/Djibouti.gif b/public/gfx/flags_old/Djibouti.gif deleted file mode 100644 index 67354e35..00000000 Binary files a/public/gfx/flags_old/Djibouti.gif and /dev/null differ diff --git a/public/gfx/flags_old/Dominica.gif b/public/gfx/flags_old/Dominica.gif deleted file mode 100644 index fbce9fd7..00000000 Binary files a/public/gfx/flags_old/Dominica.gif and /dev/null differ diff --git a/public/gfx/flags_old/England.gif b/public/gfx/flags_old/England.gif deleted file mode 100644 index f1e668a9..00000000 Binary files a/public/gfx/flags_old/England.gif and /dev/null differ diff --git a/public/gfx/flags_old/EquatorialGuinea.gif b/public/gfx/flags_old/EquatorialGuinea.gif deleted file mode 100644 index 65f8f219..00000000 Binary files a/public/gfx/flags_old/EquatorialGuinea.gif and /dev/null differ diff --git a/public/gfx/flags_old/Eritrea.gif b/public/gfx/flags_old/Eritrea.gif deleted file mode 100644 index 2aa3b46c..00000000 Binary files a/public/gfx/flags_old/Eritrea.gif and /dev/null differ diff --git a/public/gfx/flags_old/Ethiopia.gif b/public/gfx/flags_old/Ethiopia.gif deleted file mode 100644 index 574db4fc..00000000 Binary files a/public/gfx/flags_old/Ethiopia.gif and /dev/null differ diff --git a/public/gfx/flags_old/FalklandIslands.gif b/public/gfx/flags_old/FalklandIslands.gif deleted file mode 100644 index ab671c65..00000000 Binary files a/public/gfx/flags_old/FalklandIslands.gif and /dev/null differ diff --git a/public/gfx/flags_old/Fiji.gif b/public/gfx/flags_old/Fiji.gif deleted file mode 100644 index 4198ffc6..00000000 Binary files a/public/gfx/flags_old/Fiji.gif and /dev/null differ diff --git a/public/gfx/flags_old/Gabon.gif b/public/gfx/flags_old/Gabon.gif deleted file mode 100644 index 7608d06a..00000000 Binary files a/public/gfx/flags_old/Gabon.gif and /dev/null differ diff --git a/public/gfx/flags_old/Ghana.gif b/public/gfx/flags_old/Ghana.gif deleted file mode 100644 index 842070dc..00000000 Binary files a/public/gfx/flags_old/Ghana.gif and /dev/null differ diff --git a/public/gfx/flags_old/Greenland.gif b/public/gfx/flags_old/Greenland.gif deleted file mode 100644 index 1c54b91e..00000000 Binary files a/public/gfx/flags_old/Greenland.gif and /dev/null differ diff --git a/public/gfx/flags_old/Guam.gif b/public/gfx/flags_old/Guam.gif deleted file mode 100644 index 0c4dd3a7..00000000 Binary files a/public/gfx/flags_old/Guam.gif and /dev/null differ diff --git a/public/gfx/flags_old/Guernsey.gif b/public/gfx/flags_old/Guernsey.gif deleted file mode 100644 index dfa8b964..00000000 Binary files a/public/gfx/flags_old/Guernsey.gif and /dev/null differ diff --git a/public/gfx/flags_old/Guinea-Bissau.gif b/public/gfx/flags_old/Guinea-Bissau.gif deleted file mode 100644 index d2ec67d7..00000000 Binary files a/public/gfx/flags_old/Guinea-Bissau.gif and /dev/null differ diff --git a/public/gfx/flags_old/Guinea.gif b/public/gfx/flags_old/Guinea.gif deleted file mode 100644 index 8cc33774..00000000 Binary files a/public/gfx/flags_old/Guinea.gif and /dev/null differ diff --git a/public/gfx/flags_old/Guyana.gif b/public/gfx/flags_old/Guyana.gif deleted file mode 100644 index fed54bab..00000000 Binary files a/public/gfx/flags_old/Guyana.gif and /dev/null differ diff --git a/public/gfx/flags_old/Haiti.gif b/public/gfx/flags_old/Haiti.gif deleted file mode 100644 index bfb23ad5..00000000 Binary files a/public/gfx/flags_old/Haiti.gif and /dev/null differ diff --git a/public/gfx/flags_old/Iran.gif b/public/gfx/flags_old/Iran.gif deleted file mode 100644 index 333c5b8e..00000000 Binary files a/public/gfx/flags_old/Iran.gif and /dev/null differ diff --git a/public/gfx/flags_old/Iraq.gif b/public/gfx/flags_old/Iraq.gif deleted file mode 100644 index 77c614ce..00000000 Binary files a/public/gfx/flags_old/Iraq.gif and /dev/null differ diff --git a/public/gfx/flags_old/Jamaica.gif b/public/gfx/flags_old/Jamaica.gif deleted file mode 100644 index e40a6ddc..00000000 Binary files a/public/gfx/flags_old/Jamaica.gif and /dev/null differ diff --git a/public/gfx/flags_old/Kazakhstan.gif b/public/gfx/flags_old/Kazakhstan.gif deleted file mode 100644 index 725225fe..00000000 Binary files a/public/gfx/flags_old/Kazakhstan.gif and /dev/null differ diff --git a/public/gfx/flags_old/Kiribati.gif b/public/gfx/flags_old/Kiribati.gif deleted file mode 100644 index f43875dd..00000000 Binary files a/public/gfx/flags_old/Kiribati.gif and /dev/null differ diff --git a/public/gfx/flags_old/Kuwait.gif b/public/gfx/flags_old/Kuwait.gif deleted file mode 100644 index 1d32076c..00000000 Binary files a/public/gfx/flags_old/Kuwait.gif and /dev/null differ diff --git a/public/gfx/flags_old/Kyrgyzstan.gif b/public/gfx/flags_old/Kyrgyzstan.gif deleted file mode 100644 index da9a6378..00000000 Binary files a/public/gfx/flags_old/Kyrgyzstan.gif and /dev/null differ diff --git a/public/gfx/flags_old/Laos.gif b/public/gfx/flags_old/Laos.gif deleted file mode 100644 index a9b7dfec..00000000 Binary files a/public/gfx/flags_old/Laos.gif and /dev/null differ diff --git a/public/gfx/flags_old/Lesotho.gif b/public/gfx/flags_old/Lesotho.gif deleted file mode 100644 index dcdf7786..00000000 Binary files a/public/gfx/flags_old/Lesotho.gif and /dev/null differ diff --git a/public/gfx/flags_old/Liberia.gif b/public/gfx/flags_old/Liberia.gif deleted file mode 100644 index 9d933cdb..00000000 Binary files a/public/gfx/flags_old/Liberia.gif and /dev/null differ diff --git a/public/gfx/flags_old/Libya.gif b/public/gfx/flags_old/Libya.gif deleted file mode 100644 index 35419c2d..00000000 Binary files a/public/gfx/flags_old/Libya.gif and /dev/null differ diff --git a/public/gfx/flags_old/Liechtenstein.gif b/public/gfx/flags_old/Liechtenstein.gif deleted file mode 100644 index dcdf7786..00000000 Binary files a/public/gfx/flags_old/Liechtenstein.gif and /dev/null differ diff --git a/public/gfx/flags_old/Macedonia.gif b/public/gfx/flags_old/Macedonia.gif deleted file mode 100644 index a5144e62..00000000 Binary files a/public/gfx/flags_old/Macedonia.gif and /dev/null differ diff --git a/public/gfx/flags_old/Madagascar.gif b/public/gfx/flags_old/Madagascar.gif deleted file mode 100644 index c0753172..00000000 Binary files a/public/gfx/flags_old/Madagascar.gif and /dev/null differ diff --git a/public/gfx/flags_old/Malawi.gif b/public/gfx/flags_old/Malawi.gif deleted file mode 100644 index 5047043a..00000000 Binary files a/public/gfx/flags_old/Malawi.gif and /dev/null differ diff --git a/public/gfx/flags_old/Maldives.gif b/public/gfx/flags_old/Maldives.gif deleted file mode 100644 index 355d0533..00000000 Binary files a/public/gfx/flags_old/Maldives.gif and /dev/null differ diff --git a/public/gfx/flags_old/Mali.gif b/public/gfx/flags_old/Mali.gif deleted file mode 100644 index fa9c8579..00000000 Binary files a/public/gfx/flags_old/Mali.gif and /dev/null differ diff --git a/public/gfx/flags_old/MarshallIslands.gif b/public/gfx/flags_old/MarshallIslands.gif deleted file mode 100644 index 7ef2fcce..00000000 Binary files a/public/gfx/flags_old/MarshallIslands.gif and /dev/null differ diff --git a/public/gfx/flags_old/Mauritania.gif b/public/gfx/flags_old/Mauritania.gif deleted file mode 100644 index 0228d036..00000000 Binary files a/public/gfx/flags_old/Mauritania.gif and /dev/null differ diff --git a/public/gfx/flags_old/Mauritius.gif b/public/gfx/flags_old/Mauritius.gif deleted file mode 100644 index ee587178..00000000 Binary files a/public/gfx/flags_old/Mauritius.gif and /dev/null differ diff --git a/public/gfx/flags_old/Moldova.gif b/public/gfx/flags_old/Moldova.gif deleted file mode 100644 index 25058558..00000000 Binary files a/public/gfx/flags_old/Moldova.gif and /dev/null differ diff --git a/public/gfx/flags_old/Mongolia.gif b/public/gfx/flags_old/Mongolia.gif deleted file mode 100644 index f0fc1c52..00000000 Binary files a/public/gfx/flags_old/Mongolia.gif and /dev/null differ diff --git a/public/gfx/flags_old/Morocco.gif b/public/gfx/flags_old/Morocco.gif deleted file mode 100644 index fcf5641b..00000000 Binary files a/public/gfx/flags_old/Morocco.gif and /dev/null differ diff --git a/public/gfx/flags_old/Mozambique.gif b/public/gfx/flags_old/Mozambique.gif deleted file mode 100644 index 9ed9febe..00000000 Binary files a/public/gfx/flags_old/Mozambique.gif and /dev/null differ diff --git a/public/gfx/flags_old/Myanmar.gif b/public/gfx/flags_old/Myanmar.gif deleted file mode 100644 index d908c353..00000000 Binary files a/public/gfx/flags_old/Myanmar.gif and /dev/null differ diff --git a/public/gfx/flags_old/Namibia.gif b/public/gfx/flags_old/Namibia.gif deleted file mode 100644 index 256b3333..00000000 Binary files a/public/gfx/flags_old/Namibia.gif and /dev/null differ diff --git a/public/gfx/flags_old/Nauru.gif b/public/gfx/flags_old/Nauru.gif deleted file mode 100644 index 4965f435..00000000 Binary files a/public/gfx/flags_old/Nauru.gif and /dev/null differ diff --git a/public/gfx/flags_old/Nicaragua.gif b/public/gfx/flags_old/Nicaragua.gif deleted file mode 100644 index b34e47e8..00000000 Binary files a/public/gfx/flags_old/Nicaragua.gif and /dev/null differ diff --git a/public/gfx/flags_old/Niger.gif b/public/gfx/flags_old/Niger.gif deleted file mode 100644 index 53ea0f04..00000000 Binary files a/public/gfx/flags_old/Niger.gif and /dev/null differ diff --git a/public/gfx/flags_old/Nigeria.gif b/public/gfx/flags_old/Nigeria.gif deleted file mode 100644 index 7db5fe3a..00000000 Binary files a/public/gfx/flags_old/Nigeria.gif and /dev/null differ diff --git a/public/gfx/flags_old/NorthKorea.gif b/public/gfx/flags_old/NorthKorea.gif deleted file mode 100644 index f77e38a9..00000000 Binary files a/public/gfx/flags_old/NorthKorea.gif and /dev/null differ diff --git a/public/gfx/flags_old/NorthernCyprus.gif b/public/gfx/flags_old/NorthernCyprus.gif deleted file mode 100644 index 66545484..00000000 Binary files a/public/gfx/flags_old/NorthernCyprus.gif and /dev/null differ diff --git a/public/gfx/flags_old/Oman.gif b/public/gfx/flags_old/Oman.gif deleted file mode 100644 index 299be54c..00000000 Binary files a/public/gfx/flags_old/Oman.gif and /dev/null differ diff --git a/public/gfx/flags_old/Palestine.gif b/public/gfx/flags_old/Palestine.gif deleted file mode 100644 index 1ddd4c7a..00000000 Binary files a/public/gfx/flags_old/Palestine.gif and /dev/null differ diff --git a/public/gfx/flags_old/Panama.gif b/public/gfx/flags_old/Panama.gif deleted file mode 100644 index 5ad58b0d..00000000 Binary files a/public/gfx/flags_old/Panama.gif and /dev/null differ diff --git a/public/gfx/flags_old/PapuaNewGuinea.gif b/public/gfx/flags_old/PapuaNewGuinea.gif deleted file mode 100644 index 9e7842c5..00000000 Binary files a/public/gfx/flags_old/PapuaNewGuinea.gif and /dev/null differ diff --git a/public/gfx/flags_old/Qatar.gif b/public/gfx/flags_old/Qatar.gif deleted file mode 100644 index 6abd44d1..00000000 Binary files a/public/gfx/flags_old/Qatar.gif and /dev/null differ diff --git a/public/gfx/flags_old/RussianFederation.gif b/public/gfx/flags_old/RussianFederation.gif deleted file mode 100644 index b1ec8683..00000000 Binary files a/public/gfx/flags_old/RussianFederation.gif and /dev/null differ diff --git a/public/gfx/flags_old/Rwanda.gif b/public/gfx/flags_old/Rwanda.gif deleted file mode 100644 index 69d700c3..00000000 Binary files a/public/gfx/flags_old/Rwanda.gif and /dev/null differ diff --git a/public/gfx/flags_old/SaintLucia.gif b/public/gfx/flags_old/SaintLucia.gif deleted file mode 100644 index 098649b0..00000000 Binary files a/public/gfx/flags_old/SaintLucia.gif and /dev/null differ diff --git a/public/gfx/flags_old/Samoa.gif b/public/gfx/flags_old/Samoa.gif deleted file mode 100644 index 958844ac..00000000 Binary files a/public/gfx/flags_old/Samoa.gif and /dev/null differ diff --git a/public/gfx/flags_old/Senegal.gif b/public/gfx/flags_old/Senegal.gif deleted file mode 100644 index 9e7120e8..00000000 Binary files a/public/gfx/flags_old/Senegal.gif and /dev/null differ diff --git a/public/gfx/flags_old/Seychelles.gif b/public/gfx/flags_old/Seychelles.gif deleted file mode 100644 index be3ee4a4..00000000 Binary files a/public/gfx/flags_old/Seychelles.gif and /dev/null differ diff --git a/public/gfx/flags_old/SierraLeone.gif b/public/gfx/flags_old/SierraLeone.gif deleted file mode 100644 index 68f1029a..00000000 Binary files a/public/gfx/flags_old/SierraLeone.gif and /dev/null differ diff --git a/public/gfx/flags_old/SolomonIslands.gif b/public/gfx/flags_old/SolomonIslands.gif deleted file mode 100644 index 6a0d6218..00000000 Binary files a/public/gfx/flags_old/SolomonIslands.gif and /dev/null differ diff --git a/public/gfx/flags_old/Somalia.gif b/public/gfx/flags_old/Somalia.gif deleted file mode 100644 index 6d799222..00000000 Binary files a/public/gfx/flags_old/Somalia.gif and /dev/null differ diff --git a/public/gfx/flags_old/Suriname.gif b/public/gfx/flags_old/Suriname.gif deleted file mode 100644 index d263268b..00000000 Binary files a/public/gfx/flags_old/Suriname.gif and /dev/null differ diff --git a/public/gfx/flags_old/Swaziland.gif b/public/gfx/flags_old/Swaziland.gif deleted file mode 100644 index 7e5dfe44..00000000 Binary files a/public/gfx/flags_old/Swaziland.gif and /dev/null differ diff --git a/public/gfx/flags_old/Syria.gif b/public/gfx/flags_old/Syria.gif deleted file mode 100644 index 17f0b7e1..00000000 Binary files a/public/gfx/flags_old/Syria.gif and /dev/null differ diff --git a/public/gfx/flags_old/Tajikistan.gif b/public/gfx/flags_old/Tajikistan.gif deleted file mode 100644 index 31f5eb74..00000000 Binary files a/public/gfx/flags_old/Tajikistan.gif and /dev/null differ diff --git a/public/gfx/flags_old/Tanzania.gif b/public/gfx/flags_old/Tanzania.gif deleted file mode 100644 index 0ba90690..00000000 Binary files a/public/gfx/flags_old/Tanzania.gif and /dev/null differ diff --git a/public/gfx/flags_old/TheFaroes.gif b/public/gfx/flags_old/TheFaroes.gif deleted file mode 100644 index 5ad83bea..00000000 Binary files a/public/gfx/flags_old/TheFaroes.gif and /dev/null differ diff --git a/public/gfx/flags_old/TheGambia.gif b/public/gfx/flags_old/TheGambia.gif deleted file mode 100644 index d44c03ac..00000000 Binary files a/public/gfx/flags_old/TheGambia.gif and /dev/null differ diff --git a/public/gfx/flags_old/TheSudan.gif b/public/gfx/flags_old/TheSudan.gif deleted file mode 100644 index 1a3f6d91..00000000 Binary files a/public/gfx/flags_old/TheSudan.gif and /dev/null differ diff --git a/public/gfx/flags_old/Tibet.gif b/public/gfx/flags_old/Tibet.gif deleted file mode 100644 index 4767bcfb..00000000 Binary files a/public/gfx/flags_old/Tibet.gif and /dev/null differ diff --git a/public/gfx/flags_old/Timor-Leste.gif b/public/gfx/flags_old/Timor-Leste.gif deleted file mode 100644 index 1451c967..00000000 Binary files a/public/gfx/flags_old/Timor-Leste.gif and /dev/null differ diff --git a/public/gfx/flags_old/Togo.gif b/public/gfx/flags_old/Togo.gif deleted file mode 100644 index 4f078644..00000000 Binary files a/public/gfx/flags_old/Togo.gif and /dev/null differ diff --git a/public/gfx/flags_old/Tunisia.gif b/public/gfx/flags_old/Tunisia.gif deleted file mode 100644 index c1b0b3d6..00000000 Binary files a/public/gfx/flags_old/Tunisia.gif and /dev/null differ diff --git a/public/gfx/flags_old/Turkmenistan.gif b/public/gfx/flags_old/Turkmenistan.gif deleted file mode 100644 index 33c91424..00000000 Binary files a/public/gfx/flags_old/Turkmenistan.gif and /dev/null differ diff --git a/public/gfx/flags_old/Uganda.gif b/public/gfx/flags_old/Uganda.gif deleted file mode 100644 index b0726bfe..00000000 Binary files a/public/gfx/flags_old/Uganda.gif and /dev/null differ diff --git a/public/gfx/flags_old/Ukraine.gif b/public/gfx/flags_old/Ukraine.gif deleted file mode 100644 index 05fcaa57..00000000 Binary files a/public/gfx/flags_old/Ukraine.gif and /dev/null differ diff --git a/public/gfx/flags_old/UnitedArabEmirates.gif b/public/gfx/flags_old/UnitedArabEmirates.gif deleted file mode 100644 index 84165ef6..00000000 Binary files a/public/gfx/flags_old/UnitedArabEmirates.gif and /dev/null differ diff --git a/public/gfx/flags_old/Uzbekistan.gif b/public/gfx/flags_old/Uzbekistan.gif deleted file mode 100644 index 5737325a..00000000 Binary files a/public/gfx/flags_old/Uzbekistan.gif and /dev/null differ diff --git a/public/gfx/flags_old/Vanuatu.gif b/public/gfx/flags_old/Vanuatu.gif deleted file mode 100644 index 27e63bcf..00000000 Binary files a/public/gfx/flags_old/Vanuatu.gif and /dev/null differ diff --git a/public/gfx/flags_old/Wales.gif b/public/gfx/flags_old/Wales.gif deleted file mode 100644 index 264a357c..00000000 Binary files a/public/gfx/flags_old/Wales.gif and /dev/null differ diff --git a/public/gfx/flags_old/WesternSahara.gif b/public/gfx/flags_old/WesternSahara.gif deleted file mode 100644 index 29bc51d7..00000000 Binary files a/public/gfx/flags_old/WesternSahara.gif and /dev/null differ diff --git a/public/gfx/flags_old/Yemen.gif b/public/gfx/flags_old/Yemen.gif deleted file mode 100644 index 3ea076a7..00000000 Binary files a/public/gfx/flags_old/Yemen.gif and /dev/null differ diff --git a/public/gfx/flags_old/Zimbabwe.gif b/public/gfx/flags_old/Zimbabwe.gif deleted file mode 100644 index 88c2ce86..00000000 Binary files a/public/gfx/flags_old/Zimbabwe.gif and /dev/null differ diff --git a/public/gfx/flags_old/afganistan.gif b/public/gfx/flags_old/afganistan.gif deleted file mode 100644 index cf012b8b..00000000 Binary files a/public/gfx/flags_old/afganistan.gif and /dev/null differ diff --git a/public/gfx/flags_old/andora.gif b/public/gfx/flags_old/andora.gif deleted file mode 100644 index 439560f2..00000000 Binary files a/public/gfx/flags_old/andora.gif and /dev/null differ diff --git a/public/gfx/flags_old/anguilla.gif b/public/gfx/flags_old/anguilla.gif deleted file mode 100644 index 5019fd35..00000000 Binary files a/public/gfx/flags_old/anguilla.gif and /dev/null differ diff --git a/public/gfx/flags_old/antigua.gif b/public/gfx/flags_old/antigua.gif deleted file mode 100644 index 04a6745c..00000000 Binary files a/public/gfx/flags_old/antigua.gif and /dev/null differ diff --git a/public/gfx/flags_old/arabemirates.gif b/public/gfx/flags_old/arabemirates.gif deleted file mode 100644 index 84165ef6..00000000 Binary files a/public/gfx/flags_old/arabemirates.gif and /dev/null differ diff --git a/public/gfx/flags_old/argentina.gif b/public/gfx/flags_old/argentina.gif deleted file mode 100644 index 7ed1634d..00000000 Binary files a/public/gfx/flags_old/argentina.gif and /dev/null differ diff --git a/public/gfx/flags_old/aruba.gif b/public/gfx/flags_old/aruba.gif deleted file mode 100644 index c4e0af7f..00000000 Binary files a/public/gfx/flags_old/aruba.gif and /dev/null differ diff --git a/public/gfx/flags_old/avstralija.gif b/public/gfx/flags_old/avstralija.gif deleted file mode 100644 index 8c218dd1..00000000 Binary files a/public/gfx/flags_old/avstralija.gif and /dev/null differ diff --git a/public/gfx/flags_old/avstrija.gif b/public/gfx/flags_old/avstrija.gif deleted file mode 100644 index 5bda9ca8..00000000 Binary files a/public/gfx/flags_old/avstrija.gif and /dev/null differ diff --git a/public/gfx/flags_old/bahamasa.gif b/public/gfx/flags_old/bahamasa.gif deleted file mode 100644 index 2f560964..00000000 Binary files a/public/gfx/flags_old/bahamasa.gif and /dev/null differ diff --git a/public/gfx/flags_old/barbados.gif b/public/gfx/flags_old/barbados.gif deleted file mode 100644 index c694a521..00000000 Binary files a/public/gfx/flags_old/barbados.gif and /dev/null differ diff --git a/public/gfx/flags_old/belgija.gif b/public/gfx/flags_old/belgija.gif deleted file mode 100644 index 780ca480..00000000 Binary files a/public/gfx/flags_old/belgija.gif and /dev/null differ diff --git a/public/gfx/flags_old/bermuda.gif b/public/gfx/flags_old/bermuda.gif deleted file mode 100644 index 279fa0bd..00000000 Binary files a/public/gfx/flags_old/bermuda.gif and /dev/null differ diff --git a/public/gfx/flags_old/bolgarija.gif b/public/gfx/flags_old/bolgarija.gif deleted file mode 100644 index cf00b114..00000000 Binary files a/public/gfx/flags_old/bolgarija.gif and /dev/null differ diff --git a/public/gfx/flags_old/bosna.gif b/public/gfx/flags_old/bosna.gif deleted file mode 100644 index a0755bb9..00000000 Binary files a/public/gfx/flags_old/bosna.gif and /dev/null differ diff --git a/public/gfx/flags_old/brazilija.gif b/public/gfx/flags_old/brazilija.gif deleted file mode 100644 index a6f172be..00000000 Binary files a/public/gfx/flags_old/brazilija.gif and /dev/null differ diff --git a/public/gfx/flags_old/cambodia.gif b/public/gfx/flags_old/cambodia.gif deleted file mode 100644 index 27b02162..00000000 Binary files a/public/gfx/flags_old/cambodia.gif and /dev/null differ diff --git a/public/gfx/flags_old/caribbean.gif b/public/gfx/flags_old/caribbean.gif deleted file mode 100644 index 098649b0..00000000 Binary files a/public/gfx/flags_old/caribbean.gif and /dev/null differ diff --git a/public/gfx/flags_old/cayman.gif b/public/gfx/flags_old/cayman.gif deleted file mode 100644 index 1693f730..00000000 Binary files a/public/gfx/flags_old/cayman.gif and /dev/null differ diff --git a/public/gfx/flags_old/ceska.gif b/public/gfx/flags_old/ceska.gif deleted file mode 100644 index e3cfbf59..00000000 Binary files a/public/gfx/flags_old/ceska.gif and /dev/null differ diff --git a/public/gfx/flags_old/chile.gif b/public/gfx/flags_old/chile.gif deleted file mode 100644 index c285b6e1..00000000 Binary files a/public/gfx/flags_old/chile.gif and /dev/null differ diff --git a/public/gfx/flags_old/china.gif b/public/gfx/flags_old/china.gif deleted file mode 100644 index 565e97b0..00000000 Binary files a/public/gfx/flags_old/china.gif and /dev/null differ diff --git a/public/gfx/flags_old/ciper.gif b/public/gfx/flags_old/ciper.gif deleted file mode 100644 index dec296f0..00000000 Binary files a/public/gfx/flags_old/ciper.gif and /dev/null differ diff --git a/public/gfx/flags_old/congo.gif b/public/gfx/flags_old/congo.gif deleted file mode 100644 index 13b47def..00000000 Binary files a/public/gfx/flags_old/congo.gif and /dev/null differ diff --git a/public/gfx/flags_old/costarica.gif b/public/gfx/flags_old/costarica.gif deleted file mode 100644 index a8f7d5f7..00000000 Binary files a/public/gfx/flags_old/costarica.gif and /dev/null differ diff --git a/public/gfx/flags_old/denmark.gif b/public/gfx/flags_old/denmark.gif deleted file mode 100644 index b7d17c01..00000000 Binary files a/public/gfx/flags_old/denmark.gif and /dev/null differ diff --git a/public/gfx/flags_old/diminicanrepublic.gif b/public/gfx/flags_old/diminicanrepublic.gif deleted file mode 100644 index d6d1598e..00000000 Binary files a/public/gfx/flags_old/diminicanrepublic.gif and /dev/null differ diff --git a/public/gfx/flags_old/dominican.gif b/public/gfx/flags_old/dominican.gif deleted file mode 100644 index d6d1598e..00000000 Binary files a/public/gfx/flags_old/dominican.gif and /dev/null differ diff --git a/public/gfx/flags_old/egipt.gif b/public/gfx/flags_old/egipt.gif deleted file mode 100644 index 97fe50d0..00000000 Binary files a/public/gfx/flags_old/egipt.gif and /dev/null differ diff --git a/public/gfx/flags_old/ekvador.gif b/public/gfx/flags_old/ekvador.gif deleted file mode 100644 index 6f38968d..00000000 Binary files a/public/gfx/flags_old/ekvador.gif and /dev/null differ diff --git a/public/gfx/flags_old/elsavlador.gif b/public/gfx/flags_old/elsavlador.gif deleted file mode 100644 index ac0e9301..00000000 Binary files a/public/gfx/flags_old/elsavlador.gif and /dev/null differ diff --git a/public/gfx/flags_old/estonia.gif b/public/gfx/flags_old/estonia.gif deleted file mode 100644 index e89c959f..00000000 Binary files a/public/gfx/flags_old/estonia.gif and /dev/null differ diff --git a/public/gfx/flags_old/filipini.gif b/public/gfx/flags_old/filipini.gif deleted file mode 100644 index e3741c76..00000000 Binary files a/public/gfx/flags_old/filipini.gif and /dev/null differ diff --git a/public/gfx/flags_old/finska.gif b/public/gfx/flags_old/finska.gif deleted file mode 100644 index 0cfa6345..00000000 Binary files a/public/gfx/flags_old/finska.gif and /dev/null differ diff --git a/public/gfx/flags_old/france.gif b/public/gfx/flags_old/france.gif deleted file mode 100644 index 47d9241f..00000000 Binary files a/public/gfx/flags_old/france.gif and /dev/null differ diff --git a/public/gfx/flags_old/francija.gif b/public/gfx/flags_old/francija.gif deleted file mode 100644 index 47d9241f..00000000 Binary files a/public/gfx/flags_old/francija.gif and /dev/null differ diff --git a/public/gfx/flags_old/georgia.gif b/public/gfx/flags_old/georgia.gif deleted file mode 100644 index 95296729..00000000 Binary files a/public/gfx/flags_old/georgia.gif and /dev/null differ diff --git a/public/gfx/flags_old/gibraltar.gif b/public/gfx/flags_old/gibraltar.gif deleted file mode 100644 index 7c52c0ed..00000000 Binary files a/public/gfx/flags_old/gibraltar.gif and /dev/null differ diff --git a/public/gfx/flags_old/grcija.gif b/public/gfx/flags_old/grcija.gif deleted file mode 100644 index f03bb67e..00000000 Binary files a/public/gfx/flags_old/grcija.gif and /dev/null differ diff --git a/public/gfx/flags_old/grenada.gif b/public/gfx/flags_old/grenada.gif deleted file mode 100644 index 8ff562bb..00000000 Binary files a/public/gfx/flags_old/grenada.gif and /dev/null differ diff --git a/public/gfx/flags_old/guatemala.gif b/public/gfx/flags_old/guatemala.gif deleted file mode 100644 index ad97d0ea..00000000 Binary files a/public/gfx/flags_old/guatemala.gif and /dev/null differ diff --git a/public/gfx/flags_old/honduras.gif b/public/gfx/flags_old/honduras.gif deleted file mode 100644 index 97a2ac28..00000000 Binary files a/public/gfx/flags_old/honduras.gif and /dev/null differ diff --git a/public/gfx/flags_old/hong.gif b/public/gfx/flags_old/hong.gif deleted file mode 100644 index dd60a876..00000000 Binary files a/public/gfx/flags_old/hong.gif and /dev/null differ diff --git a/public/gfx/flags_old/hrvaska.gif b/public/gfx/flags_old/hrvaska.gif deleted file mode 100644 index b2dc367a..00000000 Binary files a/public/gfx/flags_old/hrvaska.gif and /dev/null differ diff --git a/public/gfx/flags_old/hungary.gif b/public/gfx/flags_old/hungary.gif deleted file mode 100644 index c801d247..00000000 Binary files a/public/gfx/flags_old/hungary.gif and /dev/null differ diff --git a/public/gfx/flags_old/iceland.gif b/public/gfx/flags_old/iceland.gif deleted file mode 100644 index 02b46560..00000000 Binary files a/public/gfx/flags_old/iceland.gif and /dev/null differ diff --git a/public/gfx/flags_old/indija.gif b/public/gfx/flags_old/indija.gif deleted file mode 100644 index 2a154db8..00000000 Binary files a/public/gfx/flags_old/indija.gif and /dev/null differ diff --git a/public/gfx/flags_old/indonesia.gif b/public/gfx/flags_old/indonesia.gif deleted file mode 100644 index e3639a6f..00000000 Binary files a/public/gfx/flags_old/indonesia.gif and /dev/null differ diff --git a/public/gfx/flags_old/irska.gif b/public/gfx/flags_old/irska.gif deleted file mode 100644 index 693001e6..00000000 Binary files a/public/gfx/flags_old/irska.gif and /dev/null differ diff --git a/public/gfx/flags_old/italija.gif b/public/gfx/flags_old/italija.gif deleted file mode 100644 index 3ac944ed..00000000 Binary files a/public/gfx/flags_old/italija.gif and /dev/null differ diff --git a/public/gfx/flags_old/ivorycoast.gif b/public/gfx/flags_old/ivorycoast.gif deleted file mode 100644 index 63b96e9d..00000000 Binary files a/public/gfx/flags_old/ivorycoast.gif and /dev/null differ diff --git a/public/gfx/flags_old/izrael.gif b/public/gfx/flags_old/izrael.gif deleted file mode 100644 index ce011927..00000000 Binary files a/public/gfx/flags_old/izrael.gif and /dev/null differ diff --git a/public/gfx/flags_old/jafrika.gif b/public/gfx/flags_old/jafrika.gif deleted file mode 100644 index b6fbde9e..00000000 Binary files a/public/gfx/flags_old/jafrika.gif and /dev/null differ diff --git a/public/gfx/flags_old/jamajka.gif b/public/gfx/flags_old/jamajka.gif deleted file mode 100644 index e40a6ddc..00000000 Binary files a/public/gfx/flags_old/jamajka.gif and /dev/null differ diff --git a/public/gfx/flags_old/japonska.gif b/public/gfx/flags_old/japonska.gif deleted file mode 100644 index 1e08360f..00000000 Binary files a/public/gfx/flags_old/japonska.gif and /dev/null differ diff --git a/public/gfx/flags_old/jkoreja.gif b/public/gfx/flags_old/jkoreja.gif deleted file mode 100644 index 4046562b..00000000 Binary files a/public/gfx/flags_old/jkoreja.gif and /dev/null differ diff --git a/public/gfx/flags_old/jordan.gif b/public/gfx/flags_old/jordan.gif deleted file mode 100644 index 9ba220f1..00000000 Binary files a/public/gfx/flags_old/jordan.gif and /dev/null differ diff --git a/public/gfx/flags_old/jugoslavija.gif b/public/gfx/flags_old/jugoslavija.gif deleted file mode 100644 index e5cd29e9..00000000 Binary files a/public/gfx/flags_old/jugoslavija.gif and /dev/null differ diff --git a/public/gfx/flags_old/kanada.gif b/public/gfx/flags_old/kanada.gif deleted file mode 100644 index fce2cd99..00000000 Binary files a/public/gfx/flags_old/kanada.gif and /dev/null differ diff --git a/public/gfx/flags_old/kenya.gif b/public/gfx/flags_old/kenya.gif deleted file mode 100644 index 29b370ce..00000000 Binary files a/public/gfx/flags_old/kenya.gif and /dev/null differ diff --git a/public/gfx/flags_old/kolumbija.gif b/public/gfx/flags_old/kolumbija.gif deleted file mode 100644 index 2b154a9c..00000000 Binary files a/public/gfx/flags_old/kolumbija.gif and /dev/null differ diff --git a/public/gfx/flags_old/latvia.gif b/public/gfx/flags_old/latvia.gif deleted file mode 100644 index ceb1ed23..00000000 Binary files a/public/gfx/flags_old/latvia.gif and /dev/null differ diff --git a/public/gfx/flags_old/lebanon.gif b/public/gfx/flags_old/lebanon.gif deleted file mode 100644 index c76126b6..00000000 Binary files a/public/gfx/flags_old/lebanon.gif and /dev/null differ diff --git a/public/gfx/flags_old/lithuania.gif b/public/gfx/flags_old/lithuania.gif deleted file mode 100644 index 6af4425f..00000000 Binary files a/public/gfx/flags_old/lithuania.gif and /dev/null differ diff --git a/public/gfx/flags_old/luksemburg.gif b/public/gfx/flags_old/luksemburg.gif deleted file mode 100644 index 232095af..00000000 Binary files a/public/gfx/flags_old/luksemburg.gif and /dev/null differ diff --git a/public/gfx/flags_old/macau.gif b/public/gfx/flags_old/macau.gif deleted file mode 100644 index 512138a6..00000000 Binary files a/public/gfx/flags_old/macau.gif and /dev/null differ diff --git a/public/gfx/flags_old/malasyia.gif b/public/gfx/flags_old/malasyia.gif deleted file mode 100644 index 6d7cf6ce..00000000 Binary files a/public/gfx/flags_old/malasyia.gif and /dev/null differ diff --git a/public/gfx/flags_old/malaysia.gif b/public/gfx/flags_old/malaysia.gif deleted file mode 100644 index 6d7cf6ce..00000000 Binary files a/public/gfx/flags_old/malaysia.gif and /dev/null differ diff --git a/public/gfx/flags_old/malta.gif b/public/gfx/flags_old/malta.gif deleted file mode 100644 index 41d6173a..00000000 Binary files a/public/gfx/flags_old/malta.gif and /dev/null differ diff --git a/public/gfx/flags_old/meksiko.gif b/public/gfx/flags_old/meksiko.gif deleted file mode 100644 index 65d32fbc..00000000 Binary files a/public/gfx/flags_old/meksiko.gif and /dev/null differ diff --git a/public/gfx/flags_old/monako.gif b/public/gfx/flags_old/monako.gif deleted file mode 100644 index 86c7a9a1..00000000 Binary files a/public/gfx/flags_old/monako.gif and /dev/null differ diff --git a/public/gfx/flags_old/nemcija.gif b/public/gfx/flags_old/nemcija.gif deleted file mode 100644 index 18069499..00000000 Binary files a/public/gfx/flags_old/nemcija.gif and /dev/null differ diff --git a/public/gfx/flags_old/nepal.gif b/public/gfx/flags_old/nepal.gif deleted file mode 100644 index c24ef591..00000000 Binary files a/public/gfx/flags_old/nepal.gif and /dev/null differ diff --git a/public/gfx/flags_old/nigerija.gif b/public/gfx/flags_old/nigerija.gif deleted file mode 100644 index 7db5fe3a..00000000 Binary files a/public/gfx/flags_old/nigerija.gif and /dev/null differ diff --git a/public/gfx/flags_old/nizozemska.gif b/public/gfx/flags_old/nizozemska.gif deleted file mode 100644 index 5c61d89a..00000000 Binary files a/public/gfx/flags_old/nizozemska.gif and /dev/null differ diff --git a/public/gfx/flags_old/northenireland.gif b/public/gfx/flags_old/northenireland.gif deleted file mode 100644 index 446056f8..00000000 Binary files a/public/gfx/flags_old/northenireland.gif and /dev/null differ diff --git a/public/gfx/flags_old/northernmarianaislands.gif b/public/gfx/flags_old/northernmarianaislands.gif deleted file mode 100644 index dba6f77b..00000000 Binary files a/public/gfx/flags_old/northernmarianaislands.gif and /dev/null differ diff --git a/public/gfx/flags_old/norveska.gif b/public/gfx/flags_old/norveska.gif deleted file mode 100644 index 0e9c92e6..00000000 Binary files a/public/gfx/flags_old/norveska.gif and /dev/null differ diff --git a/public/gfx/flags_old/nzel.gif b/public/gfx/flags_old/nzel.gif deleted file mode 100644 index 798daea7..00000000 Binary files a/public/gfx/flags_old/nzel.gif and /dev/null differ diff --git a/public/gfx/flags_old/other.gif b/public/gfx/flags_old/other.gif deleted file mode 100644 index 937350a8..00000000 Binary files a/public/gfx/flags_old/other.gif and /dev/null differ diff --git a/public/gfx/flags_old/pakistan.gif b/public/gfx/flags_old/pakistan.gif deleted file mode 100644 index 3269e8e9..00000000 Binary files a/public/gfx/flags_old/pakistan.gif and /dev/null differ diff --git a/public/gfx/flags_old/paragvaj.gif b/public/gfx/flags_old/paragvaj.gif deleted file mode 100644 index a2a85002..00000000 Binary files a/public/gfx/flags_old/paragvaj.gif and /dev/null differ diff --git a/public/gfx/flags_old/peru.gif b/public/gfx/flags_old/peru.gif deleted file mode 100644 index bd050ee3..00000000 Binary files a/public/gfx/flags_old/peru.gif and /dev/null differ diff --git a/public/gfx/flags_old/polska.gif b/public/gfx/flags_old/polska.gif deleted file mode 100644 index e934158d..00000000 Binary files a/public/gfx/flags_old/polska.gif and /dev/null differ diff --git a/public/gfx/flags_old/portugalska.gif b/public/gfx/flags_old/portugalska.gif deleted file mode 100644 index 3a4033ad..00000000 Binary files a/public/gfx/flags_old/portugalska.gif and /dev/null differ diff --git a/public/gfx/flags_old/puertorico.gif b/public/gfx/flags_old/puertorico.gif deleted file mode 100644 index 1e5d7d7b..00000000 Binary files a/public/gfx/flags_old/puertorico.gif and /dev/null differ diff --git a/public/gfx/flags_old/romunija.gif b/public/gfx/flags_old/romunija.gif deleted file mode 100644 index d5a3539f..00000000 Binary files a/public/gfx/flags_old/romunija.gif and /dev/null differ diff --git a/public/gfx/flags_old/rusija.gif b/public/gfx/flags_old/rusija.gif deleted file mode 100644 index b1ec8683..00000000 Binary files a/public/gfx/flags_old/rusija.gif and /dev/null differ diff --git a/public/gfx/flags_old/sanmarino.gif b/public/gfx/flags_old/sanmarino.gif deleted file mode 100644 index d7a0c83c..00000000 Binary files a/public/gfx/flags_old/sanmarino.gif and /dev/null differ diff --git a/public/gfx/flags_old/saudiarabia.gif b/public/gfx/flags_old/saudiarabia.gif deleted file mode 100644 index 00202837..00000000 Binary files a/public/gfx/flags_old/saudiarabia.gif and /dev/null differ diff --git a/public/gfx/flags_old/scotland.gif b/public/gfx/flags_old/scotland.gif deleted file mode 100644 index 8606de88..00000000 Binary files a/public/gfx/flags_old/scotland.gif and /dev/null differ diff --git a/public/gfx/flags_old/singapore.gif b/public/gfx/flags_old/singapore.gif deleted file mode 100644 index 720ddc5e..00000000 Binary files a/public/gfx/flags_old/singapore.gif and /dev/null differ diff --git a/public/gfx/flags_old/sirija.gif b/public/gfx/flags_old/sirija.gif deleted file mode 100644 index 17f0b7e1..00000000 Binary files a/public/gfx/flags_old/sirija.gif and /dev/null differ diff --git a/public/gfx/flags_old/slovaska.gif b/public/gfx/flags_old/slovaska.gif deleted file mode 100644 index e6b38362..00000000 Binary files a/public/gfx/flags_old/slovaska.gif and /dev/null differ diff --git a/public/gfx/flags_old/slovenija.gif b/public/gfx/flags_old/slovenija.gif deleted file mode 100644 index 4955e21d..00000000 Binary files a/public/gfx/flags_old/slovenija.gif and /dev/null differ diff --git a/public/gfx/flags_old/spanija.gif b/public/gfx/flags_old/spanija.gif deleted file mode 100644 index ab9ce357..00000000 Binary files a/public/gfx/flags_old/spanija.gif and /dev/null differ diff --git a/public/gfx/flags_old/srilanka.gif b/public/gfx/flags_old/srilanka.gif deleted file mode 100644 index d3312d78..00000000 Binary files a/public/gfx/flags_old/srilanka.gif and /dev/null differ diff --git a/public/gfx/flags_old/stkitts.gif b/public/gfx/flags_old/stkitts.gif deleted file mode 100644 index 55c7be49..00000000 Binary files a/public/gfx/flags_old/stkitts.gif and /dev/null differ diff --git a/public/gfx/flags_old/svedska.gif b/public/gfx/flags_old/svedska.gif deleted file mode 100644 index 8dceaa7d..00000000 Binary files a/public/gfx/flags_old/svedska.gif and /dev/null differ diff --git a/public/gfx/flags_old/svica.gif b/public/gfx/flags_old/svica.gif deleted file mode 100644 index 3b4f498a..00000000 Binary files a/public/gfx/flags_old/svica.gif and /dev/null differ diff --git a/public/gfx/flags_old/taiwan.gif b/public/gfx/flags_old/taiwan.gif deleted file mode 100644 index 148b700b..00000000 Binary files a/public/gfx/flags_old/taiwan.gif and /dev/null differ diff --git a/public/gfx/flags_old/thailand.gif b/public/gfx/flags_old/thailand.gif deleted file mode 100644 index e1d2625a..00000000 Binary files a/public/gfx/flags_old/thailand.gif and /dev/null differ diff --git a/public/gfx/flags_old/tobago.gif b/public/gfx/flags_old/tobago.gif deleted file mode 100644 index 856d48a1..00000000 Binary files a/public/gfx/flags_old/tobago.gif and /dev/null differ diff --git a/public/gfx/flags_old/turcija.gif b/public/gfx/flags_old/turcija.gif deleted file mode 100644 index 7db9ab89..00000000 Binary files a/public/gfx/flags_old/turcija.gif and /dev/null differ diff --git a/public/gfx/flags_old/turkscaicos.gif b/public/gfx/flags_old/turkscaicos.gif deleted file mode 100644 index 7ca4620a..00000000 Binary files a/public/gfx/flags_old/turkscaicos.gif and /dev/null differ diff --git a/public/gfx/flags_old/uk.gif b/public/gfx/flags_old/uk.gif deleted file mode 100644 index 360685d3..00000000 Binary files a/public/gfx/flags_old/uk.gif and /dev/null differ diff --git a/public/gfx/flags_old/uruguay.gif b/public/gfx/flags_old/uruguay.gif deleted file mode 100644 index f9edfaf7..00000000 Binary files a/public/gfx/flags_old/uruguay.gif and /dev/null differ diff --git a/public/gfx/flags_old/usa.gif b/public/gfx/flags_old/usa.gif deleted file mode 100644 index 0eb38f9f..00000000 Binary files a/public/gfx/flags_old/usa.gif and /dev/null differ diff --git a/public/gfx/flags_old/venezuela.gif b/public/gfx/flags_old/venezuela.gif deleted file mode 100644 index b27d5a57..00000000 Binary files a/public/gfx/flags_old/venezuela.gif and /dev/null differ diff --git a/public/gfx/flags_old/vietnam.gif b/public/gfx/flags_old/vietnam.gif deleted file mode 100644 index a66445e3..00000000 Binary files a/public/gfx/flags_old/vietnam.gif and /dev/null differ diff --git a/public/gfx/flags_old/vincent.gif b/public/gfx/flags_old/vincent.gif deleted file mode 100644 index 8e730597..00000000 Binary files a/public/gfx/flags_old/vincent.gif and /dev/null differ diff --git a/public/gfx/flags_old/virginislands.gif b/public/gfx/flags_old/virginislands.gif deleted file mode 100644 index dffcd91b..00000000 Binary files a/public/gfx/flags_old/virginislands.gif and /dev/null differ diff --git a/public/gfx/flags_old/zambia.gif b/public/gfx/flags_old/zambia.gif deleted file mode 100644 index 4a26fbc5..00000000 Binary files a/public/gfx/flags_old/zambia.gif and /dev/null differ diff --git a/public/gfx/folder-bottom.jpg b/public/gfx/folder-bottom.jpg deleted file mode 100644 index 159c3fb2..00000000 Binary files a/public/gfx/folder-bottom.jpg and /dev/null differ diff --git a/public/gfx/folder-login.jpg b/public/gfx/folder-login.jpg deleted file mode 100644 index 707cf255..00000000 Binary files a/public/gfx/folder-login.jpg and /dev/null differ diff --git a/public/gfx/folder-middle.jpg b/public/gfx/folder-middle.jpg deleted file mode 100644 index 81aec773..00000000 Binary files a/public/gfx/folder-middle.jpg and /dev/null differ diff --git a/public/gfx/folder-other.jpg b/public/gfx/folder-other.jpg deleted file mode 100644 index 92728461..00000000 Binary files a/public/gfx/folder-other.jpg and /dev/null differ diff --git a/public/gfx/folder-search.jpg b/public/gfx/folder-search.jpg deleted file mode 100644 index 3dfcf966..00000000 Binary files a/public/gfx/folder-search.jpg and /dev/null differ diff --git a/public/gfx/folder-skinz.jpg b/public/gfx/folder-skinz.jpg deleted file mode 100644 index 44746495..00000000 Binary files a/public/gfx/folder-skinz.jpg and /dev/null differ diff --git a/public/gfx/folderopen.gif b/public/gfx/folderopen.gif deleted file mode 100644 index cc9521d2..00000000 Binary files a/public/gfx/folderopen.gif and /dev/null differ diff --git a/public/gfx/footer.png b/public/gfx/footer.png deleted file mode 100644 index 00ef5096..00000000 Binary files a/public/gfx/footer.png and /dev/null differ diff --git a/public/gfx/footer_black.png b/public/gfx/footer_black.png deleted file mode 100644 index e80d4fda..00000000 Binary files a/public/gfx/footer_black.png and /dev/null differ diff --git a/public/gfx/footer_main.png b/public/gfx/footer_main.png deleted file mode 100644 index 9b77639e..00000000 Binary files a/public/gfx/footer_main.png and /dev/null differ diff --git a/public/gfx/forkme.png b/public/gfx/forkme.png deleted file mode 100644 index 4e1b6d18..00000000 Binary files a/public/gfx/forkme.png and /dev/null differ diff --git a/public/gfx/frame.jpg b/public/gfx/frame.jpg deleted file mode 100644 index b0a389d2..00000000 Binary files a/public/gfx/frame.jpg and /dev/null differ diff --git a/public/gfx/frame.png b/public/gfx/frame.png deleted file mode 100644 index b50228b7..00000000 Binary files a/public/gfx/frame.png and /dev/null differ diff --git a/public/gfx/get.gif b/public/gfx/get.gif deleted file mode 100644 index d82f741e..00000000 Binary files a/public/gfx/get.gif and /dev/null differ diff --git a/public/gfx/gray/back.gif b/public/gfx/gray/back.gif deleted file mode 100644 index 8346a759..00000000 Binary files a/public/gfx/gray/back.gif and /dev/null differ diff --git a/public/gfx/gray/border.png b/public/gfx/gray/border.png deleted file mode 100644 index 125e8b7a..00000000 Binary files a/public/gfx/gray/border.png and /dev/null differ diff --git a/public/gfx/gray/search.gif b/public/gfx/gray/search.gif deleted file mode 100644 index 3cc071b7..00000000 Binary files a/public/gfx/gray/search.gif and /dev/null differ diff --git a/public/gfx/grayeye.jpg b/public/gfx/grayeye.jpg deleted file mode 100644 index 9cd06811..00000000 Binary files a/public/gfx/grayeye.jpg and /dev/null differ diff --git a/public/gfx/gui_champs2006_wc.jpg b/public/gfx/gui_champs2006_wc.jpg deleted file mode 100644 index 6d454715..00000000 Binary files a/public/gfx/gui_champs2006_wc.jpg and /dev/null differ diff --git a/public/gfx/guruweb120x60.gif b/public/gfx/guruweb120x60.gif deleted file mode 100644 index c9100f1b..00000000 Binary files a/public/gfx/guruweb120x60.gif and /dev/null differ diff --git a/public/gfx/headbar.jpg b/public/gfx/headbar.jpg deleted file mode 100644 index d6f7b257..00000000 Binary files a/public/gfx/headbar.jpg and /dev/null differ diff --git a/public/gfx/header.jpg b/public/gfx/header.jpg deleted file mode 100644 index 827e827e..00000000 Binary files a/public/gfx/header.jpg and /dev/null differ diff --git a/public/gfx/header_logo.jpg b/public/gfx/header_logo.jpg deleted file mode 100644 index 32fef78d..00000000 Binary files a/public/gfx/header_logo.jpg and /dev/null differ diff --git a/public/gfx/header_trans.png b/public/gfx/header_trans.png deleted file mode 100644 index 2a41f664..00000000 Binary files a/public/gfx/header_trans.png and /dev/null differ diff --git a/public/gfx/highlight_15px.png b/public/gfx/highlight_15px.png deleted file mode 100644 index f7b768f3..00000000 Binary files a/public/gfx/highlight_15px.png and /dev/null differ diff --git a/public/gfx/highlight_28px-2.png b/public/gfx/highlight_28px-2.png deleted file mode 100644 index 32f283d9..00000000 Binary files a/public/gfx/highlight_28px-2.png and /dev/null differ diff --git a/public/gfx/highlight_28px-3.png b/public/gfx/highlight_28px-3.png deleted file mode 100644 index f53fb647..00000000 Binary files a/public/gfx/highlight_28px-3.png and /dev/null differ diff --git a/public/gfx/highlight_28px.png b/public/gfx/highlight_28px.png deleted file mode 100644 index f9deb648..00000000 Binary files a/public/gfx/highlight_28px.png and /dev/null differ diff --git a/public/gfx/hydra.gif b/public/gfx/hydra.gif deleted file mode 100644 index 1b107bf1..00000000 Binary files a/public/gfx/hydra.gif and /dev/null differ diff --git a/public/gfx/innocence.jpg b/public/gfx/innocence.jpg deleted file mode 100644 index 45e0f5b2..00000000 Binary files a/public/gfx/innocence.jpg and /dev/null differ diff --git a/public/gfx/input_field.gif b/public/gfx/input_field.gif deleted file mode 100644 index ebbc61fa..00000000 Binary files a/public/gfx/input_field.gif and /dev/null differ diff --git a/public/gfx/join_sb.gif b/public/gfx/join_sb.gif deleted file mode 100644 index 7e412737..00000000 Binary files a/public/gfx/join_sb.gif and /dev/null differ diff --git a/public/gfx/kazaa_chance.gif b/public/gfx/kazaa_chance.gif deleted file mode 100644 index c3914762..00000000 Binary files a/public/gfx/kazaa_chance.gif and /dev/null differ diff --git a/public/gfx/kazaa_logo.gif b/public/gfx/kazaa_logo.gif deleted file mode 100644 index 48ab5710..00000000 Binary files a/public/gfx/kazaa_logo.gif and /dev/null differ diff --git a/public/gfx/kazaa_logo.jpg b/public/gfx/kazaa_logo.jpg deleted file mode 100644 index 7a97c126..00000000 Binary files a/public/gfx/kazaa_logo.jpg and /dev/null differ diff --git a/public/gfx/kazaa_logo2.gif b/public/gfx/kazaa_logo2.gif deleted file mode 100644 index 37741d33..00000000 Binary files a/public/gfx/kazaa_logo2.gif and /dev/null differ diff --git a/public/gfx/kks.jpg b/public/gfx/kks.jpg deleted file mode 100644 index c7b2afdb..00000000 Binary files a/public/gfx/kks.jpg and /dev/null differ diff --git a/public/gfx/kks2.jpg b/public/gfx/kks2.jpg deleted file mode 100644 index 65e2d07b..00000000 Binary files a/public/gfx/kks2.jpg and /dev/null differ diff --git a/public/gfx/label_new_yellow.png b/public/gfx/label_new_yellow.png deleted file mode 100644 index e5bbff4b..00000000 Binary files a/public/gfx/label_new_yellow.png and /dev/null differ diff --git a/public/gfx/latest_desktop_wallpaper.jpg b/public/gfx/latest_desktop_wallpaper.jpg deleted file mode 100644 index 3ecc56dd..00000000 Binary files a/public/gfx/latest_desktop_wallpaper.jpg and /dev/null differ diff --git a/public/gfx/left.jpg b/public/gfx/left.jpg deleted file mode 100644 index 7de3afcb..00000000 Binary files a/public/gfx/left.jpg and /dev/null differ diff --git a/public/gfx/linkus.jpg b/public/gfx/linkus.jpg deleted file mode 100644 index 72a3db7b..00000000 Binary files a/public/gfx/linkus.jpg and /dev/null differ diff --git a/public/gfx/linkus4.gif b/public/gfx/linkus4.gif deleted file mode 100644 index 9c572567..00000000 Binary files a/public/gfx/linkus4.gif and /dev/null differ diff --git a/public/gfx/lites2k.gif b/public/gfx/lites2k.gif deleted file mode 100644 index 99b80982..00000000 Binary files a/public/gfx/lites2k.gif and /dev/null differ diff --git a/public/gfx/login_button.jpg b/public/gfx/login_button.jpg deleted file mode 100644 index 555c5d05..00000000 Binary files a/public/gfx/login_button.jpg and /dev/null differ diff --git a/public/gfx/login_button.png b/public/gfx/login_button.png deleted file mode 100644 index 819c1e88..00000000 Binary files a/public/gfx/login_button.png and /dev/null differ diff --git a/public/gfx/login_button2.png b/public/gfx/login_button2.png deleted file mode 100644 index 1f4f0b3d..00000000 Binary files a/public/gfx/login_button2.png and /dev/null differ diff --git a/public/gfx/login_button3.png b/public/gfx/login_button3.png deleted file mode 100644 index d9c6726a..00000000 Binary files a/public/gfx/login_button3.png and /dev/null differ diff --git a/public/gfx/login_button_over.png b/public/gfx/login_button_over.png deleted file mode 100644 index be3f418f..00000000 Binary files a/public/gfx/login_button_over.png and /dev/null differ diff --git a/public/gfx/login_field.gif b/public/gfx/login_field.gif deleted file mode 100644 index 2ab85f1f..00000000 Binary files a/public/gfx/login_field.gif and /dev/null differ diff --git a/public/gfx/login_field2.gif b/public/gfx/login_field2.gif deleted file mode 100644 index a583cfed..00000000 Binary files a/public/gfx/login_field2.gif and /dev/null differ diff --git a/public/gfx/login_input.jpg b/public/gfx/login_input.jpg deleted file mode 100644 index 5698bb86..00000000 Binary files a/public/gfx/login_input.jpg and /dev/null differ diff --git a/public/gfx/login_input.png b/public/gfx/login_input.png deleted file mode 100644 index 8da3727a..00000000 Binary files a/public/gfx/login_input.png and /dev/null differ diff --git a/public/gfx/login_input3.png b/public/gfx/login_input3.png deleted file mode 100644 index d02eecf0..00000000 Binary files a/public/gfx/login_input3.png and /dev/null differ diff --git a/public/gfx/login_text.png b/public/gfx/login_text.png deleted file mode 100644 index 51653ac1..00000000 Binary files a/public/gfx/login_text.png and /dev/null differ diff --git a/public/gfx/logo-4black.jpg b/public/gfx/logo-4black.jpg deleted file mode 100644 index 519f1a0e..00000000 Binary files a/public/gfx/logo-4black.jpg and /dev/null differ diff --git a/public/gfx/logo-4pinky.jpg b/public/gfx/logo-4pinky.jpg deleted file mode 100644 index 0b20d4b9..00000000 Binary files a/public/gfx/logo-4pinky.jpg and /dev/null differ diff --git a/public/gfx/logo-gray.jpg b/public/gfx/logo-gray.jpg deleted file mode 100644 index 9ea8b8a4..00000000 Binary files a/public/gfx/logo-gray.jpg and /dev/null differ diff --git a/public/gfx/logo-green.jpg b/public/gfx/logo-green.jpg deleted file mode 100644 index 06d45e70..00000000 Binary files a/public/gfx/logo-green.jpg and /dev/null differ diff --git a/public/gfx/logo-red.jpg b/public/gfx/logo-red.jpg deleted file mode 100644 index 9a93b922..00000000 Binary files a/public/gfx/logo-red.jpg and /dev/null differ diff --git a/public/gfx/logo.jpg b/public/gfx/logo.jpg deleted file mode 100644 index e9283ea9..00000000 Binary files a/public/gfx/logo.jpg and /dev/null differ diff --git a/public/gfx/logo2.gif b/public/gfx/logo2.gif deleted file mode 100644 index 1af899dc..00000000 Binary files a/public/gfx/logo2.gif and /dev/null differ diff --git a/public/gfx/logo_xmas.jpg b/public/gfx/logo_xmas.jpg deleted file mode 100644 index 72650526..00000000 Binary files a/public/gfx/logo_xmas.jpg and /dev/null differ diff --git a/public/gfx/lotsoftut.gif b/public/gfx/lotsoftut.gif deleted file mode 100644 index d7887a63..00000000 Binary files a/public/gfx/lotsoftut.gif and /dev/null differ diff --git a/public/gfx/ls2k.gif b/public/gfx/ls2k.gif deleted file mode 100644 index b418d055..00000000 Binary files a/public/gfx/ls2k.gif and /dev/null differ diff --git a/public/gfx/luis2.gif b/public/gfx/luis2.gif deleted file mode 100644 index d71527dc..00000000 Binary files a/public/gfx/luis2.gif and /dev/null differ diff --git a/public/gfx/main-red-bg.gif b/public/gfx/main-red-bg.gif deleted file mode 100644 index 08da2a22..00000000 Binary files a/public/gfx/main-red-bg.gif and /dev/null differ diff --git a/public/gfx/mascot_other.webp b/public/gfx/mascot_other.webp new file mode 100644 index 00000000..0e71d250 Binary files /dev/null and b/public/gfx/mascot_other.webp differ diff --git a/public/gfx/mascot_photography.webp b/public/gfx/mascot_photography.webp new file mode 100644 index 00000000..6a7062e2 Binary files /dev/null and b/public/gfx/mascot_photography.webp differ diff --git a/public/gfx/mascot_skins.webp b/public/gfx/mascot_skins.webp new file mode 100644 index 00000000..f156d2ff Binary files /dev/null and b/public/gfx/mascot_skins.webp differ diff --git a/public/gfx/mascot_wallpapers.webp b/public/gfx/mascot_wallpapers.webp new file mode 100644 index 00000000..175d274f Binary files /dev/null and b/public/gfx/mascot_wallpapers.webp differ diff --git a/public/gfx/mind_games_5.jpg b/public/gfx/mind_games_5.jpg deleted file mode 100644 index 01928b22..00000000 Binary files a/public/gfx/mind_games_5.jpg and /dev/null differ diff --git a/public/gfx/missing.gif b/public/gfx/missing.gif deleted file mode 100644 index 13d98c17..00000000 Binary files a/public/gfx/missing.gif and /dev/null differ diff --git a/public/gfx/more-rev-pig-88x31.gif b/public/gfx/more-rev-pig-88x31.gif deleted file mode 100644 index a2419f93..00000000 Binary files a/public/gfx/more-rev-pig-88x31.gif and /dev/null differ diff --git a/public/gfx/more_arrow.jpg b/public/gfx/more_arrow.jpg deleted file mode 100644 index 36651f47..00000000 Binary files a/public/gfx/more_arrow.jpg and /dev/null differ diff --git a/public/gfx/more_arrow.png b/public/gfx/more_arrow.png deleted file mode 100644 index 96a03e73..00000000 Binary files a/public/gfx/more_arrow.png and /dev/null differ diff --git a/public/gfx/myBrowser.png b/public/gfx/myBrowser.png deleted file mode 100644 index 171c9acb..00000000 Binary files a/public/gfx/myBrowser.png and /dev/null differ diff --git a/public/gfx/noaccess.html b/public/gfx/noaccess.html deleted file mode 100644 index b42192bb..00000000 --- a/public/gfx/noaccess.html +++ /dev/null @@ -1,2 +0,0 @@ -403 Permission denied - diff --git a/public/gfx/normativi_120x60.gif b/public/gfx/normativi_120x60.gif deleted file mode 100644 index a675579f..00000000 Binary files a/public/gfx/normativi_120x60.gif and /dev/null differ diff --git a/public/gfx/openMenu.png b/public/gfx/openMenu.png deleted file mode 100644 index aebda6b6..00000000 Binary files a/public/gfx/openMenu.png and /dev/null differ diff --git a/public/gfx/p11.jpg b/public/gfx/p11.jpg deleted file mode 100644 index 730e15fc..00000000 Binary files a/public/gfx/p11.jpg and /dev/null differ diff --git a/public/gfx/p12.jpg b/public/gfx/p12.jpg deleted file mode 100644 index 8c46efd1..00000000 Binary files a/public/gfx/p12.jpg and /dev/null differ diff --git a/public/gfx/p13.jpg b/public/gfx/p13.jpg deleted file mode 100644 index 73fc03d8..00000000 Binary files a/public/gfx/p13.jpg and /dev/null differ diff --git a/public/gfx/p14.jpg b/public/gfx/p14.jpg deleted file mode 100644 index 00bb25ab..00000000 Binary files a/public/gfx/p14.jpg and /dev/null differ diff --git a/public/gfx/p15.jpg b/public/gfx/p15.jpg deleted file mode 100644 index fbfad3ed..00000000 Binary files a/public/gfx/p15.jpg and /dev/null differ diff --git a/public/gfx/p21.jpg b/public/gfx/p21.jpg deleted file mode 100644 index 24d5ba24..00000000 Binary files a/public/gfx/p21.jpg and /dev/null differ diff --git a/public/gfx/p211.jpg b/public/gfx/p211.jpg deleted file mode 100644 index 455260af..00000000 Binary files a/public/gfx/p211.jpg and /dev/null differ diff --git a/public/gfx/p22.jpg b/public/gfx/p22.jpg deleted file mode 100644 index ba4e37dc..00000000 Binary files a/public/gfx/p22.jpg and /dev/null differ diff --git a/public/gfx/p23.jpg b/public/gfx/p23.jpg deleted file mode 100644 index 41d07470..00000000 Binary files a/public/gfx/p23.jpg and /dev/null differ diff --git a/public/gfx/p24.jpg b/public/gfx/p24.jpg deleted file mode 100644 index d76356f1..00000000 Binary files a/public/gfx/p24.jpg and /dev/null differ diff --git a/public/gfx/palcka.gif b/public/gfx/palcka.gif deleted file mode 100644 index 6a6ee8b5..00000000 Binary files a/public/gfx/palcka.gif and /dev/null differ diff --git a/public/gfx/panel.jpg b/public/gfx/panel.jpg deleted file mode 100644 index 2c049317..00000000 Binary files a/public/gfx/panel.jpg and /dev/null differ diff --git a/public/gfx/partners/1-tsslogo.gif b/public/gfx/partners/1-tsslogo.gif deleted file mode 100644 index 90586704..00000000 Binary files a/public/gfx/partners/1-tsslogo.gif and /dev/null differ diff --git a/public/gfx/partners/2.gif b/public/gfx/partners/2.gif deleted file mode 100644 index 74ae7ba6..00000000 Binary files a/public/gfx/partners/2.gif and /dev/null differ diff --git a/public/gfx/partners/545button.jpg b/public/gfx/partners/545button.jpg deleted file mode 100644 index bb9f0f95..00000000 Binary files a/public/gfx/partners/545button.jpg and /dev/null differ diff --git a/public/gfx/partners/80button1.gif b/public/gfx/partners/80button1.gif deleted file mode 100644 index d423743c..00000000 Binary files a/public/gfx/partners/80button1.gif and /dev/null differ diff --git a/public/gfx/partners/88x31.gif b/public/gfx/partners/88x31.gif deleted file mode 100644 index ff67274d..00000000 Binary files a/public/gfx/partners/88x31.gif and /dev/null differ diff --git a/public/gfx/partners/88x31_brubcc.gif b/public/gfx/partners/88x31_brubcc.gif deleted file mode 100644 index 1f8e746b..00000000 Binary files a/public/gfx/partners/88x31_brubcc.gif and /dev/null differ diff --git a/public/gfx/partners/88x31_modzine.gif b/public/gfx/partners/88x31_modzine.gif deleted file mode 100644 index fd39393a..00000000 Binary files a/public/gfx/partners/88x31_modzine.gif and /dev/null differ diff --git a/public/gfx/partners/88x31titanskn.gif b/public/gfx/partners/88x31titanskn.gif deleted file mode 100644 index 28d85b36..00000000 Binary files a/public/gfx/partners/88x31titanskn.gif and /dev/null differ diff --git a/public/gfx/partners/AcidSnow.gif b/public/gfx/partners/AcidSnow.gif deleted file mode 100644 index 206c9b7f..00000000 Binary files a/public/gfx/partners/AcidSnow.gif and /dev/null differ diff --git a/public/gfx/partners/Customize1.gif b/public/gfx/partners/Customize1.gif deleted file mode 100644 index e0b15f8b..00000000 Binary files a/public/gfx/partners/Customize1.gif and /dev/null differ diff --git a/public/gfx/partners/GUIO_BANNER.gif b/public/gfx/partners/GUIO_BANNER.gif deleted file mode 100644 index dfed23d9..00000000 Binary files a/public/gfx/partners/GUIO_BANNER.gif and /dev/null differ diff --git a/public/gfx/partners/LB2.gif b/public/gfx/partners/LB2.gif deleted file mode 100644 index ebb79598..00000000 Binary files a/public/gfx/partners/LB2.gif and /dev/null differ diff --git a/public/gfx/partners/RealmJamesT.gif b/public/gfx/partners/RealmJamesT.gif deleted file mode 100644 index 34519fa4..00000000 Binary files a/public/gfx/partners/RealmJamesT.gif and /dev/null differ diff --git a/public/gfx/partners/Skinning.png b/public/gfx/partners/Skinning.png deleted file mode 100644 index ff57158c..00000000 Binary files a/public/gfx/partners/Skinning.png and /dev/null differ diff --git a/public/gfx/partners/WMminibanner.jpg b/public/gfx/partners/WMminibanner.jpg deleted file mode 100644 index 93cb41f1..00000000 Binary files a/public/gfx/partners/WMminibanner.jpg and /dev/null differ diff --git a/public/gfx/partners/Xchange01.gif b/public/gfx/partners/Xchange01.gif deleted file mode 100644 index c070a3b1..00000000 Binary files a/public/gfx/partners/Xchange01.gif and /dev/null differ diff --git a/public/gfx/partners/ad_bee_88x31.gif b/public/gfx/partners/ad_bee_88x31.gif deleted file mode 100644 index 83c5a98a..00000000 Binary files a/public/gfx/partners/ad_bee_88x31.gif and /dev/null differ diff --git a/public/gfx/partners/adni18.jpg b/public/gfx/partners/adni18.jpg deleted file mode 100644 index d1f72056..00000000 Binary files a/public/gfx/partners/adni18.jpg and /dev/null differ diff --git a/public/gfx/partners/adni18_siteban.jpg b/public/gfx/partners/adni18_siteban.jpg deleted file mode 100644 index 1d486474..00000000 Binary files a/public/gfx/partners/adni18_siteban.jpg and /dev/null differ diff --git a/public/gfx/partners/adniSitelogo.gif b/public/gfx/partners/adniSitelogo.gif deleted file mode 100644 index cf5895c7..00000000 Binary files a/public/gfx/partners/adniSitelogo.gif and /dev/null differ diff --git a/public/gfx/partners/alekicon.gif b/public/gfx/partners/alekicon.gif deleted file mode 100644 index 4d65e2ab..00000000 Binary files a/public/gfx/partners/alekicon.gif and /dev/null differ diff --git a/public/gfx/partners/alexandrie.jpg b/public/gfx/partners/alexandrie.jpg deleted file mode 100644 index e45c9957..00000000 Binary files a/public/gfx/partners/alexandrie.jpg and /dev/null differ diff --git a/public/gfx/partners/anslogo.gif b/public/gfx/partners/anslogo.gif deleted file mode 100644 index 6454295b..00000000 Binary files a/public/gfx/partners/anslogo.gif and /dev/null differ diff --git a/public/gfx/partners/armonia.jpg b/public/gfx/partners/armonia.jpg deleted file mode 100644 index a448c2ca..00000000 Binary files a/public/gfx/partners/armonia.jpg and /dev/null differ diff --git a/public/gfx/partners/aroskin.GIF b/public/gfx/partners/aroskin.GIF deleted file mode 100644 index 15a3cece..00000000 Binary files a/public/gfx/partners/aroskin.GIF and /dev/null differ diff --git a/public/gfx/partners/artnskins.gif b/public/gfx/partners/artnskins.gif deleted file mode 100644 index c7931709..00000000 Binary files a/public/gfx/partners/artnskins.gif and /dev/null differ diff --git a/public/gfx/partners/artnskins.jpg b/public/gfx/partners/artnskins.jpg deleted file mode 100644 index c8675653..00000000 Binary files a/public/gfx/partners/artnskins.jpg and /dev/null differ diff --git a/public/gfx/partners/aston.gif b/public/gfx/partners/aston.gif deleted file mode 100644 index 56f81eb7..00000000 Binary files a/public/gfx/partners/aston.gif and /dev/null differ diff --git a/public/gfx/partners/aubutton.gif b/public/gfx/partners/aubutton.gif deleted file mode 100644 index 518041a8..00000000 Binary files a/public/gfx/partners/aubutton.gif and /dev/null differ diff --git a/public/gfx/partners/bannerfive.gif b/public/gfx/partners/bannerfive.gif deleted file mode 100644 index 06db0028..00000000 Binary files a/public/gfx/partners/bannerfive.gif and /dev/null differ diff --git a/public/gfx/partners/basehead2.jpg b/public/gfx/partners/basehead2.jpg deleted file mode 100644 index e46abe5f..00000000 Binary files a/public/gfx/partners/basehead2.jpg and /dev/null differ diff --git a/public/gfx/partners/belchfire_button.png b/public/gfx/partners/belchfire_button.png deleted file mode 100644 index e43486ef..00000000 Binary files a/public/gfx/partners/belchfire_button.png and /dev/null differ diff --git a/public/gfx/partners/bfarber.gif b/public/gfx/partners/bfarber.gif deleted file mode 100644 index 71091f8e..00000000 Binary files a/public/gfx/partners/bfarber.gif and /dev/null differ diff --git a/public/gfx/partners/bkaro.gif b/public/gfx/partners/bkaro.gif deleted file mode 100644 index b54a5a41..00000000 Binary files a/public/gfx/partners/bkaro.gif and /dev/null differ diff --git a/public/gfx/partners/breed_button.gif b/public/gfx/partners/breed_button.gif deleted file mode 100644 index 8951358d..00000000 Binary files a/public/gfx/partners/breed_button.gif and /dev/null differ diff --git a/public/gfx/partners/button2.gif b/public/gfx/partners/button2.gif deleted file mode 100644 index ffe60f3d..00000000 Binary files a/public/gfx/partners/button2.gif and /dev/null differ diff --git a/public/gfx/partners/button_artkeep.gif b/public/gfx/partners/button_artkeep.gif deleted file mode 100644 index caec9d2b..00000000 Binary files a/public/gfx/partners/button_artkeep.gif and /dev/null differ diff --git a/public/gfx/partners/c6s-button.gif b/public/gfx/partners/c6s-button.gif deleted file mode 100644 index 1c696344..00000000 Binary files a/public/gfx/partners/c6s-button.gif and /dev/null differ diff --git a/public/gfx/partners/chichi_logo.jpg b/public/gfx/partners/chichi_logo.jpg deleted file mode 100644 index 696224ae..00000000 Binary files a/public/gfx/partners/chichi_logo.jpg and /dev/null differ diff --git a/public/gfx/partners/competition.gif b/public/gfx/partners/competition.gif deleted file mode 100644 index b031f41e..00000000 Binary files a/public/gfx/partners/competition.gif and /dev/null differ diff --git a/public/gfx/partners/devart-button-tech13.gif b/public/gfx/partners/devart-button-tech13.gif deleted file mode 100644 index 55f3777c..00000000 Binary files a/public/gfx/partners/devart-button-tech13.gif and /dev/null differ diff --git a/public/gfx/partners/dew-88x31.gif b/public/gfx/partners/dew-88x31.gif deleted file mode 100644 index cb71eb01..00000000 Binary files a/public/gfx/partners/dew-88x31.gif and /dev/null differ diff --git a/public/gfx/partners/dezani.gif b/public/gfx/partners/dezani.gif deleted file mode 100644 index eadce14a..00000000 Binary files a/public/gfx/partners/dezani.gif and /dev/null differ diff --git a/public/gfx/partners/dm_1.gif b/public/gfx/partners/dm_1.gif deleted file mode 100644 index 537a29f6..00000000 Binary files a/public/gfx/partners/dm_1.gif and /dev/null differ diff --git a/public/gfx/partners/dotproject.gif b/public/gfx/partners/dotproject.gif deleted file mode 100644 index 9d578993..00000000 Binary files a/public/gfx/partners/dotproject.gif and /dev/null differ diff --git a/public/gfx/partners/dtobutton.gif b/public/gfx/partners/dtobutton.gif deleted file mode 100644 index 6b154537..00000000 Binary files a/public/gfx/partners/dtobutton.gif and /dev/null differ diff --git a/public/gfx/partners/eelink.gif b/public/gfx/partners/eelink.gif deleted file mode 100644 index 81b3bb40..00000000 Binary files a/public/gfx/partners/eelink.gif and /dev/null differ diff --git a/public/gfx/partners/empty.gif b/public/gfx/partners/empty.gif deleted file mode 100644 index 8c44c45c..00000000 Binary files a/public/gfx/partners/empty.gif and /dev/null differ diff --git a/public/gfx/partners/error691.gif b/public/gfx/partners/error691.gif deleted file mode 100644 index 3ae908d7..00000000 Binary files a/public/gfx/partners/error691.gif and /dev/null differ diff --git a/public/gfx/partners/ex-org.gif b/public/gfx/partners/ex-org.gif deleted file mode 100644 index a0495da3..00000000 Binary files a/public/gfx/partners/ex-org.gif and /dev/null differ diff --git a/public/gfx/partners/gp.gif b/public/gfx/partners/gp.gif deleted file mode 100644 index a3a3cac5..00000000 Binary files a/public/gfx/partners/gp.gif and /dev/null differ diff --git a/public/gfx/partners/guruwebhost.gif b/public/gfx/partners/guruwebhost.gif deleted file mode 100644 index e9d76c33..00000000 Binary files a/public/gfx/partners/guruwebhost.gif and /dev/null differ diff --git a/public/gfx/partners/higherlink1.gif b/public/gfx/partners/higherlink1.gif deleted file mode 100644 index ed5319e0..00000000 Binary files a/public/gfx/partners/higherlink1.gif and /dev/null differ diff --git a/public/gfx/partners/hipbutton.gif b/public/gfx/partners/hipbutton.gif deleted file mode 100644 index 0a07a098..00000000 Binary files a/public/gfx/partners/hipbutton.gif and /dev/null differ diff --git a/public/gfx/partners/hvd.gif b/public/gfx/partners/hvd.gif deleted file mode 100644 index 191ea477..00000000 Binary files a/public/gfx/partners/hvd.gif and /dev/null differ diff --git a/public/gfx/partners/hvdlink.jpg b/public/gfx/partners/hvdlink.jpg deleted file mode 100644 index e41c9133..00000000 Binary files a/public/gfx/partners/hvdlink.jpg and /dev/null differ diff --git a/public/gfx/partners/hydra.gif b/public/gfx/partners/hydra.gif deleted file mode 100644 index 1b107bf1..00000000 Binary files a/public/gfx/partners/hydra.gif and /dev/null differ diff --git a/public/gfx/partners/ice_new_button.gif b/public/gfx/partners/ice_new_button.gif deleted file mode 100644 index ba1e6e33..00000000 Binary files a/public/gfx/partners/ice_new_button.gif and /dev/null differ diff --git a/public/gfx/partners/klevze88.jpg b/public/gfx/partners/klevze88.jpg deleted file mode 100644 index 17261f62..00000000 Binary files a/public/gfx/partners/klevze88.jpg and /dev/null differ diff --git a/public/gfx/partners/klink.gif b/public/gfx/partners/klink.gif deleted file mode 100644 index dc48ec2c..00000000 Binary files a/public/gfx/partners/klink.gif and /dev/null differ diff --git a/public/gfx/partners/link_but1.gif b/public/gfx/partners/link_but1.gif deleted file mode 100644 index ee279fca..00000000 Binary files a/public/gfx/partners/link_but1.gif and /dev/null differ diff --git a/public/gfx/partners/linkacn2.gif b/public/gfx/partners/linkacn2.gif deleted file mode 100644 index efb44d46..00000000 Binary files a/public/gfx/partners/linkacn2.gif and /dev/null differ diff --git a/public/gfx/partners/linkus.jpg b/public/gfx/partners/linkus.jpg deleted file mode 100644 index b5ff085e..00000000 Binary files a/public/gfx/partners/linkus.jpg and /dev/null differ diff --git a/public/gfx/partners/lites2k.gif b/public/gfx/partners/lites2k.gif deleted file mode 100644 index 99b80982..00000000 Binary files a/public/gfx/partners/lites2k.gif and /dev/null differ diff --git a/public/gfx/partners/los_button.jpg b/public/gfx/partners/los_button.jpg deleted file mode 100644 index 97d36779..00000000 Binary files a/public/gfx/partners/los_button.jpg and /dev/null differ diff --git a/public/gfx/partners/lotsofskins.jpg b/public/gfx/partners/lotsofskins.jpg deleted file mode 100644 index 3e0d51f9..00000000 Binary files a/public/gfx/partners/lotsofskins.jpg and /dev/null differ diff --git a/public/gfx/partners/lotsoftut.gif b/public/gfx/partners/lotsoftut.gif deleted file mode 100644 index d7887a63..00000000 Binary files a/public/gfx/partners/lotsoftut.gif and /dev/null differ diff --git a/public/gfx/partners/ls2k.gif b/public/gfx/partners/ls2k.gif deleted file mode 100644 index b418d055..00000000 Binary files a/public/gfx/partners/ls2k.gif and /dev/null differ diff --git a/public/gfx/partners/myie2skins.gif b/public/gfx/partners/myie2skins.gif deleted file mode 100644 index 6124f71f..00000000 Binary files a/public/gfx/partners/myie2skins.gif and /dev/null differ diff --git a/public/gfx/partners/pcdesktopsani.gif b/public/gfx/partners/pcdesktopsani.gif deleted file mode 100644 index 28930b97..00000000 Binary files a/public/gfx/partners/pcdesktopsani.gif and /dev/null differ diff --git a/public/gfx/partners/pixbutton1.gif b/public/gfx/partners/pixbutton1.gif deleted file mode 100644 index 189ab0dc..00000000 Binary files a/public/gfx/partners/pixbutton1.gif and /dev/null differ diff --git a/public/gfx/partners/pj.gif b/public/gfx/partners/pj.gif deleted file mode 100644 index 9a227d30..00000000 Binary files a/public/gfx/partners/pj.gif and /dev/null differ diff --git a/public/gfx/partners/pp-button.gif b/public/gfx/partners/pp-button.gif deleted file mode 100644 index 8bd2172a..00000000 Binary files a/public/gfx/partners/pp-button.gif and /dev/null differ diff --git a/public/gfx/partners/ra2link.gif b/public/gfx/partners/ra2link.gif deleted file mode 100644 index 8dc1ae29..00000000 Binary files a/public/gfx/partners/ra2link.gif and /dev/null differ diff --git a/public/gfx/partners/s4s.gif b/public/gfx/partners/s4s.gif deleted file mode 100644 index acfc4097..00000000 Binary files a/public/gfx/partners/s4s.gif and /dev/null differ diff --git a/public/gfx/partners/sabutton.gif b/public/gfx/partners/sabutton.gif deleted file mode 100644 index 96fcc807..00000000 Binary files a/public/gfx/partners/sabutton.gif and /dev/null differ diff --git a/public/gfx/partners/scarebear.gif b/public/gfx/partners/scarebear.gif deleted file mode 100644 index 29942fd2..00000000 Binary files a/public/gfx/partners/scarebear.gif and /dev/null differ diff --git a/public/gfx/partners/sdlink4.gif b/public/gfx/partners/sdlink4.gif deleted file mode 100644 index 9d9a0082..00000000 Binary files a/public/gfx/partners/sdlink4.gif and /dev/null differ diff --git a/public/gfx/partners/shelldu.gif b/public/gfx/partners/shelldu.gif deleted file mode 100644 index d36aadb8..00000000 Binary files a/public/gfx/partners/shelldu.gif and /dev/null differ diff --git a/public/gfx/partners/shellfront.gif b/public/gfx/partners/shellfront.gif deleted file mode 100644 index b92132d5..00000000 Binary files a/public/gfx/partners/shellfront.gif and /dev/null differ diff --git a/public/gfx/partners/skinart.gif b/public/gfx/partners/skinart.gif deleted file mode 100644 index ceb71774..00000000 Binary files a/public/gfx/partners/skinart.gif and /dev/null differ diff --git a/public/gfx/partners/skinartistry_button.png b/public/gfx/partners/skinartistry_button.png deleted file mode 100644 index a7d08198..00000000 Binary files a/public/gfx/partners/skinartistry_button.png and /dev/null differ diff --git a/public/gfx/partners/skinmem88_31.gif b/public/gfx/partners/skinmem88_31.gif deleted file mode 100644 index 478a7b49..00000000 Binary files a/public/gfx/partners/skinmem88_31.gif and /dev/null differ diff --git a/public/gfx/partners/skinnables.gif b/public/gfx/partners/skinnables.gif deleted file mode 100644 index f44cf69e..00000000 Binary files a/public/gfx/partners/skinnables.gif and /dev/null differ diff --git a/public/gfx/partners/skinnaliciou.jpg b/public/gfx/partners/skinnaliciou.jpg deleted file mode 100644 index c84e52f3..00000000 Binary files a/public/gfx/partners/skinnaliciou.jpg and /dev/null differ diff --git a/public/gfx/partners/skinnedlink.gif b/public/gfx/partners/skinnedlink.gif deleted file mode 100644 index 536b1bf7..00000000 Binary files a/public/gfx/partners/skinnedlink.gif and /dev/null differ diff --git a/public/gfx/partners/skinz.gif b/public/gfx/partners/skinz.gif deleted file mode 100644 index 936679c6..00000000 Binary files a/public/gfx/partners/skinz.gif and /dev/null differ diff --git a/public/gfx/partners/spoono.gif b/public/gfx/partners/spoono.gif deleted file mode 100644 index 2c216b9e..00000000 Binary files a/public/gfx/partners/spoono.gif and /dev/null differ diff --git a/public/gfx/partners/teknidermy.gif b/public/gfx/partners/teknidermy.gif deleted file mode 100644 index 49bd5760..00000000 Binary files a/public/gfx/partners/teknidermy.gif and /dev/null differ diff --git a/public/gfx/partners/thds-88x31.gif b/public/gfx/partners/thds-88x31.gif deleted file mode 100644 index 40b0815d..00000000 Binary files a/public/gfx/partners/thds-88x31.gif and /dev/null differ diff --git a/public/gfx/partners/thdsv2-button.gif b/public/gfx/partners/thdsv2-button.gif deleted file mode 100644 index 944c29c2..00000000 Binary files a/public/gfx/partners/thdsv2-button.gif and /dev/null differ diff --git a/public/gfx/partners/thinkdan.gif b/public/gfx/partners/thinkdan.gif deleted file mode 100644 index 17397e44..00000000 Binary files a/public/gfx/partners/thinkdan.gif and /dev/null differ diff --git a/public/gfx/partners/tranceportbutton.gif b/public/gfx/partners/tranceportbutton.gif deleted file mode 100644 index 4625a355..00000000 Binary files a/public/gfx/partners/tranceportbutton.gif and /dev/null differ diff --git a/public/gfx/partners/twisted2.gif b/public/gfx/partners/twisted2.gif deleted file mode 100644 index 0671991f..00000000 Binary files a/public/gfx/partners/twisted2.gif and /dev/null differ diff --git a/public/gfx/partners/vabutton.gif b/public/gfx/partners/vabutton.gif deleted file mode 100644 index d8031b23..00000000 Binary files a/public/gfx/partners/vabutton.gif and /dev/null differ diff --git a/public/gfx/partners/valhalla.gif b/public/gfx/partners/valhalla.gif deleted file mode 100644 index 520b9831..00000000 Binary files a/public/gfx/partners/valhalla.gif and /dev/null differ diff --git a/public/gfx/partners/vp.gif b/public/gfx/partners/vp.gif deleted file mode 100644 index a6082836..00000000 Binary files a/public/gfx/partners/vp.gif and /dev/null differ diff --git a/public/gfx/partners/vplink.gif b/public/gfx/partners/vplink.gif deleted file mode 100644 index eed9fc54..00000000 Binary files a/public/gfx/partners/vplink.gif and /dev/null differ diff --git a/public/gfx/partners/wincustbutton.gif b/public/gfx/partners/wincustbutton.gif deleted file mode 100644 index 5c9e9e87..00000000 Binary files a/public/gfx/partners/wincustbutton.gif and /dev/null differ diff --git a/public/gfx/partners/winstep88x31.gif b/public/gfx/partners/winstep88x31.gif deleted file mode 100644 index 51331368..00000000 Binary files a/public/gfx/partners/winstep88x31.gif and /dev/null differ diff --git a/public/gfx/partners/www.lightstar1.com.jpg b/public/gfx/partners/www.lightstar1.com.jpg deleted file mode 100644 index 92e264a7..00000000 Binary files a/public/gfx/partners/www.lightstar1.com.jpg and /dev/null differ diff --git a/public/gfx/partners/www.maxstyles.com.png b/public/gfx/partners/www.maxstyles.com.png deleted file mode 100644 index 04245bf9..00000000 Binary files a/public/gfx/partners/www.maxstyles.com.png and /dev/null differ diff --git a/public/gfx/partners/www.wincustomizing.com.png b/public/gfx/partners/www.wincustomizing.com.png deleted file mode 100644 index 0a1e519a..00000000 Binary files a/public/gfx/partners/www.wincustomizing.com.png and /dev/null differ diff --git a/public/gfx/partners/x1i.gif b/public/gfx/partners/x1i.gif deleted file mode 100644 index 7c9fa7c7..00000000 Binary files a/public/gfx/partners/x1i.gif and /dev/null differ diff --git a/public/gfx/partners/x21b.gif b/public/gfx/partners/x21b.gif deleted file mode 100644 index a9159a4d..00000000 Binary files a/public/gfx/partners/x21b.gif and /dev/null differ diff --git a/public/gfx/partners/xhrc.gif b/public/gfx/partners/xhrc.gif deleted file mode 100644 index b05a1e45..00000000 Binary files a/public/gfx/partners/xhrc.gif and /dev/null differ diff --git a/public/gfx/partners/xptheme_button.gif b/public/gfx/partners/xptheme_button.gif deleted file mode 100644 index c60caf92..00000000 Binary files a/public/gfx/partners/xptheme_button.gif and /dev/null differ diff --git a/public/gfx/pcdesktopsani.gif b/public/gfx/pcdesktopsani.gif deleted file mode 100644 index 28930b97..00000000 Binary files a/public/gfx/pcdesktopsani.gif and /dev/null differ diff --git a/public/gfx/photo/1st_photo.jpg b/public/gfx/photo/1st_photo.jpg deleted file mode 100644 index d976feac..00000000 Binary files a/public/gfx/photo/1st_photo.jpg and /dev/null differ diff --git a/public/gfx/pic1-1a.jpg b/public/gfx/pic1-1a.jpg deleted file mode 100644 index 4b12445b..00000000 Binary files a/public/gfx/pic1-1a.jpg and /dev/null differ diff --git a/public/gfx/pic1-1b.jpg b/public/gfx/pic1-1b.jpg deleted file mode 100644 index 021bc238..00000000 Binary files a/public/gfx/pic1-1b.jpg and /dev/null differ diff --git a/public/gfx/pic1-2.jpg b/public/gfx/pic1-2.jpg deleted file mode 100644 index 6f2c37d1..00000000 Binary files a/public/gfx/pic1-2.jpg and /dev/null differ diff --git a/public/gfx/pic1-3.jpg b/public/gfx/pic1-3.jpg deleted file mode 100644 index 3acbd70c..00000000 Binary files a/public/gfx/pic1-3.jpg and /dev/null differ diff --git a/public/gfx/pic1-4.jpg b/public/gfx/pic1-4.jpg deleted file mode 100644 index e40e0d31..00000000 Binary files a/public/gfx/pic1-4.jpg and /dev/null differ diff --git a/public/gfx/pic2-1.jpg b/public/gfx/pic2-1.jpg deleted file mode 100644 index f648065b..00000000 Binary files a/public/gfx/pic2-1.jpg and /dev/null differ diff --git a/public/gfx/pic2-2.jpg b/public/gfx/pic2-2.jpg deleted file mode 100644 index 48656716..00000000 Binary files a/public/gfx/pic2-2.jpg and /dev/null differ diff --git a/public/gfx/pic3-1.jpg b/public/gfx/pic3-1.jpg deleted file mode 100644 index b2d4800d..00000000 Binary files a/public/gfx/pic3-1.jpg and /dev/null differ diff --git a/public/gfx/pic4-1.jpg b/public/gfx/pic4-1.jpg deleted file mode 100644 index 20aad4f0..00000000 Binary files a/public/gfx/pic4-1.jpg and /dev/null differ diff --git a/public/gfx/pic5-1.jpg b/public/gfx/pic5-1.jpg deleted file mode 100644 index 0d9be21d..00000000 Binary files a/public/gfx/pic5-1.jpg and /dev/null differ diff --git a/public/gfx/print_sizes.gif b/public/gfx/print_sizes.gif deleted file mode 100644 index d94f2cbe..00000000 Binary files a/public/gfx/print_sizes.gif and /dev/null differ diff --git a/public/gfx/ra2link.gif b/public/gfx/ra2link.gif deleted file mode 100644 index 8dc1ae29..00000000 Binary files a/public/gfx/ra2link.gif and /dev/null differ diff --git a/public/gfx/recomend.jpg b/public/gfx/recomend.jpg deleted file mode 100644 index dc7ead6b..00000000 Binary files a/public/gfx/recomend.jpg and /dev/null differ diff --git a/public/gfx/right.jpg b/public/gfx/right.jpg deleted file mode 100644 index 2133f22c..00000000 Binary files a/public/gfx/right.jpg and /dev/null differ diff --git a/public/gfx/s4s.gif b/public/gfx/s4s.gif deleted file mode 100644 index acfc4097..00000000 Binary files a/public/gfx/s4s.gif and /dev/null differ diff --git a/public/gfx/sb-splash.jpg b/public/gfx/sb-splash.jpg deleted file mode 100644 index 38cad5dd..00000000 Binary files a/public/gfx/sb-splash.jpg and /dev/null differ diff --git a/public/gfx/sb90x31.gif b/public/gfx/sb90x31.gif deleted file mode 100644 index bd2d315c..00000000 Binary files a/public/gfx/sb90x31.gif and /dev/null differ diff --git a/public/gfx/sb_sections.jpg b/public/gfx/sb_sections.jpg deleted file mode 100644 index 6295e1ca..00000000 Binary files a/public/gfx/sb_sections.jpg and /dev/null differ diff --git a/public/gfx/sb_sections2.jpg b/public/gfx/sb_sections2.jpg deleted file mode 100644 index 8f3cc7e1..00000000 Binary files a/public/gfx/sb_sections2.jpg and /dev/null differ diff --git a/public/gfx/sb_xmas2006_banner.jpg b/public/gfx/sb_xmas2006_banner.jpg deleted file mode 100644 index db632a3b..00000000 Binary files a/public/gfx/sb_xmas2006_banner.jpg and /dev/null differ diff --git a/public/gfx/sdlink4.gif b/public/gfx/sdlink4.gif deleted file mode 100644 index 9d9a0082..00000000 Binary files a/public/gfx/sdlink4.gif and /dev/null differ diff --git a/public/gfx/search-button.png b/public/gfx/search-button.png deleted file mode 100644 index 9844568d..00000000 Binary files a/public/gfx/search-button.png and /dev/null differ diff --git a/public/gfx/sep-bot.jpg b/public/gfx/sep-bot.jpg deleted file mode 100644 index 56390d77..00000000 Binary files a/public/gfx/sep-bot.jpg and /dev/null differ diff --git a/public/gfx/sep-mid.jpg b/public/gfx/sep-mid.jpg deleted file mode 100644 index 58ac318d..00000000 Binary files a/public/gfx/sep-mid.jpg and /dev/null differ diff --git a/public/gfx/sep-top.jpg b/public/gfx/sep-top.jpg deleted file mode 100644 index 9bb1c6c6..00000000 Binary files a/public/gfx/sep-top.jpg and /dev/null differ diff --git a/public/gfx/separator.jpg b/public/gfx/separator.jpg deleted file mode 100644 index d708194f..00000000 Binary files a/public/gfx/separator.jpg and /dev/null differ diff --git a/public/gfx/seperator.gif b/public/gfx/seperator.gif deleted file mode 100644 index b3a743d2..00000000 Binary files a/public/gfx/seperator.gif and /dev/null differ diff --git a/public/gfx/seperator2.gif b/public/gfx/seperator2.gif deleted file mode 100644 index ab5603bd..00000000 Binary files a/public/gfx/seperator2.gif and /dev/null differ diff --git a/public/gfx/shadow2.png b/public/gfx/shadow2.png deleted file mode 100644 index f2e216d6..00000000 Binary files a/public/gfx/shadow2.png and /dev/null differ diff --git a/public/gfx/shelldu.gif b/public/gfx/shelldu.gif deleted file mode 100644 index d36aadb8..00000000 Binary files a/public/gfx/shelldu.gif and /dev/null differ diff --git a/public/gfx/shellfront.gif b/public/gfx/shellfront.gif deleted file mode 100644 index b92132d5..00000000 Binary files a/public/gfx/shellfront.gif and /dev/null differ diff --git a/public/gfx/skinbase_logo.png b/public/gfx/skinbase_logo.png new file mode 100644 index 00000000..a19693dc Binary files /dev/null and b/public/gfx/skinbase_logo.png differ diff --git a/public/gfx/skinbaselogo.psd b/public/gfx/skinbaselogo.psd deleted file mode 100644 index cc3cdaaf..00000000 Binary files a/public/gfx/skinbaselogo.psd and /dev/null differ diff --git a/public/gfx/survey-120x60.gif b/public/gfx/survey-120x60.gif deleted file mode 100644 index 41d3fcc3..00000000 Binary files a/public/gfx/survey-120x60.gif and /dev/null differ diff --git a/public/gfx/teddy.gif b/public/gfx/teddy.gif deleted file mode 100644 index 2ca77bc4..00000000 Binary files a/public/gfx/teddy.gif and /dev/null differ diff --git a/public/gfx/teknidermy.gif b/public/gfx/teknidermy.gif deleted file mode 100644 index 49bd5760..00000000 Binary files a/public/gfx/teknidermy.gif and /dev/null differ diff --git a/public/gfx/test2.jpg b/public/gfx/test2.jpg deleted file mode 100644 index abb594a3..00000000 --- a/public/gfx/test2.jpg +++ /dev/null @@ -1,13 +0,0 @@ -P6 -160 128 -255 -}|llllllllllllllllllllllllllllllllllllllllllllllllllllllŷºʿǹ¿¹Ľ¸ūƹĽlnkSURXXVjjjyyyOTP|~{ʹ°ʹŰ˷½PUOS]TPZQ\c[`ja\c\ǿNSM`jaXbYOVNV`W^e^Êkul^j^pzqnxoisjdnelvmkulpzqisjZfZkulnxolvmfpgkulkulkulszs~қeee.42&,*598ttt¸ʽʾʼ߾ƶȿ͵CJBUWThicEKAR\S͹Ư߲߶̾Дblafper~rYcZQXPfrfnxo^h_ϔV`W\f]LSL{|uvZfZʳХ=D=А>BA"6+*@3"3)&$Y[ZҼĵɼḸɳKUL\c\9>:jjjRRRdddSXRS_UһĿ漼֝akbkwk{{\f]U\Twx]i]VbVԝMWNt~u{|S]TW^V\h\WcYYeYνпĿ}|'nnn$5+fxlCYL/%' %йѾʿķȇU\U9@9UUUccc[[[FKE̲ͲϴĿeleeof_i`ȚOYPT`T`g__f_KWMMWNȜV`WWcWaha˭ɰμmol%/&.:0.427M@fxl7MA4H?.;2`eaրuwt/6/'0<2+7-%+)9MBf|o=SF8MD%4-/<3U^Y[`\npmoqn1810702924;43:33:31;33:31;33:33:3ikhOVOPWPPWPPWPPWPPWPPWPPWPPWP`e_|||NUNPWPPWPPWPPWPPWPPWPPWPPWPT[TMTMPWPPWPPWPPWPPWPPWPPWPPWPQXQ_a^181070070181070070181070070181RWSPUQ4+7-495(<33G<-A6BYO->60@64D9vzAHAchdOYPuuyyr~rss}}xxo{oT`Tnsm2<3-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/afbYeY[g[hrinxolvmkult~u^j^[g[\f]}}}UaUlvmq{r^j^r|sisjlvmoypfpgQ[RQ[R[g[hrioyphriq{risjisj[g[UaU^c_,8.,8.,8.,8.,8.,8.,8.,8.,8.,8.LVNFKEWcWZfZfrfo{oyyr~r`l`ZfZ]g^z{y{y{y{z{y{y{y{y{y{y{y{z{y{y{y{y{uzvx~zu{wx}ykrk.:0+7-+7-+7-+7-+7-+7-,8.+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-*6,",$",$",$",$",$",$",$'3)(4*",$",$",$",$",$",$",$)5+%/&",$",$",$",$#-%#-%#-%#-%%/&+7-|||%)"' +$ -$)6-6H<*4,kpl^j^akbakbakbakbakbakbakbcmdqvp/91-9/-9/.:0.:0.:0-9/-9/-9/-9/.:0bgcYeY[g[^j^amahri^j^hri]i][g[^h_~~~UaUbnbbnbamahriisjfpgeod`l`Q[RQ[R[g[`l`fpgamaeodbnbeod[g[UaU_d`-9/-9/-9/-9/-9/,8.,8.,8.,8.,8.Q[SSZS`jaakbakbakbakbakbakbisjwxW\X+7-,8.,8.,8.,8.,8.,8.,8.,8.+7-,8.+7-+7-+7-+7-+7-+7-'3)$.&(4*'3)$ *"(4*(4*+5-",$]hbepl;I.91!+#:FC?nnn|||[[[$.&-7/#-%+7-+7-+7-+7-+7-+7-+7-.91!+#8D:COEEPHFQIFQIISKMWOCOE-7/.:0ǿLQM'4@6.:0kpl[g[hri{zr|swxuv{zisj[g[ovo/91-9/-9/.:0-9/-9/-9/-9/-9/-9/-9/bgc_k_r|s`l`kullvmkulisjlvmlvm^h_~~~UaU[g[amabnbkulnxolvm^j^[g[Q[RQ[R[g[t~uisjisjhrilvmnxo`l`UaU_d`-9/-9/-9/-9/-9/,8.,8.,8.,8.,8.Q[SRYR[g[[g[zyr|szyuvr|s{zNXOEOFjvjlxllxlq}qiuiq}qjvjkwko{op|pdpdnznnzn`l`U_Vy~z]d\ͺuztlvmmwnUUUUUUUUUUUUUUUUUUUUUUUUUUUmmm$.&+7-+7-'3)&1)%ǘvvv8:9!+#-7/#-%+7-7E8+7-+7-+7-+7-+7-.91!+#FQICOEOYQFQIISKKUMCOE-7/.:0ş~afb3:3#-%0:19E;.:0kpl[g[[g[[g[[g[[g[[g[^j^[g[[g[ovo/90-9/-9/.:0.:0-9/-9/-9/-9/-9/.:0bgc\h\fpgisjfpgeodhrihribnbbnb^h_~~~UaU[g[amabnbeodbnbeod]i][g[Q[RQ[R[g[fpgeodfpgfpgeodfpg^j^UaU_d`-9/-9/-9/-9/-9/,8.,8.,8.,8.,8.Q[SRYR[g[[g[[g[[g[[g[^j^[g[v{uNXOXbY\f][e\[e\[e\[e\[e\[e\[e\[e\[e\[e\[e\[e\[e\akb{c~}ˤsut\a]]b^]b^]b^]b^]b^]b^]b^]b^]b^`eaY^ZdieTYU'3)+7-+7-'3)&1)(2*ЧoooAC@*6,.80#-%+7-9G:GXH6D7+7-+7-+7-.91!+#ISKEPH:FCHD273%/'+7-+7-'3)&0(*6,%!!'*6,-7/#-%@RBOePTlTVnVH]JPfQJ]J-80!+#9E;KUMDOGPZRGQIISKISKBME-7/.:0Ͼɼ{}z.:0.:0.:0.:0.:0.:0kpl[g[[g[{zq{rr|st~uama[g[ovo/90-9/-9/.:0.:0-9/-9/-9/-9/-9/.:0bgcYeYkullvmlvmhrinxooypkulnxo^h_~~~UaU[g[bnbfpgkulnxolvm^j^[g[Q[Rbgc`ea`ea`ea`ea`ea`ea`ea`eabgcMTM-9/-9/-9/-9/-9/,8.,8.,8.,8.,8.Q[SRYRhrir|sq{rwx}|t~uU\THJG.5.NZNZfZ]g^]g^]g\WmV]g^YcZ]g^YcZ]g^YcZblcVXU[]Zzzz|||Zd[\a[bnbuu|}vuPPPPPPPPPPPPPPPPPPPPPpppƸ)3++7-+7-+7-2<45?75?75?75?75?75?75?6*6,5?76@86@86@86@86@86@82>4,6-3=53=53=57A93=53=53=53=57A9,8.bibhohgngbib_d^mol.:0.:0.:0.:0.:0.:0jokFPGGQHGQHGQHGQHGQHGQHGQHISJotn/91-9/-9/.:0.:0.:0-9/-9/-9/-9/-9/afbYeYfpgeodbnbbnbamaeodbnbeod^h_~~~UaU[g[`l`bnbeodbnbeod]i][g[Q[R^d`-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/,8.,8.,8.,8.,8.Q[SMTMEOFGQHGQHGQHGQHGQHGQHNXOJTKEOFVbV[g[[g[[g[[g[YjXOI[g[]w\\h\ZtY_k_WtV`l`HJG|~{ejdƫnnnJLIJLIJLIJLIJLIJLIJLIJLIJLIJLIQSPOQNXZWEGD#-%+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-diceqemymo{odpdamaY^Z.:0.:0.:0.:0.:0.:0dieOYPZfZZfZssvvr~rZfZZfZUaUrwq/90-9/-9/.:0.:0-9/-9/-9/-9/-9/.:0_d`YeY`l`oyphrilvmnxokulisj[g[]g^|||UaU[g[amahrikulnxolvm^j^[g[Q[R^d`-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/,8.6@8OVOCME,8.Q[SDICWcWZfZamaxx||o{oZfZy~xV`Wfrfo{ojvjiuifrfiuifrfjvjcoc\^[fffV[WYcZSUR_f_t~uyz~```````````````uuu)5++7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-mrlcocgsggsgdpd_k_bgc.:0.:0.:0.:0.:0.:0kpl^j^akbakbakbakbakbakbakbcmdqvp/91-9/-9/.:0.:0-9/-9/-9/-9/-9/.:0^c_VbV\h\ak`fpgcmdfpgcmd_k_YeYZd[{{{UaU[g[^j^bnbeodbnbeod]i][g[Q[R^d`-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/-9/.:0DNFinjvxu'.'UZVSZS`jaakbakbakbakbakbakb\f]iuifrffrfcoceqecoccocamaOYPNXOah`nsmdicglfkpjnsmpwpVVVVVVVVVVVVVVVdddxxxtttOTPcjccjccjccjccjccjccjccjccjccjccjccjccjccjccjccjccjccjccjccjcbibbibbibbibbibbibbibbibbibbibbibpuoMYM[g[[g[[g[YeYbgc.:0.:0.:0.:0.:0.:0kpl[g[[g[q{roypwxr|swx[g[[g[ovo/90-9/-9/.:0.:0-9/-9/-9/-9/-9/-9/_ea`ea`ea`ea`ea`ea`ea`ea`ea`eainjlnkUaUlvmisjnxolvmbnbq{risjnxoQ[R^d`-9/-9/-9/ALDglh`eainjchd`eaoqnsury{x}}}wwwOOORYR[g[[g[kul~}~}q{r[g[غȴkplfkginjjokjokjokmrnbgclqmaaaBGCAHAJQJW^WRYRX_XPWPHOHOVOW^WKRKPWPGNGY`Y[b[T[ST[TT[ST[TT[TT[TT[ST[ST[ST[ST[TT[ST[ST[TSZSSZST[TT[TT[ST[TT[ST[ST[ST[ST[TT[TT[ST[TT[ST[ST[TuzvMYMVbVVbVVbVS_Sinj0<2.:0.:0.:0.:0.:0kpl[g[[g[[g[[g[[g[[g[[g[[g[[g[ovo/91-9/-9/.:0.:0.:0-9/-9/-9/-9/.:0-9/.:0.:0.:0-9/-9/-9/.:0-9/.:0-9/_d`UaUfpgbnbeodeod^j^hribnbbnbQ[R^d`-9/-9/3?5ɀQSR]d\YeYlxlyyr~rnznkwkXdXR\Sfffhhh___{{{RYR[g[[g[[g[[g[[g[[g[[g[t{t™999PPP666$$$#$$$8=9wwweeeW^VUaUfrf~r|smwnkujq{rlvkhrgamanxolvknxofrfUaUUaUUaUUaUUaUUaUUaUUaUUaUUaUVbVVbVVbVUaUUaUUaUUaUUaUUaUUaUUaUUaUUaUUaUUaUUaUUaUVbVVbVVbVUaU|~{.:0.:0.:0.:0.:0.:0kpl[g[[g[eodzyr|st~uama[g[[g[ovo/91-9/-9/.:0.:0-9/-9/-9/-9/-9/-9/-9/.:0.:0.:0-9/-9/-9/-9/-9/.:0-9/_d`UaUbnblvmnxoq{rhrinxokuleodQ[R^d`-9/-9/hohBHDou3<7ZfZgsghtheqeamaiuiZfZXdX777YYYuuuRYR[g[{z{zoyp{z{zzyhogaaa"""---TTTQQQKKK999+-**4,,8.,8.ntp~z|yz|yz|yz|yz|yz|yz|yz|yz|yz|yz|yz|yz|yz|yz|yz|yxzwwyvwyvwyvwyvwyvwyvwyvwyvwyvwyvwyvwyvwyvwyvwyvxzwz|yz|yz|yz|yz|yz|yz|yz|yz|yz|yz|yz|yqvpz{{zrwqkplpro.:0.:0.:0.:0.:0.:0kpl[g[[g[[g[[g[[g[[g[[g[[g[[g[ovo/91-9/-9/.:0.:0-9/-9/-9/-9/-9/.:0-9/.:0.:0.:0-9/-9/-9/.:0-9/.:0-9/_d`UaU`l`fpgbnbeodbnbbnbbnb`l`Q[R^d`-9/-9/jqj;D?/@69F=ÁS]Tama_k_[g[\h\[g[R\QcjbaaavvvRYR[g[[g[[g[[g[[g[^j^`l`ZfZGQHVVVmmmooooooYYY999===CCC###(((***:::???---)/+,8.X^ZHRIISJLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMLVMotngsgq}qlxldpd`l`chd0=3.:0.:01=3kpl[g[[g[nxouvq{ruvisj[g[[g[ovo9C;7C96B86B85A77C9-9/-9/-9/-9/-9/-9/.:0.:0.:0-9/-9/-9/-9/-9/.:0-9/]b^UaU[g[fpglvmhrioyphrihri[g[Q[R[a]-9/-9/7A9rxtjjj[[[fff```WWWTTTNNNUUUPPPPWP[g[zyuvt~ukulr|sr|snxoZfZ^`]ԽSSS888lll"""!!!!!!222333---)+(RWSAKB½޾½½½puofrfkwkjvjdpd`l`cjc3E5.?/$2%*8+&4'$0&jokFPGGQHGQHGQHGQHISJGQHGQHISJotnRYRRYROVOMRLKPJOTNafbQVPQVPZ_[SXRNSOUZV`eaMRLHMGJOIJOKOTPLQMFKEHMGfheS_SYeYak`isjak`cmd_k__k_YeYOYPmolNUNFMFCJCJOKKKKNNNDDD&&&...000;=:BGCy~zˠY`YQ[RR\SQ[RQ[RQ[RQ[RQ[RQ[RPZQtvs\\\뵵:::XXX444$$$%%%000000000---```BLCmrk{yfkepuny~wmrkzxmrkjohtyry~w{yqvo~|punuzs~puoNZNamayxYeY_f_ 5""5""5"2  dieOYPZfZZfZmymuup|pZfZZfZUaUrwqrwsuzvotprtqhjgjlipro[]Zac`qspWYVLNK\^[[]ZOQNHJGbdc`b_`b_ikhJLIJLImmmikhikhgifgifhjghjghjgikhikhmol^`]JOKEKGX]W;;;AAAJJJ 444>>>OOO\\\bbbegf^`]WYXSUTŸdddeee```lnknnnnnnmmmkkkkkknnneee[[[^^^𭭭666KKK(((''' %%%---000000000___BLC||}}~yx}|}|~~t~uuv{|t~ut~ut~urwsNZN^j^rqVbV^c]%%%   kpl^j^akbakbakbakbakbakbakbcmdqvp}|uwtfhedfcbdc[]Z\^[Y[XIKHHJGHJGHJGHJGIKHHJGHJGFHEFHEIKHGIFHJGHJGHJGEGDMRN;B;_d^[[[DDD+++OOOXZWhjgnpmmmmnnnkmlikjΊmmmTTT]_\ikhjlklnmlnmkmljlkjlklnkxxxooohhh𙙙HHH***///,,,+++###///000000```BLC{|szs|{ryr+-*sxry~zv}v^c]isj]d\yyOYPR\Styso{oHUKIVLHUKERH9F<- kpl[g[eodzyoypwxwx~}fpg[g[ovovxurtsuwvnpmgifrtqjlijlijlkjlijlijlijligifegfbdckmlegfgifkmlacbhhhlll___LLLbbb333333888?IA05/%%%...```BLC{zy~x~}v}u^e^hohpwpmtm~}rwqxxnznjtilxlxx~}~y{x~~z|eqg3?5kpl[g[[g[[g[]i][g[[g[[g[[g[[g[ovoɽ¾JQImymeqeamaUaUUaUYeY]i]YeYYeY^j^YeY[g[[g[]i]YeY]i]UaU^j^[g[YeY[g[ffffffggg\\\[[[ŶOOOBBB===***6;7]i_lxnFMF___BLCwx|{yyefefotpfrfiuiiuidpd_k_w|xmwokpl[g[[g[[g[oyp{zzy[g[[g[[g[ovoؙ`g`mymeqeamaZfZVbVZfZfrffrf[g[^j^`l`\h\amafrf[g[dpdZfZbnbbnbcocdpdםRRRMMM[[[[[[\\\Z_YOVOOVOOVOOVOOVOOVOOVOOVOOVOOVOOVOOVOOVOOVOOVOOVOOVOOVOOVOOVOOVOOVOOVOOVOPWPHHHRRR===,,*:D;UaWZf\\h^NUN,.+ssqBLCjok]NXOBIBchbchbOTPlslTYSchbQVRQpPQpP8ZŝԈ{SVÜkulypuofrfo{onzndpd`l`injKUMKUMKUMKWMEQG3?5kpl[g[[g[[g[[g[[g[[g[[g[[g[[g[ovo9C:5A7)5+,8.fph͔З;;;CCCIIIOOOMMM~OYPkwkvvcockwko{o[g[_k_[g[[g[xxo{o[g[q}qlxlgsgiuitt[g[uubnbkwko{onznlxlhthovoLQMSXTHHH---.801;23?53?54@6rwqBLChricmdw~wyyyy^}^^}^ΐ~ԥpuoP\P`l`lzm[g[YeYhmiHRIISKKWMNZPMYOIUKkpllvmr|sq{r}|{zr|s{z}|kulovo7A9CMECME%1'MTM~~~777MOLT[TIKJKKKFMEQ[RS]TXbWWaXT^UQ[RQ[RQ[RQ[RQ[RQ[RQ[RQ[RWcWWcWjqiszsszsszsszsszsszsszsszsszsszsszswww}}}tttsurtvstvsrwsuwtxzwpuqMYM`l`o}n[g[XdXglhFRHJWMKXNLZMKYLLZMjokFPGGQHGQHGQHGQHGQHISJKULISJotn=G?8B9;G=.:0?I@mrn___BGCU_VXbZWaY\c\x}yRvRSSSSSSSSZw[_i`_i`_i`_i`_i`_i`_i`_i`]i]~~ՍR\Qcocxys}tnxor|snxmt~uuvvws}toypxyeqes}tUaUUaUUaUUaUUaUUaUVbVVbVVbVUaUUaUUaUUaUUaUUaUUaUUaUUaUUaUUaUUaUUaUVbVVbVVbVUaUUaUUaUS_Sȭݞ[e\^h__k_amaamaamadieOYPZfZ]i]uuuusscocZfZUaUrwqFPH7C90<21=3'3)8B::?;_a^nnniii\\\hjigihWYXgihhjiWYXfhgjlk^`_acbjjjfff[]\kkkikjnnn{{{ttt```kkkhhh\\\GGG.3/KUMS]TY`XV`W]d]vxuISJBLCOYPJTKFPGKULNXONXOLVMFPGJTKPZQMWNNXOPZQĺŎǾԵryrw~wzzzzu|u{{qxqryr||ryrv}vw~wszszzovoovoovoovoovoovopwppwppwpovoovoovoovoovoovoqxqryrryrryrryrryrryrryrryrryrryrryrryrszsִť֜KWMISKKWMO[QP^QP^Qkpl^j^akbakbakbakbakbakbakbcmdqvp3=5GQIEOGISKR\TYc[Y`Y?IANTPT[TFMF4>64>6;E=9C;:D<>E>DKDHOHFMFCJCDKDHOHDKDDKDĈooo^^^AAA777999FMFRYRT^UX_WWaXXbY^e^oqnGQHhth~~ssgsgvv~~gsgmymV`Wѡأ׫NPM\a[\a[[b[\a[\a[[b[[b[[b[[b[[b[[b[[b[\a[[b[[b[\a[[b[\a[\a[[b[[b[[b[[b[[b[[b[[b[[b[[b[[b[[b[[b[\a[[b[\a[\a[[b[[b[\a[[b[\a[\a[\a[[b[\a[[b[\a[\a[[b[[b[\a[\a[\a[[b[[b[[b[[b[[b[[b[[b[[b[[b[[b[\a[vxunsokwk_k_iuimym^j^fkg>L?;I<6B66D75E84D7kpl[g[ama{z{zr|skulwxhri[g[ovoHRJ[e]T^VLVMOYQcjc^e^ahajqjgngX_WPZRFPGDNF?IA=H@CMEMWOU_WU\UJTL\c\MWOISKv|xrrrOOO999999IPINXOR\ST[SV]UX_WXbY^e^npmT`TV`WYcZZd[Zd[YcZYcZYcZYcZZd[Zd[YcZYcZXbY_i`ި楥ͻ徾EJDHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIISJLVMHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIHRIKULV`Wmolpuqr~rdpdo{osseqefkgJ>@=070=D<=Dsk~ws~yz{|{z{rwsjqjpwpw~w{{szsoypoypfpglvmnxonxoisjq{rlvmeodoypisjhrilvmoyphriq{risj`l`[g[U_VКCJCV`X]d]UWVARHL]SMZQ­/1.{z{zjqi=D<=D<=D<=D<=D<=D<=D<=D<=D<=D/3'+!$&*"$ !(!$+$130222egdKUL|~{ǏKUL[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[KULHRIHRIryrMOLV`Wlxlmymmymmymmymjvjfpgjli}w~{w}y{vzu|~{v{ux}w|{~~~{{w~wt{tnso|}cmd[g[[g[[g[[g[gqhuv[g[[g[[g[[g[[g[[g[cocq{rpzqisj[g[[g[[g[[g[YeY;B;OYQPZROYQMWONXO|~{VXULRN.$EUKXnaqyB]N*G5":,-#(%#')+5-/51/40352gifKULüźƿǒLVM[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[ISJfrfWcWS]TPRO_i`wwxx||xxjvjfpgjli|wxz{wzyutq|nnunkul[g[[g[[g[[g[[g[[g[[g[[g[nxouvuvr|szyr|s[g[[g[[g[YeY:A:KUMOYPNXPNXPMWNkmlUWV5@:#3<7I_R^tg'?1+$' &'##&(,2..40241463ikhKULɰƿĽüĶ»ǕLVM_k_kwkmymyyq}qkwktttt^j^[g[iuiq}qnzno{ottq}quuttuufrfyynzno{o[g[[g[WaVYcZZd[WaXSURlvm{{jvjfpguwtہ}~v{w{u{wzv|wuwtxzwx}yzys}t[g[[g[[g[_k__k_[g[[g[amavw\h\[g[}|s}tlvm[g[[g[YeY:A:KUMOYQOYQMWOS]UY[ZXZY094"?OEF^POeX!1'(!-"%%%(!-#($'-)>D@nsoȲ®ǗLVM_k_eqedpdamaeqeamacocamaamadpdcoccocama`l`[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[BLCPZQMWNT^UPRO_i`wwxxxxxx{{jvjfpguwtۅ}|{{~{}t~uisj[g[[g[oypuv[g[[g[pzq~}\h\s}ts}tbnbpzq[g[[g[YeY;B;JTLLVNRYRQXQinjXZY>@? &*)/%6N@Vj_Wh^dqhntrlrnjzpitnejfcigoyq{{fmfglhprqzzzôKcKǙLVMdpdfrfhthnzniuimymnznfrfeqeo{ojvjo{olxliui[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[NXOamaYcZXbYJLIOYPcocdpddpddpddpdamafpguwtیsut|}v{wy{xq{rmwn[g[[g[pzqzy[g[[g[pzquvhrigqhmwnkuls}tq{r[g[[g[XdXCEB6;7MON]_^=?<^`]npoUWVGIF#'&043&5.1#@TH̤LSKMWN^h_krj^h_akbV`Wņ}|~~~}~}|~~}|}|}||~{ikhz|y}|ǵǘLVM[g[[g[[g[[g[[g[[g[[g[[g[WcW]g^glfaf`af``g`bibcjcbga_f_^h_[g[[g[[g[[g[[g[[g[KULKULKULT^SQSPglf^h_JTKXdXfpguwtې{}z~qspϼhrihri[g[[g[]i]isj[g[[g[amauvzyfpglvmt~ur|slvm[g[[g[WaX@BASUTTVUUWVUWVUWTgifUWTKML -31.$*@3ᯯܵT^UQ[Rcmdlvmblcdne[e\ѣQ[R_k_nzniuihthjvjiuimymhthkwkZfZp|pq}qcocjvjiuicockwkjvjkwkR\SǕLVM[g[`l`^j^\h\[g[[g[[g[[g[OYP`g_cmd[e\Zd[Zd[XbW]g^WaXdneW^WZfZcoc[g[[g[[g[[g[ISJcoc`l`U_VXZWdkd~}ɄNUM^j^fpguwtۋz{frfssxxegd~~}~ryrlvmlvm[g[[g[[g[[g[zyPRQY[XUWTQSR/40'"0E6vxuwyvwyvwyvwyvy{x{}z~}~}~}~}~}z|yĉ~~ɵǒLVM_k_iuio{oo{oq}qiui^j^dpdyyr~rttq}q_k_[g[WaVYcZZd[XbYUWT`g`xwɀQ[Rcocfpguwtۏjlikmj~xzwcmd[g[[g[[g[[g[[g[[g[[g[ĮuzvY[XTVS$('/40!(!!,$[a]XdXS_SOYPOYPOYPOYPOYPOYPOYPOYPOYPOYPMWN֧ǐKULhthfrfcocfrfdpdfrf^`]_a^_a^_a^_a^_a^_a^cebR^R[g[[g[[g[BLCR\SKULT^UZ\Y||~:?9iuifpguwtیISJKULKULKULKULKULKULKULKULKULegd~}]d]Q[RQ[RQ[RQ[RQ[RQ[Rjtk}}}zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz|||uwtTVSFHE,.-*0,$UZVS_SO=0A1fme}|R\SS]TXbWZdYWaVS]TXbWS]TZdYXbWYcXZdYXbWQ[RQ[RQ[RQ[RtmqsrSURTVSPROQ>8K8oypuzvy{xfhg]_^_a`_a`iiiffflllӻϷ܏LSLTVSTVSFHGjliOYPEOF@MNFsyo˩|pPROPZQʒnsm]i]coc_k_eqe\h\ȧʭDŽJTKhthnznq}qttxxo{ofrfQVPJLI,1-7<6R\SU_VXbYZd[PZQT^UWaXYcZWaX]g^q}q_k_[g[[g[WaVYcZZd[WaXdfeɀ:?9jvjfpgcebR^R}xzˈfrfgsgcoc`l``l``l``l``l``l``l`FTG\o[XkWz|y{zPUQLVNEOGcie}~otp̵JTKZfZgsg`l`{{p|plxllxlmymnznr~rlxl_k_{{⛝IPIPWPOTNVXUkmjOYPEOF@MNFssky]_\WcW0QJ -/zjoijvj`l`[g[\h\ZfZĨǀJTKeqefrffrfhtheqemymcocYcXQ[RNXOZd[hthfrfkwklxljvjfrfo{obnbkwkfrfeqe[g[[g[[g[BLCU_VKULQ[Rdfe||:?9jvjfpgac`HRI~vwt׽mymiui[g[[g[[g[[g[[g[[g[[g[[g[IWJYoZWmX}~{||}{}zRYROYQ_iaz{w|xєв~}GNGJTLKUM}|OYPEOF@NPE\bXI2,f[ITUOORKXdXVbV:G@$=7nsmcoc\h\n|on|oamaYeYR\QQ[RQ[RXbYcoeamcWaXcoeamcV`WWaXiuigsgQ[RQ[R~}yyyJTKdpdeqefrfcoccoceqecoc`l`_k_amafrfhthdpdfrfeqecochthfrfcocfrfdpdcoc[g[[g[[g[NXO`l`\f]dkd_a`~:?9jvjfpgcebX_Wrohskϰeqegsg[g[[g[[g[[g[[g[[g[[g[[g[{zCQDEXDAT@q{rqvr}|uwtQWSGQIU_W}~otpz{ċ~~~}}}\\\wpſRWSEOGJTLOYQv{wz|yOYPEOF@@MVE[g[ZfZWbZMUyXdX[g[LVMKULOYPXdXamaz{{|lzm[g[ZfZYeYYeYuueqeuuo{oxxuu}}eqe~~}}YeYWcW~~~ISJhtho{oq}qo{ozznznttuuq}qss_k_[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[\h\^j^XdXgihɀ:?9jvjfpgfhemtmxmn{j~hthhthhth`l``l``l``l``l``l``l`mtm7C5=N<7H6isjy~z|~{SZSDOGDNFv|xuzv|}sssEKG5@:HMI}}uuvfwxy|`ffn{lot4;4ISKJTLLVMQXQhmiOYPEOF@@MVEYd\>CIQ\UaU`fboyxlqk[g[qrqrcocjqiyyyLSK[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[T`Tw|xced||:?9jvjfpgegd^l_vroyq{}zmymnznjvj[g[[g[[g[[g[[g[[g[[g[x}w9G8CVBCVBmyminj|~}qspU\UNXPJTLhohx}ypuqnsoEKGj|p4D:\a]TTlex}eoxxx;@8ntAUJ0@6MXP{{{=?E=BLCS_Sc_TgB:{URgfd=HDQVRZZZ[[[YYYYYY^^^`ba`ba`ba`ba`ba`ba_a`aaabbbjjjppppppppppppppppppooogifW\VU_VV`WZd[Zd[[e\Zd[Zd[YcZW^VӨLVMNXO[e\V`W^h_U_V_i`Q[RNXOwyv_i`Y`XkmlɄQ[R_k_fpggifo{q^mVZgV*,+021-9+_i`y~z|}wyxV]VLVNHSKKVNqvrpuqafbUZVtvu\a]NYQWYV'.'-4-E=ZfZ_fE66QQ5knO]hX[g[[g[[g[[g[[g[[g[WcW^h_kplV`Wlxllxllxllxllxllxllxllxllxllxllxllxliui]g^S]TQ[RKULLVMEOFKULKULKULKULKULKULKULKULKULKULKULKULKULKULKULKULKULKULKULKULKULKULKULKULLVMUaU^j^_k__k__k__k__k_^j^isj\^[kwmZeWXbW`e_iiihhhhhhhjifhghjihjghjiffffffffflllbbbdddaaaKKK"$!%1#^h_qvruzv{||~{U\UMWONXPOYQLVNdkdpuqafbZ_[INJ7<8INJDIE273FPHJTLKUMOYQNXPKUMFPHFPHISKNXPXbZOYQKVNNXPQ[SS]US]UV]VX_XX_XW^WOYQhmiOYPEOFF^FZfZY -IJQRJ@G?NXOZ_YhohAKB-7,ZfZdnLJL'zyAik9U`R[g[[g[[g[[g[[g[[g[U_VbnbkplOVOblcblcblcblcblcblcblcblcblcblcblcblcblcakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbakbblcblcblcblcblcblccmd[e\nsoT_QT`RP\PCMDFPEEQGEQGCME[e\]h`aldakcbldbldbldMXP=G?7A94>6:D<6@7-;,_i`lqmz{xzwX_XMWOLVNNXPITLNXPrwshmiZ_[PUQSXTUZVOTPJOKGLHMWOMWONXPZd\R\TNXPJTLFPHGQIMWOV`XPZRKVNLVNLXNQ[SMYOQ[SS]UT^VW^WOYQhmiOYPEOFF^FZfZJLI]_\5:4VbVS_S-2,(/(&2$'1(ZfZXdX/1.687HOGZfZ[g[[g[[g[[g[[g[XdX`ja[g[kplAAATVSUWTVXUWYVY[XZ\Y[]Z\^[]_Z_a\]b\]b\`e^`e^^dZ]b[\aZ\^Y\a[_d^_d]\aZ]b[[`YX]WX]VWYVTVUVVVUWVUUUTVSUWTSURSURTVSUWTXZUZ\W[]X\^Y^`[^`[_a\]b\`b]bd_af`dfaegddfcegdgifhjgLXJR^PR^RQ]QP\PNZPJVL\g_q~tuxx}y~y}x|xz[e]IOKDIE?D@=?<8:76=6bib{|v{w~}~}Y`YKUMLVNGQILVNJTLT^VV]Vlqmz|yz|yz|yz|ytvsqsp}~|~~w|xw}yz|v|xu{wv|x}~~w}yxxy{|}|}|}}~|}|}{|yyqvpjjpzq_k_S]RPZQXdX[g[[g[R^RR\S_i`cmdlvmlvmblc_i`fpglvmlvmlvmlvmlvmisjovnpzqlvmy~z495AHAELEJQJOVOT^V`jahrigqflyhukvlyoywjteudrdocxjuesbmYcN`yQBW6?W3>I;241,.+ "$&# "!!#).(6;5AF@JQJQXPW_T^f[cmbishq{p}|COEIWHGUHJXKJXKS_Ukqm]c_]b\]b^\a]qsp[`Z}~uwtûpuqISKHRJKUMV`XʾU\U]d\X_X]d\Y`X_f_]d\_f_V]U\c\ʷWaXZd[Zd[Zd[Zd[||Ŀ—}sj{cvdC\49L0495CEB%'$ (*)352@B?JOKV[W_d^hoht{sŽBN@GUDFTGHVGHVIq{s~pwp|||@JBKUMOYQݲű۷T^U[eZhriakbT^U^h_YcZhriT^SU_VÿXkXĪKULYeYYeYYeY[g[ĭdzâǐzwr|dp^=P2~oqnNPOżιDPDHVGHUKLZMKXNfrhsxtrwqrwqrwqrwqrwqrwqrwqsxrvvv{}|DNFITLOYQ~z|yz|yz|yz|yz|yz|yz|yz|ygifRRR~}~IKH\^[\^[\^[kmj}}}ŌNUNHRIISJMWNOYPOYPOYPOYPOYPOYPOYPOYPOYPOYPOYPOYPOYPOYPOYPOYP`g`xvqq[dzTv{u̲ɞY[X#%"֏puo}|nsoɄftersuvESFHVGGUHFTGHVIpzqhmggnggnggnggnggnggnggngkrk}}}y{z_a`JUMPZRchdMWNBLCEOFFPGEOFEOFFPGEOFEOFFPGEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFDNE7>7DNEEOFEOFEOFEOFS]Rejf495?F??F?@G@RYRX]WR^RR^RR^RR^RR^RR^RR^RR^RR^RR^RT[SKUL_k_[g[[g[bnbfrfiuiiuihthfrfiuieqelxliuihthhth[g[[g[[g[frf[g[bnbah`uqzabNVaP#02/PRO~~~lllGUDFTEFTGGUHKXNovn~}}|~}u|t|{~}~BLDMWOKUM]b^HRIXdXmymuu^j^p|puudpddpdttmymssZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZYeYYcZ`ea;E=NXPMWOMWO`g`[bZ[g[[g[gsgiuigsghthiuibnb[g[WcWMTLVbVlxlmymlxlhthiuigsgjvjiuifrfiuigsgiuijvjgsggsgbnbbnbbnbbnbbnbdpdS]R{mjmVZpLJRGϾ!).*8=9>C?574*/+).**/+.3/493@E?PRMX]WbgainhrtoxzwIWFHVGIWJJXKZg]y|bgcV[WV[WV[WUZVSXTRWSQVRPUQLQMJOKJOKJOKJOKKPLMRNxzw}}}___VVVEGF:DE>MWOOYQKUM[b[]d\[g[[g[bnbgsgcocgsgiuifrf[g[[g[XdXWcW[g[[g[[g[eqebnbbnbbnbbnbbnbbnbbnbbnbbnbbnbbnbbnbbnbbnbbnbbnbcocT^Srzkk^`|KFV>C?:@<7A9=D=BIBLQK]d]puo½O]LP^OR`SR`Sn{quxq~tp}sozrdogXe\Q[SJTLITL,8.)! +#*"",$",$+5-bgcprqtvuz|{{}|vxw~GLH;B;>H@EOGFPHISKhmiZfZ[g[t~u̼{}zXdX[g[[g[qxqZfZLSLkpl>E>NXPMYOLVNXbZ^e][g[[g[nznfrfr~rhtheqekwk[g[[g[XdX_k_nznnznlxlbnb[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[bnbT^S{vyakSL`=5@/7<6t{t(-)384@B?;@<7<86;77<8;@<;B;ELEU\Uchbsxq~|LZIHVIJXKO]Puzwyy{]h`OZRQ[SOYQQ[SQ[ST^VüuzvovoU_WBMEFPHGQIhmiZfZ[g[s}tͺвz|yWcW[g[[g[glhfhgkmlbdc{}zT[TWcWR\Skpl5:6Q[SOYQMWOY`Yu|uWcWXdXXdXXdXXdXXdXZfZ[g[[g[WcWKRJWcW[g[[g[[g[hthhthhthhthhthhthhthhthhthhthhthhthhthhthhthhthhtheqeT^Szv\uKNd>;I/-5&24/+0,/40051;V`Wgqfdnednekulhrgmwn]g^ɴDzķTbSN\ONZNboe|~{}|}|}|}|}|}|~~~tvsy{x}||~{uwt}||~{{}zz|yz|y~}|~{~~~}}|}|}|}|lnk;E=GQIGQIhmiZfZ[g[s}tսy{xWcW[g[[g[FKGfmfkwkr~rwwo{oo{oeqeo{or~r[g[U_VWaXBGAkpl576130BDC^`_oqpĿ̿y~xuzt^j^bnbeqecocdpdbnbbnbbnbbnbbnbbnbbnbbnbbnbbnbbnbbnbbnbbnbbnbbnbbnbT^Smoj/<*&1# %!')&ŷ<>;796|{v}vt{tt{tszsnunszst{tֶKYJBPCBNBdqgSXRXbYISJHRIHRIHRIHRIHRIHRIHRIHRIHRIWcWLVMJTKJTKJTKJTKJTKJTKJTKJTKJTKJTKJTKJTKJTKJTKJTKJTKJTKGQH^c]GRJHRJhmiZfZ[g[pzqxxxmolWcW[g[[g[JTKz|yWcW]i]^j^`l`^j^^j^[g[[g[[g[[g[U_VS]TBGAkpl354IKJIKJEGFRTSһ}~nznsscochthV`UWcW[g[[g[\h\kwklxljvjiuijvjp|pkwkkwko{ojvjkwkiuimymlxlgsglskjqjeqeT^Sikf3>0-2,%'$(*'241TVS?D@}}}Z_Y[b[[`ZW\VV[UV[UV[UV[UV[UV[UV[UV[UV[UV[UV[UZ_Y\a[\a[y{xNZNO[OQ_Ry|MWN^e^LVMfrfbnbgsghthq}qdpdhthkwkmymR\SWaXXdXcmbjtieodblakujgqflvkeod_i^dncmwldncVbVbladncblaYeYOYPISKJUMhmiZfZ[g[]g^_f_SZSISJJTIJTIJTIJTIJTIJTIJTIJTIJTIJTIKWKZfZ[g[[g[MWN:::coc{zr~r{zp|p[g[[g[[g[XdXS]TU_VBGAkpl@BAACB465.0/CEDenifvl1<6£amakwkkwkmymo{or~rp|pp|piuip|plxlr~rmymq}qp|pjvjssmymmymiphhoheqeT^SUWT!( #("#%"---IIIʻfhebdakkkUaU[g[CMDT^UmwncmdlvmU_VU_Vblc\f]XbY`ja`jaWaXGQH\h\[g[chdFSIKYLQ_Rw|MWNS_SS]T_i`\f]akbblcfpg_i`dnecmdeof_i`NXONXONXONXOQ[RZd[NXONXONXO[e\_i`_i`_i`gqhisjhrieofisjhrigqh}|GRJJTLhmiZfZxxxYcZzyzyzyzyzyzyzyzyzyyyiphZfZ[g[FMF6;5S]T[g[[g[[g[[g[[g[[g[XdXWcWVbVU_VWaXBGAkpl384:A:FPH]d]@?fkeX]YgihUaU[g[T^Ucmdoyphri]g^kulkuldnedneakblvmdnedne\f]^j^[g[fkgESFHVIQ_Rv{NXObibUaUisjYcZO[OR\SO[OO[OYcXkujR\SUaUJTKish`j_gqhWaXJTKkuj^h]eodV`W[g[[g[[g[]i]\h\\h\^j^jvjiuiblcHSKGRJhmi~~;A=+8/5;7ZfZISJ.0-YK>{ztt[g[[g[ZfZWcWZfZ[g[YeYS]TS]TBGAkplAHAPZROYQPZRAKCdie5B9y|ƒQ[R[g[hthiuikwknznvvo{ofrfnznnznnznlxluur~rq}qnznsscoc`lXghWcUWaXiii%*$).(-/*.3/:<9ȾVXWUaU[g[FPGDNEEOFEOFEOFEOFEOFEOFEOFFPGPZQ[g[[g[[g[[g[[g[kpluzvDPDESFR_UrwNXObibq}q~}nznwwWaX~}Zd[qxqryrryrryrt{tpwpqxqt{tyyszsovoovopwpv}uovonunovov}v­JTLISKhmiEGF+;1R[Vv{wS]TT^UAH@OWL[g[[g[[g[YeYWcW[g[[g[[g[[g[T^UU_VBGAkplAHAQ[SQ[SS]U]b^}}}}|R\SS_ST^SZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZZfZR\S]g^bbb&+%%*$05/6;7=?<XXXUaU[g[DNE[g[[g[[g[UaU[g[XdX[g[[g[ZfZR\SISJZfZ[g[_i`xxlnkuztCOCCQDVcYm}ry~ejdcjbYeYeqep|pttr~rq}quur~rlxlXbY>C=CHBIPIQXQ@E?FKE?D>{}zBGAc^j}i=G?FQIHSKhmiGIH1B8ARH:J@Yd\kmjԱOVOIPIBDCjvj{zww~bnb[g[[g[[g[[g[ZfZQ[RWaXBGAkplAHAQ[SR\TPZR7B:3=5INJ687*/++0*"'#6;7TTTXdX\h\LVM\h\\h\\h\GQHKULBLCBLC\h\\h\\h\YeYR\S\h\lsljjjgif}|COCCQDTaWfvkot̓̕>H@EPHGRJhmi094?OEASG~DNELSK>@=XdX[g[[g[WcW[g[[g[[g[[g[[g[VbVQ[R_i`kpl?F?NZPOYQNYQ8C;7A94>6(2*#($ %!!&"#($$)%%*&&+'',((/(/4.2735:6;@:=BAF?CHBINJFKGLQMTVSSXRV[TZ_X[`YY^XPUOIQD>F;7A6-4-"' $ !*/)160273284$ ~TTTUaU[g[FPG[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[R^RYeYV`WkplAMAAMAP]Sboegtjʈ;E=EPHISKhmiXbYCHDwwwwwwyyyvvvvvvggg=D=WcWAD=764MTLttjvjkwk[g[[g[[g[[g[XdXS_SQ[Reofkpl?F?NXPQ[SU\UFPH8C;5@83>63>65A77C99D<;F>=H@BLDIUKV`WXbYXdZ^h]lvmyz}||sp^h]LWIEOFHOGHMFQVPKPJBGC4;4:A:070`jakulvwvwblcVVV}x@v3ZaY{|yz}~vw}~vws}t[g[[g[[g[[g[ZfZV`WV`WkplFTEIWJP]SZg]]j`Ɨ}}}~~~~~~}}}~~~řǮƲ¿Ü1;3@KCEPHhmiZfZR\SKPJQSPGIF:A:MWNCMDCMDCMDCMDCMDCMDCMDCMDCMDCMDISJXdX[g[BIB:<9LVM\f]YcZXbYU_VU_VU_VS]TOYPOYPOYPgqhkplAHAPZQPZQT[TS]UR\T8C;3?55A77C9:F<@JBDOGLVNWaXQ[R]g^^h_^h_jokv{wrwsv{wpuquzvotpnsorwstyuuzvqvrtvs3:3CJC ' Y[ZX_M^cOEOFYeYVbVWcWXdXVbVXdXWcW[g[[g[[g[[g[[g[XbYR\SkplCOAAMAIWJS`VVcYBRHdjfBRHekg?OE|~;KAz|4D:glhZfZ[g[ak`\f]]g^]g^]g^]g^]g^]g^]g^]g^]g^]g^]g^]g^]g^`ja[g[[g[eofkpl;E=LXLLXNLXNMYOPZQR\SPZRO[QLVMKWMLXN^h_gqiakbxyq{ro{o~}{}z{}z{}z|~{{}z|~{}||~{{}z}|}|}|!(!)!ˤTYU'.'V[WVmGeMWNdnenxowx`l`[g[[g[[g[[g[[g[[g[[g[YcZV`Wkplkpjsvxz}mmm*4,2>46A9fkgZfZZfZU_VU_VU_VU_VU_VU_VV`WV`WWcW[g[VbVU_VU_VU_VU_VU_VU_VV`WV`WZfZesdqr[g[gqhkpl:DAKBxxxLLLMWNŸR\SYeY@G?Q[Rcocjoilqmlqmlqmlqmlqm]d\ovoV\Xxz - - - SURUaU[g[FPG[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[YcZR\Skpl  ŵͽ¼ĹձZfZYeY]i]S_S^j^[g[S_S_k_[g[T`T_k_YeYR^R_k_\h\T`TiphcebU_VrtqMWNAKB?F>DNE?F>EOFinhWaVotnEOFAKBAH@tysS]T[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[U_VS]TBGAkplDKDszriphlskhogkrj^e]Ƿĺ$)%UWTGQHPZQWcWDNEyyyKKKGGGSR3LK,?A>[g[S]TQ[R^h_MWNOYPXbYWaXR\SOYPWaXovo,1-:A:ʷ   -RTQXdX\h\LVM\h\\h\\h\AKBAKBAH@BLC\h\\h\\h\\h\\h\Zd[WaXkpl - -ɹͽξ˽ʤjokinjotptysinjjokinjinjqvrrwsinjjokinjinjotplqm߬cebcocxxxx|{|{|{{zdpdbnb^h_kulisj_i`kulgqheofmwnfpggqhlvm_i`amalvmmwnmwnmwnmwnmwnmwnmwnmwnlvmZfZS]TBGAkpl[`\~}}|~}y~xv{u-/,UWTGQHPZQ[i\FMEsssSSS6=69<3ZX[CAF/2)7>7ZfZV`WQ[R^h_[e\]i]oynkujdpd]i]dneovoTVSUaU[g[FPG[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[YcZV`WkplɹuwvsuregdSURSURikhegdSURSURnpmegdSUR! bgcƪ||||||}~u|t|}{{otnˤejdPZQBGAkpl;B;JTKJTKJTKJTKJTKJTKJTKJTKJTKJTKJTKKULR\QR^RR^RXbY*/+XZWGQHPZQ\h\JTK///!ELEwwwkkkfffuusqqoGLE\h\VbVQ[R_k_Q[RR\SU_VS]TR\SR\SXbYovo SURejdaf`PZQgsgmymjvjcociuiamalxliui\h\[g[[g[[g[YcZS]TSZSkpl}mrnjokå}|UZTFMF?D>}|UZTFMF?D>}|UZTFMF.911=30<2fkgiiigggx}yt{tvvtnzxXs>q|tbhx^|`ewaproyx^j\tt]b\MWNBGAkplPROdieY^Xdieejf`e_]b\diedieZ_YdiebgcTYUKULPZQ[g[]g^6=6`eaGQHPZQ[g[[i\vvv6;7bdaOOO<<<;;;999<<<;;;EEEFME[i\UaWQ[R\f]VbVZfZcoco{oZfZZfZ`jaovoWYVR\SS]TISJ\h\XdX]i]\h\\h\YeY]i][g[[g[[g[[g[[g[YcZU_VDKDkpl -  l~rtyytzdvj|~tyumrnІ^c]FMF@E?uzvW\VFMF@E?puoW\VFMFӏ%/'+7-+7-ejfXbY]_\_a^bdabda^`]]_\HOGMWNNUMGLFDICKRKNSMGLFFMF:>=;B;HOH9>8>E>JTKELEDKDDKDDKDDKDDKDDKDDKDDKDCJCAKBOYPBGAkplAFBRYRT[TRYRRYRRYRRYRQXQQXQRYRQXQKRKXdXXdXS_S_i`5<5]b^GQHPZQWcW\h\yyyooo&+%\^]WWYyyy@B?ZfZOYNQ[Rcocamacmbcmbcmbcmbcmbbnbovo(2*5B8uvvw|}s}twx4@64@6afbT^UYcZISJ_k_[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[YcZWaVDKDkpl$.&.:0Yi^_od[k`MZPBOEcieٗƘFMFotnFMFotnFMF%/'+7-+7-ejfQ[RT`Tpwp|{S_ST`T]g^[e\T`TS_SGNGJOKKPLKPLKPLKPLKPLLQKR^ROYPU_VBGAkpltvuvwgng,8.,8.+7-+7-(4*qqqXdX[g[U_V`ja5<5]b^GQHPZQEOFVbV?F?///AMAY[X<<<\\\\\\WWWQQQIII;;;CHDQ]QLSLQ[Rcocovo$+$)5+)5+)5+]b^dic]b^MWNbnbfrfr~rnzndpdeqejvj\h\[g[[g[[g[[g[YcZT^UDKDkpl *"(4*.:07C97C97C9/;1glhƀ}~hmgFMFaf`glfpuqFMFZ_YglflqkFMF͎%/'+7-+7-ejfU_V_i`Ǽqxq[g[ɠ[g[U\Tlll`g_U_VS]TBGAkplDKDX_WU\TtysrwqMTMHMIHMIHMIDIEqqqXdX[g[U_Tcmd5<5]b^GQHPZQGMIBLD*/)HRI=D<.3/273273273273273.3/292]b^Q[Rcoc{zovo$+$)5+)5+)5+]b^T`TYeYFPG[g[[g[XdX[g[[g[[g[[g[[g[[g[[g[[g[[g[YcZU_VDKDkpl *"(4*,8.+7-+7-+7-+7-chdjokuztz|y`g`KRK]b\z|y`g`KRK]b\z|y`g`%/'+7-+7-ejfU_V]g^[b[[g[lvk[g[U_VY`XU_VWcWWaXkplIPH\f]XbYpuq^e^cmdjtkMOLHJGuuuXdX[g[U_Tdne5<5]b^GQHR\SKRKKRKKRKmtmv{uKRKKRKKRKKRKKRKKRKKRKKRKKRKKRKLSLS]TbnbNXOLVMLVMLVMLVMLVMU_Tovo$+$)5+Ͼ)5+)5+]b^_f^_f_NXOhthcociuifrfZfZ[g[[g[[g[[g[[g[[g[[g[YcZWaVDKDkpl *"(4*,8.+7-+7-+7-+7-uzvchdjokqspX]WglfBGATYUy~zqspX]WglfBGATYUy~zqspX]Wglf%/'+7-+7-ejfT^UU_VPWPRWSRWSRWSRWSRWSRWSKPJU_VU_VR\SQVPRWSRWSRWSRWSRWSNSMPZQU_VU_VNUNRWSRWSRWSRWSRWSQVRLQKV`WV`WZfZLSLkplR\Smym`l`^e^kplx}ykrk[]ZXZYWYXSUTXdX[g[U_Tdne5<5]b^HRIUaUU_VXbYYcZS]TR\SYcZU_VXbYYcZU_VXbYYcZU_VXbYYcZU_VQ[R\f]T^S^j^eqejvjfrfWcW\f]ovo$+$)5+)5+)5+]b^Y`YV]VISJ[g[ZfZ\h\ZfZYeY[g[[g[[g[[g[[g[[g[[g[YcZT^UDKDkpl *"(4*,8.+7-+7-+7-+7-v{wwyv|~}y~zinhglhqsp|~}y~zinhglhqsp|~}y~zinh$0&+7-+7-bgcZfZ[g[WcWV`WWcWWaXV`WWcWWaXV`WWcWWaXV`WWcWWaXV`WWcWWaXV`WWcWWaXV`WWcWWaXV`WWcWWaXV`WWcWWaXWaV[g[[g[[g[[g[hmiNZNcqbdrcZ_[cjcinh^h_hriRTQGIHCEDXdX[g[U_Tdne5<5]b^S_SWaXZd[Zd[Zd[Zd[Zd[Zd[Zd[Zd[Zd[Zd[Zd[Zd[Zd[Zd[Zd[Zd[]g^\h\_i`gqhhrigqhhriakbeofovo$+$)5+{{zz||w~w)5+)5+]b^UaU[g[LVM\h\_k_[g[[g[\h\VaST]L[g[[g[[g[[g[[g[YcZU_VDKDkpl *"(4*+7-+7-+7-+7-+7-puq%/'+7-+7-Y^ZYeYT^ULVMFMEFPGFPGFMEFPGFPGFMEFPGLVMxxFPGFPGFMEFPGFPGFMEFPGFPGFMEFPGFPGLVMV`WWcW[g[[g[`ea>C=PWPPWPOVOnpm{}|RWS6=66=63=55<5181XdX[g[U_Tdne5<5]b^NXOCMDFPGFPGFPGFPGFPGFPGFPGFPGFPGFPGFPGFPGFPGFPGFPGFPGGQH]i]_k_gsg^j^[g[kwkr~r_k_ovo$+$)5+)5+)5+]b^ejd`eaOYP`l`jvjfrfjvjjvjcjXbjS[g[[g[[g[[g[[g[Zd[WaVDKDkpl *"(4*+7-+7-+7-+7-+7-fhgggggggggggggggggggggggggdddcccfffccceeebbbeeebbbiiilllmmmnnnjjjrrrllloookkkmmmnnnjjjlllhhheeeggg;=:&2(+7-+7-injS_SNXOOYPPWOPWOPWOPWOPWOPWOPWOPWOU\Ux}wv{uv{uv{uv{uv{u`g`PWOPWOPWOPWOPWOPWOPWOPWOPWOPWOPWOT^UQ[RS]TUaUUaUmrn?F?]cW\c\IPIEOGFPHY`Y]d]]d]]d]]d]W^WXdX[g[U_Tdne5<5]b^GQHR\SblcMWNOYPPZQ\f]YcZOYPOYPT^Ufrfo{oiuidpd~~wwovo$+$)5+ȟ)5+)5+]b^R\ST^UFPG[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[[g[WcW`jaT^UDKDkpl *"(4*+7-+7-+7-+7-+7-+7-$.&",$",$",$",$",$",$",$",$",$",$",$",$",$",$",$",$$.&%/'%/'%/'&0('1)'1)'1)&0(&0(%/'%/'%/'#-%",$",$%/&*6,+7-+7-W\XSURTVSTVSTVSSURTVSSURTVSSURSURTVSSURSURSURSURSURSURSURSURSURSURTVSSURSURSURSURZ\[WYV[[[jjjkkkVVVSSSSSSTTT[[[elehogfmfXdX[g[U_Tdne5<5]b^GQHPZQlskT^U]i]]i]dpdcoc]i]]g^YcZeqecoczzbnbama~~uuovo$+$)5+ž)5+)5+]b^V`WZd[LVMeqeamafrfeqeeqegsgcoccoc[g[[g[[g[YcZ_k_WaVYcZkpl *"(4*+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-+7-'3)%/'%/'%/'%/'%/'%/'$.&%/'$.&%/'$.&%/'$.&$.&$.&$.&%/'$.&$.&%/'$.&%/'$.&$.&$.&$.&LQK>E=LLLYYYfff***130888lslXdX[g[U_Tdne5<5]b^GQHPZQlskQ[RR\SS]TZd[XbYR\SS]TR\Scoc^j^dpd]i][g[dpdjvj]i]ovo$+$)5+)5+)5+]b^af`[`\LVMZfZ`l`ZfZ^j^]i]]i][g[YeY[g[ZfZWaXcmd[g[num~jli *"(4*+7-+7-2>4t~uwyvvxuwyvwyvwyvwyvwyvwyvwyvwyvuzvwyvuzvwyvuzvwyvwyvwyvwyvwyvwyvwyvuzvwyvwyvwyvwyvwyvwyvwyvwyvuzvuzvuzvwyvuzvwyvwyvwyv{}z:FE=:A:Y^ZU\UZfZ\f]\f]\f]\f]\f]\f]\f]\f]\f]\f]\f]\f]\f]\f]\f]\f]\f]\f]\f]\f]]g^`l`[g[[g[\f]4;4chdPZQV`WWaXWaXWaXWaXWaXWaXWaXWaXWaXWaXWaXWaXWaXWaXWaXWaX[e\VbVUaUWcWUaUUaUXdXWcWVbVotn&-&)5+)5+)5+7A9tvueeeddddddfffhhhddddddeeeeeedddddddddeeeeeeppp<>;#/%(4*+7-CMEnpmdiediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediediedieejfSYULQMJOKJOKJOKJOKJOKJOKJOKJOKJOKJOKJOKJOKJOKJOKJOKJOKJOKJOKJOKJOKJOKJOKJOKJOKJOKRTQ'.'JQJTVSSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURTVU)!)5+~}`ba4DJFl|qFZN' QSR0<2)5+)5+)5+(4*(4*(4*(4*(4*(4*(4*(4*(4*(4*(4*(4*(4*(4*(4*(4*(4*(4*(4*(4*+7-1=34@66B84@64@66B84@64@66B84@64@66B84@64@6:F<9E;9E;:E=:F<:F<9E;9E;9E;9E;9E;9E;:F<4@66B84@64@66B84@64@66B84@64@66B84@64@67C99D<9E;:F<9E;9E;9E;9E;9E;9E;9E;9E;9E;5A76B83?53?55A73?54@65A74@64@65A74@63?55A79E;9E;9E;9E;9E;9E;8D:8D:8D:8D:8D:8D:7C95A73?53?55A73?53?55A73?53?55A73?53?55A77C98D:8D:8D:8D:8D:8D:8D:8D:8D:8D:8D:8D:4@62>43?55A73?53?55A72>43?54@62>42>44@65A78D:8D:8D:8D:8D:8D:7C9AMC)6/tz42>44@62>42>44@62>42>44@62>47C97C97C97C97C97C97C97C95A72>4/;1-9/*6,1=3BNDxx~~~~}v{wv{wv{wv{wv{wv{wv{wv{wxzwv{wv{wv{w|}v{wxzwv{wv{wv{wxzwv{wv{wv{wv{wv{wxzwv{wxzwv{wv{wy{x+4/ERKFSL?JD>GBv{wv{wv{wv{wv{wv{wv{wv{wv{wv{wv{wv{wv{wv{wv{wv{wv{w=I?Ѿy}~kyyǹǽǵõǼǵϼȻļѵYf_o{wR^RMWNPZQOYPLVMPZQJTKPZQT`TOYPOYPR\SӉQ[R[e\\f]t~ugqhyzXbYjtk_i`uvkulXbYvwdkdĭޟT^UdkdЪPZQ`g_ļU\U[e\׏lnm$*"'4+vxuؼKULUaUUaUUaUUaUakbajU~gT`Tikqxq_|y|qbNW]kx@HoxatwpʷрiȡԸɧټzaqnS_SAKBKULEOFOYPKULKULR\QQ[RKULHRINXOωXbYoyp{|dneYcZYcZYeYYeYYeYYeYXdZ[e\IJܜkulYcZʦ`ja`jaWaXdne۵ԷS]TZfZZfZZfZZfZbnb[fUvydfke~x_eaYgtv}vsb[RYsFJuz~Wwrlx}y{}z{}z{}z{}z{}z{}z{}z{}z{}z{}z{}z~~~}|~{~}~~{}zz|yxzwxzwxzwxzwy{xпäprouwtnpm{}z{}z{}z{}z{}z{}z{}z{}z{}z{}z{}z{}z{}z{}z{}z{}z{}z \ No newline at end of file diff --git a/public/gfx/textures/4584293182.jpg b/public/gfx/textures/4584293182.jpg deleted file mode 100644 index e906f08f..00000000 Binary files a/public/gfx/textures/4584293182.jpg and /dev/null differ diff --git a/public/gfx/textures/743_tid_image06.jpg b/public/gfx/textures/743_tid_image06.jpg deleted file mode 100644 index ec78da3d..00000000 Binary files a/public/gfx/textures/743_tid_image06.jpg and /dev/null differ diff --git a/public/gfx/textures/TorqueX_Particle_Effect_Guide_snow.png b/public/gfx/textures/TorqueX_Particle_Effect_Guide_snow.png deleted file mode 100644 index 6d6873fe..00000000 Binary files a/public/gfx/textures/TorqueX_Particle_Effect_Guide_snow.png and /dev/null differ diff --git a/public/gfx/textures/fire.png b/public/gfx/textures/fire.png deleted file mode 100644 index f45b4b0a..00000000 Binary files a/public/gfx/textures/fire.png and /dev/null differ diff --git a/public/gfx/textures/ice_texture_by_digitalwideresource-d4ldqap.jpg b/public/gfx/textures/ice_texture_by_digitalwideresource-d4ldqap.jpg deleted file mode 100644 index 19985ea5..00000000 Binary files a/public/gfx/textures/ice_texture_by_digitalwideresource-d4ldqap.jpg and /dev/null differ diff --git a/public/gfx/textures/monster.dae b/public/gfx/textures/monster.dae deleted file mode 100644 index a7b0eff0..00000000 --- a/public/gfx/textures/monster.dae +++ /dev/null @@ -1,1924 +0,0 @@ - - - - - Tim - 3dsMax 8 - Feeling ColladaMax v3.04E. - ColladaMax Export Options: ExportNormals=1;ExportEPolyAsTriangles=1;ExportXRefs=1;ExportSelected=0;ExportTangents=0;ExportAnimations=1;SampleAnim=1;ExportAnimClip=1;BakeMatrices=1;ExportRelativePaths=1;AnimStart=0;AnimEnd=3.33333; - - 2007-12-05T22:27:58Z - 2007-12-05T22:28:00Z - - Z_UP - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 524.412 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.634893 -0.746072 0.200716 142.077 0.754783 0.654426 0.045049 -0.208117 -0.164963 0.122896 0.978613 -0.038858 0 0 0 1 0.656578 -0.735841 0.165663 142.074 0.742122 0.66948 0.032417 -0.212967 -0.134763 0.101657 0.985649 -0.032083 0 0 0 1 0.678956 -0.722669 0.129492 142.07 0.72686 0.686492 0.020085 -0.218372 -0.10341 0.080485 0.991377 -0.025354 0 0 0 1 0.700457 -0.707696 0.092341 142.065 0.710159 0.703991 0.008407 -0.22395 -0.070957 0.059687 0.995692 -0.018779 0 0 0 1 0.719307 -0.692503 0.055107 142.06 0.693643 0.720316 -0.002208 -0.229009 -0.038165 0.039812 0.998479 -0.012442 0 0 0 1 0.733723 -0.679171 0.019447 142.056 0.679418 0.733663 -0.011399 -0.233311 -0.006525 0.021576 0.999746 -0.006653 0 0 0 1 0.742772 -0.669391 -0.014317 142.053 0.669129 0.742894 -0.019363 -0.236128 0.023597 0.004802 0.99971 -0.001338 0 0 0 1 0.745243 -0.665264 -0.045129 142.051 0.664827 0.746535 -0.026246 -0.237349 0.051151 -0.010442 0.998636 0.003494 0 0 0 1 0.739872 -0.668541 -0.075111 142.052 0.668221 0.743229 -0.033032 -0.236398 0.077908 -0.025751 0.996628 0.008385 0 0 0 1 0.727293 -0.677968 -0.10679 142.055 0.678092 0.733846 -0.040754 -0.23335 0.105998 -0.042772 0.993446 0.013779 0 0 0 1 0.709351 -0.691197 -0.138087 142.06 0.692104 0.720117 -0.049232 -0.228875 0.133467 -0.060647 0.989195 0.019444 0 0 0 1 0.688661 -0.705719 -0.166454 142.064 0.70765 0.70419 -0.057854 -0.223847 0.158044 -0.077948 0.984351 0.02496 0 0 0 1 0.667464 -0.71984 -0.190585 142.069 0.722898 0.68779 -0.066058 -0.218803 0.178634 -0.093681 0.979446 0.029921 0 0 0 1 0.648694 -0.731889 -0.208649 142.072 0.735967 0.673083 -0.07287 -0.214113 0.193771 -0.106288 0.975273 0.033917 0 0 0 1 0.635736 -0.740263 -0.218748 142.075 0.745006 0.662589 -0.077088 -0.210734 0.202005 -0.113962 0.972732 0.036378 0 0 0 1 0.631353 -0.743775 -0.219526 142.076 0.748633 0.658414 -0.077714 -0.209357 0.202341 -0.115279 0.972506 0.036811 0 0 0 1 0.639455 -0.740611 -0.206382 142.075 0.74476 0.663342 -0.072869 -0.21107 0.19087 -0.107108 0.975754 0.034226 0 0 0 1 0.658127 -0.7313 -0.17908 142.072 0.734108 0.676098 -0.063069 -0.214937 0.167198 -0.089957 0.981811 0.028779 0 0 0 1 0.682279 -0.717324 -0.141212 142.068 0.718677 0.693508 -0.050505 -0.220506 0.13416 -0.067028 0.98869 0.021456 0 0 0 1 0.706958 -0.700596 -0.096834 142.063 0.700836 0.712349 -0.037254 -0.226509 0.09508 -0.041527 0.994603 0.013375 0 0 0 1 0.727548 -0.684132 -0.051355 142.057 0.683876 0.729164 -0.025159 -0.231855 0.054658 -0.016815 0.998364 0.005511 0 0 0 1 0.741377 -0.671034 -0.008532 142.053 0.670889 0.741408 -0.014916 -0.235773 0.016334 0.005335 0.999852 -0.001495 0 0 0 1 0.745878 -0.665581 0.025876 142.051 0.665926 0.745984 -0.007204 -0.237276 -0.014507 0.022606 0.999639 -0.007 0 0 0 1 0.741021 -0.669153 0.055878 142.053 0.670216 0.742166 -0.000369 -0.235941 -0.041224 0.037724 0.998438 -0.011771 0 0 0 1 0.728982 -0.678904 0.08761 142.056 0.681026 0.732222 0.007446 -0.232832 -0.069205 0.054237 0.996127 -0.017047 0 0 0 1 0.711567 -0.692471 0.11898 142.06 0.695955 0.717906 0.016051 -0.228272 -0.096531 0.071384 0.992767 -0.022474 0 0 0 1 0.69135 -0.707318 0.147433 142.065 0.712322 0.701414 0.024821 -0.223069 -0.120968 0.08786 0.988761 -0.027716 0 0 0 1 0.670426 -0.721817 0.171783 142.069 0.728349 0.6844 0.033225 -0.217625 -0.141551 0.102843 0.984574 -0.032467 0 0 0 1 0.65207 -0.734019 0.189789 142.073 0.741832 0.669385 0.040118 -0.212923 -0.15649 0.114631 0.981005 -0.036199 0 0 0 1 0.63927 -0.742536 0.199935 142.076 0.751145 0.658641 0.044415 -0.20942 -0.164666 0.121787 0.978802 -0.038464 0 0 0 1 0.634893 -0.746072 0.200716 142.077 0.754783 0.654426 0.045049 -0.208117 -0.164963 0.122896 0.978613 -0.038818 0 0 0 1 0.642774 -0.742753 0.187513 142.076 0.750525 0.659624 0.040102 -0.209793 -0.153475 0.114957 0.981443 -0.036314 0 0 0 1 0.660989 -0.733117 0.160104 142.073 0.739081 0.672943 0.030114 -0.214031 -0.129818 0.098425 0.986641 -0.031063 0 0 0 1 0.684506 -0.718707 0.122114 142.068 0.722545 0.691107 0.017339 -0.219705 -0.096855 0.076365 0.992365 -0.024055 0 0 0 1 0.708432 -0.701496 0.077634 142.063 0.703398 0.710786 0.003912 -0.226003 -0.057926 0.051836 0.996974 -0.016251 0 0 0 1 0.728245 -0.684565 0.032095 142.057 0.685088 0.728413 -0.008287 -0.231614 -0.017705 0.028024 0.99945 -0.0087 0 0 0 1 0.741286 -0.671107 -0.010503 142.053 0.670885 0.74133 -0.018506 -0.235761 0.020206 0.00667 0.999774 -0.001929 0 0 0 1 0.745243 -0.665263 -0.045141 142.051 0.664827 0.746536 -0.026249 -0.237381 0.051162 -0.010448 0.998636 0.003496 0 0 0 1 0.739872 -0.668541 -0.075111 142.052 0.668221 0.743229 -0.033032 -0.236423 0.077908 -0.025751 0.996628 0.008385 0 0 0 1 0.727198 -0.678039 -0.106987 142.055 0.678167 0.733774 -0.040805 -0.23327 0.106172 -0.042882 0.993423 0.013814 0 0 0 1 0.709351 -0.691197 -0.138087 142.06 0.692103 0.720118 -0.049232 -0.228943 0.133467 -0.060647 0.989195 0.019444 0 0 0 1 0.688661 -0.705719 -0.166454 142.064 0.70765 0.70419 -0.057854 -0.223988 0.158044 -0.077948 0.984351 0.024921 0 0 0 1 0.667339 -0.719921 -0.190717 142.069 0.722986 0.687693 -0.066105 -0.218667 0.178746 -0.09377 0.979417 0.029988 0 0 0 1 0.648695 -0.731889 -0.208648 142.073 0.735967 0.673083 -0.07287 -0.214089 0.193771 -0.106288 0.975272 0.033957 0 0 0 1 0.635736 -0.740263 -0.218748 142.075 0.745006 0.662589 -0.077088 -0.210759 0.202005 -0.113962 0.972732 0.036378 0 0 0 1 0.631353 -0.743775 -0.219526 142.076 0.748633 0.658414 -0.077714 -0.209386 0.202341 -0.115279 0.972507 0.036771 0 0 0 1 0.639455 -0.740611 -0.206382 142.075 0.74476 0.663342 -0.072869 -0.21107 0.19087 -0.107108 0.975754 0.034187 0 0 0 1 0.658127 -0.7313 -0.17908 142.072 0.734108 0.676098 -0.063069 -0.214999 0.167198 -0.089957 0.981811 0.028779 0 0 0 1 0.682279 -0.717324 -0.141212 142.068 0.718677 0.693508 -0.050505 -0.220562 0.13416 -0.067028 0.98869 0.021496 0 0 0 1 0.706958 -0.700596 -0.096834 142.063 0.700836 0.712349 -0.037254 -0.226509 0.09508 -0.041527 0.994603 0.013375 0 0 0 1 0.727548 -0.684132 -0.051355 142.057 0.683876 0.729164 -0.025159 -0.231855 0.054658 -0.016815 0.998364 0.005511 0 0 0 1 0.741321 -0.671093 -0.008773 142.053 0.670946 0.741355 -0.01497 -0.235749 0.016551 0.005211 0.999849 -0.001456 0 0 0 1 0.745878 -0.665581 0.025877 142.051 0.665926 0.745984 -0.007204 -0.237245 -0.014508 0.022606 0.999639 -0.007 0 0 0 1 0.741021 -0.669153 0.055878 142.053 0.670216 0.742166 -0.000369 -0.235997 -0.041224 0.037724 0.998438 -0.011771 0 0 0 1 0.72889 -0.678977 0.087807 142.056 0.681107 0.732146 0.007496 -0.232876 -0.069377 0.054342 0.996109 -0.01708 0 0 0 1 0.711568 -0.692471 0.118979 142.06 0.695955 0.717906 0.016051 -0.22824 -0.096531 0.071383 0.992767 -0.022474 0 0 0 1 0.69135 -0.707318 0.147433 142.065 0.712322 0.701414 0.024821 -0.223125 -0.120968 0.08786 0.988761 -0.027716 0 0 0 1 0.670426 -0.721817 0.171783 142.069 0.728349 0.6844 0.033225 -0.217606 -0.141551 0.102843 0.984574 -0.032467 0 0 0 1 0.65207 -0.734019 0.189789 142.073 0.741832 0.669385 0.040118 -0.212899 -0.15649 0.114631 0.981005 -0.0362 0 0 0 1 0.63927 -0.742536 0.199935 142.076 0.751145 0.658641 0.044415 -0.209408 -0.164666 0.121787 0.978802 -0.038503 0 0 0 1 0.634893 -0.746072 0.200716 142.077 0.754783 0.654426 0.045049 -0.208117 -0.164963 0.122896 0.978613 -0.038818 0 0 0 1 0.642691 -0.742792 0.18764 142.076 0.750573 0.659566 0.040151 -0.209719 -0.153585 0.115033 0.981417 -0.036338 0 0 0 1 0.660989 -0.733117 0.160104 142.073 0.739081 0.672943 0.030114 -0.214031 -0.129818 0.098425 0.986641 -0.031063 0 0 0 1 0.684655 -0.718609 0.121856 142.068 0.722434 0.691224 0.017256 -0.219791 -0.09663 0.076219 0.992398 -0.024008 0 0 0 1 0.708431 -0.701496 0.077635 142.063 0.703398 0.710785 0.003912 -0.226059 -0.057927 0.051837 0.996974 -0.016251 0 0 0 1 0.728245 -0.684565 0.032095 142.057 0.685088 0.728413 -0.008287 -0.231614 -0.017705 0.028024 0.99945 -0.0087 0 0 0 1 0.741286 -0.671107 -0.010503 142.053 0.670885 0.74133 -0.018506 -0.235705 0.020206 0.00667 0.999774 -0.001929 0 0 0 1 0.745243 -0.665263 -0.045141 142.051 0.664827 0.746536 -0.026249 -0.237381 0.051162 -0.010448 0.998636 0.003496 0 0 0 1 0.739872 -0.668541 -0.075111 142.052 0.668221 0.743229 -0.033032 -0.236423 0.077908 -0.025751 0.996628 0.008385 0 0 0 1 0.727198 -0.678039 -0.106987 142.055 0.678167 0.733774 -0.040805 -0.23327 0.106172 -0.042882 0.993423 0.013814 0 0 0 1 0.709351 -0.691197 -0.138087 142.06 0.692103 0.720118 -0.049232 -0.228943 0.133467 -0.060647 0.989195 0.019444 0 0 0 1 0.688661 -0.705719 -0.166454 142.064 0.70765 0.70419 -0.057854 -0.223988 0.158044 -0.077948 0.984351 0.024921 0 0 0 1 0.667464 -0.71984 -0.190585 142.069 0.722898 0.68779 -0.066058 -0.218747 0.178634 -0.093681 0.979446 0.02996 0 0 0 1 0.648694 -0.731889 -0.208649 142.073 0.735967 0.673083 -0.07287 -0.214089 0.193771 -0.106288 0.975272 0.033957 0 0 0 1 0.635736 -0.740263 -0.218748 142.075 0.745006 0.662589 -0.077088 -0.210759 0.202005 -0.113962 0.972732 0.036378 0 0 0 1 0.631353 -0.743775 -0.219526 142.076 0.748633 0.658414 -0.077714 -0.209386 0.202341 -0.115279 0.972507 0.036771 0 0 0 1 0.63937 -0.740649 -0.206508 142.075 0.744804 0.663287 -0.072917 -0.210878 0.19098 -0.107187 0.975724 0.034252 0 0 0 1 0.658127 -0.7313 -0.17908 142.072 0.734108 0.676098 -0.063069 -0.214999 0.167198 -0.089957 0.981811 0.028779 0 0 0 1 0.682432 -0.717229 -0.140955 142.068 0.718573 0.693621 -0.050423 -0.220581 0.133935 -0.066876 0.988731 0.021408 0 0 0 1 0.706957 -0.700596 -0.096835 142.063 0.700836 0.712349 -0.037254 -0.226497 0.095081 -0.041528 0.994603 0.013375 0 0 0 1 0.727548 -0.684132 -0.051355 142.057 0.683876 0.729164 -0.025159 -0.231855 0.054658 -0.016815 0.998364 0.005511 0 0 0 1 0.741321 -0.671093 -0.008773 142.053 0.670946 0.741355 -0.01497 -0.235749 0.016551 0.005211 0.999849 -0.001456 0 0 0 1 0.74588 -0.665586 0.025674 142.051 0.665927 0.745982 -0.007249 -0.237245 -0.014327 0.022505 0.999644 -0.006968 0 0 0 1 0.741021 -0.669153 0.055878 142.053 0.670216 0.742166 -0.000369 -0.235997 -0.041224 0.037724 0.998438 -0.011771 0 0 0 1 0.72889 -0.678977 0.087807 142.056 0.681107 0.732146 0.007496 -0.232876 -0.069377 0.054342 0.996109 -0.01708 0 0 0 1 0.711568 -0.692471 0.118979 142.06 0.695955 0.717906 0.016051 -0.22824 -0.096531 0.071383 0.992767 -0.022474 0 0 0 1 0.69135 -0.707318 0.147433 142.065 0.712322 0.701414 0.024821 -0.223125 -0.120968 0.08786 0.988761 -0.027716 0 0 0 1 0.670549 -0.721734 0.171651 142.069 0.728257 0.6845 0.033177 -0.21763 -0.14144 0.102759 0.984599 -0.03244 0 0 0 1 0.65207 -0.734019 0.189789 142.073 0.741832 0.669384 0.040118 -0.212899 -0.156491 0.114631 0.981004 -0.036199 0 0 0 1 0.63927 -0.742536 0.199935 142.076 0.751145 0.658641 0.044415 -0.209408 -0.164666 0.121787 0.978802 -0.038464 0 0 0 1 0.634893 -0.746072 0.200716 142.077 0.754783 0.654426 0.045049 -0.208117 -0.164963 0.122896 0.978613 -0.038818 0 0 0 1 0.642691 -0.742792 0.18764 142.076 0.750573 0.659566 0.040151 -0.209831 -0.153585 0.115033 0.981417 -0.036338 0 0 0 1 0.660989 -0.733117 0.160104 142.073 0.739081 0.672943 0.030114 -0.214055 -0.129818 0.098425 0.986641 -0.031063 0 0 0 1 0.684655 -0.718609 0.121856 142.068 0.722434 0.691224 0.017256 -0.219791 -0.09663 0.076219 0.992398 -0.024008 0 0 0 1 0.708431 -0.701496 0.077635 142.063 0.703398 0.710785 0.003912 -0.226059 -0.057927 0.051837 0.996974 -0.016251 0 0 0 1 0.728245 -0.684565 0.032095 142.057 0.685088 0.728413 -0.008287 -0.231614 -0.017705 0.028024 0.99945 -0.0087 0 0 0 1 0.741286 -0.671107 -0.010503 142.053 0.670885 0.74133 -0.018506 -0.235705 0.020206 0.00667 0.999774 -0.001929 0 0 0 1 0.74525 -0.665269 -0.044939 142.051 0.664833 0.746532 -0.026204 -0.237381 0.050982 -0.010347 0.998646 0.003464 0 0 0 1 0.739872 -0.668541 -0.075111 142.052 0.668221 0.743229 -0.033032 -0.236423 0.077908 -0.025751 0.996628 0.008385 0 0 0 1 0.727198 -0.678039 -0.106987 142.055 0.678167 0.733774 -0.040805 -0.23327 0.106172 -0.042882 0.993423 0.013814 0 0 0 1 0.709351 -0.691197 -0.138087 142.06 0.692103 0.720118 -0.049232 -0.228943 0.133467 -0.060647 0.989195 0.019444 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.955391 -0.206897 0.210765 399.228 0.228589 0.969883 -0.084102 -0.310882 -0.187017 0.128529 0.973912 -0.041171 0 0 0 1 0.965973 -0.190211 0.175255 399.223 0.205482 0.975905 -0.073387 -0.312763 -0.157073 0.106902 0.981784 -0.034244 0 0 0 1 0.975593 -0.169997 0.138993 399.216 0.17987 0.981749 -0.061766 -0.31485 -0.125956 0.085259 0.988365 -0.027321 0 0 0 1 0.983676 -0.148038 0.102302 399.21 0.153624 0.986912 -0.049034 -0.316422 -0.093704 0.06395 0.993544 -0.020505 0 0 0 1 0.989749 -0.12658 0.06614 399.202 0.129106 0.990999 -0.035398 -0.317631 -0.061064 0.043574 0.997182 -0.013939 0 0 0 1 0.993596 -0.10835 0.032056 399.197 0.109068 0.993801 -0.021553 -0.318778 -0.029522 0.024911 0.999254 -0.00799 0 0 0 1 0.99544 -0.09539 0.000194 399.192 0.095388 0.995409 -0.007851 -0.319175 0.000555 0.007834 0.999969 -0.002518 0 0 0 1 0.995505 -0.090261 -0.028676 399.191 0.090438 0.99589 0.004962 -0.319232 0.02811 -0.007534 0.999577 0.002389 0 0 0 1 0.993832 -0.095217 -0.056844 399.193 0.09634 0.995197 0.017363 -0.318988 0.054918 -0.022732 0.998232 0.007281 0 0 0 1 0.990256 -0.10877 -0.08696 399.197 0.111738 0.993284 0.03002 -0.31841 0.083111 -0.039444 0.995759 0.012645 0 0 0 1 0.984822 -0.127982 -0.117244 399.203 0.133656 0.990144 0.041846 -0.317515 0.110734 -0.056881 0.992221 0.01823 0 0 0 1 0.978027 -0.149529 -0.145274 399.21 0.158445 0.986008 0.05181 -0.316117 0.135494 -0.073689 0.988034 0.023578 0 0 0 1 0.970555 -0.170998 -0.169654 399.217 0.183298 0.98125 0.059589 -0.314707 0.156283 -0.088932 0.9837 0.028471 0 0 0 1 0.963609 -0.189722 -0.188315 399.223 0.204962 0.976618 0.064873 -0.313193 0.171604 -0.101111 0.979964 0.032378 0 0 0 1 0.958772 -0.202873 -0.198997 399.227 0.219931 0.973177 0.067501 -0.312097 0.179965 -0.108483 0.977673 0.034717 0 0 0 1 0.957418 -0.20821 -0.199999 399.229 0.225455 0.971915 0.06746 -0.311519 0.180336 -0.109679 0.977471 0.035121 0 0 0 1 0.961353 -0.202545 -0.186482 399.227 0.217529 0.973985 0.063524 -0.312288 0.168764 -0.101634 0.980402 0.032528 0 0 0 1 0.969461 -0.187076 -0.158579 399.222 0.197873 0.978675 0.05514 -0.313723 0.144882 -0.084835 0.985805 0.027163 0 0 0 1 0.978909 -0.164955 -0.120524 399.215 0.171123 0.984325 0.042684 -0.31564 0.111594 -0.062409 0.991792 0.019998 0 0 0 1 0.987205 -0.139712 -0.076853 399.207 0.142128 0.989483 0.026904 -0.317216 0.072286 -0.037483 0.996679 0.012001 0 0 0 1 0.992711 -0.115905 -0.033035 399.199 0.116276 0.993171 0.009543 -0.318509 0.031704 -0.013315 0.999409 0.00425 0 0 0 1 0.995199 -0.097582 0.007491 399.193 0.097638 0.995192 -0.007723 -0.319094 -0.006701 0.008417 0.999943 -0.002714 0 0 0 1 0.995142 -0.090075 0.039714 399.191 0.090996 0.995608 -0.022011 -0.319168 -0.037557 0.025519 0.998969 -0.008182 0 0 0 1 0.993175 -0.094866 0.067854 399.192 0.097358 0.994655 -0.03438 -0.318922 -0.06423 0.040751 0.997103 -0.013069 0 0 0 1 0.989289 -0.108235 0.09794 399.197 0.113233 0.992457 -0.04699 -0.318164 -0.092115 0.057577 0.994082 -0.018463 0 0 0 1 0.983553 -0.127254 0.128181 399.203 0.135618 0.989018 -0.05875 -0.317146 -0.119298 0.075168 0.99001 -0.024092 0 0 0 1 0.976487 -0.148615 0.156162 399.21 0.160825 0.984593 -0.06864 -0.315735 -0.143555 0.092141 0.985344 -0.029526 0 0 0 1 0.968742 -0.170039 0.180626 399.216 0.186176 0.979543 -0.076381 -0.314112 -0.163944 0.107623 0.980581 -0.034523 0 0 0 1 0.961677 -0.188504 0.199109 399.222 0.20795 0.974734 -0.081559 -0.312503 -0.178704 0.119838 0.976577 -0.038408 0 0 0 1 0.956748 -0.201573 0.209765 399.227 0.22306 0.971166 -0.084146 -0.311316 -0.186755 0.127297 0.974124 -0.040785 0 0 0 1 0.955391 -0.206897 0.210765 399.228 0.228589 0.969883 -0.084102 -0.310877 -0.187017 0.128529 0.973912 -0.04118 0 0 0 1 0.959453 -0.201321 0.197282 399.226 0.220467 0.97209 -0.080218 -0.311703 -0.175627 0.12046 0.977059 -0.038605 0 0 0 1 0.967822 -0.186037 0.169441 399.222 0.200407 0.977069 -0.07193 -0.313277 -0.152174 0.103572 0.982912 -0.033186 0 0 0 1 0.977635 -0.164164 0.131456 399.215 0.173094 0.983101 -0.059582 -0.315182 -0.119453 0.081003 0.98953 -0.025941 0 0 0 1 0.986361 -0.139196 0.087843 399.207 0.143433 0.988686 -0.043891 -0.316995 -0.08074 0.055893 0.995167 -0.017905 0 0 0 1 0.992311 -0.115658 0.044061 399.199 0.116894 0.992789 -0.026584 -0.318304 -0.040668 0.03153 0.998675 -0.010117 0 0 0 1 0.995213 -0.097655 0.00377 399.193 0.097687 0.995172 -0.009433 -0.31911 -0.002831 0.009756 0.999948 -0.00311 0 0 0 1 0.995505 -0.090261 -0.028687 399.191 0.090438 0.99589 0.004967 -0.319313 0.028121 -0.00754 0.999576 0.00239 0 0 0 1 0.993832 -0.095217 -0.056844 399.193 0.09634 0.995197 0.017363 -0.319129 0.054918 -0.022732 0.998232 0.007284 0 0 0 1 0.990228 -0.108872 -0.087149 399.197 0.111855 0.993268 0.030097 -0.318609 0.083286 -0.039551 0.99574 0.01267 0 0 0 1 0.984822 -0.127982 -0.117244 399.203 0.133656 0.990143 0.041845 -0.317517 0.110733 -0.05688 0.992221 0.018212 0 0 0 1 0.978027 -0.149529 -0.145274 399.21 0.158445 0.986008 0.05181 -0.316148 0.135494 -0.073689 0.988034 0.023584 0 0 0 1 0.970509 -0.171123 -0.169789 399.217 0.183443 0.98122 0.05963 -0.314618 0.156396 -0.089017 0.983674 0.028521 0 0 0 1 0.96361 -0.189722 -0.188315 399.223 0.204962 0.976618 0.064873 -0.313081 0.171604 -0.101111 0.979964 0.032382 0 0 0 1 0.958771 -0.202873 -0.198997 399.227 0.219931 0.973177 0.067501 -0.312043 0.179965 -0.108483 0.977673 0.03471 0 0 0 1 0.957418 -0.20821 -0.199999 399.229 0.225455 0.971915 0.06746 -0.311548 0.180336 -0.109679 0.977471 0.03511 0 0 0 1 0.961353 -0.202545 -0.186482 399.227 0.217529 0.973985 0.063524 -0.312228 0.168764 -0.101634 0.980402 0.03253 0 0 0 1 0.969461 -0.187076 -0.158579 399.222 0.197873 0.978675 0.05514 -0.313723 0.144882 -0.084835 0.985805 0.027163 0 0 0 1 0.978909 -0.164955 -0.120524 399.215 0.171123 0.984325 0.042684 -0.315657 0.111594 -0.062409 0.991792 0.019995 0 0 0 1 0.987205 -0.139712 -0.076853 399.207 0.142128 0.989483 0.026904 -0.317215 0.072286 -0.037483 0.996679 0.011997 0 0 0 1 0.992711 -0.115905 -0.033035 399.199 0.116276 0.993171 0.009543 -0.318509 0.031704 -0.013315 0.999409 0.00425 0 0 0 1 0.995193 -0.097664 0.007265 399.193 0.097718 0.995185 -0.007622 -0.318998 -0.006485 0.008296 0.999945 -0.002676 0 0 0 1 0.995142 -0.090075 0.039714 399.191 0.090996 0.995608 -0.022011 -0.31912 -0.037558 0.025519 0.998969 -0.008181 0 0 0 1 0.993175 -0.094866 0.067854 399.192 0.097358 0.994655 -0.03438 -0.3188 -0.06423 0.040751 0.997103 -0.013075 0 0 0 1 0.989259 -0.108336 0.098128 399.197 0.113353 0.99244 -0.047066 -0.318201 -0.092287 0.057684 0.99406 -0.018493 0 0 0 1 0.983553 -0.127254 0.12818 399.203 0.135618 0.989018 -0.05875 -0.317132 -0.119297 0.075167 0.99001 -0.024082 0 0 0 1 0.976487 -0.148614 0.156162 399.21 0.160825 0.984593 -0.06864 -0.315693 -0.143555 0.092141 0.985343 -0.029518 0 0 0 1 0.968742 -0.170039 0.180626 399.216 0.186176 0.979543 -0.076381 -0.314056 -0.163944 0.107623 0.980581 -0.034507 0 0 0 1 0.961677 -0.188504 0.199109 399.222 0.20795 0.974734 -0.081559 -0.312417 -0.178704 0.119838 0.976577 -0.038397 0 0 0 1 0.956748 -0.201573 0.209765 399.227 0.22306 0.971166 -0.084146 -0.311563 -0.186755 0.127297 0.974124 -0.040786 0 0 0 1 0.955391 -0.206897 0.210765 399.228 0.228589 0.969883 -0.084102 -0.310877 -0.187017 0.128529 0.973912 -0.04118 0 0 0 1 0.959413 -0.201385 0.197412 399.227 0.220555 0.972067 -0.080255 -0.311637 -0.175736 0.120538 0.97703 -0.038619 0 0 0 1 0.967822 -0.186037 0.169441 399.222 0.200407 0.977069 -0.07193 -0.313277 -0.152174 0.103572 0.982912 -0.033186 0 0 0 1 0.977694 -0.164018 0.131201 399.215 0.172916 0.983138 -0.059495 -0.315219 -0.11923 0.080853 0.989569 -0.0259 0 0 0 1 0.986361 -0.139197 0.087844 399.207 0.143434 0.988686 -0.043891 -0.316945 -0.080741 0.055893 0.995167 -0.017907 0 0 0 1 0.992311 -0.115658 0.044061 399.199 0.116894 0.992789 -0.026584 -0.318304 -0.040668 0.03153 0.998675 -0.010117 0 0 0 1 0.995213 -0.097655 0.003769 399.193 0.097687 0.995172 -0.009433 -0.318995 -0.002831 0.009756 0.999948 -0.00311 0 0 0 1 0.995505 -0.090261 -0.028687 399.191 0.090438 0.99589 0.004967 -0.319313 0.028121 -0.00754 0.999576 0.00239 0 0 0 1 0.993832 -0.095217 -0.056844 399.193 0.09634 0.995197 0.017363 -0.319129 0.054918 -0.022732 0.998232 0.007284 0 0 0 1 0.990228 -0.108872 -0.087149 399.197 0.111855 0.993268 0.030097 -0.318609 0.083286 -0.039551 0.99574 0.01267 0 0 0 1 0.984822 -0.127982 -0.117244 399.203 0.133656 0.990144 0.041845 -0.317517 0.110733 -0.05688 0.992221 0.018212 0 0 0 1 0.978027 -0.149529 -0.145274 399.21 0.158445 0.986008 0.05181 -0.316148 0.135494 -0.073689 0.988034 0.023584 0 0 0 1 0.970555 -0.170998 -0.169654 399.217 0.183298 0.98125 0.05959 -0.314634 0.156283 -0.088932 0.9837 0.028506 0 0 0 1 0.96361 -0.189722 -0.188315 399.223 0.204962 0.976618 0.064874 -0.31312 0.171604 -0.101111 0.979964 0.032388 0 0 0 1 0.958771 -0.202873 -0.198997 399.227 0.219931 0.973177 0.067501 -0.312043 0.179965 -0.108483 0.977673 0.03471 0 0 0 1 0.957418 -0.20821 -0.199999 399.229 0.225455 0.971915 0.06746 -0.311548 0.180336 -0.109679 0.977471 0.03511 0 0 0 1 0.961314 -0.20261 -0.186612 399.227 0.217615 0.973963 0.063561 -0.312402 0.168875 -0.101712 0.980375 0.032612 0 0 0 1 0.969461 -0.187076 -0.158579 399.222 0.197873 0.978675 0.05514 -0.313723 0.144882 -0.084835 0.985805 0.027163 0 0 0 1 0.978965 -0.164808 -0.120268 399.215 0.170949 0.984359 0.042596 -0.315573 0.111367 -0.062261 0.991827 0.019957 0 0 0 1 0.987205 -0.139712 -0.076854 399.207 0.142129 0.989482 0.026905 -0.317325 0.072287 -0.037483 0.996679 0.012 0 0 0 1 0.992711 -0.115905 -0.033035 399.199 0.116276 0.993171 0.009543 -0.318509 0.031704 -0.013315 0.999409 0.00425 0 0 0 1 0.995193 -0.097664 0.007265 399.193 0.097718 0.995185 -0.007622 -0.318998 -0.006485 0.008296 0.999945 -0.002677 0 0 0 1 0.995149 -0.090084 0.039526 399.191 0.090997 0.99561 -0.021927 -0.319096 -0.037378 0.025417 0.998978 -0.00815 0 0 0 1 0.993175 -0.094866 0.067854 399.192 0.097358 0.994655 -0.03438 -0.3188 -0.06423 0.040751 0.997103 -0.013075 0 0 0 1 0.989259 -0.108336 0.098128 399.197 0.113353 0.99244 -0.047066 -0.318201 -0.092287 0.057684 0.99406 -0.018496 0 0 0 1 0.983553 -0.127254 0.12818 399.203 0.135617 0.989018 -0.05875 -0.317074 -0.119297 0.075167 0.99001 -0.02408 0 0 0 1 0.976487 -0.148615 0.156162 399.21 0.160825 0.984593 -0.06864 -0.315693 -0.143555 0.092141 0.985343 -0.029518 0 0 0 1 0.968789 -0.169915 0.180492 399.216 0.186029 0.979574 -0.076342 -0.313991 -0.163834 0.107536 0.980609 -0.034497 0 0 0 1 0.961677 -0.188504 0.19911 399.222 0.20795 0.974733 -0.081559 -0.312503 -0.178705 0.119839 0.976577 -0.038371 0 0 0 1 0.956748 -0.201573 0.209765 399.227 0.22306 0.971166 -0.084146 -0.311557 -0.186755 0.127297 0.974124 -0.040787 0 0 0 1 0.955391 -0.206897 0.210765 399.228 0.228589 0.969883 -0.084102 -0.310877 -0.187017 0.128529 0.973912 -0.04118 0 0 0 1 0.959413 -0.201385 0.197412 399.227 0.220555 0.972067 -0.080255 -0.311624 -0.175736 0.120538 0.97703 -0.038607 0 0 0 1 0.967822 -0.186037 0.169441 399.222 0.200407 0.977069 -0.07193 -0.313172 -0.152174 0.103572 0.982912 -0.033185 0 0 0 1 0.977694 -0.164018 0.1312 399.215 0.172916 0.983138 -0.059495 -0.315219 -0.11923 0.080854 0.989569 -0.0259 0 0 0 1 0.986361 -0.139197 0.087844 399.207 0.143434 0.988686 -0.043891 -0.317002 -0.080741 0.055893 0.995167 -0.017904 0 0 0 1 0.992311 -0.115658 0.044061 399.199 0.116894 0.992789 -0.026584 -0.318304 -0.040668 0.03153 0.998675 -0.010117 0 0 0 1 0.995213 -0.097655 0.003769 399.193 0.097687 0.995172 -0.009433 -0.318995 -0.002831 0.009756 0.999948 -0.003149 0 0 0 1 0.99551 -0.090265 -0.028498 399.191 0.090439 0.99589 0.004882 -0.319236 0.02794 -0.007438 0.999582 0.002363 0 0 0 1 0.993832 -0.095217 -0.056844 399.193 0.09634 0.995197 0.017363 -0.319129 0.054918 -0.022732 0.998232 0.007284 0 0 0 1 0.990228 -0.108873 -0.087149 399.197 0.111855 0.993268 0.030097 -0.318609 0.083286 -0.039551 0.99574 0.01267 0 0 0 1 0.984822 -0.127982 -0.117244 399.203 0.133656 0.990144 0.041845 -0.317474 0.110733 -0.05688 0.992221 0.018219 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.767026 0.627219 -0.135158 402.56 -0.617671 0.778843 0.109021 -0.112731 0.173646 -0.000139 0.984808 -0.000017 0 0 0 1 0.814578 0.574055 -0.083215 402.568 -0.568606 0.818602 0.081099 -0.118439 0.114676 -0.018744 0.993226 0.002709 0 0 0 1 0.859844 0.509933 -0.025247 402.577 -0.508093 0.859499 0.05571 -0.124322 0.050108 -0.035074 0.998128 0.005056 0 0 0 1 0.897521 0.439485 0.036187 402.587 -0.440631 0.897031 0.034363 -0.129759 -0.017359 -0.046787 0.998754 0.006786 0 0 0 1 0.924007 0.369887 0.096931 402.597 -0.373189 0.927584 0.017818 -0.134152 -0.08332 -0.052638 0.995132 0.00764 0 0 0 1 0.938426 0.31046 0.151561 402.606 -0.314903 0.949107 0.005627 -0.137372 -0.1421 -0.053007 0.988432 0.007674 0 0 0 1 0.942991 0.268267 0.196978 402.612 -0.272777 0.962067 -0.004387 -0.139239 -0.190683 -0.049593 0.980398 0.007164 0 0 0 1 0.94034 0.251605 0.229033 402.614 -0.255112 0.966801 -0.014665 -0.14001 -0.225119 -0.044638 0.973309 0.00649 0 0 0 1 0.932307 0.266 0.245046 402.612 -0.267624 0.963137 -0.027287 -0.139461 -0.243271 -0.04014 0.969127 0.005827 0 0 0 1 0.919069 0.306568 0.247644 402.606 -0.30577 0.951149 -0.042676 -0.137682 -0.248629 -0.036499 0.967911 0.005301 0 0 0 1 0.899625 0.365227 0.23934 402.598 -0.361871 0.930329 -0.059468 -0.134683 -0.244384 -0.03311 0.969113 0.004794 0 0 0 1 0.873653 0.43224 0.223379 402.588 -0.426559 0.901287 -0.075688 -0.130503 -0.234045 -0.029159 0.971789 0.004239 0 0 0 1 0.841542 0.500605 0.20298 402.578 -0.49297 0.865342 -0.090352 -0.125312 -0.220879 -0.024027 0.975005 0.003444 0 0 0 1 0.806187 0.562989 0.181951 402.569 -0.553792 0.826273 -0.102902 -0.119544 -0.208274 -0.017803 0.977909 0.002576 0 0 0 1 0.773243 0.612332 0.164758 402.562 -0.601831 0.790519 -0.113489 -0.114389 -0.199737 -0.011403 0.979783 0.001642 0 0 0 1 0.767026 0.627218 0.135161 402.56 -0.61767 0.778844 -0.109022 -0.112702 -0.17365 0.000137 0.984807 0.000015 0 0 0 1 0.809441 0.580886 0.085891 402.567 -0.575159 0.813785 -0.083345 -0.117729 -0.118312 0.018062 0.992813 -0.002604 0 0 0 1 0.852442 0.521905 0.03095 402.575 -0.519693 0.852321 -0.058885 -0.123389 -0.057112 0.034112 0.997785 -0.004959 0 0 0 1 0.890265 0.454589 -0.027883 402.585 -0.455376 0.889515 -0.037363 -0.128798 0.007817 0.045961 0.998913 -0.006656 0 0 0 1 0.91853 0.3856 -0.087267 402.595 -0.388607 0.921188 -0.019918 -0.133247 0.072709 0.052208 0.995986 -0.007557 0 0 0 1 0.935291 0.323932 -0.142471 402.604 -0.328165 0.944597 -0.006625 -0.136611 0.132432 0.05295 0.989777 -0.007676 0 0 0 1 0.941868 0.276263 -0.191215 402.611 -0.280659 0.959798 0.004255 -0.138975 0.184703 0.049658 0.981539 -0.007201 0 0 0 1 0.940332 0.251604 -0.229067 402.614 -0.255111 0.9668 0.014674 -0.139836 0.225154 0.044638 0.9733 -0.006451 0 0 0 1 0.931038 0.265303 -0.250566 402.612 -0.266817 0.963324 0.028556 -0.139524 0.248953 0.040268 0.967678 -0.00583 0 0 0 1 0.913547 0.316573 -0.255369 402.605 -0.315257 0.947832 0.047209 -0.137207 0.256991 0.037379 0.965691 -0.005442 0 0 0 1 0.887974 0.387481 -0.24771 402.595 -0.38315 0.921215 0.067521 -0.133496 0.254358 0.034952 0.966478 -0.005055 0 0 0 1 0.857341 0.458908 -0.233174 402.584 -0.451929 0.887915 0.085836 -0.128642 0.24643 0.031787 0.968639 -0.004591 0 0 0 1 0.828003 0.516655 -0.217897 402.576 -0.507536 0.855754 0.100452 -0.123813 0.238365 0.027415 0.970789 -0.004007 0 0 0 1 0.796289 0.570948 -0.199856 402.568 -0.560114 0.82069 0.112873 -0.118768 0.228465 0.022061 0.973302 -0.003197 0 0 0 1 0.766737 0.618458 -0.172118 402.561 -0.607131 0.785701 0.118604 -0.113645 0.208585 0.01356 0.97791 -0.001971 0 0 0 1 0.767026 0.627219 -0.135158 402.56 -0.617671 0.778843 0.109021 -0.112709 0.173646 -0.000139 0.984808 0.000021 0 0 0 1 0.80073 0.592597 -0.087519 402.565 -0.586506 0.805296 0.086648 -0.116642 0.121827 -0.018051 0.992387 0.002612 0 0 0 1 0.843228 0.536661 -0.030995 402.573 -0.534264 0.843042 0.061988 -0.121964 0.059396 -0.035711 0.997595 0.005179 0 0 0 1 0.884274 0.465914 0.031376 402.583 -0.46687 0.883471 0.038874 -0.127835 -0.009608 -0.049024 0.998751 0.007093 0 0 0 1 0.916036 0.389785 0.094586 402.594 -0.393207 0.919233 0.019955 -0.133072 -0.079168 -0.055472 0.995316 0.008021 0 0 0 1 0.93478 0.321136 0.151847 402.604 -0.325781 0.945426 0.006075 -0.136915 -0.141609 -0.055147 0.988385 0.007988 0 0 0 1 0.941902 0.270917 0.198556 402.611 -0.27552 0.961284 -0.004607 -0.13914 -0.192117 -0.050366 0.980079 0.007284 0 0 0 1 0.940342 0.251606 0.229027 402.614 -0.255113 0.9668 -0.014666 -0.140024 -0.225113 -0.044636 0.97331 0.006447 0 0 0 1 0.931534 0.269018 0.244691 402.612 -0.270581 0.962294 -0.027868 -0.139266 -0.242962 -0.040247 0.9692 0.005838 0 0 0 1 0.915235 0.314938 0.251314 402.605 -0.313799 0.948389 -0.045694 -0.137313 -0.252734 -0.03704 0.966826 0.005342 0 0 0 1 0.891693 0.378265 0.248596 402.596 -0.374143 0.925052 -0.065545 -0.133846 -0.254759 -0.034563 0.966387 0.005016 0 0 0 1 0.861838 0.448332 0.237135 402.586 -0.441421 0.893303 -0.084604 -0.129249 -0.249765 -0.031761 0.967786 0.004633 0 0 0 1 0.827987 0.516694 0.217865 402.576 -0.507577 0.855731 -0.10045 -0.123901 -0.238335 -0.027412 0.970796 0.003998 0 0 0 1 0.796084 0.573601 0.192953 402.568 -0.563238 0.818873 -0.1105 -0.118498 -0.221387 -0.020711 0.974966 0.00304 0 0 0 1 0.773243 0.612332 0.164758 402.562 -0.601831 0.790519 -0.113489 -0.11448 -0.199737 -0.011403 0.979783 0.00163 0 0 0 1 0.767026 0.627218 0.135161 402.56 -0.61767 0.778844 -0.109022 -0.112796 -0.17365 0.000137 0.984807 -0.000015 0 0 0 1 0.782715 0.614319 0.099847 402.562 -0.60701 0.788931 -0.09554 -0.113981 -0.137465 0.014173 0.990405 -0.002063 0 0 0 1 0.814092 0.578105 0.055218 402.567 -0.573987 0.815439 -0.07482 -0.118048 -0.08828 0.029216 0.995667 -0.004174 0 0 0 1 0.852358 0.522954 0.00237 402.575 -0.522173 0.851315 -0.05098 -0.123169 -0.028678 0.042215 0.998697 -0.006087 0 0 0 1 0.889031 0.454362 -0.056372 402.585 -0.456312 0.889383 -0.02791 -0.128654 0.037456 0.050536 0.99802 -0.00732 0 0 0 1 0.917194 0.380993 -0.116621 402.596 -0.384552 0.923061 -0.008829 -0.133562 0.104284 0.052945 0.993137 -0.007681 0 0 0 1 0.934325 0.310164 -0.175601 402.606 -0.314156 0.949357 0.005312 -0.137518 0.168355 0.050203 0.984447 -0.007283 0 0 0 1 0.940325 0.251603 -0.229097 402.614 -0.25511 0.9668 0.014684 -0.140012 0.225185 0.044636 0.973293 -0.006444 0 0 0 1 0.931534 0.269019 -0.24469 402.612 -0.270582 0.962293 0.027868 -0.139377 0.242961 0.040248 0.969201 -0.005825 0 0 0 1 0.91462 0.328055 -0.236326 402.603 -0.327105 0.943945 0.044382 -0.136632 0.237639 0.036709 0.97066 -0.005316 0 0 0 1 0.889314 0.396164 -0.22842 402.593 -0.392513 0.917571 0.063225 -0.132922 0.234639 0.03343 0.971507 -0.004815 0 0 0 1 0.857752 0.465222 -0.218699 402.583 -0.458924 0.884684 0.081994 -0.12804 0.231625 0.030036 0.972341 -0.004368 0 0 0 1 0.823287 0.5292 -0.205296 402.574 -0.520594 0.848105 0.098487 -0.122696 0.226232 0.025792 0.973732 -0.003741 0 0 0 1 0.792278 0.580676 -0.187379 402.567 -0.570537 0.813892 0.109852 -0.117868 0.216295 0.019874 0.976125 -0.002893 0 0 0 1 0.771377 0.614791 -0.164345 402.562 -0.604251 0.788607 0.113929 -0.114116 0.199646 0.011424 0.979802 -0.001673 0 0 0 1 0.767026 0.627219 -0.135158 402.56 -0.617671 0.778843 0.109021 -0.112662 0.173646 -0.000139 0.984808 0.00002 0 0 0 1 0.785933 0.610749 -0.096412 402.562 -0.603688 0.79167 0.093912 -0.114632 0.133683 -0.015606 0.990901 0.002261 0 0 0 1 0.822658 0.566588 -0.047035 402.569 -0.562959 0.823355 0.071864 -0.119062 0.079444 -0.03264 0.996305 0.004718 0 0 0 1 0.86504 0.501592 0.010486 402.578 -0.501478 0.863844 0.04789 -0.124996 0.014962 -0.046685 0.998797 0.006735 0 0 0 1 0.902012 0.425729 0.071621 402.589 -0.428384 0.903214 0.02629 -0.130615 -0.053496 -0.054395 0.997086 0.007863 0 0 0 1 0.927265 0.350523 0.13158 402.6 -0.354715 0.93493 0.009119 -0.135328 -0.119821 -0.05513 0.991264 0.007986 0 0 0 1 0.939442 0.287929 0.185864 402.609 -0.292322 0.956312 -0.003927 -0.138484 -0.178875 -0.050642 0.982568 0.007322 0 0 0 1 0.940327 0.251602 0.229092 402.614 -0.255108 0.966801 -0.014684 -0.140015 -0.225181 -0.044635 0.973294 0.006485 0 0 0 1 0.930995 0.263167 0.252966 402.613 -0.264676 0.963911 -0.028689 -0.139507 -0.251387 -0.040244 0.96705 0.005838 0 0 0 1 0.912331 0.318109 0.257796 402.605 -0.316656 0.947309 -0.048307 -0.13716 -0.25958 -0.03756 0.964991 0.005435 0 0 0 1 0.886969 0.388413 0.249845 402.595 -0.383951 0.920813 -0.068453 -0.133224 -0.256647 -0.035212 0.965864 0.005128 0 0 0 1 0.861838 0.448332 0.237135 402.586 -0.441421 0.893303 -0.084604 -0.129249 -0.249765 -0.031761 0.967786 0.004633 0 0 0 1 0.833026 0.506696 0.222098 402.577 -0.497594 0.861683 -0.099516 -0.124699 -0.241803 -0.027615 0.969932 0.00403 0 0 0 1 0.796498 0.570574 0.200092 402.568 -0.559733 0.820949 -0.112878 -0.11876 -0.22867 -0.02209 0.973253 0.003213 0 0 0 1 0.768315 0.616759 0.171172 402.561 -0.605569 0.787041 -0.117698 -0.113856 -0.207311 -0.013226 0.978186 0.001938 0 0 0 1 0.767026 0.627218 0.135161 402.56 -0.61767 0.778844 -0.109022 -0.112796 -0.17365 0.000137 0.984807 -0.000015 0 0 0 1 0.796105 0.598533 0.089309 402.564 -0.592202 0.800904 -0.088599 -0.115862 -0.124557 0.017645 0.992056 -0.002577 0 0 0 1 0.837828 0.544924 0.033211 402.572 -0.542313 0.837724 -0.064149 -0.121222 -0.062778 0.035735 0.997388 -0.00516 0 0 0 1 0.88015 0.47378 -0.029476 402.582 -0.474648 0.879247 -0.040436 -0.127253 0.006759 0.049581 0.998747 -0.007191 0 0 0 1 0.913436 0.396269 -0.092774 402.593 -0.399686 0.916413 -0.02093 -0.132623 0.076725 0.056199 0.995467 -0.008147 0 0 0 1 0.933669 0.324838 -0.150806 402.604 -0.329521 0.944126 -0.006468 -0.136596 0.140279 0.055733 0.988542 -0.008078 0 0 0 1 0.941645 0.272042 -0.198237 402.611 -0.276668 0.960955 0.004526 -0.139155 0.191728 0.050584 0.980144 -0.007322 0 0 0 1 0.940377 0.251606 -0.228881 402.614 -0.255123 0.966798 0.014595 -0.140044 0.224954 0.044668 0.973345 -0.006453 0 0 0 1 0.931534 0.269019 -0.24469 402.612 -0.270582 0.962293 0.027868 -0.139377 0.242961 0.040248 0.969201 -0.005825 0 0 0 1 0.915235 0.314939 -0.251312 402.605 -0.3138 0.948389 0.045695 -0.137298 0.252733 0.03704 0.966827 -0.005379 0 0 0 1 0.891693 0.378266 -0.248594 402.596 -0.374144 0.925051 0.065546 -0.133932 0.254757 0.034563 0.966388 -0.005035 0 0 0 1 0.861838 0.448333 -0.237133 402.586 -0.441422 0.893302 0.084604 -0.129273 0.249762 0.03176 0.967786 -0.004569 0 0 0 1 0.828194 0.516304 -0.218001 402.576 -0.507198 0.855965 0.100367 -0.123876 0.238421 0.027446 0.970774 -0.003972 0 0 0 1 0.796084 0.573603 -0.19295 402.568 -0.56324 0.818871 0.110499 -0.118558 0.221384 0.020709 0.974966 -0.003028 0 0 0 1 0.773243 0.612333 -0.164755 402.562 -0.601832 0.790518 0.113487 -0.11435 0.199734 0.011401 0.979784 -0.001648 0 0 0 1 0.767026 0.627219 -0.135157 402.56 -0.617671 0.778843 0.109021 -0.112713 0.173646 -0.000138 0.984808 0.000007 0 0 0 1 0.785071 0.611499 -0.098656 402.562 -0.604243 0.791102 0.095118 -0.114537 0.136211 -0.015062 0.990565 0.002216 0 0 0 1 0.821695 0.567709 -0.050235 402.568 -0.563849 0.822606 0.073439 -0.11899 0.083016 -0.032019 0.996034 0.004596 0 0 0 1 0.864401 0.50275 0.00733 402.578 -0.502465 0.863193 0.04926 -0.124895 0.018438 -0.046264 0.99876 0.006706 0 0 0 1 0.901767 0.426645 0.069207 402.589 -0.429218 0.902792 0.027194 -0.13061 -0.050877 -0.054228 0.997231 0.007837 0 0 0 1 0.927258 0.35105 0.130218 402.6 -0.355222 0.934733 0.009552 -0.135382 -0.118366 -0.055115 0.991439 0.007996 0 0 0 1 0.939474 0.288089 0.185454 402.609 -0.292484 0.956263 -0.003816 -0.138435 -0.178442 -0.050656 0.982646 0.007323 0 0 0 1 0.940377 0.251605 0.228882 402.614 -0.255122 0.966799 -0.014595 -0.140029 -0.224955 -0.044667 0.973345 0.006494 0 0 0 1 0.930995 0.263167 0.252966 402.613 -0.264676 0.963911 -0.028689 -0.139507 -0.251387 -0.040244 0.96705 0.005838 0 0 0 1 0.912331 0.318109 0.257796 402.605 -0.316656 0.947309 -0.048307 -0.137122 -0.25958 -0.03756 0.964991 0.005436 0 0 0 1 0.886969 0.388413 0.249845 402.594 -0.383951 0.920813 -0.068453 -0.13334 -0.256647 -0.035212 0.965864 0.005101 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.999373 -0.013879 0.032569 181.732 0.016083 0.997526 -0.068434 -0.00008 -0.031539 0.068915 0.997124 -0.000002 0 0 0 1 0.9999 0.014165 0.000389 181.732 -0.014114 0.997986 -0.061838 0.000045 -0.001265 0.061826 0.998086 -0.000002 0 0 0 1 0.998377 0.045436 -0.034349 181.732 -0.047319 0.997299 -0.056175 -0.000013 0.031703 0.057709 0.99783 -0.000002 0 0 0 1 0.994539 0.077413 -0.069998 181.732 -0.081057 0.995413 -0.050816 0.000033 0.065743 0.056212 0.996252 -0.000002 0 0 0 1 0.988771 0.1071 -0.104222 181.732 -0.112305 0.992636 -0.045414 0.000031 0.09859 0.056608 0.993517 -0.000002 0 0 0 1 0.982257 0.131208 -0.134 181.732 -0.137643 0.989678 -0.039905 0.000027 0.127381 0.057642 0.990178 -0.000002 0 0 0 1 0.97643 0.147696 -0.157383 181.732 -0.154845 0.98735 -0.034103 0.000155 0.150355 0.057669 0.986949 -0.000002 0 0 0 1 0.973067 0.154069 -0.171474 181.732 -0.161097 0.986548 -0.027765 0.000125 0.164889 0.054641 0.984798 -0.000002 0 0 0 1 0.974281 0.149196 -0.168867 181.732 -0.155034 0.987667 -0.021856 0.000071 0.163523 0.047474 0.985397 -0.000002 0 0 0 1 0.979681 0.134847 -0.14846 181.732 -0.138628 0.990225 -0.015373 0.000028 0.144936 0.035641 0.988799 -0.000002 0 0 0 1 0.986699 0.112807 -0.117045 181.732 -0.114167 0.993449 -0.004966 0.000073 0.115718 0.018263 0.993114 -0.000002 0 0 0 1 0.992907 0.085283 -0.082842 181.732 -0.08464 0.996348 0.01125 0.000042 0.083498 -0.004158 0.996499 -0.000002 0 0 0 1 0.997144 0.053543 -0.053272 181.732 -0.051804 0.998095 0.033514 -0.000012 0.054965 -0.030658 0.998018 -0.000002 0 0 0 1 0.999144 0.019549 -0.03647 181.732 -0.017358 0.998078 0.05949 0.00003 0.037563 -0.058806 0.997562 -0.000002 0 0 0 1 0.99912 -0.013578 -0.039677 181.732 0.016889 0.996293 0.084347 -0.000065 0.038385 -0.084943 0.995646 -0.000002 0 0 0 1 0.99974 -0.022369 -0.004439 181.732 0.022686 0.99535 0.093612 -0.000126 0.002324 -0.093688 0.995599 -0.000002 0 0 0 1 0.996964 0.022683 0.074491 181.732 -0.028889 0.996103 0.08333 0.000024 -0.07231 -0.085229 0.993734 -0.000002 0 0 0 1 0.990115 0.059348 0.127083 181.732 -0.068706 0.995139 0.070556 -0.00001 -0.122277 -0.07859 0.989379 -0.000002 0 0 0 1 0.982866 0.088584 0.16164 181.732 -0.099141 0.993356 0.058441 0.000017 -0.155389 -0.073464 0.985118 -0.000002 0 0 0 1 0.976466 0.111014 0.184905 181.732 -0.12188 0.991363 0.048434 0.00002 -0.17793 -0.06983 0.981563 -0.000002 0 0 0 1 0.970817 0.127675 0.20301 181.732 -0.138533 0.989544 0.040144 -0.000036 -0.195762 -0.067096 0.978353 -0.000002 0 0 0 1 0.964726 0.141082 0.222257 181.732 -0.151627 0.98795 0.031025 0.000082 -0.215202 -0.063632 0.974495 -0.000002 0 0 0 1 0.956716 0.153544 0.247225 181.732 -0.162894 0.986485 0.017692 0.000076 -0.241166 -0.057199 0.968797 -0.000002 0 0 0 1 0.951417 0.15276 0.267341 181.732 -0.158608 0.987342 0.000284 0.000075 -0.263913 -0.042672 0.963602 -0.000002 0 0 0 1 0.9529 0.131338 0.273372 181.732 -0.131157 0.991179 -0.01902 0.000046 -0.273459 -0.01773 0.96172 -0.000002 0 0 0 1 0.957396 0.09976 0.270999 181.732 -0.091925 0.994901 -0.041486 0.000117 -0.273756 0.014807 0.961685 -0.000002 0 0 0 1 0.961557 0.06963 0.26563 181.732 -0.053657 0.996314 -0.066933 0.000037 -0.269311 0.050107 0.961749 -0.000002 0 0 0 1 0.963777 0.051945 0.261602 181.732 -0.028015 0.995142 -0.094387 -0.000077 -0.265234 0.083639 0.960549 -0.000002 0 0 0 1 0.96357 0.029404 0.265836 181.732 0.003307 0.992553 -0.121772 0.000045 -0.267436 0.118214 0.956297 -0.000002 0 0 0 1 0.963845 -0.000485 0.266461 181.732 0.040697 0.988534 -0.145411 -0.000065 -0.263336 0.150998 0.952814 -0.000002 0 0 0 1 0.971794 -0.003456 0.235804 181.732 0.042809 0.985866 -0.161974 0.000072 -0.231911 0.1675 0.958207 -0.000002 0 0 0 1 0.982661 0.021822 0.184124 181.732 0.010069 0.985303 -0.170518 -0.000029 -0.185139 0.169416 0.967999 -0.000002 0 0 0 1 0.988509 0.050368 0.142527 181.732 -0.025084 0.984439 -0.173926 -0.000056 -0.149069 0.168352 0.97439 -0.000002 0 0 0 1 0.990761 0.079589 0.109812 181.732 -0.059634 0.98288 -0.174327 0.000009 -0.121807 0.166168 0.978545 -0.000002 0 0 0 1 0.990652 0.10631 0.085479 181.732 -0.090258 0.980669 -0.173615 0.000018 -0.102284 0.164277 0.981097 -0.000002 0 0 0 1 0.989454 0.127285 0.069127 181.732 -0.113788 0.978368 -0.172769 0.000013 -0.089623 0.163081 0.982534 -0.000002 0 0 0 1 0.988234 0.140763 0.059832 181.732 -0.128752 0.976756 -0.171379 -0.000018 -0.082565 0.161659 0.983387 -0.000002 0 0 0 1 0.987754 0.144995 0.057612 181.732 -0.133591 0.976732 -0.167774 0.000033 -0.080599 0.158023 0.984141 -0.000002 0 0 0 1 0.98833 0.137579 0.065392 181.732 -0.125693 0.979059 -0.160139 0.000013 -0.086054 0.15005 0.984926 -0.000002 0 0 0 1 0.989263 0.119363 0.084329 181.732 -0.106121 0.983416 -0.147072 -0.000051 -0.100486 0.136543 0.985525 -0.000002 0 0 0 1 0.989345 0.094207 0.111006 181.732 -0.079804 0.988594 -0.127722 0.000041 -0.121772 0.117503 0.985579 -0.000002 0 0 0 1 0.987723 0.06565 0.141753 181.732 -0.051358 0.993434 -0.102227 0.000098 -0.147534 0.093692 0.984609 -0.000002 0 0 0 1 0.984135 0.036582 0.173609 181.732 -0.024403 0.997123 -0.07177 0.000108 -0.175735 0.066395 0.982195 -0.000002 0 0 0 1 0.979121 0.01115 0.202971 181.732 -0.003013 0.999181 -0.040355 0.00004 -0.203255 0.038901 0.978353 -0.000002 0 0 0 1 0.973698 -0.006842 0.227739 181.732 0.010011 0.999868 -0.012759 -0.000124 -0.227622 0.014704 0.973639 -0.000002 0 0 0 1 0.968988 -0.013432 0.246741 181.732 0.01232 0.999906 0.006047 0.00003 -0.246799 -0.002819 0.969063 -0.000002 0 0 0 1 0.965532 -0.009382 0.260114 181.732 0.005927 0.999884 0.014069 -0.000129 -0.260216 -0.012042 0.965475 -0.000002 0 0 0 1 0.962871 0.001486 0.269959 181.732 -0.005544 0.999883 0.014267 -0.000056 -0.269906 -0.015234 0.962766 -0.000002 0 0 0 1 0.960364 0.019415 0.278072 181.732 -0.022979 0.99969 0.009562 0.000066 -0.2778 -0.015572 0.960513 -0.000002 0 0 0 1 0.957197 0.044502 0.285997 181.732 -0.047237 0.99888 0.002665 0.000032 -0.285558 -0.016061 0.958227 -0.000002 0 0 0 1 0.952386 0.076203 0.295219 181.732 -0.078399 0.996912 -0.004409 0.000078 -0.294644 -0.018945 0.955419 -0.000002 0 0 0 1 0.944562 0.11513 0.307486 181.732 -0.117386 0.993023 -0.011215 0.000003 -0.306632 -0.0255 0.951487 -0.000002 0 0 0 1 0.932207 0.161295 0.323996 181.732 -0.164266 0.986245 -0.018353 0.000137 -0.3225 -0.036112 0.94588 -0.000002 0 0 0 1 0.937675 0.154432 0.311315 181.732 -0.155495 0.987601 -0.021566 0.000031 -0.310786 -0.028185 0.950062 -0.000002 0 0 0 1 0.958439 0.122612 0.257605 181.732 -0.120792 0.992413 -0.022939 0.000033 -0.258464 -0.009131 0.965978 -0.000002 0 0 0 1 0.972998 0.09136 0.211963 181.732 -0.086135 0.995711 -0.033773 -0.000000 -0.21414 0.014602 0.976693 -0.000002 0 0 0 1 0.983229 0.061875 0.171561 181.732 -0.053668 0.9972 -0.052072 -0.000016 -0.174303 0.041992 0.983796 -0.000002 0 0 0 1 0.99057 0.034997 0.132463 181.732 -0.025129 0.996832 -0.075452 -0.000016 -0.134684 0.071412 0.988312 -0.000002 0 0 0 1 0.995718 0.01277 0.091556 181.732 -0.003569 0.994986 -0.099954 0.000049 -0.092374 0.099199 0.990771 -0.000002 0 0 0 1 0.99901 -0.003232 0.044378 181.732 0.008606 0.992562 -0.121433 0.000014 -0.043656 0.121694 0.991607 -0.000002 0 0 0 1 0.99983 -0.011284 -0.014575 181.732 0.009206 0.990738 -0.135474 -0.00005 0.015969 0.135317 0.990674 -0.000002 0 0 0 1 0.996293 -0.007635 -0.085688 181.732 -0.004285 0.990411 -0.138084 0.000039 0.08592 0.137939 0.986707 -0.000002 0 0 0 1 0.986456 0.008001 -0.163833 181.732 -0.029505 0.991174 -0.12924 0.000008 0.161353 0.132323 0.977986 -0.000002 0 0 0 1 0.968896 0.032663 -0.245305 181.732 -0.061468 0.99195 -0.110704 -0.000025 0.239714 0.122339 0.963104 -0.000002 0 0 0 1 0.943651 0.062441 -0.324998 181.732 -0.095111 0.991778 -0.085614 -0.000019 0.31698 0.111702 0.941832 -0.000002 0 0 0 1 0.911949 0.093466 -0.399516 181.732 -0.126563 0.990307 -0.057217 0.000052 0.390295 0.102743 0.914939 -0.000002 0 0 0 1 0.875725 0.122375 -0.467044 181.732 -0.153044 0.987819 -0.028134 0.000069 0.457911 0.096116 0.883787 -0.000002 0 0 0 1 0.838422 0.145417 -0.525264 181.732 -0.171656 0.985156 -0.00126 0.000036 0.517283 0.091222 0.850939 -0.000002 0 0 0 1 0.814283 0.143942 -0.562337 181.732 -0.164855 0.986222 0.01373 0.000034 0.556566 0.081524 0.826794 -0.000002 0 0 0 1 0.809336 0.115094 -0.575959 181.732 -0.130265 0.991365 0.015057 0.000059 0.572718 0.062841 0.81734 -0.000002 0 0 0 1 0.814995 0.079985 -0.573921 181.732 -0.088233 0.996008 0.013515 0.000033 0.572711 0.039624 0.818799 -0.000002 0 0 0 1 0.823742 0.059672 -0.563816 181.732 -0.058965 0.99807 0.019484 0.000098 0.563891 0.017195 0.82567 -0.000002 0 0 0 1 0.830435 0.03887 -0.555757 181.732 -0.027589 0.999208 0.028661 0.000039 0.556431 -0.008469 0.83085 -0.000002 0 0 0 1 0.835239 0.002124 -0.549883 181.732 0.020002 0.999213 0.034242 -0.000087 0.549524 -0.0396 0.834539 -0.000002 0 0 0 1 0.84231 -0.028961 -0.538214 181.732 0.060526 0.997322 0.041056 -0.00012 0.535584 -0.067158 0.841807 -0.000002 0 0 0 1 0.858672 -0.033905 -0.511402 181.732 0.071849 0.995919 0.05461 0.00003 0.507464 -0.083635 0.857605 -0.000002 0 0 0 1 0.878558 -0.013901 -0.477432 181.732 0.055715 0.995735 0.073532 -0.000023 0.474374 -0.091202 0.875586 -0.000002 0 0 0 1 0.892771 0.012702 -0.450332 181.732 0.032554 0.99517 0.092607 -0.000035 0.449333 -0.097337 0.888046 -0.000002 0 0 0 1 0.902387 0.042101 -0.428867 181.732 0.00656 0.993758 0.11136 -0.000047 0.430879 -0.103304 0.896477 -0.000002 0 0 0 1 0.908425 0.069932 -0.412157 181.732 -0.017835 0.991494 0.128921 0.000002 0.417667 -0.109765 0.901946 -0.000002 0 0 0 1 0.912199 0.092533 -0.399162 181.732 -0.037387 0.988899 0.143805 0.000012 0.408038 -0.116255 0.905533 -0.000002 0 0 0 1 0.914921 0.106959 -0.389204 181.732 -0.050058 0.986875 0.153534 0.000087 0.400517 -0.120989 0.908266 -0.000002 0 0 0 1 0.917434 0.110279 -0.382301 181.732 -0.054258 0.986523 0.154365 0.000075 0.394172 -0.120877 0.911053 -0.000002 0 0 0 1 0.919607 0.100373 -0.3798 181.732 -0.048741 0.98849 0.143219 0.000031 0.389804 -0.113193 0.913915 -0.000002 0 0 0 1 0.920639 0.079247 -0.382287 181.732 -0.035269 0.99206 0.120715 -0.000041 0.388818 -0.097652 0.916124 -0.000002 0 0 0 1 0.920169 0.050832 -0.388207 181.732 -0.017483 0.995882 0.088962 0.000043 0.39113 -0.075073 0.917268 -0.000002 0 0 0 1 0.918161 0.018734 -0.395765 181.732 0.001449 0.998716 0.050639 -0.000002 0.396206 -0.047068 0.916955 -0.000002 0 0 0 1 0.914823 -0.013901 -0.403615 181.732 0.019128 0.999777 0.008917 -0.000039 0.403401 -0.015878 0.914886 -0.000002 0 0 0 1 0.910572 -0.043253 -0.411081 181.732 0.033288 0.998954 -0.031373 -0.000018 0.412008 0.014883 0.911059 -0.000002 0 0 0 1 0.905984 -0.064725 -0.418335 181.732 0.041757 0.997086 -0.063838 -0.000049 0.421248 0.040368 0.906047 -0.000002 0 0 0 1 0.901426 -0.07438 -0.426496 181.732 0.04282 0.995618 -0.083132 -0.000066 0.430811 0.056675 0.900661 -0.000002 0 0 0 1 0.896092 -0.069219 -0.438439 181.732 0.034791 0.99568 -0.086087 0.000000 0.442503 0.061888 0.894629 -0.000002 0 0 0 1 0.888937 -0.051852 -0.455086 181.732 0.019026 0.996894 -0.076421 0.000011 0.457635 0.059275 0.887162 -0.000002 0 0 0 1 0.879958 -0.02589 -0.474345 181.732 -0.002242 0.998277 -0.058644 0.000047 0.475046 0.052668 0.878383 -0.000002 0 0 0 1 0.869454 0.004383 -0.493993 181.732 -0.026346 0.998949 -0.037507 0.000021 0.49331 0.045625 0.868656 -0.000002 0 0 0 1 0.857943 0.035032 -0.51255 181.732 -0.050768 0.99857 -0.016727 0.000042 0.511231 0.040372 0.858495 -0.000002 0 0 0 1 0.846251 0.062838 -0.529065 181.732 -0.073191 0.997317 0.001381 0.000047 0.527732 0.037554 0.84858 -0.000002 0 0 0 1 0.835983 0.084401 -0.542226 181.732 -0.090769 0.995758 0.015051 0.000014 0.541196 0.036634 0.840098 -0.000002 0 0 0 1 0.835817 0.081326 -0.542951 181.732 -0.085299 0.996194 0.017906 0.000034 0.542341 0.031347 0.839573 -0.000002 0 0 0 1 0.849005 0.051306 -0.525887 181.732 -0.053515 0.998506 0.011019 0.000027 0.525667 0.018787 0.850483 -0.000002 0 0 0 1 0.868391 0.016257 -0.495613 181.732 -0.016196 0.999859 0.004417 -0.000014 0.495616 0.004191 0.868532 -0.000002 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.350776 0.631512 0.691483 7.49618 0.635478 -0.702886 0.319561 0.138573 0.68784 0.327328 -0.647867 42.5129 0 0 0 1 0.29888 0.565265 0.76886 4.95064 0.562294 -0.755285 0.336704 -0.664562 0.771036 0.331692 -0.543585 42.8762 0 0 0 1 0.232133 0.487629 0.841624 2.16323 0.487141 -0.807209 0.333328 -1.36949 0.841908 0.332613 -0.424924 43.0879 0 0 0 1 0.151483 0.403821 0.902209 -0.749328 0.417424 -0.853496 0.311931 -1.87507 0.895997 0.329351 -0.297855 43.1149 0 0 0 1 0.05779 0.322011 0.944971 -3.59665 0.357109 -0.89059 0.281641 -2.12756 0.932274 0.321181 -0.16646 42.9586 0 0 0 1 -0.045828 0.252768 0.966441 -6.13415 0.307084 -0.917047 0.254411 -2.14363 0.950579 0.308437 -0.035595 42.6693 0 0 0 1 -0.153918 0.203613 0.966877 -8.23144 0.265472 -0.934036 0.238958 -1.99626 0.951753 0.293459 0.089711 42.3225 0 0 0 1 -0.258805 0.183356 0.948367 -9.718 0.227766 -0.942549 0.244388 -1.78241 0.938692 0.279254 0.202173 42.0165 0 0 0 1 -0.352564 0.197505 0.914708 -10.5016 0.187518 -0.942737 0.275834 -1.58818 0.916807 0.268773 0.295339 41.836 0 0 0 1 -0.433469 0.24039 0.868514 -10.7329 0.137974 -0.934698 0.32757 -1.43108 0.890543 0.261824 0.371996 41.7835 0 0 0 1 -0.498386 0.303335 0.812157 -10.5497 0.076946 -0.917618 0.389943 -1.2847 0.863533 0.256835 0.433987 41.8354 0 0 0 1 -0.544703 0.375871 0.749679 -10.1032 0.00737 -0.891754 0.45246 -1.1142 0.838597 0.251982 0.482971 41.9509 0 0 0 1 -0.57385 0.450431 0.683965 -9.53505 -0.067582 -0.85836 0.508578 -0.892556 0.816167 0.245623 0.523011 42.0897 0 0 0 1 -0.58843 0.519017 0.619977 -8.99088 -0.142125 -0.821234 0.552608 -0.623958 0.795959 0.237056 0.557004 42.2151 0 0 0 1 -0.5937 0.573844 0.564113 -8.62218 -0.209015 -0.786946 0.580542 -0.347614 0.777067 0.226759 0.587152 42.296 0 0 0 1 -0.572789 0.597854 0.560788 -7.49615 -0.23749 -0.775831 0.584538 0.150478 0.784545 0.201635 0.586372 42.5129 0 0 0 1 -0.522607 0.564258 0.639135 -5.10719 -0.204392 -0.810712 0.548607 0.924446 0.827711 0.156072 0.539013 42.8583 0 0 0 1 -0.450308 0.51508 0.729325 -2.4653 -0.155309 -0.849563 0.504105 1.61716 0.879262 0.113732 0.462561 43.0731 0 0 0 1 -0.36232 0.454612 0.813666 0.337539 -0.104552 -0.887296 0.449194 2.12861 0.926171 0.077681 0.369016 43.1218 0 0 0 1 -0.262946 0.389665 0.882621 3.13887 -0.064429 -0.919863 0.386912 2.39817 0.962657 0.04487 0.266981 42.9954 0 0 0 1 -0.15481 0.328322 0.931793 5.71695 -0.039668 -0.944469 0.326197 2.43031 0.987148 0.013536 0.159237 42.7274 0 0 0 1 -0.042774 0.278296 0.959542 7.97348 -0.026457 -0.9604 0.277365 2.28833 0.998734 -0.013522 0.048443 42.3718 0 0 0 1 0.064504 0.249668 0.966181 9.71975 -0.019222 -0.967706 0.251345 2.07157 0.997732 -0.034786 -0.057622 42.0162 0 0 0 1 0.158952 0.260831 0.952209 10.747 -0.006674 -0.964165 0.26522 1.88295 0.987264 -0.048513 -0.151515 41.7734 0 0 0 1 0.237074 0.312951 0.919705 11.0941 0.024048 -0.948294 0.31648 1.75819 0.971194 -0.052912 -0.232342 41.6876 0 0 0 1 0.298309 0.391753 0.870368 10.9804 0.09523 -0.919553 0.381252 1.65348 0.949707 -0.030844 -0.311619 41.7216 0 0 0 1 0.338079 0.475516 0.812149 10.6382 0.204658 -0.879458 0.429731 1.51682 0.918595 0.02093 -0.394645 41.8149 0 0 0 1 0.360431 0.543536 0.758062 10.2901 0.329183 -0.834516 0.441839 1.32798 0.872771 0.090289 -0.479708 41.9077 0 0 0 1 0.36514 0.600682 0.711234 9.86259 0.445408 -0.783592 0.433125 1.09705 0.817486 0.158638 -0.553668 42.0162 0 0 0 1 0.362435 0.640733 0.676833 9.0046 0.572234 -0.726194 0.381038 0.729946 0.735655 0.249206 -0.629847 42.2151 0 0 0 1 0.350776 0.631512 0.691483 7.49619 0.635478 -0.702886 0.31956 0.13867 0.68784 0.327328 -0.647867 42.5129 0 0 0 1 0.307635 0.581906 0.752825 5.25926 0.591738 -0.736586 0.327546 -0.634727 0.745122 0.344711 -0.570935 42.84 0 0 0 1 0.233466 0.513873 0.825487 2.56416 0.505414 -0.789388 0.348458 -1.39701 0.830693 0.335859 -0.444014 43.0649 0 0 0 1 0.144706 0.431097 0.890626 -0.41471 0.420181 -0.841685 0.339138 -1.97166 0.895828 0.325149 -0.302936 43.1148 0 0 0 1 0.052814 0.342254 0.938122 -3.41752 0.357301 -0.883718 0.30229 -2.25006 0.932495 0.319227 -0.168961 42.9665 0 0 0 1 -0.049473 0.263242 0.96346 -6.11296 0.306044 -0.914244 0.26551 -2.23605 0.950731 0.307996 -0.035333 42.6673 0 0 0 1 -0.156207 0.205811 0.966044 -8.2932 0.26481 -0.933518 0.241701 -2.02972 0.951564 0.293573 0.091322 42.3087 0 0 0 1 -0.2588 0.183358 0.948368 -9.71781 0.22777 -0.942547 0.244389 -1.78234 0.938693 0.279258 0.202167 42.0166 0 0 0 1 -0.352962 0.200446 0.913914 -10.4884 0.187039 -0.94195 0.278831 -1.59286 0.916752 0.269355 0.294981 41.8391 0 0 0 1 -0.43912 0.247324 0.863715 -10.9101 0.13538 -0.93217 0.335755 -1.45446 0.88817 0.264366 0.375852 41.7367 0 0 0 1 -0.509063 0.313226 0.801713 -10.9974 0.071714 -0.912761 0.402149 -1.34748 0.857736 0.262214 0.44219 41.7176 0 0 0 1 -0.558752 0.387616 0.733178 -10.7818 -0.001075 -0.884393 0.466742 -1.22642 0.829334 0.260005 0.494572 41.7781 0 0 0 1 -0.587638 0.4621 0.664188 -10.2885 -0.078137 -0.849446 0.521858 -1.0386 0.805342 0.254766 0.535275 41.908 0 0 0 1 -0.597334 0.526567 0.604912 -9.55694 -0.150035 -0.814316 0.560695 -0.749376 0.787834 0.244164 0.565423 42.088 0 0 0 1 -0.5937 0.573843 0.564113 -8.62225 -0.209015 -0.786946 0.580542 -0.347674 0.777067 0.226759 0.587152 42.296 0 0 0 1 -0.572789 0.597854 0.560788 -7.49618 -0.23749 -0.775831 0.584538 0.150597 0.784545 0.201635 0.586372 42.5129 0 0 0 1 -0.528953 0.594663 0.605462 -5.93396 -0.225191 -0.786216 0.575459 0.756373 0.818229 0.168046 0.549784 42.7544 0 0 0 1 -0.464211 0.567605 0.67995 -3.81071 -0.186142 -0.813051 0.551633 1.40585 0.865944 0.129506 0.483084 42.9816 0 0 0 1 -0.383295 0.519911 0.763399 -1.23775 -0.136484 -0.849332 0.509908 1.96702 0.913486 0.091253 0.396504 43.1124 0 0 0 1 -0.28722 0.456488 0.842095 1.61694 -0.090846 -0.888156 0.450472 2.3262 0.953547 0.052884 0.296567 43.0835 0 0 0 1 -0.176661 0.384529 0.906051 4.50177 -0.05684 -0.922979 0.380631 2.43019 0.982629 0.015743 0.18491 42.8725 0 0 0 1 -0.056857 0.311736 0.948466 7.26783 -0.034283 -0.950052 0.310203 2.31174 0.997794 -0.014879 0.064704 42.4973 0 0 0 1 0.064533 0.249667 0.966179 9.72102 -0.019231 -0.967706 0.251346 2.07157 0.99773 -0.034801 -0.057648 42.016 0 0 0 1 0.15302 0.264719 0.952107 10.4884 -0.007048 -0.963137 0.268919 1.8821 0.988198 -0.04786 -0.145513 41.8391 0 0 0 1 0.218205 0.324956 0.920212 10.2586 0.023459 -0.944408 0.327937 1.72934 0.975621 -0.049969 -0.213698 41.9021 0 0 0 1 0.278385 0.400365 0.873046 10.1292 0.09415 -0.915976 0.39003 1.58771 0.955843 -0.02638 -0.292688 41.9387 0 0 0 1 0.322892 0.480848 0.815185 9.99911 0.203665 -0.876443 0.436311 1.4412 0.924262 0.025144 -0.380929 41.9747 0 0 0 1 0.345253 0.55399 0.757559 9.76621 0.329718 -0.827338 0.45475 1.258 0.878684 0.092778 -0.468302 42.0347 0 0 0 1 0.350151 0.607369 0.713089 9.33727 0.445453 -0.777662 0.443637 1.00253 0.823994 0.162308 -0.542853 42.1381 0 0 0 1 0.358516 0.634766 0.684499 8.61866 0.569588 -0.72968 0.378334 0.637725 0.739619 0.254244 -0.623157 42.2967 0 0 0 1 0.350776 0.631512 0.691483 7.49632 0.635478 -0.702886 0.31956 0.138609 0.68784 0.327328 -0.647867 42.5129 0 0 0 1 0.302965 0.602497 0.738384 5.77107 0.598588 -0.723196 0.344499 -0.529016 0.741556 0.337617 -0.57975 42.7759 0 0 0 1 0.23077 0.548158 0.803908 3.42967 0.514237 -0.770104 0.377491 -1.2645 0.826018 0.326285 -0.4596 43.0092 0 0 0 1 0.147257 0.472298 0.869051 0.645994 0.427793 -0.822611 0.374572 -1.87079 0.891801 0.316616 -0.323181 43.1166 0 0 0 1 0.060673 0.384071 0.921308 -2.30917 0.362976 -0.868306 0.338072 -2.20337 0.929821 0.313901 -0.192091 43.0429 0 0 0 1 -0.039696 0.297603 0.953864 -5.17245 0.308566 -0.904308 0.294983 -2.23527 0.950374 0.306039 -0.055932 42.7916 0 0 0 1 -0.148843 0.225775 0.962742 -7.72171 0.265023 -0.928862 0.258803 -2.04155 0.952685 0.293669 0.078419 42.4162 0 0 0 1 -0.258842 0.183274 0.948373 -9.72063 0.227768 -0.942566 0.244317 -1.78231 0.938681 0.279249 0.202231 42.0159 0 0 0 1 -0.359602 0.192621 0.913008 -10.852 0.187764 -0.94351 0.27301 -1.59268 0.914019 0.269605 0.30312 41.7463 0 0 0 1 -0.445988 0.248545 0.859837 -11.2056 0.134202 -0.93124 0.338794 -1.47682 0.88492 0.26649 0.381968 41.6574 0 0 0 1 -0.511837 0.322439 0.796276 -11.0791 0.068078 -0.908753 0.411744 -1.37548 0.85638 0.264956 0.443183 41.6951 0 0 0 1 -0.558752 0.387616 0.733178 -10.7818 -0.001075 -0.884393 0.466742 -1.22642 0.829334 0.260005 0.494572 41.7781 0 0 0 1 -0.590893 0.451641 0.66848 -10.4382 -0.073588 -0.855329 0.512833 -1.04751 0.803387 0.253837 0.538643 41.8708 0 0 0 1 -0.60364 0.522088 0.60253 -9.87106 -0.149781 -0.816562 0.557488 -0.809042 0.783061 0.246274 0.571108 42.0141 0 0 0 1 -0.598508 0.576678 0.556085 -8.94921 -0.213019 -0.783707 0.58346 -0.426473 0.772276 0.230749 0.591899 42.227 0 0 0 1 -0.572789 0.597854 0.560788 -7.49618 -0.23749 -0.775831 0.584538 0.150597 0.784545 0.201635 0.586372 42.5129 0 0 0 1 -0.523101 0.580785 0.623743 -5.37691 -0.213908 -0.797903 0.563556 0.906382 0.82499 0.161372 0.541618 42.8258 0 0 0 1 -0.450126 0.537365 0.713179 -2.70994 -0.164655 -0.834917 0.525169 1.68719 0.877653 0.118964 0.464298 43.0559 0 0 0 1 -0.359725 0.473835 0.80379 0.291923 -0.109151 -0.876913 0.468091 2.28489 0.926652 0.080649 0.367168 43.1149 0 0 0 1 -0.257661 0.400891 0.879145 3.31228 -0.064541 -0.914976 0.398314 2.5707 0.964078 0.045888 0.261628 42.973 0 0 0 1 -0.146846 0.329733 0.932584 6.05577 -0.037286 -0.943979 0.327891 2.55047 0.988456 0.013377 0.150914 42.6741 0 0 0 1 -0.036264 0.274014 0.961042 8.27682 -0.024911 -0.961623 0.27324 2.32828 0.999032 -0.014032 0.041697 42.3115 0 0 0 1 0.063877 0.249689 0.966217 9.71111 -0.019037 -0.967713 0.251334 2.07288 0.997776 -0.034448 -0.057061 42.018 0 0 0 1 0.15302 0.26472 0.952107 10.4884 -0.007048 -0.963137 0.26892 1.8821 0.988198 -0.047861 -0.145513 41.8391 0 0 0 1 0.2332 0.311562 0.921166 10.9102 0.024076 -0.948843 0.314828 1.74353 0.972131 -0.051238 -0.228771 41.7367 0 0 0 1 0.299281 0.382767 0.874025 10.9978 0.094374 -0.923393 0.372072 1.63659 0.949487 -0.028868 -0.312477 41.7176 0 0 0 1 0.343239 0.465435 0.815817 10.782 0.20342 -0.884807 0.41921 1.51563 0.916956 0.022064 -0.398379 41.7781 0 0 0 1 0.360362 0.543142 0.758378 10.2925 0.32842 -0.83482 0.441832 1.32933 0.873087 0.089847 -0.479216 41.9071 0 0 0 1 0.357977 0.601746 0.713971 9.55696 0.444759 -0.782215 0.436267 1.03858 0.821 0.161372 -0.547647 42.088 0 0 0 1 0.360295 0.632547 0.685618 8.62243 0.568933 -0.731463 0.375866 0.636798 0.739258 0.254648 -0.62342 42.296 0 0 0 1 0.350776 0.631512 0.691483 7.49623 0.635478 -0.702886 0.319561 0.138516 0.68784 0.327328 -0.647867 42.5129 0 0 0 1 0.304242 0.604078 0.736564 5.88022 0.599198 -0.722451 0.345001 -0.505618 0.740539 0.336384 -0.581762 42.7614 0 0 0 1 0.232976 0.550384 0.801748 3.58387 0.514982 -0.769172 0.378374 -1.23763 0.824934 0.324733 -0.462637 42.9975 0 0 0 1 0.149732 0.474475 0.867441 0.796123 0.428349 -0.821853 0.3756 -1.85249 0.891122 0.315328 -0.326298 43.1149 0 0 0 1 0.062701 0.385743 0.920473 -2.19613 0.363245 -0.867852 0.338947 -2.19612 0.929581 0.313105 -0.194536 43.0492 0 0 0 1 -0.038501 0.298546 0.953618 -5.10951 0.308622 -0.904117 0.295509 -2.23466 0.950405 0.305685 -0.057327 42.7992 0 0 0 1 -0.148475 0.226058 0.962732 -7.7029 0.265012 -0.928819 0.258966 -2.04218 0.952745 0.293586 0.077999 42.4195 0 0 0 1 -0.258191 0.183369 0.948532 -9.71085 0.228023 -0.942516 0.244274 -1.78369 0.938799 0.279356 0.201536 42.018 0 0 0 1 -0.359602 0.192621 0.913008 -10.852 0.187764 -0.94351 0.27301 -1.59268 0.914019 0.269605 0.30312 41.7463 0 0 0 1 -0.445989 0.248545 0.859837 -11.2056 0.134202 -0.93124 0.338795 -1.47682 0.88492 0.26649 0.381968 41.6574 0 0 0 1 -0.511838 0.322439 0.796276 -11.0791 0.068079 -0.908753 0.411744 -1.37553 0.85638 0.264957 0.443183 41.6951 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.917178 -0.198333 0.345613 175.071 -0.358196 -0.790364 0.497012 0.000071 0.174586 -0.579645 -0.795947 0.000007 0 0 0 1 0.857285 -0.258132 0.445455 175.071 -0.484094 -0.698688 0.526771 -0.000054 0.175258 -0.667235 -0.723935 -0.000053 0 0 0 1 0.795299 -0.283321 0.535936 175.071 -0.585284 -0.58917 0.557066 -0.000072 0.157929 -0.756709 -0.63439 -0.000063 0 0 0 1 0.740677 -0.27957 0.610933 175.071 -0.661028 -0.46587 0.588223 0.000041 0.120166 -0.839527 -0.529863 -0.000018 0 0 0 1 0.698331 -0.251652 0.670079 175.071 -0.712435 -0.334701 0.616774 -0.000054 0.069063 -0.9081 -0.413018 0.000074 0 0 0 1 0.669512 -0.203913 0.714263 175.071 -0.742616 -0.205196 0.637508 -0.000046 0.016568 -0.957243 -0.288811 0.000006 0 0 0 1 0.654418 -0.141907 0.742697 175.071 -0.755507 -0.082766 0.649892 0.000077 -0.030754 -0.986414 -0.161376 -0.000013 0 0 0 1 0.651011 -0.071663 0.755678 175.071 -0.756235 0.024709 0.653834 0.000029 -0.065528 -0.997123 -0.038108 0.00003 0 0 0 1 0.658656 0.004865 0.752429 175.071 -0.748206 0.110218 0.654247 -0.000008 -0.079748 -0.993896 0.076235 0.000021 0 0 0 1 0.673853 0.089015 0.733484 175.071 -0.735439 0.176302 0.654253 -0.00008 -0.071076 -0.980303 0.184267 0.000059 0 0 0 1 0.688649 0.176235 0.703352 175.071 -0.723778 0.225511 0.652143 -0.000078 -0.043684 -0.958169 0.282853 0.00003 0 0 0 1 0.696998 0.260318 0.668153 175.071 -0.717049 0.260785 0.6464 0.00002 -0.005975 -0.929637 0.368427 -0.000005 0 0 0 1 0.696846 0.337583 0.632806 175.071 -0.716474 0.287394 0.635665 -0.000051 0.032725 -0.896349 0.442139 0.000017 0 0 0 1 0.689566 0.402014 0.602398 175.071 -0.721581 0.310404 0.618845 0.000083 0.061797 -0.861414 0.50413 -0.000008 0 0 0 1 0.679611 0.446897 0.581731 175.071 -0.730116 0.33518 0.595471 -0.000008 0.07113 -0.82942 0.554079 0.000059 0 0 0 1 0.693223 0.424229 0.582642 175.071 -0.720637 0.395501 0.56944 -0.000071 0.011137 -0.814622 0.579885 -0.000011 0 0 0 1 0.710405 0.337213 0.617747 175.071 -0.694449 0.478412 0.537459 0.000001 -0.1143 -0.810808 0.574044 -0.000041 0 0 0 1 0.693654 0.242093 0.678406 175.071 -0.675657 0.545126 0.496312 0.000037 -0.249663 -0.802638 0.541701 -0.000029 0 0 0 1 0.650872 0.144118 0.745382 175.071 -0.6574 0.598067 0.458411 -0.000038 -0.379723 -0.788382 0.484009 0.000019 0 0 0 1 0.587169 0.041762 0.808386 175.071 -0.636308 0.641109 0.429059 -0.000041 -0.500344 -0.766313 0.403013 0.000046 0 0 0 1 0.49941 -0.044671 0.865213 175.071 -0.635413 0.659983 0.400842 -0.000013 -0.588932 -0.749952 0.301217 0.00004 0 0 0 1 0.398162 -0.10585 0.911187 175.071 -0.679083 0.63378 0.370365 0.000019 -0.616695 -0.766237 0.180466 -0.000031 0 0 0 1 0.307903 -0.150317 0.939467 175.071 -0.766717 0.545457 0.33856 0.000065 -0.563331 -0.824549 0.052697 0.000009 0 0 0 1 0.243745 -0.203274 0.948298 175.071 -0.865298 0.396014 0.307299 -0.000035 -0.438005 -0.895462 -0.079366 0.000047 0 0 0 1 0.217911 -0.281436 0.93451 175.071 -0.935837 0.2115 0.281916 -0.000069 -0.27699 -0.935982 -0.21729 -0.000051 0 0 0 1 0.266437 -0.379543 0.885979 175.071 -0.957628 0.000053 0.288006 -0.000077 -0.109358 -0.925174 -0.363447 0.000012 0 0 0 1 0.39889 -0.450108 0.79893 175.071 -0.915773 -0.240565 0.321696 -0.000001 0.047396 -0.85996 -0.508156 0.000064 0 0 0 1 0.575875 -0.446658 0.684736 175.071 -0.8006 -0.477714 0.361704 -0.000085 0.16555 -0.756496 -0.632698 0.000093 0 0 0 1 0.733773 -0.372797 0.567978 175.071 -0.641241 -0.65624 0.397694 -0.000033 0.224471 -0.656028 -0.720583 -0.000009 0 0 0 1 0.863107 -0.268164 0.427943 175.071 -0.46119 -0.763827 0.451521 0.000088 0.205793 -0.587074 -0.782939 0.000026 0 0 0 1 0.917179 -0.198331 0.345613 175.071 -0.358194 -0.790365 0.497012 -0.000052 0.174587 -0.579645 -0.795947 -0.000017 0 0 0 1 0.88148 -0.240524 0.406376 175.071 -0.436404 -0.743684 0.506445 0.000086 0.180403 -0.623765 -0.760508 -0.000007 0 0 0 1 0.8021 -0.296836 0.518193 175.071 -0.569831 -0.640055 0.515386 0.000047 0.178687 -0.708673 -0.682534 0.000022 0 0 0 1 0.72683 -0.306837 0.614467 175.071 -0.671493 -0.505404 0.541908 -0.000007 0.144276 -0.806485 -0.573382 0.000004 0 0 0 1 0.6834 -0.274705 0.676389 175.071 -0.724925 -0.364892 0.584241 -0.000006 0.086315 -0.889601 -0.448508 -0.000028 0 0 0 1 0.659086 -0.217441 0.719948 175.071 -0.751665 -0.221766 0.621144 -0.000015 0.024598 -0.950547 -0.309605 0.000009 0 0 0 1 0.651354 -0.145455 0.744702 175.071 -0.758213 -0.08703 0.646172 0.000022 -0.029177 -0.98553 -0.166973 0.000108 0 0 0 1 0.652208 -0.070412 0.754762 175.071 -0.755197 0.025799 0.654991 -0.000092 -0.065591 -0.997184 -0.036348 -0.000019 0 0 0 1 0.660079 0.006376 0.751169 175.071 -0.746967 0.111534 0.655439 0.00004 -0.079602 -0.99374 0.078383 0.000021 0 0 0 1 0.675436 0.091155 0.731763 175.071 -0.734032 0.178096 0.655346 0.000003 -0.070584 -0.979782 0.187203 0.000118 0 0 0 1 0.689992 0.177724 0.701658 175.071 -0.722529 0.226894 0.653047 -0.000078 -0.04314 -0.957566 0.284966 0.000105 0 0 0 1 0.698041 0.261523 0.666591 175.071 -0.716037 0.261952 0.647049 -0.000033 -0.005396 -0.928971 0.370113 -0.000027 0 0 0 1 0.697507 0.338825 0.631411 175.071 -0.715799 0.288372 0.635982 0.000016 0.033405 -0.895566 0.443673 0.000056 0 0 0 1 0.689867 0.402398 0.601796 175.071 -0.721271 0.310798 0.619008 0.000038 0.06205 -0.861092 0.504648 -0.000009 0 0 0 1 0.679611 0.446898 0.581731 175.071 -0.730116 0.335179 0.595471 -0.00004 0.07113 -0.82942 0.554078 0.00002 0 0 0 1 0.693064 0.424017 0.582985 175.071 -0.720792 0.395293 0.569387 -0.000113 0.010979 -0.814833 0.579592 0.000012 0 0 0 1 0.710245 0.337003 0.618046 175.071 -0.694588 0.478231 0.53744 -0.000004 -0.114449 -0.811002 0.57374 -0.000019 0 0 0 1 0.693586 0.242004 0.678508 175.071 -0.675707 0.545061 0.496315 0.000111 -0.249718 -0.802709 0.541571 -0.000056 0 0 0 1 0.650873 0.144118 0.745382 175.071 -0.6574 0.598067 0.458411 -0.000108 -0.379723 -0.788382 0.484009 0.000014 0 0 0 1 0.58717 0.041762 0.808386 175.071 -0.636308 0.641108 0.429061 0.000002 -0.500344 -0.766313 0.403013 0.000082 0 0 0 1 0.49941 -0.044672 0.865213 175.071 -0.635412 0.659983 0.400842 -0.00007 -0.588932 -0.749951 0.301217 0.000032 0 0 0 1 0.398765 -0.10551 0.910963 175.071 -0.678726 0.634057 0.370544 -0.000032 -0.616699 -0.766054 0.181228 -0.000031 0 0 0 1 0.307902 -0.150318 0.939468 175.071 -0.766718 0.545454 0.33856 0.000099 -0.563329 -0.824551 0.052695 -0.000099 0 0 0 1 0.243745 -0.203274 0.948297 175.071 -0.865297 0.396015 0.3073 -0.000018 -0.438006 -0.895462 -0.079365 -0.00005 0 0 0 1 0.21798 -0.282043 0.934311 175.071 -0.936126 0.210268 0.281878 -0.000035 -0.275957 -0.936076 -0.218193 0.000098 0 0 0 1 0.266435 -0.379541 0.88598 175.071 -0.957629 0.000057 0.288007 -0.000068 -0.109361 -0.925175 -0.363445 -0.00003 0 0 0 1 0.398891 -0.450108 0.79893 175.071 -0.915773 -0.240566 0.321697 -0.000016 0.047397 -0.85996 -0.508156 -0.000079 0 0 0 1 0.575875 -0.446658 0.684737 175.071 -0.8006 -0.477714 0.361704 -0.000051 0.165551 -0.756496 -0.632698 0.000031 0 0 0 1 0.733774 -0.372797 0.567978 175.071 -0.64124 -0.656241 0.397692 0.000018 0.224472 -0.656027 -0.720584 -0.000002 0 0 0 1 0.863107 -0.268164 0.427943 175.071 -0.46119 -0.763828 0.451521 -0.00002 0.205793 -0.587074 -0.782939 0.000004 0 0 0 1 0.917178 -0.198331 0.345613 175.071 -0.358194 -0.790365 0.497012 0.000034 0.174588 -0.579645 -0.795947 0.000000 0 0 0 1 0.881815 -0.240174 0.405855 175.071 -0.435725 -0.744146 0.506349 0.000043 0.180403 -0.623348 -0.76085 0.000055 0 0 0 1 0.802099 -0.296837 0.518194 175.071 -0.569832 -0.640054 0.515386 -0.000007 0.178687 -0.708674 -0.682534 -0.000004 0 0 0 1 0.726447 -0.306746 0.614965 175.071 -0.671969 -0.504548 0.542116 -0.000001 0.143987 -0.807056 -0.572651 0.00003 0 0 0 1 0.683399 -0.274706 0.676389 175.071 -0.724924 -0.364895 0.584241 0.000025 0.086316 -0.8896 -0.44851 0.000003 0 0 0 1 0.659086 -0.217441 0.719948 175.071 -0.751665 -0.221765 0.621144 -0.000092 0.024598 -0.950547 -0.309605 -0.000023 0 0 0 1 0.651353 -0.145454 0.744703 175.071 -0.758213 -0.08703 0.646172 0.000002 -0.029177 -0.98553 -0.166973 -0.000043 0 0 0 1 0.652208 -0.070411 0.754763 175.071 -0.755196 0.025799 0.654991 -0.000053 -0.065591 -0.997184 -0.036347 -0.00008 0 0 0 1 0.660079 0.006376 0.751169 175.071 -0.746967 0.111534 0.655439 0.000047 -0.079602 -0.99374 0.078383 0.00002 0 0 0 1 0.675436 0.091154 0.731762 175.071 -0.734032 0.178097 0.655346 -0.000069 -0.070585 -0.979782 0.187203 0.000006 0 0 0 1 0.689992 0.177724 0.701658 175.071 -0.72253 0.226895 0.653046 -0.000124 -0.043141 -0.957566 0.284966 0.000028 0 0 0 1 0.698041 0.261523 0.666591 175.071 -0.716037 0.261953 0.647049 -0.000143 -0.005396 -0.928971 0.370114 -0.000065 0 0 0 1 0.697516 0.338394 0.631634 175.071 -0.7158 0.28821 0.636054 0.00005 0.033193 -0.895782 0.443253 0.000042 0 0 0 1 0.689867 0.402398 0.601796 175.071 -0.721272 0.310799 0.619008 -0.00004 0.06205 -0.861091 0.504649 -0.000013 0 0 0 1 0.679611 0.446897 0.581731 175.071 -0.730116 0.335179 0.595471 0.000009 0.07113 -0.82942 0.554078 0.000007 0 0 0 1 0.693064 0.424017 0.582985 175.071 -0.720792 0.395294 0.569387 -0.00004 0.01098 -0.814833 0.579592 -0.000029 0 0 0 1 0.71029 0.337524 0.61771 175.071 -0.694677 0.477778 0.537729 0.000017 -0.113632 -0.811052 0.573831 -0.000033 0 0 0 1 0.693586 0.242004 0.678508 175.071 -0.675707 0.545061 0.496315 0.000155 -0.249718 -0.802709 0.541571 -0.000027 0 0 0 1 0.650537 0.143491 0.745796 175.071 -0.657278 0.598363 0.4582 -0.000167 -0.380509 -0.788272 0.483571 0.00001 0 0 0 1 0.587171 0.041764 0.808385 175.071 -0.636308 0.641108 0.42906 -0.000083 -0.500342 -0.766314 0.403014 -0.000099 0 0 0 1 0.49941 -0.044671 0.865213 175.071 -0.635412 0.659983 0.400842 -0.000073 -0.588932 -0.749951 0.301217 -0.000000 0 0 0 1 0.398765 -0.10551 0.910963 175.071 -0.678726 0.634057 0.370544 0.000056 -0.616699 -0.766054 0.181228 -0.000047 0 0 0 1 0.308377 -0.150018 0.93936 175.071 -0.766125 0.54618 0.338733 0.000049 -0.563876 -0.824125 0.053496 -0.000107 0 0 0 1 0.243745 -0.203274 0.948297 175.071 -0.865297 0.396015 0.3073 -0.000000 -0.438006 -0.895462 -0.079365 0.000025 0 0 0 1 0.21798 -0.282043 0.934311 175.071 -0.936126 0.210268 0.281878 -0.000027 -0.275957 -0.936076 -0.218193 0.000008 0 0 0 1 0.266435 -0.379541 0.88598 175.071 -0.957629 0.000057 0.288007 -0.000079 -0.109361 -0.925175 -0.363445 0.00002 0 0 0 1 0.398891 -0.450109 0.79893 175.071 -0.915773 -0.240565 0.321697 0.000019 0.047396 -0.85996 -0.508156 -0.00002 0 0 0 1 0.574823 -0.446925 0.685446 175.071 -0.80147 -0.476414 0.361491 -0.000109 0.164997 -0.757158 -0.632051 0.000067 0 0 0 1 0.733776 -0.372795 0.567975 175.071 -0.641237 -0.656242 0.397694 -0.000003 0.224471 -0.656026 -0.720585 -0.000013 0 0 0 1 0.863107 -0.268163 0.427943 175.071 -0.46119 -0.763828 0.451521 -0.000006 0.205793 -0.587074 -0.782939 0.000015 0 0 0 1 0.917179 -0.198331 0.345613 175.071 -0.358194 -0.790365 0.497012 0.000056 0.174588 -0.579645 -0.795947 0.000049 0 0 0 1 0.881815 -0.240174 0.405854 175.071 -0.435725 -0.744146 0.506349 -0.000067 0.180403 -0.623348 -0.76085 -0.000009 0 0 0 1 0.802099 -0.296837 0.518194 175.071 -0.569831 -0.640055 0.515386 0.00001 0.178687 -0.708673 -0.682534 0.000037 0 0 0 1 0.726447 -0.306746 0.614965 175.071 -0.671969 -0.504548 0.542116 -0.000091 0.143987 -0.807056 -0.572651 0.000017 0 0 0 1 0.683399 -0.274707 0.676388 175.071 -0.724924 -0.364894 0.584242 -0.000099 0.086314 -0.8896 -0.44851 -0.000088 0 0 0 1 0.659086 -0.217441 0.719948 175.071 -0.751665 -0.221766 0.621144 -0.000059 0.024598 -0.950547 -0.309605 0.000028 0 0 0 1 0.651353 -0.145455 0.744702 175.071 -0.758213 -0.087028 0.646172 0.000034 -0.029179 -0.98553 -0.166973 0.000018 0 0 0 1 0.652182 -0.07089 0.754741 175.071 -0.755233 0.025179 0.654973 -0.000041 -0.065434 -0.997166 -0.037117 -0.000032 0 0 0 1 0.660079 0.006374 0.751169 175.071 -0.746967 0.111535 0.655439 -0.000017 -0.079603 -0.99374 0.078384 -0.00005 0 0 0 1 0.675436 0.091155 0.731763 175.071 -0.734032 0.178096 0.655346 -0.000055 -0.070584 -0.979782 0.187203 -0.000024 0 0 0 1 0.689993 0.177723 0.701658 175.071 -0.722529 0.226895 0.653046 -0.000173 -0.043141 -0.957566 0.284966 0.00006 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.472321 0.881426 0 370.017 -0.881427 0.472321 0 0.00002 0 0 1 0.000000 0 0 0 1 0.31911 0.947718 0 370.017 -0.947718 0.31911 0 0.000064 0 0 1 0.000000 0 0 0 1 0.188328 0.982106 0 370.017 -0.982106 0.188328 0 0.000012 0 0 1 0.000000 0 0 0 1 0.074413 0.997227 0 370.018 -0.997227 0.074413 0 -0.000006 0 0 1 0.000000 0 0 0 1 -0.021681 0.999765 0 370.018 -0.999765 -0.021681 0 0.000055 0 0 1 0.000000 0 0 0 1 -0.0937 0.9956 0 370.018 -0.9956 -0.0937 0 0.000126 0 0 1 0.000000 0 0 0 1 -0.140994 0.99001 0 370.018 -0.99001 -0.140994 0 -0.000026 0 0 1 0.000000 0 0 0 1 -0.163086 0.986612 0 370.018 -0.986612 -0.163086 0 -0.000000 0 0 1 0.000000 0 0 0 1 -0.163842 0.986487 0 370.017 -0.986487 -0.163842 0 0.000017 0 0 1 0.000000 0 0 0 1 -0.14538 0.989376 0 370.017 -0.989376 -0.14538 0 0.000109 0 0 1 0.000000 0 0 0 1 -0.109253 0.994013 0 370.018 -0.994013 -0.109253 0 0.000002 0 0 1 0.000000 0 0 0 1 -0.059656 0.998219 0 370.018 -0.998219 -0.059656 0 0.000079 0 0 1 0.000000 0 0 0 1 -0.000796 1 0 370.017 -1 -0.000795 0 0.000076 0 0 1 0.000000 0 0 0 1 0.061211 0.998125 0 370.017 -0.998125 0.061211 0 0.000013 0 0 1 0.000000 0 0 0 1 0.118702 0.99293 0 370.017 -0.99293 0.118702 0 0.000104 0 0 1 0.000000 0 0 0 1 0.112618 0.993638 0 370.017 -0.993638 0.112618 0 0.000028 0 0 1 0.000000 0 0 0 1 0.078147 0.996941 0 370.018 -0.996941 0.078147 0 0.000049 0 0 1 0.000000 0 0 0 1 0.077721 0.996975 0 370.018 -0.996975 0.077721 0 0.000051 0 0 1 0.000000 0 0 0 1 0.034534 0.999404 0 370.018 -0.999403 0.034534 0 0.00011 0 0 1 0.000000 0 0 0 1 -0.099232 0.995064 0 370.017 -0.995064 -0.099232 0 0.000031 0 0 1 0.000000 0 0 0 1 -0.243679 0.969856 0 370.018 -0.969856 -0.243679 0 0.000085 0 0 1 0.000000 0 0 0 1 -0.347392 0.93772 0 370.017 -0.93772 -0.347392 0 0.000003 0 0 1 0.000000 0 0 0 1 -0.386367 0.922345 0 370.018 -0.922345 -0.386367 0 -0.000005 0 0 1 0.000000 0 0 0 1 -0.367516 0.930017 0 370.018 -0.930017 -0.367516 0 0.000066 0 0 1 0.000000 0 0 0 1 -0.317089 0.948396 0 370.017 -0.948396 -0.317089 0 -0.000117 0 0 1 0.000000 0 0 0 1 -0.278351 0.96048 0 370.017 -0.96048 -0.278351 0 0.000000 0 0 1 0.000000 0 0 0 1 -0.23207 0.972699 0 370.017 -0.972699 -0.23207 0 0.000029 0 0 1 0.000000 0 0 0 1 -0.132309 0.991208 0 370.017 -0.991208 -0.132309 0 0.00003 0 0 1 0.000000 0 0 0 1 0.03208 0.999485 0 370.017 -0.999485 0.03208 0 0.000108 0 0 1 0.000000 0 0 0 1 0.290971 0.956732 0 370.017 -0.956732 0.290971 0 0.000101 0 0 1 0.000000 0 0 0 1 0.472324 0.881425 0 370.017 -0.881425 0.472324 0 0.000056 0 0 1 0.000000 0 0 0 1 0.386845 0.922145 0 370.017 -0.922145 0.386845 0 0.00008 0 0 1 0.000000 0 0 0 1 0.218078 0.975931 0 370.017 -0.975931 0.218078 0 -0.000124 0 0 1 0.000000 0 0 0 1 0.075253 0.997164 0 370.018 -0.997164 0.075253 0 0.000099 0 0 1 0.000000 0 0 0 1 -0.021595 0.999767 0 370.017 -0.999767 -0.021595 0 0.000000 0 0 1 0.000000 0 0 0 1 -0.094689 0.995507 0 370.017 -0.995507 -0.094689 0 -0.000008 0 0 1 0.000000 0 0 0 1 -0.141787 0.989897 0 370.017 -0.989897 -0.141787 0 -0.000105 0 0 1 0.000000 0 0 0 1 -0.163085 0.986612 0 370.017 -0.986612 -0.163085 0 0.000023 0 0 1 0.000000 0 0 0 1 -0.163841 0.986487 0 370.017 -0.986487 -0.163841 0 -0.000002 0 0 1 0.000000 0 0 0 1 -0.145209 0.989401 0 370.018 -0.989401 -0.145209 0 0.000046 0 0 1 0.000000 0 0 0 1 -0.109253 0.994014 0 370.017 -0.994014 -0.109252 0 0.000004 0 0 1 0.000000 0 0 0 1 -0.059655 0.998219 0 370.017 -0.998219 -0.059655 0 0.000082 0 0 1 0.000000 0 0 0 1 -0.000415 1 0 370.018 -1 -0.000415 0 0.000036 0 0 1 0.000000 0 0 0 1 0.061212 0.998125 0 370.017 -0.998125 0.061212 0 0.00004 0 0 1 0.000000 0 0 0 1 0.118703 0.99293 0 370.018 -0.99293 0.118703 0 0.000015 0 0 1 0.000000 0 0 0 1 0.112619 0.993638 0 370.017 -0.993638 0.112619 0 0.000042 0 0 1 0.000000 0 0 0 1 0.078148 0.996942 0 370.017 -0.996942 0.078148 0 0.000009 0 0 1 0.000000 0 0 0 1 0.077723 0.996975 0 370.017 -0.996975 0.077723 0 0.000034 0 0 1 0.000000 0 0 0 1 0.034535 0.999404 0 370.018 -0.999403 0.034535 0 0.000088 0 0 1 0.000000 0 0 0 1 -0.099231 0.995064 0 370.017 -0.995064 -0.099231 0 0.000099 0 0 1 0.000000 0 0 0 1 -0.243678 0.969856 0 370.017 -0.969856 -0.243678 0 0.000099 0 0 1 0.000000 0 0 0 1 -0.346949 0.937884 0 370.018 -0.937884 -0.346949 0 0.000017 0 0 1 0.000000 0 0 0 1 -0.386367 0.922345 0 370.018 -0.922345 -0.386367 0 -0.000034 0 0 1 0.000000 0 0 0 1 -0.367516 0.930017 0 370.018 -0.930017 -0.367516 0 -0.000048 0 0 1 0.000000 0 0 0 1 -0.31681 0.948489 0 370.018 -0.948489 -0.31681 0 -0.000011 0 0 1 0.000000 0 0 0 1 -0.278352 0.96048 0 370.018 -0.96048 -0.278352 0 0.000037 0 0 1 0.000000 0 0 0 1 -0.232069 0.972699 0 370.017 -0.972699 -0.232069 0 0.000024 0 0 1 0.000000 0 0 0 1 -0.132307 0.991208 0 370.018 -0.991208 -0.132307 0 -0.000066 0 0 1 0.000000 0 0 0 1 0.032082 0.999485 0 370.017 -0.999485 0.032082 0 0.000006 0 0 1 0.000000 0 0 0 1 0.290972 0.956731 0 370.017 -0.956732 0.290972 0 0.000085 0 0 1 0.000000 0 0 0 1 0.472323 0.881425 0 370.017 -0.881425 0.472323 0 0.000079 0 0 1 0.000000 0 0 0 1 0.387631 0.921815 0 370.017 -0.921815 0.387631 0 0.000131 0 0 1 0.000000 0 0 0 1 0.218076 0.975932 0 370.017 -0.975932 0.218076 0 0.000138 0 0 1 0.000000 0 0 0 1 0.0745 0.997221 0 370.017 -0.997221 0.0745 0 0.000088 0 0 1 0.000000 0 0 0 1 -0.021594 0.999767 0 370.017 -0.999767 -0.021594 0 0.000061 0 0 1 0.000000 0 0 0 1 -0.09469 0.995507 0 370.018 -0.995507 -0.09469 0 0.000005 0 0 1 0.000000 0 0 0 1 -0.141788 0.989897 0 370.018 -0.989897 -0.141788 0 0.000083 0 0 1 0.000000 0 0 0 1 -0.163086 0.986612 0 370.018 -0.986612 -0.163086 0 0.000085 0 0 1 0.000000 0 0 0 1 -0.163842 0.986487 0 370.017 -0.986487 -0.163842 0 -0.00005 0 0 1 0.000000 0 0 0 1 -0.145209 0.989401 0 370.017 -0.989401 -0.14521 0 -0.000000 0 0 1 0.000000 0 0 0 1 -0.109253 0.994014 0 370.017 -0.994014 -0.109253 0 0.000023 0 0 1 0.000000 0 0 0 1 -0.059657 0.998219 0 370.018 -0.998219 -0.059656 0 0.000017 0 0 1 0.000000 0 0 0 1 -0.000796 1 0 370.018 -1 -0.000796 0 0.000064 0 0 1 0.000000 0 0 0 1 0.061211 0.998125 0 370.017 -0.998125 0.061211 0 0.000013 0 0 1 0.000000 0 0 0 1 0.118701 0.99293 0 370.017 -0.99293 0.118701 0 0.000081 0 0 1 0.000000 0 0 0 1 0.112617 0.993638 0 370.018 -0.993638 0.112617 0 0.000024 0 0 1 0.000000 0 0 0 1 0.078154 0.996941 0 370.017 -0.996941 0.078154 0 0.000012 0 0 1 0.000000 0 0 0 1 0.077722 0.996975 0 370.018 -0.996975 0.077722 0 0.000061 0 0 1 0.000000 0 0 0 1 0.033978 0.999423 0 370.018 -0.999423 0.033978 0 0.000016 0 0 1 0.000000 0 0 0 1 -0.099229 0.995064 0 370.017 -0.995064 -0.099229 0 0.00002 0 0 1 0.000000 0 0 0 1 -0.243678 0.969856 0 370.017 -0.969856 -0.243678 0 0.000067 0 0 1 0.000000 0 0 0 1 -0.346949 0.937884 0 370.018 -0.937884 -0.346949 0 0.000001 0 0 1 0.000000 0 0 0 1 -0.386368 0.922345 0 370.018 -0.922345 -0.386368 0 -0.000003 0 0 1 0.000000 0 0 0 1 -0.367516 0.930017 0 370.018 -0.930017 -0.367516 0 0.000001 0 0 1 0.000000 0 0 0 1 -0.31681 0.948489 0 370.017 -0.948489 -0.31681 0 0.000028 0 0 1 0.000000 0 0 0 1 -0.278353 0.960478 0 370.018 -0.960478 -0.278353 0 0.000000 0 0 1 0.000000 0 0 0 1 -0.232071 0.972699 0 370.017 -0.972699 -0.232071 0 0.000022 0 0 1 0.000000 0 0 0 1 -0.133133 0.991098 0 370.017 -0.991098 -0.133133 0 0.000048 0 0 1 0.000000 0 0 0 1 0.032084 0.999485 0 370.017 -0.999485 0.032084 0 -0.000027 0 0 1 0.000000 0 0 0 1 0.290972 0.956732 0 370.017 -0.956731 0.290972 0 0.000025 0 0 1 0.000000 0 0 0 1 0.472325 0.881424 0 370.017 -0.881424 0.472325 0 0.000071 0 0 1 0.000000 0 0 0 1 0.387632 0.921814 0 370.018 -0.921814 0.387632 0 -0.000091 0 0 1 0.000000 0 0 0 1 0.218077 0.975932 0 370.017 -0.975932 0.218077 0 0.000014 0 0 1 0.000000 0 0 0 1 0.0745 0.997221 0 370.017 -0.997221 0.0745 0 0.000074 0 0 1 0.000000 0 0 0 1 -0.021595 0.999767 0 370.018 -0.999767 -0.021595 0 -0.000017 0 0 1 0.000000 0 0 0 1 -0.09469 0.995507 0 370.017 -0.995507 -0.09469 0 0.000019 0 0 1 0.000000 0 0 0 1 -0.141788 0.989897 0 370.017 -0.989897 -0.141788 0 -0.00002 0 0 1 0.000000 0 0 0 1 -0.163073 0.986614 0 370.017 -0.986614 -0.163073 0 -0.000074 0 0 1 0.000000 0 0 0 1 -0.163843 0.986486 0 370.018 -0.986486 -0.163843 0 0.000024 0 0 1 0.000000 0 0 0 1 -0.14521 0.989401 0 370.018 -0.989401 -0.14521 0 0.00006 0 0 1 0.000000 0 0 0 1 -0.109255 0.994013 0 370.017 -0.994013 -0.109255 0 0.000065 0 0 1 0.000000 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.85009 -0.525938 -0.027135 370.018 0.510042 0.809374 0.291155 -0.000058 -0.131167 -0.261348 0.956291 -0.000004 0 0 0 1 0.804873 -0.591158 -0.052076 370.017 0.576001 0.757079 0.308308 -0.000003 -0.142834 -0.278145 0.94986 -0.000004 0 0 0 1 0.767912 -0.636199 -0.074581 370.017 0.621747 0.712287 0.325696 -0.000006 -0.154084 -0.296477 0.942528 -0.000004 0 0 0 1 0.751181 -0.653094 -0.095894 370.017 0.64056 0.686132 0.344827 -0.000017 -0.159409 -0.320453 0.933755 -0.000004 0 0 0 1 0.760363 -0.639505 -0.113496 370.017 0.630529 0.684875 0.365212 -0.000000 -0.155824 -0.349256 0.92398 -0.000004 0 0 0 1 0.789234 -0.601663 -0.122927 370.017 0.596617 0.70384 0.385563 -0.000013 -0.145458 -0.37764 0.914456 -0.000004 0 0 0 1 0.832901 -0.539611 -0.122869 370.018 0.538349 0.73853 0.4059 0.000001 -0.128285 -0.404221 0.90562 -0.000004 0 0 0 1 0.883387 -0.454982 -0.112326 370.017 0.456561 0.78145 0.425309 0.000003 -0.105731 -0.426996 0.898051 -0.000004 0 0 0 1 0.929858 -0.355611 -0.09437 370.017 0.35891 0.820326 0.445252 -0.000001 -0.080923 -0.447891 0.890418 -0.000004 0 0 0 1 0.966508 -0.246528 -0.071313 370.017 0.250791 0.848336 0.466295 0.00004 -0.054456 -0.468563 0.88175 -0.000004 0 0 0 1 0.98983 -0.135471 -0.043414 370.018 0.139426 0.863269 0.485105 0.000084 -0.028238 -0.486225 0.873377 -0.000004 0 0 0 1 0.999372 -0.033279 -0.01219 370.018 0.034923 0.866019 0.498791 -0.000034 -0.006043 -0.498903 0.866637 -0.000004 0 0 0 1 0.998333 0.053575 0.021465 370.017 -0.057063 0.860586 0.506098 0.000027 0.008641 -0.506479 0.862209 -0.000004 0 0 0 1 0.991501 0.117527 0.055794 370.017 -0.129549 0.852541 0.506351 0.000006 0.011943 -0.509276 0.86052 -0.000004 0 0 0 1 0.984445 0.151862 0.088353 370.018 -0.175691 0.848105 0.49985 -0.000025 0.000975 -0.507597 0.861594 -0.000004 0 0 0 1 0.995145 0.0129 0.097568 370.017 -0.060822 0.860005 0.506649 0.000006 -0.077373 -0.510123 0.856614 -0.000004 0 0 0 1 0.952986 -0.292132 0.080477 370.017 0.210214 0.828664 0.518773 -0.000051 -0.21824 -0.477465 0.851116 -0.000004 0 0 0 1 0.835691 -0.545953 0.059623 370.017 0.444483 0.736117 0.510457 -0.000066 -0.322575 -0.400083 0.857834 -0.000004 0 0 0 1 0.754159 -0.655515 0.039288 370.018 0.555669 0.668883 0.493788 0.000005 -0.349964 -0.350564 0.868694 -0.000004 0 0 0 1 0.75986 -0.64986 0.017164 370.018 0.563286 0.671355 0.481655 -0.000039 -0.324532 -0.356322 0.876192 -0.000004 0 0 0 1 0.808086 -0.589064 -0.000893 370.018 0.521239 0.714334 0.466943 -0.000072 -0.274421 -0.377796 0.884287 -0.000004 0 0 0 1 0.873364 -0.486912 -0.012259 370.017 0.441297 0.78039 0.442999 -0.000009 -0.206134 -0.39231 0.896438 -0.000004 0 0 0 1 0.929889 -0.367436 -0.017245 370.018 0.34179 0.845756 0.409728 0.00002 -0.135963 -0.386895 0.912045 -0.000004 0 0 0 1 0.965102 -0.261458 -0.014748 370.018 0.248151 0.895088 0.370458 -0.000017 -0.083658 -0.36119 0.928732 -0.000004 0 0 0 1 0.97712 -0.212579 -0.006875 370.018 0.202736 0.921127 0.332301 0.000019 -0.064307 -0.326092 0.943148 -0.000004 0 0 0 1 0.950548 -0.310397 -0.010528 370.018 0.298087 0.902283 0.311496 0.00001 -0.087188 -0.299231 0.950189 -0.000004 0 0 0 1 0.860626 -0.508614 -0.025178 370.017 0.491202 0.816089 0.304499 0.000003 -0.134325 -0.274427 0.95218 -0.000004 0 0 0 1 0.73331 -0.678864 -0.037419 370.017 0.656632 0.692874 0.297926 -0.000003 -0.176324 -0.243044 0.953855 -0.000004 0 0 0 1 0.667068 -0.74403 -0.037949 370.017 0.720153 0.63094 0.288608 -0.000002 -0.19079 -0.219851 0.956695 -0.000004 0 0 0 1 0.758069 -0.651371 -0.03235 370.018 0.631517 0.720768 0.285797 -0.000001 -0.162843 -0.237083 0.957744 -0.000004 0 0 0 1 0.85009 -0.525937 -0.027135 370.017 0.510041 0.809375 0.291155 0.000027 -0.131166 -0.261348 0.956291 -0.000004 0 0 0 1 0.826675 -0.561336 -0.03888 370.017 0.546854 0.78523 0.290456 0.000013 -0.132513 -0.261376 0.956097 -0.000004 0 0 0 1 0.776009 -0.628167 -0.056716 370.017 0.614039 0.731878 0.295482 0.000001 -0.144103 -0.264122 0.953663 -0.000004 0 0 0 1 0.749662 -0.657373 -0.076609 370.018 0.644028 0.697942 0.313217 -0.000001 -0.152432 -0.284145 0.946587 -0.000004 0 0 0 1 0.759137 -0.643459 -0.098339 370.017 0.63299 0.694517 0.342008 0.000005 -0.151769 -0.32188 0.934538 -0.000004 0 0 0 1 0.788211 -0.604595 -0.11484 370.018 0.598283 0.709107 0.373127 -0.000000 -0.144157 -0.36281 0.920645 -0.000004 0 0 0 1 0.832569 -0.540437 -0.121479 370.017 0.538962 0.739739 0.402872 -0.00002 -0.127864 -0.400892 0.907159 -0.000004 0 0 0 1 0.883586 -0.454177 -0.114013 370.018 0.456426 0.780908 0.42645 0.000002 -0.10465 -0.428844 0.897297 -0.000004 0 0 0 1 0.930042 -0.354581 -0.09641 370.018 0.358786 0.819635 0.446622 0.000016 -0.079343 -0.449967 0.889514 -0.000004 0 0 0 1 0.966827 -0.244681 -0.073323 370.017 0.250012 0.847675 0.467913 0.000029 -0.052335 -0.470723 0.880728 -0.000004 0 0 0 1 0.989892 -0.134344 -0.045438 370.018 0.139383 0.862455 0.486564 0.00002 -0.026178 -0.487979 0.872463 -0.000004 0 0 0 1 0.999381 -0.032332 -0.01383 370.017 0.034915 0.865292 0.50005 0.000003 -0.004199 -0.500224 0.865886 -0.000004 0 0 0 1 0.998291 0.054693 0.02058 370.017 -0.057569 0.860003 0.507032 0.000008 0.010031 -0.507351 0.861682 -0.000004 0 0 0 1 0.991494 0.117838 0.055269 370.017 -0.129543 0.852264 0.506817 -0.000058 0.012618 -0.509666 0.86028 -0.000004 0 0 0 1 0.984445 0.151863 0.088354 370.017 -0.175692 0.848105 0.49985 -0.000003 0.000975 -0.507597 0.861594 -0.000004 0 0 0 1 0.99512 0.012732 0.097852 370.017 -0.060799 0.860164 0.506381 0.000021 -0.077722 -0.509859 0.85674 -0.000004 0 0 0 1 0.952917 -0.292283 0.080746 370.017 0.210275 0.828802 0.518529 0.000034 -0.21848 -0.477136 0.851239 -0.000004 0 0 0 1 0.835653 -0.546001 0.059728 370.017 0.444517 0.736162 0.510362 -0.000000 -0.322628 -0.399935 0.857883 -0.000004 0 0 0 1 0.754161 -0.655514 0.039288 370.017 0.555668 0.668885 0.493788 -0.000011 -0.349964 -0.350564 0.868694 -0.000004 0 0 0 1 0.759861 -0.649859 0.017164 370.018 0.563285 0.671355 0.481655 0.000057 -0.324531 -0.356322 0.876192 -0.000004 0 0 0 1 0.808087 -0.589062 -0.000893 370.018 0.521238 0.714336 0.466943 -0.00003 -0.27442 -0.377796 0.884287 -0.000004 0 0 0 1 0.872979 -0.487605 -0.012211 370.017 0.441857 0.779976 0.44317 0.000033 -0.206568 -0.392274 0.896354 -0.000004 0 0 0 1 0.92989 -0.367433 -0.017245 370.018 0.341788 0.845757 0.409726 -0.000027 -0.135961 -0.386895 0.912045 -0.000004 0 0 0 1 0.965103 -0.261457 -0.014748 370.017 0.24815 0.895088 0.370458 0.000077 -0.083658 -0.36119 0.928732 -0.000004 0 0 0 1 0.977119 -0.212586 -0.006831 370.017 0.202741 0.921194 0.332112 0.000044 -0.064308 -0.325898 0.943215 -0.000004 0 0 0 1 0.950549 -0.310395 -0.010527 370.017 0.298084 0.902283 0.311498 0.000001 -0.087188 -0.299232 0.950188 -0.000004 0 0 0 1 0.860626 -0.508614 -0.025177 370.017 0.491201 0.816089 0.304499 -0.000007 -0.134326 -0.274427 0.95218 -0.000004 0 0 0 1 0.73331 -0.678863 -0.037418 370.017 0.656632 0.692874 0.297927 0.000003 -0.176325 -0.243044 0.953855 -0.000004 0 0 0 1 0.667068 -0.74403 -0.037948 370.017 0.720152 0.63094 0.28861 -0.000006 -0.190791 -0.219851 0.956694 -0.000004 0 0 0 1 0.758069 -0.651371 -0.032348 370.018 0.631516 0.720769 0.285797 0 -0.162844 -0.237083 0.957744 -0.000004 0 0 0 1 0.85009 -0.525938 -0.027136 370.017 0.510042 0.809375 0.291154 -0.000035 -0.131166 -0.261348 0.956291 -0.000004 0 0 0 1 0.826899 -0.561012 -0.038781 370.018 0.546521 0.785461 0.290457 0.000007 -0.132488 -0.261374 0.956102 -0.000004 0 0 0 1 0.776009 -0.628167 -0.056715 370.018 0.61404 0.731878 0.295481 -0.000038 -0.144102 -0.264122 0.953664 -0.000004 0 0 0 1 0.749661 -0.657358 -0.076736 370.017 0.644029 0.697881 0.313351 0.000004 -0.152431 -0.284328 0.946532 -0.000004 0 0 0 1 0.759137 -0.643459 -0.098339 370.017 0.632991 0.694517 0.342007 0.000002 -0.151769 -0.321879 0.934538 -0.000004 0 0 0 1 0.788211 -0.604595 -0.114841 370.018 0.598283 0.709108 0.373127 0.00001 -0.144156 -0.36281 0.920645 -0.000004 0 0 0 1 0.832569 -0.540437 -0.12148 370.017 0.538963 0.739739 0.402871 0.000063 -0.127863 -0.400891 0.907159 -0.000004 0 0 0 1 0.883586 -0.454178 -0.114014 370.018 0.456426 0.780907 0.42645 0.000053 -0.104649 -0.428844 0.897296 -0.000004 0 0 0 1 0.930041 -0.354582 -0.09641 370.017 0.358787 0.819635 0.446621 0.000005 -0.079343 -0.449967 0.889514 -0.000004 0 0 0 1 0.966827 -0.244682 -0.073323 370.018 0.250012 0.847674 0.467912 -0.000009 -0.052335 -0.470722 0.880728 -0.000004 0 0 0 1 0.989892 -0.134344 -0.045439 370.018 0.139384 0.862455 0.486564 -0.000006 -0.026177 -0.487979 0.872463 -0.000004 0 0 0 1 0.999381 -0.032333 -0.013831 370.018 0.034916 0.865292 0.50005 -0.000065 -0.0042 -0.500224 0.865886 -0.000004 0 0 0 1 0.998321 0.054223 0.020359 370.017 -0.057053 0.86005 0.50701 0.000006 0.009981 -0.50732 0.8617 -0.000004 0 0 0 1 0.991494 0.117838 0.055268 370.017 -0.129542 0.852264 0.506818 -0.00001 0.012619 -0.509667 0.86028 -0.000004 0 0 0 1 0.984445 0.151861 0.088352 370.018 -0.17569 0.848105 0.49985 -0.000073 0.000975 -0.507598 0.861594 -0.000004 0 0 0 1 0.99512 0.012731 0.09785 370.017 -0.060796 0.860164 0.506382 -0.000042 -0.077721 -0.509859 0.85674 -0.000004 0 0 0 1 0.953444 -0.290518 0.080894 370.017 0.208674 0.829218 0.51851 0.000001 -0.217716 -0.477489 0.851237 -0.000004 0 0 0 1 0.835652 -0.546001 0.059727 370.017 0.444518 0.736162 0.510362 -0.000001 -0.322628 -0.399935 0.857883 -0.000004 0 0 0 1 0.754135 -0.655545 0.039263 370.018 0.555705 0.668854 0.493789 -0.000044 -0.349963 -0.350564 0.868695 -0.000004 0 0 0 1 0.759861 -0.649859 0.017165 370.017 0.563285 0.671355 0.481656 -0.000022 -0.324533 -0.356322 0.876192 -0.000004 0 0 0 1 0.808087 -0.589063 -0.000894 370.017 0.521238 0.714335 0.466943 0.000061 -0.27442 -0.377796 0.884287 -0.000004 0 0 0 1 0.872979 -0.487606 -0.012211 370.018 0.441857 0.779976 0.44317 -0.000078 -0.206568 -0.392274 0.896354 -0.000004 0 0 0 1 0.929608 -0.368146 -0.017239 370.018 0.342401 0.845402 0.409947 -0.000001 -0.136346 -0.386993 0.911946 -0.000004 0 0 0 1 0.965102 -0.261457 -0.014749 370.017 0.248151 0.895088 0.370458 -0.000026 -0.083658 -0.36119 0.928732 -0.000004 0 0 0 1 0.977119 -0.212587 -0.006832 370.017 0.202741 0.921194 0.332112 0.000036 -0.064308 -0.325897 0.943215 -0.000004 0 0 0 1 0.950549 -0.310396 -0.010528 370.017 0.298085 0.902283 0.311497 0.000000 -0.087187 -0.299231 0.950189 -0.000004 0 0 0 1 0.860626 -0.508615 -0.025178 370.018 0.491202 0.816089 0.304499 -0.000001 -0.134325 -0.274427 0.95218 -0.000004 0 0 0 1 0.73396 -0.678163 -0.037379 370.017 0.655953 0.693499 0.297968 -0.000003 -0.176148 -0.243215 0.953844 -0.000004 0 0 0 1 0.667067 -0.744031 -0.037949 370.017 0.720153 0.630939 0.28861 0.000007 -0.19079 -0.219851 0.956694 -0.000004 0 0 0 1 0.758069 -0.651371 -0.032348 370.017 0.631516 0.720769 0.285796 0.000004 -0.162843 -0.237083 0.957744 -0.000004 0 0 0 1 0.850091 -0.525936 -0.027134 370.017 0.51004 0.809375 0.291154 -0.000029 -0.131166 -0.261348 0.956291 -0.000004 0 0 0 1 0.826899 -0.561011 -0.03878 370.018 0.54652 0.785462 0.290458 -0.000034 -0.132489 -0.261374 0.956102 -0.000004 0 0 0 1 0.776009 -0.628167 -0.056716 370.017 0.614039 0.731879 0.295481 0.000006 -0.144102 -0.264122 0.953663 -0.000004 0 0 0 1 0.749662 -0.657357 -0.076736 370.017 0.644028 0.697882 0.313353 0.00001 -0.152432 -0.284328 0.946531 -0.000004 0 0 0 1 0.759138 -0.643459 -0.098339 370.017 0.63299 0.694518 0.342008 -0.000004 -0.15177 -0.321879 0.934538 -0.000004 0 0 0 1 0.788211 -0.604595 -0.114841 370.017 0.598283 0.709107 0.373127 0.000015 -0.144157 -0.36281 0.920645 -0.000004 0 0 0 1 0.832569 -0.540436 -0.12148 370.018 0.538962 0.73974 0.402872 0.000021 -0.127863 -0.400892 0.907159 -0.000004 0 0 0 1 0.883277 -0.454758 -0.114093 370.018 0.456989 0.780653 0.426312 -0.000034 -0.104801 -0.428691 0.897352 -0.000004 0 0 0 1 0.930042 -0.354581 -0.09641 370.018 0.358786 0.819635 0.446622 0.000022 -0.079342 -0.449967 0.889514 -0.000004 0 0 0 1 0.966827 -0.244683 -0.073324 370.018 0.250013 0.847674 0.467913 0.000049 -0.052335 -0.470723 0.880727 -0.000004 0 0 0 1 0.989892 -0.134344 -0.045439 370.018 0.139383 0.862455 0.486564 0.000034 -0.026177 -0.487979 0.872462 -0.000004 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.873378 0.43301 0.222966 186.693 -0.406165 0.900177 -0.157199 -0.000023 -0.268778 0.046733 0.962068 -0.000009 0 0 0 1 0.841562 0.491996 0.222966 186.693 -0.467055 0.870142 -0.157199 -0.000062 -0.271354 0.028155 0.962068 -0.000009 0 0 0 1 0.806237 0.547966 0.222966 186.693 -0.525023 0.836444 -0.157199 -0.000005 -0.272639 0.009677 0.962068 -0.000009 0 0 0 1 0.784918 0.578092 0.222966 186.693 -0.556308 0.815971 -0.157199 -0.000057 -0.27281 -0.000649 0.962068 -0.000009 0 0 0 1 0.77981 0.584964 0.222966 186.693 -0.563454 0.811054 -0.157199 0.000035 -0.272794 -0.003045 0.962068 -0.000009 0 0 0 1 0.778455 0.586766 0.222966 186.693 -0.565328 0.809748 -0.157199 -0.000007 -0.272786 -0.003677 0.962068 -0.000009 0 0 0 1 0.779922 0.584814 0.222966 186.693 -0.563298 0.811162 -0.157199 -0.000102 -0.272794 -0.002994 0.962068 -0.000009 0 0 0 1 0.783327 0.580244 0.222966 186.693 -0.558546 0.814442 -0.157199 -0.000022 -0.272807 -0.001398 0.962068 -0.000009 0 0 0 1 0.787665 0.574343 0.222966 186.693 -0.552412 0.818614 -0.157199 0.000009 -0.27281 0.000651 0.962068 -0.000009 0 0 0 1 0.792094 0.568219 0.222966 186.693 -0.546048 0.822873 -0.157199 -0.000035 -0.272796 0.002765 0.962068 -0.000009 0 0 0 1 0.795732 0.563111 0.222966 186.693 -0.540743 0.826368 -0.157199 -0.000005 -0.272773 0.00452 0.962068 -0.000009 0 0 0 1 0.797681 0.560348 0.222966 186.693 -0.537874 0.828239 -0.157199 0.000076 -0.272756 0.005466 0.962068 -0.000009 0 0 0 1 0.797147 0.561109 0.222966 186.693 -0.538664 0.827726 -0.157199 0.000081 -0.272761 0.005206 0.962068 -0.000009 0 0 0 1 0.793186 0.566694 0.222966 186.693 -0.544464 0.823922 -0.157199 0.00001 -0.27279 0.00329 0.962068 -0.000009 0 0 0 1 0.784918 0.578092 0.222966 186.693 -0.556309 0.815971 -0.157199 0.000012 -0.27281 -0.00065 0.962068 -0.000009 0 0 0 1 0.738845 0.63592 0.222966 186.693 -0.616553 0.77146 -0.157199 0.000044 -0.271976 -0.021325 0.962068 -0.000009 0 0 0 1 0.648818 0.727544 0.222966 186.693 -0.712632 0.683698 -0.157199 0.000013 -0.266814 -0.0569 0.962068 -0.000009 0 0 0 1 0.57496 0.787214 0.222966 186.693 -0.775768 0.611124 -0.157199 -0.000003 -0.260009 -0.082587 0.962068 -0.000009 0 0 0 1 0.592978 0.773733 0.222966 186.693 -0.761455 0.628868 -0.157199 -0.00002 -0.261846 -0.076563 0.962068 -0.000009 0 0 0 1 0.716254 0.661271 0.222966 186.693 -0.643059 0.749515 -0.157199 -0.000069 -0.271027 -0.030787 0.962068 -0.000009 0 0 0 1 0.859131 0.460631 0.222966 186.693 -0.434654 0.886772 -0.157199 0.000062 -0.270131 0.038141 0.962068 -0.000009 0 0 0 1 0.956384 0.188714 0.222966 186.693 -0.155779 0.975203 -0.157199 -0.000091 -0.247107 0.115603 0.962068 -0.000009 0 0 0 1 0.970194 -0.094895 0.222966 186.693 0.131858 0.978724 -0.157199 -0.00007 -0.203317 0.181916 0.962068 -0.000009 0 0 0 1 0.918542 -0.326446 0.222966 186.693 0.364372 0.91789 -0.157199 0.000049 -0.153341 0.225637 0.962068 -0.000009 0 0 0 1 0.857136 -0.464331 0.222966 186.693 0.501702 0.850637 -0.157199 0.000036 -0.116671 0.246604 0.962068 -0.000009 0 0 0 1 0.851953 -0.473776 0.222966 186.693 0.511073 0.845041 -0.157199 0.000012 -0.113939 0.247878 0.962068 -0.000009 0 0 0 1 0.900758 -0.372722 0.222966 186.693 0.410566 0.898178 -0.157199 0.000023 -0.141672 0.233141 0.962068 -0.000009 0 0 0 1 0.952921 -0.205493 0.222966 186.693 0.243187 0.957156 -0.157199 -0.000057 -0.181109 0.204022 0.962068 -0.000009 0 0 0 1 0.974319 -0.031516 0.222966 186.693 0.06784 0.985235 -0.157199 0.000013 -0.214707 0.168283 0.962068 -0.000009 0 0 0 1 0.951387 0.21248 0.222966 186.693 -0.180024 0.97102 -0.157199 -0.00004 -0.249906 0.109418 0.962068 -0.000009 0 0 0 1 0.873378 0.43301 0.222966 186.693 -0.406165 0.900177 -0.157199 0.000039 -0.268778 0.046733 0.962068 -0.000009 0 0 0 1 0.82455 0.520002 0.222966 186.693 -0.496036 0.853953 -0.157199 0.000058 -0.272149 0.019019 0.962068 -0.000009 0 0 0 1 0.796928 0.561419 0.222966 186.693 -0.538986 0.827516 -0.157199 -0.000000 -0.272763 0.0051 0.962068 -0.000009 0 0 0 1 0.784918 0.578092 0.222966 186.693 -0.556308 0.815971 -0.157199 0.00004 -0.27281 -0.000649 0.962068 -0.000009 0 0 0 1 0.77981 0.584964 0.222966 186.693 -0.563454 0.811054 -0.157199 -0.00003 -0.272794 -0.003045 0.962068 -0.000009 0 0 0 1 0.778455 0.586765 0.222966 186.693 -0.565328 0.809749 -0.157199 0.000007 -0.272786 -0.003677 0.962068 -0.000009 0 0 0 1 0.779922 0.584814 0.222966 186.693 -0.563298 0.811162 -0.157199 -0.000103 -0.272794 -0.002994 0.962068 -0.000009 0 0 0 1 0.783327 0.580244 0.222966 186.693 -0.558546 0.814441 -0.157199 -0.000125 -0.272807 -0.001398 0.962068 -0.000009 0 0 0 1 0.787665 0.574343 0.222966 186.693 -0.552412 0.818614 -0.157199 0.000164 -0.27281 0.000651 0.962068 -0.000009 0 0 0 1 0.792119 0.568184 0.222966 186.693 -0.546012 0.822897 -0.157199 -0.000071 -0.272796 0.002778 0.962068 -0.000009 0 0 0 1 0.795732 0.563111 0.222966 186.693 -0.540743 0.826368 -0.157199 0.000048 -0.272773 0.00452 0.962068 -0.000009 0 0 0 1 0.797681 0.560348 0.222966 186.693 -0.537874 0.828239 -0.157199 0.000041 -0.272756 0.005466 0.962068 -0.000009 0 0 0 1 0.797137 0.561123 0.222966 186.693 -0.538679 0.827716 -0.157199 -0.000015 -0.272761 0.005202 0.962068 -0.000009 0 0 0 1 0.793186 0.566694 0.222966 186.693 -0.544464 0.823922 -0.157199 0 -0.27279 0.00329 0.962068 -0.000009 0 0 0 1 0.784918 0.578092 0.222966 186.693 -0.556309 0.815971 -0.157199 0.000025 -0.27281 -0.00065 0.962068 -0.000009 0 0 0 1 0.738845 0.63592 0.222966 186.693 -0.616553 0.77146 -0.157199 -0.000036 -0.271976 -0.021325 0.962068 -0.000009 0 0 0 1 0.648818 0.727544 0.222966 186.693 -0.712632 0.683698 -0.157199 -0.000068 -0.266814 -0.0569 0.962068 -0.000009 0 0 0 1 0.57496 0.787214 0.222966 186.693 -0.775768 0.611124 -0.157199 0.000013 -0.260009 -0.082587 0.962068 -0.000009 0 0 0 1 0.592978 0.773733 0.222966 186.693 -0.761455 0.628868 -0.157199 0.000008 -0.261846 -0.076563 0.962068 -0.000009 0 0 0 1 0.716254 0.661271 0.222966 186.693 -0.643059 0.749515 -0.157199 0.000014 -0.271027 -0.030787 0.962068 -0.000009 0 0 0 1 0.859131 0.460631 0.222966 186.693 -0.434654 0.886772 -0.157199 0.000052 -0.270131 0.038141 0.962068 -0.000009 0 0 0 1 0.956036 0.190476 0.222966 186.693 -0.157575 0.974914 -0.157199 0.000004 -0.247316 0.115154 0.962068 -0.000009 0 0 0 1 0.970193 -0.0949 0.222966 186.693 0.131863 0.978724 -0.157199 -0.000019 -0.203316 0.181917 0.962068 -0.000009 0 0 0 1 0.918542 -0.326446 0.222966 186.693 0.364372 0.917889 -0.157199 -0.000000 -0.153341 0.225637 0.962068 -0.000009 0 0 0 1 0.85705 -0.464491 0.222966 186.693 0.50186 0.850544 -0.157199 0.000046 -0.116625 0.246625 0.962068 -0.000009 0 0 0 1 0.851953 -0.473776 0.222966 186.693 0.511073 0.845041 -0.157199 -0.000005 -0.113939 0.247878 0.962068 -0.000009 0 0 0 1 0.900758 -0.372722 0.222966 186.693 0.410566 0.898178 -0.157199 -0.000041 -0.141672 0.233141 0.962068 -0.000009 0 0 0 1 0.952922 -0.205493 0.222966 186.693 0.243187 0.957156 -0.157199 -0.000018 -0.181109 0.204022 0.962068 -0.000009 0 0 0 1 0.974319 -0.031516 0.222966 186.693 0.06784 0.985235 -0.157199 0.000012 -0.214707 0.168283 0.962068 -0.000009 0 0 0 1 0.951387 0.21248 0.222966 186.693 -0.180024 0.97102 -0.157199 0.000027 -0.249906 0.109418 0.962068 -0.000009 0 0 0 1 0.873378 0.43301 0.222966 186.693 -0.406165 0.900177 -0.157199 0.000067 -0.268778 0.046733 0.962068 -0.000009 0 0 0 1 0.824799 0.519608 0.222966 186.693 -0.495628 0.85419 -0.157199 0.000066 -0.272137 0.019149 0.962068 -0.000009 0 0 0 1 0.796928 0.561419 0.222966 186.693 -0.538986 0.827516 -0.157199 -0.000003 -0.272763 0.0051 0.962068 -0.000009 0 0 0 1 0.784864 0.578165 0.222966 186.693 -0.556384 0.815919 -0.157199 0.000065 -0.27281 -0.000675 0.962068 -0.000009 0 0 0 1 0.77981 0.584964 0.222966 186.693 -0.563454 0.811054 -0.157199 -0.000071 -0.272794 -0.003045 0.962068 -0.000009 0 0 0 1 0.778455 0.586765 0.222966 186.693 -0.565328 0.809748 -0.157199 0.000179 -0.272786 -0.003677 0.962068 -0.000009 0 0 0 1 0.779922 0.584814 0.222966 186.693 -0.563298 0.811162 -0.157199 -0.000033 -0.272794 -0.002994 0.962068 -0.000009 0 0 0 1 0.783327 0.580244 0.222966 186.693 -0.558546 0.814441 -0.157199 -0.000064 -0.272807 -0.001398 0.962068 -0.000009 0 0 0 1 0.787665 0.574343 0.222966 186.693 -0.552412 0.818614 -0.157199 0.000036 -0.27281 0.00065 0.962068 -0.000009 0 0 0 1 0.792119 0.568184 0.222966 186.693 -0.546012 0.822897 -0.157199 0.00001 -0.272796 0.002778 0.962068 -0.000009 0 0 0 1 0.795733 0.563111 0.222966 186.693 -0.540744 0.826368 -0.157199 0.000027 -0.272773 0.00452 0.962068 -0.000009 0 0 0 1 0.797681 0.560349 0.222966 186.693 -0.537874 0.828239 -0.157199 -0.000032 -0.272756 0.005467 0.962068 -0.000009 0 0 0 1 0.797147 0.561109 0.222966 186.693 -0.538664 0.827726 -0.157199 0.000093 -0.272761 0.005206 0.962068 -0.000009 0 0 0 1 0.793186 0.566694 0.222966 186.693 -0.544464 0.823922 -0.157199 0.000048 -0.27279 0.00329 0.962068 -0.000009 0 0 0 1 0.784918 0.578092 0.222966 186.693 -0.556308 0.815971 -0.157199 0.000006 -0.27281 -0.000649 0.962068 -0.000009 0 0 0 1 0.738845 0.63592 0.222966 186.693 -0.616553 0.77146 -0.157199 -0.00002 -0.271976 -0.021325 0.962068 -0.000009 0 0 0 1 0.649342 0.727077 0.222966 186.693 -0.712141 0.68421 -0.157199 -0.000036 -0.266852 -0.056708 0.962068 -0.000009 0 0 0 1 0.57496 0.787214 0.222966 186.693 -0.775768 0.611124 -0.157199 0.000034 -0.260009 -0.082587 0.962068 -0.000009 0 0 0 1 0.593306 0.773481 0.222966 186.693 -0.761188 0.629191 -0.157199 0.000007 -0.261881 -0.076452 0.962068 -0.000009 0 0 0 1 0.716251 0.661274 0.222966 186.693 -0.643062 0.749512 -0.157199 -0.00007 -0.271027 -0.030788 0.962068 -0.000009 0 0 0 1 0.859131 0.460631 0.222966 186.693 -0.434654 0.886772 -0.157199 -0.000003 -0.270131 0.038141 0.962068 -0.000009 0 0 0 1 0.956036 0.190476 0.222966 186.693 -0.157575 0.974915 -0.157199 -0.000013 -0.247316 0.115154 0.962068 -0.000009 0 0 0 1 0.970354 -0.093269 0.222966 186.693 0.130215 0.978944 -0.157199 -0.000024 -0.20361 0.181572 0.962068 -0.000009 0 0 0 1 0.918542 -0.326446 0.222966 186.693 0.364372 0.917889 -0.157199 -0.000009 -0.153341 0.225637 0.962068 -0.000009 0 0 0 1 0.85705 -0.464491 0.222966 186.693 0.50186 0.850544 -0.157199 -0.000053 -0.116625 0.246625 0.962068 -0.000009 0 0 0 1 0.851953 -0.473776 0.222966 186.693 0.511073 0.845041 -0.157199 -0.000037 -0.113939 0.247878 0.962068 -0.000009 0 0 0 1 0.900758 -0.372722 0.222966 186.693 0.410566 0.898178 -0.157199 0.000058 -0.141672 0.233141 0.962068 -0.000009 0 0 0 1 0.95269 -0.206562 0.222966 186.693 0.244262 0.956882 -0.157199 -0.000044 -0.180881 0.204224 0.962068 -0.000009 0 0 0 1 0.97432 -0.031512 0.222966 186.693 0.067836 0.985235 -0.157199 0.000043 -0.214708 0.168282 0.962068 -0.000009 0 0 0 1 0.951387 0.21248 0.222966 186.693 -0.180024 0.97102 -0.157199 -0.000043 -0.249906 0.109418 0.962068 -0.000009 0 0 0 1 0.873378 0.43301 0.222966 186.693 -0.406165 0.900177 -0.157199 0.000053 -0.268778 0.046733 0.962068 -0.000009 0 0 0 1 0.824799 0.519607 0.222966 186.693 -0.495628 0.85419 -0.157199 -0.000025 -0.272137 0.019149 0.962068 -0.000009 0 0 0 1 0.796928 0.561419 0.222966 186.693 -0.538986 0.827516 -0.157199 -0.000046 -0.272763 0.005101 0.962068 -0.000009 0 0 0 1 0.784864 0.578165 0.222966 186.693 -0.556384 0.815919 -0.157199 0.000036 -0.27281 -0.000675 0.962068 -0.000009 0 0 0 1 0.77981 0.584964 0.222966 186.693 -0.563454 0.811054 -0.157199 0.000044 -0.272794 -0.003045 0.962068 -0.000009 0 0 0 1 0.778455 0.586765 0.222966 186.693 -0.565328 0.809748 -0.157199 0.00012 -0.272786 -0.003677 0.962068 -0.000009 0 0 0 1 0.779922 0.584814 0.222966 186.693 -0.563298 0.811162 -0.157199 -0.000002 -0.272794 -0.002994 0.962068 -0.000009 0 0 0 1 0.783303 0.580277 0.222966 186.693 -0.55858 0.814418 -0.157199 -0.000088 -0.272807 -0.001409 0.962068 -0.000009 0 0 0 1 0.787665 0.574343 0.222966 186.693 -0.552412 0.818614 -0.157199 -0.000017 -0.27281 0.000651 0.962068 -0.000009 0 0 0 1 0.792119 0.568184 0.222966 186.693 -0.546012 0.822897 -0.157199 0.000029 -0.272796 0.002778 0.962068 -0.000009 0 0 0 1 0.795733 0.563112 0.222966 186.693 -0.540744 0.826368 -0.157199 0.000064 -0.272773 0.00452 0.962068 -0.000009 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 1 0 0 167.761 0 1 0 0.000019 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000034 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000007 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000013 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000012 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000004 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000047 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000009 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000015 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000008 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000005 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000015 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000008 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000006 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000011 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000003 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000053 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000021 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.00001 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000027 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.00002 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000049 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000036 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000022 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000059 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000017 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000069 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000085 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000114 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000009 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000011 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000016 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000021 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000021 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000025 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000031 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000015 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000003 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000003 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000002 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.00001 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000015 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000000 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000014 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000054 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000004 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000057 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000009 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000009 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000017 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000144 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000131 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000025 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000034 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000067 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000055 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000002 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000094 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000018 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000069 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.00001 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000076 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000026 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.00002 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000001 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000036 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000001 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000011 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000007 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000008 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000009 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000009 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000000 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000021 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000000 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000018 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000003 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000037 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.00002 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000038 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000000 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.00012 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000024 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000089 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.00004 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000017 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000115 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000064 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000008 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000027 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.00004 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000014 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000007 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000001 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000013 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000012 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000004 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000048 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 0.000002 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000000 0 0 1 0.000013 0 0 0 1 1 0 0 167.761 0 1 0 -0.000019 0 0 1 0.000013 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 1 0 0 345.132 0 1 0 0.000017 0 0 1 -0.000007 0 0 0 1 1 0 0 345.132 0 1 0 0.000033 0 0 1 0.00001 0 0 0 1 1 0 0 345.132 0 1 0 -0.000028 0 0 1 -0.000008 0 0 0 1 1 0 0 345.132 0 1 0 -0.000043 0 0 1 -0.000005 0 0 0 1 1 0 0 345.132 0 1 0 -0.00006 0 0 1 0.000004 0 0 0 1 1 0 0 345.132 0 1 0 0.000053 0 0 1 -0.000000 0 0 0 1 1 0 0 345.132 0 1 0 0.000041 0 0 1 0.000000 0 0 0 1 1 0 0 345.132 0 1 0 0.000013 0 0 1 0 0 0 0 1 1 0 0 345.132 0 1 0 -0.000039 0 0 1 -0.000000 0 0 0 1 1 0 0 345.132 0 1 0 0.000046 0 0 1 -0.000003 0 0 0 1 1 0 0 345.132 0 1 0 -0.000021 0 0 1 0.000005 0 0 0 1 1 0 0 345.132 0 1 0 -0.000013 0 0 1 0.000006 0 0 0 1 1 0 0 345.132 0 1 0 -0.00001 0 0 1 -0.000004 0 0 0 1 1 0 0 345.132 0 1 0 -0.000007 0 0 1 -0.000007 0 0 0 1 1 0 0 345.132 0 1 0 0.000007 0 0 1 0.000013 0 0 0 1 1 0 0 345.132 0 1 0 0.000009 0 0 1 -0.000012 0 0 0 1 1 0 0 345.132 0 1 0 0.000029 0 0 1 -0.00001 0 0 0 1 1 0 0 345.132 0 1 0 -0.000017 0 0 1 0.000009 0 0 0 1 1 0 0 345.132 0 1 0 -0.000009 0 0 1 -0.000002 0 0 0 1 1 0 0 345.132 0 1 0 0.000022 0 0 1 0.000002 0 0 0 1 1 0 0 345.132 0 1 0 0.00002 0 0 1 0.000005 0 0 0 1 1 0 0 345.132 0 1 0 -0.00004 0 0 1 -0.000002 0 0 0 1 1 0 0 345.132 0 1 0 0.000006 0 0 1 0.000003 0 0 0 1 1 0 0 345.132 0 1 0 0.000036 0 0 1 -0.00001 0 0 0 1 1 0 0 345.132 0 1 0 -0.000038 0 0 1 0.000000 0 0 0 1 1 0 0 345.132 0 1 0 -0.000017 0 0 1 0.000011 0 0 0 1 1 0 0 345.132 0 1 0 0.000026 0 0 1 0.000011 0 0 0 1 1 0 0 345.132 0 1 0 0.000005 0 0 1 -0.000002 0 0 0 1 1 0 0 345.132 0 1 0 0.000001 0 0 1 0.000023 0 0 0 1 1 0 0 345.132 0 1 0 0.000015 0 0 1 -0.000054 0 0 0 1 1 0 0 345.132 0 1 0 -0.000052 0 0 1 0.000015 0 0 0 1 1 0 0 345.132 0 1 0 0.000017 0 0 1 0.000003 0 0 0 1 1 0 0 345.132 0 1 0 -0.000033 0 0 1 0.000019 0 0 0 1 1 0 0 345.132 0 1 0 -0.000075 0 0 1 0.000002 0 0 0 1 1 0 0 345.132 0 1 0 -0.000054 0 0 1 -0.000028 0 0 0 1 1 0 0 345.132 0 1 0 -0.000043 0 0 1 0.000025 0 0 0 1 1 0 0 345.132 0 1 0 -0.000042 0 0 1 -0.000003 0 0 0 1 1 0 0 345.132 0 1 0 0.000069 0 0 1 0.00001 0 0 0 1 1 0 0 345.132 0 1 0 0.000017 0 0 1 0.000001 0 0 0 1 1 0 0 345.132 0 1 0 0.000027 0 0 1 -0.000004 0 0 0 1 1 0 0 345.132 0 1 0 -0.000039 0 0 1 -0.000042 0 0 0 1 1 0 0 345.132 0 1 0 0.000000 0 0 1 0.000001 0 0 0 1 1 0 0 345.132 0 1 0 0.000007 0 0 1 -0.000004 0 0 0 1 1 0 0 345.132 0 1 0 -0.000022 0 0 1 0.000023 0 0 0 1 1 0 0 345.132 0 1 0 0.000019 0 0 1 0.000017 0 0 0 1 1 0 0 345.132 0 1 0 0.000013 0 0 1 0.00001 0 0 0 1 1 0 0 345.132 0 1 0 0.000046 0 0 1 0.000017 0 0 0 1 1 0 0 345.132 0 1 0 -0.000003 0 0 1 0.00001 0 0 0 1 1 0 0 345.132 0 1 0 0.000016 0 0 1 0.000003 0 0 0 1 1 0 0 345.132 0 1 0 -0.000016 0 0 1 0.000009 0 0 0 1 1 0 0 345.132 0 1 0 0.000031 0 0 1 -0.000016 0 0 0 1 1 0 0 345.132 0 1 0 -0.000022 0 0 1 -0.00002 0 0 0 1 1 0 0 345.132 0 1 0 0.000055 0 0 1 -0.000003 0 0 0 1 1 0 0 345.132 0 1 0 -0.000033 0 0 1 0.00002 0 0 0 1 1 0 0 345.132 0 1 0 -0.000021 0 0 1 -0.000019 0 0 0 1 1 0 0 345.132 0 1 0 0.000036 0 0 1 0.000018 0 0 0 1 1 0 0 345.132 0 1 0 0.000031 0 0 1 0.000018 0 0 0 1 1 0 0 345.132 0 1 0 0.000038 0 0 1 0.000005 0 0 0 1 1 0 0 345.132 0 1 0 0.000045 0 0 1 0.000005 0 0 0 1 1 0 0 345.132 0 1 0 -0.000023 0 0 1 0.000004 0 0 0 1 1 0 0 345.132 0 1 0 0.000035 0 0 1 -0.000007 0 0 0 1 1 0 0 345.132 0 1 0 0.000003 0 0 1 -0.000009 0 0 0 1 1 0 0 345.132 0 1 0 0.000047 0 0 1 -0.000009 0 0 0 1 1 0 0 345.132 0 1 0 0.000034 0 0 1 -0.000005 0 0 0 1 1 0 0 345.132 0 1 0 0.000008 0 0 1 0.000004 0 0 0 1 1 0 0 345.132 0 1 0 -0.000021 0 0 1 0.000000 0 0 0 1 1 0 0 345.132 0 1 0 -0.000052 0 0 1 -0.000036 0 0 0 1 1 0 0 345.132 0 1 0 -0.000021 0 0 1 0.000008 0 0 0 1 1 0 0 345.132 0 1 0 -0.000001 0 0 1 -0.000041 0 0 0 1 1 0 0 345.132 0 1 0 -0.000015 0 0 1 0.000003 0 0 0 1 1 0 0 345.132 0 1 0 0.000063 0 0 1 -0.000019 0 0 0 1 1 0 0 345.132 0 1 0 -0.000021 0 0 1 -0.000013 0 0 0 1 1 0 0 345.132 0 1 0 0.000009 0 0 1 -0.000006 0 0 0 1 1 0 0 345.132 0 1 0 0.000054 0 0 1 0.000000 0 0 0 1 1 0 0 345.132 0 1 0 0.000015 0 0 1 0.000095 0 0 0 1 1 0 0 345.132 0 1 0 -0.000003 0 0 1 -0.000000 0 0 0 1 1 0 0 345.132 0 1 0 0.000005 0 0 1 -0.000012 0 0 0 1 1 0 0 345.132 0 1 0 -0.000019 0 0 1 0.000053 0 0 0 1 1 0 0 345.132 0 1 0 -0.000027 0 0 1 -0.000002 0 0 0 1 1 0 0 345.132 0 1 0 0.00005 0 0 1 -0.000052 0 0 0 1 1 0 0 345.132 0 1 0 -0.000017 0 0 1 0.000055 0 0 0 1 1 0 0 345.132 0 1 0 0.000021 0 0 1 0.00001 0 0 0 1 1 0 0 345.132 0 1 0 -0.000023 0 0 1 -0.000016 0 0 0 1 1 0 0 345.132 0 1 0 0.000005 0 0 1 -0.000012 0 0 0 1 1 0 0 345.132 0 1 0 0.000031 0 0 1 -0.00003 0 0 0 1 1 0 0 345.132 0 1 0 0.000006 0 0 1 -0.000027 0 0 0 1 1 0 0 345.132 0 1 0 -0.000029 0 0 1 -0.000033 0 0 0 1 1 0 0 345.132 0 1 0 -0.000036 0 0 1 0.000024 0 0 0 1 1 0 0 345.132 0 1 0 -0.000008 0 0 1 0.000031 0 0 0 1 1 0 0 345.132 0 1 0 0.000045 0 0 1 0.000028 0 0 0 1 1 0 0 345.132 0 1 0 -0.000031 0 0 1 -0.000005 0 0 0 1 1 0 0 345.132 0 1 0 0.000053 0 0 1 -0.000039 0 0 0 1 1 0 0 345.132 0 1 0 -0.000017 0 0 1 0.000005 0 0 0 1 1 0 0 345.132 0 1 0 -0.000016 0 0 1 -0.000047 0 0 0 1 1 0 0 345.132 0 1 0 -0.000051 0 0 1 0.000028 0 0 0 1 1 0 0 345.132 0 1 0 -0.000082 0 0 1 -0.000042 0 0 0 1 1 0 0 345.132 0 1 0 -0.000003 0 0 1 0.000046 0 0 0 1 1 0 0 345.132 0 1 0 -0.000039 0 0 1 0.000035 0 0 0 1 1 0 0 345.132 0 1 0 0.00001 0 0 1 -0.000011 0 0 0 1 1 0 0 345.132 0 1 0 -0.000006 0 0 1 0.000058 0 0 0 1 1 0 0 345.132 0 1 0 -0.000044 0 0 1 -0.000007 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.988998 -0.016084 -0.147054 -64.1862 -0.002497 -0.995745 0.092117 86.8699 -0.14791 -0.090736 -0.98483 -181.92 0 0 0 1 0.98822 0.008131 -0.152823 -71.9975 0.021679 -0.995956 0.087196 88.749 -0.151497 -0.089482 -0.984399 -178.051 0 0 0 1 0.986741 0.032591 -0.158997 -80.0879 0.046067 -0.995582 0.08182 90.2004 -0.155628 -0.088059 -0.983883 -173.819 0 0 0 1 0.984505 0.059012 -0.165126 -88.2262 0.072369 -0.994473 0.07607 91.3381 -0.159724 -0.086841 -0.983335 -169.226 0 0 0 1 0.9754 0.104534 -0.194085 -96.0419 0.120914 -0.989861 0.074529 92.2995 -0.184327 -0.096163 -0.97815 -164.382 0 0 0 1 0.961352 0.16149 -0.222985 -103.048 0.180798 -0.981101 0.068938 93.2678 -0.207638 -0.106589 -0.972381 -159.523 0 0 0 1 0.940354 0.229663 -0.250975 -109.055 0.251671 -0.966014 0.058974 94.511 -0.228901 -0.11862 -0.966195 -154.728 0 0 0 1 0.911129 0.30564 -0.276453 -113.726 0.329875 -0.942968 0.04467 96.3165 -0.247033 -0.131896 -0.959989 -150.189 0 0 0 1 0.874019 0.381496 -0.300917 -117.16 0.407793 -0.912664 0.027387 99.1814 -0.264188 -0.146649 -0.953257 -145.622 0 0 0 1 0.82865 0.455119 -0.325892 -119.78 0.483444 -0.875349 0.006806 103.187 -0.282171 -0.163191 -0.945383 -140.629 0 0 0 1 0.775825 0.526034 -0.348402 -121.543 0.555703 -0.831197 -0.017535 107.867 -0.298814 -0.180004 -0.937181 -135.524 0 0 0 1 0.717386 0.593163 -0.365396 -122.462 0.623021 -0.780936 -0.044544 112.64 -0.311773 -0.195694 -0.929786 -130.74 0 0 0 1 0.65262 0.658368 -0.375019 -122.684 0.687075 -0.722872 -0.073375 117.109 -0.319398 -0.20978 -0.924109 -126.549 0 0 0 1 0.581021 0.722153 -0.375379 -122.395 0.748415 -0.655303 -0.102255 120.795 -0.31983 -0.221527 -0.921213 -123.332 0 0 0 1 0.502712 0.783505 -0.36524 -121.848 0.806382 -0.577275 -0.128462 123.186 -0.311494 -0.229943 -0.922007 -121.501 0 0 0 1 0.413853 0.84295 -0.343746 -121.279 0.861875 -0.484379 -0.150164 123.891 -0.293084 -0.23412 -0.926979 -121.356 0 0 0 1 0.399741 0.848781 -0.346091 -120.629 0.864681 -0.474476 -0.164923 122.161 -0.304195 -0.233331 -0.923592 -123.729 0 0 0 1 0.380245 0.862205 -0.334689 -119.566 0.874183 -0.453212 -0.174365 118.151 -0.302023 -0.226278 -0.926056 -128.551 0 0 0 1 0.372378 0.872538 -0.316245 -117.811 0.880686 -0.439715 -0.176191 112.573 -0.292791 -0.212903 -0.932172 -135.001 0 0 0 1 0.393687 0.870304 -0.295941 -115.184 0.874173 -0.454024 -0.172291 106.202 -0.284309 -0.190875 -0.939539 -142.223 0 0 0 1 0.465999 0.839578 -0.279202 -111.766 0.836608 -0.52082 -0.169807 99.9916 -0.28798 -0.154453 -0.945099 -149.263 0 0 0 1 0.571696 0.774641 -0.270359 -107.718 0.764324 -0.62263 -0.167754 94.6606 -0.298283 -0.110737 -0.948032 -155.571 0 0 0 1 0.674446 0.686476 -0.271799 -103.52 0.673489 -0.722867 -0.154518 91.1788 -0.302548 -0.078839 -0.949868 -160.418 0 0 0 1 0.764968 0.580586 -0.278827 -98.6421 0.57235 -0.811314 -0.119098 89.3151 -0.295362 -0.068479 -0.952928 -164.485 0 0 0 1 0.845821 0.453649 -0.280696 -92.547 0.455031 -0.888155 -0.064254 88.1087 -0.27845 -0.073376 -0.957644 -168.624 0 0 0 1 0.90685 0.326585 -0.266395 -85.7921 0.336329 -0.941696 -0.009547 87.3443 -0.253982 -0.080938 -0.963816 -172.546 0 0 0 1 0.946465 0.218305 -0.237795 -79.0927 0.23157 -0.972386 0.029003 86.8668 -0.224897 -0.082516 -0.970882 -175.954 0 0 0 1 0.970201 0.129161 -0.205002 -72.8974 0.143079 -0.988208 0.054529 86.5739 -0.195542 -0.082237 -0.977241 -178.751 0 0 0 1 0.982412 0.06238 -0.175996 -67.9514 0.075572 -0.994731 0.069265 86.4564 -0.170748 -0.081347 -0.981952 -180.745 0 0 0 1 0.987668 0.01542 -0.1558 -64.8538 0.028066 -0.996456 0.079298 86.5423 -0.154025 -0.082693 -0.984601 -181.839 0 0 0 1 0.989032 -0.016046 -0.146826 -64.1862 -0.002517 -0.995768 0.091866 86.8698 -0.147678 -0.090487 -0.984887 -181.92 0 0 0 1 0.990728 0.020474 -0.134309 -67.1053 0.03065 -0.996776 0.074142 87.6436 -0.132358 -0.077571 -0.988162 -180.491 0 0 0 1 0.989953 0.048403 -0.132853 -73.3987 0.057405 -0.996247 0.064785 88.8695 -0.129218 -0.071761 -0.989016 -177.419 0 0 0 1 0.987527 0.072667 -0.13968 -81.9029 0.081793 -0.994797 0.060737 90.2847 -0.134539 -0.071405 -0.988332 -172.928 0 0 0 1 0.978236 0.113686 -0.173581 -91.4007 0.126457 -0.989883 0.064345 91.6896 -0.164509 -0.084895 -0.982715 -167.341 0 0 0 1 0.963488 0.165766 -0.210269 -100.518 0.182712 -0.981096 0.06377 93.0219 -0.195723 -0.099861 -0.975561 -161.27 0 0 0 1 0.941477 0.230916 -0.245558 -108.312 0.251814 -0.966097 0.056971 94.4613 -0.224077 -0.115473 -0.967706 -155.279 0 0 0 1 0.911685 0.306147 -0.274053 -113.728 0.329785 -0.943049 0.043597 96.3166 -0.245099 -0.130126 -0.960725 -150.188 0 0 0 1 0.874677 0.382106 -0.29822 -117.16 0.407734 -0.912718 0.026425 99.1813 -0.262093 -0.144708 -0.954131 -145.622 0 0 0 1 0.829068 0.456265 -0.323217 -119.794 0.483893 -0.875107 0.005879 103.215 -0.280167 -0.161277 -0.946307 -140.598 0 0 0 1 0.776566 0.526773 -0.345623 -121.542 0.55574 -0.831158 -0.018121 107.867 -0.296813 -0.178004 -0.938198 -135.524 0 0 0 1 0.71808 0.593897 -0.362833 -122.461 0.623106 -0.780846 -0.04493 112.64 -0.31 -0.19382 -0.930771 -130.74 0 0 0 1 0.652778 0.659432 -0.372867 -122.684 0.687586 -0.722348 -0.073751 117.135 -0.317974 -0.208234 -0.924949 -126.525 0 0 0 1 0.581435 0.72266 -0.37376 -122.395 0.748527 -0.655164 -0.102313 120.795 -0.318812 -0.220282 -0.921865 -123.332 0 0 0 1 0.50292 0.783788 -0.364344 -121.848 0.806456 -0.577174 -0.128446 123.186 -0.310965 -0.22923 -0.922364 -121.501 0 0 0 1 0.413852 0.84295 -0.343746 -121.279 0.861875 -0.484378 -0.150164 123.891 -0.293084 -0.23412 -0.926979 -121.356 0 0 0 1 0.399742 0.848784 -0.346082 -120.629 0.864682 -0.474474 -0.164922 122.161 -0.30419 -0.233325 -0.923595 -123.729 0 0 0 1 0.380249 0.862212 -0.334666 -119.566 0.874186 -0.453207 -0.174362 118.151 -0.30201 -0.22626 -0.926065 -128.551 0 0 0 1 0.372382 0.872546 -0.31622 -117.811 0.880689 -0.43971 -0.176187 112.573 -0.292776 -0.212883 -0.932182 -135.001 0 0 0 1 0.393686 0.870305 -0.295941 -115.184 0.874173 -0.454023 -0.17229 106.202 -0.284309 -0.190875 -0.939539 -142.223 0 0 0 1 0.465977 0.839556 -0.279305 -111.766 0.836596 -0.520832 -0.169827 99.9916 -0.28805 -0.15453 -0.945065 -149.263 0 0 0 1 0.570987 0.77507 -0.270629 -107.744 0.764799 -0.622023 -0.167838 94.6882 -0.298424 -0.111144 -0.94794 -155.536 0 0 0 1 0.674373 0.686416 -0.272128 -103.52 0.673446 -0.722901 -0.154546 91.1787 -0.302805 -0.079042 -0.949769 -160.418 0 0 0 1 0.76491 0.580544 -0.279072 -98.6421 0.572326 -0.811332 -0.119095 89.3151 -0.29556 -0.068624 -0.952856 -164.485 0 0 0 1 0.846242 0.452834 -0.280741 -92.5067 0.454283 -0.888563 -0.063895 88.1026 -0.27839 -0.073464 -0.957654 -168.649 0 0 0 1 0.906849 0.326586 -0.266397 -85.7923 0.33633 -0.941696 -0.009548 87.3443 -0.253983 -0.080938 -0.963816 -172.546 0 0 0 1 0.94646 0.218301 -0.237818 -79.0926 0.23157 -0.972385 0.029013 86.8669 -0.224917 -0.082531 -0.970876 -175.954 0 0 0 1 0.970187 0.129149 -0.20508 -72.8974 0.143083 -0.988204 0.054574 86.574 -0.195612 -0.082291 -0.977223 -178.751 0 0 0 1 0.982388 0.06236 -0.176135 -67.9513 0.075581 -0.994724 0.069368 86.4564 -0.170879 -0.081459 -0.981918 -180.745 0 0 0 1 0.987638 0.015391 -0.155994 -64.8538 0.028081 -0.996441 0.079475 86.5421 -0.154215 -0.082873 -0.984556 -181.839 0 0 0 1 0.988998 -0.016082 -0.147054 -64.1862 -0.002495 -0.995745 0.092117 86.8698 -0.14791 -0.090736 -0.98483 -181.92 0 0 0 1 0.990716 0.020261 -0.134433 -67.0765 0.030468 -0.99677 0.074307 87.6375 -0.132493 -0.077714 -0.988133 -180.505 0 0 0 1 0.989964 0.048414 -0.13277 -73.3987 0.0574 -0.996252 0.064706 88.8695 -0.12914 -0.071677 -0.989033 -177.419 0 0 0 1 0.987529 0.072913 -0.139537 -81.9591 0.081995 -0.994796 0.06047 90.2934 -0.134403 -0.071157 -0.988369 -172.896 0 0 0 1 0.978275 0.113723 -0.173332 -91.4007 0.12644 -0.989898 0.064152 91.6896 -0.164286 -0.084674 -0.982771 -167.342 0 0 0 1 0.963532 0.165808 -0.210031 -100.518 0.182699 -0.981109 0.063613 93.0219 -0.195516 -0.099665 -0.975623 -161.27 0 0 0 1 0.941525 0.23096 -0.245333 -108.312 0.251803 -0.966107 0.056848 94.4614 -0.223888 -0.1153 -0.967771 -155.279 0 0 0 1 0.911733 0.306189 -0.273846 -113.728 0.329776 -0.943056 0.043505 96.3166 -0.244931 -0.129973 -0.960789 -150.188 0 0 0 1 0.874722 0.382148 -0.298034 -117.16 0.407731 -0.912722 0.026358 99.1813 -0.261949 -0.144574 -0.954191 -145.622 0 0 0 1 0.829109 0.456304 -0.323056 -119.794 0.483892 -0.875108 0.005833 103.215 -0.280047 -0.161161 -0.946362 -140.598 0 0 0 1 0.776603 0.526808 -0.345487 -121.542 0.555741 -0.831158 -0.018149 107.867 -0.296716 -0.177907 -0.938248 -135.524 0 0 0 1 0.718109 0.593928 -0.362725 -122.461 0.62311 -0.780842 -0.044946 112.64 -0.309926 -0.193741 -0.930812 -130.74 0 0 0 1 0.653223 0.659052 -0.372761 -122.684 0.687194 -0.722737 -0.073586 117.109 -0.317906 -0.208091 -0.925005 -126.549 0 0 0 1 0.581448 0.722677 -0.373707 -122.395 0.748531 -0.655159 -0.102315 120.795 -0.318779 -0.22024 -0.921887 -123.332 0 0 0 1 0.502927 0.783796 -0.364318 -121.848 0.806458 -0.577171 -0.128446 123.186 -0.310949 -0.229208 -0.922374 -121.501 0 0 0 1 0.413852 0.84295 -0.343746 -121.279 0.861875 -0.484378 -0.150164 123.891 -0.293084 -0.23412 -0.926979 -121.356 0 0 0 1 0.399822 0.848696 -0.346205 -120.635 0.864624 -0.47459 -0.164892 122.179 -0.304249 -0.23341 -0.923554 -123.707 0 0 0 1 0.380203 0.862146 -0.334888 -119.566 0.874161 -0.453242 -0.174393 118.151 -0.302138 -0.226441 -0.925979 -128.551 0 0 0 1 0.372327 0.872503 -0.316403 -117.797 0.880669 -0.439725 -0.176245 112.536 -0.292904 -0.213025 -0.932109 -135.044 0 0 0 1 0.393623 0.870224 -0.296261 -115.184 0.874137 -0.454069 -0.172354 106.202 -0.284509 -0.19113 -0.939427 -142.223 0 0 0 1 0.465948 0.839523 -0.279453 -111.766 0.836577 -0.520853 -0.169854 99.9916 -0.28815 -0.154641 -0.945016 -149.263 0 0 0 1 0.571018 0.775098 -0.270486 -107.744 0.764818 -0.622006 -0.167815 94.6883 -0.298317 -0.111047 -0.947985 -155.536 0 0 0 1 0.673843 0.687084 -0.271756 -103.549 0.674093 -0.722273 -0.154662 91.1954 -0.302548 -0.078971 -0.949857 -160.39 0 0 0 1 0.764976 0.580591 -0.278794 -98.6421 0.572353 -0.811312 -0.119099 89.3151 -0.295337 -0.06846 -0.952937 -164.485 0 0 0 1 0.846269 0.452853 -0.280628 -92.5067 0.45429 -0.888559 -0.063912 88.1026 -0.278297 -0.073399 -0.957687 -168.649 0 0 0 1 0.906849 0.326586 -0.266397 -85.7923 0.33633 -0.941695 -0.009547 87.3443 -0.253983 -0.080938 -0.963816 -172.546 0 0 0 1 0.946455 0.218296 -0.237842 -79.0926 0.23157 -0.972385 0.029023 86.8669 -0.224938 -0.082546 -0.97087 -175.954 0 0 0 1 0.970076 0.129633 -0.205299 -72.9323 0.143573 -0.98814 0.054467 86.5752 -0.195804 -0.082312 -0.977182 -178.736 0 0 0 1 0.982387 0.062356 -0.176149 -67.9513 0.07558 -0.994723 0.069381 86.4564 -0.170894 -0.081471 -0.981915 -180.745 0 0 0 1 0.987637 0.01539 -0.155998 -64.8537 0.028081 -0.996441 0.07948 86.5421 -0.15422 -0.082878 -0.984555 -181.839 0 0 0 1 0.988998 -0.016084 -0.147054 -64.1862 -0.002496 -0.995745 0.092118 86.8698 -0.14791 -0.090736 -0.98483 -181.92 0 0 0 1 0.990705 0.020251 -0.134512 -67.0764 0.030475 -0.996764 0.074389 87.6376 -0.13257 -0.077797 -0.988116 -180.505 0 0 0 1 0.989943 0.048391 -0.132934 -73.3987 0.05741 -0.996241 0.064864 88.8695 -0.129296 -0.071843 -0.989 -177.419 0 0 0 1 0.987495 0.072878 -0.139792 -81.9591 0.082009 -0.994781 0.060699 90.2934 -0.134638 -0.071405 -0.988319 -172.896 0 0 0 1 0.978232 0.113682 -0.173602 -91.4007 0.126457 -0.989882 0.064362 91.6896 -0.164529 -0.084915 -0.98271 -167.342 0 0 0 1 0.963479 0.165756 -0.210316 -100.518 0.182714 -0.981094 0.063801 93.0219 -0.195764 -0.099898 -0.975549 -161.27 0 0 0 1 0.941461 0.230901 -0.245632 -108.312 0.251817 -0.966094 0.057012 94.4614 -0.224139 -0.115529 -0.967685 -155.279 0 0 0 1 0.911869 0.305652 -0.273991 -113.7 0.3293 -0.943211 0.043739 96.3018 -0.245062 -0.13011 -0.960737 -150.218 0 0 0 1 0.874645 0.382076 -0.298352 -117.16 0.407737 -0.912716 0.026472 99.1813 -0.262196 -0.144803 -0.954089 -145.622 0 0 0 1 0.829027 0.456225 -0.323378 -119.794 0.483894 -0.875107 0.005923 103.215 -0.280288 -0.161391 -0.946251 -140.598 0 0 0 1 0.776516 0.526723 -0.345812 -121.542 0.555737 -0.831161 -0.018081 107.867 -0.29695 -0.17814 -0.938129 -135.524 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.044008 0.999031 0 547.819 -0.999031 0.044008 0 0.000037 0 0 1 -0.000015 0 0 0 1 0.032261 0.999479 0 547.819 -0.999479 0.032261 0 -0.000081 0 0 1 -0.000015 0 0 0 1 0.020287 0.999794 0 547.819 -0.999794 0.020287 0 0.00005 0 0 1 -0.000015 0 0 0 1 0.010958 0.99994 0 547.819 -0.99994 0.010958 0 0.000008 0 0 1 -0.000015 0 0 0 1 -0.052769 0.998607 0 547.819 -0.998607 -0.052769 0 -0.000061 0 0 1 -0.000015 0 0 0 1 -0.097287 0.995256 0 547.819 -0.995256 -0.097287 0 -0.000032 0 0 1 -0.000015 0 0 0 1 -0.120776 0.99268 0 547.819 -0.99268 -0.120776 0 -0.000026 0 0 1 -0.000015 0 0 0 1 -0.122837 0.992427 0 547.819 -0.992427 -0.122837 0 0.000064 0 0 1 -0.000015 0 0 0 1 -0.106969 0.994262 0 547.819 -0.994262 -0.106969 0 0.000028 0 0 1 -0.000015 0 0 0 1 -0.075506 0.997145 0 547.819 -0.997145 -0.075506 0 -0.000038 0 0 1 -0.000015 0 0 0 1 -0.029777 0.999557 0 547.819 -0.999557 -0.029777 0 -0.000001 0 0 1 -0.000015 0 0 0 1 0.027946 0.999609 0 547.819 -0.999609 0.027946 0 0.000086 0 0 1 -0.000015 0 0 0 1 0.097664 0.995219 0 547.819 -0.995219 0.097664 0 -0.000004 0 0 1 -0.000015 0 0 0 1 0.178916 0.983864 0 547.819 -0.983864 0.178916 0 0.000017 0 0 1 -0.000015 0 0 0 1 0.269693 0.962946 0 547.819 -0.962946 0.269693 0 0.000044 0 0 1 -0.000015 0 0 0 1 0.371507 0.92843 0 547.819 -0.92843 0.371507 0 -0.000009 0 0 1 -0.000015 0 0 0 1 0.33859 0.940934 0 547.819 -0.940933 0.33859 0 -0.000002 0 0 1 -0.000015 0 0 0 1 0.315911 0.948789 0 547.819 -0.948789 0.315911 0 0.000004 0 0 1 -0.000015 0 0 0 1 0.283607 0.958941 0 547.819 -0.958941 0.283607 0 0.000029 0 0 1 -0.000015 0 0 0 1 0.213675 0.976904 0 547.819 -0.976904 0.213675 0 0.000017 0 0 1 -0.000015 0 0 0 1 0.063262 0.997997 0 547.819 -0.997997 0.063262 0 0.000009 0 0 1 -0.000015 0 0 0 1 -0.125102 0.992143 0 547.819 -0.992143 -0.125102 0 -0.000017 0 0 1 -0.000015 0 0 0 1 -0.26599 0.963976 0 547.819 -0.963976 -0.26599 0 -0.00002 0 0 1 -0.000015 0 0 0 1 -0.34606 0.938212 0 547.819 -0.938212 -0.34606 0 -0.000017 0 0 1 -0.000015 0 0 0 1 -0.383874 0.923385 0 547.819 -0.923385 -0.383874 0 -0.000006 0 0 1 -0.000015 0 0 0 1 -0.380476 0.924791 0 547.819 -0.924791 -0.380476 0 0.000033 0 0 1 -0.000015 0 0 0 1 -0.343814 0.939038 0 547.819 -0.939038 -0.343814 0 -0.000091 0 0 1 -0.000015 0 0 0 1 -0.278014 0.960577 0 547.819 -0.960577 -0.278014 0 0.000031 0 0 1 -0.000015 0 0 0 1 -0.188387 0.982095 0 547.819 -0.982095 -0.188387 0 -0.000022 0 0 1 -0.000015 0 0 0 1 -0.079894 0.996803 0 547.819 -0.996803 -0.079894 0 -0.000016 0 0 1 -0.000015 0 0 0 1 0.04401 0.999031 0 547.819 -0.999031 0.04401 0 0.000093 0 0 1 -0.000015 0 0 0 1 0.045618 0.998959 0 547.819 -0.998959 0.045618 0 -0.000038 0 0 1 -0.000015 0 0 0 1 0.037496 0.999297 0 547.819 -0.999297 0.037496 0 -0.000078 0 0 1 -0.000015 0 0 0 1 0.025623 0.999672 0 547.819 -0.999672 0.025623 0 0.000067 0 0 1 -0.000015 0 0 0 1 -0.043671 0.999046 0 547.819 -0.999046 -0.043671 0 -0.000151 0 0 1 -0.000015 0 0 0 1 -0.093962 0.995576 0 547.819 -0.995576 -0.093962 0 -0.000015 0 0 1 -0.000015 0 0 0 1 -0.120448 0.99272 0 547.819 -0.99272 -0.120448 0 -0.000126 0 0 1 -0.000015 0 0 0 1 -0.122837 0.992427 0 547.819 -0.992427 -0.122837 0 0.000025 0 0 1 -0.000015 0 0 0 1 -0.106969 0.994262 0 547.819 -0.994262 -0.10697 0 0.000049 0 0 1 -0.000015 0 0 0 1 -0.075265 0.997163 0 547.819 -0.997163 -0.075265 0 0.000008 0 0 1 -0.000015 0 0 0 1 -0.029778 0.999557 0 547.819 -0.999557 -0.029778 0 -0.000076 0 0 1 -0.000015 0 0 0 1 0.027946 0.999609 0 547.819 -0.999609 0.027946 0 0.000034 0 0 1 -0.000015 0 0 0 1 0.098135 0.995173 0 547.819 -0.995173 0.098135 0 0.000007 0 0 1 -0.000015 0 0 0 1 0.178913 0.983864 0 547.819 -0.983864 0.178913 0 0.000011 0 0 1 -0.000015 0 0 0 1 0.269693 0.962946 0 547.819 -0.962946 0.269693 0 0.000000 0 0 1 -0.000015 0 0 0 1 0.371507 0.92843 0 547.819 -0.92843 0.371507 0 -0.000027 0 0 1 -0.000015 0 0 0 1 0.33859 0.940934 0 547.819 -0.940934 0.33859 0 -0.000002 0 0 1 -0.000015 0 0 0 1 0.315911 0.948789 0 547.819 -0.948789 0.315911 0 0.000001 0 0 1 -0.000015 0 0 0 1 0.283608 0.95894 0 547.819 -0.95894 0.283608 0 -0.000031 0 0 1 -0.000015 0 0 0 1 0.213677 0.976905 0 547.819 -0.976905 0.213677 0 -0.000039 0 0 1 -0.000015 0 0 0 1 0.063263 0.997997 0 547.819 -0.997997 0.063263 0 -0.000000 0 0 1 -0.000015 0 0 0 1 -0.12407 0.992273 0 547.819 -0.992273 -0.12407 0 -0.00005 0 0 1 -0.000015 0 0 0 1 -0.265992 0.963975 0 547.819 -0.963975 -0.265992 0 0.000000 0 0 1 -0.000015 0 0 0 1 -0.34606 0.938212 0 547.819 -0.938212 -0.34606 0 0.000044 0 0 1 -0.000015 0 0 0 1 -0.383875 0.923385 0 547.819 -0.923385 -0.383875 0 0.000036 0 0 1 -0.000015 0 0 0 1 -0.380478 0.924791 0 547.819 -0.924791 -0.380478 0 0.000059 0 0 1 -0.000015 0 0 0 1 -0.343814 0.939038 0 547.819 -0.939038 -0.343814 0 -0.000025 0 0 1 -0.000015 0 0 0 1 -0.278015 0.960577 0 547.819 -0.960577 -0.278014 0 0.0001 0 0 1 -0.000015 0 0 0 1 -0.188385 0.982095 0 547.819 -0.982095 -0.188386 0 -0.000048 0 0 1 -0.000015 0 0 0 1 -0.079894 0.996803 0 547.819 -0.996803 -0.079894 0 0.000061 0 0 1 -0.000015 0 0 0 1 0.04401 0.999031 0 547.819 -0.999031 0.04401 0 0.000002 0 0 1 -0.000015 0 0 0 1 0.045619 0.998959 0 547.819 -0.998959 0.045619 0 0.000049 0 0 1 -0.000015 0 0 0 1 0.037496 0.999297 0 547.819 -0.999297 0.037496 0 -0.000101 0 0 1 -0.000015 0 0 0 1 0.025396 0.999678 0 547.819 -0.999678 0.025396 0 -0.000034 0 0 1 -0.000015 0 0 0 1 -0.043671 0.999046 0 547.819 -0.999046 -0.043672 0 0.000011 0 0 1 -0.000015 0 0 0 1 -0.093964 0.995576 0 547.819 -0.995576 -0.093964 0 -0.000051 0 0 1 -0.000015 0 0 0 1 -0.120449 0.99272 0 547.819 -0.99272 -0.120449 0 0.000002 0 0 1 -0.000015 0 0 0 1 -0.122838 0.992427 0 547.819 -0.992427 -0.122838 0 0.000053 0 0 1 -0.000015 0 0 0 1 -0.10697 0.994262 0 547.819 -0.994262 -0.10697 0 -0.000013 0 0 1 -0.000015 0 0 0 1 -0.075265 0.997163 0 547.819 -0.997163 -0.075265 0 -0.000054 0 0 1 -0.000015 0 0 0 1 -0.029779 0.999557 0 547.819 -0.999557 -0.029779 0 0.000045 0 0 1 -0.000015 0 0 0 1 0.027946 0.99961 0 547.819 -0.999609 0.027946 0 0.000045 0 0 1 -0.000015 0 0 0 1 0.097663 0.99522 0 547.819 -0.99522 0.097663 0 -0.000026 0 0 1 -0.000015 0 0 0 1 0.178915 0.983864 0 547.819 -0.983864 0.178915 0 0.000035 0 0 1 -0.000015 0 0 0 1 0.269693 0.962946 0 547.819 -0.962946 0.269693 0 0.000009 0 0 1 -0.000015 0 0 0 1 0.371507 0.92843 0 547.819 -0.92843 0.371507 0 -0.000023 0 0 1 -0.000015 0 0 0 1 0.338764 0.940872 0 547.819 -0.940872 0.338764 0 0.00001 0 0 1 -0.000015 0 0 0 1 0.31591 0.948789 0 547.819 -0.948789 0.31591 0 0.000005 0 0 1 -0.000015 0 0 0 1 0.283291 0.959035 0 547.819 -0.959035 0.283291 0 0.000001 0 0 1 -0.000015 0 0 0 1 0.213678 0.976904 0 547.819 -0.976904 0.213678 0 0.000015 0 0 1 -0.000015 0 0 0 1 0.063262 0.997997 0 547.819 -0.997997 0.063263 0 0.000054 0 0 1 -0.000015 0 0 0 1 -0.12407 0.992273 0 547.819 -0.992273 -0.12407 0 0.000009 0 0 1 -0.000015 0 0 0 1 -0.265304 0.964165 0 547.819 -0.964165 -0.265304 0 0.000074 0 0 1 -0.000015 0 0 0 1 -0.346061 0.938212 0 547.819 -0.938212 -0.346061 0 0.000071 0 0 1 -0.000015 0 0 0 1 -0.383875 0.923385 0 547.819 -0.923385 -0.383875 0 0.000034 0 0 1 -0.000015 0 0 0 1 -0.380478 0.92479 0 547.819 -0.924791 -0.380478 0 0.000031 0 0 1 -0.000015 0 0 0 1 -0.343814 0.939038 0 547.819 -0.939038 -0.343814 0 -0.000127 0 0 1 -0.000015 0 0 0 1 -0.278499 0.960437 0 547.819 -0.960437 -0.278499 0 -0.00011 0 0 1 -0.000015 0 0 0 1 -0.188384 0.982095 0 547.819 -0.982095 -0.188384 0 0.000015 0 0 1 -0.000015 0 0 0 1 -0.079894 0.996803 0 547.819 -0.996803 -0.079894 0 0.000027 0 0 1 -0.000015 0 0 0 1 0.044011 0.999031 0 547.819 -0.999031 0.044011 0 -0.00002 0 0 1 -0.000015 0 0 0 1 0.045619 0.998959 0 547.819 -0.998959 0.045619 0 -0.00001 0 0 1 -0.000015 0 0 0 1 0.037494 0.999297 0 547.819 -0.999297 0.037494 0 0.000013 0 0 1 -0.000015 0 0 0 1 0.025395 0.999678 0 547.819 -0.999678 0.025395 0 -0.000098 0 0 1 -0.000015 0 0 0 1 -0.043672 0.999046 0 547.819 -0.999046 -0.043672 0 -0.000038 0 0 1 -0.000015 0 0 0 1 -0.093964 0.995576 0 547.819 -0.995576 -0.093964 0 -0.000069 0 0 1 -0.000015 0 0 0 1 -0.120449 0.99272 0 547.819 -0.99272 -0.120449 0 0.00007 0 0 1 -0.000015 0 0 0 1 -0.122839 0.992427 0 547.819 -0.992427 -0.122839 0 -0.000018 0 0 1 -0.000015 0 0 0 1 -0.10697 0.994262 0 547.819 -0.994262 -0.10697 0 0.000004 0 0 1 -0.000015 0 0 0 1 -0.075265 0.997163 0 547.819 -0.997163 -0.075265 0 -0.000019 0 0 1 -0.000015 0 0 0 1 -0.029778 0.999557 0 547.819 -0.999557 -0.029778 0 0.000045 0 0 1 -0.000015 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.970553 -0.186579 0.152365 532.748 0.219338 0.945982 -0.238764 0.000041 -0.099587 0.265152 0.95905 -0.000002 0 0 0 1 0.948887 -0.269556 0.16418 532.748 0.303763 0.921189 -0.243182 0.000004 -0.085688 0.280624 0.955985 -0.000002 0 0 0 1 0.920379 -0.348564 0.177218 532.748 0.384412 0.889565 -0.246783 -0.000033 -0.071627 0.295259 0.952728 -0.000002 0 0 0 1 0.885424 -0.423656 0.191152 532.748 0.461272 0.851436 -0.249568 0.000011 -0.057023 0.309147 0.949303 -0.000002 0 0 0 1 0.833229 -0.513848 0.204178 532.748 0.549668 0.809815 -0.205098 0.000048 -0.059957 0.283123 0.957207 -0.000002 0 0 0 1 0.775894 -0.594066 0.212307 532.748 0.627298 0.762237 -0.159662 -0.000039 -0.066979 0.257061 0.964071 -0.000002 0 0 0 1 0.71603 -0.663788 0.216069 532.748 0.693676 0.711253 -0.113723 -0.00005 -0.078192 0.231311 0.969733 -0.000002 0 0 0 1 0.657321 -0.721889 0.216344 532.748 0.747814 0.660347 -0.068667 0.000002 -0.093291 0.206922 0.973899 -0.000002 0 0 0 1 0.603889 -0.768374 0.211943 532.748 0.78925 0.613591 -0.024306 -0.000025 -0.111369 0.181955 0.97698 -0.000002 0 0 0 1 0.557043 -0.805167 0.20349 532.748 0.819816 0.572272 0.020159 -0.000064 -0.132683 0.155595 0.97887 -0.000002 0 0 0 1 0.517523 -0.833161 0.194966 532.748 0.841213 0.537103 0.062296 -0.000018 -0.15662 0.131767 0.978829 -0.000002 0 0 0 1 0.485813 -0.853212 0.189778 532.748 0.855077 0.508931 0.099161 0.000013 -0.181189 0.114101 0.976807 -0.000002 0 0 0 1 0.460578 -0.867022 0.190105 532.748 0.86366 0.487173 0.129435 0.000001 -0.204837 0.104571 0.973194 -0.000002 0 0 0 1 0.441175 -0.875455 0.197339 532.748 0.868667 0.471805 0.151057 0.000031 -0.225349 0.104779 0.968627 -0.000002 0 0 0 1 0.427436 -0.878908 0.211704 532.748 0.871536 0.462841 0.161873 0.000007 -0.240257 0.115317 0.963835 -0.000002 0 0 0 1 0.419237 -0.877513 0.232833 532.748 0.873371 0.459847 0.16051 -0.000003 -0.247917 0.136058 0.959179 -0.000002 0 0 0 1 0.555868 -0.818359 0.145941 532.748 0.794155 0.574676 0.197647 0.000049 -0.245615 0.006034 0.969348 -0.000002 0 0 0 1 0.688609 -0.722542 0.061244 532.748 0.694145 0.681253 0.232503 -0.000003 -0.209716 -0.117592 0.970665 -0.000002 0 0 0 1 0.786131 -0.618 -0.008558 532.748 0.598161 0.757264 0.26221 0.000034 -0.155565 -0.211251 0.964973 -0.000002 0 0 0 1 0.827901 -0.558444 -0.052153 532.748 0.549255 0.788409 0.277003 -0.000008 -0.113572 -0.257977 0.959453 -0.000002 0 0 0 1 0.786425 -0.615057 -0.05692 532.748 0.605626 0.74967 0.266856 0.000042 -0.121461 -0.244334 0.962054 -0.000002 0 0 0 1 0.681583 -0.73136 -0.023623 532.748 0.713011 0.656532 0.246134 -0.000047 -0.164503 -0.184605 0.968948 -0.000002 0 0 0 1 0.593783 -0.804266 0.024057 532.748 0.78022 0.582823 0.227101 -0.000002 -0.196671 -0.116079 0.973574 -0.000002 0 0 0 1 0.544617 -0.834446 0.084213 532.748 0.812077 0.549766 0.195674 -0.000006 -0.209577 -0.038179 0.977046 -0.000002 0 0 0 1 0.522694 -0.838181 0.155702 532.748 0.828023 0.542603 0.141276 -0.000034 -0.202899 0.055081 0.977649 -0.000002 0 0 0 1 0.56308 -0.80004 0.207069 532.748 0.807276 0.586097 0.069249 -0.000002 -0.176765 0.128169 0.975872 -0.000002 0 0 0 1 0.653825 -0.720856 0.229955 532.748 0.741781 0.670607 -0.006886 -0.000024 -0.149245 0.175079 0.973177 -0.000002 0 0 0 1 0.756398 -0.610501 0.234843 532.748 0.641275 0.762891 -0.082239 0.000034 -0.128952 0.212804 0.968549 -0.000002 0 0 0 1 0.850125 -0.477326 0.222366 532.748 0.513359 0.845294 -0.148127 0.000003 -0.11726 0.24008 0.963645 -0.000002 0 0 0 1 0.922903 -0.332235 0.194604 532.748 0.369009 0.907498 -0.200699 -0.00004 -0.109924 0.257036 0.96013 -0.000002 0 0 0 1 0.970529 -0.186513 0.152597 532.748 0.219361 0.945917 -0.239 0.000007 -0.099767 0.26543 0.958954 -0.000002 0 0 0 1 0.946982 -0.263653 0.183607 532.748 0.305529 0.915766 -0.260813 0.000044 -0.099376 0.303083 0.947768 -0.000002 0 0 0 1 0.918003 -0.340202 0.203799 532.748 0.386796 0.881505 -0.27081 0.000003 -0.08752 0.327432 0.940812 -0.000002 0 0 0 1 0.883291 -0.415824 0.216534 532.748 0.463661 0.843167 -0.272191 -0.000059 -0.06939 0.340822 0.937563 -0.000002 0 0 0 1 0.8312 -0.508691 0.224363 532.748 0.551852 0.803917 -0.221758 0.000007 -0.067563 0.30814 0.948939 -0.000002 0 0 0 1 0.774196 -0.591751 0.224611 532.748 0.62903 0.758744 -0.169203 -0.000037 -0.070296 0.272283 0.959646 -0.000002 0 0 0 1 0.715151 -0.663081 0.221096 532.748 0.694494 0.709828 -0.11757 0.000029 -0.078981 0.23763 0.968139 -0.000002 0 0 0 1 0.657129 -0.721457 0.218362 532.748 0.747979 0.659978 -0.070396 0.00002 -0.093325 0.209589 0.973326 -0.000002 0 0 0 1 0.603637 -0.76796 0.214148 532.748 0.789469 0.61323 -0.026227 -0.000038 -0.11118 0.184895 0.976449 -0.000002 0 0 0 1 0.556467 -0.805009 0.205682 532.748 0.820252 0.571707 0.018406 0.000043 -0.132408 0.158468 0.978445 -0.000002 0 0 0 1 0.517179 -0.832869 0.197114 532.748 0.841537 0.536826 0.06027 0.000016 -0.156013 0.134708 0.978526 -0.000002 0 0 0 1 0.485458 -0.852986 0.191693 532.748 0.855432 0.508704 0.097245 -0.000004 -0.180463 0.116772 0.976626 -0.000002 0 0 0 1 0.460111 -0.866917 0.191709 532.748 0.864055 0.486877 0.127909 0.000002 -0.204225 0.106795 0.973081 -0.000002 0 0 0 1 0.440919 -0.875338 0.198431 532.748 0.868965 0.471663 0.149775 0.00001 -0.224696 0.10639 0.968603 -0.000002 0 0 0 1 0.427293 -0.878841 0.212273 532.748 0.871719 0.462752 0.161139 0.000001 -0.239846 0.116189 0.963833 -0.000002 0 0 0 1 0.419236 -0.877513 0.232833 532.748 0.873371 0.459846 0.16051 0.000005 -0.247918 0.136058 0.959179 -0.000002 0 0 0 1 0.555867 -0.818359 0.145946 532.748 0.794159 0.574675 0.19764 0.000053 -0.245612 0.006042 0.96935 -0.000002 0 0 0 1 0.688605 -0.722544 0.061257 532.748 0.694149 0.681254 0.232484 -0.000001 -0.209712 -0.117568 0.970669 -0.000002 0 0 0 1 0.786129 -0.618004 -0.008541 532.748 0.598165 0.757269 0.262189 -0.000013 -0.155565 -0.211224 0.964979 -0.000002 0 0 0 1 0.827902 -0.558444 -0.052153 532.748 0.549255 0.788409 0.277003 -0.000038 -0.113572 -0.257977 0.959453 -0.000002 0 0 0 1 0.786434 -0.615039 -0.056993 532.748 0.605617 0.74965 0.266932 0.000048 -0.121449 -0.24444 0.962029 -0.000002 0 0 0 1 0.682231 -0.730741 -0.024073 532.748 0.712448 0.657034 0.246421 -0.000044 -0.164253 -0.185267 0.968864 -0.000002 0 0 0 1 0.593835 -0.804235 0.023787 532.748 0.780181 0.582798 0.2273 -0.000011 -0.196665 -0.116421 0.973534 -0.000002 0 0 0 1 0.544661 -0.834438 0.084005 532.748 0.812048 0.549759 0.195813 -0.000041 -0.209577 -0.038435 0.977036 -0.000002 0 0 0 1 0.522723 -0.838104 0.15602 532.748 0.82803 0.542678 0.140948 0.000034 -0.202797 0.055512 0.977646 -0.000002 0 0 0 1 0.563079 -0.80004 0.207069 532.748 0.807277 0.586095 0.06925 -0.000006 -0.176766 0.128168 0.975872 -0.000002 0 0 0 1 0.653829 -0.720859 0.229934 532.748 0.741778 0.67061 -0.006872 0.000000 -0.149242 0.175054 0.973182 -0.000002 0 0 0 1 0.756407 -0.610517 0.234771 532.748 0.641268 0.762902 -0.082188 -0.000033 -0.12893 0.212719 0.96857 -0.000002 0 0 0 1 0.850142 -0.477358 0.222233 532.748 0.513345 0.845321 -0.148021 -0.000014 -0.117198 0.239921 0.963692 -0.000002 0 0 0 1 0.922925 -0.332285 0.194413 532.748 0.368988 0.907544 -0.200528 -0.000013 -0.109806 0.256809 0.960204 -0.000002 0 0 0 1 0.970554 -0.186577 0.152365 532.748 0.219336 0.945983 -0.238763 -0.000043 -0.099587 0.265152 0.95905 -0.000002 0 0 0 1 0.947158 -0.263207 0.183339 532.748 0.304999 0.91599 -0.260649 0.000002 -0.099332 0.302794 0.947865 -0.000002 0 0 0 1 0.917995 -0.340175 0.203875 532.748 0.386804 0.881478 -0.270887 -0.000029 -0.087563 0.327533 0.940774 -0.000002 0 0 0 1 0.883004 -0.416245 0.216895 532.748 0.464197 0.842836 -0.272305 -0.000008 -0.06946 0.341127 0.937447 -0.000002 0 0 0 1 0.831185 -0.508618 0.224585 532.748 0.551865 0.803851 -0.221965 0.000003 -0.067638 0.308434 0.948837 -0.000002 0 0 0 1 0.77418 -0.591693 0.224822 532.748 0.629044 0.75869 -0.169387 0.000002 -0.070345 0.272559 0.959564 -0.000002 0 0 0 1 0.715134 -0.663034 0.22129 532.748 0.694508 0.709786 -0.117737 -0.000006 -0.079005 0.237886 0.968075 -0.000002 0 0 0 1 0.657112 -0.721419 0.218536 532.748 0.747993 0.659946 -0.070546 0.000015 -0.093328 0.20982 0.973276 -0.000002 0 0 0 1 0.603619 -0.767932 0.214301 532.748 0.789485 0.613204 -0.026359 -0.000041 -0.111168 0.185098 0.976412 -0.000002 0 0 0 1 0.556449 -0.804989 0.205811 532.748 0.820267 0.571688 0.018292 -0.000045 -0.132384 0.158642 0.978421 -0.000002 0 0 0 1 0.517164 -0.832855 0.197218 532.748 0.841553 0.536813 0.060172 -0.000003 -0.155984 0.13485 0.978511 -0.000002 0 0 0 1 0.485442 -0.852976 0.191773 532.748 0.855447 0.508694 0.097165 0.000006 -0.180433 0.116884 0.976618 -0.000002 0 0 0 1 0.460238 -0.866847 0.19172 532.748 0.864026 0.486983 0.127698 -0.000043 -0.204059 0.10688 0.973107 -0.000002 0 0 0 1 0.440911 -0.875333 0.198467 532.748 0.868975 0.471658 0.149734 0.000057 -0.224676 0.106444 0.968602 -0.000002 0 0 0 1 0.427289 -0.878838 0.21229 532.748 0.871725 0.462749 0.161118 0.000003 -0.239833 0.116215 0.963833 -0.000002 0 0 0 1 0.419235 -0.877514 0.232833 532.748 0.873372 0.459846 0.160511 0.00004 -0.247918 0.136058 0.959179 -0.000002 0 0 0 1 0.555047 -0.81884 0.146369 532.748 0.794707 0.573983 0.197444 0.000006 -0.245688 0.00673 0.969326 -0.000002 0 0 0 1 0.688635 -0.722527 0.061118 532.748 0.694109 0.681232 0.232672 -0.000006 -0.209748 -0.117803 0.970633 -0.000002 0 0 0 1 0.786579 -0.617422 -0.009081 532.748 0.597651 0.757528 0.26261 -0.000004 -0.155261 -0.211991 0.964859 -0.000002 0 0 0 1 0.827926 -0.558387 -0.052364 532.748 0.549224 0.78834 0.277258 -0.000003 -0.113536 -0.25831 0.959367 -0.000002 0 0 0 1 0.786448 -0.615012 -0.057099 532.748 0.605603 0.749623 0.267041 -0.000000 -0.121431 -0.244593 0.961992 -0.000002 0 0 0 1 0.682212 -0.730762 -0.023961 532.748 0.712464 0.657053 0.246326 -0.000055 -0.164261 -0.185118 0.968891 -0.000002 0 0 0 1 0.594218 -0.803954 0.023721 532.748 0.779923 0.583162 0.227249 -0.000056 -0.196531 -0.116535 0.973548 -0.000002 0 0 0 1 0.544611 -0.834447 0.084241 532.748 0.812081 0.549766 0.195656 -0.000031 -0.209578 -0.038145 0.977048 -0.000002 0 0 0 1 0.522702 -0.838099 0.156118 532.748 0.828043 0.542675 0.140885 0.000011 -0.202797 0.05563 0.977639 -0.000002 0 0 0 1 0.563079 -0.80004 0.207069 532.748 0.807277 0.586095 0.069251 0.000064 -0.176766 0.128168 0.975872 -0.000002 0 0 0 1 0.653833 -0.720863 0.229913 532.748 0.741775 0.670613 -0.006859 -0.000045 -0.149239 0.175028 0.973187 -0.000002 0 0 0 1 0.755789 -0.611281 0.234775 532.748 0.641978 0.762355 -0.081727 -0.000006 -0.129023 0.212488 0.968608 -0.000002 0 0 0 1 0.850146 -0.477359 0.222217 532.748 0.513341 0.845325 -0.148011 0.000058 -0.117192 0.239904 0.963697 -0.000002 0 0 0 1 0.922925 -0.332286 0.194409 532.748 0.368988 0.907545 -0.200524 0.000018 -0.109803 0.256803 0.960206 -0.000002 0 0 0 1 0.970554 -0.186576 0.152364 532.748 0.219335 0.945983 -0.238763 -0.000005 -0.099587 0.265151 0.95905 -0.000002 0 0 0 1 0.947166 -0.263231 0.183263 532.748 0.304991 0.916015 -0.260572 -0.000004 -0.099281 0.302698 0.947901 -0.000002 0 0 0 1 0.91801 -0.340228 0.203723 532.748 0.38679 0.881531 -0.270733 0.000008 -0.087477 0.327333 0.940851 -0.000002 0 0 0 1 0.883021 -0.416329 0.216666 532.748 0.464181 0.842919 -0.272076 -0.000051 -0.069359 0.34082 0.937566 -0.000002 0 0 0 1 0.831202 -0.508698 0.224343 532.748 0.55185 0.803923 -0.22174 -0.000028 -0.067557 0.308114 0.948947 -0.000002 0 0 0 1 0.774199 -0.591763 0.22457 532.748 0.629027 0.758754 -0.169166 -0.000029 -0.070287 0.272229 0.959662 -0.000002 0 0 0 1 0.715156 -0.663097 0.221033 532.748 0.694489 0.709841 -0.117516 -0.000023 -0.078974 0.237547 0.96816 -0.000002 0 0 0 1 0.657486 -0.72115 0.218299 532.748 0.747677 0.660298 -0.070607 0.00005 -0.093224 0.209641 0.973324 -0.000002 0 0 0 1 0.603649 -0.767981 0.214041 532.748 0.789458 0.613248 -0.026134 -0.000019 -0.11119 0.184752 0.976475 -0.000002 0 0 0 1 0.556485 -0.80503 0.205554 532.748 0.820235 0.571726 0.018523 0.000019 -0.132432 0.158296 0.978471 -0.000002 0 0 0 1 0.517203 -0.832889 0.196968 532.748 0.841515 0.536846 0.060408 -0.000025 -0.156055 0.134507 0.978547 -0.000002 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.099612 -0.992857 0.06567 214.572 0.994956 0.100175 0.005319 189.364 -0.011859 0.06481 0.997827 -0.000000 0 0 0 1 0.087659 -0.995243 0.042507 214.572 0.996111 0.087954 0.005134 189.363 -0.008848 0.041891 0.999083 -0.000000 0 0 0 1 0.012528 -0.999665 0.022639 214.572 0.999919 0.012478 -0.002291 189.363 0.002007 0.022666 0.999741 -0.000000 0 0 0 1 0 -1 0 214.572 1 0 0 189.363 0 0 1 -0.000000 0 0 0 1 0.000502 -1 0.000576 214.572 0.999997 0.000501 -0.002317 189.363 0.002316 0.000578 0.999997 -0.000000 0 0 0 1 0.000751 -0.999999 0.000863 214.572 0.999994 0.000748 -0.003467 189.363 0.003467 0.000865 0.999994 -0.000000 0 0 0 1 0.00078 -0.999999 0.000897 214.572 0.999993 0.000778 -0.003602 189.363 0.003601 0.000899 0.999993 -0.000000 0 0 0 1 0.000626 -0.999999 0.00072 214.572 0.999996 0.000624 -0.002893 189.363 0.002892 0.000722 0.999996 -0.000000 0 0 0 1 0.000346 -1 0.000399 214.572 0.999999 0.000347 -0.001603 189.363 0.001603 0.000399 0.999999 -0.000000 0 0 0 1 0 -1 0 214.572 1 0 0 189.363 0 0 1 -0.000000 0 0 0 1 -0.000348 -1 -0.000402 214.572 0.999999 -0.000348 0.001612 189.363 -0.001611 -0.000401 0.999999 -0.000000 0 0 0 1 -0.000625 -1 -0.000723 214.572 0.999996 -0.000627 0.002898 189.363 -0.002899 -0.000721 0.999996 -0.000000 0 0 0 1 -0.000778 -0.999999 -0.000898 214.572 0.999993 -0.00078 0.003601 189.363 -0.003603 -0.000895 0.999993 -0.000000 0 0 0 1 -0.000748 -0.999999 -0.000865 214.572 0.999994 -0.000751 0.003465 189.363 -0.003465 -0.000862 0.999994 -0.000000 0 0 0 1 -0.000497 -1 -0.000575 214.572 0.999997 -0.000499 0.002306 189.363 -0.002307 -0.000574 0.999997 -0.000000 0 0 0 1 0 -1 0 214.572 1 0 0 189.363 0 0 1 -0.000000 0 0 0 1 -0.138293 -0.986714 0.085274 214.572 0.989429 -0.141441 -0.032007 189.363 0.043644 0.079945 0.995843 -0.000000 0 0 0 1 -0.246647 -0.959946 0.132926 214.572 0.968225 -0.249938 -0.008402 189.363 0.041289 0.12663 0.99109 -0.000000 0 0 0 1 -0.33596 -0.929348 0.15311 214.572 0.941364 -0.336674 0.022027 189.363 0.031076 0.151532 0.987964 -0.000000 0 0 0 1 -0.404434 -0.896978 0.178506 214.572 0.913126 -0.406986 0.023763 189.363 0.051334 0.172609 0.983652 -0.000000 0 0 0 1 -0.148506 -0.966402 0.209795 214.572 0.988877 -0.146889 0.023355 189.363 0.008245 0.21093 0.977466 -0.000000 0 0 0 1 0.449508 -0.866437 0.217325 214.572 0.88623 0.46306 0.013089 189.363 -0.111976 0.186716 0.976012 -0.000000 0 0 0 1 0.736266 -0.653687 0.17494 214.572 0.66178 0.749537 0.015529 189.363 -0.141275 0.104339 0.984457 -0.000000 0 0 0 1 0.75428 -0.643924 0.128155 214.572 0.646992 0.762188 0.021682 189.363 -0.11164 0.066561 0.991517 -0.000000 0 0 0 1 0.72232 -0.685118 0.094165 214.572 0.687996 0.72571 0.002589 189.363 -0.07011 0.062915 0.995553 -0.000000 0 0 0 1 0.714382 -0.696681 0.065531 214.572 0.69792 0.716156 0.00537 189.363 -0.050671 0.041898 0.997836 -0.000000 0 0 0 1 0.682351 -0.729387 0.048897 214.572 0.729522 0.68371 0.018392 189.363 -0.046846 0.023122 0.998635 -0.000000 0 0 0 1 0.546643 -0.836067 0.046624 214.572 0.836327 0.54789 0.019298 189.363 -0.04168 0.028444 0.998726 -0.000000 0 0 0 1 0.347758 -0.936081 0.053078 214.572 0.937063 0.348895 0.013617 189.364 -0.031266 0.045002 0.998498 -0.000000 0 0 0 1 0.170955 -0.983343 0.061735 214.572 0.985119 0.171721 0.007284 189.363 -0.017764 0.059571 0.998066 -0.000000 0 0 0 1 0.099612 -0.992857 0.065671 214.572 0.994955 0.100175 0.005318 189.363 -0.011859 0.06481 0.997827 -0.000000 0 0 0 1 0.087657 -0.995243 0.042506 214.572 0.996111 0.087953 0.005134 189.363 -0.008847 0.041891 0.999083 -0.000000 0 0 0 1 0.012527 -0.999665 0.022639 214.572 0.999919 0.012478 -0.002291 189.363 0.002007 0.022666 0.999741 -0.000000 0 0 0 1 0 -1 0 214.572 1 0 0 189.363 0 0 1 -0.000000 0 0 0 1 0.000502 -1 0.000576 214.572 0.999997 0.0005 -0.002317 189.363 0.002316 0.000578 0.999997 -0.000000 0 0 0 1 0.000751 -0.999999 0.000863 214.572 0.999994 0.000748 -0.003467 189.363 0.003467 0.000865 0.999994 -0.000000 0 0 0 1 0.000781 -0.999999 0.000896 214.572 0.999993 0.000778 -0.003602 189.363 0.003601 0.000899 0.999993 -0.000000 0 0 0 1 0.000626 -0.999999 0.00072 214.572 0.999995 0.000624 -0.002892 189.363 0.002892 0.000722 0.999996 -0.000000 0 0 0 1 0.000346 -1 0.000398 214.572 0.999999 0.000347 -0.001603 189.363 0.001603 0.000399 0.999999 -0.000000 0 0 0 1 -0.000002 -1 -0.000002 214.572 1 -0.000002 0.00001 189.363 -0.00001 -0.000002 1 -0.000000 0 0 0 1 -0.000347 -1 -0.000402 214.572 0.999999 -0.000348 0.001612 189.363 -0.001611 -0.000401 0.999999 -0.000000 0 0 0 1 -0.000625 -0.999999 -0.000723 214.572 0.999995 -0.000627 0.002899 189.363 -0.002899 -0.000721 0.999996 -0.000000 0 0 0 1 -0.000778 -0.999999 -0.000898 214.572 0.999993 -0.000781 0.003601 189.363 -0.003603 -0.000895 0.999993 -0.000000 0 0 0 1 -0.000748 -0.999999 -0.000865 214.572 0.999994 -0.000751 0.003464 189.363 -0.003465 -0.000862 0.999994 -0.000000 0 0 0 1 -0.000497 -1 -0.000575 214.572 0.999997 -0.0005 0.002305 189.363 -0.002306 -0.000574 0.999997 -0.000000 0 0 0 1 0 -1 0 214.572 1 0 0 189.363 0 0 1 -0.000000 0 0 0 1 -0.138294 -0.986714 0.085274 214.572 0.989429 -0.141441 -0.032007 189.363 0.043644 0.079945 0.995843 -0.000000 0 0 0 1 -0.246647 -0.959946 0.132926 214.572 0.968225 -0.249938 -0.008402 189.363 0.041289 0.12663 0.99109 -0.000000 0 0 0 1 -0.335959 -0.929349 0.15311 214.572 0.941364 -0.336674 0.022027 189.363 0.031077 0.151532 0.987964 -0.000000 0 0 0 1 -0.404434 -0.896978 0.178506 214.572 0.913126 -0.406986 0.023764 189.363 0.051334 0.172609 0.983652 -0.000000 0 0 0 1 -0.148506 -0.966402 0.209795 214.572 0.988877 -0.146889 0.023355 189.363 0.008245 0.21093 0.977467 -0.000000 0 0 0 1 0.446783 -0.867833 0.217371 214.572 0.887665 0.4603 0.013199 189.363 -0.111511 0.187055 0.976 -0.000000 0 0 0 1 0.736266 -0.653688 0.174939 214.572 0.66178 0.749537 0.01553 189.363 -0.141275 0.104337 0.984457 -0.000000 0 0 0 1 0.754279 -0.643925 0.128155 214.572 0.646992 0.762188 0.021682 189.363 -0.11164 0.066561 0.991517 -0.000000 0 0 0 1 0.722192 -0.685279 0.093975 214.572 0.68815 0.725563 0.002531 189.363 -0.069919 0.062841 0.995571 -0.000000 0 0 0 1 0.714382 -0.69668 0.065531 214.572 0.697919 0.716157 0.00537 189.363 -0.050672 0.041899 0.997836 -0.000000 0 0 0 1 0.682351 -0.729388 0.048897 214.572 0.729522 0.68371 0.018392 189.363 -0.046846 0.023121 0.998635 -0.000000 0 0 0 1 0.546643 -0.836067 0.046624 214.572 0.836327 0.54789 0.019298 189.363 -0.04168 0.028444 0.998726 -0.000000 0 0 0 1 0.347758 -0.936081 0.053078 214.572 0.937063 0.348895 0.013617 189.363 -0.031266 0.045002 0.998498 -0.000000 0 0 0 1 0.170955 -0.983343 0.061735 214.572 0.985119 0.171721 0.007284 189.364 -0.017764 0.059571 0.998066 -0.000000 0 0 0 1 0.099612 -0.992857 0.06567 214.572 0.994956 0.100175 0.005319 189.363 -0.011859 0.06481 0.997827 -0.000000 0 0 0 1 0.087879 -0.995218 0.042643 214.572 0.996091 0.088177 0.005157 189.364 -0.008891 0.042023 0.999077 -0.000000 0 0 0 1 0.012527 -0.999665 0.022639 214.572 0.999919 0.012478 -0.002291 189.363 0.002007 0.022666 0.999741 -0.000000 0 0 0 1 0 -1 0 214.572 1 0 -0.000000 189.363 0.000000 0 1 -0.000000 0 0 0 1 0.000502 -1 0.000576 214.572 0.999997 0.000501 -0.002317 189.363 0.002316 0.000578 0.999997 -0.000000 0 0 0 1 0.000751 -0.999999 0.000863 214.572 0.999994 0.000748 -0.003467 189.363 0.003467 0.000865 0.999994 -0.000000 0 0 0 1 0.000781 -0.999999 0.000896 214.572 0.999993 0.000777 -0.003602 189.364 0.003601 0.000899 0.999993 -0.000000 0 0 0 1 0.000626 -0.999999 0.00072 214.572 0.999995 0.000624 -0.002892 189.364 0.002892 0.000722 0.999996 -0.000000 0 0 0 1 0.000346 -1 0.000399 214.572 0.999999 0.000347 -0.001603 189.363 0.001603 0.000399 0.999999 -0.000000 0 0 0 1 -0.000002 -1 -0.000002 214.572 1 -0.000002 0.00001 189.363 -0.00001 -0.000002 1 -0.000000 0 0 0 1 -0.000347 -1 -0.000402 214.572 0.999999 -0.000348 0.001612 189.363 -0.001611 -0.000401 0.999999 -0.000000 0 0 0 1 -0.000625 -1 -0.000723 214.572 0.999996 -0.000627 0.002898 189.363 -0.002899 -0.000721 0.999996 -0.000000 0 0 0 1 -0.000778 -0.999999 -0.000898 214.572 0.999993 -0.00078 0.003602 189.363 -0.003603 -0.000895 0.999993 -0.000000 0 0 0 1 -0.000748 -0.999999 -0.000865 214.572 0.999994 -0.000751 0.003464 189.363 -0.003465 -0.000862 0.999994 -0.000000 0 0 0 1 -0.000497 -1 -0.000575 214.572 0.999997 -0.0005 0.002305 189.363 -0.002306 -0.000574 0.999997 -0.000000 0 0 0 1 0 -1 0 214.572 1 0 0 189.363 0 0 1 -0.000000 0 0 0 1 -0.137523 -0.986857 0.084857 214.572 0.989536 -0.14066 -0.03213 189.363 0.043644 0.079551 0.995875 -0.000000 0 0 0 1 -0.246647 -0.959946 0.132926 214.572 0.968225 -0.249938 -0.008402 189.363 0.041289 0.12663 0.99109 -0.000000 0 0 0 1 -0.336456 -0.929149 0.153233 214.572 0.941187 -0.337161 0.022154 189.363 0.031079 0.151675 0.987942 -0.000000 0 0 0 1 -0.404434 -0.896978 0.178505 214.572 0.913126 -0.406986 0.023763 189.363 0.051334 0.172608 0.983652 -0.000000 0 0 0 1 -0.148506 -0.966402 0.209795 214.572 0.988877 -0.146889 0.023355 189.363 0.008245 0.21093 0.977466 -0.000000 0 0 0 1 0.446783 -0.867833 0.217371 214.572 0.887665 0.4603 0.013199 189.363 -0.111511 0.187055 0.976 -0.000000 0 0 0 1 0.736007 -0.653914 0.175184 214.572 0.662068 0.749287 0.015314 189.363 -0.141277 0.104713 0.984417 -0.000000 0 0 0 1 0.75428 -0.643924 0.128155 214.572 0.646992 0.762188 0.021682 189.363 -0.11164 0.066561 0.991517 -0.000000 0 0 0 1 0.722192 -0.685279 0.093975 214.572 0.68815 0.725564 0.00253 189.363 -0.069919 0.062841 0.995571 -0.000000 0 0 0 1 0.714382 -0.69668 0.065531 214.572 0.697919 0.716157 0.00537 189.363 -0.050672 0.041899 0.997836 -0.000000 0 0 0 1 0.682351 -0.729388 0.048897 214.572 0.729522 0.68371 0.018391 189.363 -0.046846 0.023122 0.998634 -0.000000 0 0 0 1 0.54768 -0.835388 0.046618 214.572 0.835646 0.548928 0.019319 189.363 -0.041729 0.028376 0.998726 -0.000000 0 0 0 1 0.347754 -0.936082 0.053078 214.572 0.937064 0.348891 0.013617 189.363 -0.031264 0.045002 0.998498 -0.000000 0 0 0 1 0.170955 -0.983343 0.061735 214.572 0.985119 0.171721 0.007284 189.363 -0.017763 0.059571 0.998066 -0.000000 0 0 0 1 0.099612 -0.992857 0.06567 214.572 0.994956 0.100175 0.005318 189.363 -0.011859 0.06481 0.997827 -0.000000 0 0 0 1 0.087879 -0.995218 0.042643 214.572 0.996091 0.088177 0.005157 189.363 -0.008891 0.042023 0.999077 -0.000000 0 0 0 1 0.012528 -0.999665 0.022639 214.572 0.999919 0.012478 -0.002291 189.363 0.002007 0.022666 0.999741 -0.000000 0 0 0 1 0 -1 0 214.572 1 0 -0.000000 189.363 0.000000 0 1 -0.000000 0 0 0 1 0.000502 -1 0.000576 214.572 0.999997 0.000501 -0.002317 189.363 0.002316 0.000578 0.999997 -0.000000 0 0 0 1 0.000751 -0.999999 0.000863 214.572 0.999994 0.000748 -0.003467 189.363 0.003467 0.000865 0.999994 -0.000000 0 0 0 1 0.000781 -0.999999 0.000896 214.572 0.999993 0.000777 -0.003602 189.363 0.003601 0.000899 0.999993 -0.000000 0 0 0 1 0.000628 -0.999999 0.000721 214.572 0.999995 0.000626 -0.002898 189.363 0.002898 0.000723 0.999996 -0.000000 0 0 0 1 0.000346 -1 0.000399 214.572 0.999999 0.000347 -0.001603 189.363 0.001603 0.000399 0.999999 -0.000000 0 0 0 1 -0.000002 -1 -0.000002 214.572 1 -0.000002 0.00001 189.363 -0.00001 -0.000002 1 -0.000000 0 0 0 1 -0.000347 -1 -0.000402 214.572 0.999999 -0.000348 0.001612 189.364 -0.001611 -0.000401 0.999999 -0.000000 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.910453 -0.384975 0.402477 179.053 0.30073 -1.01613 -1.53964 1051.53 -0.260873 0.124214 -9.62368 -104.193 0 0 0 1 0.648858 -0.360821 0.61613 175.185 0.271803 -0.962082 0.11372 1031.61 -0.211723 -0.117182 -8.26376 -114.317 0 0 0 1 0.176574 -0.262541 0.926457 165.365 0.242434 -0.502321 1.96218 981.015 -0.044593 -0.38357 -4.01832 -140.021 0 0 0 1 -0.446997 -0.095791 -0.199082 151.879 0.200351 -0.022726 -0.443051 911.534 0.006307 -0.109259 0.234917 -175.322 0 0 0 1 -1.04732 -0.238015 -2.97457 137.097 0.300034 -0.154463 -5.17388 835.378 -0.351485 0.470857 -1.4152 -214.015 0 0 0 1 -1.24046 -0.795655 -3.39659 123.699 0.702861 -0.685794 -6.78413 766.351 -1.04989 0.532245 -8.22715 -249.085 0 0 0 1 -0.908886 -1.32796 -0.435691 113.836 1.21267 -1.00164 -5.80734 715.537 -1.68371 0.084808 -13.7258 -274.902 0 0 0 1 -0.422741 -1.65352 1.01547 110.012 1.44037 -0.904542 -5.41289 695.835 -1.97949 -0.167805 -15.3879 -284.912 0 0 0 1 -0.226803 -1.69631 -2.38748 111.874 1.51666 -0.348406 -4.96641 708.039 -1.67754 0.016921 -14.387 -277.042 0 0 0 1 -0.024014 -1.28152 -7.01882 116.783 1.46741 0.256682 -1.22331 740.217 -1.0967 0.439736 -10.7638 -256.293 0 0 0 1 0.242093 -0.525365 -7.25355 123.77 1.15075 0.341319 3.58182 786.016 -0.426708 0.65148 -4.67334 -226.762 0 0 0 1 0.302598 -0.074413 -3.50626 131.68 0.545299 0.059451 3.96738 837.861 -0.006527 0.372537 0.224563 -193.331 0 0 0 1 -0.009593 -0.023096 -0.516336 139.636 0.023819 0.094143 0.864751 890.011 0.025722 -0.09608 0.702781 -159.703 0 0 0 1 -0.462824 -0.022515 0.780665 146.613 -0.130008 0.508005 -0.894984 935.747 -0.169749 -0.266856 -2.0134 -130.212 0 0 0 1 -0.788106 0.005495 1.7881 151.485 -0.05507 0.872498 -0.486142 967.682 -0.354501 -0.127435 -4.47273 -109.619 0 0 0 1 -0.914162 0.000022 2.34923 153.347 0.002202 0.999986 0.02847 979.888 -0.405341 0.005384 -5.29806 -101.749 0 0 0 1 -0.757911 0.006198 1.67509 145.943 -0.078218 0.869456 -0.607136 967.063 -0.32719 -0.159947 -4.25317 -107.298 0 0 0 1 -0.346132 -0.046239 0.561107 127.141 -0.126635 0.489056 -0.774296 934.5 -0.107804 -0.338599 -1.28929 -121.387 0 0 0 1 0.138864 -0.095234 -1.34655 101.319 0.191241 0.076596 1.91459 889.779 -0.003339 -0.164955 0.93743 -140.736 0 0 0 1 0.32074 -0.281899 -5.52411 73.0169 0.782837 0.006852 3.93697 840.761 -0.311901 0.249606 -1.944 -161.944 0 0 0 1 0.229284 -0.829048 -7.25778 47.3641 1.14371 -0.055379 0.123079 796.333 -0.909124 0.372412 -8.44063 -181.167 0 0 0 1 0.156002 -1.26625 -3.01331 28.3979 1.25128 -0.566724 -4.4632 763.485 -1.39545 0.144582 -13.0871 -195.379 0 0 0 1 0.057507 -1.32112 0.740967 21.1577 1.17195 -1.09284 -5.20293 750.946 -1.59323 0.009318 -14.3655 -200.804 0 0 0 1 -0.391328 -0.870366 -0.123553 27.942 1.19687 -1.10665 -5.4527 763.861 -1.4987 0.134905 -13.1402 -196.653 0 0 0 1 -0.852102 -0.419329 -2.58132 45.8286 0.868525 -0.791206 -6.31404 797.911 -1.1892 0.347741 -9.12847 -185.709 0 0 0 1 -0.987843 -0.051929 -3.15262 71.2863 0.441179 -0.33195 -5.77781 846.375 -0.672368 0.277686 -3.25322 -170.132 0 0 0 1 -0.713768 0.03978 -1.25563 100.105 0.203253 -0.099143 -2.468 901.238 -0.201187 -0.122885 0.321892 -152.499 0 0 0 1 -0.206399 -0.120097 0.592502 129.264 0.189799 -0.319449 1.28125 956.748 -0.006036 -0.466528 -1.13988 -134.658 0 0 0 1 0.299868 -0.302601 0.905288 154.517 0.248662 -0.776829 1.85131 1004.82 -0.079424 -0.391888 -5.49085 -119.207 0 0 0 1 0.683595 -0.36497 0.572369 172.269 0.276896 -1.03805 -0.232361 1038.62 -0.215765 -0.065415 -8.65318 -108.345 0 0 0 1 0.910452 -0.384975 0.402475 179.053 0.30073 -1.01613 -1.53964 1051.53 -0.260875 0.124214 -9.62369 -104.193 0 0 0 1 0.909914 -0.384779 0.381821 179.053 0.300681 -1.01611 -1.53918 1051.53 -0.262803 0.124984 -9.6246 -104.193 0 0 0 1 0.909423 -0.384724 0.36136 179.053 0.30051 -1.01604 -1.53871 1051.53 -0.26469 0.125732 -9.62546 -104.193 0 0 0 1 0.90897 -0.384806 0.340709 179.053 0.300218 -1.01591 -1.53821 1051.53 -0.266572 0.126472 -9.6263 -104.193 0 0 0 1 0.908554 -0.385025 0.319861 179.053 0.299803 -1.01574 -1.53769 1051.53 -0.268449 0.127204 -9.6271 -104.193 0 0 0 1 0.908184 -0.385379 0.299216 179.053 0.299274 -1.01552 -1.53711 1051.53 -0.270285 0.127912 -9.62785 -104.193 0 0 0 1 0.907851 -0.38587 0.278377 179.053 0.298625 -1.01524 -1.53649 1051.53 -0.272117 0.128613 -9.62858 -104.193 0 0 0 1 0.907555 -0.3865 0.257351 179.053 0.297852 -1.01491 -1.53581 1051.53 -0.273943 0.129305 -9.62927 -104.193 0 0 0 1 0.907302 -0.387256 0.236523 179.053 0.296972 -1.01454 -1.53506 1051.53 -0.275731 0.129976 -9.62992 -104.193 0 0 0 1 0.907085 -0.388155 0.215375 179.053 0.295964 -1.01411 -1.53424 1051.53 -0.277524 0.130643 -9.63055 -104.193 0 0 0 1 0.906907 -0.38918 0.194303 179.053 0.294848 -1.01363 -1.53334 1051.53 -0.27929 0.131292 -9.63114 -104.193 0 0 0 1 0.906766 -0.390331 0.173302 179.053 0.293623 -1.01311 -1.53236 1051.53 -0.281029 0.131926 -9.6317 -104.193 0 0 0 1 0.906661 -0.391626 0.151986 179.053 0.292269 -1.01253 -1.53126 1051.53 -0.282773 0.132553 -9.63223 -104.193 0 0 0 1 0.906594 -0.393044 0.130747 179.053 0.290811 -1.0119 -1.53007 1051.53 -0.28449 0.133166 -9.63273 -104.193 0 0 0 1 0.906561 -0.394581 0.109588 179.053 0.289249 -1.01122 -1.52878 1051.53 -0.286181 0.133763 -9.6332 -104.193 0 0 0 1 0.906563 -0.396255 0.088246 179.053 0.287566 -1.01049 -1.52736 1051.53 -0.287867 0.13435 -9.63365 -104.193 0 0 0 1 0.906598 -0.398067 0.06672 179.053 0.285761 -1.0097 -1.52581 1051.53 -0.289547 0.134929 -9.63406 -104.193 0 0 0 1 0.906667 -0.399981 0.045413 179.053 0.283867 -1.00887 -1.52416 1051.53 -0.291192 0.13549 -9.63445 -104.193 0 0 0 1 0.906767 -0.402032 0.023926 179.053 0.281851 -1.00798 -1.52234 1051.53 -0.292831 0.136042 -9.63481 -104.193 0 0 0 1 0.9069 -0.404221 0.00226 179.053 0.279714 -1.00703 -1.52037 1051.53 -0.294465 0.136584 -9.63515 -104.193 0 0 0 1 0.907062 -0.406505 -0.01918 179.053 0.277494 -1.00603 -1.51828 1051.53 -0.296063 0.137109 -9.63547 -104.193 0 0 0 1 0.907254 -0.408924 -0.040798 179.053 0.275153 -1.00498 -1.51601 1051.53 -0.297656 0.137625 -9.63576 -104.193 0 0 0 1 0.907475 -0.411479 -0.062588 179.053 0.272689 -1.00387 -1.51356 1051.53 -0.299244 0.138132 -9.63603 -104.193 0 0 0 1 0.907722 -0.414123 -0.084144 179.053 0.270148 -1.00272 -1.51097 1051.53 -0.300797 0.138621 -9.63627 -104.193 0 0 0 1 0.907998 -0.416917 -0.106008 179.053 0.267468 -1.00149 -1.50817 1051.53 -0.302354 0.139105 -9.63649 -104.193 0 0 0 1 0.908297 -0.419813 -0.127768 179.053 0.264699 -1.00021 -1.50521 1051.53 -0.303888 0.139574 -9.63669 -104.193 0 0 0 1 0.908619 -0.422806 -0.149421 179.053 0.261844 -0.998889 -1.50206 1051.53 -0.305396 0.140029 -9.63687 -104.193 0 0 0 1 0.908967 -0.425951 -0.171374 179.053 0.258846 -0.997488 -1.49869 1051.53 -0.306909 0.140478 -9.63703 -104.193 0 0 0 1 0.909336 -0.429191 -0.193217 179.053 0.255764 -0.996038 -1.49514 1051.53 -0.308399 0.140914 -9.63717 -104.193 0 0 0 1 0.909723 -0.432522 -0.214943 179.053 0.252597 -0.994536 -1.4914 1051.53 -0.309865 0.141335 -9.63729 -104.193 0 0 0 1 0.910132 -0.435984 -0.236826 179.053 0.249308 -0.992964 -1.48742 1051.53 -0.311325 0.141748 -9.63739 -104.193 0 0 0 1 0.910559 -0.439557 -0.258726 179.053 0.245916 -0.99133 -1.48323 1051.53 -0.312771 0.142149 -9.63747 -104.193 0 0 0 1 0.911002 -0.443237 -0.280638 179.053 0.242422 -0.989634 -1.47881 1051.53 -0.314204 0.14254 -9.63754 -104.193 0 0 0 1 0.911464 -0.44705 -0.302696 179.053 0.238804 -0.987862 -1.47413 1051.53 -0.315631 0.142922 -9.63758 -104.193 0 0 0 1 0.911938 -0.450944 -0.324624 179.053 0.235108 -0.986038 -1.46925 1051.53 -0.317035 0.143291 -9.63762 -104.193 0 0 0 1 0.912421 -0.454918 -0.346419 179.053 0.231335 -0.984158 -1.46415 1051.53 -0.318416 0.143647 -9.63764 -104.193 0 0 0 1 0.912919 -0.45902 -0.368351 179.053 0.227438 -0.982201 -1.45878 1051.53 -0.319793 0.143994 -9.63764 -104.193 0 0 0 1 0.91343 -0.46325 -0.390413 179.053 0.223417 -0.980163 -1.45312 1051.53 -0.321164 0.144332 -9.63762 -104.193 0 0 0 1 0.913944 -0.467526 -0.412196 179.053 0.219348 -0.978083 -1.44728 1051.53 -0.322505 0.144657 -9.63759 -104.193 0 0 0 1 0.914471 -0.471957 -0.43424 179.053 0.21513 -0.975905 -1.4411 1051.53 -0.323849 0.144973 -9.63755 -104.193 0 0 0 1 0.915001 -0.476456 -0.456129 179.053 0.21084 -0.973671 -1.4347 1051.53 -0.325172 0.145279 -9.6375 -104.193 0 0 0 1 0.915532 -0.481023 -0.477864 179.053 0.206478 -0.971379 -1.42808 1051.53 -0.326473 0.145572 -9.63743 -104.193 0 0 0 1 0.916069 -0.485713 -0.499711 179.053 0.201994 -0.969 -1.42115 1051.53 -0.327769 0.145857 -9.63734 -104.193 0 0 0 1 0.916611 -0.490525 -0.521665 179.053 0.197386 -0.966531 -1.41388 1051.53 -0.32906 0.146132 -9.63725 -104.193 0 0 0 1 0.917146 -0.495369 -0.543316 179.053 0.192738 -0.964018 -1.40643 1051.53 -0.330322 0.146395 -9.63714 -104.193 0 0 0 1 0.917682 -0.500332 -0.565062 179.053 0.187968 -0.961413 -1.39864 1051.53 -0.33158 0.146648 -9.63702 -104.193 0 0 0 1 0.918215 -0.505382 -0.586767 179.053 0.183104 -0.95873 -1.39057 1051.53 -0.332824 0.146893 -9.6369 -104.193 0 0 0 1 0.918743 -0.510519 -0.608425 179.053 0.178146 -0.955968 -1.38221 1051.53 -0.334056 0.147127 -9.63676 -104.193 0 0 0 1 0.919267 -0.515774 -0.630165 179.053 0.173062 -0.953109 -1.37349 1051.53 -0.335282 0.147353 -9.6366 -104.193 0 0 0 1 0.91978 -0.521078 -0.651713 179.053 0.167919 -0.950186 -1.36454 1051.53 -0.336488 0.147567 -9.63644 -104.193 0 0 0 1 0.920281 -0.526431 -0.673067 179.053 0.162715 -0.947199 -1.35533 1051.53 -0.337676 0.147771 -9.63628 -104.193 0 0 0 1 0.920772 -0.531896 -0.694485 179.053 0.157388 -0.944111 -1.34576 1051.53 -0.338857 0.147965 -9.6361 -104.193 0 0 0 1 0.921251 -0.537438 -0.715831 179.053 0.151971 -0.940938 -1.33589 1051.53 -0.340027 0.148151 -9.63591 -104.193 0 0 0 1 0.921715 -0.543056 -0.7371 179.053 0.146464 -0.937679 -1.32571 1051.53 -0.341185 0.148327 -9.63571 -104.193 0 0 0 1 0.922165 -0.548784 -0.758417 179.053 0.140833 -0.934312 -1.31513 1051.53 -0.342337 0.148495 -9.63551 -104.193 0 0 0 1 0.922595 -0.554548 -0.779512 179.053 0.135148 -0.930876 -1.30432 1051.53 -0.343471 0.148652 -9.63529 -104.193 0 0 0 1 0.923001 -0.560346 -0.80038 179.053 0.129411 -0.927375 -1.29325 1051.53 -0.344585 0.148799 -9.63507 -104.193 0 0 0 1 0.923389 -0.566248 -0.821279 179.053 0.123551 -0.92376 -1.28179 1051.53 -0.345695 0.148936 -9.63485 -104.193 0 0 0 1 0.923756 -0.572254 -0.842202 179.053 0.117569 -0.920031 -1.26994 1051.53 -0.3468 0.149067 -9.63461 -104.193 0 0 0 1 0.924093 -0.57825 -0.862751 179.053 0.111574 -0.916255 -1.25791 1051.53 -0.34788 0.149187 -9.63437 -104.193 0 0 0 1 0.924406 -0.584345 -0.883313 179.053 0.105458 -0.912361 -1.24548 1051.53 -0.348955 0.149298 -9.63412 -104.193 0 0 0 1 0.92469 -0.5905 -0.903748 179.053 0.099258 -0.908373 -1.23272 1051.53 -0.350019 0.1494 -9.63387 -104.193 0 0 0 1 0.924944 -0.596714 -0.924055 179.053 0.092974 -0.904288 -1.21964 1051.53 -0.351072 0.149494 -9.63361 -104.193 0 0 0 1 0.925167 -0.603023 -0.94435 179.053 0.086569 -0.900079 -1.20614 1051.53 -0.35212 0.149579 -9.63334 -104.193 0 0 0 1 0.925355 -0.609347 -0.964372 179.053 0.080121 -0.895796 -1.19238 1051.53 -0.353149 0.149656 -9.63307 -104.193 0 0 0 1 0.925508 -0.615683 -0.98412 179.053 0.073635 -0.891442 -1.17839 1051.53 -0.354162 0.149722 -9.63279 -104.193 0 0 0 1 0.925623 -0.622109 -1.00384 179.053 0.067027 -0.88696 -1.16397 1051.53 -0.355171 0.14978 -9.63251 -104.193 0 0 0 1 0.9257 -0.628582 -1.02339 179.053 0.060341 -0.882376 -1.14922 1051.53 -0.356168 0.149831 -9.63222 -104.193 0 0 0 1 0.925736 -0.6351 -1.04278 179.053 0.053577 -0.877689 -1.13414 1051.53 -0.357155 0.149872 -9.63193 -104.193 0 0 0 1 0.92573 -0.641702 -1.0621 179.053 0.046693 -0.872868 -1.11862 1051.53 -0.358137 0.149905 -9.63163 -104.193 0 0 0 1 0.925679 -0.648305 -1.08113 179.053 0.039776 -0.867971 -1.10287 1051.53 -0.359102 0.14993 -9.63133 -104.193 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 17.8219 17.8219 17.8212 17.822 17.8219 17.8219 17.8219 17.8219 17.8219 17.8219 17.8219 17.8219 17.8222 17.8219 17.8219 17.8219 17.8219 17.822 17.8219 17.8219 17.8219 17.8219 17.8219 17.8219 17.8219 17.822 17.8219 17.822 17.822 17.8219 17.8219 17.8219 17.8219 17.8219 17.822 17.8219 17.8219 17.8219 17.8219 17.822 17.8219 17.8219 17.8219 17.8219 17.8219 17.8219 17.8219 17.8219 17.822 17.8219 17.8219 17.8219 17.8218 17.8219 17.822 17.822 17.822 17.8219 17.8219 17.8219 17.822 17.822 17.8219 17.8219 17.8219 17.822 17.8219 17.8219 17.822 17.8219 17.822 17.8219 17.822 17.8219 17.8219 17.8219 17.8219 17.8219 17.8219 17.8219 17.8219 17.822 17.8218 17.8219 17.822 17.8219 17.8219 17.8219 17.822 17.822 17.8219 17.8219 17.822 17.8219 17.8219 17.8219 17.822 17.8219 17.822 17.822 17.8219 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - -0.572789 0.597854 -0.560788 -7.49618 -0.237486 -0.77583 -0.584541 0.150702 -0.784546 -0.201639 0.586369 -42.5129 0 0 0 1 -0.512791 0.557768 -0.65264 -4.9504 -0.191467 -0.815353 -0.546389 0.954039 -0.83689 -0.155225 0.5249 -42.8762 0 0 0 1 -0.443505 0.503851 -0.74124 -2.16319 -0.146367 -0.85664 -0.494718 1.65894 -0.88424 -0.110917 0.453671 -43.0879 0 0 0 1 -0.355888 0.440258 -0.824328 0.749369 -0.097529 -0.894759 -0.435768 2.16455 -0.929425 -0.074688 0.361372 -43.1149 0 0 0 1 -0.249878 0.374596 -0.892882 3.59685 -0.055648 -0.926167 -0.372987 2.41695 -0.966677 -0.043514 0.252274 -42.9585 0 0 0 1 -0.140081 0.315259 -0.93861 6.13424 -0.032472 -0.94891 -0.313872 2.43312 -0.989607 -0.013489 0.143161 -42.6693 0 0 0 1 -0.032108 0.270291 -0.962243 8.23147 -0.022609 -0.96269 -0.269662 2.28578 -0.999229 0.013097 0.037021 -42.3225 0 0 0 1 0.067761 0.24978 -0.965929 9.71818 -0.017837 -0.967696 -0.251488 2.07189 -0.997542 0.034271 -0.061117 -42.0165 0 0 0 1 0.154202 0.261794 -0.952725 10.5017 -0.006425 -0.963972 -0.265924 1.8776 -0.988018 0.047128 -0.146964 -41.836 0 0 0 1 0.228523 0.303513 -0.925017 10.733 0.023392 -0.951598 -0.306455 1.72046 -0.973257 0.048394 -0.224562 -41.7835 0 0 0 1 0.289937 0.370105 -0.882587 10.5497 0.092262 -0.928712 -0.35914 1.57418 -0.952588 0.022698 -0.303415 -41.8353 0 0 0 1 0.331445 0.448931 -0.829822 10.1035 0.199008 -0.893016 -0.403632 1.40355 -0.922247 -0.031359 -0.385326 -41.9509 0 0 0 1 0.350178 0.525773 -0.775202 9.53502 0.322586 -0.844669 -0.427169 1.18191 -0.879383 -0.100485 -0.465391 -42.0897 0 0 0 1 0.352565 0.589058 -0.727123 8.99086 0.440005 -0.790117 -0.426743 0.913387 -0.825889 -0.169483 -0.537756 -42.2151 0 0 0 1 0.360295 0.632547 -0.685617 8.62262 0.568938 -0.731462 -0.375864 0.637063 -0.739255 -0.254652 -0.623422 -42.296 0 0 0 1 0.350776 0.631512 -0.691483 7.49615 0.635482 -0.702884 -0.319557 0.138858 -0.687837 -0.327332 -0.647869 -42.5129 0 0 0 1 0.313092 0.570139 -0.759549 5.10735 0.58831 -0.744267 -0.316162 -0.634871 -0.745563 -0.347863 -0.568443 -42.8584 0 0 0 1 0.239548 0.499578 -0.832489 2.46547 0.502942 -0.79729 -0.333734 -1.32781 -0.830461 -0.338749 -0.442248 -43.0731 0 0 0 1 0.152266 0.421025 -0.894177 -0.337461 0.420919 -0.846201 -0.326759 -1.83924 -0.894227 -0.326622 -0.306065 -43.1218 0 0 0 1 0.064575 0.340098 -0.93817 -3.13877 0.361036 -0.884409 -0.295759 -2.10874 -0.930313 -0.319615 -0.179898 -42.9955 0 0 0 1 -0.033119 0.268366 -0.962747 -5.71688 0.310936 -0.912707 -0.265113 -2.14107 -0.949854 -0.308133 -0.053216 -42.7274 0 0 0 1 -0.137414 0.212879 -0.967368 -7.97344 0.269121 -0.93187 -0.243295 -1.99887 -0.953253 -0.29377 0.070761 -42.3718 0 0 0 1 -0.24021 0.183202 -0.953276 -9.71957 0.232921 -0.942463 -0.239816 -1.78216 -0.942362 -0.279645 0.183717 -42.0162 0 0 0 1 -0.335155 0.195154 -0.92173 -10.7469 0.194693 -0.942851 -0.270419 -1.5935 -0.921827 -0.270086 0.278006 -41.7734 0 0 0 1 -0.417684 0.247556 -0.874217 -11.094 0.145312 -0.931581 -0.333227 -1.4688 -0.896897 -0.266218 0.353134 -41.6876 0 0 0 1 -0.483553 0.321946 -0.813957 -10.9803 0.082467 -0.90901 -0.408535 -1.364 -0.871421 -0.264673 0.413005 -41.7216 0 0 0 1 -0.530811 0.398394 -0.748012 -10.638 0.011857 -0.879042 -0.476596 -1.22744 -0.847407 -0.261852 0.461881 -41.8149 0 0 0 1 -0.564452 0.461919 -0.684124 -10.2898 -0.059621 -0.849422 -0.524336 -1.03873 -0.82331 -0.255174 0.506997 -41.9077 0 0 0 1 -0.583609 0.522403 -0.621689 -9.86259 -0.131457 -0.816275 -0.562508 -0.807541 -0.801324 -0.24656 0.545058 -42.0162 0 0 0 1 -0.583432 0.578052 -0.570494 -9.00432 -0.197755 -0.782408 -0.590534 -0.440545 -0.787718 -0.231718 0.570795 -42.2151 0 0 0 1 -0.572789 0.597854 -0.560788 -7.49605 -0.237486 -0.77583 -0.584541 0.150858 -0.784546 -0.201639 0.586369 -42.5129 0 0 0 1 -0.536299 0.575482 -0.617417 -5.25917 -0.223396 -0.802208 -0.553676 0.924002 -0.813927 -0.159008 0.558784 -42.84 0 0 0 1 -0.458826 0.529557 -0.713476 -2.56419 -0.168412 -0.840264 -0.515358 1.68637 -0.87242 -0.116302 0.474719 -43.0649 0 0 0 1 -0.358737 0.466174 -0.808696 0.414791 -0.106448 -0.881142 -0.460715 2.26115 -0.927349 -0.079192 0.365721 -43.1148 0 0 0 1 -0.251509 0.394542 -0.883787 3.41759 -0.060061 -0.917743 -0.392608 2.53951 -0.96599 -0.045662 0.254517 -42.9666 0 0 0 1 -0.139572 0.326135 -0.934963 6.11307 -0.033564 -0.94522 -0.324703 2.52554 -0.989643 -0.013938 0.142873 -42.6673 0 0 0 1 -0.030436 0.273021 -0.961526 8.29357 -0.022469 -0.961916 -0.272421 2.31897 -0.999284 0.013313 0.035411 -42.3087 0 0 0 1 0.067756 0.24978 -0.96593 9.7178 -0.017836 -0.967696 -0.251488 2.07178 -0.997542 0.034269 -0.061112 -42.0166 0 0 0 1 0.154033 0.264757 -0.951934 10.4883 -0.006603 -0.963134 -0.26894 1.88225 -0.988044 0.047711 -0.146606 -41.8391 0 0 0 1 0.233197 0.311562 -0.921167 10.9101 0.024079 -0.948843 -0.314826 1.74376 -0.972132 0.051235 -0.228769 -41.7367 0 0 0 1 0.299281 0.382766 -0.874025 10.9977 0.094378 -0.923394 -0.37207 1.63683 -0.949486 0.028863 -0.31248 -41.7176 0 0 0 1 0.343239 0.465435 -0.815817 10.7821 0.203425 -0.884807 -0.419207 1.51592 -0.916955 -0.022069 -0.398381 -41.7781 0 0 0 1 0.360391 0.543569 -0.758057 10.2887 0.32919 -0.834494 -0.441877 1.32824 -0.872785 -0.090296 -0.479681 -41.908 0 0 0 1 0.357977 0.601746 -0.713971 9.55691 0.444762 -0.782215 -0.436264 1.03896 -0.821 -0.161374 -0.547647 -42.088 0 0 0 1 0.360295 0.632547 -0.685618 8.62231 0.568938 -0.731462 -0.375864 0.636994 -0.739255 -0.254652 -0.623422 -42.296 0 0 0 1 0.350776 0.631512 -0.691483 7.49625 0.635482 -0.702884 -0.319557 0.138976 -0.687837 -0.327332 -0.647869 -42.5129 0 0 0 1 0.302091 0.607135 -0.734934 5.93416 0.600079 -0.720151 -0.348263 -0.467158 -0.740706 -0.335811 -0.58188 -42.7544 0 0 0 1 0.229185 0.561787 -0.794903 3.81109 0.518743 -0.7615 -0.388617 -1.11646 -0.823638 -0.323285 -0.465947 -42.9817 0 0 0 1 0.148169 0.496529 -0.855281 1.238 0.435311 -0.809285 -0.394414 -1.67752 -0.888004 -0.313873 -0.336055 -43.1124 0 0 0 1 0.06608 0.415773 -0.907065 -1.61692 0.371416 -0.853976 -0.364382 -2.03684 -0.926112 -0.31282 -0.210856 -43.0835 0 0 0 1 -0.028237 0.330789 -0.943282 -4.50191 0.315947 -0.892328 -0.322378 -2.14077 -0.948357 -0.30713 -0.079315 -42.8724 0 0 0 1 -0.132321 0.249663 -0.959249 -7.26758 0.270184 -0.922028 -0.277245 -2.02245 -0.953673 -0.295859 0.054549 -42.4973 0 0 0 1 -0.240211 0.183108 -0.953294 -9.72104 0.232907 -0.942491 -0.239721 -1.78204 -0.942365 -0.279612 0.183749 -42.016 0 0 0 1 -0.330315 0.2003 -0.922373 -10.4882 0.194345 -0.941851 -0.274128 -1.5927 -0.923646 -0.269807 0.272181 -41.8391 0 0 0 1 -0.402134 0.263554 -0.876828 -10.2585 0.143552 -0.92768 -0.344675 -1.43993 -0.904257 -0.264476 0.335219 -41.9021 0 0 0 1 -0.466716 0.335164 -0.818439 -10.1292 0.081621 -0.905137 -0.417212 -1.29834 -0.880633 -0.261522 0.395085 -41.9387 0 0 0 1 -0.518074 0.407986 -0.751762 -9.99894 0.011358 -0.87555 -0.482994 -1.15183 -0.85526 -0.258765 0.448966 -41.9747 0 0 0 1 -0.553593 0.476762 -0.682812 -9.76617 -0.06327 -0.841621 -0.53635 -0.96859 -0.83038 -0.253718 0.49608 -42.0347 0 0 0 1 -0.572278 0.534415 -0.622012 -9.3372 -0.134017 -0.809246 -0.571979 -0.713063 -0.809035 -0.24397 0.534734 -42.1381 0 0 0 1 -0.577145 0.57623 -0.578672 -8.61839 -0.193946 -0.785043 -0.588296 -0.348351 -0.793277 -0.227301 0.564842 -42.2968 0 0 0 1 -0.572789 0.597854 -0.560788 -7.49605 -0.237486 -0.77583 -0.584541 0.150736 -0.784546 -0.201639 0.586369 -42.5129 0 0 0 1 -0.54061 0.591633 -0.598089 -5.77094 -0.235213 -0.788878 -0.567755 0.818521 -0.807722 -0.166256 0.565636 -42.7759 0 0 0 1 -0.468845 0.557132 -0.685411 -3.42944 -0.185589 -0.820797 -0.54023 1.55389 -0.863563 -0.126079 0.488225 -43.0092 0 0 0 1 -0.374639 0.499781 -0.780938 -0.646012 -0.123349 -0.86166 -0.492266 2.16013 -0.918929 -0.088094 0.384459 -43.1167 0 0 0 1 -0.271619 0.428992 -0.861505 2.30935 -0.073862 -0.901809 -0.425775 2.49282 -0.959566 -0.052015 0.276634 -43.0429 0 0 0 1 -0.158445 0.354904 -0.921378 5.17251 -0.04223 -0.934748 -0.352792 2.52478 -0.986464 -0.016989 0.163094 -42.7916 0 0 0 1 -0.042594 0.289944 -0.956095 7.72178 -0.026126 -0.95696 -0.289043 2.33093 -0.998751 0.012667 0.048336 -42.4162 0 0 0 1 0.067818 0.249777 -0.965926 9.72082 -0.017852 -0.967695 -0.251489 2.07173 -0.997538 0.0343 -0.061168 -42.0159 0 0 0 1 0.162346 0.25868 -0.952223 10.852 -0.006054 -0.964746 -0.263114 1.88209 -0.986715 0.048481 -0.155057 -41.7463 0 0 0 1 0.240141 0.314378 -0.918422 11.2058 0.024532 -0.94777 -0.31801 1.76627 -0.970428 0.053836 -0.235311 -41.6574 0 0 0 1 0.300495 0.392642 -0.869215 11.0792 0.095537 -0.919141 -0.382166 1.6649 -0.948987 0.031796 -0.31371 -41.6951 0 0 0 1 0.343239 0.465435 -0.815817 10.7821 0.203425 -0.884807 -0.419207 1.51586 -0.916954 -0.022069 -0.398381 -41.7781 0 0 0 1 0.366673 0.534372 -0.761575 10.4383 0.326979 -0.840387 -0.432242 1.33685 -0.870997 -0.090528 -0.482876 -41.8708 0 0 0 1 0.365498 0.600373 -0.711311 9.87145 0.445361 -0.783831 -0.432739 1.09831 -0.817353 -0.158626 -0.553871 -42.0141 0 0 0 1 0.362701 0.638811 -0.678505 8.94933 0.571537 -0.72756 -0.379476 0.71573 -0.736066 -0.250154 -0.628991 -42.227 0 0 0 1 0.350776 0.631512 -0.691483 7.49625 0.635482 -0.702884 -0.319557 0.138976 -0.687837 -0.327332 -0.647869 -42.5129 0 0 0 1 0.304968 0.588211 -0.749001 5.3769 0.593589 -0.732415 -0.333496 -0.616897 -0.744746 -0.342893 -0.572519 -42.8258 0 0 0 1 0.229792 0.522613 -0.821018 2.71001 0.5066 -0.784527 -0.357594 -1.39795 -0.830995 -0.333755 -0.445034 -43.0559 0 0 0 1 0.142699 0.439415 -0.886878 -0.291796 0.420715 -0.837998 -0.347503 -1.99557 -0.895899 -0.323534 -0.30445 -43.1149 0 0 0 1 0.055914 0.349156 -0.935394 -3.31221 0.358844 -0.881288 -0.307509 -2.28133 -0.931721 -0.318467 -0.174571 -42.973 0 0 0 1 -0.041156 0.26716 -0.962773 -6.05558 0.308393 -0.913145 -0.266571 -2.26114 -0.950368 -0.307883 -0.044809 -42.6741 0 0 0 1 -0.142549 0.206936 -0.967914 -8.27663 0.268355 -0.933192 -0.239035 -2.03878 -0.952715 -0.293819 0.077494 -42.3115 0 0 0 1 -0.239601 0.183252 -0.95342 -9.71086 0.233163 -0.942424 -0.239734 -1.78345 -0.942457 -0.279743 0.183078 -42.018 0 0 0 1 -0.330315 0.2003 -0.922373 -10.4882 0.194345 -0.941851 -0.274128 -1.5927 -0.923646 -0.269807 0.272181 -41.8391 0 0 0 1 -0.413792 0.247158 -0.876179 -10.9101 0.145636 -0.932074 -0.331705 -1.45419 -0.898647 -0.26486 0.34969 -41.7367 0 0 0 1 -0.48278 0.313052 -0.817877 -10.9973 0.085291 -0.912677 -0.399683 -1.34727 -0.871579 -0.262717 0.413921 -41.7177 0 0 0 1 -0.533248 0.387452 -0.752016 -10.782 0.015505 -0.884325 -0.466615 -1.22625 -0.845817 -0.260482 0.465557 -41.7781 0 0 0 1 -0.564288 0.46153 -0.684521 -10.2923 -0.059169 -0.849618 -0.524069 -1.04002 -0.823455 -0.255223 0.506737 -41.907 0 0 0 1 -0.577447 0.52648 -0.623997 -9.55685 -0.131459 -0.814287 -0.56538 -0.749169 -0.805775 -0.244447 0.539418 -42.088 0 0 0 1 -0.577779 0.573816 -0.580436 -8.62226 -0.192657 -0.786936 -0.586186 -0.347348 -0.79313 -0.226861 0.565225 -42.296 0 0 0 1 -0.572789 0.597854 -0.560788 -7.4961 -0.237486 -0.77583 -0.584541 0.150731 -0.784546 -0.201639 0.586369 -42.5129 0 0 0 1 -0.54242 0.592003 -0.596082 -5.88008 -0.23609 -0.788352 -0.568122 0.794983 -0.806252 -0.167432 0.567384 -42.7614 0 0 0 1 -0.471641 0.557826 -0.682924 -3.58366 -0.186685 -0.820085 -0.540933 1.52702 -0.861802 -0.127635 0.490924 -42.9975 0 0 0 1 -0.377612 0.500626 -0.778963 -0.795873 -0.124218 -0.861029 -0.493152 2.14193 -0.917594 -0.089458 0.387322 -43.1149 0 0 0 1 -0.274012 0.429749 -0.860368 2.19624 -0.074345 -0.901397 -0.426564 2.48553 -0.958849 -0.052919 0.278944 -43.0492 0 0 0 1 -0.159839 0.3554 -0.920947 5.10976 -0.042399 -0.934552 -0.353292 2.5241 -0.986232 -0.017422 0.164447 -42.7991 0 0 0 1 -0.043021 0.290109 -0.956026 7.70322 -0.026148 -0.956911 -0.289202 2.33158 -0.998732 0.012556 0.048753 -42.4195 0 0 0 1 0.067176 0.249799 -0.965965 9.71101 -0.017685 -0.967701 -0.251478 2.07316 -0.997584 0.033976 -0.060589 -42.018 0 0 0 1 0.162346 0.25868 -0.952223 10.852 -0.006054 -0.964746 -0.263114 1.88209 -0.986715 0.048481 -0.155057 -41.7463 0 0 0 1 0.240141 0.314378 -0.918422 11.2058 0.024532 -0.94777 -0.31801 1.76626 -0.970428 0.053836 -0.235311 -41.6574 0 0 0 1 0.300495 0.392642 -0.869215 11.0792 0.095537 -0.919141 -0.382166 1.66485 -0.948987 0.031796 -0.31371 -41.6951 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.64804 -0.018001 0.848896 164.819 -0.09659 -0.613235 -0.343087 1034.98 -0.048948 0.00796 -7.34032 -108.759 0 0 0 1 0.656517 0.007333 0.749682 141.481 -0.102239 -0.615508 -0.275965 1038.58 -0.039231 0.008114 -7.34715 -98.0347 0 0 0 1 0.682301 0.073692 0.514012 82.2215 -0.11831 -0.616522 -0.124094 1047.72 -0.041799 0.003064 -7.339 -70.8029 0 0 0 1 0.717314 0.168393 0.181694 0.838244 -0.142236 -0.609289 0.051401 1060.28 -0.056065 -0.009069 -7.27903 -33.4048 0 0 0 1 0.752725 0.276748 -0.189861 -88.3645 -0.172545 -0.587926 0.197859 1074.05 -0.079253 -0.028849 -7.1365 7.58657 0 0 0 1 0.778108 0.381366 -0.52047 -169.216 -0.209457 -0.551553 0.28572 1086.52 -0.103972 -0.052968 -6.89867 44.7404 0 0 0 1 0.783537 0.47051 -0.741321 -228.735 -0.256375 -0.50286 0.317539 1095.7 -0.120426 -0.075095 -6.55789 72.0912 0 0 0 1 0.757945 0.532609 -0.789307 -251.813 -0.31555 -0.446647 0.308344 1099.26 -0.117534 -0.085388 -6.11161 82.6963 0 0 0 1 0.798195 0.448327 -0.631484 -234.502 -0.27975 -0.194042 0.255794 1094.14 -0.112384 -0.058792 -5.235 75.1773 0 0 0 1 0.676066 0.275449 -0.365861 -188.86 -0.190801 0.075896 0.163344 1080.62 -0.076032 -0.020676 -3.723 55.3536 0 0 0 1 0.402554 0.094977 -0.119771 -123.898 -0.086325 0.319106 0.061928 1061.38 -0.030351 0.005925 -1.78632 27.1389 0 0 0 1 0.036574 -0.027275 0.010304 -50.3598 0.004625 0.524503 -0.006158 1039.61 -0.001092 0.011755 0.307728 -4.801 0 0 0 1 -0.355513 -0.062483 0.002982 23.6118 0.065264 0.695474 -0.009634 1017.7 0.000852 0.001949 2.3579 -36.929 0 0 0 1 -0.696279 -0.020381 -0.105265 88.4842 0.091849 0.83859 0.05422 998.49 -0.018958 -0.012758 4.1194 -65.105 0 0 0 1 -0.918607 0.051681 -0.231225 133.782 0.092998 0.947138 0.142078 985.075 -0.042385 -0.0238 5.32877 -84.7793 0 0 0 1 -0.994708 0.089786 -0.289329 151.095 0.088251 0.995579 0.186299 979.948 -0.052587 -0.027568 5.78539 -92.2986 0 0 0 1 -0.943775 0.069923 -0.255595 136.891 0.070791 0.944416 0.15545 981.346 -0.024686 -0.024451 4.96231 -86.8323 0 0 0 1 -0.805891 0.027381 -0.135856 100.825 0.03086 0.810641 0.083189 985.006 -0.010684 -0.017664 2.87393 -72.9523 0 0 0 1 -0.604723 -0.011517 0.009239 51.2948 -0.009327 0.61798 -0.002276 990.267 -0.026707 -0.017681 0.004749 -53.8905 0 0 0 1 -0.371264 -0.026295 0.125963 -2.99447 -0.031836 0.394075 -0.088879 996.445 -0.075524 -0.035336 -3.14164 -32.9972 0 0 0 1 -0.138919 -0.011172 0.18994 -52.2013 -0.030698 0.16749 -0.175175 1002.71 -0.143527 -0.074589 -5.99397 -14.0598 0 0 0 1 0.06056 0.02427 0.215626 -88.5822 -0.013321 -0.034262 -0.261386 1008.52 -0.208836 -0.13074 -8.10184 -0.058611 0 0 0 1 0.200202 0.059163 0.228844 -102.47 0.004847 -0.18565 -0.324744 1013.04 -0.2412 -0.182995 -8.90439 5.28623 0 0 0 1 0.301951 0.076214 0.249632 -90.9856 0.018313 -0.283175 -0.302889 1016.77 -0.226128 -0.156518 -8.83996 0.38606 0 0 0 1 0.393842 0.083038 0.330383 -60.7067 0.020058 -0.370295 -0.283405 1020.57 -0.204634 -0.128785 -8.66626 -12.5332 0 0 0 1 0.473964 0.077405 0.446932 -17.6111 0.008781 -0.446181 -0.274759 1024.29 -0.177432 -0.100947 -8.4164 -30.9209 0 0 0 1 0.53898 0.060834 0.572268 31.1745 -0.01302 -0.508251 -0.28172 1027.67 -0.147034 -0.074535 -8.13086 -51.7363 0 0 0 1 0.5891 0.036891 0.688435 80.5354 -0.041117 -0.556748 -0.302265 1030.63 -0.115492 -0.049747 -7.83962 -72.7972 0 0 0 1 0.623025 0.011638 0.778393 123.283 -0.06875 -0.589977 -0.327562 1032.94 -0.086609 -0.027666 -7.586 -91.0365 0 0 0 1 0.642058 -0.008585 0.833797 153.335 -0.089234 -0.608453 -0.345347 1034.44 -0.06356 -0.008537 -7.40749 -103.859 0 0 0 1 0.648041 -0.018001 0.848895 164.82 -0.096593 -0.613236 -0.343085 1034.98 -0.048948 0.007959 -7.34031 -108.759 0 0 0 1 0.64804 -0.01801 0.848879 164.82 -0.096602 -0.613235 -0.343095 1034.98 -0.048948 0.007959 -7.34031 -108.759 0 0 0 1 0.648038 -0.018019 0.848839 164.82 -0.096612 -0.613235 -0.343104 1034.98 -0.048952 0.00796 -7.34032 -108.759 0 0 0 1 0.648036 -0.018028 0.848778 164.82 -0.096621 -0.613235 -0.343112 1034.98 -0.048956 0.00796 -7.34032 -108.759 0 0 0 1 0.648034 -0.018037 0.848693 164.82 -0.096631 -0.613234 -0.343111 1034.98 -0.048964 0.007959 -7.34033 -108.759 0 0 0 1 0.648032 -0.018046 0.848588 164.82 -0.096641 -0.613234 -0.343108 1034.98 -0.048972 0.007957 -7.34035 -108.759 0 0 0 1 0.64803 -0.018055 0.848458 164.82 -0.09665 -0.613234 -0.343102 1034.98 -0.048984 0.007956 -7.34036 -108.759 0 0 0 1 0.648027 -0.018065 0.848309 164.82 -0.09666 -0.613234 -0.343097 1034.98 -0.048997 0.007954 -7.34038 -108.759 0 0 0 1 0.648025 -0.018074 0.848134 164.82 -0.09667 -0.613233 -0.343088 1034.98 -0.049012 0.007954 -7.3404 -108.759 0 0 0 1 0.648022 -0.018083 0.847937 164.82 -0.096679 -0.613233 -0.343077 1034.98 -0.049029 0.007952 -7.34042 -108.759 0 0 0 1 0.648019 -0.018092 0.847721 164.82 -0.096689 -0.613233 -0.343057 1034.98 -0.049049 0.007949 -7.34045 -108.759 0 0 0 1 0.648016 -0.018101 0.847484 164.82 -0.096698 -0.613233 -0.343035 1034.98 -0.049069 0.007947 -7.34048 -108.759 0 0 0 1 0.648013 -0.01811 0.847223 164.82 -0.096708 -0.613232 -0.343012 1034.98 -0.049092 0.007945 -7.34051 -108.759 0 0 0 1 0.64801 -0.018119 0.846944 164.82 -0.096718 -0.613232 -0.342988 1034.98 -0.049117 0.007942 -7.34054 -108.759 0 0 0 1 0.648006 -0.018128 0.846642 164.82 -0.096727 -0.613232 -0.34296 1034.98 -0.049144 0.00794 -7.34058 -108.759 0 0 0 1 0.648002 -0.018137 0.846317 164.82 -0.096737 -0.613232 -0.34293 1034.98 -0.049173 0.007938 -7.34062 -108.759 0 0 0 1 0.647999 -0.018146 0.845973 164.82 -0.096747 -0.613232 -0.342894 1034.98 -0.049203 0.007933 -7.34066 -108.759 0 0 0 1 0.647995 -0.018155 0.84561 164.82 -0.096757 -0.613231 -0.342855 1034.98 -0.049236 0.00793 -7.3407 -108.759 0 0 0 1 0.647991 -0.018164 0.845222 164.82 -0.096766 -0.613231 -0.34282 1034.98 -0.04927 0.007928 -7.34075 -108.759 0 0 0 1 0.647987 -0.018174 0.844815 164.82 -0.096776 -0.613231 -0.34277 1034.98 -0.049306 0.007923 -7.3408 -108.759 0 0 0 1 0.647982 -0.018183 0.844388 164.82 -0.096786 -0.613231 -0.342733 1034.98 -0.049344 0.00792 -7.34085 -108.759 0 0 0 1 0.647978 -0.018192 0.843942 164.82 -0.096795 -0.61323 -0.342687 1034.98 -0.049383 0.007916 -7.3409 -108.759 0 0 0 1 0.647973 -0.018201 0.843472 164.82 -0.096805 -0.61323 -0.342631 1034.98 -0.049426 0.007911 -7.34096 -108.759 0 0 0 1 0.647968 -0.01821 0.842987 164.82 -0.096815 -0.61323 -0.342581 1034.98 -0.049468 0.007908 -7.34102 -108.759 0 0 0 1 0.647963 -0.018219 0.842475 164.82 -0.096824 -0.61323 -0.342522 1034.98 -0.049514 0.007903 -7.34108 -108.759 0 0 0 1 0.647958 -0.018228 0.841949 164.82 -0.096834 -0.61323 -0.342461 1034.98 -0.049561 0.007898 -7.34114 -108.759 0 0 0 1 0.647953 -0.018237 0.841405 164.82 -0.096844 -0.613229 -0.3424 1034.98 -0.04961 0.007893 -7.34121 -108.759 0 0 0 1 0.647948 -0.018246 0.840834 164.82 -0.096854 -0.613229 -0.342336 1034.98 -0.049661 0.007888 -7.34127 -108.759 0 0 0 1 0.647942 -0.018256 0.840245 164.82 -0.096863 -0.613229 -0.342263 1034.98 -0.049713 0.007882 -7.34135 -108.759 0 0 0 1 0.647937 -0.018265 0.839643 164.82 -0.096872 -0.613229 -0.342196 1034.98 -0.049767 0.007877 -7.34142 -108.759 0 0 0 1 0.647931 -0.018274 0.839019 164.82 -0.096883 -0.613229 -0.342121 1034.98 -0.049823 0.00787 -7.34149 -108.759 0 0 0 1 0.647925 -0.018283 0.838376 164.82 -0.096891 -0.613228 -0.342043 1034.98 -0.049881 0.007864 -7.34157 -108.759 0 0 0 1 0.647919 -0.018292 0.83771 164.82 -0.096902 -0.613228 -0.34197 1034.98 -0.04994 0.00786 -7.34165 -108.759 0 0 0 1 0.647913 -0.018301 0.837024 164.82 -0.096912 -0.613228 -0.341882 1034.98 -0.050001 0.007852 -7.34173 -108.759 0 0 0 1 0.647907 -0.01831 0.836324 164.82 -0.096922 -0.613228 -0.341799 1034.98 -0.050064 0.007846 -7.34181 -108.759 0 0 0 1 0.6479 -0.018319 0.835607 164.82 -0.096931 -0.613228 -0.341715 1034.98 -0.050128 0.00784 -7.3419 -108.759 0 0 0 1 0.647894 -0.018328 0.834869 164.82 -0.096941 -0.613227 -0.341623 1034.98 -0.050194 0.007832 -7.34199 -108.759 0 0 0 1 0.647887 -0.018337 0.834109 164.82 -0.096951 -0.613227 -0.341534 1034.98 -0.050262 0.007827 -7.34208 -108.759 0 0 0 1 0.64788 -0.018346 0.833337 164.82 -0.096961 -0.613227 -0.341439 1034.98 -0.050331 0.007819 -7.34217 -108.759 0 0 0 1 0.647873 -0.018356 0.832539 164.82 -0.09697 -0.613227 -0.341341 1034.98 -0.050402 0.007812 -7.34227 -108.759 0 0 0 1 0.647866 -0.018365 0.831728 164.82 -0.09698 -0.613227 -0.341242 1034.98 -0.050475 0.007805 -7.34236 -108.759 0 0 0 1 0.647859 -0.018374 0.830905 164.82 -0.09699 -0.613227 -0.341142 1034.98 -0.050549 0.007797 -7.34246 -108.759 0 0 0 1 0.647851 -0.018383 0.830059 164.82 -0.097 -0.613226 -0.341033 1034.98 -0.050624 0.007788 -7.34256 -108.759 0 0 0 1 0.647844 -0.018392 0.829187 164.82 -0.097009 -0.613226 -0.340921 1034.98 -0.050702 0.00778 -7.34266 -108.759 0 0 0 1 0.647836 -0.018401 0.828312 164.82 -0.097018 -0.613226 -0.340816 1034.98 -0.05078 0.007772 -7.34277 -108.759 0 0 0 1 0.647829 -0.01841 0.827411 164.82 -0.097028 -0.613226 -0.340702 1034.98 -0.050861 0.007764 -7.34288 -108.759 0 0 0 1 0.647821 -0.018419 0.826496 164.82 -0.097038 -0.613226 -0.340593 1034.98 -0.050943 0.007757 -7.34299 -108.759 0 0 0 1 0.647813 -0.018428 0.825563 164.82 -0.097048 -0.613226 -0.340469 1034.98 -0.051026 0.007747 -7.34309 -108.759 0 0 0 1 0.647804 -0.018436 0.824607 164.82 -0.097058 -0.613225 -0.34035 1034.98 -0.051112 0.007738 -7.34321 -108.759 0 0 0 1 0.647796 -0.018446 0.823636 164.82 -0.097067 -0.613225 -0.340229 1034.98 -0.051199 0.00773 -7.34332 -108.759 0 0 0 1 0.647788 -0.018455 0.822658 164.82 -0.097077 -0.613225 -0.340101 1034.98 -0.051287 0.00772 -7.34344 -108.759 0 0 0 1 0.647779 -0.018464 0.821656 164.82 -0.097087 -0.613225 -0.339979 1034.98 -0.051377 0.007712 -7.34356 -108.759 0 0 0 1 0.64777 -0.018473 0.820639 164.82 -0.097097 -0.613225 -0.339848 1034.98 -0.051468 0.007701 -7.34368 -108.759 0 0 0 1 0.647762 -0.018482 0.819607 164.82 -0.097106 -0.613225 -0.339714 1034.98 -0.05156 0.007692 -7.3438 -108.759 0 0 0 1 0.647753 -0.018492 0.818549 164.82 -0.097116 -0.613224 -0.33958 1034.98 -0.051655 0.007682 -7.34392 -108.759 0 0 0 1 0.647744 -0.018501 0.817481 164.82 -0.097125 -0.613224 -0.339443 1034.98 -0.05175 0.007672 -7.34405 -108.759 0 0 0 1 0.647734 -0.01851 0.816405 164.82 -0.097135 -0.613224 -0.339307 1034.98 -0.051847 0.007663 -7.34417 -108.759 0 0 0 1 0.647725 -0.018519 0.815306 164.82 -0.097145 -0.613224 -0.339169 1034.98 -0.051945 0.007653 -7.3443 -108.759 0 0 0 1 0.647716 -0.018528 0.814186 164.82 -0.097154 -0.613224 -0.33902 1034.98 -0.052046 0.007642 -7.34443 -108.759 0 0 0 1 0.647706 -0.018537 0.813062 164.82 -0.097164 -0.613224 -0.338872 1034.98 -0.052147 0.007631 -7.34456 -108.759 0 0 0 1 0.647696 -0.018546 0.811914 164.82 -0.097174 -0.613223 -0.338729 1034.98 -0.05225 0.007622 -7.3447 -108.759 0 0 0 1 0.647686 -0.018555 0.810752 164.82 -0.097183 -0.613223 -0.338577 1034.98 -0.052354 0.007611 -7.34483 -108.759 0 0 0 1 0.647676 -0.018564 0.809576 164.82 -0.097193 -0.613223 -0.338425 1034.98 -0.052459 0.0076 -7.34497 -108.759 0 0 0 1 0.647666 -0.018573 0.808378 164.82 -0.097203 -0.613223 -0.33827 1034.98 -0.052566 0.007589 -7.34511 -108.759 0 0 0 1 0.647656 -0.018582 0.807172 164.82 -0.097211 -0.613223 -0.338107 1034.98 -0.052674 0.007577 -7.34525 -108.759 0 0 0 1 0.647646 -0.018591 0.805955 164.82 -0.097222 -0.613223 -0.337951 1034.98 -0.052784 0.007566 -7.34539 -108.759 0 0 0 1 0.647635 -0.0186 0.80472 164.82 -0.097231 -0.613223 -0.337786 1034.98 -0.052894 0.007554 -7.34553 -108.759 0 0 0 1 0.647625 -0.018609 0.803468 164.82 -0.097241 -0.613223 -0.337627 1034.98 -0.053007 0.007543 -7.34567 -108.759 0 0 0 1 0.647614 -0.018618 0.802204 164.82 -0.097251 -0.613222 -0.33746 1034.98 -0.053119 0.007531 -7.34582 -108.759 0 0 0 1 0.647603 -0.018627 0.800913 164.82 -0.09726 -0.613222 -0.337289 1034.98 -0.053235 0.007519 -7.34597 -108.759 0 0 0 1 0.647592 -0.018636 0.799623 164.82 -0.09727 -0.613222 -0.337112 1034.98 -0.053351 0.007506 -7.34612 -108.759 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 1 0 -0.000000 17.8219 0 1 0 0.000007 0 0 1 -0.000002 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000017 0 0 1 0.000002 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000023 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.822 0 1 0 0.000001 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000012 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000000 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000002 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000003 0 0 1 0 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000032 0 0 1 0 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000000 0 0 1 0 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.00001 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.8217 0 1 0 0.000016 0 0 1 -0.000009 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000012 0 0 1 -0.000005 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000009 0 0 1 0.000003 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000021 0 0 1 -0.000003 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000003 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.822 0 1 0 -0.000003 0 0 1 0.000003 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000000 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.822 0 1 0 0.00003 0 0 1 0.002975 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000035 0 0 1 0.000004 0 0 0 1 1 0 -0.000000 17.8221 0 1 0 0.000065 0 0 1 -0.000005 0 0 0 1 1 0 -0.000000 17.8223 0 1 0 0.000247 0 0 1 -0.000009 0 0 0 1 1 0 -0.000000 17.8221 0 1 0 0.000002 0 0 1 -0.000002 0 0 0 1 1 0 -0.000000 17.8218 0 1 0 -0.000024 0 0 1 0.000001 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000016 0 0 1 0.000001 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000021 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000023 0 0 1 0.000001 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000000 0 0 1 0.000001 0 0 0 1 1 0 -0.000000 17.822 0 1 0 0.000000 0 0 1 0 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000016 0 0 1 -0.000002 0 0 0 1 1 0 -0.000000 17.822 0 1 0 0.000002 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000023 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000000 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000031 0 0 1 -0.000001 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000000 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000002 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000006 0 0 1 0 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000003 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.822 0 1 0 0.000002 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000000 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000014 0 0 1 0.000002 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000002 0 0 1 0.000001 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000009 0 0 1 0.000001 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000011 0 0 1 0.000001 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.00001 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.822 0 1 0 0.000013 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000011 0 0 1 -0.000001 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000009 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000014 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000007 0 0 1 -0.000001 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000002 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.822 0 1 0 0.000004 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000009 0 0 1 0 0 0 0 1 1 0 -0.000000 17.822 0 1 0 -0.000016 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000000 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000008 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000027 0 0 1 -0.000001 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000015 0 0 1 0.000001 0 0 0 1 1 0 -0.000000 17.822 0 1 0 0.00001 0 0 1 -0.000002 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000009 0 0 1 0.000001 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000001 0 0 1 -0.000002 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000006 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000018 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.822 0 1 0 0.000018 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.822 0 1 0 -0.000007 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000027 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.822 0 1 0 0.000012 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000000 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000009 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000005 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000014 0 0 1 0 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000000 0 0 1 0.000002 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000001 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.00002 0 0 1 0 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000012 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000014 0 0 1 0.000003 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.00001 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.822 0 1 0 0.000003 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000013 0 0 1 0.000002 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000013 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000003 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.822 0 1 0 -0.000000 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.822 0 1 0 -0.000007 0 0 1 0 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.00001 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.822 0 1 0 0.000005 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.822 0 1 0 -0.000007 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000016 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000005 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000012 0 0 1 -0.000002 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000002 0 0 1 -0.000001 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000004 0 0 1 0.000001 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000002 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.822 0 1 0 0.000027 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000013 0 0 1 -0.000001 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.000008 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.822 0 1 0 0.000004 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.822 0 1 0 0.000007 0 0 1 -0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 0.000008 0 0 1 0 0 0 0 1 1 0 -0.000000 17.822 0 1 0 0.000006 0 0 1 0 0 0 0 1 1 0 -0.000000 17.822 0 1 0 0.000004 0 0 1 0.000000 0 0 0 1 1 0 -0.000000 17.8219 0 1 0 -0.00001 0 0 1 -0.000001 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.698734 0.399124 -0.593692 175.071 -0.715347 0.381718 -0.585295 -0.000136 -0.006981 0.833661 0.552232 0.000015 0 0 0 1 0.695512 0.275759 -0.663491 175.071 -0.69796 0.478588 -0.532735 0.000048 0.170632 0.833613 0.525331 -0.000057 0 0 0 1 0.6565 0.187725 -0.730594 175.071 -0.684863 0.554303 -0.47298 0.000058 0.316181 0.810868 0.492466 -0.000107 0 0 0 1 0.602214 0.104774 -0.79143 175.071 -0.671152 0.603278 -0.430827 0.00001 0.432313 0.790619 0.433621 -0.00003 0 0 0 1 0.538038 0.016446 -0.84276 175.071 -0.661104 0.628495 -0.4098 0.000028 0.52293 0.77764 0.349027 -0.000058 0 0 0 1 0.461371 -0.0502 -0.885786 175.071 -0.681088 0.619771 -0.389876 0.00007 0.568556 0.783176 0.251754 -0.000087 0 0 0 1 0.380154 -0.096674 -0.919857 175.071 -0.743342 0.55987 -0.366045 -0.000093 0.550387 0.822921 0.140975 0.000028 0 0 0 1 0.308595 -0.136916 -0.941288 175.071 -0.832982 0.438887 -0.336926 0.000048 0.45925 0.88805 0.02139 -0.000033 0 0 0 1 0.260956 -0.190635 -0.946341 175.071 -0.913067 0.269499 -0.30607 -0.000081 0.313386 0.943943 -0.103735 -0.000035 0 0 0 1 0.251001 -0.266512 -0.930575 175.071 -0.956476 0.079532 -0.280765 -0.000007 0.148838 0.960545 -0.23495 0.000014 0 0 0 1 0.307424 -0.354534 -0.88306 175.071 -0.951573 -0.115511 -0.284899 -0.000028 -0.000997 0.927881 -0.372876 -0.000026 0 0 0 1 0.432559 -0.416693 -0.799537 175.071 -0.893718 -0.315209 -0.319235 -0.000083 -0.118998 0.852649 -0.508753 -0.000077 0 0 0 1 0.59208 -0.420681 -0.687363 175.071 -0.782253 -0.505027 -0.36473 -0.000032 -0.193702 0.753642 -0.628095 -0.000088 0 0 0 1 0.739536 -0.365691 -0.565116 175.071 -0.635593 -0.655776 -0.407405 0.000028 -0.221605 0.660475 -0.717401 -0.000033 0 0 0 1 0.870314 -0.275507 -0.408228 175.071 -0.457857 -0.757989 -0.464564 0.000009 -0.181442 0.591226 -0.785831 0.000015 0 0 0 1 0.927365 -0.205947 -0.312379 175.071 -0.34642 -0.788069 -0.508862 0.000027 -0.141378 0.580115 -0.802171 -0.000013 0 0 0 1 0.895425 -0.238091 -0.3762 175.071 -0.416481 -0.746585 -0.518801 -0.000079 -0.157344 0.621227 -0.767672 0.000035 0 0 0 1 0.821139 -0.282984 -0.495632 175.071 -0.543625 -0.652247 -0.528247 -0.000131 -0.173789 0.703202 -0.689423 0.000034 0 0 0 1 0.749463 -0.291655 -0.594342 175.071 -0.644682 -0.52576 -0.554942 -0.00002 -0.15063 0.799071 -0.582063 -0.000033 0 0 0 1 0.708028 -0.268615 -0.653101 175.071 -0.699992 -0.389164 -0.598802 -0.000019 -0.093316 0.881134 -0.463567 0.000033 0 0 0 1 0.684363 -0.2236 -0.69401 175.071 -0.728533 -0.248561 -0.638323 -0.000074 -0.029775 0.942455 -0.333006 -0.000038 0 0 0 1 0.67613 -0.166062 -0.717824 175.071 -0.736195 -0.113363 -0.667208 -0.000105 0.029422 0.979577 -0.198902 0.000034 0 0 0 1 0.676039 -0.107765 -0.728942 175.071 -0.733115 0.001313 -0.680103 -0.000067 0.074248 0.994176 -0.078116 -0.000106 0 0 0 1 0.683266 -0.047472 -0.728625 175.071 -0.723324 0.092321 -0.684309 -0.000095 0.099753 0.994597 0.028742 -0.000046 0 0 0 1 0.699049 0.021024 -0.714765 175.071 -0.707473 0.165686 -0.687044 -0.000096 0.103982 0.985955 0.130696 -0.000027 0 0 0 1 0.715992 0.094634 -0.691664 175.071 -0.692368 0.223053 -0.686202 -0.000066 0.08934 0.970202 0.225226 0.000058 0 0 0 1 0.727742 0.16909 -0.66468 175.071 -0.683052 0.266156 -0.680148 -0.000052 0.061901 0.948984 0.30919 -0.000003 0 0 0 1 0.73109 0.242514 -0.637726 175.071 -0.68166 0.299495 -0.667564 0.000059 0.029101 0.922762 0.38427 0.000046 0 0 0 1 0.725469 0.308735 -0.615124 175.071 -0.688254 0.326426 -0.647883 -0.00009 0.000768 0.89338 0.449301 -0.000063 0 0 0 1 0.713398 0.36249 -0.59972 175.071 -0.70062 0.351885 -0.620733 0.000032 -0.013977 0.863005 0.505002 -0.000082 0 0 0 1 0.698734 0.399124 -0.593692 175.071 -0.715347 0.381718 -0.585294 0.000034 -0.006982 0.833661 0.552232 -0.000003 0 0 0 1 0.700541 0.349583 -0.622121 175.071 -0.70777 0.4517 -0.543166 -0.000099 0.091131 0.820828 0.563858 0.000019 0 0 0 1 0.681221 0.243063 -0.690549 175.071 -0.690142 0.52789 -0.495011 -0.000025 0.244215 0.813789 0.527358 -0.000045 0 0 0 1 0.630861 0.136306 -0.763829 175.071 -0.675544 0.580723 -0.454314 -0.000049 0.381647 0.802609 0.458437 0.000017 0 0 0 1 0.564689 0.036524 -0.824495 175.071 -0.664908 0.611943 -0.42828 -0.000039 0.488902 0.790057 0.369843 -0.000024 0 0 0 1 0.478483 -0.041114 -0.877134 175.071 -0.682935 0.610468 -0.40116 -0.000011 0.551956 0.790973 0.26402 -0.000078 0 0 0 1 0.385372 -0.094665 -0.917893 175.071 -0.743821 0.556813 -0.369715 0.000038 0.546094 0.825226 0.144166 -0.000102 0 0 0 1 0.307959 -0.137456 -0.941417 175.071 -0.833202 0.438708 -0.336615 0.000035 0.459277 0.888054 0.020575 -0.000018 0 0 0 1 0.260616 -0.190939 -0.946373 175.071 -0.913177 0.269401 -0.305828 0.000064 0.313348 0.94391 -0.104151 -0.000044 0 0 0 1 0.251042 -0.267059 -0.930407 175.071 -0.956618 0.078364 -0.280607 -0.000102 0.14785 0.960489 -0.235802 0.00005 0 0 0 1 0.307584 -0.354372 -0.883071 175.071 -0.951521 -0.115455 -0.285093 -0.000076 -0.000925 0.92795 -0.372704 -0.000052 0 0 0 1 0.432699 -0.416548 -0.799537 175.071 -0.893662 -0.31515 -0.31945 -0.000011 -0.118908 0.852742 -0.508618 -0.00004 0 0 0 1 0.59309 -0.420453 -0.686632 175.071 -0.781419 -0.506062 -0.365082 -0.000046 -0.193978 0.753074 -0.628691 -0.000014 0 0 0 1 0.739533 -0.365694 -0.565118 175.071 -0.635596 -0.655774 -0.407404 -0.000017 -0.221604 0.660476 -0.717399 -0.000069 0 0 0 1 0.870313 -0.275508 -0.408228 175.071 -0.457858 -0.757989 -0.464564 0.000131 -0.181441 0.591227 -0.785831 0.000055 0 0 0 1 0.927365 -0.205947 -0.31238 175.071 -0.34642 -0.788069 -0.508862 0.000062 -0.141378 0.580115 -0.802171 0.000074 0 0 0 1 0.895425 -0.23809 -0.3762 175.071 -0.41648 -0.746586 -0.518801 0.000054 -0.157345 0.621227 -0.767672 0.000012 0 0 0 1 0.821139 -0.282983 -0.495632 175.071 -0.543625 -0.652248 -0.528247 -0.000021 -0.17379 0.703202 -0.689423 0.000014 0 0 0 1 0.749464 -0.291653 -0.594341 175.071 -0.644681 -0.525761 -0.554943 0.000026 -0.150631 0.79907 -0.582063 -0.000012 0 0 0 1 0.708029 -0.268613 -0.653101 175.071 -0.699991 -0.389166 -0.598802 -0.000087 -0.093318 0.881134 -0.463569 0.000095 0 0 0 1 0.684364 -0.2236 -0.69401 175.071 -0.728533 -0.248562 -0.638324 -0.000127 -0.029775 0.942454 -0.333006 0.000024 0 0 0 1 0.676137 -0.166432 -0.717732 175.071 -0.736201 -0.114145 -0.667068 0.000008 0.029095 0.979424 -0.199705 -0.000021 0 0 0 1 0.67604 -0.107762 -0.728943 175.071 -0.733115 0.001313 -0.680103 -0.000035 0.074247 0.994176 -0.078114 -0.000106 0 0 0 1 0.683266 -0.047472 -0.728625 175.071 -0.723324 0.09232 -0.68431 0.000062 0.099752 0.994597 0.028742 -0.000000 0 0 0 1 0.699149 0.021446 -0.714654 175.071 -0.707374 0.166115 -0.687042 -0.000125 0.10398 0.985873 0.13131 0.000076 0 0 0 1 0.715992 0.094633 -0.691664 175.071 -0.692368 0.223051 -0.686203 -0.000059 0.089338 0.970202 0.225224 -0.000022 0 0 0 1 0.727742 0.16909 -0.664681 175.071 -0.683052 0.266156 -0.680148 -0.00009 0.061902 0.948984 0.30919 -0.000126 0 0 0 1 0.73109 0.242514 -0.637726 175.071 -0.68166 0.299495 -0.667565 0.00004 0.029101 0.922762 0.38427 -0.000017 0 0 0 1 0.725469 0.308736 -0.615123 175.071 -0.688254 0.326425 -0.647884 -0.000062 0.000766 0.893381 0.4493 -0.000051 0 0 0 1 0.713398 0.36249 -0.59972 175.071 -0.70062 0.351885 -0.620733 -0.000134 -0.013977 0.863005 0.505002 -0.00004 0 0 0 1 0.698734 0.399125 -0.593692 175.071 -0.715347 0.381718 -0.585294 0.00005 -0.006982 0.833661 0.552232 0.000012 0 0 0 1 0.700592 0.350042 -0.621805 175.071 -0.707821 0.451237 -0.543484 -0.000033 0.090338 0.820887 0.5639 -0.000044 0 0 0 1 0.681222 0.243062 -0.690549 175.071 -0.690142 0.52789 -0.495011 0.000086 0.244216 0.813789 0.527358 -0.00004 0 0 0 1 0.630489 0.13566 -0.764251 175.071 -0.675459 0.580981 -0.454109 0.000016 0.382411 0.802531 0.457936 0.000033 0 0 0 1 0.56469 0.036526 -0.824494 175.071 -0.664908 0.611943 -0.428281 -0.00011 0.4889 0.790058 0.369845 -0.00001 0 0 0 1 0.478483 -0.041114 -0.877134 175.071 -0.682934 0.610469 -0.40116 -0.000093 0.551956 0.790973 0.26402 0.000005 0 0 0 1 0.385372 -0.094665 -0.917893 175.071 -0.743821 0.556813 -0.369715 0.00003 0.546094 0.825226 0.144166 -0.000045 0 0 0 1 0.30796 -0.137456 -0.941417 175.071 -0.833202 0.438707 -0.336616 0.000000 0.459276 0.888055 0.020575 -0.000038 0 0 0 1 0.260615 -0.190939 -0.946373 175.071 -0.913177 0.269401 -0.305828 -0.00004 0.313348 0.94391 -0.104151 0.00006 0 0 0 1 0.251042 -0.267059 -0.930407 175.071 -0.956619 0.078364 -0.280607 -0.000035 0.14785 0.960489 -0.235802 0.000011 0 0 0 1 0.307584 -0.354372 -0.883071 175.071 -0.951521 -0.115455 -0.285093 -0.000022 -0.000926 0.92795 -0.372704 -0.000021 0 0 0 1 0.432699 -0.416548 -0.799537 175.071 -0.893663 -0.31515 -0.31945 -0.000013 -0.118908 0.852742 -0.508618 -0.000072 0 0 0 1 0.592127 -0.42063 -0.687355 175.071 -0.782229 -0.504997 -0.364822 -0.000023 -0.193657 0.75369 -0.628051 -0.000014 0 0 0 1 0.739536 -0.365693 -0.565116 175.071 -0.635594 -0.655775 -0.407406 -0.000038 -0.221604 0.660474 -0.717401 -0.00007 0 0 0 1 0.870313 -0.275508 -0.408228 175.071 -0.457858 -0.757989 -0.464564 0.00006 -0.181441 0.591227 -0.785831 0.000035 0 0 0 1 0.927365 -0.205946 -0.312379 175.071 -0.34642 -0.788069 -0.508862 0.000012 -0.141379 0.580115 -0.802171 0.000094 0 0 0 1 0.895737 -0.237814 -0.375632 175.071 -0.415848 -0.747004 -0.518706 0.000069 -0.157243 0.62083 -0.768014 -0.000047 0 0 0 1 0.821139 -0.282982 -0.495632 175.071 -0.543624 -0.652249 -0.528247 -0.000078 -0.173791 0.703202 -0.689423 0.000006 0 0 0 1 0.749101 -0.291586 -0.594832 175.071 -0.645162 -0.524947 -0.555156 -0.000019 -0.150379 0.79963 -0.581358 0.000014 0 0 0 1 0.708029 -0.268615 -0.6531 175.071 -0.69999 -0.389169 -0.598801 0.000048 -0.09332 0.881133 -0.463571 -0.000000 0 0 0 1 0.684364 -0.223598 -0.69401 175.071 -0.728532 -0.248564 -0.638324 -0.000029 -0.029778 0.942454 -0.333006 -0.00005 0 0 0 1 0.676137 -0.166431 -0.717732 175.071 -0.736201 -0.114145 -0.667067 -0.000071 0.029094 0.979424 -0.199704 0.000071 0 0 0 1 0.676023 -0.108138 -0.728902 175.071 -0.733152 0.000668 -0.680064 0.000011 0.074028 0.994136 -0.07883 -0.000099 0 0 0 1 0.683266 -0.047469 -0.728625 175.071 -0.723324 0.092318 -0.68431 -0.000014 0.099749 0.994597 0.028742 -0.00006 0 0 0 1 0.699149 0.021447 -0.714654 175.071 -0.707375 0.166114 -0.687042 -0.000052 0.103979 0.985874 0.13131 0.000058 0 0 0 1 0.715993 0.094633 -0.691664 175.071 -0.692368 0.223053 -0.686203 -0.000021 0.089339 0.970202 0.225225 -0.000057 0 0 0 1 0.727742 0.169091 -0.66468 175.071 -0.683052 0.266154 -0.680148 -0.000011 0.061901 0.948984 0.30919 -0.000079 0 0 0 1 0.731086 0.242084 -0.637894 175.071 -0.681656 0.2993 -0.667656 0.000061 0.029293 0.922938 0.383832 0.000046 0 0 0 1 0.725469 0.308736 -0.615123 175.071 -0.688254 0.326427 -0.647883 0.000002 0.000767 0.893379 0.449302 0.000008 0 0 0 1 0.713398 0.362491 -0.59972 175.071 -0.70062 0.351884 -0.620733 0.00004 -0.013977 0.863005 0.505001 -0.000016 0 0 0 1 0.698734 0.399125 -0.593692 175.071 -0.715347 0.381718 -0.585294 -0.000001 -0.006982 0.833661 0.552232 0.000038 0 0 0 1 0.700592 0.350042 -0.621805 175.071 -0.707821 0.451237 -0.543484 -0.000057 0.090338 0.820887 0.5639 -0.000024 0 0 0 1 0.681222 0.243062 -0.690549 175.071 -0.690142 0.52789 -0.495011 0.000033 0.244216 0.813789 0.527358 -0.000035 0 0 0 1 0.630488 0.135662 -0.764251 175.071 -0.67546 0.580981 -0.454108 -0.000116 0.38241 0.802531 0.457936 -0.000001 0 0 0 1 0.56469 0.036526 -0.824494 175.071 -0.664908 0.611944 -0.42828 -0.000108 0.488901 0.790058 0.369845 0.000017 0 0 0 1 0.478482 -0.041113 -0.877134 175.071 -0.682935 0.610468 -0.40116 -0.000091 0.551955 0.790973 0.26402 -0.000078 0 0 0 1 0.385372 -0.094665 -0.917893 175.071 -0.743821 0.556813 -0.369715 0.000014 0.546094 0.825226 0.144166 -0.000033 0 0 0 1 0.30835 -0.137149 -0.941334 175.071 -0.832659 0.439596 -0.336799 -0.00005 0.459998 0.887663 0.02135 -0.000006 0 0 0 1 0.260616 -0.190938 -0.946373 175.071 -0.913177 0.2694 -0.305828 -0.000049 0.313347 0.94391 -0.104151 0.000016 0 0 0 1 0.251042 -0.267059 -0.930407 175.071 -0.956619 0.078364 -0.280607 -0.000075 0.14785 0.960489 -0.235802 -0.000003 0 0 0 1 0.307584 -0.354372 -0.883071 175.071 -0.951521 -0.115455 -0.285093 -0.000036 -0.000926 0.92795 -0.372704 -0.00003 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.112619 0.993638 0 370.017 -0.993638 0.112619 0 0.000029 0 0 1 0.000003 0 0 0 1 0.019813 0.999804 0 370.017 -0.999804 0.019813 0 0.000014 0 0 1 0.000003 0 0 0 1 0.014553 0.999894 0 370.017 -0.999894 0.014553 0 0.000042 0 0 1 0.000003 0 0 0 1 -0.036816 0.999322 0 370.018 -0.999322 -0.036816 0 0.000042 0 0 1 0.000003 0 0 0 1 -0.189791 0.981825 0 370.018 -0.981825 -0.189791 0 0.000051 0 0 1 0.000003 0 0 0 1 -0.331439 0.943477 0 370.017 -0.943477 -0.331439 0 0.000099 0 0 1 0.000003 0 0 0 1 -0.419202 0.907893 0 370.018 -0.907893 -0.419202 0 -0.000011 0 0 1 0.000003 0 0 0 1 -0.435055 0.900404 0 370.018 -0.900404 -0.435055 0 -0.000024 0 0 1 0.000003 0 0 0 1 -0.387921 0.921692 0 370.018 -0.921693 -0.387921 0 0.000004 0 0 1 0.000003 0 0 0 1 -0.309997 0.950738 0 370.017 -0.950738 -0.309997 0 0.000015 0 0 1 0.000003 0 0 0 1 -0.248673 0.968588 0 370.017 -0.968588 -0.248673 0 0.000005 0 0 1 0.000003 0 0 0 1 -0.19561 0.980682 0 370.018 -0.980682 -0.19561 0 0.000126 0 0 1 0.000003 0 0 0 1 -0.10894 0.994048 0 370.017 -0.994048 -0.108941 0 -0.000036 0 0 1 0.000003 0 0 0 1 0.034473 0.999406 0 370.017 -0.999406 0.034473 0 0.000016 0 0 1 0.000003 0 0 0 1 0.284613 0.958642 0 370.017 -0.958642 0.284613 0 -0.000000 0 0 1 0.000003 0 0 0 1 0.472321 0.881427 0 370.017 -0.881427 0.472321 0 0.000055 0 0 1 0.000003 0 0 0 1 0.401358 0.915922 0 370.017 -0.915921 0.401358 0 0.000034 0 0 1 0.000003 0 0 0 1 0.24788 0.968791 0 370.017 -0.968791 0.24788 0 0.000099 0 0 1 0.000003 0 0 0 1 0.105804 0.994387 0 370.018 -0.994387 0.105804 0 -0.000047 0 0 1 0.000003 0 0 0 1 -0.002642 0.999997 0 370.017 -0.999996 -0.002642 0 0.000031 0 0 1 0.000003 0 0 0 1 -0.089713 0.995968 0 370.017 -0.995968 -0.089713 0 0.000088 0 0 1 0.000003 0 0 0 1 -0.152886 0.988244 0 370.018 -0.988244 -0.152886 0 0.000082 0 0 1 0.000003 0 0 0 1 -0.190832 0.981622 0 370.017 -0.981622 -0.190832 0 -0.000028 0 0 1 0.000003 0 0 0 1 -0.208319 0.978061 0 370.018 -0.978061 -0.20832 0 -0.000022 0 0 1 0.000003 0 0 0 1 -0.205653 0.978625 0 370.017 -0.978625 -0.205653 0 -0.000024 0 0 1 0.000003 0 0 0 1 -0.183063 0.983101 0 370.018 -0.983101 -0.183063 0 0.000031 0 0 1 0.000003 0 0 0 1 -0.143085 0.98971 0 370.017 -0.98971 -0.143085 0 0.00009 0 0 1 0.000003 0 0 0 1 -0.088141 0.996108 0 370.017 -0.996108 -0.088141 0 0.000078 0 0 1 0.000003 0 0 0 1 -0.023732 0.999718 0 370.018 -0.999718 -0.023732 0 0.000056 0 0 1 0.000003 0 0 0 1 0.044682 0.999001 0 370.017 -0.999001 0.044682 0 0.000051 0 0 1 0.000003 0 0 0 1 0.112619 0.993638 0 370.017 -0.993638 0.112619 0 0.000004 0 0 1 0.000003 0 0 0 1 0.091219 0.995831 0 370.017 -0.995831 0.091219 0 0.000029 0 0 1 0.000003 0 0 0 1 0.037205 0.999308 0 370.018 -0.999308 0.037205 0 0.000062 0 0 1 0.000003 0 0 0 1 -0.041762 0.999128 0 370.018 -0.999128 -0.041762 0 0.000046 0 0 1 0.000003 0 0 0 1 -0.196039 0.980597 0 370.017 -0.980597 -0.196039 0 0.000082 0 0 1 0.000003 0 0 0 1 -0.336594 0.94165 0 370.018 -0.94165 -0.336594 0 0.000014 0 0 1 0.000003 0 0 0 1 -0.421361 0.906893 0 370.017 -0.906893 -0.421361 0 -0.000034 0 0 1 0.000003 0 0 0 1 -0.435054 0.900405 0 370.018 -0.900405 -0.435054 0 0.000001 0 0 1 0.000003 0 0 0 1 -0.387921 0.921692 0 370.017 -0.921692 -0.387921 0 0.000025 0 0 1 0.000003 0 0 0 1 -0.30956 0.950879 0 370.017 -0.950879 -0.30956 0 0.00004 0 0 1 0.000003 0 0 0 1 -0.248675 0.968587 0 370.017 -0.968587 -0.248675 0 0.000013 0 0 1 0.000003 0 0 0 1 -0.195612 0.980681 0 370.018 -0.980681 -0.195612 0 0.000033 0 0 1 0.000003 0 0 0 1 -0.108227 0.994126 0 370.017 -0.994126 -0.108227 0 0.00012 0 0 1 0.000003 0 0 0 1 0.034465 0.999406 0 370.018 -0.999406 0.034465 0 -0.000018 0 0 1 0.000003 0 0 0 1 0.284611 0.958643 0 370.017 -0.958643 0.284611 0 0.0001 0 0 1 0.000003 0 0 0 1 0.472321 0.881426 0 370.017 -0.881426 0.472321 0 -0.000038 0 0 1 0.000003 0 0 0 1 0.40136 0.91592 0 370.018 -0.91592 0.40136 0 -0.000058 0 0 1 0.000003 0 0 0 1 0.24788 0.968791 0 370.018 -0.968791 0.24788 0 0.000000 0 0 1 0.000003 0 0 0 1 0.105805 0.994387 0 370.017 -0.994387 0.105805 0 0.000153 0 0 1 0.000003 0 0 0 1 -0.00264 0.999997 0 370.018 -0.999997 -0.00264 0 0.000016 0 0 1 0.000003 0 0 0 1 -0.089713 0.995968 0 370.018 -0.995968 -0.089712 0 -0.000011 0 0 1 0.000003 0 0 0 1 -0.15257 0.988293 0 370.018 -0.988293 -0.15257 0 0.000093 0 0 1 0.000003 0 0 0 1 -0.190832 0.981622 0 370.017 -0.981623 -0.190832 0 0.000043 0 0 1 0.000003 0 0 0 1 -0.208319 0.978061 0 370.018 -0.978061 -0.208319 0 0.000088 0 0 1 0.000003 0 0 0 1 -0.205604 0.978635 0 370.018 -0.978635 -0.205604 0 0.000031 0 0 1 0.000003 0 0 0 1 -0.183064 0.983101 0 370.017 -0.983101 -0.183064 0 0.000056 0 0 1 0.000003 0 0 0 1 -0.143085 0.98971 0 370.018 -0.98971 -0.143085 0 0.000086 0 0 1 0.000003 0 0 0 1 -0.088141 0.996108 0 370.018 -0.996108 -0.088141 0 0.000076 0 0 1 0.000003 0 0 0 1 -0.023731 0.999718 0 370.018 -0.999718 -0.023731 0 0.000079 0 0 1 0.000003 0 0 0 1 0.044684 0.999001 0 370.017 -0.999001 0.044684 0 0.00006 0 0 1 0.000003 0 0 0 1 0.11262 0.993638 0 370.017 -0.993638 0.11262 0 0.000045 0 0 1 0.000003 0 0 0 1 0.091454 0.995809 0 370.017 -0.995809 0.091454 0 0.000031 0 0 1 0.000003 0 0 0 1 0.037204 0.999308 0 370.018 -0.999308 0.037204 0 0.000043 0 0 1 0.000003 0 0 0 1 -0.042498 0.999096 0 370.017 -0.999096 -0.042498 0 0.000051 0 0 1 0.000003 0 0 0 1 -0.196037 0.980596 0 370.018 -0.980596 -0.196037 0 0.000058 0 0 1 0.000003 0 0 0 1 -0.336595 0.94165 0 370.018 -0.941649 -0.336595 0 0.000069 0 0 1 0.000003 0 0 0 1 -0.421362 0.906893 0 370.017 -0.906893 -0.421362 0 0.000005 0 0 1 0.000003 0 0 0 1 -0.435055 0.900403 0 370.018 -0.900403 -0.435055 0 0.000032 0 0 1 0.000003 0 0 0 1 -0.387922 0.921692 0 370.017 -0.921692 -0.387922 0 0.000057 0 0 1 0.000003 0 0 0 1 -0.30956 0.950879 0 370.017 -0.950879 -0.30956 0 0.000049 0 0 1 0.000003 0 0 0 1 -0.248675 0.968587 0 370.018 -0.968587 -0.248675 0 0.000029 0 0 1 0.000003 0 0 0 1 -0.195612 0.980681 0 370.018 -0.980681 -0.195612 0 -0.000055 0 0 1 0.000003 0 0 0 1 -0.108945 0.994048 0 370.018 -0.994048 -0.108945 0 -0.000013 0 0 1 0.000003 0 0 0 1 0.034468 0.999406 0 370.017 -0.999406 0.034468 0 0.000053 0 0 1 0.000003 0 0 0 1 0.28461 0.958643 0 370.017 -0.958643 0.28461 0 0.000062 0 0 1 0.000003 0 0 0 1 0.472322 0.881426 0 370.018 -0.881426 0.472322 0 -0.000016 0 0 1 0.000003 0 0 0 1 0.402054 0.915616 0 370.017 -0.915616 0.402054 0 -0.000014 0 0 1 0.000003 0 0 0 1 0.247881 0.968791 0 370.017 -0.968791 0.247881 0 0.000097 0 0 1 0.000003 0 0 0 1 0.105018 0.99447 0 370.017 -0.99447 0.105018 0 -0.000001 0 0 1 0.000003 0 0 0 1 -0.00264 0.999997 0 370.018 -0.999997 -0.00264 0 0.000063 0 0 1 0.000003 0 0 0 1 -0.089711 0.995968 0 370.017 -0.995968 -0.089711 0 0.000062 0 0 1 0.000003 0 0 0 1 -0.15257 0.988293 0 370.018 -0.988293 -0.15257 0 -0.000119 0 0 1 0.000003 0 0 0 1 -0.190659 0.981656 0 370.017 -0.981656 -0.190659 0 -0.000072 0 0 1 0.000003 0 0 0 1 -0.208319 0.978061 0 370.017 -0.978061 -0.208319 0 -0.00003 0 0 1 0.000003 0 0 0 1 -0.205605 0.978635 0 370.017 -0.978635 -0.205605 0 -0.000055 0 0 1 0.000003 0 0 0 1 -0.183065 0.983101 0 370.017 -0.9831 -0.183064 0 0.00005 0 0 1 0.000003 0 0 0 1 -0.143086 0.98971 0 370.017 -0.98971 -0.143086 0 0.000051 0 0 1 0.000003 0 0 0 1 -0.088514 0.996075 0 370.018 -0.996075 -0.088514 0 0.000028 0 0 1 0.000003 0 0 0 1 -0.02373 0.999718 0 370.018 -0.999718 -0.02373 0 0.000091 0 0 1 0.000003 0 0 0 1 0.044682 0.999001 0 370.017 -0.999001 0.044682 0 0.000037 0 0 1 0.000003 0 0 0 1 0.11262 0.993638 0 370.018 -0.993638 0.11262 0 0.000056 0 0 1 0.000003 0 0 0 1 0.091454 0.995809 0 370.018 -0.995809 0.091454 0 0.000034 0 0 1 0.000003 0 0 0 1 0.037204 0.999308 0 370.018 -0.999308 0.037204 0 0.000041 0 0 1 0.000003 0 0 0 1 -0.042498 0.999097 0 370.018 -0.999096 -0.042498 0 0.000071 0 0 1 0.000003 0 0 0 1 -0.196036 0.980597 0 370.017 -0.980597 -0.196036 0 0.000016 0 0 1 0.000003 0 0 0 1 -0.336596 0.941649 0 370.018 -0.941649 -0.336596 0 0.000113 0 0 1 0.000003 0 0 0 1 -0.421362 0.906893 0 370.018 -0.906893 -0.421362 0 0.000019 0 0 1 0.000003 0 0 0 1 -0.435058 0.900402 0 370.018 -0.900402 -0.435058 0 -0.000023 0 0 1 0.000003 0 0 0 1 -0.387922 0.921692 0 370.018 -0.921692 -0.387922 0 0.000036 0 0 1 0.000003 0 0 0 1 -0.309561 0.950879 0 370.017 -0.950879 -0.309561 0 -0.000035 0 0 1 0.000003 0 0 0 1 -0.248675 0.968587 0 370.017 -0.968587 -0.248675 0 0.000059 0 0 1 0.000003 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.995261 0.013675 -0.09627 370.017 -0.060933 0.859273 -0.507874 -0.000002 0.075777 0.511334 0.856035 0.000064 0 0 0 1 0.942021 -0.331108 -0.054445 370.017 0.257082 0.816432 -0.517057 -0.000054 0.215653 0.473081 0.854218 -0.000027 0 0 0 1 0.802307 -0.596481 -0.022691 370.017 0.505354 0.698984 -0.506003 -0.000033 0.317682 0.394502 0.862233 -0.000017 0 0 0 1 0.703892 -0.710141 0.015331 370.018 0.626148 0.610159 -0.485434 0.000008 0.335372 0.351292 0.874139 -0.000008 0 0 0 1 0.691961 -0.718955 0.065525 370.017 0.660109 0.593341 -0.460654 0.000065 0.29231 0.362009 0.885158 0.000037 0 0 0 1 0.721516 -0.683641 0.109768 370.017 0.656281 0.6247 -0.423138 -0.000000 0.220702 0.37734 0.899391 -0.000013 0 0 0 1 0.775508 -0.615617 0.14001 370.017 0.617369 0.693076 -0.372158 -0.00001 0.132069 0.37505 0.917549 0.000015 0 0 0 1 0.83905 -0.522765 0.150703 370.018 0.542047 0.77947 -0.314024 0.000022 0.046692 0.34517 0.937378 0.000005 0 0 0 1 0.895183 -0.422523 0.141852 370.018 0.445546 0.856693 -0.259934 -0.000057 -0.011694 0.29589 0.95515 0.000005 0 0 0 1 0.926302 -0.356335 0.122435 370.017 0.375355 0.900971 -0.217623 -0.000003 -0.032764 0.247541 0.968323 0.000001 0 0 0 1 0.905047 -0.412015 0.105516 370.018 0.425215 0.881827 -0.203894 0.000004 -0.00904 0.229401 0.97329 -0.000013 0 0 0 1 0.822968 -0.559597 0.097855 370.018 0.566267 0.794288 -0.220109 -0.000011 0.045446 0.236554 0.970555 -0.000018 0 0 0 1 0.71342 -0.69385 0.098006 370.018 0.692633 0.67703 -0.248776 -0.000005 0.10626 0.245364 0.96359 -0.00003 0 0 0 1 0.65924 -0.746186 0.092785 370.018 0.737497 0.617581 -0.273298 0.000009 0.146629 0.248599 0.957444 -0.000006 0 0 0 1 0.756206 -0.651881 0.056595 370.017 0.637179 0.713947 -0.290316 -0.000035 0.148845 0.2556 0.955256 0.000015 0 0 0 1 0.850192 -0.525734 0.027881 370.018 0.509892 0.809074 -0.292249 0.000034 0.131088 0.262684 0.955936 -0.000033 0 0 0 1 0.826792 -0.558951 0.063165 370.018 0.551894 0.784347 -0.283221 -0.000052 0.108763 0.269025 0.956972 -0.000014 0 0 0 1 0.770365 -0.626558 0.118167 370.018 0.63182 0.725246 -0.273536 -0.000045 0.085685 0.285382 0.954576 0.000008 0 0 0 1 0.728959 -0.665821 0.159066 370.017 0.679956 0.677342 -0.280834 0.000016 0.079243 0.312874 0.946483 0.000019 0 0 0 1 0.71883 -0.670452 0.183787 370.018 0.689739 0.654795 -0.309039 0.000002 0.086852 0.348911 0.933123 -0.000003 0 0 0 1 0.728318 -0.654532 0.202833 370.018 0.678948 0.649274 -0.342743 0 0.092641 0.387339 0.917271 -0.000024 0 0 0 1 0.757443 -0.617599 0.211781 370.017 0.646158 0.662587 -0.378759 0.000002 0.093597 0.423733 0.900938 0.000007 0 0 0 1 0.800694 -0.562646 0.205719 370.017 0.592431 0.692666 -0.411387 0.000025 0.08897 0.451269 0.887941 0.000033 0 0 0 1 0.848941 -0.494089 0.187552 370.018 0.522096 0.729054 -0.442601 -0.000032 0.081948 0.473662 0.876886 -0.000004 0 0 0 1 0.896375 -0.41289 0.161349 370.017 0.437238 0.763512 -0.47526 0.00008 0.073037 0.496559 0.864925 0.000043 0 0 0 1 0.937652 -0.323588 0.126884 370.018 0.341884 0.792857 -0.504473 0.000016 0.062641 0.5164 0.854054 0.000048 0 0 0 1 0.968365 -0.234233 0.086047 370.017 0.243838 0.814927 -0.525773 0.000005 0.053031 0.530122 0.846262 -0.000013 0 0 0 1 0.987953 -0.149477 0.040067 370.018 0.147438 0.83049 -0.537167 0.000014 0.047018 0.536604 0.842524 -0.000002 0 0 0 1 0.997 -0.077047 -0.007367 370.017 0.061022 0.841042 -0.537517 0.000109 0.04761 0.535455 0.84322 -0.000003 0 0 0 1 0.998332 -0.021656 -0.053516 370.018 -0.00984 0.849581 -0.527367 0.000003 0.056887 0.527014 0.847951 -0.000038 0 0 0 1 0.995261 0.013675 -0.09627 370.018 -0.060933 0.859273 -0.507874 -0.000003 0.075777 0.511334 0.856035 -0.000083 0 0 0 1 0.975938 -0.197723 -0.091924 370.017 0.123776 0.849433 -0.512975 -0.000033 0.17951 0.489254 0.853468 0.000022 0 0 0 1 0.834057 -0.550527 -0.03563 370.018 0.45383 0.721413 -0.52307 -0.000049 0.313668 0.4201 0.851545 -0.000048 0 0 0 1 0.697013 -0.716671 0.02356 370.018 0.62616 0.592315 -0.507037 -0.000029 0.349423 0.368164 0.861602 0.000005 0 0 0 1 0.686363 -0.72352 0.073655 370.018 0.661191 0.578622 -0.477517 -0.000026 0.302875 0.37645 0.87553 0.00003 0 0 0 1 0.717942 -0.68646 0.115465 370.018 0.658331 0.615683 -0.433053 -0.000104 0.226184 0.386921 0.893943 -0.000055 0 0 0 1 0.774098 -0.617016 0.141642 370.018 0.61879 0.690215 -0.375104 0.000003 0.133682 0.378014 0.916097 -0.000005 0 0 0 1 0.839016 -0.523036 0.149953 370.018 0.542059 0.779597 -0.313691 0.000041 0.047168 0.344475 0.93761 0.000018 0 0 0 1 0.895187 -0.422653 0.141436 370.017 0.445544 0.856754 -0.259738 -0.000002 -0.011397 0.29553 0.955266 -0.000013 0 0 0 1 0.926301 -0.356363 0.122358 370.017 0.375358 0.901017 -0.217432 0.000006 -0.032761 0.247335 0.968376 -0.000012 0 0 0 1 0.905046 -0.411963 0.105732 370.018 0.425215 0.881797 -0.204022 -0.000026 -0.009184 0.229608 0.97324 -0.000013 0 0 0 1 0.822977 -0.559547 0.098061 370.018 0.566262 0.794255 -0.220242 0.000000 0.045349 0.236783 0.970504 0.000016 0 0 0 1 0.712885 -0.694387 0.098083 370.017 0.693137 0.676429 -0.249006 -0.000005 0.106561 0.245498 0.963523 0.000017 0 0 0 1 0.659239 -0.746187 0.092786 370.018 0.737499 0.61758 -0.273298 0.000003 0.146628 0.248597 0.957444 0.000012 0 0 0 1 0.756206 -0.651882 0.056596 370.018 0.63718 0.713946 -0.290315 -0.000001 0.148844 0.2556 0.955256 -0.000011 0 0 0 1 0.850192 -0.525734 0.02788 370.017 0.509891 0.809074 -0.292249 0.000006 0.131088 0.262684 0.955936 -0.000005 0 0 0 1 0.826793 -0.55895 0.063165 370.017 0.551893 0.784347 -0.283221 0.000007 0.108763 0.269025 0.956972 -0.00001 0 0 0 1 0.770365 -0.626558 0.118166 370.017 0.631819 0.725246 -0.273536 0.000000 0.085686 0.285382 0.954576 0.000008 0 0 0 1 0.728958 -0.665821 0.159066 370.018 0.679956 0.677342 -0.280834 -0.000000 0.079243 0.312874 0.946483 -0.000007 0 0 0 1 0.71883 -0.670453 0.183786 370.017 0.689739 0.654794 -0.309039 0.000008 0.086854 0.348911 0.933122 -0.000041 0 0 0 1 0.728318 -0.654532 0.202833 370.017 0.678948 0.649273 -0.342744 -0.00002 0.092642 0.387339 0.917271 0.000001 0 0 0 1 0.757213 -0.617881 0.211779 370.018 0.646426 0.662451 -0.378539 -0.000014 0.093599 0.423534 0.901032 0.000012 0 0 0 1 0.800693 -0.562646 0.205719 370.018 0.592431 0.692665 -0.411387 -0.000017 0.08897 0.451269 0.887941 0.000038 0 0 0 1 0.848941 -0.494089 0.187552 370.017 0.522096 0.729054 -0.442602 -0.00004 0.081949 0.473663 0.876885 -0.000024 0 0 0 1 0.896654 -0.412358 0.161159 370.017 0.436676 0.763713 -0.475455 0.00008 0.072977 0.496692 0.864853 0.00004 0 0 0 1 0.937652 -0.323591 0.126884 370.017 0.341887 0.792857 -0.504473 0.000064 0.062641 0.516399 0.854053 0.000014 0 0 0 1 0.968365 -0.234233 0.086046 370.018 0.243838 0.814927 -0.525773 0.000016 0.053031 0.530121 0.846262 -0.000032 0 0 0 1 0.987953 -0.149477 0.040067 370.017 0.147438 0.83049 -0.537167 -0.000041 0.047018 0.536604 0.842523 -0.000046 0 0 0 1 0.997 -0.077047 -0.007367 370.017 0.061022 0.841042 -0.537518 0.000016 0.04761 0.535455 0.843221 -0.000027 0 0 0 1 0.998332 -0.021656 -0.053517 370.017 -0.009841 0.849581 -0.527366 -0.000051 0.056888 0.527013 0.847951 -0.000036 0 0 0 1 0.995261 0.013675 -0.09627 370.017 -0.060932 0.859273 -0.507874 -0.000005 0.075777 0.511334 0.856035 -0.000052 0 0 0 1 0.97629 -0.195882 -0.09213 370.017 0.122077 0.849696 -0.512946 -0.000037 0.17876 0.489537 0.853463 -0.000042 0 0 0 1 0.834057 -0.550527 -0.035631 370.017 0.45383 0.721413 -0.52307 -0.000014 0.313668 0.4201 0.851544 0.000012 0 0 0 1 0.69662 -0.717043 0.023881 370.017 0.626599 0.591865 -0.50702 -0.000044 0.34942 0.368165 0.861603 0.000006 0 0 0 1 0.686362 -0.723521 0.073654 370.017 0.661191 0.578622 -0.477518 -0.000003 0.302876 0.37645 0.875529 -0.000066 0 0 0 1 0.717943 -0.686459 0.115465 370.017 0.658331 0.615683 -0.433053 -0.000003 0.226184 0.386921 0.893943 -0.000016 0 0 0 1 0.774098 -0.617016 0.141642 370.018 0.61879 0.690214 -0.375104 0.000002 0.133682 0.378014 0.916098 -0.000032 0 0 0 1 0.839016 -0.523036 0.149954 370.017 0.54206 0.779596 -0.313691 0.000091 0.047168 0.344475 0.93761 0.00001 0 0 0 1 0.895188 -0.422652 0.141436 370.018 0.445543 0.856754 -0.259737 0.000025 -0.011396 0.295529 0.955266 0.000002 0 0 0 1 0.926301 -0.356363 0.122359 370.018 0.375358 0.901017 -0.217431 -0.000019 -0.032762 0.247335 0.968376 -0.000013 0 0 0 1 0.905046 -0.411961 0.105732 370.018 0.425215 0.881798 -0.204021 0.000008 -0.009185 0.229608 0.97324 -0.00001 0 0 0 1 0.822977 -0.559547 0.098063 370.017 0.566262 0.794255 -0.220242 -0.00001 0.045349 0.236783 0.970504 0.000019 0 0 0 1 0.713427 -0.69383 0.098087 370.017 0.692628 0.677014 -0.248833 0.000002 0.106242 0.245462 0.963567 0.000011 0 0 0 1 0.659238 -0.746187 0.092786 370.018 0.737499 0.617579 -0.273298 -0.000004 0.146628 0.248599 0.957444 0.000012 0 0 0 1 0.756205 -0.651882 0.056596 370.017 0.637181 0.713946 -0.290315 0 0.148845 0.2556 0.955256 -0.000006 0 0 0 1 0.850192 -0.525734 0.02788 370.017 0.509892 0.809074 -0.292249 -0.000000 0.131088 0.262684 0.955936 0.00001 0 0 0 1 0.827033 -0.558625 0.062882 370.017 0.551503 0.784603 -0.283271 0.000006 0.108905 0.268954 0.956976 0.000008 0 0 0 1 0.770364 -0.626559 0.118166 370.018 0.63182 0.725246 -0.273536 0.000007 0.085686 0.285382 0.954576 -0.000005 0 0 0 1 0.728793 -0.665953 0.159274 370.018 0.680133 0.67712 -0.280939 -0.000002 0.079244 0.313073 0.946417 -0.000016 0 0 0 1 0.718829 -0.670453 0.183786 370.017 0.68974 0.654794 -0.309038 -0.000008 0.086853 0.34891 0.933123 0.000011 0 0 0 1 0.728317 -0.654533 0.202833 370.018 0.678949 0.649273 -0.342743 -0.000014 0.092643 0.387339 0.917271 0.000017 0 0 0 1 0.757213 -0.617882 0.211779 370.017 0.646427 0.662451 -0.378538 -0.000009 0.093599 0.423534 0.901032 -0.000005 0 0 0 1 0.800403 -0.563031 0.205794 370.017 0.592817 0.692455 -0.411186 0.000033 0.089006 0.451113 0.888017 0.000064 0 0 0 1 0.84894 -0.49409 0.187553 370.018 0.522097 0.729053 -0.442601 -0.000023 0.081949 0.473663 0.876885 -0.000023 0 0 0 1 0.896654 -0.412358 0.16116 370.017 0.436675 0.763713 -0.475455 0.000027 0.072977 0.496692 0.864854 0.000013 0 0 0 1 0.937652 -0.323591 0.126884 370.018 0.341886 0.792857 -0.504473 0.000025 0.062641 0.516399 0.854054 -0.000029 0 0 0 1 0.968365 -0.234235 0.086047 370.018 0.24384 0.814927 -0.525773 0.000022 0.053031 0.530122 0.846262 0.000027 0 0 0 1 0.987867 -0.14996 0.040378 370.017 0.148012 0.830403 -0.537144 -0.000011 0.047019 0.536604 0.842523 -0.000028 0 0 0 1 0.997 -0.077044 -0.007368 370.018 0.06102 0.841042 -0.537517 -0.000002 0.04761 0.535455 0.843221 0.000026 0 0 0 1 0.998332 -0.021659 -0.053516 370.017 -0.009837 0.849581 -0.527367 -0.000003 0.056888 0.527014 0.847951 0.000004 0 0 0 1 0.995261 0.013675 -0.09627 370.017 -0.060933 0.859274 -0.507874 -0.000016 0.075777 0.511334 0.856035 0.000011 0 0 0 1 0.97629 -0.195882 -0.09213 370.017 0.122077 0.849696 -0.512946 0.000001 0.178759 0.489537 0.853463 0.000041 0 0 0 1 0.834057 -0.550527 -0.03563 370.017 0.45383 0.721412 -0.52307 0.000011 0.313668 0.4201 0.851545 -0.000054 0 0 0 1 0.69662 -0.717042 0.023882 370.018 0.6266 0.591865 -0.507019 -0.00001 0.349419 0.368165 0.861604 0.000001 0 0 0 1 0.686362 -0.72352 0.073654 370.018 0.661191 0.578623 -0.477517 -0.000035 0.302875 0.37645 0.875529 -0.000007 0 0 0 1 0.717941 -0.68646 0.115466 370.017 0.658332 0.615682 -0.433052 -0.000024 0.226183 0.386921 0.893943 -0.000046 0 0 0 1 0.774098 -0.617017 0.141642 370.018 0.61879 0.690215 -0.375104 -0.000058 0.133682 0.378014 0.916098 0.000014 0 0 0 1 0.838637 -0.523642 0.149954 370.017 0.542604 0.779074 -0.314044 -0.000002 0.047621 0.344735 0.937491 0.000008 0 0 0 1 0.895187 -0.422654 0.141436 370.017 0.445545 0.856753 -0.259737 0.000006 -0.011397 0.295529 0.955266 -0.000008 0 0 0 1 0.9263 -0.356364 0.122359 370.017 0.375358 0.901016 -0.217431 0.000012 -0.032762 0.247335 0.968376 0.000002 0 0 0 1 0.905046 -0.411961 0.105732 370.017 0.425215 0.881798 -0.204021 -0.00001 -0.009185 0.229608 0.97324 0.000009 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.738845 0.63592 -0.222966 186.693 -0.616553 0.77146 0.157199 0.000056 0.271976 0.021325 0.962068 0.000003 0 0 0 1 0.661326 0.716194 -0.222966 186.693 -0.700681 0.695941 0.157199 0.00002 0.267757 0.052268 0.962068 0.000003 0 0 0 1 0.576267 0.786258 -0.222966 186.693 -0.774751 0.612412 0.157199 0.000089 0.260146 0.082155 0.962068 0.000003 0 0 0 1 0.592978 0.773733 -0.222966 186.693 -0.761455 0.628868 0.157199 0.000031 0.261846 0.076563 0.962068 0.000003 0 0 0 1 0.725858 0.650715 -0.222966 186.693 -0.632016 0.758849 0.157199 -0.000107 0.271452 0.026815 0.962068 0.000003 0 0 0 1 0.867578 0.444515 -0.222966 186.693 -0.418027 0.89473 0.157199 0.000031 0.269372 -0.043176 0.962068 0.000003 0 0 0 1 0.958917 0.175396 -0.222966 186.693 -0.142202 0.977275 0.157199 -0.000081 0.245472 -0.119035 0.962068 0.000003 0 0 0 1 0.969269 -0.103912 -0.222966 186.693 0.140953 0.977456 0.157199 -0.000028 0.201616 -0.1838 0.962068 0.000003 0 0 0 1 0.917586 -0.329123 -0.222966 186.693 0.367048 0.916823 0.157199 0.00006 0.152683 -0.226083 0.962068 0.000003 0 0 0 1 0.857136 -0.464331 -0.222966 186.693 0.501703 0.850637 0.157199 -0.000009 0.116671 -0.246604 0.962068 0.000003 0 0 0 1 0.851953 -0.473776 -0.222966 186.693 0.511073 0.845041 0.157199 -0.000053 0.113939 -0.247878 0.962068 0.000003 0 0 0 1 0.900758 -0.372722 -0.222966 186.693 0.410566 0.898178 0.157199 0.000079 0.141672 -0.233141 0.962068 0.000003 0 0 0 1 0.95269 -0.206563 -0.222966 186.693 0.244262 0.956883 0.157199 0.000043 0.180881 -0.204224 0.962068 0.000003 0 0 0 1 0.97432 -0.031512 -0.222966 186.693 0.067836 0.985235 0.157199 -0.000056 0.214708 -0.168281 0.962068 0.000003 0 0 0 1 0.951387 0.21248 -0.222966 186.693 -0.180024 0.97102 0.157199 0.000042 0.249906 -0.109418 0.962068 0.000003 0 0 0 1 0.873378 0.43301 -0.222966 186.693 -0.406165 0.900177 0.157199 -0.000002 0.268778 -0.046732 0.962068 0.000003 0 0 0 1 0.825041 0.519223 -0.222966 186.693 -0.495228 0.854421 0.157199 -0.00008 0.272131 -0.019276 0.962068 0.000003 0 0 0 1 0.797981 0.559921 -0.222966 186.693 -0.537431 0.828527 0.157199 -0.000024 0.272753 -0.005612 0.962068 0.000003 0 0 0 1 0.784918 0.578092 -0.222966 186.693 -0.556308 0.815971 0.157199 0.000049 0.27281 0.000649 0.962068 0.000003 0 0 0 1 0.776656 0.589145 -0.222966 186.693 -0.567804 0.808014 0.157199 0.000055 0.272773 0.004512 0.962068 0.000003 0 0 0 1 0.771069 0.596438 -0.222966 186.693 -0.575393 0.802627 0.157199 -0.000044 0.272718 0.007082 0.962068 0.000003 0 0 0 1 0.767541 0.600972 -0.222966 186.693 -0.580113 0.799223 0.157199 -0.000077 0.272672 0.008688 0.962068 0.000003 0 0 0 1 0.765631 0.603402 -0.222966 186.693 -0.582644 0.79738 0.157199 0.000076 0.272643 0.009552 0.962068 0.000003 0 0 0 1 0.764761 0.604505 -0.222966 186.693 -0.583792 0.796539 0.157199 0.000029 0.272629 0.009946 0.962068 0.000003 0 0 0 1 0.764351 0.605024 -0.222966 186.693 -0.584333 0.796143 0.157199 0.000045 0.272622 0.010131 0.962068 0.000003 0 0 0 1 0.763828 0.605684 -0.222966 186.693 -0.585021 0.795638 0.157199 0.000071 0.272613 0.010367 0.962068 0.000003 0 0 0 1 0.76263 0.607191 -0.222966 186.693 -0.586591 0.794481 0.157199 -0.000037 0.272592 0.010905 0.962068 0.000003 0 0 0 1 0.760135 0.610312 -0.222966 186.693 -0.589843 0.792069 0.157199 -0.00002 0.272545 0.012022 0.962068 0.000003 0 0 0 1 0.755771 0.615708 -0.222966 186.693 -0.595466 0.78785 0.157199 -0.000004 0.272453 0.013962 0.962068 0.000003 0 0 0 1 0.748937 0.624003 -0.222966 186.693 -0.604116 0.781238 0.157199 -0.00002 0.272282 0.016965 0.962068 0.000003 0 0 0 1 0.738845 0.63592 -0.222966 186.693 -0.616553 0.77146 0.157199 0.000018 0.271976 0.021325 0.962068 0.000003 0 0 0 1 0.67708 0.701319 -0.222966 186.693 -0.685042 0.711342 0.157199 -0.000014 0.268849 0.046303 0.962068 0.000003 0 0 0 1 0.584956 0.779815 -0.222966 186.693 -0.767908 0.620971 0.157199 0.000026 0.261042 0.079263 0.962068 0.000003 0 0 0 1 0.592978 0.773733 -0.222966 186.693 -0.761455 0.628868 0.157199 0.000034 0.261846 0.076563 0.962068 0.000003 0 0 0 1 0.725858 0.650715 -0.222966 186.693 -0.632016 0.758849 0.157199 0.000046 0.271452 0.026815 0.962068 0.000003 0 0 0 1 0.867578 0.444515 -0.222966 186.693 -0.418027 0.89473 0.157199 -0.000041 0.269372 -0.043176 0.962068 0.000003 0 0 0 1 0.958917 0.175396 -0.222966 186.693 -0.142202 0.977275 0.157199 -0.000021 0.245472 -0.119035 0.962068 0.000003 0 0 0 1 0.969269 -0.103912 -0.222966 186.693 0.140953 0.977456 0.157199 -0.000022 0.201616 -0.1838 0.962068 0.000003 0 0 0 1 0.917586 -0.329123 -0.222966 186.693 0.367048 0.916823 0.157199 0.000005 0.152683 -0.226083 0.962068 0.000003 0 0 0 1 0.857049 -0.464491 -0.222966 186.693 0.501861 0.850544 0.157199 0.000006 0.116625 -0.246626 0.962068 0.000003 0 0 0 1 0.851953 -0.473776 -0.222966 186.693 0.511073 0.845041 0.157199 0.000085 0.113939 -0.247878 0.962068 0.000003 0 0 0 1 0.900758 -0.372722 -0.222966 186.693 0.410566 0.898178 0.157199 -0.00006 0.141672 -0.233141 0.962068 0.000003 0 0 0 1 0.952922 -0.205493 -0.222966 186.693 0.243187 0.957156 0.157199 0.000138 0.181109 -0.204022 0.962068 0.000003 0 0 0 1 0.974319 -0.031516 -0.222966 186.693 0.06784 0.985235 0.157199 0.00007 0.214707 -0.168282 0.962068 0.000003 0 0 0 1 0.951387 0.21248 -0.222966 186.693 -0.180024 0.97102 0.157199 -0.00004 0.249906 -0.109418 0.962068 0.000003 0 0 0 1 0.873378 0.43301 -0.222966 186.693 -0.406165 0.900177 0.157199 0.000045 0.268778 -0.046732 0.962068 0.000003 0 0 0 1 0.825041 0.519223 -0.222966 186.693 -0.495228 0.854422 0.157199 0.000008 0.272131 -0.019276 0.962068 0.000003 0 0 0 1 0.797981 0.559921 -0.222966 186.693 -0.537431 0.828527 0.157199 0.000043 0.272753 -0.005612 0.962068 0.000003 0 0 0 1 0.784918 0.578092 -0.222966 186.693 -0.556308 0.815971 0.157199 0.000002 0.27281 0.000649 0.962068 0.000003 0 0 0 1 0.776656 0.589145 -0.222966 186.693 -0.567804 0.808014 0.157199 -0.000071 0.272773 0.004512 0.962068 0.000003 0 0 0 1 0.771069 0.596439 -0.222966 186.693 -0.575393 0.802627 0.157199 -0.00017 0.272718 0.007081 0.962068 0.000003 0 0 0 1 0.767558 0.60095 -0.222966 186.693 -0.580091 0.799239 0.157199 -0.000006 0.272672 0.00868 0.962068 0.000003 0 0 0 1 0.765631 0.603402 -0.222966 186.693 -0.582643 0.79738 0.157199 -0.000076 0.272643 0.009552 0.962068 0.000003 0 0 0 1 0.764761 0.604505 -0.222966 186.693 -0.583792 0.796539 0.157199 0.0001 0.272629 0.009946 0.962068 0.000003 0 0 0 1 0.764348 0.605028 -0.222966 186.693 -0.584337 0.79614 0.157199 0.000051 0.272622 0.010132 0.962068 0.000003 0 0 0 1 0.763828 0.605684 -0.222966 186.693 -0.585021 0.795638 0.157199 0.000005 0.272613 0.010367 0.962068 0.000003 0 0 0 1 0.76263 0.607191 -0.222966 186.693 -0.586591 0.794481 0.157199 -0.000025 0.272592 0.010905 0.962068 0.000003 0 0 0 1 0.760135 0.610312 -0.222966 186.693 -0.589843 0.792069 0.157199 -0.000089 0.272545 0.012022 0.962068 0.000003 0 0 0 1 0.755771 0.615708 -0.222966 186.693 -0.595466 0.78785 0.157199 -0.000073 0.272453 0.013962 0.962068 0.000003 0 0 0 1 0.748937 0.624003 -0.222966 186.693 -0.604116 0.781238 0.157199 0.000018 0.272282 0.016964 0.962068 0.000003 0 0 0 1 0.738845 0.63592 -0.222966 186.693 -0.616553 0.77146 0.157199 0.000033 0.271976 0.021325 0.962068 0.000003 0 0 0 1 0.677558 0.700857 -0.222966 186.693 -0.684556 0.711809 0.157199 -0.000031 0.268883 0.046121 0.962068 0.000003 0 0 0 1 0.584956 0.779815 -0.222966 186.693 -0.767908 0.620971 0.157199 -0.000042 0.261042 0.079263 0.962068 0.000003 0 0 0 1 0.593121 0.773623 -0.222966 186.693 -0.761339 0.629009 0.157199 0.000003 0.261861 0.076514 0.962068 0.000003 0 0 0 1 0.725855 0.650718 -0.222966 186.693 -0.63202 0.758846 0.157199 -0.000094 0.271452 0.026816 0.962068 0.000003 0 0 0 1 0.867578 0.444515 -0.222966 186.693 -0.418027 0.89473 0.157199 0.000111 0.269372 -0.043176 0.962068 0.000003 0 0 0 1 0.958917 0.175396 -0.222966 186.693 -0.142202 0.977275 0.157199 -0.000019 0.245472 -0.119035 0.962068 0.000003 0 0 0 1 0.969269 -0.103912 -0.222966 186.693 0.140953 0.977456 0.157199 -0.000027 0.201616 -0.1838 0.962068 0.000003 0 0 0 1 0.917586 -0.329123 -0.222966 186.693 0.367048 0.916823 0.157199 0.000004 0.152683 -0.226083 0.962068 0.000003 0 0 0 1 0.85705 -0.464491 -0.222966 186.693 0.501862 0.850544 0.157199 0.000017 0.116625 -0.246626 0.962068 0.000003 0 0 0 1 0.851953 -0.473775 -0.222966 186.693 0.511073 0.845041 0.157199 -0.000052 0.113939 -0.247878 0.962068 0.000003 0 0 0 1 0.900758 -0.372722 -0.222966 186.693 0.410566 0.898178 0.157199 -0.000053 0.141672 -0.233141 0.962068 0.000003 0 0 0 1 0.95269 -0.206562 -0.222966 186.693 0.244262 0.956883 0.157199 0.00007 0.180881 -0.204224 0.962068 0.000003 0 0 0 1 0.97432 -0.031512 -0.222966 186.693 0.067836 0.985235 0.157199 0.00006 0.214708 -0.168281 0.962068 0.000003 0 0 0 1 0.951387 0.21248 -0.222966 186.693 -0.180024 0.97102 0.157199 -0.000028 0.249906 -0.109418 0.962068 0.000003 0 0 0 1 0.873378 0.43301 -0.222966 186.693 -0.406165 0.900177 0.157199 0.000052 0.268778 -0.046732 0.962068 0.000003 0 0 0 1 0.825287 0.518833 -0.222966 186.693 -0.494825 0.854656 0.157199 0.000086 0.272119 -0.019404 0.962068 0.000003 0 0 0 1 0.797981 0.559921 -0.222966 186.693 -0.537431 0.828527 0.157199 0.000027 0.272753 -0.005612 0.962068 0.000003 0 0 0 1 0.784851 0.578183 -0.222966 186.693 -0.556403 0.815907 0.157199 -0.000031 0.27281 0.000681 0.962068 0.000003 0 0 0 1 0.776656 0.589145 -0.222966 186.693 -0.567803 0.808014 0.157199 0.000018 0.272773 0.004511 0.962068 0.000003 0 0 0 1 0.771069 0.596438 -0.222966 186.693 -0.575393 0.802627 0.157199 0.000004 0.272718 0.007082 0.962068 0.000003 0 0 0 1 0.767558 0.60095 -0.222966 186.693 -0.580091 0.799239 0.157199 0.000024 0.272672 0.00868 0.962068 0.000003 0 0 0 1 0.76564 0.603391 -0.222966 186.693 -0.582632 0.797388 0.157199 0.000084 0.272643 0.009548 0.962068 0.000003 0 0 0 1 0.764761 0.604505 -0.222966 186.693 -0.583792 0.796539 0.157199 -0.000038 0.272629 0.009946 0.962068 0.000003 0 0 0 1 0.764348 0.605028 -0.222966 186.693 -0.584337 0.79614 0.157199 -0.00001 0.272622 0.010132 0.962068 0.000003 0 0 0 1 0.763828 0.605684 -0.222966 186.693 -0.585021 0.795638 0.157199 -0.000013 0.272613 0.010367 0.962068 0.000003 0 0 0 1 0.76263 0.607191 -0.222966 186.693 -0.586591 0.794481 0.157199 0.00014 0.272592 0.010905 0.962068 0.000003 0 0 0 1 0.760156 0.610286 -0.222966 186.693 -0.589815 0.79209 0.157199 -0.000005 0.272546 0.012013 0.962068 0.000003 0 0 0 1 0.755771 0.615708 -0.222966 186.693 -0.595466 0.78785 0.157199 -0.000094 0.272453 0.013962 0.962068 0.000003 0 0 0 1 0.748937 0.624003 -0.222966 186.693 -0.604116 0.781238 0.157199 0.000006 0.272282 0.016965 0.962068 0.000003 0 0 0 1 0.738845 0.63592 -0.222966 186.693 -0.616553 0.77146 0.157199 0.000061 0.271976 0.021325 0.962068 0.000003 0 0 0 1 0.677558 0.700857 -0.222966 186.693 -0.684556 0.711809 0.157199 0.000074 0.268883 0.046121 0.962068 0.000003 0 0 0 1 0.584956 0.779815 -0.222966 186.693 -0.767908 0.620971 0.157199 -0.000005 0.261042 0.079263 0.962068 0.000003 0 0 0 1 0.593121 0.773623 -0.222966 186.693 -0.761339 0.629009 0.157199 0.000014 0.261861 0.076514 0.962068 0.000003 0 0 0 1 0.725855 0.650718 -0.222966 186.693 -0.63202 0.758846 0.157199 0.000054 0.271452 0.026816 0.962068 0.000003 0 0 0 1 0.867579 0.444515 -0.222966 186.693 -0.418027 0.89473 0.157199 -0.000005 0.269372 -0.043176 0.962068 0.000003 0 0 0 1 0.958917 0.175396 -0.222966 186.693 -0.142202 0.977275 0.157199 0.000007 0.245472 -0.119035 0.962068 0.000003 0 0 0 1 0.969441 -0.102321 -0.222966 186.693 0.139346 0.977687 0.157199 -0.000047 0.201906 -0.183465 0.962068 0.000003 0 0 0 1 0.917586 -0.329123 -0.222966 186.693 0.367048 0.916823 0.157199 -0.000052 0.152683 -0.226083 0.962068 0.000003 0 0 0 1 0.85705 -0.464491 -0.222966 186.693 0.501862 0.850544 0.157199 -0.000007 0.116625 -0.246626 0.962068 0.000003 0 0 0 1 0.851953 -0.473776 -0.222966 186.693 0.511073 0.845041 0.157199 0.000131 0.113939 -0.247878 0.962068 0.000003 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 1 0 0 167.761 -0.000000 1 0 -0.000005 0 0 -1 -0.000044 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000006 0 0 -1 0.000005 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000034 0 0 -1 0.000001 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000054 0 0 -1 0.000014 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000011 0 0 -1 -0.000016 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000084 0 0 -1 0.000001 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000083 0 0 -1 -0.000007 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000115 0 0 -1 0.000048 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000057 0 0 -1 0.000022 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000004 0 0 -1 -0.000034 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000008 0 0 -1 0.000003 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000005 0 0 -1 0.000021 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000051 0 0 -1 0.000032 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000024 0 0 -1 0.000003 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000022 0 0 -1 0.000038 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.00001 0 0 -1 0.00001 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.00004 0 0 -1 -0.000013 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000017 0 0 -1 0.000019 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000019 0 0 -1 -0.000017 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000038 0 0 -1 0.000019 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000006 0 0 -1 -0.000017 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000011 0 0 -1 -0.000002 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000025 0 0 -1 0.000012 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000007 0 0 -1 0.000003 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000037 0 0 -1 0.000003 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000013 0 0 -1 0.000011 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000004 0 0 -1 -0.000033 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000018 0 0 -1 -0.000023 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000007 0 0 -1 0.000012 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000025 0 0 -1 0.000026 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000017 0 0 -1 0.000005 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000025 0 0 -1 -0.000064 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000031 0 0 -1 -0.000006 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000029 0 0 -1 0.000002 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.00007 0 0 -1 -0.000003 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000026 0 0 -1 -0.000003 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000016 0 0 -1 0.000022 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000013 0 0 -1 -0.00001 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.00003 0 0 -1 0.000000 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000008 0 0 -1 -0.000005 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000016 0 0 -1 0.00003 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000077 0 0 -1 -0.000032 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000021 0 0 -1 -0.000015 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000069 0 0 -1 0.000006 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000038 0 0 -1 0.000016 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000014 0 0 -1 0.000011 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000002 0 0 -1 0.00002 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000016 0 0 -1 -0.000043 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000006 0 0 -1 0.000003 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000012 0 0 -1 -0.000019 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000002 0 0 -1 -0.000014 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000015 0 0 -1 0.000011 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000001 0 0 -1 0.000008 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000019 0 0 -1 0.000041 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000039 0 0 -1 0.000057 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000005 0 0 -1 0.000008 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000005 0 0 -1 -0.000002 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000002 0 0 -1 -0.000068 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000026 0 0 -1 0.000062 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.00003 0 0 -1 -0.000016 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000015 0 0 -1 0.000016 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000063 0 0 -1 0.000003 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000062 0 0 -1 0.000004 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000014 0 0 -1 -0.000001 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000027 0 0 -1 0.000001 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000005 0 0 -1 0.000000 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000035 0 0 -1 -0.000009 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000028 0 0 -1 -0.00001 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000032 0 0 -1 0.000036 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000063 0 0 -1 0.000005 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000094 0 0 -1 -0.000016 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000034 0 0 -1 -0.000014 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000033 0 0 -1 -0.000041 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.00003 0 0 -1 -0.000005 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000035 0 0 -1 -0.000018 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000015 0 0 -1 0.000015 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000008 0 0 -1 0.000061 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000011 0 0 -1 0.000004 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000033 0 0 -1 0.000007 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000029 0 0 -1 -0.000023 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000018 0 0 -1 0.000002 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000014 0 0 -1 -0.000011 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000003 0 0 -1 0.000024 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000043 0 0 -1 -0.000008 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000008 0 0 -1 -0.000013 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000005 0 0 -1 -0.000016 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000007 0 0 -1 0.000004 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000056 0 0 -1 0.000019 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000007 0 0 -1 0.000011 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000005 0 0 -1 -0.000003 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000012 0 0 -1 -0.000022 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000005 0 0 -1 0.000009 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000003 0 0 -1 -0.000009 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.00003 0 0 -1 -0.000021 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000062 0 0 -1 -0.000007 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000051 0 0 -1 0.000004 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000101 0 0 -1 0.000037 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000004 0 0 -1 0.000021 0 0 0 1 1 0 0 167.761 -0.000000 1 0 -0.000076 0 0 -1 -0.000002 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.000006 0 0 -1 0.000035 0 0 0 1 1 0 0 167.761 -0.000000 1 0 0.00004 0 0 -1 0.000026 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.429568 0.848459 0.309172 -115.92 0.861327 -0.487813 0.141963 125.412 0.271268 0.205316 -0.940351 124.981 0 0 0 1 0.414135 0.861857 0.292737 -114.26 0.868422 -0.470463 0.156551 120.63 0.272646 0.189386 -0.943291 131.056 0 0 0 1 0.393969 0.877361 0.273911 -112.518 0.878343 -0.447166 0.168983 115.442 0.270743 0.174014 -0.946793 137.085 0 0 0 1 0.386422 0.886252 0.255412 -110.479 0.882967 -0.435495 0.175249 110.057 0.266546 0.1578 -0.950817 143.031 0 0 0 1 0.408573 0.88068 0.239734 -108.011 0.874018 -0.453188 0.175251 104.786 0.262984 0.137929 -0.954889 148.749 0 0 0 1 0.480036 0.846385 0.230647 -105.094 0.836115 -0.520997 0.171683 100.035 0.265477 0.110433 -0.957772 154.006 0 0 0 1 0.582707 0.77933 0.230427 -101.655 0.766452 -0.621274 0.163005 96.0177 0.270193 0.081627 -0.95934 158.789 0 0 0 1 0.684247 0.689777 0.236675 -97.6841 0.677637 -0.721327 0.143164 93.0422 0.26947 0.062421 -0.960984 162.991 0 0 0 1 0.775238 0.582488 0.244365 -92.7271 0.575063 -0.810881 0.108513 91.1062 0.261358 0.056402 -0.963593 166.929 0 0 0 1 0.856826 0.452785 0.246646 -86.5382 0.453072 -0.889518 0.059018 89.7743 0.246119 0.061179 -0.967307 170.923 0 0 0 1 0.916742 0.324731 0.232667 -79.686 0.332027 -0.943234 0.008224 88.8477 0.22213 0.069712 -0.972522 174.696 0 0 0 1 0.956245 0.208734 0.205001 -72.8976 0.219844 -0.974985 -0.032745 88.1947 0.193038 0.076381 -0.978214 177.96 0 0 0 1 0.978883 0.107643 0.173783 -66.6625 0.12027 -0.990688 -0.063809 87.7305 0.165296 0.083362 -0.982715 180.613 0 0 0 1 0.988665 0.037923 0.145273 -61.6267 0.050401 -0.995258 -0.083193 87.4635 0.141428 0.089572 -0.985888 182.521 0 0 0 1 0.992285 0.002759 0.123943 -58.4975 0.014425 -0.995531 -0.093326 87.4474 0.123132 0.094394 -0.987891 183.555 0 0 0 1 0.993853 -0.006712 0.110503 -57.8232 0.004174 -0.995179 -0.097985 87.7391 0.110627 0.097844 -0.989034 183.63 0 0 0 1 0.994707 0.008648 0.102389 -60.7708 0.018088 -0.995629 -0.091628 88.5715 0.101149 0.092995 -0.990516 182.275 0 0 0 1 0.994355 0.040467 0.098081 -67.1313 0.0482 -0.995803 -0.077801 89.9402 0.094521 0.082089 -0.992132 179.352 0 0 0 1 0.992308 0.070423 0.10181 -75.7375 0.077777 -0.994499 -0.070165 91.5532 0.096309 0.077544 -0.992326 175.06 0 0 0 1 0.984346 0.112515 0.135663 -85.3657 0.123438 -0.989517 -0.074959 93.179 0.125807 0.090532 -0.987916 169.693 0 0 0 1 0.970497 0.169177 0.171795 -94.6246 0.184122 -0.980035 -0.075031 94.7186 0.155671 0.10445 -0.982271 163.831 0 0 0 1 0.948042 0.242175 0.206318 -102.596 0.260832 -0.962972 -0.068201 96.3344 0.182161 0.118473 -0.976106 157.991 0 0 0 1 0.916265 0.32571 0.233178 -108.07 0.346698 -0.936401 -0.054343 98.2688 0.200647 0.130635 -0.970915 153.077 0 0 0 1 0.875528 0.410082 0.255508 -111.57 0.432537 -0.900887 -0.036245 101.146 0.21532 0.14225 -0.966127 148.633 0 0 0 1 0.825785 0.490519 0.278334 -114.25 0.514318 -0.857473 -0.014764 105.118 0.231421 0.155344 -0.960371 143.77 0 0 0 1 0.768664 0.565475 0.298987 -116.065 0.589951 -0.807374 0.010285 109.731 0.247211 0.168481 -0.954201 138.793 0 0 0 1 0.70704 0.633172 0.31494 -117.029 0.657312 -0.752682 0.037565 114.421 0.260835 0.180454 -0.948368 134.13 0 0 0 1 0.640808 0.695527 0.324974 -117.289 0.718186 -0.692681 0.066339 118.827 0.271245 0.190881 -0.943394 130.019 0 0 0 1 0.572194 0.75178 0.327751 -117.028 0.771914 -0.628678 0.094412 122.406 0.277028 0.198973 -0.940035 126.906 0 0 0 1 0.501898 0.802455 0.322746 -116.494 0.819252 -0.560713 0.120113 124.736 0.277353 0.204125 -0.938833 125.121 0 0 0 1 0.429508 0.848371 0.309498 -115.92 0.861301 -0.487853 0.141988 125.412 0.271448 0.205586 -0.94024 124.981 0 0 0 1 0.375514 0.87848 0.295403 -115.236 0.886527 -0.433409 0.161945 123.696 0.270296 0.20107 -0.941547 127.297 0 0 0 1 0.361623 0.887588 0.285335 -114.111 0.889924 -0.419859 0.178194 119.737 0.277963 0.189488 -0.941717 132 0 0 0 1 0.379552 0.88369 0.273921 -112.277 0.880876 -0.435693 0.185011 114.234 0.282838 0.171069 -0.943789 138.286 0 0 0 1 0.415351 0.872672 0.256759 -109.567 0.865868 -0.465803 0.182482 107.947 0.278847 0.146526 -0.949092 145.318 0 0 0 1 0.484053 0.841626 0.239497 -106.07 0.830951 -0.527894 0.175636 101.811 0.274248 0.113993 -0.954879 152.165 0 0 0 1 0.583948 0.777781 0.232512 -101.976 0.764692 -0.623164 0.164052 96.5541 0.27249 0.082002 -0.958658 158.258 0 0 0 1 0.684247 0.689783 0.236659 -97.6832 0.677647 -0.721321 0.14315 93.0404 0.269449 0.062421 -0.96099 162.993 0 0 0 1 0.775161 0.582432 0.24474 -92.7271 0.57503 -0.810905 0.108508 91.1061 0.26166 0.056622 -0.963498 166.929 0 0 0 1 0.857255 0.451965 0.246662 -86.4975 0.452305 -0.889931 0.058692 89.7672 0.246038 0.061251 -0.967323 170.947 0 0 0 1 0.916807 0.324778 0.232342 -79.6861 0.33203 -0.943232 0.008318 88.8478 0.221854 0.069518 -0.972599 174.696 0 0 0 1 0.956298 0.208771 0.204717 -72.8975 0.219835 -0.974992 -0.032621 88.1947 0.192787 0.076198 -0.978277 177.96 0 0 0 1 0.979009 0.107134 0.173389 -66.6273 0.119725 -0.990753 -0.063836 87.7282 0.164947 0.083256 -0.982782 180.628 0 0 0 1 0.988681 0.037937 0.145157 -61.6268 0.050392 -0.995266 -0.0831 87.4637 0.141317 0.089474 -0.985913 182.521 0 0 0 1 0.992291 0.002764 0.123898 -58.4974 0.01442 -0.995535 -0.093284 87.4474 0.123087 0.094352 -0.9879 183.555 0 0 0 1 0.993853 -0.006711 0.110502 -57.8232 0.004173 -0.995179 -0.097985 87.739 0.110627 0.097844 -0.989034 183.63 0 0 0 1 0.994706 0.008646 0.102402 -60.7709 0.018088 -0.995627 -0.091642 88.5715 0.101161 0.093009 -0.990513 182.275 0 0 0 1 0.994355 0.040466 0.098089 -67.1313 0.0482 -0.995802 -0.077806 89.9402 0.094529 0.082095 -0.992131 179.352 0 0 0 1 0.992308 0.070425 0.10181 -75.7375 0.077779 -0.994499 -0.070165 91.5533 0.096309 0.077544 -0.992326 175.06 0 0 0 1 0.984345 0.112516 0.135664 -85.3657 0.123438 -0.989517 -0.07496 93.179 0.125808 0.090532 -0.987916 169.693 0 0 0 1 0.970497 0.169178 0.1718 -94.6246 0.184123 -0.980035 -0.075035 94.7186 0.155675 0.104454 -0.98227 163.831 0 0 0 1 0.948208 0.241684 0.206135 -102.554 0.260323 -0.963105 -0.068272 96.3233 0.182029 0.118398 -0.976139 158.025 0 0 0 1 0.916261 0.325707 0.233195 -108.07 0.346699 -0.9364 -0.05435 98.2688 0.200662 0.130647 -0.970911 153.077 0 0 0 1 0.875523 0.410078 0.255532 -111.57 0.432538 -0.900887 -0.036251 101.146 0.215339 0.142267 -0.966121 148.633 0 0 0 1 0.825444 0.490999 0.278501 -114.264 0.51481 -0.857179 -0.014625 105.145 0.231544 0.155447 -0.960325 143.739 0 0 0 1 0.768658 0.565465 0.299021 -116.065 0.589948 -0.807376 0.010278 109.731 0.247235 0.168506 -0.954192 138.794 0 0 0 1 0.707032 0.633163 0.314977 -117.029 0.657311 -0.752683 0.03756 114.421 0.26086 0.180481 -0.948356 134.13 0 0 0 1 0.640801 0.695518 0.325009 -117.289 0.718185 -0.692683 0.066337 118.827 0.271267 0.190907 -0.943382 130.019 0 0 0 1 0.572188 0.751772 0.32778 -117.028 0.771911 -0.628681 0.094412 122.406 0.277045 0.198995 -0.940025 126.906 0 0 0 1 0.501894 0.80245 0.322762 -116.494 0.81925 -0.560715 0.120114 124.736 0.277364 0.204139 -0.938828 125.121 0 0 0 1 0.429509 0.848371 0.309498 -115.92 0.8613 -0.487854 0.141988 125.412 0.271448 0.205586 -0.94024 124.981 0 0 0 1 0.375735 0.878377 0.295425 -115.242 0.886443 -0.433619 0.161844 123.713 0.270262 0.201067 -0.941558 127.275 0 0 0 1 0.361652 0.887632 0.285163 -114.111 0.889942 -0.419832 0.178167 119.737 0.277867 0.189344 -0.941774 132 0 0 0 1 0.379767 0.883711 0.273553 -112.263 0.880835 -0.43579 0.184973 114.197 0.282674 0.170709 -0.943903 138.327 0 0 0 1 0.415405 0.872743 0.256435 -109.567 0.865909 -0.465753 0.182422 107.947 0.278642 0.14627 -0.949191 145.317 0 0 0 1 0.484097 0.841673 0.239242 -106.07 0.830984 -0.527859 0.175588 101.811 0.274074 0.113805 -0.954951 152.165 0 0 0 1 0.583968 0.777798 0.232403 -101.976 0.764706 -0.623151 0.164035 96.5542 0.272408 0.081927 -0.958687 158.258 0 0 0 1 0.684247 0.689782 0.236659 -97.6832 0.677646 -0.721321 0.14315 93.0404 0.269449 0.062421 -0.96099 162.993 0 0 0 1 0.775157 0.582428 0.244764 -92.7271 0.575027 -0.810907 0.108508 91.1061 0.261679 0.056635 -0.963492 166.929 0 0 0 1 0.857252 0.451964 0.246673 -86.4975 0.452304 -0.889931 0.05869 89.7672 0.246048 0.061258 -0.96732 170.947 0 0 0 1 0.916807 0.324779 0.232342 -79.6861 0.332031 -0.943232 0.008317 88.8478 0.221854 0.069519 -0.972599 174.696 0 0 0 1 0.956298 0.208771 0.204717 -72.8975 0.219836 -0.974991 -0.032621 88.1947 0.192787 0.0762 -0.978277 177.96 0 0 0 1 0.978917 0.107669 0.173579 -66.6626 0.120257 -0.990698 -0.063683 87.7306 0.165108 0.083214 -0.982759 180.613 0 0 0 1 0.988681 0.037936 0.145157 -61.6267 0.050391 -0.995266 -0.083101 87.4636 0.141317 0.089475 -0.985913 182.521 0 0 0 1 0.992291 0.002764 0.123898 -58.4974 0.014421 -0.995535 -0.093284 87.4474 0.123087 0.094352 -0.9879 183.555 0 0 0 1 0.993853 -0.006711 0.110502 -57.8232 0.004173 -0.995179 -0.097985 87.739 0.110627 0.097844 -0.989034 183.63 0 0 0 1 0.994703 0.008498 0.10244 -60.7417 0.01795 -0.995624 -0.091705 88.5645 0.101212 0.093058 -0.990503 182.288 0 0 0 1 0.994355 0.040466 0.098089 -67.1313 0.0482 -0.995802 -0.077806 89.9402 0.094529 0.082095 -0.992131 179.352 0 0 0 1 0.992286 0.070658 0.101859 -75.7945 0.078015 -0.994482 -0.070139 91.5633 0.096341 0.077544 -0.992323 175.03 0 0 0 1 0.984343 0.112513 0.135686 -85.3656 0.123439 -0.989515 -0.074977 93.1789 0.125828 0.090553 -0.987911 169.693 0 0 0 1 0.970489 0.16917 0.171849 -94.6246 0.184125 -0.980032 -0.075067 94.7186 0.155718 0.104494 -0.982259 163.831 0 0 0 1 0.948194 0.24167 0.206214 -102.554 0.260327 -0.963101 -0.068314 96.3234 0.182095 0.118458 -0.976119 158.025 0 0 0 1 0.916466 0.325162 0.233152 -108.042 0.346166 -0.936589 -0.054497 98.2537 0.200647 0.130655 -0.970912 153.106 0 0 0 1 0.875494 0.41005 0.255676 -111.57 0.432542 -0.900883 -0.0363 101.146 0.215449 0.142371 -0.966081 148.633 0 0 0 1 0.825406 0.490962 0.278677 -114.264 0.514812 -0.857177 -0.014669 105.145 0.231673 0.155574 -0.960272 143.739 0 0 0 1 0.768611 0.565419 0.299228 -116.065 0.589948 -0.807376 0.010241 109.731 0.247381 0.168657 -0.954126 138.794 0 0 0 1 0.70698 0.633105 0.315212 -117.029 0.657304 -0.75269 0.037531 114.421 0.261018 0.180656 -0.948279 134.13 0 0 0 1 0.641165 0.695078 0.32523 -117.289 0.717815 -0.693085 0.066139 118.802 0.271384 0.191048 -0.943319 130.042 0 0 0 1 0.572124 0.751696 0.328065 -117.028 0.771896 -0.628701 0.094406 122.406 0.27722 0.19922 -0.939926 126.906 0 0 0 1 0.501834 0.802365 0.323069 -116.494 0.819228 -0.560747 0.120122 124.736 0.277541 0.204386 -0.938721 125.121 0 0 0 1 0.429449 0.848282 0.309824 -115.92 0.861274 -0.487894 0.142012 125.412 0.271627 0.205856 -0.940129 124.981 0 0 0 1 0.375676 0.878287 0.295769 -115.242 0.886412 -0.433667 0.161885 123.714 0.270447 0.201356 -0.941442 127.275 0 0 0 1 0.361591 0.887542 0.285519 -114.111 0.889905 -0.419887 0.178222 119.737 0.278066 0.189641 -0.941656 132 0 0 0 1 0.379707 0.883628 0.273905 -112.263 0.880795 -0.435846 0.185033 114.197 0.282881 0.170997 -0.943789 138.327 0 0 0 1 0.41535 0.872674 0.256759 -109.567 0.86587 -0.4658 0.182482 107.947 0.278846 0.146527 -0.949092 145.317 0 0 0 1 0.484058 0.841632 0.239465 -106.07 0.830956 -0.527889 0.175629 101.811 0.274226 0.11397 -0.954888 152.165 0 0 0 1 0.583954 0.777787 0.232478 -101.976 0.764697 -0.623159 0.164047 96.5542 0.272464 0.081979 -0.958667 158.258 0 0 0 1 0.683645 0.690393 0.236615 -97.7121 0.678239 -0.72073 0.14332 93.0574 0.269483 0.062501 -0.960975 162.966 0 0 0 1 0.775137 0.582414 0.244859 -92.7271 0.575018 -0.810913 0.108507 91.1061 0.261755 0.05669 -0.963468 166.929 0 0 0 1 0.857196 0.451926 0.246938 -86.4975 0.452292 -0.88994 0.058653 89.7672 0.246266 0.061409 -0.967255 170.947 0 0 0 1 0.916741 0.324733 0.232665 -79.6861 0.33203 -0.943233 0.008225 88.8478 0.222129 0.069711 -0.972522 174.696 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.371507 0.92843 0 547.819 -0.92843 0.371507 0 -0.000005 0 0 1 -0.000012 0 0 0 1 0.332374 0.943148 0 547.819 -0.943148 0.332374 0 0.000013 0 0 1 -0.000012 0 0 0 1 0.307307 0.95161 0 547.819 -0.95161 0.307307 0 0.000033 0 0 1 -0.000012 0 0 0 1 0.274732 0.961521 0 547.819 -0.961521 0.274732 0 -0.000023 0 0 1 -0.000012 0 0 0 1 0.206204 0.978509 0 547.819 -0.978508 0.206204 0 -0.000007 0 0 1 -0.000012 0 0 0 1 0.059911 0.998204 0 547.819 -0.998204 0.059911 0 -0.000007 0 0 1 -0.000012 0 0 0 1 -0.124243 0.992252 0 547.819 -0.992252 -0.124243 0 -0.000000 0 0 1 -0.000012 0 0 0 1 -0.265996 0.963974 0 547.819 -0.963974 -0.265996 0 0.000023 0 0 1 -0.000012 0 0 0 1 -0.347693 0.937608 0 547.819 -0.937608 -0.347693 0 -0.000043 0 0 1 -0.000012 0 0 0 1 -0.387139 0.922021 0 547.819 -0.922021 -0.387139 0 -0.000006 0 0 1 -0.000012 0 0 0 1 -0.383624 0.92349 0 547.819 -0.92349 -0.383624 0 -0.000071 0 0 1 -0.000012 0 0 0 1 -0.345151 0.938547 0 547.819 -0.938547 -0.345151 0 -0.000026 0 0 1 -0.000012 0 0 0 1 -0.27213 0.96226 0 547.819 -0.96226 -0.27213 0 -0.000048 0 0 1 -0.000012 0 0 0 1 -0.169694 0.985496 0 547.819 -0.985497 -0.169694 0 -0.00001 0 0 1 -0.000012 0 0 0 1 -0.056478 0.998404 0 547.819 -0.998404 -0.056478 0 0.000026 0 0 1 -0.000012 0 0 0 1 0.044008 0.999031 0 547.819 -0.999031 0.044008 0 -0.000085 0 0 1 -0.000012 0 0 0 1 0.078392 0.996922 0 547.819 -0.996922 0.078392 0 0.000046 0 0 1 -0.000012 0 0 0 1 0.052376 0.998627 0 547.819 -0.998627 0.052376 0 -0.000005 0 0 1 -0.000012 0 0 0 1 0.025234 0.999682 0 547.819 -0.999682 0.025234 0 -0.000046 0 0 1 -0.000012 0 0 0 1 -0.044561 0.999007 0 547.819 -0.999007 -0.044561 0 -0.000147 0 0 1 -0.000012 0 0 0 1 -0.093552 0.995614 0 547.819 -0.995614 -0.093552 0 -0.000049 0 0 1 -0.000012 0 0 0 1 -0.116381 0.993205 0 547.819 -0.993205 -0.116381 0 -0.000067 0 0 1 -0.000012 0 0 0 1 -0.112501 0.993652 0 547.819 -0.993652 -0.112501 0 -0.000005 0 0 1 -0.000012 0 0 0 1 -0.088307 0.996093 0 547.819 -0.996093 -0.088307 0 0.00005 0 0 1 -0.000012 0 0 0 1 -0.047213 0.998885 0 547.819 -0.998885 -0.047213 0 -0.000037 0 0 1 -0.000012 0 0 0 1 0.007989 0.999968 0 547.819 -0.999968 0.007989 0 0.000041 0 0 1 -0.000012 0 0 0 1 0.072962 0.997335 0 547.819 -0.997335 0.072962 0 0.000029 0 0 1 -0.000012 0 0 0 1 0.145973 0.989288 0 547.819 -0.989288 0.145973 0 -0.000015 0 0 1 -0.000012 0 0 0 1 0.222291 0.97498 0 547.819 -0.97498 0.222291 0 0.000023 0 0 1 -0.000012 0 0 0 1 0.29835 0.954457 0 547.819 -0.954457 0.29835 0 -0.000002 0 0 1 -0.000012 0 0 0 1 0.371509 0.92843 0 547.819 -0.928429 0.371509 0 0.000035 0 0 1 -0.000012 0 0 0 1 0.40134 0.915929 0 547.819 -0.915929 0.40134 0 -0.000002 0 0 1 -0.000012 0 0 0 1 0.36677 0.930312 0 547.819 -0.930312 0.366769 0 0.000001 0 0 1 -0.000012 0 0 0 1 0.295347 0.95539 0 547.819 -0.95539 0.295347 0 -0.000021 0 0 1 -0.000012 0 0 0 1 0.204634 0.978838 0 547.819 -0.978838 0.204634 0 0.000046 0 0 1 -0.000012 0 0 0 1 0.057518 0.998345 0 547.819 -0.998344 0.057518 0 -0.000024 0 0 1 -0.000012 0 0 0 1 -0.125455 0.992099 0 547.819 -0.992099 -0.125455 0 -0.000041 0 0 1 -0.000012 0 0 0 1 -0.265994 0.963975 0 547.819 -0.963975 -0.265994 0 0.00006 0 0 1 -0.000012 0 0 0 1 -0.347694 0.937608 0 547.819 -0.937608 -0.347694 0 -0.000001 0 0 1 -0.000012 0 0 0 1 -0.38714 0.922021 0 547.819 -0.922021 -0.38714 0 -0.000022 0 0 1 -0.000012 0 0 0 1 -0.383625 0.923488 0 547.819 -0.923488 -0.383626 0 -0.000016 0 0 1 -0.000012 0 0 0 1 -0.345151 0.938547 0 547.819 -0.938547 -0.345151 0 -0.00003 0 0 1 -0.000012 0 0 0 1 -0.271583 0.962415 0 547.819 -0.962415 -0.271583 0 0.000046 0 0 1 -0.000012 0 0 0 1 -0.169696 0.985496 0 547.819 -0.985496 -0.169696 0 0.000022 0 0 1 -0.000012 0 0 0 1 -0.056478 0.998404 0 547.819 -0.998404 -0.056478 0 0.000005 0 0 1 -0.000012 0 0 0 1 0.044008 0.999031 0 547.819 -0.999031 0.044008 0 -0.000026 0 0 1 -0.000012 0 0 0 1 0.07839 0.996922 0 547.819 -0.996923 0.07839 0 0.000000 0 0 1 -0.000012 0 0 0 1 0.052375 0.998627 0 547.819 -0.998627 0.052375 0 -0.000048 0 0 1 -0.000012 0 0 0 1 0.025234 0.999682 0 547.819 -0.999682 0.025234 0 -0.000012 0 0 1 -0.000012 0 0 0 1 -0.044561 0.999006 0 547.819 -0.999007 -0.044561 0 0.000067 0 0 1 -0.000012 0 0 0 1 -0.093552 0.995614 0 547.819 -0.995614 -0.093552 0 0.000003 0 0 1 -0.000012 0 0 0 1 -0.116381 0.993205 0 547.819 -0.993205 -0.116381 0 0.000025 0 0 1 -0.000012 0 0 0 1 -0.1125 0.993652 0 547.819 -0.993652 -0.1125 0 0.00005 0 0 1 -0.000012 0 0 0 1 -0.088306 0.996093 0 547.819 -0.996093 -0.088306 0 0.000089 0 0 1 -0.000012 0 0 0 1 -0.046912 0.998899 0 547.819 -0.998899 -0.046912 0 -0.000045 0 0 1 -0.000012 0 0 0 1 0.007988 0.999968 0 547.819 -0.999968 0.007988 0 0.000042 0 0 1 -0.000012 0 0 0 1 0.072962 0.997335 0 547.819 -0.997335 0.072962 0 -0.000016 0 0 1 -0.000012 0 0 0 1 0.145974 0.989288 0 547.819 -0.989288 0.145974 0 -0.000007 0 0 1 -0.000012 0 0 0 1 0.222291 0.97498 0 547.819 -0.97498 0.222291 0 -0.000023 0 0 1 -0.000012 0 0 0 1 0.298351 0.954456 0 547.819 -0.954456 0.298351 0 -0.000008 0 0 1 -0.000012 0 0 0 1 0.371508 0.92843 0 547.819 -0.92843 0.371508 0 -0.000049 0 0 1 -0.000012 0 0 0 1 0.401342 0.915928 0 547.819 -0.915928 0.401342 0 0.000037 0 0 1 -0.000012 0 0 0 1 0.366769 0.930312 0 547.819 -0.930312 0.366769 0 0.000026 0 0 1 -0.000012 0 0 0 1 0.294841 0.955546 0 547.819 -0.955546 0.294841 0 -0.000001 0 0 1 -0.000012 0 0 0 1 0.204636 0.978838 0 547.819 -0.978838 0.204636 0 -0.000021 0 0 1 -0.000012 0 0 0 1 0.057518 0.998344 0 547.819 -0.998344 0.057518 0 -0.000004 0 0 1 -0.000012 0 0 0 1 -0.125456 0.992099 0 547.819 -0.992099 -0.125456 0 0.000001 0 0 1 -0.000012 0 0 0 1 -0.265994 0.963975 0 547.819 -0.963975 -0.265994 0 0.000011 0 0 1 -0.000012 0 0 0 1 -0.347694 0.937608 0 547.819 -0.937608 -0.347694 0 0.000045 0 0 1 -0.000012 0 0 0 1 -0.38714 0.922021 0 547.819 -0.922021 -0.38714 0 -0.000001 0 0 1 -0.000012 0 0 0 1 -0.383625 0.923488 0 547.819 -0.923488 -0.383625 0 0.000047 0 0 1 -0.000012 0 0 0 1 -0.345151 0.938547 0 547.819 -0.938547 -0.345151 0 -0.000107 0 0 1 -0.000012 0 0 0 1 -0.272131 0.96226 0 547.819 -0.96226 -0.272131 0 0.000021 0 0 1 -0.000012 0 0 0 1 -0.169694 0.985497 0 547.819 -0.985497 -0.169694 0 0.000045 0 0 1 -0.000012 0 0 0 1 -0.056478 0.998404 0 547.819 -0.998404 -0.056478 0 -0.000008 0 0 1 -0.000012 0 0 0 1 0.044008 0.999031 0 547.819 -0.999031 0.044008 0 -0.000056 0 0 1 -0.000012 0 0 0 1 0.078392 0.996923 0 547.819 -0.996923 0.078392 0 0.000024 0 0 1 -0.000012 0 0 0 1 0.052374 0.998627 0 547.819 -0.998627 0.052374 0 -0.000071 0 0 1 -0.000012 0 0 0 1 0.024928 0.99969 0 547.819 -0.99969 0.024928 0 -0.000044 0 0 1 -0.000012 0 0 0 1 -0.044561 0.999007 0 547.819 -0.999007 -0.044561 0 0.000032 0 0 1 -0.000012 0 0 0 1 -0.093553 0.995614 0 547.819 -0.995614 -0.093553 0 -0.000038 0 0 1 -0.000012 0 0 0 1 -0.116382 0.993205 0 547.819 -0.993205 -0.116382 0 0.000051 0 0 1 -0.000012 0 0 0 1 -0.112572 0.993644 0 547.819 -0.993644 -0.112572 0 0.000013 0 0 1 -0.000012 0 0 0 1 -0.088309 0.996093 0 547.819 -0.996093 -0.088309 0 0.000019 0 0 1 -0.000012 0 0 0 1 -0.046912 0.998899 0 547.819 -0.998899 -0.046912 0 0.000002 0 0 1 -0.000012 0 0 0 1 0.007988 0.999968 0 547.819 -0.999968 0.007988 0 0.000032 0 0 1 -0.000012 0 0 0 1 0.072962 0.997335 0 547.819 -0.997335 0.072962 0 -0.000036 0 0 1 -0.000012 0 0 0 1 0.145506 0.989357 0 547.819 -0.989357 0.145506 0 0.000009 0 0 1 -0.000012 0 0 0 1 0.222293 0.97498 0 547.819 -0.97498 0.222293 0 -0.000017 0 0 1 -0.000012 0 0 0 1 0.29835 0.954457 0 547.819 -0.954456 0.29835 0 0.000023 0 0 1 -0.000012 0 0 0 1 0.371509 0.928429 0 547.819 -0.928429 0.371509 0 -0.000025 0 0 1 -0.000012 0 0 0 1 0.401342 0.915928 0 547.819 -0.915928 0.401342 0 0.000005 0 0 1 -0.000012 0 0 0 1 0.366769 0.930312 0 547.819 -0.930312 0.366769 0 -0.000003 0 0 1 -0.000012 0 0 0 1 0.294841 0.955546 0 547.819 -0.955546 0.294841 0 -0.000019 0 0 1 -0.000012 0 0 0 1 0.204636 0.978838 0 547.819 -0.978838 0.204636 0 -0.000013 0 0 1 -0.000012 0 0 0 1 0.057517 0.998344 0 547.819 -0.998344 0.057517 0 0.000028 0 0 1 -0.000012 0 0 0 1 -0.125455 0.992099 0 547.819 -0.992099 -0.125455 0 0.000013 0 0 1 -0.000012 0 0 0 1 -0.265304 0.964165 0 547.819 -0.964165 -0.265304 0 -0.00003 0 0 1 -0.000012 0 0 0 1 -0.347694 0.937608 0 547.819 -0.937608 -0.347694 0 0.000004 0 0 1 -0.000012 0 0 0 1 -0.38714 0.922021 0 547.819 -0.922021 -0.38714 0 -0.000019 0 0 1 -0.000012 0 0 0 1 -0.383626 0.923488 0 547.819 -0.923488 -0.383626 0 0.000038 0 0 1 -0.000012 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.419188 -0.877486 -0.233021 532.748 0.873442 0.459808 -0.160238 0.000051 0.247751 -0.13636 0.959179 -0.000008 0 0 0 1 0.547481 -0.822753 -0.152782 532.748 0.801488 0.568043 -0.186933 -0.000015 0.240586 -0.02011 0.970419 -0.000008 0 0 0 1 0.679376 -0.730626 -0.068071 532.748 0.703991 0.675144 -0.220401 -0.000009 0.206989 0.101814 0.973031 -0.000008 0 0 0 1 0.77946 -0.626431 0.005114 532.748 0.606799 0.752953 -0.25467 0.000018 0.155682 0.201609 0.967015 -0.000008 0 0 0 1 0.824259 -0.563808 0.052128 532.748 0.554466 0.785076 -0.276087 0.000033 0.114735 0.25647 0.959718 -0.000008 0 0 0 1 0.785578 -0.616155 0.056741 532.748 0.606338 0.748277 -0.26914 0.000001 0.123374 0.245835 0.961428 -0.000008 0 0 0 1 0.682879 -0.730183 0.022563 532.748 0.71138 0.657634 -0.247903 -0.000053 0.166176 0.185339 0.968522 -0.000008 0 0 0 1 0.593786 -0.804265 -0.024002 532.748 0.78022 0.582813 -0.227126 -0.000017 0.196658 0.116137 0.97357 -0.000008 0 0 0 1 0.544955 -0.834824 -0.078052 532.748 0.81243 0.548759 -0.197031 -0.000013 0.207318 0.043961 0.977285 -0.000008 0 0 0 1 0.52572 -0.838807 -0.141498 532.748 0.826848 0.542965 -0.146665 0.000044 0.199852 -0.039892 0.979014 -0.000008 0 0 0 1 0.568442 -0.800576 -0.189611 532.748 0.804063 0.589401 -0.078034 0.000073 0.174229 -0.108101 0.978754 -0.000008 0 0 0 1 0.66921 -0.712129 -0.212203 532.748 0.728693 0.68484 -0.000218 -0.000032 0.145481 -0.154484 0.977226 -0.000008 0 0 0 1 0.786257 -0.579614 -0.21412 532.748 0.605488 0.791832 0.079917 -0.000032 0.123226 -0.192483 0.973533 -0.000008 0 0 0 1 0.883589 -0.423993 -0.198749 532.748 0.454944 0.877805 0.149943 -0.000025 0.110889 -0.222908 0.968512 -0.000008 0 0 0 1 0.943455 -0.2816 -0.174913 532.748 0.314366 0.927453 0.202496 -0.000007 0.105201 -0.246032 0.963536 -0.000008 0 0 0 1 0.970553 -0.186578 -0.152365 532.748 0.219337 0.945982 0.238764 0.000013 0.099585 -0.265153 0.95905 -0.000008 0 0 0 1 0.966455 -0.205678 -0.153819 532.748 0.240069 0.936267 0.256456 -0.00001 0.091268 -0.28478 0.954238 -0.000008 0 0 0 1 0.93285 -0.314297 -0.176093 532.748 0.351833 0.899908 0.257643 -0.000017 0.07749 -0.302298 0.950059 -0.000008 0 0 0 1 0.887858 -0.419362 -0.189324 532.748 0.456623 0.853682 0.250445 -0.000037 0.056595 -0.30881 0.949439 -0.000008 0 0 0 1 0.833052 -0.516128 -0.199089 532.748 0.550428 0.809292 0.205125 0.000006 0.05525 -0.280464 0.958273 -0.000008 0 0 0 1 0.767664 -0.607128 -0.205152 532.748 0.638173 0.753469 0.158177 -0.000032 0.058541 -0.252349 0.965864 -0.000008 0 0 0 1 0.694838 -0.687688 -0.210442 532.748 0.715902 0.689257 0.111399 0.000012 0.06844 -0.22806 0.971238 -0.000008 0 0 0 1 0.621229 -0.752648 -0.218165 532.748 0.779091 0.62313 0.068739 -0.000053 0.084208 -0.212674 0.973488 -0.000008 0 0 0 1 0.55205 -0.80295 -0.224747 532.748 0.827339 0.56101 0.027895 -0.000021 0.103686 -0.201342 0.974018 -0.000008 0 0 0 1 0.492238 -0.840442 -0.226627 532.748 0.861198 0.508085 -0.013685 0.000002 0.126648 -0.188434 0.973885 -0.000008 0 0 0 1 0.444819 -0.866464 -0.22666 532.748 0.882615 0.467061 -0.053326 0.000021 0.152069 -0.176332 0.972513 -0.000008 0 0 0 1 0.41195 -0.882518 -0.226845 532.748 0.89374 0.439843 -0.088135 0.000002 0.177557 -0.166433 0.969935 -0.000008 0 0 0 1 0.393161 -0.890729 -0.228092 532.748 0.897084 0.426004 -0.117307 0.000005 0.201657 -0.158497 0.966547 -0.000008 0 0 0 1 0.388614 -0.892171 -0.23024 532.748 0.894224 0.425428 -0.139189 -0.000027 0.222131 -0.151794 0.963129 -0.000008 0 0 0 1 0.397558 -0.887678 -0.232325 532.748 0.886238 0.437075 -0.153453 0.000012 0.23776 -0.144889 0.960457 -0.000008 0 0 0 1 0.419237 -0.877513 -0.232833 532.748 0.873371 0.459847 -0.16051 0.000033 0.247917 -0.136057 0.959179 -0.000008 0 0 0 1 0.504219 -0.842217 -0.190876 532.748 0.826065 0.534824 -0.177709 0.000033 0.251755 -0.068072 0.965394 -0.000008 0 0 0 1 0.646628 -0.756637 -0.096809 532.748 0.728106 0.650065 -0.217432 0.000048 0.22745 0.07011 0.971263 -0.000008 0 0 0 1 0.772351 -0.635189 0.002914 532.748 0.613308 0.744534 -0.26367 -0.000016 0.16531 0.205434 0.964608 -0.000008 0 0 0 1 0.827934 -0.557359 0.06226 532.748 0.549539 0.784097 -0.288443 0.000029 0.111948 0.273027 0.955471 -0.000008 0 0 0 1 0.7871 -0.613623 0.062771 532.748 0.604656 0.74745 -0.275155 0.000038 0.121924 0.254529 0.959348 -0.000008 0 0 0 1 0.683118 -0.729906 0.024205 532.748 0.711197 0.657344 -0.249194 -0.000051 0.165977 0.187444 0.968151 -0.000008 0 0 0 1 0.593786 -0.804265 -0.024006 532.748 0.780221 0.582812 -0.227122 -0.000034 0.196657 0.116131 0.97357 -0.000008 0 0 0 1 0.545021 -0.834811 -0.077736 532.748 0.812387 0.548748 -0.19724 -0.000044 0.207316 0.044348 0.977268 -0.000008 0 0 0 1 0.525742 -0.838741 -0.141805 532.748 0.826859 0.543037 -0.146342 0.000003 0.199748 -0.040314 0.979018 -0.000008 0 0 0 1 0.56839 -0.800545 -0.189896 532.748 0.804096 0.589379 -0.077853 0.000008 0.174245 -0.108443 0.978713 -0.000008 0 0 0 1 0.669172 -0.712089 -0.212459 532.748 0.728718 0.684813 -0.000047 -0.000091 0.145528 -0.154792 0.97717 -0.000008 0 0 0 1 0.786911 -0.578673 -0.214265 532.748 0.604646 0.792412 0.08053 -0.000024 0.123186 -0.192924 0.97345 -0.000008 0 0 0 1 0.883574 -0.423969 -0.198862 532.748 0.454958 0.877783 0.150035 -0.000024 0.110949 -0.223041 0.968475 -0.000008 0 0 0 1 0.94345 -0.281588 -0.174957 532.748 0.314369 0.927443 0.202537 -0.000091 0.105231 -0.246085 0.963519 -0.000008 0 0 0 1 0.970554 -0.186577 -0.152365 532.748 0.219336 0.945983 0.238765 0.000001 0.099585 -0.265153 0.95905 -0.000008 0 0 0 1 0.966456 -0.205681 -0.153807 532.748 0.240068 0.936271 0.256443 0.000036 0.09126 -0.284764 0.954244 -0.000008 0 0 0 1 0.93285 -0.314299 -0.176087 532.748 0.351832 0.89991 0.257637 0.000029 0.077487 -0.30229 0.950061 -0.000008 0 0 0 1 0.887858 -0.419362 -0.189325 532.748 0.456624 0.853681 0.250445 -0.000029 0.056596 -0.30881 0.949439 -0.000008 0 0 0 1 0.833052 -0.516127 -0.199088 532.748 0.550428 0.809292 0.205124 0.000019 0.05525 -0.280463 0.958274 -0.000008 0 0 0 1 0.767664 -0.60713 -0.205148 532.748 0.638173 0.753469 0.158173 0.000069 0.058541 -0.252343 0.965865 -0.000008 0 0 0 1 0.695299 -0.687236 -0.210395 532.748 0.715463 0.689669 0.111669 0.000027 0.06836 -0.228172 0.971218 -0.000008 0 0 0 1 0.621229 -0.752651 -0.218152 532.748 0.779091 0.623132 0.068726 0.00002 0.08421 -0.212655 0.973492 -0.000008 0 0 0 1 0.552052 -0.802954 -0.224728 532.748 0.827337 0.561014 0.027877 -0.000000 0.10369 -0.201316 0.974023 -0.000008 0 0 0 1 0.491904 -0.840642 -0.226609 532.748 0.861365 0.507794 -0.013961 -0.000017 0.126807 -0.188325 0.973886 -0.000008 0 0 0 1 0.444825 -0.866468 -0.226634 532.748 0.882611 0.467067 -0.05335 -0.000015 0.15208 -0.176298 0.972518 -0.000008 0 0 0 1 0.411955 -0.882523 -0.22682 532.748 0.893735 0.439848 -0.088162 -0.000013 0.177571 -0.166398 0.969938 -0.000008 0 0 0 1 0.393166 -0.890734 -0.228068 532.748 0.897078 0.426009 -0.117334 0.000037 0.201672 -0.158464 0.966549 -0.000008 0 0 0 1 0.388618 -0.892174 -0.230222 532.748 0.894219 0.425432 -0.139212 0.00001 0.222145 -0.151769 0.96313 -0.000008 0 0 0 1 0.397561 -0.887679 -0.232315 532.748 0.886234 0.437078 -0.153467 0.000003 0.237769 -0.144873 0.960457 -0.000008 0 0 0 1 0.419238 -0.877513 -0.232833 532.748 0.873371 0.459848 -0.160511 0.000003 0.247918 -0.136057 0.959179 -0.000008 0 0 0 1 0.503488 -0.842554 -0.191321 532.748 0.826518 0.534203 -0.177466 0.000036 0.251729 -0.068777 0.965351 -0.000008 0 0 0 1 0.646604 -0.756645 -0.09691 532.748 0.728141 0.650076 -0.217285 0.000002 0.227408 0.069933 0.971285 -0.000008 0 0 0 1 0.772866 -0.634561 0.003219 532.748 0.612759 0.744973 -0.263704 -0.000007 0.164938 0.205781 0.964598 -0.000008 0 0 0 1 0.827909 -0.55742 0.06205 532.748 0.549569 0.784169 -0.288189 0.000042 0.111984 0.272696 0.955561 -0.000008 0 0 0 1 0.787077 -0.613671 0.062592 532.748 0.60468 0.747498 -0.27497 -0.000005 0.121954 0.25427 0.959413 -0.000008 0 0 0 1 0.683103 -0.729923 0.024122 532.748 0.71121 0.657357 -0.249122 -0.000031 0.165983 0.187332 0.968172 -0.000008 0 0 0 1 0.593785 -0.804265 -0.024005 532.748 0.780221 0.582812 -0.227122 -0.000038 0.196657 0.116132 0.97357 -0.000008 0 0 0 1 0.545026 -0.83481 -0.077715 532.748 0.812384 0.548748 -0.197253 -0.000018 0.207316 0.044373 0.977267 -0.000008 0 0 0 1 0.525744 -0.838741 -0.141795 532.748 0.826858 0.543037 -0.146348 -0.000028 0.199747 -0.040302 0.979019 -0.000008 0 0 0 1 0.56839 -0.800545 -0.189896 532.748 0.804097 0.589379 -0.077853 0.000072 0.174245 -0.108444 0.978713 -0.000008 0 0 0 1 0.669172 -0.712089 -0.21246 532.748 0.728719 0.684813 -0.000047 -0.000025 0.145528 -0.154792 0.97717 -0.000008 0 0 0 1 0.786233 -0.579576 -0.214312 532.748 0.605506 0.791804 0.080058 -0.00003 0.123294 -0.192711 0.973479 -0.000008 0 0 0 1 0.883576 -0.423966 -0.198862 532.748 0.454955 0.877784 0.150036 0.000006 0.110949 -0.223041 0.968474 -0.000008 0 0 0 1 0.94345 -0.281588 -0.174957 532.748 0.31437 0.927443 0.202537 -0.000055 0.105231 -0.246085 0.963519 -0.000008 0 0 0 1 0.970553 -0.186577 -0.152365 532.748 0.219337 0.945982 0.238764 0.000039 0.099587 -0.265153 0.95905 -0.000008 0 0 0 1 0.966545 -0.20531 -0.153745 532.748 0.239685 0.936388 0.256375 -0.000002 0.091329 -0.284648 0.954272 -0.000008 0 0 0 1 0.93285 -0.314299 -0.176087 532.748 0.351833 0.899909 0.257637 0.000043 0.077486 -0.30229 0.950061 -0.000008 0 0 0 1 0.887541 -0.419965 -0.18948 532.748 0.457244 0.853386 0.250321 0.000027 0.056573 -0.308808 0.949441 -0.000008 0 0 0 1 0.833053 -0.516133 -0.199068 532.748 0.550426 0.809298 0.205106 -0.000005 0.055242 -0.280436 0.958282 -0.000008 0 0 0 1 0.767667 -0.607141 -0.205104 532.748 0.638171 0.75348 0.158135 -0.000017 0.058531 -0.252287 0.965881 -0.000008 0 0 0 1 0.695303 -0.687253 -0.210328 532.748 0.715459 0.689682 0.111611 0.000001 0.068354 -0.228084 0.971239 -0.000008 0 0 0 1 0.621685 -0.752313 -0.218018 532.748 0.778738 0.623553 0.068908 0.000002 0.084104 -0.212618 0.973509 -0.000008 0 0 0 1 0.552064 -0.802978 -0.224614 532.748 0.827327 0.561034 0.027777 0.000009 0.103712 -0.201164 0.974052 -0.000008 0 0 0 1 0.491921 -0.840668 -0.226474 532.748 0.861349 0.507818 -0.014087 -0.000041 0.12685 -0.188143 0.973916 -0.000008 0 0 0 1 0.444848 -0.866496 -0.226482 532.748 0.882588 0.467093 -0.053501 0.000004 0.152147 -0.17609 0.972545 -0.000008 0 0 0 1 0.411985 -0.882551 -0.226653 532.748 0.893703 0.439878 -0.088337 0.000003 0.177662 -0.166167 0.969961 -0.000008 0 0 0 1 0.393265 -0.890737 -0.227881 532.748 0.89704 0.426077 -0.117377 -0.000008 0.201647 -0.158258 0.966588 -0.000008 0 0 0 1 0.38866 -0.892203 -0.230038 532.748 0.894167 0.425467 -0.139437 0.00001 0.22228 -0.151498 0.963141 -0.000008 0 0 0 1 0.397607 -0.887708 -0.232128 532.748 0.886172 0.437115 -0.153717 0.000008 0.237922 -0.144587 0.960462 -0.000008 0 0 0 1 0.419286 -0.87754 -0.232645 532.748 0.873301 0.459886 -0.160784 -0.000004 0.248084 -0.135755 0.959179 -0.000008 0 0 0 1 0.503538 -0.842568 -0.191125 532.748 0.826442 0.534223 -0.17776 0.000016 0.251878 -0.068444 0.965335 -0.000008 0 0 0 1 0.646652 -0.75663 -0.0967 532.748 0.72807 0.650053 -0.217588 -0.000002 0.227495 0.070299 0.971239 -0.000008 0 0 0 1 0.772903 -0.634516 0.003438 532.748 0.61271 0.744911 -0.263994 -0.000011 0.164948 0.206149 0.964518 -0.000008 0 0 0 1 0.827933 -0.557361 0.062261 532.748 0.549541 0.784095 -0.288442 0.000059 0.111947 0.273027 0.955471 -0.000008 0 0 0 1 0.787096 -0.613631 0.062748 532.748 0.60466 0.747455 -0.275132 0.00001 0.121927 0.254497 0.959357 -0.000008 0 0 0 1 0.683113 -0.729912 0.024179 532.748 0.711202 0.657348 -0.249171 -0.000003 0.165978 0.187409 0.968157 -0.000008 0 0 0 1 0.594224 -0.803951 -0.023685 532.748 0.779919 0.583158 -0.227273 -0.000034 0.196529 0.116578 0.973543 -0.000008 0 0 0 1 0.545043 -0.834806 -0.077636 532.748 0.812372 0.548745 -0.197306 0.000006 0.207315 0.04447 0.977263 -0.000008 0 0 0 1 0.52579 -0.838751 -0.141567 532.748 0.826829 0.543042 -0.146493 -0.000055 0.199748 -0.040027 0.97903 -0.000008 0 0 0 1 0.56844 -0.800577 -0.189611 532.748 0.804065 0.589398 -0.078035 0.00004 0.174229 -0.108101 0.978754 -0.000008 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0 -1 0 214.572 1 0 0 189.363 0 0 1 0.00003 0 0 0 1 -0.136487 -0.986701 -0.088268 214.572 0.98954 -0.139994 0.034813 189.363 -0.046706 -0.082594 0.995488 0.00003 0 0 0 1 -0.244943 -0.959927 -0.136175 214.572 0.968561 -0.248572 0.010048 189.363 -0.043495 -0.129433 0.990634 0.00003 0 0 0 1 -0.335393 -0.929315 -0.154546 214.572 0.941553 -0.336144 -0.02204 189.363 -0.031467 -0.152905 0.98774 0.00003 0 0 0 1 -0.404434 -0.896978 -0.178507 214.572 0.913126 -0.406986 -0.023764 189.363 -0.051333 -0.17261 0.983652 0.00003 0 0 0 1 -0.149149 -0.965994 -0.211212 214.572 0.988797 -0.146995 -0.025954 189.363 -0.005974 -0.212717 0.977096 0.00003 0 0 0 1 0.446304 -0.867357 -0.220237 214.572 0.887499 0.460555 -0.015307 189.363 0.114708 -0.188629 0.975326 0.00003 0 0 0 1 0.736262 -0.653693 -0.174935 214.572 0.661784 0.749533 -0.015535 189.363 0.141275 -0.104332 0.984458 0.00003 0 0 0 1 0.754105 -0.644192 -0.127836 214.572 0.647263 0.761964 -0.021485 189.363 0.111248 -0.06654 0.991562 0.00003 0 0 0 1 0.722077 -0.685415 -0.09387 214.572 0.688263 0.725456 -0.002765 189.363 0.069994 -0.062611 0.995581 0.00003 0 0 0 1 0.714375 -0.696687 -0.06554 214.572 0.697926 0.716151 -0.005375 189.363 0.050681 -0.041902 0.997835 0.00003 0 0 0 1 0.680033 -0.731491 -0.049763 214.572 0.731652 0.681431 -0.01835 189.363 0.047333 -0.023928 0.998592 0.00003 0 0 0 1 0.539681 -0.84043 -0.049203 214.572 0.840813 0.54101 -0.01849 189.363 0.042159 -0.031392 0.998618 0.00003 0 0 0 1 0.334377 -0.940659 -0.057906 214.572 0.941933 0.33558 -0.012196 189.363 0.030905 -0.050465 0.998247 0.00003 0 0 0 1 0.158538 -0.985082 -0.066921 214.572 0.987207 0.159314 -0.006382 189.363 0.016948 -0.065053 0.997738 0.00003 0 0 0 1 0.099612 -0.992857 -0.06567 214.572 0.994956 0.100175 -0.005318 189.363 0.011858 -0.064809 0.997827 0.00003 0 0 0 1 0.072647 -0.996144 -0.049168 214.572 0.997323 0.072965 -0.004708 189.363 0.008277 -0.048695 0.998779 0.00003 0 0 0 1 0.003873 -0.999687 -0.024729 214.572 0.999991 0.003914 -0.001599 189.363 0.001696 -0.024723 0.999693 0.00003 0 0 0 1 0 -1 0 214.572 1 0 0 189.363 0 0 1 0.00003 0 0 0 1 0.002915 -0.999994 0.0019 214.572 0.999995 0.002912 -0.001476 189.363 0.001471 0.001905 0.999997 0.00003 0 0 0 1 0.010495 -0.999922 0.006814 214.572 0.999931 0.010459 -0.005335 189.363 0.005263 0.00687 0.999963 0.00003 0 0 0 1 0.02136 -0.999677 0.013786 214.572 0.999715 0.02121 -0.010914 189.363 0.010618 0.014015 0.999845 0.00003 0 0 0 1 0.033779 -0.999194 0.021652 214.572 0.999291 0.033406 -0.01736 189.363 0.016623 0.022223 0.999615 0.00003 0 0 0 1 0.046158 -0.998502 0.029385 214.572 0.998681 0.045464 -0.023857 189.363 0.022485 0.030448 0.999283 0.00003 0 0 0 1 0.057054 -0.997718 0.036105 214.572 0.997991 0.055998 -0.029635 189.363 0.027546 0.037723 0.998908 0.00003 0 0 0 1 0.064811 -0.997061 0.040839 214.572 0.997413 0.06345 -0.033782 189.363 0.031092 0.042923 0.998595 0.00003 0 0 0 1 0.067711 -0.996795 0.042598 214.572 0.997179 0.066227 -0.035341 189.363 0.032406 0.044871 0.998467 0.00003 0 0 0 1 0.064198 -0.997116 0.040466 214.572 0.997461 0.062863 -0.033453 189.363 0.030813 0.042511 0.998621 0.00003 0 0 0 1 0.052698 -0.998051 0.033427 214.572 0.998284 0.051794 -0.027318 189.363 0.025533 0.03481 0.999068 0.00003 0 0 0 1 0.031849 -0.999284 0.020438 214.572 0.999369 0.031518 -0.016354 189.363 0.015698 0.020946 0.999657 0.00003 0 0 0 1 0 -1 0 214.572 1 0 0 189.363 0 0 1 0.00003 0 0 0 1 -0.074224 -0.996209 -0.04537 214.572 0.997188 -0.074615 0.006997 189.363 -0.010356 -0.044724 0.998946 0.00003 0 0 0 1 -0.190662 -0.976592 -0.099579 214.572 0.981627 -0.190451 -0.011709 189.363 -0.00753 -0.099982 0.994961 0.00003 0 0 0 1 -0.315658 -0.938275 -0.14142 214.572 0.948724 -0.314726 -0.029511 189.363 -0.016819 -0.143484 0.98951 0.00003 0 0 0 1 -0.404434 -0.896972 -0.178534 214.572 0.913126 -0.406985 -0.023776 189.363 -0.051333 -0.172639 0.983647 0.00003 0 0 0 1 -0.149149 -0.965994 -0.211212 214.572 0.988797 -0.146995 -0.025954 189.363 -0.005975 -0.212717 0.977096 0.00003 0 0 0 1 0.446304 -0.867357 -0.220237 214.572 0.887499 0.460555 -0.015307 189.363 0.114708 -0.188629 0.975326 0.00003 0 0 0 1 0.736262 -0.653693 -0.174935 214.572 0.661784 0.749533 -0.015535 189.363 0.141275 -0.104332 0.984458 0.00003 0 0 0 1 0.754105 -0.644192 -0.127836 214.572 0.647263 0.761964 -0.021487 189.363 0.111248 -0.06654 0.991562 0.00003 0 0 0 1 0.72195 -0.685575 -0.093679 214.572 0.688416 0.725311 -0.002711 189.363 0.069805 -0.062533 0.995599 0.00003 0 0 0 1 0.714376 -0.696686 -0.06554 214.572 0.697925 0.716151 -0.005374 189.363 0.050681 -0.041903 0.997835 0.00003 0 0 0 1 0.680032 -0.731491 -0.049762 214.572 0.731652 0.681431 -0.01835 189.363 0.047333 -0.02393 0.998592 0.00003 0 0 0 1 0.538608 -0.841117 -0.049221 214.572 0.841503 0.539937 -0.018464 189.363 0.042106 -0.031475 0.998618 0.00003 0 0 0 1 0.33438 -0.940657 -0.057905 214.572 0.941932 0.335584 -0.012195 189.363 0.030904 -0.050465 0.998247 0.00003 0 0 0 1 0.158538 -0.985082 -0.066921 214.572 0.987207 0.159313 -0.006382 189.363 0.016948 -0.065053 0.997738 0.00003 0 0 0 1 0.099612 -0.992857 -0.06567 214.572 0.994956 0.100175 -0.005318 189.363 0.011858 -0.064809 0.997827 0.00003 0 0 0 1 0.072647 -0.996145 -0.049168 214.572 0.997323 0.072965 -0.004708 189.363 0.008277 -0.048695 0.998779 0.00003 0 0 0 1 0.003873 -0.999687 -0.024729 214.572 0.999991 0.003914 -0.001599 189.363 0.001696 -0.024723 0.999693 0.00003 0 0 0 1 0 -1 0 214.572 1 0 0 189.363 0 0 1 0.00003 0 0 0 1 0.002914 -0.999994 0.0019 214.572 0.999995 0.002912 -0.001476 189.363 0.001471 0.001905 0.999997 0.00003 0 0 0 1 0.010495 -0.999922 0.006813 214.572 0.999931 0.010459 -0.005335 189.363 0.005263 0.00687 0.999963 0.00003 0 0 0 1 0.021288 -0.999679 0.01374 214.572 0.999717 0.021139 -0.010877 189.363 0.010583 0.013966 0.999846 0.00003 0 0 0 1 0.033779 -0.999194 0.021652 214.572 0.999291 0.033407 -0.01736 189.363 0.016623 0.022223 0.999615 0.00003 0 0 0 1 0.046158 -0.998502 0.029385 214.572 0.998681 0.045464 -0.023857 189.363 0.022485 0.030448 0.999283 0.00003 0 0 0 1 0.057112 -0.997713 0.03614 214.572 0.997987 0.056054 -0.029667 189.363 0.027573 0.037762 0.998906 0.00003 0 0 0 1 0.064811 -0.997061 0.040839 214.572 0.997413 0.06345 -0.033782 189.363 0.031093 0.042922 0.998594 0.00003 0 0 0 1 0.067711 -0.996795 0.042598 214.572 0.997179 0.066227 -0.03534 189.363 0.032406 0.044871 0.998467 0.00003 0 0 0 1 0.064198 -0.997116 0.040466 214.572 0.997461 0.062863 -0.033453 189.363 0.030813 0.042511 0.998621 0.00003 0 0 0 1 0.052698 -0.99805 0.033427 214.572 0.998284 0.051794 -0.027318 189.363 0.025533 0.03481 0.999068 0.00003 0 0 0 1 0.031849 -0.999284 0.020438 214.572 0.999369 0.031518 -0.016354 189.363 0.015698 0.020946 0.999657 0.00003 0 0 0 1 0 -1 0 214.572 1 0 0 189.363 0 0 1 0.00003 0 0 0 1 -0.073625 -0.996268 -0.045054 214.572 0.997232 -0.074015 0.007048 189.363 -0.010356 -0.044411 0.99896 0.00003 0 0 0 1 -0.190662 -0.976592 -0.099579 214.572 0.981627 -0.190451 -0.011709 189.363 -0.00753 -0.099982 0.994961 0.00003 0 0 0 1 -0.31633 -0.938013 -0.141658 214.572 0.948498 -0.315402 -0.029552 189.363 -0.016958 -0.143711 0.989475 0.00003 0 0 0 1 -0.404434 -0.896972 -0.178533 214.572 0.913126 -0.406985 -0.023776 189.363 -0.051333 -0.172639 0.983647 0.00003 0 0 0 1 -0.149149 -0.965994 -0.211212 214.572 0.988797 -0.146995 -0.025954 189.363 -0.005974 -0.212717 0.977096 0.00003 0 0 0 1 0.446304 -0.867357 -0.220237 214.572 0.887499 0.460555 -0.015307 189.363 0.114708 -0.188629 0.975326 0.00003 0 0 0 1 0.736262 -0.653693 -0.174935 214.572 0.661784 0.749533 -0.015535 189.363 0.141275 -0.104332 0.984458 0.00003 0 0 0 1 0.754105 -0.644192 -0.127836 214.572 0.647263 0.761964 -0.021485 189.363 0.111248 -0.06654 0.991562 0.00003 0 0 0 1 0.721949 -0.685575 -0.093679 214.572 0.688416 0.725311 -0.002711 189.363 0.069805 -0.062533 0.995599 0.00003 0 0 0 1 0.714376 -0.696686 -0.06554 214.572 0.697925 0.716151 -0.005374 189.363 0.050681 -0.041903 0.997835 0.00003 0 0 0 1 0.680033 -0.731491 -0.049762 214.572 0.731652 0.681431 -0.01835 189.363 0.047333 -0.023929 0.998592 0.00003 0 0 0 1 0.539681 -0.84043 -0.049203 214.572 0.840813 0.541009 -0.01849 189.363 0.042158 -0.031392 0.998618 0.00003 0 0 0 1 0.334377 -0.940659 -0.057906 214.572 0.941933 0.33558 -0.012195 189.363 0.030904 -0.050465 0.998247 0.00003 0 0 0 1 0.158538 -0.985082 -0.066921 214.572 0.987207 0.159314 -0.006382 189.363 0.016948 -0.065053 0.997738 0.00003 0 0 0 1 0.099612 -0.992857 -0.06567 214.572 0.994956 0.100175 -0.005318 189.364 0.011858 -0.064809 0.997827 0.00003 0 0 0 1 0.07295 -0.996117 -0.049297 214.572 0.997301 0.07327 -0.004715 189.363 0.008309 -0.04882 0.998773 0.00003 0 0 0 1 0.003873 -0.999687 -0.024729 214.572 0.999991 0.003914 -0.001599 189.363 0.001695 -0.024723 0.999693 0.00003 0 0 0 1 0 -1 0.000031 214.572 1 0 0 189.364 0 0.000031 1 0.00003 0 0 0 1 0.002915 -0.999994 0.0019 214.572 0.999995 0.002912 -0.001476 189.364 0.001471 0.001905 0.999997 0.00003 0 0 0 1 0.010495 -0.999922 0.006814 214.572 0.999931 0.010459 -0.005335 189.363 0.005263 0.00687 0.999963 0.00003 0 0 0 1 0.021287 -0.999679 0.01374 214.572 0.999717 0.021139 -0.010877 189.363 0.010583 0.013966 0.999846 0.00003 0 0 0 1 0.033702 -0.999198 0.021604 214.572 0.999294 0.033331 -0.017319 189.363 0.016586 0.022172 0.999617 0.00003 0 0 0 1 0.046158 -0.998502 0.029385 214.572 0.998681 0.045464 -0.023857 189.363 0.022486 0.030448 0.999283 0.00003 0 0 0 1 0.057112 -0.997713 0.03614 214.572 0.997987 0.056054 -0.029667 189.363 0.027572 0.037762 0.998906 0.00003 0 0 0 1 0.064811 -0.997061 0.040839 214.572 0.997413 0.06345 -0.033782 189.363 0.031092 0.042923 0.998595 0.00003 0 0 0 1 0.067711 -0.996795 0.042598 214.572 0.997178 0.066227 -0.035341 189.363 0.032406 0.044871 0.998467 0.00003 0 0 0 1 0.064245 -0.997112 0.040495 214.572 0.997458 0.062908 -0.033479 189.363 0.030835 0.042543 0.998619 0.00003 0 0 0 1 0.052696 -0.99805 0.033427 214.572 0.998283 0.051794 -0.027318 189.363 0.025533 0.03481 0.999068 0.00003 0 0 0 1 0.031849 -0.999284 0.020438 214.572 0.999369 0.031517 -0.016354 189.363 0.015698 0.020946 0.999657 0.00003 0 0 0 1 0 -1 0 214.572 1 0 0 189.363 0 0 1 0.00003 0 0 0 1 -0.073624 -0.996268 -0.045054 214.572 0.997232 -0.074014 0.007047 189.363 -0.010356 -0.04441 0.99896 0.00003 0 0 0 1 -0.190662 -0.976592 -0.099579 214.572 0.981627 -0.190451 -0.011709 189.363 -0.007529 -0.099982 0.994961 0.00003 0 0 0 1 -0.316329 -0.938013 -0.141658 214.572 0.948498 -0.315403 -0.029552 189.363 -0.016958 -0.143711 0.989475 0.00003 0 0 0 1 -0.404434 -0.896972 -0.178533 214.572 0.913126 -0.406985 -0.023776 189.363 -0.051333 -0.172639 0.983647 0.00003 0 0 0 1 -0.149149 -0.965994 -0.211212 214.572 0.988797 -0.146995 -0.025955 189.363 -0.005974 -0.212717 0.977096 0.00003 0 0 0 1 0.446304 -0.867357 -0.220237 214.572 0.887499 0.460555 -0.015307 189.363 0.114708 -0.188629 0.975326 0.00003 0 0 0 1 0.736007 -0.653914 -0.175184 214.572 0.662068 0.749287 -0.015314 189.363 0.141277 -0.104713 0.984417 0.00003 0 0 0 1 0.754105 -0.644192 -0.127836 214.572 0.647263 0.761964 -0.021485 189.363 0.111248 -0.06654 0.991562 0.00003 0 0 0 1 0.72195 -0.685576 -0.093679 214.572 0.688416 0.725311 -0.002711 189.363 0.069805 -0.062533 0.995599 0.00003 0 0 0 1 0.714376 -0.696686 -0.06554 214.572 0.697925 0.716151 -0.005374 189.363 0.050681 -0.041903 0.997835 0.00003 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - -0.961176 -0.270648 -0.053767 -217.547 0.265068 -0.959767 0.09266 76.1463 -0.076681 0.074811 0.994245 -46.1944 0 0 0 1 -0.966892 -0.248029 -0.060005 -220.493 0.242782 -0.966521 0.083025 72.3032 -0.078589 0.065709 0.994739 -37.5713 0 0 0 1 -0.972442 -0.222865 -0.068461 -223.277 0.217936 -0.973255 0.07266 67.6319 -0.082824 0.055738 0.995004 -28.7549 0 0 0 1 -0.977336 -0.196999 -0.077493 -225.714 0.192576 -0.979385 0.060981 62.5368 -0.087909 0.044674 0.995126 -19.8152 0 0 0 1 -0.981264 -0.172767 -0.085283 -227.632 0.16915 -0.984421 0.048011 57.5336 -0.09225 0.032686 0.995199 -10.9824 0 0 0 1 -0.984139 -0.152913 -0.089931 -228.913 0.150369 -0.988029 0.03446 53.257 -0.094124 0.020391 0.995352 -2.63677 0 0 0 1 -0.986165 -0.139322 -0.089824 -229.558 0.137998 -0.990214 0.020819 50.1855 -0.091847 0.008135 0.99574 5.17882 0 0 0 1 -0.987431 -0.134369 -0.083214 -229.562 0.134179 -0.990925 0.007893 48.9204 -0.083519 -0.00337 0.9965 12.2666 0 0 0 1 -0.987727 -0.140188 -0.068866 -228.861 0.140852 -0.990019 -0.004863 49.9732 -0.067497 -0.014505 0.997614 19.1733 0 0 0 1 -0.986693 -0.155403 -0.047812 -227.447 0.156433 -0.987514 -0.018579 52.9903 -0.044329 -0.025812 0.998684 26.5357 0 0 0 1 -0.983949 -0.177049 -0.022324 -225.422 0.17772 -0.983533 -0.032845 57.2903 -0.016141 -0.036285 0.999211 33.9081 0 0 0 1 -0.979476 -0.201505 0.004804 -223.015 0.201065 -0.978453 -0.046932 62.1103 0.014158 -0.045003 0.998887 40.6998 0 0 0 1 -0.973607 -0.225997 0.031865 -220.471 0.223822 -0.972755 -0.060429 66.9036 0.044654 -0.051702 0.997664 46.5787 0 0 0 1 -0.967268 -0.247328 0.05676 -218.167 0.243092 -0.967303 -0.07233 71.0769 0.072794 -0.056164 0.995764 51.0577 0 0 0 1 -0.961961 -0.262067 0.077147 -216.578 0.255919 -0.963286 -0.081156 74.0089 0.095583 -0.058326 0.993711 53.6097 0 0 0 1 -0.959184 -0.267526 0.09163 -216.107 0.260077 -0.961788 -0.085577 75.2127 0.111023 -0.058252 0.992109 53.8413 0 0 0 1 -0.960314 -0.259786 0.101527 -217.308 0.251947 -0.964103 -0.08384 73.992 0.119664 -0.054934 0.991293 50.5952 0 0 0 1 -0.964519 -0.240518 0.108874 -219.874 0.233184 -0.969466 -0.075899 70.605 0.123804 -0.047818 0.991154 43.8835 0 0 0 1 -0.970214 -0.214224 0.113108 -223 0.208232 -0.97608 -0.062501 65.7235 0.123791 -0.037087 0.991615 34.6939 0 0 0 1 -0.976058 -0.185636 0.113362 -225.952 0.181611 -0.982343 -0.044949 60.1135 0.119705 -0.023285 0.992537 24.0967 0 0 0 1 -0.981075 -0.160063 0.108952 -228.173 0.158196 -0.987075 -0.025629 54.7939 0.111646 -0.007907 0.993717 13.4094 0 0 0 1 -0.984942 -0.141563 0.099236 -229.479 0.141608 -0.989901 -0.006626 50.6943 0.099172 0.007525 0.995042 3.48016 0 0 0 1 -0.987285 -0.134928 0.084043 -229.818 0.136156 -0.990646 0.009035 49.0492 0.082038 0.020362 0.996421 -4.43756 0 0 0 1 -0.988235 -0.141201 0.058767 -229.328 0.142768 -0.989481 0.023359 50.2218 0.054851 0.031474 0.997998 -11.3543 0 0 0 1 -0.987374 -0.156893 0.021859 -228.133 0.157666 -0.98669 0.039804 53.3707 0.015323 0.042748 0.998968 -18.7382 0 0 0 1 -0.983608 -0.179006 -0.021705 -226.323 0.177509 -0.98241 0.057975 57.808 -0.031702 0.053171 0.998082 -26.1404 0 0 0 1 -0.976767 -0.203881 -0.066026 -224.109 0.198751 -0.977041 0.076733 62.7602 -0.080155 0.061829 0.994863 -32.9667 0 0 0 1 -0.967528 -0.228869 -0.10728 -221.711 0.219157 -0.971044 0.095095 67.7023 -0.125938 0.068496 0.989671 -38.9137 0 0 0 1 -0.957969 -0.250314 -0.140134 -219.54 0.236082 -0.965419 0.110597 71.9429 -0.162972 0.072866 0.983936 -43.3905 0 0 0 1 -0.950724 -0.265194 -0.160613 -218.015 0.247742 -0.961275 0.120727 74.9333 -0.186409 0.074988 0.979606 -45.9612 0 0 0 1 -0.948436 -0.270658 -0.164964 -217.547 0.252513 -0.959757 0.122895 76.1463 -0.191588 0.074903 0.978613 -46.1944 0 0 0 1 -0.953853 -0.262719 -0.145409 -218.657 0.247817 -0.962211 0.112854 74.8622 -0.169563 0.071611 0.982914 -42.9245 0 0 0 1 -0.964536 -0.243044 -0.102954 -221.038 0.234073 -0.967865 0.091908 71.3436 -0.121983 0.06455 0.990431 -36.1687 0 0 0 1 -0.975327 -0.216184 -0.044737 -223.905 0.2131 -0.974865 0.065011 66.2856 -0.057667 0.053875 0.996881 -26.9298 0 0 0 1 -0.982148 -0.186932 0.021004 -226.552 0.187607 -0.981554 0.036825 60.4795 0.013733 0.040108 0.999101 -16.2913 0 0 0 1 -0.983442 -0.160677 0.083812 -228.457 0.162175 -0.986697 0.011332 54.9697 0.080878 0.024737 0.996417 -5.57961 0 0 0 1 -0.980634 -0.141615 0.135283 -229.46 0.141574 -0.989877 -0.009972 50.718 0.135326 0.009374 0.990757 4.30098 0 0 0 1 -0.976986 -0.134396 0.16564 -229.563 0.131902 -0.990921 -0.026022 48.9204 0.167633 -0.003574 0.985843 12.2693 0 0 0 1 -0.974293 -0.140199 0.176343 -228.861 0.135298 -0.990014 -0.039578 49.973 0.18013 -0.014702 0.983533 19.1733 0 0 0 1 -0.971851 -0.155532 0.176962 -227.436 0.148236 -0.987487 -0.053807 53.0133 0.183116 -0.026061 0.982745 26.5817 0 0 0 1 -0.969555 -0.177061 0.169153 -225.422 0.167943 -0.983525 -0.066884 57.2902 0.178209 -0.036439 0.983318 33.9079 0 0 0 1 -0.967146 -0.201516 0.154985 -223.015 0.191476 -0.978445 -0.077341 62.1102 0.16723 -0.045124 0.984885 40.6998 0 0 0 1 -0.964531 -0.226148 0.13615 -220.456 0.216175 -0.972714 -0.084241 66.9316 0.151485 -0.051821 0.9871 46.6111 0 0 0 1 -0.962084 -0.247332 0.11498 -218.167 0.238286 -0.967299 -0.086905 71.077 0.132715 -0.056212 0.989559 51.0576 0 0 0 1 -0.960513 -0.262068 0.093458 -216.578 0.254505 -0.963284 -0.085501 74.009 0.112433 -0.058339 0.991945 53.6097 0 0 0 1 -0.960772 -0.267525 0.073132 -216.107 0.261678 -0.961789 -0.080533 75.2125 0.091882 -0.058237 0.994065 53.8413 0 0 0 1 -0.964367 -0.259783 0.05008 -217.308 0.256066 -0.964106 -0.070218 73.9921 0.066524 -0.054892 0.996274 50.5952 0 0 0 1 -0.970415 -0.240513 0.021178 -219.874 0.239092 -0.969471 -0.05442 70.605 0.03362 -0.047746 0.998294 43.8835 0 0 0 1 -0.976715 -0.214218 -0.011792 -223 0.214506 -0.976085 -0.035277 65.7236 -0.003952 -0.036985 0.999308 34.6939 0 0 0 1 -0.981524 -0.185631 -0.046378 -225.952 0.186485 -0.982347 -0.01478 60.1135 -0.042816 -0.023156 0.998815 24.0967 0 0 0 1 -0.983925 -0.160061 -0.079196 -228.173 0.16017 -0.987077 0.005008 54.7939 -0.078975 -0.007755 0.996846 13.4094 0 0 0 1 -0.984018 -0.141642 -0.107914 -229.474 0.139957 -0.989889 0.023076 50.7123 -0.110092 0.007604 0.993892 3.53587 0 0 0 1 -0.982373 -0.134947 -0.129353 -229.818 0.131057 -0.99064 0.03816 49.0493 -0.133293 0.020535 0.990864 -4.43774 0 0 0 1 -0.979314 -0.141208 -0.144929 -229.328 0.134937 -0.989474 0.052274 50.2219 -0.150785 0.031638 0.98806 -11.3543 0 0 0 1 -0.974806 -0.157021 -0.158425 -228.124 0.147863 -0.98666 0.068102 53.3945 -0.167005 0.04296 0.985019 -18.7844 0 0 0 1 -0.969235 -0.179017 -0.168927 -226.323 0.166799 -0.982402 0.084053 57.8078 -0.181001 0.05329 0.982038 -26.1403 0 0 0 1 -0.963042 -0.203891 -0.176004 -224.109 0.188797 -0.977033 0.098798 62.7603 -0.192106 0.061918 0.979419 -32.9667 0 0 0 1 -0.956779 -0.228877 -0.179412 -221.711 0.211419 -0.971038 0.111297 67.7024 -0.19969 0.068555 0.977458 -38.9138 0 0 0 1 -0.951507 -0.250318 -0.178819 -219.54 0.231406 -0.965415 0.120102 71.9429 -0.202698 0.072898 0.976524 -43.3905 0 0 0 1 -0.948345 -0.265196 -0.174108 -218.015 0.246001 -0.961273 0.124247 74.9332 -0.200315 0.074999 0.976857 -45.9612 0 0 0 1 -0.948436 -0.270658 -0.164964 -217.547 0.252513 -0.959757 0.122895 76.1463 -0.191588 0.074903 0.978613 -46.1944 0 0 0 1 -0.953265 -0.262807 -0.149061 -218.646 0.247462 -0.962185 0.113855 74.8774 -0.173346 0.071647 0.982252 -42.9559 0 0 0 1 -0.961894 -0.243046 -0.125253 -221.038 0.231882 -0.967864 0.09732 71.3435 -0.144881 0.064568 0.98734 -36.1687 0 0 0 1 -0.971777 -0.216011 -0.094805 -223.923 0.209309 -0.974905 0.075823 66.2517 -0.108806 0.053839 0.992604 -26.8676 0 0 0 1 -0.98055 -0.186934 -0.05981 -226.552 0.183941 -0.981551 0.052191 60.4797 -0.068463 0.040174 0.996844 -16.2915 0 0 0 1 -0.986754 -0.160674 -0.022392 -228.457 0.160011 -0.986695 0.028787 54.9697 -0.026719 0.024823 0.999335 -5.57961 0 0 0 1 -0.989802 -0.141607 0.015505 -229.46 0.141733 -0.989878 0.007347 50.7179 0.014308 0.009469 0.999853 4.30098 0 0 0 1 -0.989605 -0.134378 0.051213 -229.562 0.134015 -0.990924 -0.010455 48.9204 0.052153 -0.003483 0.998633 12.2693 0 0 0 1 -0.986056 -0.14019 0.089674 -228.861 0.13826 -0.990017 -0.027413 49.9731 0.092621 -0.014632 0.995594 19.1733 0 0 0 1 -0.978427 -0.155525 0.135995 -227.436 0.150364 -0.987489 -0.047501 53.0132 0.141681 -0.026028 0.98957 26.5817 0 0 0 1 -0.966779 -0.177063 0.184351 -225.422 0.166873 -0.983524 -0.069525 57.2902 0.193625 -0.036451 0.980398 33.9079 0 0 0 1 -0.952097 -0.201528 0.229996 -223.015 0.184852 -0.97844 -0.092114 62.1102 0.243601 -0.045186 0.968823 40.6998 0 0 0 1 -0.936186 -0.226028 0.269199 -220.471 0.202195 -0.972738 -0.113573 66.9035 0.28753 -0.051894 0.956365 46.5787 0 0 0 1 -0.921951 -0.247365 0.298021 -218.167 0.217083 -0.967282 -0.131305 71.077 0.320751 -0.056362 0.945485 51.0577 0 0 0 1 -0.912973 -0.262106 0.312698 -216.578 0.22786 -0.963263 -0.142141 74.009 0.338467 -0.058519 0.939157 53.6097 0 0 0 1 -0.912203 -0.267564 0.310314 -216.107 0.233312 -0.961767 -0.143425 75.2126 0.336825 -0.058432 0.939753 53.8413 0 0 0 1 -0.923705 -0.259901 0.281461 -217.296 0.231573 -0.964061 -0.130229 74.0064 0.305192 -0.055114 0.950695 50.6265 0 0 0 1 -0.944312 -0.240535 0.224539 -219.874 0.222306 -0.969457 -0.103598 70.605 0.2426 -0.047913 0.968942 43.8835 0 0 0 1 -0.965668 -0.214054 0.147194 -223.019 0.205745 -0.976119 -0.069715 65.6907 0.158602 -0.037037 0.986647 34.6321 0 0 0 1 -0.980784 -0.185633 0.060027 -225.952 0.183789 -0.982344 -0.034946 60.1136 0.065455 -0.023242 0.997585 24.0969 0 0 0 1 -0.986773 -0.160059 -0.025697 -228.173 0.160205 -0.987077 -0.003731 54.7939 -0.024767 -0.007798 0.999663 13.4094 0 0 0 1 -0.984939 -0.141642 -0.099165 -229.474 0.140156 -0.989889 0.021824 50.7123 -0.101254 0.007597 0.994832 3.53587 0 0 0 1 -0.979717 -0.134936 -0.148144 -229.818 0.130301 -0.990643 0.040602 49.0492 -0.152236 0.020475 0.988132 -4.39126 0 0 0 1 -0.974273 -0.141212 -0.175644 -229.328 0.133226 -0.989473 0.056516 50.2219 -0.181776 0.031662 0.98283 -11.3543 0 0 0 1 -0.96854 -0.157025 -0.193063 -228.124 0.145341 -0.986658 0.073356 53.3945 -0.202007 0.042988 0.97844 -18.7844 0 0 0 1 -0.962986 -0.179022 -0.201521 -226.323 0.163869 -0.982399 0.089658 57.8078 -0.214025 0.053316 0.975372 -26.1403 0 0 0 1 -0.957794 -0.203895 -0.202624 -224.109 0.185986 -0.977031 0.104015 62.7604 -0.219178 0.061939 0.973717 -32.9667 0 0 0 1 -0.953152 -0.228735 -0.197942 -221.725 0.209086 -0.971073 0.115326 67.6736 -0.218595 0.068536 0.973406 -38.8811 0 0 0 1 -0.949537 -0.250321 -0.188996 -219.54 0.230108 -0.965414 0.122582 71.943 -0.213144 0.072906 0.974296 -43.3906 0 0 0 1 -0.947703 -0.265196 -0.177567 -218.015 0.245545 -0.961273 0.125147 74.9332 -0.203879 0.075002 0.976119 -45.9612 0 0 0 1 -0.948436 -0.270658 -0.164964 -217.547 0.252513 -0.959757 0.122895 76.1463 -0.191588 0.074903 0.978613 -46.1944 0 0 0 1 -0.953545 -0.262807 -0.147256 -218.646 0.247678 -0.962185 0.113384 74.8775 -0.171485 0.071645 0.982578 -42.9559 0 0 0 1 -0.962445 -0.243046 -0.120946 -221.038 0.232315 -0.967864 0.096278 71.3436 -0.140459 0.064564 0.987979 -36.1687 0 0 0 1 -0.972415 -0.21601 -0.088032 -223.923 0.209832 -0.974906 0.074356 66.2517 -0.101884 0.053833 0.993338 -26.8676 0 0 0 1 -0.981025 -0.186934 -0.051428 -226.552 0.184381 -0.981551 0.05061 60.4797 -0.05994 0.040168 0.997393 -16.2915 0 0 0 1 -0.986907 -0.160674 -0.014064 -228.457 0.160249 -0.986696 0.027429 54.9696 -0.018284 0.024816 0.999525 -5.57961 0 0 0 1 -0.989694 -0.141607 0.021301 -229.46 0.141774 -0.989878 0.006513 50.718 0.020163 0.009466 0.999752 4.30098 0 0 0 1 -0.989618 -0.134373 0.050981 -229.562 0.134017 -0.990925 -0.010348 48.9204 0.051909 -0.003407 0.998646 12.2229 0 0 0 1 -0.987121 -0.140189 0.07707 -228.861 0.138599 -0.990017 -0.025634 49.9731 0.079894 -0.014622 0.996696 19.1733 0 0 0 1 -0.982416 -0.155522 0.103301 -227.436 0.151863 -0.98749 -0.042435 53.0132 0.108608 -0.026001 0.993745 26.5817 0 0 0 1 -0.975825 -0.177056 0.128133 -225.422 0.170613 -0.983527 -0.059711 57.2901 0.136594 -0.036406 0.989958 33.9079 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.966687 -0.249688 -0.056315 275.134 0.249268 0.968326 -0.014473 -0.261342 0.058146 -0.000045 0.998308 0.000000 0 0 0 1 0.967597 -0.249688 -0.037569 275.134 0.249502 0.968326 -0.009655 -0.261421 0.03879 -0.00003 0.999247 0.000000 0 0 0 1 0.968169 -0.249688 -0.017432 275.134 0.249649 0.968326 -0.00448 -0.26144 0.017999 -0.000013 0.999838 0.000000 0 0 0 1 0.968321 -0.249688 0.003237 275.134 0.249688 0.968326 0.000832 -0.261359 -0.003342 0.000003 0.999994 0.000000 0 0 0 1 0.968048 -0.249688 0.023213 275.134 0.249617 0.968326 0.005966 -0.261495 -0.023968 0.000019 0.999713 0.000000 0 0 0 1 0.967461 -0.249688 0.040924 275.134 0.249467 0.968326 0.010518 -0.261358 -0.042253 0.000034 0.999107 0.000000 0 0 0 1 0.966734 -0.249688 0.055503 275.134 0.24928 0.968326 0.014265 -0.261443 -0.057307 0.000046 0.998357 0.000000 0 0 0 1 0.966096 -0.249688 0.065678 275.134 0.249116 0.968326 0.01688 -0.261453 -0.067813 0.000054 0.997698 0.000000 0 0 0 1 0.965661 -0.249688 0.071794 275.134 0.249005 0.968326 0.018452 -0.26139 -0.074127 0.000059 0.997249 0.000000 0 0 0 1 0.965383 -0.249688 0.075443 275.134 0.248933 0.968326 0.019389 -0.261557 -0.077894 0.000062 0.996962 0.000000 0 0 0 1 0.965277 -0.249688 0.076787 275.134 0.248906 0.968326 0.019735 -0.261355 -0.079282 0.000063 0.996852 0.000000 0 0 0 1 0.965336 -0.249688 0.076038 275.134 0.248921 0.968326 0.019542 -0.261341 -0.078509 0.000062 0.996913 0.000000 0 0 0 1 0.96554 -0.249688 0.073407 275.134 0.248973 0.968326 0.018866 -0.261344 -0.075793 0.000059 0.997124 0.000000 0 0 0 1 0.96586 -0.249688 0.069071 275.134 0.249056 0.968326 0.017751 -0.261427 -0.071316 0.000056 0.997453 0.000000 0 0 0 1 0.966253 -0.249688 0.063336 275.134 0.249157 0.968326 0.016278 -0.261386 -0.065394 0.000051 0.997859 0.000000 0 0 0 1 0.966687 -0.249688 0.056314 275.134 0.249268 0.968326 0.014472 -0.261291 -0.058144 0.000046 0.998308 0.000000 0 0 0 1 0.967264 -0.249688 0.045336 275.134 0.249416 0.968326 0.011652 -0.261446 -0.04681 0.000036 0.998904 0.000000 0 0 0 1 0.96788 -0.249688 0.029403 275.134 0.249575 0.968326 0.007556 -0.261601 -0.030358 0.000024 0.999539 0.000000 0 0 0 1 0.968269 -0.249688 0.010522 275.134 0.249675 0.968326 0.002704 -0.261404 -0.010865 0.000008 0.999941 0.000000 0 0 0 1 0.968284 -0.249688 -0.009063 275.134 0.249679 0.968326 -0.002328 -0.261474 0.009358 -0.000007 0.999956 0.000000 0 0 0 1 0.967957 -0.249688 -0.026731 275.134 0.249594 0.968326 -0.00687 -0.26136 0.0276 -0.000021 0.999619 0.000000 0 0 0 1 0.967473 -0.249688 -0.04063 275.134 0.24947 0.968326 -0.010442 -0.261562 0.04195 -0.000033 0.99912 0.000000 0 0 0 1 0.967126 -0.249688 -0.048188 275.134 0.249381 0.968326 -0.012384 -0.26158 0.049754 -0.000039 0.998761 0.000000 0 0 0 1 0.96709 -0.249688 -0.04892 275.134 0.249371 0.968326 -0.012573 -0.261517 0.05051 -0.00004 0.998724 0.000000 0 0 0 1 0.967295 -0.249688 -0.044671 275.134 0.249424 0.968326 -0.011481 -0.261397 0.046123 -0.000036 0.998936 0.000000 0 0 0 1 0.967623 -0.249688 -0.036902 275.134 0.249509 0.968326 -0.009483 -0.261349 0.038102 -0.00003 0.999274 0.000000 0 0 0 1 0.967941 -0.249688 -0.027307 275.134 0.24959 0.968326 -0.007017 -0.261522 0.028194 -0.000022 0.999602 0.000000 0 0 0 1 0.968173 -0.249688 -0.017193 275.134 0.24965 0.968326 -0.004418 -0.261396 0.017752 -0.000014 0.999842 0.000000 0 0 0 1 0.96829 -0.249688 -0.00828 275.134 0.24968 0.968326 -0.002127 -0.261423 0.00855 -0.000007 0.999963 0.000000 0 0 0 1 0.968324 -0.249688 -0.002065 275.134 0.249689 0.968326 -0.00053 -0.261604 0.002133 -0.000002 0.999998 0.000000 0 0 0 1 0.968326 -0.249688 -0.000000 275.134 0.249689 0.968326 -0.000000 -0.261291 0.000000 0 1 0.000000 0 0 0 1 0.968318 -0.249688 -0.004099 275.134 0.249687 0.968326 -0.001054 -0.261412 0.004232 -0.000002 0.999991 0.000000 0 0 0 1 0.968232 -0.249688 -0.013513 275.134 0.249665 0.968326 -0.003473 -0.261391 0.013952 -0.00001 0.999903 0.000000 0 0 0 1 0.967979 -0.249688 -0.025924 275.134 0.2496 0.968326 -0.006663 -0.261569 0.026767 -0.00002 0.999642 0.000000 0 0 0 1 0.967544 -0.249688 -0.038922 275.134 0.249488 0.968326 -0.010003 -0.261294 0.040188 -0.000031 0.999192 0.000000 0 0 0 1 0.967043 -0.249688 -0.049843 275.134 0.249359 0.968326 -0.01281 -0.26134 0.051463 -0.00004 0.998675 0.000000 0 0 0 1 0.966678 -0.249688 -0.056477 275.134 0.249266 0.968326 -0.014515 -0.261142 0.058313 -0.000046 0.998298 0.000000 0 0 0 1 0.966688 -0.249688 -0.056312 275.134 0.249268 0.968326 -0.014472 -0.261447 0.058143 -0.000045 0.998308 0.000000 0 0 0 1 0.967108 -0.249688 -0.048552 275.134 0.249376 0.968326 -0.012478 -0.261562 0.05013 -0.000039 0.998743 0.000000 0 0 0 1 0.96769 -0.249688 -0.035067 275.134 0.249526 0.968326 -0.009012 -0.26149 0.036207 -0.000028 0.999345 0.000000 0 0 0 1 0.968163 -0.249688 -0.017773 275.134 0.249648 0.968326 -0.004567 -0.261404 0.018351 -0.000015 0.999831 0.000000 0 0 0 1 0.968325 -0.249688 0.00153 275.134 0.249689 0.968326 0.000393 -0.26146 -0.00158 0.000001 0.999999 0.000000 0 0 0 1 0.968088 -0.249688 0.021461 275.134 0.249628 0.968326 0.005515 -0.26126 -0.022158 0.000017 0.999754 0.000000 0 0 0 1 0.967504 -0.249688 0.039896 275.134 0.249478 0.968326 0.010254 -0.261268 -0.041192 0.000033 0.999152 0.000000 0 0 0 1 0.966756 -0.249688 0.055132 275.134 0.249286 0.968326 0.014169 -0.261422 -0.056924 0.000045 0.998378 0.000000 0 0 0 1 0.9661 -0.249688 0.065628 275.134 0.249117 0.968326 0.016867 -0.261356 -0.067761 0.000054 0.997702 0.000000 0 0 0 1 0.965707 -0.249688 0.071176 275.134 0.249017 0.968326 0.018293 -0.261439 -0.07349 0.000057 0.997296 0.000000 0 0 0 1 0.965555 -0.249688 0.073211 275.134 0.248977 0.968326 0.018815 -0.261519 -0.075591 0.00006 0.997139 0.000000 0 0 0 1 0.965608 -0.249688 0.072514 275.134 0.248991 0.968326 0.018637 -0.261246 -0.07487 0.00006 0.997193 0.000000 0 0 0 1 0.965812 -0.249688 0.069745 275.134 0.249043 0.968326 0.017925 -0.261485 -0.072013 0.000057 0.997404 0.000000 0 0 0 1 0.966096 -0.249688 0.06568 275.134 0.249116 0.968326 0.01688 -0.261501 -0.067814 0.000054 0.997698 0.000000 0 0 0 1 0.966406 -0.249688 0.060959 275.134 0.249196 0.968326 0.015667 -0.261282 -0.06294 0.000049 0.998017 0.000000 0 0 0 1 0.966689 -0.249688 0.056282 275.134 0.249268 0.968326 0.014465 -0.26137 -0.058111 0.000045 0.99831 0.000000 0 0 0 1 0.966984 -0.249688 0.05096 275.134 0.249345 0.968326 0.013097 -0.261352 -0.052616 0.000042 0.998615 0.000000 0 0 0 1 0.967328 -0.249688 0.043962 275.134 0.249433 0.968326 0.011299 -0.261403 -0.04539 0.000035 0.998969 0.000000 0 0 0 1 0.967658 -0.249688 0.035967 275.134 0.249518 0.968326 0.009243 -0.261384 -0.037137 0.000029 0.99931 0.000000 0 0 0 1 0.967934 -0.249688 0.027547 275.134 0.249589 0.968326 0.007079 -0.261595 -0.028442 0.000023 0.999595 0.000000 0 0 0 1 0.968138 -0.249688 0.019099 275.134 0.249641 0.968326 0.004909 -0.261391 -0.019719 0.000015 0.999806 0.000000 0 0 0 1 0.96826 -0.249688 0.011342 275.134 0.249672 0.968326 0.002915 -0.261316 -0.01171 0.000008 0.999932 0.000000 0 0 0 1 0.968314 -0.249688 0.004817 275.134 0.249686 0.968326 0.001238 -0.261511 -0.004974 0.000004 0.999988 0.000000 0 0 0 1 0.968326 -0.249688 -0.000000 275.134 0.249689 0.968326 -0.000000 -0.261291 0.000000 0.000000 1 0.000000 0 0 0 1 0.968323 -0.249688 -0.0023 275.134 0.249689 0.968326 -0.000591 -0.26145 0.002374 -0.000001 0.999997 0.000000 0 0 0 1 0.968323 -0.249688 -0.0023 275.134 0.249689 0.968326 -0.000591 -0.261533 0.002374 -0.000001 0.999997 0.000000 0 0 0 1 0.968326 -0.249688 -0.00091 275.134 0.249689 0.968326 -0.000234 -0.26138 0.00094 -0.000001 1 0.000000 0 0 0 1 0.968325 -0.249688 0.000929 275.134 0.249689 0.968326 0.000238 -0.261387 -0.000959 0.000001 1 0.000000 0 0 0 1 0.968323 -0.249688 0.002298 275.134 0.249689 0.968326 0.000591 -0.261292 -0.002374 0.000002 0.999997 0.000000 0 0 0 1 0.968323 -0.249688 0.002299 275.134 0.249688 0.968326 0.000591 -0.261617 -0.002373 0.000001 0.999997 0.000000 0 0 0 1 0.968326 -0.249688 -0.000026 275.134 0.249689 0.968326 -0.000006 -0.261322 0.000027 0.000000 1 0.000000 0 0 0 1 0.968309 -0.249688 -0.005776 275.134 0.249685 0.968326 -0.001484 -0.2613 0.005963 -0.000005 0.999982 0.000000 0 0 0 1 0.968214 -0.249688 -0.014733 275.134 0.249661 0.968326 -0.003786 -0.261597 0.015212 -0.000012 0.999884 0.000000 0 0 0 1 0.967993 -0.249688 -0.025374 275.134 0.249604 0.968326 -0.006521 -0.261379 0.026198 -0.000021 0.999657 0.000000 0 0 0 1 0.967646 -0.249688 -0.036299 275.134 0.249514 0.968326 -0.009329 -0.261433 0.037479 -0.000029 0.999297 0.000000 0 0 0 1 0.96722 -0.249688 -0.046274 275.134 0.249405 0.968326 -0.011892 -0.261566 0.047777 -0.000038 0.998858 0.000000 0 0 0 1 0.966826 -0.249688 -0.053885 275.134 0.249304 0.968326 -0.013848 -0.261479 0.055636 -0.000044 0.998451 0.000000 0 0 0 1 0.966609 -0.249688 -0.057655 275.134 0.249248 0.968326 -0.014818 -0.261363 0.059529 -0.000047 0.998227 0.000000 0 0 0 1 0.966687 -0.249688 -0.056315 275.134 0.249268 0.968326 -0.014473 -0.261431 0.058146 -0.000045 0.998308 0.000000 0 0 0 1 0.967194 -0.249688 -0.046813 275.134 0.249398 0.968326 -0.01203 -0.2614 0.048334 -0.000039 0.998831 0.000000 0 0 0 1 0.967885 -0.249688 -0.029216 275.134 0.249576 0.968326 -0.007509 -0.261414 0.030166 -0.000023 0.999545 0.000000 0 0 0 1 0.968303 -0.249688 -0.006644 275.134 0.249683 0.968326 -0.001707 -0.261274 0.00686 -0.000005 0.999976 0.000000 0 0 0 1 0.96817 -0.249688 0.01733 275.134 0.249649 0.968326 0.004453 -0.261248 -0.017894 0.000014 0.99984 0.000000 0 0 0 1 0.967523 -0.249688 0.03943 275.134 0.249483 0.968326 0.010134 -0.26146 -0.040711 0.000031 0.999171 0.000000 0 0 0 1 0.966667 -0.249688 0.056663 275.134 0.249263 0.968326 0.014563 -0.261468 -0.058504 0.000046 0.998287 0.000000 0 0 0 1 0.9661 -0.249688 0.065628 275.134 0.249117 0.968326 0.016867 -0.261407 -0.067761 0.000054 0.997702 0.000000 0 0 0 1 0.966064 -0.249688 0.06616 275.134 0.249108 0.968326 0.017004 -0.261493 -0.06831 0.000054 0.997664 0.000000 0 0 0 1 0.966391 -0.249688 0.061199 275.134 0.249192 0.968326 0.015728 -0.261284 -0.063188 0.000049 0.998002 0.000000 0 0 0 1 0.966914 -0.249688 0.052288 275.134 0.249326 0.968326 0.013438 -0.261533 -0.053988 0.000042 0.998542 0.000000 0 0 0 1 0.967459 -0.249688 0.040962 275.134 0.249467 0.968326 0.010528 -0.26151 -0.042293 0.000033 0.999105 0.000000 0 0 0 1 0.967905 -0.249688 0.028549 275.134 0.249581 0.968326 0.007337 -0.261468 -0.029477 0.000023 0.999565 0.000000 0 0 0 1 0.968185 -0.249688 0.016526 275.134 0.249653 0.968326 0.004247 -0.261374 -0.017064 0.000013 0.999854 0.000000 0 0 0 1 0.968304 -0.249688 0.006585 275.134 0.249684 0.968326 0.001692 -0.261393 -0.006798 0.000005 0.999977 0.000000 0 0 0 1 0.968326 -0.249688 -0.000000 275.134 0.249689 0.968326 -0.000000 -0.261291 0.000000 0.000000 1 0.000000 0 0 0 1 0.968321 -0.249688 -0.003217 275.134 0.249688 0.968326 -0.000826 -0.261334 0.003321 -0.000003 0.999995 0.000000 0 0 0 1 0.968316 -0.249688 -0.004468 275.134 0.249687 0.968326 -0.001147 -0.261553 0.004613 -0.000004 0.999989 0.000000 0 0 0 1 0.968317 -0.249688 -0.004286 275.134 0.249687 0.968326 -0.001101 -0.261349 0.004425 -0.000003 0.99999 0.000000 0 0 0 1 0.968321 -0.249688 -0.00321 275.134 0.249688 0.968326 -0.000824 -0.261547 0.003313 -0.000003 0.999994 0.000000 0 0 0 1 0.968324 -0.249688 -0.001787 275.134 0.249689 0.968326 -0.000459 -0.261403 0.001845 -0.000001 0.999998 0.000000 0 0 0 1 0.968326 -0.249688 -0.000536 275.134 0.249689 0.968326 -0.000137 -0.261501 0.000553 -0.000001 1 0.000000 0 0 0 1 0.968326 -0.249688 -0.000000 275.134 0.249689 0.968326 -0.000000 -0.261302 0.000000 0 1 0.000000 0 0 0 1 0.968326 -0.249688 0.00041 275.134 0.249689 0.968326 0.000105 -0.261414 -0.000424 0.000000 1 0.000000 0 0 0 1 0.968325 -0.249688 0.001415 275.134 0.249689 0.968326 0.000363 -0.261544 -0.001461 0.000000 0.999999 0.000000 0 0 0 1 0.968322 -0.249688 0.002648 275.134 0.249688 0.968326 0.00068 -0.261398 -0.002733 0.000002 0.999996 0.000000 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290226 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290381 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290176 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290267 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290301 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290416 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290384 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290297 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290473 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290284 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290413 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290359 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290448 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290349 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290448 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290441 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290459 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290375 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290466 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290407 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290321 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290263 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290383 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290218 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290441 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290374 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290309 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290307 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290338 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290315 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290466 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290503 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290385 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290361 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290498 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290467 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290455 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290403 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290257 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290324 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290465 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290374 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290403 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.29042 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.29042 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290294 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290462 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290229 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290482 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290392 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290276 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290443 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290443 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290341 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290388 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290387 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290376 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290371 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290415 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290412 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.29047 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290257 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290371 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290337 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290255 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.29048 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290249 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290317 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290443 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290259 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290433 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290463 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290256 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290373 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290466 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290522 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290376 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290333 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290299 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290475 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290451 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290394 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290341 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290447 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.29047 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290389 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290337 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290453 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290373 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.29052 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.29047 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290335 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290344 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290296 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290354 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290318 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290428 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290294 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290451 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290224 0.000000 0.000000 1 -0.000007 0 0 0 1 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290498 0.000000 0.000000 1 -0.000007 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000038 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000000 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000035 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000003 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000085 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.00003 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000077 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000029 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000064 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000061 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000027 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000032 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000046 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000103 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000021 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000001 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000023 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000057 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000113 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000033 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.00003 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.00014 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000096 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000026 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000094 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000064 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000008 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000063 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000002 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.00001 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000074 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000022 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000061 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000008 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000013 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000033 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000029 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000053 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000013 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000012 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000003 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000063 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000144 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000018 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.00004 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000004 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.00001 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000029 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000033 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000056 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000028 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.00005 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000041 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000103 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000076 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.00003 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000057 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000029 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000012 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000096 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000079 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000001 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000042 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000079 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000053 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000001 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000089 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.0001 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000015 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000013 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000111 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000122 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000056 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000056 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000085 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000005 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000052 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000002 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000042 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.00004 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000066 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000022 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000013 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000009 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000028 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000061 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.00002 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000076 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000017 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000011 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000079 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000044 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000000 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000056 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000048 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000007 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000066 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000000 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000018 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 0.000182 0.000002 0 -1 -0.000003 0 0 0 1 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000013 0.000002 0 -1 -0.000003 0 0 0 1 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - 0 0.033333 0.066666 0.1 0.133333 0.166667 0.2 0.233333 0.266667 0.3 0.333333 0.366667 0.4 0.433333 0.466667 0.5 0.533333 0.566667 0.6 0.633333 0.666667 0.7 0.733333 0.766667 0.8 0.833333 0.866667 0.9 0.933333 0.966667 1 1.03333 1.06667 1.1 1.13333 1.16667 1.2 1.23333 1.26667 1.3 1.33333 1.36667 1.4 1.43333 1.46667 1.5 1.53333 1.56667 1.6 1.63333 1.66667 1.7 1.73333 1.76667 1.8 1.83333 1.86667 1.9 1.93333 1.96667 2 2.03333 2.06667 2.1 2.13333 2.16667 2.2 2.23333 2.26667 2.3 2.33333 2.36667 2.4 2.43333 2.46667 2.5 2.53333 2.56667 2.6 2.63333 2.66667 2.7 2.73333 2.76667 2.8 2.83333 2.86667 2.9 2.93333 2.96667 3 3.03333 3.06667 3.1 3.13333 3.16667 3.2 3.23333 3.26667 3.3 3.33333 - - - - - - - CONSTANT - CONSTANT - - - - 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 166.968 - - - - - - - - LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ./monster.jpg - - - - - - - - - - - - - monster.jpg - A8R8G8B8 - - - - - monster_jpg-surface - WRAP - WRAP - NONE - NONE - NONE - - - - - - 0.588235 0.588235 0.588235 1 - - - - - - 0 - 0 - 1 - 1 - 1 - 1 - 0 - 0 - - - 1 - - - - - - 0.1 0.1 0.1 1 - - - 20 - - - 0 0 0 1 - - - 1 - - - 1 1 1 1 - - - 1 - - - 1 - - - - - - 0 - - - 0 - - - - - - - - 0 - 0 - 0 - 0 - - - - - - - - - 558.965 404.09 -9.41835 252.222 402.864 -54.205 32.5665 387.298 -78.854 -359.273 211.385 -19.0616 -598.079 -13.3313 -17.5054 -635.946 -145.914 -19.0616 -547.166 -372.164 40.2031 -260.462 -162.299 40.203 246.315 -147.057 -79.6185 542.48 -151.06 -44.913 758.412 -43.888 -62.8404 21.7976 426.108 40.203 -378.533 238.981 40.2031 -627.402 27.0373 40.2031 -605.1 -174.866 40.2031 -25.3967 -194.286 40.203 -107.623 353.534 -99.0134 268.451 290.85 -169.261 -321.215 143.919 -77.6915 260.646 153.714 -223.493 39.9728 209.082 -156.039 -391.04 -41.853 -139.908 -121.936 170.547 -142.274 380.051 66.4672 -251.531 242.389 21.5963 -203.746 22.0431 -26.5261 -156.814 -213.771 -92.1041 -97.4809 -298.191 -127.509 -103.042 -77.3162 -32.3855 -125.878 257.239 -50.0724 -161.894 34.0969 -134.952 -108.118 -257.987 -139.94 -30.6083 -50.7188 -123.835 -67.4952 22.0084 -181.514 -55.5322 -284.581 -304.684 40.203 -99.0235 -155.844 40.203 705.303 221.823 -138.614 789.328 20.678 -72.2831 -537.312 -32.2996 -100.256 -615.112 -174.866 -86.8028 -550.064 -307.245 -44.9519 -314.968 -227.647 -77.0878 -281.314 48.6181 -243.634 -169.529 -141.817 -145.953 -410.356 17.6217 -316.705 -465.797 -178.963 -326.302 -440.269 -338.364 -242.311 -255.603 -227.647 -138.915 14.2079 45.2649 -335.227 32.0551 11.6046 -247.885 -24.9719 3.8576 -444.533 -103.65 -112.409 -447.284 -132.463 -170.696 -330.935 -15.0917 -60.2354 -242.667 154.274 -15.1391 -422.936 160.1 -42.0847 -339.077 65.7941 -48.1499 -437.565 -52.7382 -120.825 -378.505 -86.6906 -159.574 -345.821 65.6433 -103.599 -310.298 143.503 -162.674 -427.832 140.897 -179.078 -341.135 76.3055 -158.966 -449.154 -56.9874 -172.668 -407.19 -101.405 -187.717 -340.868 61.6315 -188.674 -308.948 -57.088 -388.882 -363.103 -61.2255 -389.398 -234.579 -86.187 -363.046 -376.695 -171.947 -301.741 -353.317 -194.818 -287.062 -237.297 -121.906 -347.524 -216.383 -102.277 -417.599 -349.579 -101.46 -419.247 -226.311 -120.57 -397.079 -363.511 -209.07 -327.758 -348.909 -220.374 -317.345 -237.75 -150.824 -384.223 -214.018 -216.691 -512.471 -299.362 -220.533 -524.241 -242.736 -279.207 -477.521 -318.598 -372.739 -407.375 -259.441 -394.838 -404.628 -179.247 -257.957 -505.428 -155.418 -236.316 -568.835 -297.066 -240.158 -580.604 -240.44 -317.133 -577.263 -381.502 -521.043 -466.938 -278.287 -543.141 -464.192 -146.696 -231.113 -578.573 -142.03 -143.793 -589.922 -387.554 -123.358 -615.393 -345.738 -180.616 -583.426 -450.221 -97.4354 -662.435 -286.208 -384.975 -704.341 -438.572 -493.77 -624.724 -277.971 -513.328 -614.68 -198.074 -308.634 -722.901 -169.787 -207.244 -671.558 -454.329 -117.005 -756.407 -283.655 -470.519 -648.255 -230.036 -351.878 -729.182 -267.828 -158.686 -717.111 -363.501 -9.81772 -748.063 -392.599 -66.3276 -711.51 -504.127 676.056 403.457 -10.6067 922.953 375.782 -39.6783 960.668 383.161 2.14378 1061.35 356.762 40.2028 1053.7 346.758 -18.2369 1117.05 272.841 -14.6657 1119.22 284.353 40.2028 1152.01 217.427 40.2028 1120.75 128.277 -32.3903 1154.32 99.7808 40.2028 948.344 -68.9338 40.2028 918.453 14.2217 -95.2934 596.877 202.43 -226.42 766.139 12.7916 -190.462 494.4 -153.3 -118.67 729.558 136.921 -244.167 545.802 93.8417 -338.023 690.121 50.8344 -324.877 764.322 4.0724 -249.3 518.621 11.2156 -389.245 682.576 -164.696 -133.836 415.539 -12.9001 -273.108 643.124 -35.5904 -384.905 715.597 -118.766 -287.239 495.985 -152.255 -186.11 488.245 -48.2971 -391.496 623.367 -203.09 -177.233 400.659 -56.5926 -292.368 601.471 -109.919 -400.28 651.012 -204.493 -315.403 449.267 -241.792 -227.751 438.002 -183.939 -434.285 595.313 -310.175 -259.375 376.155 -167.649 -367.745 507.031 -228.749 -409.177 588.146 -278.435 -375.276 289.487 -226.311 -450.472 280.893 -219.652 -407.647 332.802 -294.654 -479.854 252.694 -283.647 -465.87 209.876 -275.697 -408.128 319.396 -310.744 -255.764 257.069 -363.088 -452.122 467.024 -349.519 -290.574 215.546 -359.667 -402.806 467.468 -347.786 -451.105 337.988 -457.825 -252.446 265.056 -466.161 -381.514 441.552 -435.883 -285.479 279.28 -455.978 -306.382 352.053 -456.275 -402.807 441.455 -445.446 -368.508 383.441 -553.769 -229.992 264.043 -561.999 -387.196 466.393 -551.819 -250.784 272.997 -559.478 -296.869 390.756 -555.537 -398.519 464.616 -556.584 -343.033 271.471 -655.645 -297.372 418.604 -630.348 -400.968 377.032 -640.682 -230.241 293.651 -667.416 -378.092 460.045 -626.719 -254.409 484.703 -631.39 -326.296 340.152 -825.111 -202.604 317.335 -787.405 -377.895 451.236 -688.596 -235.762 304.327 -790.592 -301.295 433.476 -693.155 -415.899 490.612 -692.953 -314.281 499.471 -820.408 -177.331 486.543 -861.734 -438.858 527.033 -790.548 -193.537 507.467 -768.062 -413.427 577.257 -761.531 -297.345 626.437 -888.782 -452.827 644.719 -823.452 -436.229 645.052 -822.685 -359.418 626.526 -888.681 -181.518 645.299 -822.477 -197.725 625.983 -889.066 -264.872 645.229 -822.897 -252.173 580.055 -836.628 -298.385 627.235 -885.962 -359.336 695.541 -913.328 -379.792 697.205 -900.122 -181.253 1039.45 303.194 -77.8383 1101.1 253.686 -49.6417 885.246 351.891 -63.9092 1015.08 235.109 -111.831 1102.84 161.378 -71.0802 843.785 368.243 -71.3395 965.997 179.582 -129.088 1077.52 75.2012 -88.1132 846.834 138.578 -109.506 1130.63 219.113 -9.82445 972.648 -25.3677 -63.5674 679.933 441.705 40.2029 260.312 440.008 40.203 246.48 -170.173 40.203 912.514 -48.5509 40.2028 824.669 424.477 40.2029 878.609 424.149 40.2028 909.031 425.978 40.2028 968.589 404.236 40.2028 984.155 -76.1361 40.2028 1132.43 24.6494 40.2028 1089.27 37.2052 -39.0682 1056.88 -2.82201 -53.0906 997.81 -37.0952 -45.2141 1100.85 -23.3858 40.2028 1122.15 -2.15071 40.2028 1031.13 -65.4153 40.2028 -974.541 -116.414 40.2032 -966.748 -188.349 -6.42429 -973.5 -204.705 40.2032 -1360.94 -134.989 40.2032 -1356.56 -175.492 13.1094 -1360.36 -184.7 40.2032 -1746.98 -71.4633 40.2033 987.83 34.0016 -96.8683 482.298 625.285 5.71433 309.065 777.283 20.6301 -261.253 577.012 5.71445 -468.805 677.187 20.6302 558.966 404.09 89.8242 252.222 402.864 134.611 32.5666 387.298 159.26 -359.273 211.385 99.4677 -598.079 -13.3312 97.9116 -635.946 -145.914 99.4678 246.315 -147.057 160.024 542.48 -151.06 125.319 758.412 -43.888 143.246 -233.929 337.011 40.203 -107.623 353.534 179.419 268.451 290.85 249.667 -321.215 143.919 158.098 260.646 153.714 303.899 39.9729 209.082 236.445 -391.04 -41.853 220.314 -121.935 170.547 222.68 380.051 66.4672 331.937 242.389 21.5963 284.152 22.0431 -26.5261 237.22 -213.771 -92.1041 177.887 -298.191 -127.509 183.448 -77.3161 -32.3854 206.284 257.24 -50.0724 242.3 34.0969 -134.952 188.524 -257.987 -139.94 111.014 -50.7188 -123.835 147.901 22.0084 -181.514 135.938 705.303 221.823 219.02 789.328 20.678 152.689 -537.312 -32.2996 180.662 -615.112 -174.866 167.209 -550.064 -307.245 125.358 -314.968 -227.647 157.494 -281.314 48.6181 324.041 -169.529 -141.817 226.359 -410.355 17.6217 397.111 -465.797 -178.963 406.708 -440.269 -338.364 322.717 -255.603 -227.647 219.321 14.208 45.2649 415.633 32.0552 11.6047 328.291 -24.9718 3.85764 524.939 -103.65 -112.409 527.69 -132.463 -170.696 411.341 -15.0917 -60.2354 323.073 154.274 -15.1391 503.342 160.1 -42.0846 419.483 65.7942 -48.1499 517.971 -52.7381 -120.825 458.911 -86.6904 -159.574 426.227 65.6434 -103.599 390.704 143.503 -162.674 508.238 140.897 -179.078 421.541 76.3056 -158.966 529.56 -56.9872 -172.668 487.596 -101.405 -187.717 421.274 61.6316 -188.674 389.354 -57.0879 -388.882 443.509 -61.2254 -389.398 314.985 -86.1869 -363.046 457.101 -171.947 -301.741 433.723 -194.817 -287.062 317.703 -121.906 -347.524 296.789 -102.276 -417.599 429.985 -101.46 -419.247 306.717 -120.57 -397.079 443.918 -209.07 -327.758 429.315 -220.374 -317.345 318.156 -150.824 -384.223 294.424 -216.691 -512.471 379.768 -220.533 -524.241 323.142 -279.206 -477.521 399.004 -372.739 -407.375 339.847 -394.838 -404.628 259.653 -257.957 -505.428 235.824 -236.316 -568.835 377.472 -240.158 -580.604 320.846 -317.133 -577.263 461.908 -521.042 -466.938 358.693 -543.141 -464.192 227.102 -231.113 -578.573 222.436 -143.793 -589.922 467.96 -123.358 -615.393 426.144 -180.616 -583.426 530.627 -97.4353 -662.435 366.614 -384.975 -704.341 518.979 -493.77 -624.724 358.377 -513.328 -614.68 278.481 -308.634 -722.901 250.194 -207.244 -671.558 534.735 -117.005 -756.407 364.061 -470.518 -648.255 310.442 -351.878 -729.182 348.234 -158.686 -717.111 443.907 -9.81756 -748.063 473.005 -66.3274 -711.51 584.533 676.056 403.457 91.0124 922.953 375.782 120.084 960.668 383.161 78.2619 1053.7 346.758 98.6425 1117.05 272.841 95.0714 1120.75 128.277 112.796 1150.35 66.9116 40.2028 918.453 14.2217 175.699 596.877 202.43 306.826 766.139 12.7916 270.868 494.4 -153.3 199.075 729.558 136.921 324.573 545.802 93.8417 418.428 690.121 50.8344 405.282 764.322 4.0724 329.706 518.621 11.2156 469.651 682.576 -164.696 214.241 415.539 -12.9001 353.513 643.124 -35.5904 465.31 715.597 -118.766 367.645 495.985 -152.255 266.516 488.245 -48.2971 471.902 623.367 -203.09 257.639 400.659 -56.5926 372.773 601.471 -109.919 480.686 651.012 -204.493 395.809 449.267 -241.792 308.157 438.002 -183.939 514.69 595.313 -310.175 339.781 376.155 -167.649 448.151 507.031 -228.749 489.582 588.147 -278.435 455.681 289.487 -226.311 530.878 280.893 -219.652 488.053 332.802 -294.654 560.26 252.695 -283.647 546.276 209.876 -275.697 488.534 319.396 -310.744 336.17 257.069 -363.088 532.528 467.024 -349.519 370.98 215.546 -359.667 483.212 467.468 -347.786 531.511 337.988 -457.825 332.852 265.056 -466.161 461.92 441.553 -435.883 365.885 279.28 -455.978 386.788 352.053 -456.275 483.212 441.455 -445.446 448.914 383.441 -553.769 310.398 264.043 -561.999 467.602 466.393 -551.819 331.19 272.997 -559.478 377.275 390.756 -555.537 478.924 464.616 -556.584 423.439 271.471 -655.645 377.778 418.604 -630.348 481.374 377.032 -640.682 310.647 293.651 -667.416 458.498 460.045 -626.719 334.815 484.703 -631.39 406.702 340.152 -825.111 283.009 317.335 -787.405 458.301 451.236 -688.596 316.167 304.327 -790.592 381.701 433.476 -693.155 496.305 490.612 -692.953 394.687 499.471 -820.408 257.736 486.543 -861.734 519.264 527.033 -790.548 273.943 507.467 -768.062 493.833 577.257 -761.531 377.751 626.437 -888.782 533.232 644.719 -823.452 516.635 645.052 -822.685 439.824 626.526 -888.681 261.924 645.299 -822.477 278.13 625.983 -889.066 345.278 645.229 -822.897 332.579 580.055 -836.628 378.791 627.235 -885.962 439.741 695.541 -913.328 460.197 697.205 -900.122 261.658 1039.45 303.194 158.244 1101.1 253.686 130.047 885.246 351.891 144.315 1015.08 235.109 192.237 1102.84 161.378 151.486 843.785 368.243 151.745 965.997 179.582 209.493 1077.52 75.2012 168.519 846.835 138.578 189.911 1130.63 219.113 90.2301 972.648 -25.3677 143.973 505.639 412.719 40.2029 568.185 -165.976 40.2029 762.912 -67.4993 40.2029 841.425 -35.9378 40.2029 1089.27 37.2052 119.474 1056.88 -2.82201 133.496 997.81 -37.0952 125.62 -966.748 -188.349 86.8306 -1356.56 -175.492 67.297 987.83 34.0016 177.274 442.767 586.685 40.2029 482.298 625.285 74.6915 486.264 638.201 40.2029 309.065 777.283 59.7757 286.808 755.55 40.203 311.298 784.555 40.203 3.60059 892.627 40.203 -312.712 483.512 40.203 -261.253 577.012 74.6916 -260.883 590.518 40.203 -468.805 677.187 59.7759 -484.444 650.296 40.2031 -468.596 684.792 40.2031 -793.984 706.704 40.2031 - - - - - - - - - - 0.003951 0.999992 0 0.110554 0.99387 0 0.102833 0.782531 -0.614061 0.029179 0.844324 -0.535038 -0.040556 0.999177 0 -0.043654 0.675701 -0.735882 -0.239517 0.413786 -0.878301 -0.515652 0.569872 -0.639804 -0.625457 0.780259 0 -0.561129 0.827728 0 -0.682649 0.730747 0 -0.613385 0.469875 -0.634804 -0.959489 -0.281745 0 -0.973292 -0.023675 -0.228345 -0.346074 -0.938207 0 -0.191028 -0.981585 0 -0.162091 -0.886156 -0.434113 -0.264236 -0.964458 0 0.067329 -0.997731 0 0.020066 -0.869195 -0.494063 0.268387 -0.963311 0 0.130125 -0.991362 -0.016379 0.404848 -0.914384 0 0.715591 -0.675729 -0.176976 0.135267 -0.990809 0 0.582106 -0.555438 -0.593836 -0.324869 -0.945759 0 -0.11244 -0.559395 -0.82124 -0.041094 0.554449 -0.831203 -0.308706 0.30649 -0.900425 -0.649077 0.588422 -0.482139 -0.199852 0.152187 -0.967935 0.125028 0.690402 -0.71254 -0.352076 -0.041325 -0.935059 -0.151259 0.200554 -0.967935 -0.234784 0.072102 -0.96937 0.335342 0.938623 -0.080824 -0.181497 -0.314485 -0.93175 -0.181369 -0.246131 -0.952116 -0.216352 -0.296087 -0.930336 0.063528 -0.453519 -0.888979 0.988906 -0.143524 0.038289 -0.204613 -0.971124 -0.122689 -0.058968 -0.555214 -0.829614 -0.161566 -0.608928 -0.776597 -0.284125 -0.727539 -0.624468 0.487899 -0.783648 -0.384513 0.727346 -0.686271 0.000424 0.656623 -0.754219 0 0.683707 -0.729756 0 0.024911 0.648871 -0.760491 0.396987 0.67921 -0.617313 0.604959 0.492678 -0.625535 0.162856 0.009652 -0.986603 -0.913077 -0.093294 -0.396971 -0.452602 -0.783538 -0.425699 0.01674 0.948197 0.317241 -0.477151 0.683223 -0.55275 0.489833 -0.094216 0.86671 0.559917 -0.66163 0.498737 -0.607091 -0.148271 -0.780677 -0.213606 -0.922061 -0.322764 0.202216 0.979178 -0.017837 -0.02866 0.569881 -0.821227 0.468919 0.479799 0.741558 0.524966 -0.529853 0.666083 0.014497 -0.425666 -0.904764 0.449791 -0.889485 -0.080652 0.700646 0.496146 -0.512771 0.052738 -0.012788 -0.998527 0.857724 0.252714 0.44771 0.254126 -0.238897 0.937202 -0.161138 -0.46972 -0.867985 -0.799048 -0.597824 0.064262 0.752699 -0.307481 -0.582151 0.016912 -0.100619 -0.994781 0.82225 -0.366813 0.435147 0.175473 0.14535 0.973695 -0.524694 0.240885 -0.816499 -0.690488 0.699754 0.183225 0.459618 -0.714649 -0.527283 -0.117647 -0.268346 -0.956112 0.627633 -0.455639 0.631245 0.118693 0.159233 0.98008 -0.574643 0.361038 -0.734463 -0.500235 0.635224 0.588435 0.371119 -0.756739 -0.538161 -0.067704 -0.308406 -0.948842 0.58804 -0.512878 0.625432 0.138143 0.172715 0.975236 -0.492345 0.443881 -0.74871 -0.439087 0.717935 0.540159 0.521185 -0.569577 -0.635569 -0.034473 0.125244 -0.991527 0.863399 -0.491989 0.11175 0.394897 0.183599 0.900193 -0.396976 0.759409 -0.515468 -0.204228 0.809901 0.549865 0.761651 0.594689 -0.257358 -0.031475 0.601381 -0.798342 0.92541 0.378091 0.02577 0.561192 0.069755 0.824741 -0.72615 0.475108 -0.496969 -0.734338 0.33702 0.589208 0.668467 0.74373 0.004159 0.037098 0.765901 -0.641887 0.763351 0.626641 -0.156895 0.750266 0.335599 0.569626 -0.421931 -0.468084 -0.776448 -0.844026 -0.469524 -0.259165 -0.766459 -0.486919 0.418868 -0.059291 -0.689606 0.721753 -0.267195 -0.374391 -0.88794 0.349835 -0.831706 0.431138 -0.328921 -0.943832 0.031493 -0.560808 -0.825324 0.065839 0.075668 -0.867345 -0.491922 0.695889 -0.405012 -0.593047 0.789058 -0.367521 -0.492256 0.118197 0.99299 0 0.029257 0.999572 0 0.022786 0.585812 -0.810126 0.02576 0.999668 0 0.232893 0.617869 -0.750999 0.104646 0.99451 0 0.111908 0.764994 -0.63424 0.413662 0.91043 0 0.368233 0.795185 -0.481752 0.590894 0.806749 0 0.49252 0.764298 -0.416261 0.833486 0.55254 0 0.815752 0.441381 -0.373807 0.985491 0.16973 0 0.894805 0.109397 -0.432846 0.997713 -0.067598 0 0.88159 -0.084706 -0.464354 0.962805 -0.270197 0 0.562304 -0.247991 -0.788869 -0.05172 -0.751783 -0.657379 0.000201 -1 0 -0.356051 -0.934466 0 0.536673 -0.791113 0.293466 0.988537 -0.107662 -0.105849 -0.162148 0.619895 -0.767749 -0.95648 0.052388 -0.287057 0.531929 0.339036 -0.775955 0.945364 -0.058698 -0.32069 0.481767 0.116366 -0.868539 -0.295403 0.416429 -0.85984 0.857633 -0.390921 -0.334137 -0.976716 0.214038 -0.014616 -0.598989 -0.648066 0.470343 0.274172 -0.723051 0.634056 0.368131 -0.061468 -0.92774 -0.404425 0.296384 -0.865215 0.859299 -0.420319 -0.291438 -0.710331 0.703856 0.004068 -0.416905 -0.127711 0.899933 0.49042 -0.801963 0.34109 0.32735 0.06743 -0.942494 0.045845 0.389365 -0.919942 0.645471 -0.5029 -0.574855 -0.589922 0.80218 0.092194 -0.444411 0.22876 0.866122 0.510739 -0.59996 0.615787 0.045279 -0.026753 -0.998616 -0.411493 0.662227 -0.626202 0.458666 -0.414417 -0.786056 -0.927111 0.374433 -0.01626 -0.538897 0.197364 -0.818925 -0.976711 -0.202454 -0.071051 -0.423002 -0.358106 -0.832364 -0.855572 -0.027583 0.516948 -0.261409 0.078226 0.962053 0.788202 0.06098 0.612388 0.123634 -0.280844 -0.951757 -0.810917 -0.339284 -0.476759 0.810781 -0.228702 -0.538822 -0.870677 -0.015814 0.4916 -0.093341 0.100575 0.990541 0.783567 0.123221 0.608965 0.284134 0.094254 -0.95414 -0.785894 -0.085417 -0.612433 0.887101 0.095528 -0.451582 -0.927229 -0.092829 0.362807 -0.184349 0.034536 0.982254 0.740635 0.028996 0.671282 0.377329 0.1855 -0.907311 -0.710498 -0.129224 -0.691733 0.970597 0.133761 -0.200122 -0.810389 -0.567261 0.146578 -0.567582 -0.557926 0.60545 0.348899 0.421357 0.837095 0.253331 0.218497 -0.942381 -0.646871 -0.485853 -0.587797 0.845312 0.533642 -0.025938 0.289814 -0.955286 -0.058619 -0.100411 -0.40308 0.909639 0.267295 0.575354 0.772995 0.236117 0.526238 -0.816898 -0.301272 -0.651979 -0.695815 0.666865 0.74462 0.028841 0.54555 0.573956 -0.610696 0.0768 -0.611765 -0.787302 -0.203929 -0.766999 0.60838 0.777184 0.498571 0.383942 0.133368 -0.750267 -0.647543 -0.217023 -0.626621 0.748497 0.514176 0.629662 0.582365 0.801553 0.376284 -0.464675 0.751849 -0.626234 0.206284 0.780989 -0.462282 0.419942 0.365181 0.51535 -0.775279 0.705932 0.288136 -0.647022 0.262655 0.247148 -0.932701 0.722702 0.035726 -0.690236 0.047851 0.045363 -0.997824 0.162996 -0.359637 -0.918746 0.502253 -0.606735 -0.61613 0.927098 -0.374818 0 0.769904 -0.410954 -0.488227 0.180715 -0.818684 -0.545068 0.649747 -0.76015 0 0.392829 -0.919612 0 0.827651 -0.561243 0 -0.292352 0.707466 -0.643445 -0.292352 0.707466 -0.643445 -0.292352 0.707466 -0.643445 -0.041172 0.023484 -0.998876 -0.041172 0.023484 -0.998876 -0.041172 0.023484 -0.998876 0.108915 -0.942839 -0.314949 0.108915 -0.942839 -0.314949 0.108915 -0.942839 -0.314949 0.071361 -0.881071 -0.467569 0.071361 -0.881071 -0.467569 0.071361 -0.881071 -0.467569 -0.264114 0.504294 -0.82215 -0.264114 0.504294 -0.82215 -0.264114 0.504294 -0.82215 -0.026624 0.553819 -0.832211 -0.026624 0.553819 -0.832211 -0.026624 0.553819 -0.832211 -0.024223 0.541908 -0.840088 -0.024223 0.541908 -0.840088 -0.024223 0.541908 -0.840088 -0.047534 -0.943685 -0.327412 -0.047534 -0.943685 -0.327412 -0.047534 -0.943685 -0.327412 -0.048622 -0.940296 -0.336867 -0.048622 -0.940296 -0.336867 -0.048622 -0.940296 -0.336867 0.092241 0.560524 -0.822985 0.092241 0.560524 -0.822985 0.092241 0.560524 -0.822985 -0.263992 -0.901329 -0.343386 -0.263992 -0.901329 -0.343386 -0.263992 -0.901329 -0.343386 -0.6813 -0.246224 -0.68935 -0.6813 -0.246224 -0.68935 -0.6813 -0.246224 -0.68935 -0.009776 0.064877 -0.997845 -0.009776 0.064877 -0.997845 -0.009776 0.064877 -0.997845 0.702004 0.636654 -0.319157 0.702004 0.636654 -0.319157 0.702004 0.636654 -0.319157 0.615348 0.606492 -0.503502 0.615348 0.606492 -0.503502 0.615348 0.606492 -0.503502 -0.568631 -0.141655 -0.810304 -0.568631 -0.141655 -0.810304 -0.568631 -0.141655 -0.810304 -0.391327 -0.36142 -0.846309 -0.391327 -0.36142 -0.846309 -0.391327 -0.36142 -0.846309 -0.388712 -0.359781 -0.84821 -0.388712 -0.359781 -0.84821 -0.388712 -0.359781 -0.84821 0.60435 0.721866 -0.337151 0.60435 0.721865 -0.337151 0.60435 0.721866 -0.337151 0.603477 0.721455 -0.339585 0.603477 0.721455 -0.339586 0.603477 0.721455 -0.339585 -0.242237 -0.500473 -0.831173 -0.242237 -0.500473 -0.831173 -0.242237 -0.500473 -0.831173 0.308904 0.879502 -0.362015 0.308904 0.879502 -0.362015 0.308904 0.879502 -0.362015 -0.669319 -0.359933 -0.649969 -0.669319 -0.359933 -0.649969 -0.669319 -0.359933 -0.649969 0.023854 0.437621 -0.898843 0.023854 0.437621 -0.898843 0.023854 0.437621 -0.898843 0.442743 0.833286 -0.331079 0.442743 0.833286 -0.331079 0.442743 0.833286 -0.331079 0.489285 0.841257 -0.229971 0.489285 0.841257 -0.229971 0.489285 0.841257 -0.229971 -0.560374 0.002904 -0.828234 -0.560374 0.002904 -0.828234 -0.560374 0.002904 -0.828234 -0.379031 -0.390276 -0.839059 -0.379031 -0.390276 -0.839059 -0.379031 -0.390276 -0.839059 -0.18769 -0.247335 -0.950578 -0.18769 -0.247335 -0.950578 -0.18769 -0.247335 -0.950578 0.38946 0.857117 -0.337152 0.38946 0.857117 -0.337152 0.38946 0.857117 -0.337152 0.388729 0.856488 -0.339586 0.388729 0.856488 -0.339586 0.388729 0.856488 -0.339586 -0.099681 -0.547006 -0.831173 -0.099681 -0.547006 -0.831173 -0.099681 -0.547006 -0.831173 0.062632 0.930066 -0.362014 0.062632 0.930066 -0.362014 0.062632 0.930066 -0.362014 0.029179 0.844324 0.535038 0.102833 0.782531 0.614061 -0.043653 0.675701 0.735882 -0.239517 0.413786 0.878301 -0.515652 0.569872 0.639804 -0.613385 0.469875 0.634804 -0.973292 -0.023675 0.228346 -0.162091 -0.886156 0.434113 0.020066 -0.869195 0.494062 0.130125 -0.991362 0.016379 0.715591 -0.675729 0.176976 0.582107 -0.555438 0.593835 -0.11244 -0.559395 0.82124 -0.041094 0.554449 0.831203 -0.649077 0.588422 0.482139 -0.308706 0.30649 0.900425 -0.199852 0.152187 0.967935 -0.352075 -0.041325 0.935059 0.125028 0.690402 0.71254 -0.151259 0.200554 0.967935 -0.234784 0.072102 0.96937 0.335342 0.938623 0.080824 -0.181368 -0.24613 0.952116 -0.181496 -0.314485 0.93175 -0.216352 -0.296087 0.930336 0.988906 -0.143524 -0.038289 0.063528 -0.453519 0.888979 -0.058967 -0.555214 0.829614 -0.204613 -0.971124 0.122689 -0.161566 -0.608928 0.776597 -0.284125 -0.727539 0.624468 0.727346 -0.686271 -0.000425 0.487899 -0.783648 0.384513 0.396987 0.67921 0.617313 0.024911 0.648871 0.760491 0.604959 0.492678 0.625534 0.162856 0.009652 0.986603 -0.913077 -0.093294 0.396972 -0.452602 -0.783538 0.425699 -0.477151 0.683223 0.55275 0.01674 0.948197 -0.317241 0.489833 -0.094216 -0.86671 0.559917 -0.66163 -0.498737 -0.607091 -0.148271 0.780677 -0.213606 -0.922061 0.322764 -0.028659 0.569881 0.821227 0.202216 0.979178 0.017837 0.468918 0.4798 -0.741558 0.524965 -0.529853 -0.666084 0.014498 -0.425666 0.904764 0.449791 -0.889485 0.080652 0.052738 -0.012788 0.998527 0.700647 0.496146 0.512771 0.857724 0.252714 -0.44771 0.254126 -0.238897 -0.937202 -0.161138 -0.46972 0.867985 -0.799048 -0.597824 -0.064262 0.016913 -0.100619 0.994781 0.752699 -0.307481 0.582151 0.82225 -0.366813 -0.435147 0.175473 0.14535 -0.973695 -0.524693 0.240885 0.816499 -0.690488 0.699754 -0.183225 -0.117646 -0.268346 0.956112 0.459618 -0.714649 0.527283 0.627633 -0.455639 -0.631245 0.118693 0.159233 -0.98008 -0.574643 0.361038 0.734464 -0.500235 0.635224 -0.588435 -0.067704 -0.308406 0.948842 0.371119 -0.756738 0.538161 0.58804 -0.512878 -0.625432 0.138143 0.172714 -0.975237 -0.492345 0.443881 0.74871 -0.439087 0.717935 -0.540159 -0.034472 0.125244 0.991527 0.521185 -0.569577 0.635569 0.863399 -0.491989 -0.11175 0.394896 0.183599 -0.900194 -0.396976 0.759409 0.515468 -0.204228 0.809901 -0.549865 -0.031475 0.601381 0.798342 0.761651 0.594689 0.257358 0.92541 0.378091 -0.025771 0.561191 0.069755 -0.824741 -0.72615 0.475108 0.496969 -0.734338 0.33702 -0.589207 0.037099 0.765902 0.641887 0.668467 0.74373 -0.004159 0.763352 0.626641 0.156894 0.750266 0.335599 -0.569626 -0.844026 -0.469524 0.259166 -0.421931 -0.468084 0.776448 -0.766459 -0.486918 -0.418868 -0.059292 -0.689606 -0.721753 -0.267195 -0.374391 0.88794 0.349835 -0.831706 -0.431138 -0.560809 -0.825323 -0.065839 -0.328921 -0.943832 -0.031493 0.075668 -0.867345 0.491922 0.695889 -0.405012 0.593047 0.789058 -0.367521 0.492256 0.022787 0.585812 0.810126 0.232893 0.617869 0.750999 0.111908 0.764994 0.63424 0.368233 0.795185 0.481752 0.492521 0.764298 0.41626 0.815752 0.441381 0.373807 0.894805 0.109397 0.432846 0.88159 -0.084706 0.464353 0.562305 -0.247991 0.788869 -0.05172 -0.751784 0.657378 0.988537 -0.107662 0.105849 0.536673 -0.791113 -0.293466 -0.95648 0.052388 0.287058 -0.162148 0.619895 0.767749 0.531929 0.339036 0.775955 0.945364 -0.058698 0.32069 -0.295403 0.416429 0.85984 0.481767 0.116366 0.868539 0.857633 -0.390921 0.334136 -0.59899 -0.648066 -0.470342 -0.976716 0.214038 0.014616 0.274172 -0.723051 -0.634056 -0.404425 0.296384 0.865215 0.368131 -0.061468 0.92774 0.8593 -0.420319 0.291438 -0.416906 -0.127711 -0.899933 -0.710332 0.703855 -0.004068 0.49042 -0.801963 -0.34109 0.045845 0.389365 0.919942 0.327351 0.06743 0.942494 0.645471 -0.5029 0.574855 -0.444411 0.22876 -0.866122 -0.589922 0.80218 -0.092194 0.510739 -0.59996 -0.615787 -0.411492 0.662227 0.626202 0.045279 -0.026753 0.998616 0.458666 -0.414417 0.786056 -0.927111 0.374433 0.01626 -0.538896 0.197364 0.818925 -0.976711 -0.202454 0.071052 -0.423002 -0.358106 0.832364 -0.261409 0.078226 -0.962053 -0.855572 -0.027583 -0.516948 0.788202 0.06098 -0.612388 -0.810917 -0.339284 0.476759 0.123634 -0.280844 0.951757 0.810781 -0.228702 0.538822 -0.093341 0.100575 -0.990541 -0.870678 -0.015814 -0.4916 0.783567 0.123221 -0.608966 -0.785894 -0.085417 0.612433 0.284135 0.094254 0.95414 0.887101 0.095528 0.451582 -0.18435 0.034536 -0.982254 -0.927229 -0.092829 -0.362806 0.740635 0.028996 -0.671282 -0.710498 -0.129224 0.691733 0.377329 0.1855 0.907311 0.970597 0.133761 0.200122 -0.567582 -0.557926 -0.60545 -0.810389 -0.567261 -0.146578 0.348899 0.421357 -0.837095 -0.646871 -0.485853 0.587797 0.253332 0.218497 0.942381 0.845312 0.533642 0.025938 -0.100412 -0.40308 -0.909639 0.289814 -0.955286 0.058619 0.267295 0.575354 -0.772995 -0.301271 -0.651979 0.695815 0.236117 0.526238 0.816898 0.666866 0.74462 -0.028841 0.0768 -0.611765 0.787303 0.54555 0.573956 0.610696 -0.203929 -0.766999 -0.608379 0.777184 0.498571 -0.383943 -0.217023 -0.626621 -0.748497 0.133368 -0.750267 0.647543 0.514176 0.629662 -0.582365 0.801553 0.376284 0.464675 0.751849 -0.626234 -0.206285 0.780989 -0.462282 -0.419942 0.365182 0.51535 0.775279 0.705932 0.288136 0.647022 0.262655 0.247148 0.9327 0.722702 0.035726 0.690236 0.047851 0.045363 0.997824 0.162997 -0.359637 0.918745 0.502253 -0.606735 0.616129 0.769904 -0.410954 0.488226 0.180715 -0.818684 0.545068 -0.292352 0.707466 0.643445 -0.292352 0.707466 0.643445 -0.292352 0.707466 0.643445 -0.041171 0.023484 0.998876 -0.041171 0.023484 0.998876 -0.041171 0.023484 0.998876 0.071362 -0.881071 0.467569 0.071362 -0.881071 0.467569 0.071362 -0.881071 0.467569 0.108915 -0.942839 0.314949 0.108915 -0.942839 0.314949 0.108915 -0.942839 0.314949 -0.264114 0.504295 0.82215 -0.264114 0.504295 0.82215 -0.264114 0.504295 0.82215 -0.024223 0.541908 0.840088 -0.024223 0.541908 0.840088 -0.024223 0.541908 0.840088 -0.026624 0.553819 0.832211 -0.026624 0.553819 0.832211 -0.026624 0.553819 0.832211 -0.048622 -0.940296 0.336868 -0.048622 -0.940296 0.336868 -0.048622 -0.940296 0.336868 -0.047534 -0.943685 0.327413 -0.047534 -0.943685 0.327413 -0.047534 -0.943685 0.327413 0.092241 0.560524 0.822985 0.092241 0.560524 0.822985 0.092241 0.560524 0.822985 -0.263992 -0.901329 0.343387 -0.263992 -0.901329 0.343387 -0.263992 -0.901329 0.343387 -0.6813 -0.246224 0.689351 -0.6813 -0.246224 0.689351 -0.6813 -0.246224 0.689351 -0.009776 0.064877 0.997845 -0.009776 0.064877 0.997845 -0.009776 0.064877 0.997845 0.615348 0.606492 0.503502 0.615348 0.606492 0.503502 0.615348 0.606492 0.503502 0.702005 0.636654 0.319157 0.702005 0.636654 0.319157 0.702005 0.636654 0.319157 -0.568631 -0.141655 0.810304 -0.568631 -0.141655 0.810304 -0.568631 -0.141655 0.810304 -0.388712 -0.359781 0.84821 -0.388712 -0.35978 0.84821 -0.388712 -0.359781 0.84821 -0.391327 -0.36142 0.846309 -0.391327 -0.36142 0.846309 -0.391327 -0.36142 0.846309 0.603477 0.721455 0.339585 0.603477 0.721455 0.339585 0.603477 0.721455 0.339585 0.604351 0.721866 0.33715 0.604351 0.721866 0.33715 0.604351 0.721866 0.33715 -0.242236 -0.500473 0.831173 -0.242236 -0.500473 0.831173 -0.242236 -0.500473 0.831173 0.308904 0.879502 0.362014 0.308904 0.879502 0.362015 0.308904 0.879502 0.362014 -0.669319 -0.359933 0.649969 -0.669319 -0.359933 0.649969 -0.669319 -0.359933 0.649969 0.023854 0.437621 0.898843 0.023854 0.437621 0.898843 0.023854 0.437621 0.898843 0.489285 0.841257 0.229971 0.489285 0.841257 0.229971 0.489285 0.841257 0.229971 0.442743 0.833286 0.331079 0.442743 0.833286 0.331079 0.442743 0.833286 0.331079 -0.560374 0.002904 0.828235 -0.560374 0.002904 0.828235 -0.560374 0.002904 0.828235 -0.18769 -0.247335 0.950578 -0.18769 -0.247335 0.950578 -0.18769 -0.247335 0.950578 -0.379031 -0.390276 0.839059 -0.379031 -0.390276 0.839059 -0.379031 -0.390276 0.839059 0.388729 0.856488 0.339586 0.388729 0.856488 0.339586 0.388729 0.856488 0.339586 0.38946 0.857117 0.337152 0.38946 0.857117 0.337152 0.38946 0.857117 0.337152 -0.099681 -0.547006 0.831173 -0.099681 -0.547006 0.831173 -0.099681 -0.547006 0.831173 0.062632 0.930066 0.362014 0.062632 0.930066 0.362014 0.062632 0.930066 0.362014 - - - - - - - - - - 0.962784 0.866402 0 0.583128 0.726301 0 0.923308 0.588463 0 0.973629 0.760334 0 0.639541 0.971205 0 0.578281 0.933704 0 0.614465 0.016612 0 0.546194 0.262742 0 0.485925 0.707573 0 0.578416 0.872235 0 0.470091 0.880271 0 0.535292 0.711183 0 0.844364 0.849396 0 0.569421 0.944076 0 0.543766 0.730233 0 0.544676 0.870113 0 0.17266 0.671736 0 0.578136 0.935014 0 0.544676 0.944076 0 0.544657 1.07435 0 0.574784 1.00872 0 0.702368 0.964054 0 0.695298 1.00029 0 0.719196 0.92305 0 0.327975 0.680936 0 0.43552 0.530898 0 0.955225 0.245711 0 0.876244 0.746004 0 0.665732 0.771818 0 0.806397 0.735338 0 0.830273 0.583834 0 0.999804 0.85969 0 0.481328 0.480665 0 1.00961 0.758254 0 0.900051 0.277794 0 0.822883 0.938297 0 0.544955 0.94251 0 0.999872 0.590502 0 0.664421 0.716363 0 0.345981 0.707237 0 0.990788 0.255074 0 0.623358 0.26966 0 0.889906 1.05621 0 0.619832 0.766915 0 0.103354 0.568994 0 0.561191 0.146745 0 0.059019 0.624972 0 0.98943 0.533708 0 0.171278 0.631178 0 0.018508 0.625875 0 0.119768 0.574235 0 0.925102 0.53486 0 0.808588 0.152373 0 0.944427 1.03996 0 0.04047 0.564014 0 0.076293 0.026207 0 0.694668 0.034553 0 0.64989 0.185302 0 0.007998 0.565638 0 0.17828 0.573249 0 0.100071 0.525136 0 0.061839 0.017624 0 0.054439 0.393873 0 0.01726 0.411876 0 0.13395 0.543025 0 0.147377 0.017258 0 0.109435 0.407175 0 0.168444 0.422601 0 0.082239 0.585859 0 0.083261 0.350563 0 0.128772 0.028096 0 0.10986 0.046666 0 0.059814 0.350367 0 0.109052 0.032651 0 0.020009 0.288403 0 0.134381 0.412129 0 0.08929 0.299414 0 0.068083 0.284812 0 0.037583 0.255997 0 0.093035 0.191972 0 0.816219 0.162296 0 0.074875 0.189623 0 0.821108 0.139743 0 0.117208 0.352476 0 0.072024 0.550338 0 0.042031 0.184351 0 0.018135 0.390216 0 0.091051 0.163065 0 0.83619 0.138042 0 0.074147 0.162276 0 0.046524 0.161024 0 0.090196 0.046402 0 0.165692 0.382352 0 0.069845 0.041596 0 0.048628 0.032148 0 0.081328 0.399383 0 0.850399 0.149705 0 0.189189 0.263215 0 0.173021 0.310752 0 0.092243 0.030976 0 0.118763 0.299379 0 0.820609 0.171902 0 0.184472 0.223738 0 0.761768 0.144156 0 0.149551 0.266959 0 0.119026 0.190482 0 0.763978 0.165249 0 0.191499 0.175516 0 0.759334 0.111927 0 0.133114 0.383455 0 0.767633 0.194778 0 0.823329 0.122775 0 0.336258 0.895252 0 0.49138 0.768682 0 0.048411 0.971525 0 0.299564 0.885719 0 0.535291 0.767474 0 0.066625 0.943753 0 0.059622 0.904161 0 0.140189 0.904272 0 0.220301 0.943949 0 0.015975 0.920104 0 0.272714 0.887733 0 0.306058 0.823958 0 0.444887 0.023449 0 0.271858 0.796445 0 0.281234 0.684748 0 0.143139 0.943818 0 0.872078 1.02241 0 0.944307 1.02136 0 0.498597 0.465378 0 0.857712 0.208364 0 0.861609 0.528566 0 0.43883 0.483159 0 0.390368 0.496396 0 0.355144 0.498411 0 0.424905 0.452876 0 0.901455 0.929362 0 0.466278 0.452819 0 0.38269 0.452852 0 0.353532 0.452741 0 0.495352 0.425566 0 0.425441 0.429923 0 0.85602 0.12419 0 0.467616 0.429323 0 0.383581 0.43021 0 0.352785 0.430126 0 0.480747 0.36765 0 0.425788 0.386988 0 0.115762 0.161077 0 0.458655 0.381282 0 0.386601 0.385787 0 0.352463 0.38645 0 0.426213 0.276565 0 0.525389 0.426199 0 0.452097 0.277162 0 0.395551 0.254818 0 0.307539 0.429436 0 0.424053 0.252445 0 0.355574 0.532811 0 0.518706 0.377766 0 0.424481 0.228688 0 0.311691 0.486922 0 0.372681 0.259599 0 0.468408 0.170887 0 0.420099 0.167494 0 0.142431 0.184566 0 0.443729 0.177923 0 0.398362 0.17256 0 0.366507 0.175923 0 0.468301 0.130222 0 0.420201 0.135986 0 0.447186 0.135116 0 0.394908 0.132843 0 0.366665 0.132716 0 0.874248 0.148212 0 0.836193 0.178142 0 0.393266 0.02361 0 0.450943 0.252896 0 0.470187 0.251428 0 0.487567 0.02342 0 0.494297 0.259853 0 0.419099 0.023516 0 0.764111 0.106345 0 0.747216 0.057278 0 0.745955 0.047849 0 0.454064 0.233216 0 0.277895 0.186311 0 0.365947 0.023552 0 0.773142 0.205943 0 0.218203 0.141785 0 0.305377 0.14531 0 0.307123 0.452819 0 0.506168 0.175971 0 0.228754 0.130617 0 0.298254 0.139336 0 0.27503 0.129408 0 0.303952 0.33283 0 0.2175 0.092834 0 0.308074 0.093333 0 0.223809 0.086314 0 0.171844 0.158273 0 0.312833 0.382997 0 0.298173 0.095033 0 0.265315 0.085124 0 0.221113 0.34225 0 0.256632 0.333274 0 0.219332 0.968288 0 0.535293 0.811778 0 0.744987 0.811333 0 0.21829 0.904272 0 0.257353 0.904272 0 0.998792 0.935718 0 0.258839 0.944008 0 0.308133 0.708452 0 0.751067 0.152923 0 0.137365 0.160481 0 0.1581 0.026756 0 0.129344 0.041868 0 0.719806 0.123073 0 0.817913 0.078355 0 0.850528 0.07572 0 0.863947 0.063391 0 0.827316 0.032192 0 0.524012 0.451625 0 0.75935 0.096986 0 0.306575 0.283944 0 0.216051 0.280892 0 0.313512 0.043518 0 0.307051 0.043456 0 0.288932 0.042926 0 0.219131 0.043497 0 0.22544 0.043351 0 0.257004 0.043103 0 0.277286 0.377005 0 0.212571 0.230901 0 0.251519 0.384615 0 0.306881 0.234582 0 0.274451 0.233457 0 0.265695 0.066563 0 0.279992 0.040425 0 0.228067 0.196717 0 0.246636 0.043336 0 0.284462 0.198932 0 0.265081 0.383774 0 0.241347 0.176108 0 0.251287 0.171757 0 0.304875 0.008743 0 0.241282 0.008651 0 0.738336 0.706143 0 0.753901 0.557172 0 0.898392 0.109669 0 0.810355 0.297383 0 0.79827 0.23533 0 0.774226 0.494899 0 0.928004 0.983475 0 0.658668 0.513945 0 0.410048 0.894312 0 0.851496 0.06373 0 0.25951 0.281465 0 0.23771 0.231882 0 0.274277 0.17648 0 0.266225 0.170548 0 0.823356 0.055431 0 0.761324 0.050302 0 0.72698 0.179734 0 0.763464 0.009524 0 0.722307 0.08339 0 0.048617 0.009016 0 0.726536 0.027387 0 0.143139 0.991613 0 0.545984 0.501975 0 0.484707 0.816075 0 0.410603 0.82875 0 0.339548 0.833001 0 0.25742 0.008359 0 0.641377 0.426971 0 0.585143 0.501975 0 0.31072 0.782123 0 0.406331 0.772705 0 0.284372 0.008739 0 0.466048 0.023594 0 0.005086 0.254863 0 0.345934 0.023431 0 0.545984 0.428925 0 0.34492 0.261864 0 0.328404 0.173807 0 0.343549 0.131914 0 0.009299 0.22189 0 0.488162 0.133117 0 0.007033 0.179281 0 0.022816 0.155181 0 0.031713 0.024413 0 0.512305 0.877819 0 0.717761 0.852229 0 0.275358 0.814772 0 0.404126 0.706528 0 0.272662 0.715083 0 0.27192 0.790182 0 0.294127 0.778786 0 0.298594 0.746622 0 0.298021 0.715452 0 0.272235 0.753129 0 0.272068 0.777754 0 0.272573 0.730976 0 0.595381 0.757602 0 0.668625 0.570157 0 0.217473 0.626803 0 0.22842 0.568621 0 0.193249 0.42238 0 0.180933 0.372708 0 0.69228 0.57361 0 0.64882 0.563563 0 0.70406 0.370244 0 0.067915 0.644775 0 0.020421 0.641024 0 0.945406 0.109621 0 0.973417 0.109587 0 0.221123 0.635583 0 0.224895 0.649831 0 0.687854 0.987229 0 0.329589 0.742049 0 0.687854 0.987229 0 0.639541 0.971205 0 0.665732 0.771818 0 0.578281 0.933704 0 0.619832 0.766915 0 0.578136 0.935014 0 0.544955 0.94251 0 0.595381 0.757602 0 0.668625 0.570157 0 0.69228 0.57361 0 0.64882 0.563563 0 0.70406 0.370244 0 0.639541 0.971205 0 0.687854 0.987229 0 0.665732 0.771818 0 0.578281 0.933704 0 0.619832 0.766915 0 0.544955 0.94251 0 0.578136 0.935014 0 0.595381 0.757602 0 0.668625 0.570157 0 0.69228 0.57361 0 0.64882 0.563563 0 0.70406 0.370244 0 0.962784 0.866402 0 0.583128 0.726301 0 0.923308 0.588463 0 0.973629 0.760334 0 0.639541 0.971205 0 0.578281 0.933704 0 0.614465 0.016612 0 0.546194 0.262742 0 0.485925 0.707573 0 0.578416 0.872235 0 0.470091 0.880271 0 0.535292 0.711183 0 0.844364 0.849396 0 0.569421 0.944076 0 0.543766 0.730233 0 0.544676 0.870113 0 0.17266 0.671736 0 0.578136 0.935014 0 0.544676 0.944076 0 0.544657 1.07435 0 0.574784 1.00872 0 0.702368 0.964054 0 0.695298 1.00029 0 0.719196 0.92305 0 0.327975 0.680936 0 0.43552 0.530898 0 0.955225 0.245711 0 0.876244 0.746004 0 0.665732 0.771818 0 0.806397 0.735338 0 0.830273 0.583834 0 0.999804 0.85969 0 0.481328 0.480665 0 1.00961 0.758254 0 0.900051 0.277794 0 0.822883 0.938297 0 0.544955 0.94251 0 0.999872 0.590502 0 0.664421 0.716363 0 0.345981 0.707237 0 0.990788 0.255074 0 0.623358 0.26966 0 0.889906 1.05621 0 0.619832 0.766915 0 0.103354 0.568994 0 0.561191 0.146745 0 0.059019 0.624972 0 0.98943 0.533708 0 0.171278 0.631178 0 0.018508 0.625875 0 0.119768 0.574235 0 0.925102 0.53486 0 0.808588 0.152373 0 0.944427 1.03996 0 0.04047 0.564014 0 0.076293 0.026207 0 0.694668 0.034553 0 0.64989 0.185302 0 0.007998 0.565638 0 0.17828 0.573249 0 0.100071 0.525136 0 0.061839 0.017624 0 0.054439 0.393873 0 0.01726 0.411876 0 0.13395 0.543025 0 0.147377 0.017258 0 0.109435 0.407175 0 0.168444 0.422601 0 0.082239 0.585859 0 0.083261 0.350563 0 0.128772 0.028096 0 0.10986 0.046666 0 0.059814 0.350367 0 0.109052 0.032651 0 0.020009 0.288403 0 0.134381 0.412129 0 0.08929 0.299414 0 0.068083 0.284812 0 0.037583 0.255997 0 0.093035 0.191972 0 0.816219 0.162296 0 0.074875 0.189623 0 0.821108 0.139743 0 0.117208 0.352476 0 0.072024 0.550338 0 0.042031 0.184351 0 0.018135 0.390216 0 0.091051 0.163065 0 0.83619 0.138042 0 0.074147 0.162276 0 0.046524 0.161024 0 0.090196 0.046402 0 0.165692 0.382352 0 0.069845 0.041596 0 0.048628 0.032148 0 0.081328 0.399383 0 0.850399 0.149705 0 0.189189 0.263215 0 0.173021 0.310752 0 0.092243 0.030976 0 0.118763 0.299379 0 0.820609 0.171902 0 0.184472 0.223738 0 0.761768 0.144156 0 0.149551 0.266959 0 0.119026 0.190482 0 0.763978 0.165249 0 0.191499 0.175516 0 0.759334 0.111927 0 0.133114 0.383455 0 0.767633 0.194778 0 0.823329 0.122775 0 0.336258 0.895252 0 0.49138 0.768682 0 0.048411 0.971525 0 0.299564 0.885719 0 0.535291 0.767474 0 0.066625 0.943753 0 0.059622 0.904161 0 0.140189 0.904272 0 0.220301 0.943949 0 0.015975 0.920104 0 0.272714 0.887733 0 0.306058 0.823958 0 0.444887 0.023449 0 0.271858 0.796445 0 0.281234 0.684748 0 0.143139 0.943818 0 0.872078 1.02241 0 0.944307 1.02136 0 0.498597 0.465378 0 0.857712 0.208364 0 0.861609 0.528566 0 0.43883 0.483159 0 0.390368 0.496396 0 0.355144 0.498411 0 0.424905 0.452876 0 0.901455 0.929362 0 0.466278 0.452819 0 0.38269 0.452852 0 0.353532 0.452741 0 0.495352 0.425566 0 0.425441 0.429923 0 0.85602 0.12419 0 0.467616 0.429323 0 0.383581 0.43021 0 0.352785 0.430126 0 0.480747 0.36765 0 0.425788 0.386988 0 0.115762 0.161077 0 0.458655 0.381282 0 0.386601 0.385787 0 0.352463 0.38645 0 0.426213 0.276565 0 0.525389 0.426199 0 0.452097 0.277162 0 0.395551 0.254818 0 0.307539 0.429436 0 0.424053 0.252445 0 0.355574 0.532811 0 0.518706 0.377766 0 0.424481 0.228688 0 0.311691 0.486922 0 0.372681 0.259599 0 0.468408 0.170887 0 0.420099 0.167494 0 0.142431 0.184566 0 0.443729 0.177923 0 0.398362 0.17256 0 0.366507 0.175923 0 0.468301 0.130222 0 0.420201 0.135986 0 0.447186 0.135116 0 0.394908 0.132843 0 0.366665 0.132716 0 0.874248 0.148212 0 0.836193 0.178142 0 0.393266 0.02361 0 0.450943 0.252896 0 0.470187 0.251428 0 0.487567 0.02342 0 0.494297 0.259853 0 0.419099 0.023516 0 0.764111 0.106345 0 0.747216 0.057278 0 0.745955 0.047849 0 0.454064 0.233216 0 0.277895 0.186311 0 0.365947 0.023552 0 0.773142 0.205943 0 0.218203 0.141785 0 0.305377 0.14531 0 0.307123 0.452819 0 0.506168 0.175971 0 0.228754 0.130617 0 0.298254 0.139336 0 0.27503 0.129408 0 0.303952 0.33283 0 0.2175 0.092834 0 0.308074 0.093333 0 0.223809 0.086314 0 0.171844 0.158273 0 0.312833 0.382997 0 0.298173 0.095033 0 0.265315 0.085124 0 0.221113 0.34225 0 0.256632 0.333274 0 0.219332 0.968288 0 0.535293 0.811778 0 0.744987 0.811333 0 0.21829 0.904272 0 0.257353 0.904272 0 0.998792 0.935718 0 0.258839 0.944008 0 0.308133 0.708452 0 0.751067 0.152923 0 0.137365 0.160481 0 0.1581 0.026756 0 0.129344 0.041868 0 0.719806 0.123073 0 0.817913 0.078355 0 0.850528 0.07572 0 0.863947 0.063391 0 0.827316 0.032192 0 0.524012 0.451625 0 0.75935 0.096986 0 0.306575 0.283944 0 0.216051 0.280892 0 0.313512 0.043518 0 0.307051 0.043456 0 0.288932 0.042926 0 0.219131 0.043497 0 0.22544 0.043351 0 0.257004 0.043103 0 0.277286 0.377005 0 0.212571 0.230901 0 0.251519 0.384615 0 0.306881 0.234582 0 0.274451 0.233457 0 0.265695 0.066563 0 0.279992 0.040425 0 0.228067 0.196717 0 0.246636 0.043336 0 0.284462 0.198932 0 0.265081 0.383774 0 0.241347 0.176108 0 0.251287 0.171757 0 0.304875 0.008743 0 0.241282 0.008651 0 0.738336 0.706143 0 0.753901 0.557172 0 0.898392 0.109669 0 0.810355 0.297383 0 0.79827 0.23533 0 0.774226 0.494899 0 0.928004 0.983475 0 0.658668 0.513945 0 0.410048 0.894312 0 0.851496 0.06373 0 0.25951 0.281465 0 0.23771 0.231882 0 0.274277 0.17648 0 0.266225 0.170548 0 0.823356 0.055431 0 0.761324 0.050302 0 0.72698 0.179734 0 0.763464 0.009524 0 0.722307 0.08339 0 0.048617 0.009016 0 0.726536 0.027387 0 0.143139 0.991613 0 0.545984 0.501975 0 0.484707 0.816075 0 0.410603 0.82875 0 0.339548 0.833001 0 0.25742 0.008359 0 0.641377 0.426971 0 0.585143 0.501975 0 0.31072 0.782123 0 0.406331 0.772705 0 0.284372 0.008739 0 0.466048 0.023594 0 0.005086 0.254863 0 0.345934 0.023431 0 0.545984 0.428925 0 0.34492 0.261864 0 0.328404 0.173807 0 0.343549 0.131914 0 0.009299 0.22189 0 0.488162 0.133117 0 0.007033 0.179281 0 0.022816 0.155181 0 0.031713 0.024413 0 0.512305 0.877819 0 0.717761 0.852229 0 0.275358 0.814772 0 0.404126 0.706528 0 0.272662 0.715083 0 0.27192 0.790182 0 0.294127 0.778786 0 0.298594 0.746622 0 0.298021 0.715452 0 0.272235 0.753129 0 0.272068 0.777754 0 0.272573 0.730976 0 0.595381 0.757602 0 0.668625 0.570157 0 0.217473 0.626803 0 0.22842 0.568621 0 0.193249 0.42238 0 0.180933 0.372708 0 0.69228 0.57361 0 0.64882 0.563563 0 0.70406 0.370244 0 0.067915 0.644775 0 0.020421 0.641024 0 0.945406 0.109621 0 0.973417 0.109587 0 0.221123 0.635583 0 0.224895 0.649831 0 0.687854 0.987229 0 0.329589 0.742049 0 0.687854 0.987229 0 0.639541 0.971205 0 0.665732 0.771818 0 0.578281 0.933704 0 0.619832 0.766915 0 0.578136 0.935014 0 0.544955 0.94251 0 0.595381 0.757602 0 0.668625 0.570157 0 0.69228 0.57361 0 0.64882 0.563563 0 0.70406 0.370244 0 0.639541 0.971205 0 0.687854 0.987229 0 0.665732 0.771818 0 0.578281 0.933704 0 0.619832 0.766915 0 0.544955 0.94251 0 0.578136 0.935014 0 0.595381 0.757602 0 0.668625 0.570157 0 0.69228 0.57361 0 0.64882 0.563563 0 0.70406 0.370244 0 - - - - - - - - - - - - - - - -

203 0 33 420 1 31 0 2 0 0 2 0 1 3 3 203 0 33 11 4 37 203 0 33 1 3 3 1 3 3 2 5 2 11 4 37 16 6 51 3 7 26 12 8 40 12 8 40 239 9 47 16 6 51 13 10 317 12 8 40 3 7 26 3 7 26 4 11 316 13 10 317 14 12 319 5 13 318 6 14 16 35 15 284 33 16 277 15 17 271 204 18 14 15 17 271 33 16 277 33 16 277 8 19 1 204 18 14 421 20 15 204 18 14 8 19 1 8 19 1 9 21 9 421 20 15 422 22 18 421 20 15 9 21 9 9 21 9 10 23 13 422 22 18 423 24 19 422 22 18 10 23 13 10 23 13 37 25 20 423 24 19 205 26 53 423 24 42 37 25 128 37 25 128 116 27 129 205 26 53 1 3 3 0 2 0 17 28 27 2 5 2 1 3 3 17 28 27 4 11 316 3 7 26 18 29 34 18 29 34 38 30 251 4 11 316 3 7 26 16 6 51 18 29 34 19 31 29 17 28 27 117 32 12 117 32 12 23 33 209 19 31 29 20 34 30 2 5 2 17 28 27 17 28 27 19 31 29 20 34 30 16 6 51 2 5 2 20 34 30 20 34 30 22 35 132 16 6 51 38 30 251 18 29 34 21 36 131 18 29 34 16 6 51 22 35 132 20 34 30 19 31 29 24 37 249 24 37 249 25 38 250 20 34 30 22 35 132 20 34 30 25 38 250 25 38 250 28 39 254 22 35 132 21 36 131 18 29 34 26 40 252 26 40 252 27 41 253 21 36 131 18 29 34 22 35 132 28 39 254 28 39 254 26 40 252 18 29 34 24 37 249 23 33 209 119 42 294 119 42 294 29 43 38 24 37 249 25 38 250 24 37 249 29 43 38 29 43 38 30 44 256 25 38 250 28 39 254 25 38 250 30 44 256 30 44 256 32 45 276 28 39 254 27 41 253 26 40 252 31 46 41 31 46 41 41 47 57 27 41 253 26 40 252 28 39 254 32 45 276 32 45 276 31 46 41 26 40 252 8 19 1 29 43 38 119 42 294 119 42 294 9 21 9 8 19 1 30 44 256 29 43 38 8 19 1 8 19 1 33 16 277 30 44 256 32 45 276 30 44 256 33 16 277 33 16 277 35 15 284 32 45 276 41 47 57 31 46 41 7 48 7 7 48 7 34 49 45 41 47 57 31 46 41 32 45 276 35 15 284 35 15 284 7 48 7 31 46 41 0 2 0 105 50 212 36 51 137 120 52 35 199 53 255 37 25 128 5 13 315 4 11 314 38 30 46 38 30 46 39 54 49 5 13 315 6 14 16 5 13 318 39 54 307 39 54 307 40 55 48 6 14 16 34 49 45 6 14 6 40 55 56 40 55 56 41 47 57 34 49 45 38 30 46 21 36 68 42 56 84 42 56 84 44 57 54 38 30 46 21 36 68 27 41 44 43 58 60 43 58 60 42 56 84 21 36 68 27 41 44 41 47 50 47 59 64 47 59 64 43 58 60 27 41 44 39 54 49 38 30 46 44 57 54 44 57 54 45 60 58 39 54 49 40 55 48 39 54 307 45 60 308 45 60 308 46 61 59 40 55 48 41 47 50 40 55 48 46 61 59 46 61 59 47 59 64 41 47 50 44 57 54 42 56 84 48 62 95 48 62 95 50 63 62 44 57 54 42 56 84 43 58 60 49 64 66 49 64 66 48 62 95 42 56 84 43 58 60 47 59 64 53 65 75 53 65 75 49 64 66 43 58 60 45 60 58 44 57 54 50 63 62 50 63 62 51 66 63 45 60 58 46 61 59 45 60 308 51 66 309 51 66 309 52 67 67 46 61 59 47 59 64 46 61 59 52 67 67 52 67 67 53 65 75 47 59 64 50 63 62 48 62 95 54 68 69 54 68 69 56 69 72 50 63 62 48 62 95 49 64 66 55 70 83 55 70 83 54 68 69 48 62 95 49 64 66 53 65 75 59 71 109 59 71 109 55 70 83 49 64 66 51 66 63 50 63 62 56 69 72 56 69 72 57 72 86 51 66 63 52 67 67 51 66 309 57 72 310 57 72 310 58 73 92 52 67 67 53 65 75 52 67 67 58 73 92 58 73 92 59 71 109 53 65 75 56 69 72 54 68 69 60 74 76 60 74 76 62 75 77 56 69 72 54 68 69 55 70 83 61 76 100 61 76 100 60 74 76 54 68 69 55 70 83 59 71 98 65 77 104 65 77 104 61 76 100 55 70 83 57 72 74 56 69 72 62 75 77 62 75 77 63 78 78 57 72 74 58 73 282 57 72 74 63 78 78 63 78 78 64 79 288 58 73 282 59 71 98 58 73 97 64 79 102 64 79 102 65 77 104 59 71 98 62 75 77 60 74 76 66 80 79 66 80 79 68 81 81 62 75 77 60 74 76 61 76 100 67 82 105 67 82 105 66 80 79 60 74 76 61 76 100 65 77 104 71 83 166 71 83 166 67 82 105 61 76 100 63 78 78 62 75 77 68 81 81 68 81 81 69 84 85 63 78 78 64 79 288 63 78 78 69 84 85 69 84 85 70 85 290 64 79 288 65 77 104 64 79 102 70 85 107 70 85 107 71 83 166 65 77 104 68 81 81 66 80 79 72 86 87 72 86 87 74 87 89 68 81 81 66 80 79 67 82 105 73 88 149 73 88 149 72 86 87 66 80 79 67 82 105 71 83 166 77 89 216 77 89 216 73 88 149 67 82 105 69 84 85 68 81 81 74 87 89 74 87 89 75 90 90 69 84 85 70 85 290 69 84 85 75 90 90 75 90 90 76 91 291 70 85 290 71 83 166 70 85 107 76 91 201 76 91 201 77 89 216 71 83 166 74 87 89 72 86 87 78 92 91 78 92 91 80 93 93 74 87 89 72 86 87 73 88 149 79 94 71 79 94 71 78 92 91 72 86 87 73 88 149 77 89 216 83 95 218 83 95 218 79 94 71 73 88 149 75 90 90 74 87 89 80 93 93 80 93 93 81 96 94 75 90 90 76 91 291 75 90 90 81 96 94 81 96 94 82 97 292 76 91 291 77 89 216 76 91 201 82 97 217 82 97 217 83 95 218 77 89 216 80 93 93 78 92 91 84 98 99 84 98 99 86 99 55 80 93 93 78 92 91 79 94 71 85 100 73 85 100 73 84 98 99 78 92 91 79 94 71 83 95 218 89 101 70 89 101 70 85 100 73 79 94 71 81 96 94 80 93 93 86 99 55 86 99 55 87 102 61 81 96 94 82 97 292 81 96 94 87 102 61 87 102 61 88 103 268 82 97 292 83 95 218 82 97 217 88 103 65 88 103 65 89 101 70 83 95 218 86 99 82 84 98 52 90 104 103 90 104 103 92 105 108 86 99 82 84 98 52 85 100 80 91 106 106 91 106 106 90 104 103 84 98 52 85 100 80 89 101 101 93 107 110 93 107 110 91 106 106 85 100 80 87 102 88 86 99 82 94 108 111 94 108 111 95 109 143 87 102 88 88 103 96 87 102 88 95 109 143 95 109 143 96 110 175 88 103 96 89 101 101 88 103 96 96 110 175 96 110 175 97 111 176 89 101 101 86 99 82 92 105 108 98 112 183 98 112 183 94 108 111 86 99 82 93 107 110 89 101 101 97 111 176 97 111 176 99 113 189 93 107 110 95 109 221 94 108 220 101 114 263 101 114 263 100 115 258 95 109 221 96 110 222 95 109 221 100 115 258 97 111 223 96 110 222 100 115 258 100 115 258 101 114 263 97 111 223 94 108 220 98 112 225 102 116 264 102 116 264 101 114 263 94 108 220 99 113 266 97 111 223 101 114 263 101 114 263 102 116 264 99 113 266 92 105 108 90 104 103 104 117 219 91 106 106 93 107 110 103 118 265 98 112 183 92 105 108 104 117 219 93 107 110 99 113 189 103 118 265 102 116 264 98 112 225 104 117 267 99 113 266 102 116 264 103 118 269 90 104 184 91 106 185 102 116 264 91 106 106 103 118 265 102 116 215 104 117 219 90 104 103 102 116 215 105 50 8 202 119 11 206 120 116 206 120 116 196 121 113 105 50 8 196 121 113 206 120 116 207 122 208 207 122 208 193 123 272 196 121 113 193 123 272 207 122 208 208 124 293 208 124 293 106 125 10 193 123 272 106 125 114 208 124 121 209 126 118 209 126 118 107 127 117 106 125 114 107 127 117 209 126 118 108 128 119 108 128 119 109 129 127 107 127 117 109 129 127 108 128 119 111 130 210 111 130 210 110 131 120 109 129 127 110 131 120 111 130 210 112 132 211 112 132 211 200 133 213 110 131 120 200 133 115 112 132 122 114 134 295 114 134 295 113 135 123 200 133 115 113 135 123 114 134 295 333 136 125 333 136 125 198 137 278 113 135 123 201 138 214 210 139 297 115 140 126 201 138 214 115 140 126 205 26 24 205 26 24 116 27 39 201 138 214 10 23 13 9 21 9 125 141 23 125 141 23 118 142 21 10 23 13 37 25 20 10 23 13 118 142 21 118 142 21 120 52 22 37 25 20 23 33 32 121 143 133 126 144 138 23 33 32 126 144 138 119 42 130 9 21 9 119 42 294 125 141 23 36 51 137 199 53 255 120 52 35 117 32 25 120 52 159 122 145 134 122 145 134 121 143 133 117 32 25 120 52 159 118 142 162 123 146 135 120 52 159 123 146 135 122 145 134 121 143 133 122 145 134 127 147 139 127 147 139 124 148 136 121 143 133 123 146 135 118 142 162 125 141 192 125 141 192 128 149 140 123 146 135 121 143 133 124 148 136 126 144 138 122 145 134 123 146 135 128 149 140 128 149 140 127 147 139 122 145 134 119 42 130 126 144 138 132 150 144 132 150 144 129 151 141 119 42 130 125 141 224 119 42 130 129 151 141 129 151 141 131 152 154 125 141 224 124 148 136 127 147 139 133 153 145 133 153 145 130 154 142 124 148 136 128 149 140 125 141 192 131 152 157 131 152 157 134 155 146 128 149 140 126 144 138 124 148 136 130 154 142 130 154 142 132 150 144 126 144 138 127 147 139 128 149 140 134 155 146 134 155 146 133 153 145 127 147 139 129 151 141 132 150 144 138 156 150 138 156 150 135 157 147 129 151 141 131 152 154 129 151 141 135 157 147 135 157 147 137 158 160 131 152 154 130 154 142 133 153 145 139 159 151 139 159 151 136 160 148 130 154 142 134 155 146 131 152 157 137 158 202 137 158 202 140 161 152 134 155 146 132 150 144 130 154 142 136 160 148 136 160 148 138 156 150 132 150 144 133 153 145 134 155 146 140 161 152 140 161 152 139 159 151 133 153 145 135 157 147 138 156 150 142 162 155 142 162 155 146 163 179 135 157 147 135 157 147 146 163 179 148 164 181 148 164 181 137 158 160 135 157 147 136 160 148 139 159 151 143 165 156 143 165 156 141 166 153 136 160 148 140 161 152 137 158 202 148 164 285 148 164 285 150 167 163 140 161 152 138 156 150 136 160 148 141 166 153 141 166 153 142 162 155 138 156 150 139 159 151 140 161 152 150 167 163 150 167 163 143 165 156 139 159 151 142 162 155 145 168 178 146 163 179 141 166 153 143 165 156 144 169 158 142 162 155 141 166 153 144 169 158 144 169 158 145 168 178 142 162 155 145 168 178 149 170 186 146 163 179 144 169 158 143 165 156 147 171 161 145 168 178 144 169 158 147 171 161 147 171 161 149 170 186 145 168 178 146 163 179 149 170 186 154 172 167 154 172 167 151 173 164 146 163 179 148 164 181 146 163 179 151 173 164 151 173 164 153 174 193 148 164 181 147 171 161 143 165 156 155 175 168 155 175 168 152 176 165 147 171 161 150 167 163 148 164 285 153 174 286 153 174 286 156 177 169 150 167 163 149 170 186 147 171 161 152 176 165 152 176 165 154 172 167 149 170 186 143 165 156 150 167 163 156 177 169 156 177 169 155 175 168 143 165 156 151 173 164 154 172 167 160 178 172 160 178 172 157 179 170 151 173 164 153 174 193 151 173 164 157 179 170 157 179 170 159 180 289 153 174 193 152 176 165 155 175 168 161 181 173 161 181 173 158 182 171 152 176 165 156 177 169 153 174 286 159 180 287 159 180 287 162 183 174 156 177 169 154 172 167 152 176 165 158 182 171 158 182 171 160 178 172 154 172 167 155 175 168 156 177 169 162 183 174 162 183 174 161 181 173 155 175 168 157 179 170 160 178 172 163 184 124 163 184 124 165 185 281 157 179 170 159 180 289 157 179 170 165 185 281 165 185 281 167 186 180 159 180 289 158 182 171 161 181 173 164 187 177 164 187 177 166 188 182 158 182 171 162 183 174 159 180 287 167 186 283 167 186 283 168 189 188 162 183 174 160 178 172 158 182 171 166 188 182 166 188 182 163 184 124 160 178 172 161 181 173 162 183 174 168 189 188 168 189 188 164 187 177 161 181 173 165 185 234 163 184 244 172 190 206 172 190 206 169 191 197 165 185 234 167 186 246 165 185 245 169 191 190 169 191 190 171 192 194 167 186 246 166 188 187 164 187 261 173 193 195 173 193 195 170 194 191 166 188 187 168 189 262 167 186 246 171 192 194 171 192 194 174 195 196 168 189 262 163 184 244 166 188 236 170 194 205 170 194 205 172 190 206 163 184 244 164 187 261 168 189 262 174 195 196 174 195 196 173 193 195 164 187 261 169 191 197 172 190 206 187 196 259 187 196 259 175 197 226 169 191 197 171 192 194 169 191 190 175 197 198 175 197 198 177 198 200 171 192 194 170 194 191 173 193 195 178 199 203 178 199 203 176 200 199 170 194 191 174 195 196 171 192 194 177 198 200 177 198 200 179 201 204 174 195 196 172 190 206 170 194 205 176 200 227 176 200 227 187 196 259 172 190 206 173 193 195 174 195 196 179 201 204 179 201 204 178 199 203 173 193 195 176 200 199 178 199 203 181 202 229 181 202 229 180 203 228 176 200 199 187 196 259 176 200 227 180 203 235 180 203 235 188 204 260 187 196 259 178 199 203 179 201 204 182 205 230 182 205 230 181 202 229 178 199 203 175 197 226 187 196 259 185 206 238 185 206 238 183 207 237 175 197 226 177 198 200 175 197 198 183 207 231 183 207 231 184 208 232 177 198 200 179 201 204 177 198 200 184 208 232 184 208 232 186 209 242 179 201 204 182 205 230 179 201 204 187 196 239 187 196 239 188 204 240 182 205 230 179 201 204 186 209 242 185 206 233 185 206 233 187 196 239 179 201 204 180 203 228 181 202 229 189 210 247 188 204 260 180 203 235 189 210 241 181 202 229 182 205 230 189 210 247 183 207 237 185 206 238 190 211 243 184 208 232 183 207 231 190 211 248 186 209 242 184 208 232 190 211 248 182 205 230 188 204 240 189 210 280 185 206 233 186 209 242 190 211 275 107 127 117 109 129 127 191 212 270 191 212 270 106 125 114 107 127 117 109 129 127 110 131 120 192 213 207 192 213 207 191 212 270 109 129 127 106 125 10 191 212 257 194 214 273 194 214 273 193 123 272 106 125 10 191 212 257 192 213 112 195 215 274 195 215 274 194 214 273 191 212 257 193 123 272 194 214 273 197 216 279 197 216 279 196 121 113 193 123 272 194 214 273 195 215 274 198 137 278 198 137 278 197 216 279 194 214 273 196 121 113 197 216 279 199 53 296 199 53 296 105 50 8 196 121 113 197 216 279 198 137 278 225 217 321 197 216 279 225 217 321 116 27 39 197 216 279 116 27 39 199 53 296 192 213 207 110 131 120 200 133 213 225 217 321 198 137 278 213 218 300 195 215 274 192 213 112 200 133 115 200 133 115 113 135 123 195 215 274 198 137 278 195 215 274 113 135 123 333 136 125 211 219 298 212 220 299 214 221 301 213 218 300 215 222 302 215 222 302 217 223 304 214 221 301 214 221 301 210 139 297 201 138 214 212 220 299 198 137 278 333 136 125 212 220 299 213 218 300 198 137 278 201 138 214 116 27 39 225 217 321 201 138 214 225 217 321 213 218 300 201 138 214 213 218 300 214 221 301 212 220 299 211 219 298 216 224 303 212 220 299 216 224 303 215 222 302 215 222 302 213 218 300 212 220 299 214 221 301 217 223 304 210 139 297 0 2 0 117 32 12 17 28 27 0 2 0 36 51 137 117 32 12 117 32 25 121 143 133 23 33 32 23 33 209 24 37 249 19 31 29 36 51 137 120 52 35 117 32 12 13 225 320 4 226 4 218 227 28 4 228 4 5 229 5 219 230 43 220 231 305 219 232 43 5 233 17 5 234 17 14 235 36 220 236 305 4 237 4 219 238 43 218 239 28 222 240 306 221 241 311 218 242 28 218 243 28 219 244 43 222 245 306 223 246 312 222 247 306 219 248 43 219 249 43 220 250 305 223 251 312 221 252 311 222 253 306 224 254 313 222 255 306 223 256 312 224 257 313 199 53 255 116 27 129 37 25 128 105 50 212 199 53 255 36 51 137 0 258 323 420 259 322 430 260 324 105 261 325 0 262 323 226 263 326 105 264 327 226 265 326 432 266 329 432 267 329 202 268 328 105 269 327 226 270 326 0 271 323 430 272 324 430 273 324 434 274 331 227 275 330 227 276 330 226 277 326 430 278 324 226 279 326 227 280 330 435 281 332 435 282 332 432 283 329 226 284 326 227 285 330 434 286 331 436 287 333 435 288 332 227 289 330 436 290 333 16 291 334 239 292 335 437 293 336 2 294 337 16 295 334 228 296 338 2 297 340 228 298 338 439 299 341 439 300 341 11 301 339 2 302 340 228 303 338 16 304 334 437 305 336 437 306 336 441 307 343 229 308 342 229 309 342 228 310 338 437 311 336 228 312 338 229 313 342 442 314 344 442 315 344 439 316 341 228 317 338 229 318 342 441 319 343 443 320 345 442 321 344 229 322 342 443 323 345 203 0 379 231 324 349 230 325 346 230 325 346 420 1 377 203 0 379 11 4 383 232 326 348 231 324 349 231 324 349 203 0 379 11 4 383 240 327 397 239 9 393 12 8 386 12 8 386 233 328 372 240 327 397 13 10 663 234 329 662 233 328 372 233 328 372 12 8 386 13 10 663 14 12 665 6 14 362 235 330 664 35 15 630 15 17 617 257 331 623 204 18 360 236 332 347 257 331 623 257 331 623 15 17 617 204 18 360 421 20 361 237 333 355 236 332 347 236 332 347 204 18 360 421 20 361 422 22 364 238 334 359 237 333 355 237 333 355 421 20 361 422 22 364 423 24 365 259 335 366 238 334 359 238 334 359 422 22 364 423 24 365 205 26 399 334 336 475 259 335 474 259 335 474 423 24 388 205 26 399 231 324 349 241 337 373 230 325 346 232 326 348 241 337 373 231 324 349 234 329 662 260 338 597 242 339 380 242 339 380 233 328 372 234 329 662 233 328 372 242 339 380 240 327 397 243 340 375 247 341 555 335 342 358 335 342 358 241 337 373 243 340 375 244 343 376 243 340 375 241 337 373 241 337 373 232 326 348 244 343 376 240 327 397 246 344 478 244 343 376 244 343 376 232 326 348 240 327 397 260 338 597 245 345 477 242 339 380 242 339 380 246 344 478 240 327 397 244 343 376 249 346 596 248 347 595 248 347 595 243 340 375 244 343 376 246 344 478 252 348 600 249 346 596 249 346 596 244 343 376 246 344 478 245 345 477 251 349 599 250 350 598 250 350 598 242 339 380 245 345 477 242 339 380 250 350 598 252 348 600 252 348 600 246 344 478 242 339 380 248 347 595 253 351 384 337 352 640 337 352 640 247 341 555 248 347 595 249 346 596 254 353 602 253 351 384 253 351 384 248 347 595 249 346 596 252 348 600 256 354 622 254 353 602 254 353 602 249 346 596 252 348 600 251 349 599 263 355 403 255 356 387 255 356 387 250 350 598 251 349 599 250 350 598 255 356 387 256 354 622 256 354 622 252 348 600 250 350 598 236 332 347 237 333 355 337 352 640 337 352 640 253 351 384 236 332 347 254 353 602 257 331 623 236 332 347 236 332 347 253 351 384 254 353 602 256 354 622 35 15 630 257 331 623 257 331 623 254 353 602 256 354 622 263 355 403 34 49 391 7 48 353 7 48 353 255 356 387 263 355 403 255 356 387 7 48 353 35 15 630 35 15 630 256 354 622 255 356 387 230 325 346 258 357 483 327 358 558 338 359 381 259 335 474 417 360 601 235 330 661 261 361 395 260 338 392 260 338 392 234 329 660 235 330 661 6 14 362 262 362 394 261 361 653 261 361 653 235 330 664 6 14 362 34 49 391 263 355 403 262 362 402 262 362 402 6 14 352 34 49 391 260 338 392 266 363 400 264 364 430 264 364 430 245 345 414 260 338 392 245 345 414 264 364 430 265 365 406 265 365 406 251 349 390 245 345 414 251 349 390 265 365 406 269 366 410 269 366 410 263 355 396 251 349 390 261 361 395 267 367 404 266 363 400 266 363 400 260 338 392 261 361 395 262 362 394 268 368 405 267 367 654 267 367 654 261 361 653 262 362 394 263 355 396 269 366 410 268 368 405 268 368 405 262 362 394 263 355 396 266 363 400 272 369 408 270 370 441 270 370 441 264 364 430 266 363 400 264 364 430 270 370 441 271 371 412 271 371 412 265 365 406 264 364 430 265 365 406 271 371 412 275 372 421 275 372 421 269 366 410 265 365 406 267 367 404 273 373 409 272 369 408 272 369 408 266 363 400 267 367 404 268 368 405 274 374 413 273 373 655 273 373 655 267 367 654 268 368 405 269 366 410 275 372 421 274 374 413 274 374 413 268 368 405 269 366 410 272 369 408 278 375 418 276 376 415 276 376 415 270 370 441 272 369 408 270 370 441 276 376 415 277 377 429 277 377 429 271 371 412 270 370 441 271 371 412 277 377 429 281 378 455 281 378 455 275 372 421 271 371 412 273 373 409 279 379 432 278 375 418 278 375 418 272 369 408 273 373 409 274 374 413 280 380 438 279 379 656 279 379 656 273 373 655 274 374 413 275 372 421 281 378 455 280 380 438 280 380 438 274 374 413 275 372 421 278 375 418 284 381 423 282 382 422 282 382 422 276 376 415 278 375 418 276 376 415 282 382 422 283 383 446 283 383 446 277 377 429 276 376 415 277 377 429 283 383 446 287 384 450 287 384 450 281 378 444 277 377 429 279 379 420 285 385 424 284 381 423 284 381 423 278 375 418 279 379 420 280 380 628 286 386 634 285 385 424 285 385 424 279 379 420 280 380 628 281 378 444 287 384 450 286 386 448 286 386 448 280 380 443 281 378 444 284 381 423 290 387 427 288 388 425 288 388 425 282 382 422 284 381 423 282 382 422 288 388 425 289 389 451 289 389 451 283 383 446 282 382 422 283 383 446 289 389 451 293 390 512 293 390 512 287 384 450 283 383 446 285 385 424 291 391 431 290 387 427 290 387 427 284 381 423 285 385 424 286 386 634 292 392 636 291 391 431 291 391 431 285 385 424 286 386 634 287 384 450 293 390 512 292 392 453 292 392 453 286 386 448 287 384 450 290 387 427 296 393 435 294 394 433 294 394 433 288 388 425 290 387 427 288 388 425 294 394 433 295 395 495 295 395 495 289 389 451 288 388 425 289 389 451 295 395 495 299 396 562 299 396 562 293 390 512 289 389 451 291 391 431 297 397 436 296 393 435 296 393 435 290 387 427 291 391 431 292 392 636 298 398 637 297 397 436 297 397 436 291 391 431 292 392 636 293 390 512 299 396 562 298 398 547 298 398 547 292 392 453 293 390 512 296 393 435 302 399 439 300 400 437 300 400 437 294 394 433 296 393 435 294 394 433 300 400 437 301 401 417 301 401 417 295 395 495 294 394 433 295 395 495 301 401 417 305 402 564 305 402 564 299 396 562 295 395 495 297 397 436 303 403 440 302 399 439 302 399 439 296 393 435 297 397 436 298 398 637 304 404 638 303 403 440 303 403 440 297 397 436 298 398 637 299 396 562 305 402 564 304 404 563 304 404 563 298 398 547 299 396 562 302 399 439 308 405 401 306 406 445 306 406 445 300 400 437 302 399 439 300 400 437 306 406 445 307 407 419 307 407 419 301 401 417 300 400 437 301 401 417 307 407 419 311 408 416 311 408 416 305 402 564 301 401 417 303 403 440 309 409 407 308 405 401 308 405 401 302 399 439 303 403 440 304 404 638 310 410 614 309 409 407 309 409 407 303 403 440 304 404 638 305 402 564 311 408 416 310 410 411 310 410 411 304 404 563 305 402 564 308 405 428 314 411 454 312 412 449 312 412 449 306 406 398 308 405 428 306 406 398 312 412 449 313 413 452 313 413 452 307 407 426 306 406 398 307 407 426 313 413 452 315 414 456 315 414 456 311 408 447 307 407 426 309 409 434 317 415 489 316 416 457 316 416 457 308 405 428 309 409 434 310 410 442 318 417 521 317 415 489 317 415 489 309 409 434 310 410 442 311 408 447 319 418 522 318 417 521 318 417 521 310 410 442 311 408 447 308 405 428 316 416 457 320 419 529 320 419 529 314 411 454 308 405 428 315 414 456 321 420 535 319 418 522 319 418 522 311 408 447 315 414 456 317 415 567 322 421 604 323 422 609 323 422 609 316 416 566 317 415 567 318 417 568 322 421 604 317 415 567 319 418 569 323 422 609 322 421 604 322 421 604 318 417 568 319 418 569 316 416 566 323 422 609 324 423 610 324 423 610 320 419 571 316 416 566 321 420 612 324 423 610 323 422 609 323 422 609 319 418 569 321 420 612 314 411 454 326 424 565 312 412 449 313 413 452 325 425 611 315 414 456 320 419 529 326 424 565 314 411 454 315 414 456 325 425 611 321 420 535 324 423 610 326 424 613 320 419 571 321 420 612 325 425 615 324 423 610 312 412 530 324 423 610 313 413 531 313 413 452 324 423 561 325 425 611 326 424 565 324 423 561 312 412 449 327 358 354 414 426 459 206 120 462 206 120 462 202 119 357 327 358 354 414 426 459 411 427 618 207 122 554 207 122 554 206 120 462 414 426 459 411 427 618 328 428 356 208 124 639 208 124 639 207 122 554 411 427 618 328 428 460 329 429 463 209 126 464 209 126 464 208 124 467 328 428 460 329 429 463 330 430 473 108 128 465 108 128 465 209 126 464 329 429 463 330 430 473 331 431 466 111 130 556 111 130 556 108 128 465 330 430 473 331 431 466 418 432 559 112 132 557 112 132 557 111 130 556 331 431 466 418 432 461 332 433 469 114 134 641 114 134 641 112 132 468 418 432 461 332 433 469 416 434 624 333 136 471 333 136 471 114 134 641 332 433 469 419 435 560 115 140 472 210 139 643 419 435 560 334 336 385 205 26 370 205 26 370 115 140 472 419 435 560 238 334 359 336 436 367 343 437 369 343 437 369 237 333 355 238 334 359 259 335 366 338 359 368 336 436 367 336 436 367 238 334 359 259 335 366 247 341 378 344 438 484 339 439 479 247 341 378 337 352 476 344 438 484 237 333 355 343 437 369 337 352 640 258 357 483 338 359 381 417 360 601 335 342 371 339 439 479 340 440 480 340 440 480 338 359 505 335 342 371 338 359 505 341 441 481 336 436 508 338 359 505 340 440 480 341 441 481 339 439 479 342 442 482 345 443 485 345 443 485 340 440 480 339 439 479 341 441 481 346 444 486 343 437 538 343 437 538 336 436 508 341 441 481 339 439 479 344 438 484 342 442 482 340 440 480 345 443 485 346 444 486 346 444 486 341 441 481 340 440 480 337 352 476 347 445 487 350 446 490 350 446 490 344 438 484 337 352 476 343 437 570 349 447 500 347 445 487 347 445 487 337 352 476 343 437 570 342 442 482 348 448 488 351 449 491 351 449 491 345 443 485 342 442 482 346 444 486 352 450 492 349 447 503 349 447 503 343 437 538 346 444 486 344 438 484 350 446 490 348 448 488 348 448 488 342 442 482 344 438 484 345 443 485 351 449 491 352 450 492 352 450 492 346 444 486 345 443 485 347 445 487 353 451 493 356 452 496 356 452 496 350 446 490 347 445 487 349 447 500 355 453 506 353 451 493 353 451 493 347 445 487 349 447 500 348 448 488 354 454 494 357 455 497 357 455 497 351 449 491 348 448 488 352 450 492 358 456 498 355 453 548 355 453 548 349 447 503 352 450 492 350 446 490 356 452 496 354 454 494 354 454 494 348 448 488 350 446 490 351 449 491 357 455 497 358 456 498 358 456 498 352 450 492 351 449 491 353 451 493 364 457 525 360 458 501 360 458 501 356 452 496 353 451 493 353 451 493 355 453 506 366 459 527 366 459 527 364 457 525 353 451 493 354 454 494 359 460 499 361 461 502 361 461 502 357 455 497 354 454 494 358 456 498 368 462 509 366 459 631 366 459 631 355 453 548 358 456 498 356 452 496 360 458 501 359 460 499 359 460 499 354 454 494 356 452 496 357 455 497 361 461 502 368 462 509 368 462 509 358 456 498 357 455 497 360 458 501 364 457 525 363 463 524 359 460 499 362 464 504 361 461 502 360 458 501 363 463 524 362 464 504 362 464 504 359 460 499 360 458 501 363 463 524 364 457 525 367 465 532 362 464 504 365 466 507 361 461 502 363 463 524 367 465 532 365 466 507 365 466 507 362 464 504 363 463 524 364 457 525 369 467 510 372 468 513 372 468 513 367 465 532 364 457 525 366 459 527 371 469 539 369 467 510 369 467 510 364 457 525 366 459 527 365 466 507 370 470 511 373 471 514 373 471 514 361 461 502 365 466 507 368 462 509 374 472 515 371 469 632 371 469 632 366 459 631 368 462 509 367 465 532 372 468 513 370 470 511 370 470 511 365 466 507 367 465 532 361 461 502 373 471 514 374 472 515 374 472 515 368 462 509 361 461 502 369 467 510 375 473 516 378 474 518 378 474 518 372 468 513 369 467 510 371 469 539 377 475 635 375 473 516 375 473 516 369 467 510 371 469 539 370 470 511 376 476 517 379 477 519 379 477 519 373 471 514 370 470 511 374 472 515 380 478 520 377 475 633 377 475 633 371 469 632 374 472 515 372 468 513 378 474 518 376 476 517 376 476 517 370 470 511 372 468 513 373 471 514 379 477 519 380 478 520 380 478 520 374 472 515 373 471 514 375 473 516 383 479 627 381 480 470 381 480 470 378 474 518 375 473 516 377 475 635 385 481 526 383 479 627 383 479 627 375 473 516 377 475 635 376 476 517 384 482 528 382 483 523 382 483 523 379 477 519 376 476 517 380 478 520 386 484 534 385 481 629 385 481 629 377 475 633 380 478 520 378 474 518 381 480 470 384 482 528 384 482 528 376 476 517 378 474 518 379 477 519 382 483 523 386 484 534 386 484 534 380 478 520 379 477 519 383 479 580 387 485 543 390 486 552 390 486 552 381 480 590 383 479 580 385 481 592 389 487 540 387 485 536 387 485 536 383 479 591 385 481 592 384 482 533 388 488 537 391 489 541 391 489 541 382 483 607 384 482 533 386 484 608 392 490 542 389 487 540 389 487 540 385 481 592 386 484 608 381 480 590 390 486 552 388 488 551 388 488 551 384 482 582 381 480 590 382 483 607 391 489 541 392 490 542 392 490 542 386 484 608 382 483 607 387 485 543 393 491 572 405 492 605 405 492 605 390 486 552 387 485 543 389 487 540 395 493 546 393 491 544 393 491 544 387 485 536 389 487 540 388 488 537 394 494 545 396 495 549 396 495 549 391 489 541 388 488 537 392 490 542 397 496 550 395 493 546 395 493 546 389 487 540 392 490 542 390 486 552 405 492 605 394 494 573 394 494 573 388 488 551 390 486 552 391 489 541 396 495 549 397 496 550 397 496 550 392 490 542 391 489 541 394 494 545 398 497 574 399 498 575 399 498 575 396 495 549 394 494 545 405 492 605 406 499 606 398 497 581 398 497 581 394 494 573 405 492 605 396 495 549 399 498 575 400 500 576 400 500 576 397 496 550 396 495 549 393 491 572 401 501 583 403 502 584 403 502 584 405 492 605 393 491 572 395 493 546 402 503 578 401 501 577 401 501 577 393 491 544 395 493 546 397 496 550 404 504 588 402 503 578 402 503 578 395 493 546 397 496 550 400 500 576 406 499 586 405 492 585 405 492 585 397 496 550 400 500 576 397 496 550 405 492 585 403 502 579 403 502 579 404 504 588 397 496 550 398 497 574 407 505 593 399 498 575 406 499 606 407 505 587 398 497 581 399 498 575 407 505 593 400 500 576 401 501 583 408 506 589 403 502 584 402 503 578 408 506 594 401 501 577 404 504 588 408 506 594 402 503 578 400 500 576 407 505 626 406 499 586 403 502 579 408 506 621 404 504 588 329 429 463 328 428 460 409 507 616 409 507 616 330 430 473 329 429 463 330 430 473 409 507 616 410 508 553 410 508 553 331 431 466 330 430 473 328 428 356 411 427 618 412 509 619 412 509 619 409 507 603 328 428 356 409 507 603 412 509 619 413 510 620 413 510 620 410 508 458 409 507 603 411 427 618 414 426 459 415 511 625 415 511 625 412 509 619 411 427 618 412 509 619 415 511 625 416 434 624 416 434 624 413 510 620 412 509 619 414 426 459 327 358 354 417 360 642 417 360 642 415 511 625 414 426 459 415 511 625 417 360 642 334 336 385 415 511 625 334 336 385 429 512 667 415 511 625 429 512 667 416 434 624 410 508 553 418 432 559 331 431 466 429 512 667 425 513 646 416 434 624 413 510 620 332 433 469 418 432 461 418 432 461 410 508 458 413 510 620 416 434 624 332 433 469 413 510 620 333 136 471 424 514 645 211 219 644 426 515 647 217 223 650 215 222 648 215 222 648 425 513 646 426 515 647 426 515 647 419 435 560 210 139 643 424 514 645 333 136 471 416 434 624 424 514 645 416 434 624 425 513 646 419 435 560 426 515 647 425 513 646 419 435 560 425 513 646 429 512 667 419 435 560 429 512 667 334 336 385 424 514 645 216 224 649 211 219 644 424 514 645 425 513 646 215 222 648 215 222 648 216 224 649 424 514 645 426 515 647 210 139 643 217 223 650 230 325 346 241 337 373 335 342 358 230 325 346 335 342 358 258 357 483 335 342 371 247 341 378 339 439 479 247 341 555 243 340 375 248 347 595 258 357 483 335 342 358 338 359 381 13 516 666 218 517 374 234 518 350 234 519 350 427 520 389 235 521 351 220 522 651 14 523 382 235 524 363 235 525 363 427 526 389 220 527 651 234 528 350 218 529 374 427 530 389 428 531 652 427 532 389 218 533 374 218 534 374 221 535 657 428 536 652 223 537 658 220 538 651 427 539 389 427 540 389 428 541 652 223 542 658 221 543 657 224 544 659 428 545 652 428 546 652 224 547 659 223 548 658 417 360 601 259 335 474 334 336 475 327 358 558 258 357 483 417 360 601 230 549 669 430 550 670 420 551 668 327 552 671 431 553 672 230 554 669 327 555 673 202 556 674 432 557 675 432 558 675 431 559 672 327 560 673 431 561 672 430 562 670 230 563 669 430 564 670 431 565 672 433 566 676 433 567 676 434 568 677 430 569 670 431 570 672 432 571 675 435 572 678 435 573 678 433 574 676 431 575 672 433 576 676 436 577 679 434 578 677 435 579 678 436 580 679 433 581 676 240 582 680 437 583 682 239 584 681 232 585 683 438 586 684 240 587 680 232 588 686 11 589 685 439 590 687 439 591 687 438 592 684 232 593 686 438 594 684 437 595 682 240 596 680 437 597 682 438 598 684 440 599 688 440 600 688 441 601 689 437 602 682 438 603 684 439 604 687 442 605 690 442 606 690 440 607 688 438 608 684 440 609 688 443 610 691 441 611 689 442 612 690 443 613 691 440 614 688

-
-
-
-
- - - - 0 0 -0.823226 -127.093 -0.804999 0.172274 0 -393.418 0.172274 0.804999 0 597.2 0 0 0 1 - - Bone1 Bone2 Bone3 Bone4 Bone5 Bone6 Bone7 Bone8 Bone9 Bone10 Bone11 Bone12 Bone13 Bone14 Bone15 Bone16 Bone17 Bone18 Bone19 Bone20 Bone21 Bone22 Bone23 Bone24 Bone25 Bone26 Bone27 Bone28 Bone29 Bone30 Bone31 Bone32 Bone33 Bone34 Bone35 Bone36 - - - - - - - - -0.000001 -0.498104 0.867117 -372.311 0.000002 -0.867117 -0.498104 190.579 1 0.000002 0.000002 164.813 0 0 0 1 0.018402 -0.952156 0.305058 -248.429 0.005875 -0.305001 -0.952334 488.559 0.999813 0.019317 -0.000017 166.548 0 0 0 1 0.014279 -0.978258 0.206897 -595.466 0.013021 -0.206719 -0.978314 553.498 0.999813 0.016664 0.009786 158.8 0 0 0 1 0.002118 -0.59792 0.801553 -1114.98 0.019207 -0.801383 -0.597843 -243.593 0.999813 0.016662 0.009787 158.798 0 0 0 1 0.000003 -0.987687 0.156443 -1100.78 -0.000004 -0.156443 -0.987687 728.967 1 0.000003 -0.000004 151.349 0 0 0 1 0.000003 -0.987687 0.156443 -1445.92 -0.000004 -0.156443 -0.987687 728.967 1 0.000003 -0.000004 151.349 0 0 0 1 0.982826 -0.177426 0.050735 -84.4751 -0.013035 0.207498 0.978149 -552.703 -0.184076 -0.962011 0.201621 -1001.67 0 0 0 1 0.345846 0.362543 -0.865421 956.554 0.64452 0.578511 0.499919 99.0181 0.681898 -0.730676 -0.03359 -671.86 0 0 0 1 -0.200043 -0.142123 -0.969425 352.385 0.703561 0.667768 -0.24308 479.223 0.681898 -0.730676 -0.03359 -671.86 0 0 0 1 0.217356 -0.852205 -0.475923 -682.171 -0.243388 0.424861 -0.871926 441.168 0.945261 0.305353 -0.115071 146.202 0 0 0 1 0.048129 -0.988567 0.142892 -967.298 -0.07356 -0.146177 -0.98652 -142.398 0.996129 0.03697 -0.079755 -122.422 0 0 0 1 0.048129 -0.988567 0.142892 -1135.06 -0.07356 -0.146177 -0.98652 -142.398 0.996129 0.03697 -0.079755 -122.422 0 0 0 1 -0.977172 -0.210093 0.031546 -395.778 -0.013035 0.207497 0.978149 -552.703 -0.212048 0.955409 -0.205499 938.758 0 0 0 1 -0.345847 0.362542 -0.865421 850.904 -0.644521 0.57851 0.499919 -89.6829 0.681896 0.730677 0.03359 883.479 0 0 0 1 0.200043 -0.142122 -0.969425 407.797 -0.703563 0.667766 -0.24308 270.179 0.681896 0.730677 0.03359 883.479 0 0 0 1 -0.217354 -0.852205 -0.475923 -756.014 0.243387 0.424861 -0.871926 514.158 0.945262 -0.30535 0.115071 138.002 0 0 0 1 -0.048127 -0.988567 0.142892 -988.33 0.073561 -0.146177 -0.98652 -125.343 0.996129 -0.036967 0.079755 423.785 0 0 0 1 -0.048127 -0.988567 0.142892 -1156.09 0.073561 -0.146177 -0.98652 -125.343 -0.996129 0.036967 -0.079755 -423.785 0 0 0 1 0.103504 1.23219 -0.953623 -5.24189 0.018092 0.849368 1.40418 35.1901 0.133037 -0.031979 0.016403 -1.16024 0 0 0 1 0.103504 1.23219 -0.953624 -23.0638 0.018092 0.849368 1.40418 35.1901 0.133037 -0.031979 0.016403 -1.16024 0 0 0 1 0.136359 1.29822 -0.454348 -6.65496 -0.04207 1.06418 0.58784 34.4271 0.097744 -0.040283 0.026403 0.158465 0 0 0 1 0.136359 1.29822 -0.454349 -24.4769 -0.04207 1.06418 0.58784 34.4271 0.097744 -0.040283 0.026403 0.158465 0 0 0 1 0.407337 -0.876293 0.257268 -121.912 -0.021509 0.272414 0.96194 -396.536 -0.913024 -0.397367 0.092116 -53.8212 0 0 0 1 -0.340749 0.618869 -0.707737 778.308 0.224224 -0.677569 -0.700445 4.15001 -0.913024 -0.397367 0.092116 -53.8212 0 0 0 1 0.198567 0.040829 -0.979237 178.175 0.428123 -0.902381 0.049189 -177.218 -0.881636 -0.429001 -0.196663 -7.81232 0 0 0 1 0.428123 -0.902381 0.049189 -366.582 -0.198567 -0.040829 0.979237 36.3969 -0.881636 -0.429001 -0.196663 -7.81234 0 0 0 1 0.428123 -0.902381 0.049189 -533.55 -0.198567 -0.040829 0.979237 36.3969 0.881636 0.429001 0.196663 7.81232 0 0 0 1 -0.407335 -0.876294 0.257268 -256.181 0.021509 0.272415 0.96194 -389.446 -0.913026 0.397365 -0.092116 -247.138 0 0 0 1 0.340748 0.61887 -0.707737 890.628 -0.224222 -0.67757 -0.700445 -69.7601 -0.913026 0.397365 -0.092116 -247.138 0 0 0 1 -0.198567 0.040828 -0.979237 112.722 -0.42812 -0.902382 0.049189 -318.339 -0.881637 0.428998 0.196663 -282.8 0 0 0 1 -0.42812 -0.902382 0.049189 -507.702 0.198567 -0.040828 0.979237 101.85 -0.881637 0.428998 0.196663 -282.8 0 0 0 1 -0.42812 -0.902382 0.049189 -674.671 0.198567 -0.040828 0.979237 101.85 -0.881637 0.428998 0.196663 -282.8 0 0 0 1 -0.000001 0.89786 -0.440282 85.3253 -0.000003 0.440282 0.89786 -428.17 1 0.000002 0.000002 164.813 0 0 0 1 -0.000001 0.979354 -0.202151 -290.64 -0.000003 0.202151 0.979354 -366.962 1 0.000002 0.000003 164.813 0 0 0 1 -0.000001 0.999734 0.023058 -696.012 -0.000003 -0.023058 0.999734 -215.81 1 0.000001 0.000003 164.813 0 0 0 1 0 -0.022262 0.999752 -216.662 -0.000001 0.999752 0.022262 -1070.03 -1 -0.000001 0 -164.814 0 0 0 1 - - - - - - - - 1 0.5 0.5 0.5 0.5 0.250005 0.250005 0.250005 0.249985 0.249326 0.249326 0.249326 0.249292 0.002481 0.000249 0 0 0.255314 0.255314 0.255314 0.233724 0.000333 0.34311 0.342829 0.314061 0.269713 0.269713 0.25908 0.201202 0.000293 0.976934 0.020302 0.002692 0.000072 0.504183 0.495817 0.992702 0.006541 0.000516 0.000241 0.5 0.5 0.25 0.25 0.25 0.25 0.248107 0.248107 0.248107 0.248104 0.007575 0 0 0.29226 0.29226 0.29226 0.123219 0.000002 0 0.428036 0.294492 0.277469 0.000002 0.5 0.5 0.613111 0.386889 0.330926 0.330926 0.330926 0.005259 0.001963 0.523741 0.476254 0.000004 0.531337 0.278746 0.170694 0.019223 0.224198 0.224198 0.224198 0.192595 0.13481 0.37388 0.373763 0.23913 0.013021 0.000206 0.890373 0.109627 0.529576 0.46503 0.003293 0.002091 0.00001 0.333332 0.333332 0.333313 0.000022 0.24944 0.24944 0.24944 0.24944 0.00224 0.336248 0.336248 0.327504 0 0.5588 0.43951 0.001687 0.000003 0.48408 0.414347 0.062061 0.033619 0.005893 0.375571 0.375571 0.248777 0.000073 0.000008 0.465313 0.464134 0.070472 0.000081 0 0.555267 0.438572 0.006105 0.000056 0.479845 0.479845 0.02293 0.01738 0.34641 0.330382 0.323208 0.716826 0.283171 0.000003 0.687382 0.31261 0.000007 0.000001 0.273524 0.273524 0.273524 0.179425 0.000002 0.307451 0.307451 0.307451 0.077647 0.333052 0.333052 0.332573 0.001324 0.276481 0.261169 0.250349 0.147703 0.064298 0.261252 0.261252 0.261252 0.216243 0.315936 0.315936 0.315935 0.051028 0.001164 0.333333 0.333333 0.333333 0.5 0.5 0.274488 0.274488 0.274408 0.176616 0.5 0.5 0.5 0.5 0.391301 0.391301 0.212431 0.004967 0.287452 0.287452 0.287353 0.137742 0.252191 0.252191 0.252191 0.243426 0.202008 0.202008 0.202008 0.201483 0.192492 0.000002 0.279438 0.279438 0.278072 0.148456 0.014596 0.249346 0.249346 0.235084 0.234275 0.030298 0.00165 0.281627 0.281627 0.281575 0.119793 0.03537 0.000008 0.259761 0.259761 0.259761 0.220717 0.25408 0.25408 0.25408 0.237759 0.218093 0.218093 0.218093 0.169576 0.164624 0.01152 0.577319 0.422681 0.590675 0.409325 0.000000 0 0.568801 0.431199 0.612922 0.387078 0.95794 0.04206 0.792574 0.207426 0.990969 0.009031 0 0.966959 0.03304 0.000001 0.741444 0.258556 0.98715 0.01285 0.995326 0.004669 0.000005 0.724012 0.275988 0.5 0.5 0.685744 0.314256 0.894522 0.105478 0.000057 0.995285 0.004715 0.000014 0.980918 0.019082 0.000012 0.56778 0.43222 0.5 0.5 0.796032 0.196191 0.007777 0.935409 0.061921 0.002658 0.000011 0.466364 0.466364 0.067272 0.817946 0.172792 0.009262 0 0.519451 0.480549 0.999123 0.000827 0.00005 0.662699 0.337301 0 0.526867 0.473133 0.540767 0.459005 0.000228 0.5 0.5 0.907687 0.092313 0.960711 0.039289 0.333518 0.333518 0.332964 0.515389 0.484611 0.764873 0.235127 0.5 0.5 0.796122 0.203878 0.790212 0.209788 0.498397 0.496474 0.005127 0.622905 0.365147 0.011948 0.750706 0.249294 0.503712 0.48755 0.008738 0.694048 0.276912 0.02904 0.88486 0.113768 0.001372 0.431128 0.331426 0.219147 0.018298 0.000001 0.321356 0.314105 0.302394 0.062129 0.000015 0.662066 0.291684 0.04625 0.892253 0.087419 0.017566 0.002761 0.000001 0.502866 0.480304 0.01683 0.987183 0.012817 0 0.556933 0.331912 0.111155 0.941586 0.058018 0.000396 0.729224 0.257989 0.012787 0.807969 0.192031 0.998872 0.001128 0.842727 0.157273 0.924292 0.075708 0.998612 0.001386 0.000002 0.987479 0.012521 0 0.996028 0.003972 0.999839 0.000161 0.000002 0 0 0.000033 0.966249 0.033751 0.590871 0.409129 0.544059 0.455941 0.524433 0.475567 0.5 0.5 0.555658 0.444342 0.891186 0.108814 0.999706 0.000199 0.000095 0.5 0.5 0.584365 0.415635 0 0.914776 0.085224 0.993551 0.006449 0.541343 0.458657 0.6923 0.3077 0.953948 0.046052 0.519802 0.480198 0.521872 0.478128 0.819531 0.180469 0.5 0.5 0.999888 0.000112 0.510403 0.489597 0.5 0.5 0.999647 0.000165 0.00012 0.000067 0.528926 0.471074 0 0.822694 0.177306 0.876887 0.123113 0.917105 0.067065 0.01583 0.971327 0.023824 0.004849 0.63649 0.36351 0.996398 0.003587 0.000015 0.865584 0.134416 0.721985 0.278015 0.549829 0.450171 0.964739 0.033492 0.001769 0.991533 0.008355 0.000112 0.768125 0.231875 0.364771 0.286106 0.17478 0.174342 0.478062 0.196859 0.1835 0.141579 0.382483 0.356413 0.131321 0.129783 0.501446 0.498554 0.551 0.449 0.502101 0.497899 0.518544 0.481456 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.25 0.25 0.25 0.249999 0.248714 0.248714 0.248714 0.24871 0.005025 0.000123 0 0 0.251963 0.251963 0.251963 0.243994 0.000117 0.962579 0.034928 0.002381 0.000112 0.5 0.5 0.99366 0.006246 0.000092 0.5 0.5 0.5 0.5 0.640506 0.359494 0.321798 0.321798 0.321798 0.034288 0.000318 0.543135 0.456857 0.000008 0.537131 0.284173 0.113714 0.064982 0.222332 0.222332 0.222332 0.190248 0.142757 0.371519 0.371387 0.24835 0.004851 0.003893 0.934436 0.065564 0.541833 0.454182 0.003676 0.000281 0.000028 0.359701 0 0.330259 0.297741 0.012299 0.333766 0.333766 0.332469 0.249911 0.249911 0.249911 0.249911 0.000356 0.342574 0.342574 0.314853 0 0 0.553795 0.444467 0.001732 0.000006 0.515796 0.432979 0.02896 0.021942 0.000323 0.400138 0.400138 0.19932 0.000243 0.000162 0.483968 0.481541 0.032253 0.002238 0 0.56401 0.428967 0.004143 0.00288 0.5 0.5 0.726743 0.273251 0.000006 0.283171 0.283171 0.283171 0.150484 0.000002 0.315941 0.315941 0.315941 0.052077 0.000099 0.333373 0.333373 0.333056 0.000198 0.295638 0.285615 0.24195 0.111306 0.065491 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.000007 0.000006 0.619164 0.380836 0.5489 0.4511 0.925804 0.074196 0.675774 0.324226 0.988633 0.011367 0 0.96422 0.03578 0 0.638222 0.361778 0.980415 0.019585 0.994453 0.00554 0.000007 0.653968 0.346032 0.5 0.5 0.672457 0.327543 0.857161 0.142839 0.992384 0.007616 0.9999 0.0001 0.9766 0.0234 0.999873 0.000127 0.5 0.5 0.803129 0.189578 0.007293 0.743446 0.256191 0.000358 0.000005 0.394101 0.394101 0.211799 0.743136 0.255217 0.001647 0 0.52149 0.47851 0.99936 0.00064 0 0.722442 0.277558 0 0.536039 0.463961 0.523373 0.430113 0.046514 0.500004 0.499996 0.926311 0.073689 0.967818 0.032182 0.5 0.5 0.524571 0.475429 0.548234 0.451766 0.5 0.5 0.821973 0.178027 0.829418 0.170582 0.492079 0.49188 0.016041 0.663048 0.332364 0.004588 0.548906 0.451021 0.000073 0.512982 0.481986 0.005032 0.732009 0.245128 0.022863 0.911163 0.086305 0.002531 0.452886 0.258653 0.25215 0.036308 0.000003 0.337323 0.306449 0.275558 0.080654 0.000016 0.813501 0.154318 0.032181 0.903494 0.061844 0.03466 0.000001 0.000001 0.484976 0.451264 0.06376 0.995585 0.004415 0.485339 0.260321 0.25434 0.967754 0.031666 0.000579 0.763695 0.230057 0.006248 0.835765 0.164235 0.999831 0.000169 0.8698 0.1302 0 0.946814 0.053186 0.999738 0.000261 0.000001 0.993786 0.006198 0.000016 0.997953 0.002047 0.000025 0.000000 0 0.879535 0.120465 0.604902 0.395098 0.546477 0.453523 0.51391 0.48609 0.509191 0.490809 0.534828 0.465172 0.000002 0.989554 0.010446 0.00002 0.000077 0 0.616767 0.383233 0 0.000004 0.509845 0.490155 0.000000 0.919151 0.080849 0.992821 0.007179 0.540066 0.459934 0.715687 0.284313 0.957401 0.042599 0.519792 0.480208 0.534875 0.465125 0.842078 0.157922 0.5 0.5 0.999537 0.000463 0.509435 0.490565 0.5 0.5 0.933368 0.06173 0.004902 0 0.465779 0.389618 0.130613 0.013028 0.00091 0.000052 0.71746 0.28213 0.00041 0 0.855182 0.144818 0.720255 0.279745 0.539688 0.460312 0.405706 0.269127 0.166836 0.158331 0.5056 0.4944 0.526946 0.473054 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 - - - - - - - - - - - - - - 2 1 2 4 8 5 3 5 4 2 4 2 4 7 6 4 2 2 5 3 4 5 5 2 5 1 4 5 4 4 5 5 5 4 4 3 3 4 5 4 4 5 1 4 5 3 2 4 2 2 4 4 4 6 5 6 6 4 4 6 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 1 1 1 1 1 2 2 1 1 1 2 2 2 2 1 3 3 1 2 2 3 1 2 1 1 2 2 2 2 2 2 1 1 2 2 2 2 3 4 3 4 2 3 3 2 3 2 2 2 3 2 2 2 2 2 3 3 2 3 3 3 5 5 3 5 1 3 3 3 3 3 2 2 2 2 3 3 2 1 2 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 1 2 1 3 2 1 1 1 1 1 1 1 2 2 1 1 2 2 2 2 2 2 2 2 2 2 2 2 1 4 3 2 2 3 3 2 3 2 2 2 3 3 2 4 4 4 2 2 2 1 2 2 2 2 2 2 1 2 4 8 5 4 2 3 2 2 2 5 3 4 5 5 2 5 5 3 5 5 4 5 5 5 4 2 3 5 5 4 5 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 1 1 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 1 1 1 2 2 2 2 1 3 3 1 2 2 3 1 2 1 1 2 2 2 2 2 2 2 2 3 4 3 4 2 3 3 2 3 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 5 5 3 5 1 3 2 3 3 3 2 2 3 2 3 3 2 1 2 1 1 1 1 1 2 1 2 1 2 2 2 2 2 2 2 2 2 3 2 1 1 2 1 1 2 1 2 2 1 1 2 2 2 2 2 2 2 2 2 2 2 2 4 6 4 2 2 2 4 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 3 1 2 2 2 0 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 1 11 0 12 32 13 22 14 27 15 1 16 1 17 1 18 1 19 32 20 22 21 1 22 1 23 1 24 1 25 0 26 1 27 1 28 22 29 2 30 6 31 1 32 1 33 2 34 6 35 6 36 2 37 3 38 4 39 1 40 1 41 1 42 1 43 1 44 1 45 1 46 1 47 1 48 0 49 32 50 22 51 27 52 1 53 1 54 1 55 32 56 22 57 27 58 1 59 1 60 1 61 2 62 1 63 1 64 2 65 6 66 1 67 1 68 1 69 1 70 22 71 2 72 6 73 1 74 1 75 1 76 2 77 1 78 1 79 22 80 0 81 1 82 1 83 1 84 1 85 1 86 22 87 1 88 2 89 7 90 2 91 6 92 1 93 22 94 1 95 0 0 1 96 1 97 22 98 23 99 22 100 1 101 0 102 1 103 23 104 1 105 1 106 22 107 2 108 2 109 6 110 1 111 1 112 1 113 1 114 22 115 2 116 23 117 1 118 1 119 22 120 0 121 1 122 1 123 1 124 22 125 1 126 2 127 1 128 1 129 2 130 1 131 1 132 1 133 0 134 1 135 1 136 1 137 1 138 6 139 4 140 2 141 6 142 4 143 2 144 3 145 1 146 1 147 0 148 22 149 1 150 1 151 1 152 1 153 22 154 1 155 1 156 1 157 22 158 1 159 0 160 22 161 23 162 1 163 22 0 22 164 1 165 1 166 23 167 22 168 22 169 1 170 1 171 0 172 22 173 1 174 22 175 22 176 1 177 23 178 1 179 22 180 0 181 22 182 22 183 22 184 22 185 22 186 22 187 1 188 23 189 22 190 22 191 23 192 1 193 23 194 22 195 22 196 1 197 22 198 1 199 22 200 1 201 23 202 2 203 22 204 22 205 23 206 2 207 1 208 22 209 22 210 2 211 23 212 1 213 1 214 22 215 22 216 23 217 1 218 1 219 2 220 22 221 23 222 22 223 1 224 23 225 22 226 22 227 1 228 23 229 22 230 22 231 1 232 1 233 2 234 23 0 23 0 23 0 23 0 23 0 23 0 23 0 23 0 23 0 23 0 23 0 23 0 23 0 23 0 23 0 23 0 23 0 23 0 24 235 23 236 24 237 23 238 23 0 23 0 23 0 23 0 24 0 24 0 23 239 24 0 1 240 23 0 23 0 24 0 24 241 25 242 25 243 24 244 24 245 25 246 25 247 24 248 24 0 24 249 1 250 23 251 24 252 1 253 23 254 24 0 25 255 24 256 25 257 24 258 24 259 1 260 23 261 24 0 25 262 24 263 25 0 25 0 3 264 2 265 4 266 6 267 4 268 6 269 4 0 12 270 4 271 6 272 4 0 6 273 4 0 4 0 4 274 6 275 4 0 12 276 4 277 12 278 4 279 6 280 6 281 2 282 7 283 6 284 7 285 4 286 2 287 6 288 2 289 7 290 6 291 7 292 4 293 2 294 7 295 2 296 7 297 2 298 6 299 6 300 7 301 2 302 7 303 2 304 6 305 2 306 7 307 7 308 2 309 7 310 2 311 7 312 2 313 6 314 2 315 7 316 7 317 2 318 2 319 7 320 7 321 2 322 7 323 2 324 7 325 2 326 2 327 7 328 8 329 7 330 2 331 8 332 2 333 7 334 7 335 2 336 8 337 7 338 2 339 8 340 7 341 2 342 8 343 8 344 7 345 2 346 23 347 22 348 8 349 7 350 2 351 23 352 22 353 8 354 7 355 2 356 8 357 2 358 23 359 7 360 22 361 7 0 8 362 2 363 7 364 8 365 2 366 7 367 8 368 2 369 7 370 8 371 2 372 23 373 8 374 7 375 2 376 8 377 2 378 8 379 2 380 8 381 2 382 8 383 2 384 8 385 2 386 7 387 8 388 2 389 7 390 8 391 2 392 8 0 8 393 2 394 8 0 8 0 8 0 8 0 8 0 8 0 9 395 8 0 9 396 8 0 9 397 8 0 9 398 9 399 8 400 9 401 8 402 8 403 9 404 9 405 8 406 9 407 8 408 9 409 8 410 9 0 9 411 10 412 9 0 9 413 10 414 8 415 9 416 10 417 10 0 10 0 10 0 10 0 10 0 10 0 10 0 10 418 9 419 10 0 9 420 10 0 10 0 4 421 6 422 4 423 6 424 4 425 6 426 4 427 6 428 4 429 6 430 4 431 6 432 4 433 6 434 4 435 6 436 4 437 6 438 4 439 6 440 4 441 6 442 3 443 2 444 2 0 2 445 1 446 1 447 1 448 4 449 12 450 6 451 4 452 12 453 4 454 12 455 4 456 12 457 6 458 4 459 12 460 6 461 4 462 12 463 4 464 12 465 6 466 4 467 6 468 4 469 6 470 4 471 6 472 4 473 12 474 6 475 4 476 12 477 6 478 4 479 12 480 32 481 33 482 1 483 1 484 32 485 1 486 1 487 33 488 32 489 33 490 1 491 1 492 33 493 34 494 33 495 34 496 33 497 34 498 34 0 4 499 6 500 3 501 2 502 3 503 2 504 1 505 1 506 1 507 1 508 3 509 2 510 2 0 1 511 1 512 1 513 1 514 1 515 1 516 1 517 1 518 1 519 0 520 32 521 27 522 22 523 1 524 1 525 1 526 1 527 32 528 27 529 2 530 12 531 1 532 1 533 12 534 2 535 12 536 2 537 4 538 1 539 1 540 1 541 1 542 2 543 12 544 1 545 1 546 1 547 1 548 27 549 2 550 12 551 1 552 1 553 1 554 2 555 1 556 1 557 27 558 0 559 1 560 1 561 1 562 1 563 1 564 27 565 1 566 2 567 13 568 2 569 12 570 1 571 27 572 1 573 1 574 23 575 1 576 27 577 2 578 1 579 1 580 27 581 27 582 1 583 0 584 1 585 28 586 1 587 1 588 27 589 1 590 2 591 2 592 12 593 1 594 1 595 1 596 1 597 27 598 2 599 28 600 1 601 1 602 27 603 0 604 1 605 1 606 1 607 27 608 1 609 2 610 1 611 1 612 2 613 1 614 3 615 2 616 12 617 4 618 2 619 1 620 1 621 0 622 27 623 1 624 1 625 1 626 1 627 27 628 32 629 1 630 1 631 1 632 27 633 1 634 0 635 27 636 28 637 1 638 27 639 27 640 27 0 27 0 27 0 27 0 27 0 27 0 27 0 27 0 27 0 27 0 27 0 27 0 27 0 27 0 27 641 28 642 27 643 28 644 28 0 28 0 28 0 28 0 27 645 28 646 27 647 28 648 28 0 28 0 28 0 28 0 28 0 28 0 28 0 28 0 28 0 28 0 28 0 28 0 28 0 28 0 28 0 28 0 28 0 28 0 28 0 29 0 29 0 28 649 29 0 1 650 28 0 28 0 28 0 29 651 30 652 30 653 29 654 29 655 30 656 30 657 29 658 29 0 29 659 1 660 28 661 29 662 1 663 28 664 29 0 30 665 29 666 30 667 29 668 29 669 1 670 28 671 29 0 30 672 29 673 30 0 30 0 3 674 2 675 4 676 12 677 4 678 12 679 4 680 12 681 4 682 12 683 4 684 12 685 4 686 12 687 4 688 12 689 12 690 2 691 13 692 12 693 13 694 4 695 2 696 12 697 2 698 13 699 12 700 13 701 4 702 2 703 13 704 2 705 13 706 2 707 12 708 13 709 12 710 2 711 13 712 2 713 12 714 2 715 13 716 2 717 13 718 13 719 2 720 13 721 2 722 13 723 2 724 13 725 2 726 2 727 13 728 13 729 2 730 13 731 2 732 13 733 2 734 13 735 2 736 14 737 13 738 2 739 14 740 13 741 2 742 14 743 13 744 2 745 14 746 13 747 2 748 14 749 13 750 2 751 14 752 14 753 2 754 13 755 28 756 27 757 2 758 14 759 13 760 28 761 27 762 14 763 13 764 2 765 14 766 2 767 28 768 27 769 13 770 13 0 14 771 2 772 13 773 14 774 2 775 14 776 2 777 13 778 14 779 2 780 28 781 14 782 13 783 2 784 14 785 2 786 14 787 2 788 14 789 2 790 13 791 14 792 2 793 14 794 2 795 13 796 14 797 2 798 13 799 14 800 2 801 14 0 14 0 2 802 14 0 14 0 14 0 14 0 14 0 14 0 15 803 14 0 14 0 15 804 14 0 15 805 14 806 15 807 14 808 14 809 15 810 15 811 14 812 14 813 15 814 15 815 14 816 15 0 14 817 15 818 16 819 15 0 14 820 15 0 14 821 16 822 15 823 16 824 16 0 16 0 16 0 15 825 16 0 16 0 16 0 15 826 16 0 16 827 15 828 16 0 15 829 16 0 16 0 4 830 12 831 4 832 12 833 4 834 12 835 4 836 12 837 4 838 12 839 4 840 12 841 4 842 12 843 4 844 12 845 4 846 12 847 4 848 12 849 4 850 12 851 3 852 2 853 2 854 3 855 12 856 6 857 12 858 3 859 3 860 2 861 6 862 4 863 4 864 12 865 6 866 2 867 4 868 12 869 4 870 12 871 4 872 12 873 32 874 33 875 1 876 1 877 33 878 34 879 4 880 12 881 3 882 2 883 3 884 2 885 3 886 2 887 3 888 2 889 3 890 2 891 3 892 2 893 3 894 2 895 1 896 1 897 1 898 1 899 1 900 1 901 1 902 1 903 1 904 1 905 1 906 1 907 1 908 1 909 - - - - - - - - 0.917303 0.398191 0.000000 524.412 -0.000000 0.000000 1 -0.000038 0.398191 -0.917303 0.000001 898.736 0 0 0 1 - - 0.634893 -0.746072 0.200716 142.077 0.754783 0.654426 0.045049 -0.208117 -0.164963 0.122896 0.978613 -0.038858 0 0 0 1 - - 0.955391 -0.206897 0.210765 399.228 0.228589 0.969883 -0.084102 -0.310882 -0.187017 0.128529 0.973912 -0.041171 0 0 0 1 - - 0.767026 0.627219 -0.135158 402.56 -0.617671 0.778843 0.109021 -0.112731 0.173646 -0.000139 0.984808 -0.000017 0 0 0 1 - - 0.999373 -0.013879 0.032569 181.732 0.016083 0.997526 -0.068434 -0.00008 -0.031539 0.068915 0.997124 -0.000002 0 0 0 1 - - 1 0 0 345.132 0 1 0 0.000017 0 0 1 -0.000007 0 0 0 1 - - - - -0.5 -0.5 -0.5 - 0.5 0.5 0.5 - - - - - - - - 344.632 -0.499952 -0.499979 - 345.632 0.500048 0.500021 - - - - - - 0.350776 0.631512 0.691483 7.49618 0.635478 -0.702886 0.319561 0.138573 0.68784 0.327328 -0.647867 42.5129 0 0 0 1 - - 0.917178 -0.198333 0.345613 175.071 -0.358196 -0.790364 0.497012 0.000071 0.174586 -0.579645 -0.795947 0.000007 0 0 0 1 - - 0.472321 0.881426 0 370.017 -0.881427 0.472321 0 0.00002 0 0 1 0.000000 0 0 0 1 - - 0.85009 -0.525938 -0.027135 370.018 0.510042 0.809374 0.291155 -0.000058 -0.131167 -0.261348 0.956291 -0.000004 0 0 0 1 - - 0.873378 0.43301 0.222966 186.693 -0.406165 0.900177 -0.157199 -0.000023 -0.268778 0.046733 0.962068 -0.000009 0 0 0 1 - - 1 0 0 167.761 0 1 0 0.000019 0 0 1 0.000013 0 0 0 1 - - - - -0.5 -0.5 -0.5 - 0.5 0.5 0.5 - - - - - - - - 167.261 -0.499925 -0.499991 - 168.261 0.500075 0.500009 - - - - - - - - 332.447 -68.307 -45.4604 - 333.977 -67.9702 -44.7204 - - - - - - - - 689.787 101.04 -69.2276 - 690.89 102.308 -68.8086 - - - - - - - - -0.01 -0.01 -0.01 - 0.01 0.01 0.01 - - - - - - - - -0.01 -0.01 -0.01 - 0.01 0.01 0.01 - - - - - - -0.572789 0.597854 -0.560788 -7.49618 -0.237486 -0.77583 -0.584541 0.150702 -0.784546 -0.201639 0.586369 -42.5129 0 0 0 1 - - 0.698734 0.399124 -0.593692 175.071 -0.715347 0.381718 -0.585295 -0.000136 -0.006981 0.833661 0.552232 0.000015 0 0 0 1 - - 0.112619 0.993638 0 370.017 -0.993638 0.112619 0 0.000029 0 0 1 0.000003 0 0 0 1 - - 0.995261 0.013675 -0.09627 370.017 -0.060933 0.859273 -0.507874 -0.000002 0.075777 0.511334 0.856035 0.000064 0 0 0 1 - - 0.738845 0.63592 -0.222966 186.693 -0.616553 0.77146 0.157199 0.000056 0.271976 0.021325 0.962068 0.000003 0 0 0 1 - - 1 0 0 167.761 -0.000000 1 0 -0.000005 0 0 -1 -0.000044 0 0 0 1 - - - - -0.5 -0.5 -0.5 - 0.5 0.5 0.5 - - - - - - - - -0.01 -0.01 -0.01 - 0.01 0.01 0.01 - - - - - - - - -0.01 -0.01 -0.01 - 0.01 0.01 0.01 - - - - - - - - -0.01 -0.01 -0.01 - 0.01 0.01 0.01 - - - - - - - - -0.01 -0.01 -0.01 - 0.01 0.01 0.01 - - - - - - - - -0.01 -0.01 -0.01 - 0.01 0.01 0.01 - - - - - - - - -51.3124 5.07854 -367.02 - 790.469 701.193 425.899 - - - - - - 0.910453 -0.384975 0.402477 179.053 0.30073 -1.01613 -1.53964 1051.53 -0.260873 0.124214 -9.62368 -104.193 0 0 0 1 - - 1 0 0.000000 17.8219 0 1 0 0.000014 0 0 1 -0.000002 0 0 0 1 - - - - -0.5 -0.5 -0.5 - 0.5 0.5 0.5 - - - - - - - - 17.322 -0.500014 -0.500002 - 18.322 0.499986 0.499998 - - - - - - 0.64804 -0.018001 0.848896 164.819 -0.09659 -0.613235 -0.343087 1034.98 -0.048948 0.00796 -7.34032 -108.759 0 0 0 1 - - 1 0 -0.000000 17.8219 0 1 0 0.000007 0 0 1 -0.000002 0 0 0 1 - - - - -0.5 -0.5 -0.5 - 0.5 0.5 0.5 - - - - - - - - 17.3219 -0.50006 -0.499999 - 18.3219 0.49994 0.500001 - - - - - - - - 175.629 -322.381 -370.45 - 1391.11 1055.76 556.593 - - - - - - 0.988998 -0.016084 -0.147054 -64.1862 -0.002497 -0.995745 0.092117 86.8699 -0.14791 -0.090736 -0.98483 -181.92 0 0 0 1 - - 0.044008 0.999031 0 547.819 -0.999031 0.044008 0 0.000037 0 0 1 -0.000015 0 0 0 1 - - 0.970553 -0.186579 0.152365 532.748 0.219338 0.945982 -0.238764 0.000041 -0.099587 0.265152 0.95905 -0.000002 0 0 0 1 - - 0.099612 -0.992857 0.06567 214.572 0.994956 0.100175 0.005319 189.364 -0.011859 0.06481 0.997827 -0.000000 0 0 0 1 - - 1 0 0 166.968 0 1 0 0.000004 0 0 1 -0.000033 0 0 0 1 - - - - -0.5 -0.5 -0.5 - 0.5 0.5 0.5 - - - - - - - - 166.468 -0.499949 -0.499992 - 167.468 0.500051 0.500008 - - - - - - - - -0.01 -0.01 -0.01 - 0.01 0.01 0.01 - - - - - - - - -0.01 -0.01 -0.01 - 0.01 0.01 0.01 - - - - - - - - 965.018 -673.231 68.6438 - 965.589 -672.357 70.0258 - - - - - - 0.429568 0.848459 0.309172 -115.92 0.861327 -0.487813 0.141963 125.412 0.271268 0.205316 -0.940351 124.981 0 0 0 1 - - 0.371507 0.92843 0 547.819 -0.92843 0.371507 0 -0.000005 0 0 1 -0.000012 0 0 0 1 - - 0.419188 -0.877486 -0.233021 532.748 0.873442 0.459808 -0.160238 0.000051 0.247751 -0.13636 0.959179 -0.000008 0 0 0 1 - - 0 -1 0 214.572 1 0 0 189.363 0 0 1 0.00003 0 0 0 1 - - 1 0 0 166.968 0 1 0 0.000000 0 0 -1 0.000008 0 0 0 1 - - - - -0.5 -0.5 -0.5 - 0.5 0.5 0.5 - - - - - - - - -0.01 -0.01 -0.01 - 0.01 0.01 0.01 - - - - - - - - -0.01 -0.01 -0.01 - 0.01 0.01 0.01 - - - - - - - - -0.01 -0.01 -0.01 - 0.01 0.01 0.01 - - - - - - - - -0.01 -0.01 -0.01 - 0.01 0.01 0.01 - - - - - - -0.961176 -0.270648 -0.053767 -217.547 0.265068 -0.959767 0.09266 76.1463 -0.076681 0.074811 0.994245 -46.1944 0 0 0 1 - - 0.966687 -0.249688 -0.056315 275.134 0.249268 0.968326 -0.014473 -0.261342 0.058146 -0.000045 0.998308 0.000000 0 0 0 1 - - 0.974433 -0.224679 -0.000000 339.089 0.224679 0.974433 0 -0.290226 0.000000 0.000000 1 -0.000007 0 0 0 1 - - 0.000796 1 0 374.193 1 -0.000795 0.000002 -0.000038 0.000002 0 -1 -0.000003 0 0 0 1 - - - - -0.5 -0.5 -0.5 - 0.5 0.5 0.5 - - - - - - - - -0.01 -0.01 -0.01 - 0.01 0.01 0.01 - - - - - - - - -0.01 -0.01 -0.01 - 0.01 0.01 0.01 - - - - - - - - -0.01 -0.01 -0.01 - 0.01 0.01 0.01 - - - - - - - - -1186.92 -134.371 -450.895 - 1824.03 1077.97 357.332 - - - - - - - - -684.45 -844.81 -519.071 - 1081.93 1633.24 450.018 - - - - - - - #Bip01_Pelvis-node - - - - - - - - - - - - 0 - 3.33333 - - - - - 30 - - - - - - - -
diff --git a/public/gfx/textures/monster.jpg b/public/gfx/textures/monster.jpg deleted file mode 100644 index 4f62a704..00000000 Binary files a/public/gfx/textures/monster.jpg and /dev/null differ diff --git a/public/gfx/textures/particle.png b/public/gfx/textures/particle.png deleted file mode 100644 index 82be7903..00000000 Binary files a/public/gfx/textures/particle.png and /dev/null differ diff --git a/public/gfx/textures/shiphull.jpg b/public/gfx/textures/shiphull.jpg deleted file mode 100644 index 7195c63b..00000000 Binary files a/public/gfx/textures/shiphull.jpg and /dev/null differ diff --git a/public/gfx/textures/wood_1_alt.jpg b/public/gfx/textures/wood_1_alt.jpg deleted file mode 100644 index 2202c91b..00000000 Binary files a/public/gfx/textures/wood_1_alt.jpg and /dev/null differ diff --git a/public/gfx/tivi2.jpg b/public/gfx/tivi2.jpg deleted file mode 100644 index b2a11faf..00000000 Binary files a/public/gfx/tivi2.jpg and /dev/null differ diff --git a/public/gfx/top01.gif b/public/gfx/top01.gif deleted file mode 100644 index 7ab9697f..00000000 Binary files a/public/gfx/top01.gif and /dev/null differ diff --git a/public/gfx/top02.gif b/public/gfx/top02.gif deleted file mode 100644 index 92505d3e..00000000 Binary files a/public/gfx/top02.gif and /dev/null differ diff --git a/public/gfx/top03.gif b/public/gfx/top03.gif deleted file mode 100644 index 3b8d4bc8..00000000 Binary files a/public/gfx/top03.gif and /dev/null differ diff --git a/public/gfx/top04.gif b/public/gfx/top04.gif deleted file mode 100644 index 0d1584a0..00000000 Binary files a/public/gfx/top04.gif and /dev/null differ diff --git a/public/gfx/triera.gif b/public/gfx/triera.gif deleted file mode 100644 index 63905aa2..00000000 Binary files a/public/gfx/triera.gif and /dev/null differ diff --git a/public/gfx/triera2.gif b/public/gfx/triera2.gif deleted file mode 100644 index 9a140528..00000000 Binary files a/public/gfx/triera2.gif and /dev/null differ diff --git a/public/gfx/v21.jpg b/public/gfx/v21.jpg deleted file mode 100644 index 1bf6f9b1..00000000 Binary files a/public/gfx/v21.jpg and /dev/null differ diff --git a/public/gfx/v22.jpg b/public/gfx/v22.jpg deleted file mode 100644 index fc6f7e73..00000000 Binary files a/public/gfx/v22.jpg and /dev/null differ diff --git a/public/gfx/valentines_banner.jpg b/public/gfx/valentines_banner.jpg deleted file mode 100644 index 9d2b9ec6..00000000 Binary files a/public/gfx/valentines_banner.jpg and /dev/null differ diff --git a/public/gfx/vp.gif b/public/gfx/vp.gif deleted file mode 100644 index a6082836..00000000 Binary files a/public/gfx/vp.gif and /dev/null differ diff --git a/public/gfx/wincust.gif b/public/gfx/wincust.gif deleted file mode 100644 index 5c9e9e87..00000000 Binary files a/public/gfx/wincust.gif and /dev/null differ diff --git a/public/gfx/wincustbutton.gif b/public/gfx/wincustbutton.gif deleted file mode 100644 index 5c9e9e87..00000000 Binary files a/public/gfx/wincustbutton.gif and /dev/null differ diff --git a/public/gfx/winterLogo.jpg b/public/gfx/winterLogo.jpg deleted file mode 100644 index 0dd0b8f5..00000000 Binary files a/public/gfx/winterLogo.jpg and /dev/null differ diff --git a/public/gfx/winter_competition.jpg b/public/gfx/winter_competition.jpg deleted file mode 100644 index 4c890b8b..00000000 Binary files a/public/gfx/winter_competition.jpg and /dev/null differ diff --git a/public/gfx/world_flags/ad.gif b/public/gfx/world_flags/ad.gif deleted file mode 100644 index 57b49973..00000000 Binary files a/public/gfx/world_flags/ad.gif and /dev/null differ diff --git a/public/gfx/world_flags/ae.gif b/public/gfx/world_flags/ae.gif deleted file mode 100644 index 78d15b67..00000000 Binary files a/public/gfx/world_flags/ae.gif and /dev/null differ diff --git a/public/gfx/world_flags/af.gif b/public/gfx/world_flags/af.gif deleted file mode 100644 index 98894082..00000000 Binary files a/public/gfx/world_flags/af.gif and /dev/null differ diff --git a/public/gfx/world_flags/ag.gif b/public/gfx/world_flags/ag.gif deleted file mode 100644 index 48f8e7bc..00000000 Binary files a/public/gfx/world_flags/ag.gif and /dev/null differ diff --git a/public/gfx/world_flags/ai.gif b/public/gfx/world_flags/ai.gif deleted file mode 100644 index 1cbc5795..00000000 Binary files a/public/gfx/world_flags/ai.gif and /dev/null differ diff --git a/public/gfx/world_flags/al.gif b/public/gfx/world_flags/al.gif deleted file mode 100644 index c44fe0a0..00000000 Binary files a/public/gfx/world_flags/al.gif and /dev/null differ diff --git a/public/gfx/world_flags/am.gif b/public/gfx/world_flags/am.gif deleted file mode 100644 index 2915e30c..00000000 Binary files a/public/gfx/world_flags/am.gif and /dev/null differ diff --git a/public/gfx/world_flags/an.gif b/public/gfx/world_flags/an.gif deleted file mode 100644 index cb570c67..00000000 Binary files a/public/gfx/world_flags/an.gif and /dev/null differ diff --git a/public/gfx/world_flags/ao.gif b/public/gfx/world_flags/ao.gif deleted file mode 100644 index 8c854fa1..00000000 Binary files a/public/gfx/world_flags/ao.gif and /dev/null differ diff --git a/public/gfx/world_flags/ar.gif b/public/gfx/world_flags/ar.gif deleted file mode 100644 index a9f71f7d..00000000 Binary files a/public/gfx/world_flags/ar.gif and /dev/null differ diff --git a/public/gfx/world_flags/as.gif b/public/gfx/world_flags/as.gif deleted file mode 100644 index d776ec27..00000000 Binary files a/public/gfx/world_flags/as.gif and /dev/null differ diff --git a/public/gfx/world_flags/at.gif b/public/gfx/world_flags/at.gif deleted file mode 100644 index 87e12173..00000000 Binary files a/public/gfx/world_flags/at.gif and /dev/null differ diff --git a/public/gfx/world_flags/au.gif b/public/gfx/world_flags/au.gif deleted file mode 100644 index 5269c6a0..00000000 Binary files a/public/gfx/world_flags/au.gif and /dev/null differ diff --git a/public/gfx/world_flags/aw.gif b/public/gfx/world_flags/aw.gif deleted file mode 100644 index 27fdb4d1..00000000 Binary files a/public/gfx/world_flags/aw.gif and /dev/null differ diff --git a/public/gfx/world_flags/ax.gif b/public/gfx/world_flags/ax.gif deleted file mode 100644 index 0ceb6849..00000000 Binary files a/public/gfx/world_flags/ax.gif and /dev/null differ diff --git a/public/gfx/world_flags/az.gif b/public/gfx/world_flags/az.gif deleted file mode 100644 index d7716184..00000000 Binary files a/public/gfx/world_flags/az.gif and /dev/null differ diff --git a/public/gfx/world_flags/ba.gif b/public/gfx/world_flags/ba.gif deleted file mode 100644 index 9bf5f0ac..00000000 Binary files a/public/gfx/world_flags/ba.gif and /dev/null differ diff --git a/public/gfx/world_flags/bb.gif b/public/gfx/world_flags/bb.gif deleted file mode 100644 index b7d08e57..00000000 Binary files a/public/gfx/world_flags/bb.gif and /dev/null differ diff --git a/public/gfx/world_flags/bd.gif b/public/gfx/world_flags/bd.gif deleted file mode 100644 index 0fd27eca..00000000 Binary files a/public/gfx/world_flags/bd.gif and /dev/null differ diff --git a/public/gfx/world_flags/be.gif b/public/gfx/world_flags/be.gif deleted file mode 100644 index ae09bfbe..00000000 Binary files a/public/gfx/world_flags/be.gif and /dev/null differ diff --git a/public/gfx/world_flags/bf.gif b/public/gfx/world_flags/bf.gif deleted file mode 100644 index 9d6772cd..00000000 Binary files a/public/gfx/world_flags/bf.gif and /dev/null differ diff --git a/public/gfx/world_flags/bg.gif b/public/gfx/world_flags/bg.gif deleted file mode 100644 index 11cf8ff3..00000000 Binary files a/public/gfx/world_flags/bg.gif and /dev/null differ diff --git a/public/gfx/world_flags/bh.gif b/public/gfx/world_flags/bh.gif deleted file mode 100644 index 56aa72b2..00000000 Binary files a/public/gfx/world_flags/bh.gif and /dev/null differ diff --git a/public/gfx/world_flags/bi.gif b/public/gfx/world_flags/bi.gif deleted file mode 100644 index 6e2cbe12..00000000 Binary files a/public/gfx/world_flags/bi.gif and /dev/null differ diff --git a/public/gfx/world_flags/bj.gif b/public/gfx/world_flags/bj.gif deleted file mode 100644 index e676116f..00000000 Binary files a/public/gfx/world_flags/bj.gif and /dev/null differ diff --git a/public/gfx/world_flags/bm.gif b/public/gfx/world_flags/bm.gif deleted file mode 100644 index 9feb87bc..00000000 Binary files a/public/gfx/world_flags/bm.gif and /dev/null differ diff --git a/public/gfx/world_flags/bn.gif b/public/gfx/world_flags/bn.gif deleted file mode 100644 index b7b6b0f9..00000000 Binary files a/public/gfx/world_flags/bn.gif and /dev/null differ diff --git a/public/gfx/world_flags/bo.gif b/public/gfx/world_flags/bo.gif deleted file mode 100644 index 4844f856..00000000 Binary files a/public/gfx/world_flags/bo.gif and /dev/null differ diff --git a/public/gfx/world_flags/br.gif b/public/gfx/world_flags/br.gif deleted file mode 100644 index 8c866162..00000000 Binary files a/public/gfx/world_flags/br.gif and /dev/null differ diff --git a/public/gfx/world_flags/bs.gif b/public/gfx/world_flags/bs.gif deleted file mode 100644 index c0a741e5..00000000 Binary files a/public/gfx/world_flags/bs.gif and /dev/null differ diff --git a/public/gfx/world_flags/bt.gif b/public/gfx/world_flags/bt.gif deleted file mode 100644 index abe2f3cc..00000000 Binary files a/public/gfx/world_flags/bt.gif and /dev/null differ diff --git a/public/gfx/world_flags/bv.gif b/public/gfx/world_flags/bv.gif deleted file mode 100644 index 6202d1f3..00000000 Binary files a/public/gfx/world_flags/bv.gif and /dev/null differ diff --git a/public/gfx/world_flags/bw.gif b/public/gfx/world_flags/bw.gif deleted file mode 100644 index 986ab63c..00000000 Binary files a/public/gfx/world_flags/bw.gif and /dev/null differ diff --git a/public/gfx/world_flags/by.gif b/public/gfx/world_flags/by.gif deleted file mode 100644 index 43ffcd4c..00000000 Binary files a/public/gfx/world_flags/by.gif and /dev/null differ diff --git a/public/gfx/world_flags/bz.gif b/public/gfx/world_flags/bz.gif deleted file mode 100644 index 791737f0..00000000 Binary files a/public/gfx/world_flags/bz.gif and /dev/null differ diff --git a/public/gfx/world_flags/ca.gif b/public/gfx/world_flags/ca.gif deleted file mode 100644 index 457d9662..00000000 Binary files a/public/gfx/world_flags/ca.gif and /dev/null differ diff --git a/public/gfx/world_flags/cc.gif b/public/gfx/world_flags/cc.gif deleted file mode 100644 index 3f783270..00000000 Binary files a/public/gfx/world_flags/cc.gif and /dev/null differ diff --git a/public/gfx/world_flags/cd.gif b/public/gfx/world_flags/cd.gif deleted file mode 100644 index 1df717ae..00000000 Binary files a/public/gfx/world_flags/cd.gif and /dev/null differ diff --git a/public/gfx/world_flags/cf.gif b/public/gfx/world_flags/cf.gif deleted file mode 100644 index 35787ca4..00000000 Binary files a/public/gfx/world_flags/cf.gif and /dev/null differ diff --git a/public/gfx/world_flags/cg.gif b/public/gfx/world_flags/cg.gif deleted file mode 100644 index e0a62a51..00000000 Binary files a/public/gfx/world_flags/cg.gif and /dev/null differ diff --git a/public/gfx/world_flags/ch.gif b/public/gfx/world_flags/ch.gif deleted file mode 100644 index d5c0e5b7..00000000 Binary files a/public/gfx/world_flags/ch.gif and /dev/null differ diff --git a/public/gfx/world_flags/ci.gif b/public/gfx/world_flags/ci.gif deleted file mode 100644 index 844120a5..00000000 Binary files a/public/gfx/world_flags/ci.gif and /dev/null differ diff --git a/public/gfx/world_flags/ck.gif b/public/gfx/world_flags/ck.gif deleted file mode 100644 index 2edb7399..00000000 Binary files a/public/gfx/world_flags/ck.gif and /dev/null differ diff --git a/public/gfx/world_flags/cl.gif b/public/gfx/world_flags/cl.gif deleted file mode 100644 index cbc370e6..00000000 Binary files a/public/gfx/world_flags/cl.gif and /dev/null differ diff --git a/public/gfx/world_flags/cm.gif b/public/gfx/world_flags/cm.gif deleted file mode 100644 index 1fb102b2..00000000 Binary files a/public/gfx/world_flags/cm.gif and /dev/null differ diff --git a/public/gfx/world_flags/cn.gif b/public/gfx/world_flags/cn.gif deleted file mode 100644 index b0525309..00000000 Binary files a/public/gfx/world_flags/cn.gif and /dev/null differ diff --git a/public/gfx/world_flags/co.gif b/public/gfx/world_flags/co.gif deleted file mode 100644 index d0e15caf..00000000 Binary files a/public/gfx/world_flags/co.gif and /dev/null differ diff --git a/public/gfx/world_flags/cr.gif b/public/gfx/world_flags/cr.gif deleted file mode 100644 index 0728dd6a..00000000 Binary files a/public/gfx/world_flags/cr.gif and /dev/null differ diff --git a/public/gfx/world_flags/cs.gif b/public/gfx/world_flags/cs.gif deleted file mode 100644 index 101db649..00000000 Binary files a/public/gfx/world_flags/cs.gif and /dev/null differ diff --git a/public/gfx/world_flags/cu.gif b/public/gfx/world_flags/cu.gif deleted file mode 100644 index 291255ca..00000000 Binary files a/public/gfx/world_flags/cu.gif and /dev/null differ diff --git a/public/gfx/world_flags/cv.gif b/public/gfx/world_flags/cv.gif deleted file mode 100644 index 43c6c6cb..00000000 Binary files a/public/gfx/world_flags/cv.gif and /dev/null differ diff --git a/public/gfx/world_flags/cx.gif b/public/gfx/world_flags/cx.gif deleted file mode 100644 index a5b43089..00000000 Binary files a/public/gfx/world_flags/cx.gif and /dev/null differ diff --git a/public/gfx/world_flags/cy.gif b/public/gfx/world_flags/cy.gif deleted file mode 100644 index 35c661e1..00000000 Binary files a/public/gfx/world_flags/cy.gif and /dev/null differ diff --git a/public/gfx/world_flags/cz.gif b/public/gfx/world_flags/cz.gif deleted file mode 100644 index 0a605e58..00000000 Binary files a/public/gfx/world_flags/cz.gif and /dev/null differ diff --git a/public/gfx/world_flags/de.gif b/public/gfx/world_flags/de.gif deleted file mode 100644 index 75728ddf..00000000 Binary files a/public/gfx/world_flags/de.gif and /dev/null differ diff --git a/public/gfx/world_flags/dj.gif b/public/gfx/world_flags/dj.gif deleted file mode 100644 index 212406d9..00000000 Binary files a/public/gfx/world_flags/dj.gif and /dev/null differ diff --git a/public/gfx/world_flags/dk.gif b/public/gfx/world_flags/dk.gif deleted file mode 100644 index 03e75bd2..00000000 Binary files a/public/gfx/world_flags/dk.gif and /dev/null differ diff --git a/public/gfx/world_flags/dm.gif b/public/gfx/world_flags/dm.gif deleted file mode 100644 index 2f87f3ca..00000000 Binary files a/public/gfx/world_flags/dm.gif and /dev/null differ diff --git a/public/gfx/world_flags/do.gif b/public/gfx/world_flags/do.gif deleted file mode 100644 index f7d0bad3..00000000 Binary files a/public/gfx/world_flags/do.gif and /dev/null differ diff --git a/public/gfx/world_flags/dz.gif b/public/gfx/world_flags/dz.gif deleted file mode 100644 index ed580a7c..00000000 Binary files a/public/gfx/world_flags/dz.gif and /dev/null differ diff --git a/public/gfx/world_flags/ec.gif b/public/gfx/world_flags/ec.gif deleted file mode 100644 index 9e41e0ec..00000000 Binary files a/public/gfx/world_flags/ec.gif and /dev/null differ diff --git a/public/gfx/world_flags/ee.gif b/public/gfx/world_flags/ee.gif deleted file mode 100644 index 9397a2d0..00000000 Binary files a/public/gfx/world_flags/ee.gif and /dev/null differ diff --git a/public/gfx/world_flags/eg.gif b/public/gfx/world_flags/eg.gif deleted file mode 100644 index 6857c7dd..00000000 Binary files a/public/gfx/world_flags/eg.gif and /dev/null differ diff --git a/public/gfx/world_flags/eh.gif b/public/gfx/world_flags/eh.gif deleted file mode 100644 index dd0391c2..00000000 Binary files a/public/gfx/world_flags/eh.gif and /dev/null differ diff --git a/public/gfx/world_flags/er.gif b/public/gfx/world_flags/er.gif deleted file mode 100644 index 3d4d612c..00000000 Binary files a/public/gfx/world_flags/er.gif and /dev/null differ diff --git a/public/gfx/world_flags/es.gif b/public/gfx/world_flags/es.gif deleted file mode 100644 index c27d65e5..00000000 Binary files a/public/gfx/world_flags/es.gif and /dev/null differ diff --git a/public/gfx/world_flags/et.gif b/public/gfx/world_flags/et.gif deleted file mode 100644 index f77995d0..00000000 Binary files a/public/gfx/world_flags/et.gif and /dev/null differ diff --git a/public/gfx/world_flags/fi.gif b/public/gfx/world_flags/fi.gif deleted file mode 100644 index 8d3a1918..00000000 Binary files a/public/gfx/world_flags/fi.gif and /dev/null differ diff --git a/public/gfx/world_flags/fj.gif b/public/gfx/world_flags/fj.gif deleted file mode 100644 index 486151cb..00000000 Binary files a/public/gfx/world_flags/fj.gif and /dev/null differ diff --git a/public/gfx/world_flags/fk.gif b/public/gfx/world_flags/fk.gif deleted file mode 100644 index 37b5ecf3..00000000 Binary files a/public/gfx/world_flags/fk.gif and /dev/null differ diff --git a/public/gfx/world_flags/fm.gif b/public/gfx/world_flags/fm.gif deleted file mode 100644 index 7f8723b7..00000000 Binary files a/public/gfx/world_flags/fm.gif and /dev/null differ diff --git a/public/gfx/world_flags/fo.gif b/public/gfx/world_flags/fo.gif deleted file mode 100644 index 4a90fc04..00000000 Binary files a/public/gfx/world_flags/fo.gif and /dev/null differ diff --git a/public/gfx/world_flags/fr.gif b/public/gfx/world_flags/fr.gif deleted file mode 100644 index 43d0b801..00000000 Binary files a/public/gfx/world_flags/fr.gif and /dev/null differ diff --git a/public/gfx/world_flags/ga.gif b/public/gfx/world_flags/ga.gif deleted file mode 100644 index 23fd5f0d..00000000 Binary files a/public/gfx/world_flags/ga.gif and /dev/null differ diff --git a/public/gfx/world_flags/gb.gif b/public/gfx/world_flags/gb.gif deleted file mode 100644 index 3c6bce15..00000000 Binary files a/public/gfx/world_flags/gb.gif and /dev/null differ diff --git a/public/gfx/world_flags/gd.gif b/public/gfx/world_flags/gd.gif deleted file mode 100644 index 25ea3123..00000000 Binary files a/public/gfx/world_flags/gd.gif and /dev/null differ diff --git a/public/gfx/world_flags/ge.gif b/public/gfx/world_flags/ge.gif deleted file mode 100644 index faa7f126..00000000 Binary files a/public/gfx/world_flags/ge.gif and /dev/null differ diff --git a/public/gfx/world_flags/gf.gif b/public/gfx/world_flags/gf.gif deleted file mode 100644 index 43d0b801..00000000 Binary files a/public/gfx/world_flags/gf.gif and /dev/null differ diff --git a/public/gfx/world_flags/gh.gif b/public/gfx/world_flags/gh.gif deleted file mode 100644 index 273fb7d1..00000000 Binary files a/public/gfx/world_flags/gh.gif and /dev/null differ diff --git a/public/gfx/world_flags/gi.gif b/public/gfx/world_flags/gi.gif deleted file mode 100644 index 7b1984bc..00000000 Binary files a/public/gfx/world_flags/gi.gif and /dev/null differ diff --git a/public/gfx/world_flags/gl.gif b/public/gfx/world_flags/gl.gif deleted file mode 100644 index ef445be0..00000000 Binary files a/public/gfx/world_flags/gl.gif and /dev/null differ diff --git a/public/gfx/world_flags/gm.gif b/public/gfx/world_flags/gm.gif deleted file mode 100644 index 6847c5a8..00000000 Binary files a/public/gfx/world_flags/gm.gif and /dev/null differ diff --git a/public/gfx/world_flags/gn.gif b/public/gfx/world_flags/gn.gif deleted file mode 100644 index a982ac6f..00000000 Binary files a/public/gfx/world_flags/gn.gif and /dev/null differ diff --git a/public/gfx/world_flags/gp.gif b/public/gfx/world_flags/gp.gif deleted file mode 100644 index 31166db6..00000000 Binary files a/public/gfx/world_flags/gp.gif and /dev/null differ diff --git a/public/gfx/world_flags/gq.gif b/public/gfx/world_flags/gq.gif deleted file mode 100644 index 8b4e0cc4..00000000 Binary files a/public/gfx/world_flags/gq.gif and /dev/null differ diff --git a/public/gfx/world_flags/gr.gif b/public/gfx/world_flags/gr.gif deleted file mode 100644 index b4c8c04e..00000000 Binary files a/public/gfx/world_flags/gr.gif and /dev/null differ diff --git a/public/gfx/world_flags/gs.gif b/public/gfx/world_flags/gs.gif deleted file mode 100644 index ccc96ec0..00000000 Binary files a/public/gfx/world_flags/gs.gif and /dev/null differ diff --git a/public/gfx/world_flags/gt.gif b/public/gfx/world_flags/gt.gif deleted file mode 100644 index 7e94d1dd..00000000 Binary files a/public/gfx/world_flags/gt.gif and /dev/null differ diff --git a/public/gfx/world_flags/gu.gif b/public/gfx/world_flags/gu.gif deleted file mode 100644 index eafef683..00000000 Binary files a/public/gfx/world_flags/gu.gif and /dev/null differ diff --git a/public/gfx/world_flags/gw.gif b/public/gfx/world_flags/gw.gif deleted file mode 100644 index 55f75711..00000000 Binary files a/public/gfx/world_flags/gw.gif and /dev/null differ diff --git a/public/gfx/world_flags/gy.gif b/public/gfx/world_flags/gy.gif deleted file mode 100644 index 1cb4cd71..00000000 Binary files a/public/gfx/world_flags/gy.gif and /dev/null differ diff --git a/public/gfx/world_flags/hk.gif b/public/gfx/world_flags/hk.gif deleted file mode 100644 index 798af96d..00000000 Binary files a/public/gfx/world_flags/hk.gif and /dev/null differ diff --git a/public/gfx/world_flags/hm.gif b/public/gfx/world_flags/hm.gif deleted file mode 100644 index 5269c6a0..00000000 Binary files a/public/gfx/world_flags/hm.gif and /dev/null differ diff --git a/public/gfx/world_flags/hn.gif b/public/gfx/world_flags/hn.gif deleted file mode 100644 index 6c4ffe8e..00000000 Binary files a/public/gfx/world_flags/hn.gif and /dev/null differ diff --git a/public/gfx/world_flags/hr.gif b/public/gfx/world_flags/hr.gif deleted file mode 100644 index 557c6602..00000000 Binary files a/public/gfx/world_flags/hr.gif and /dev/null differ diff --git a/public/gfx/world_flags/ht.gif b/public/gfx/world_flags/ht.gif deleted file mode 100644 index 059604ab..00000000 Binary files a/public/gfx/world_flags/ht.gif and /dev/null differ diff --git a/public/gfx/world_flags/hu.gif b/public/gfx/world_flags/hu.gif deleted file mode 100644 index 6142d868..00000000 Binary files a/public/gfx/world_flags/hu.gif and /dev/null differ diff --git a/public/gfx/world_flags/id.gif b/public/gfx/world_flags/id.gif deleted file mode 100644 index 865161b0..00000000 Binary files a/public/gfx/world_flags/id.gif and /dev/null differ diff --git a/public/gfx/world_flags/ie.gif b/public/gfx/world_flags/ie.gif deleted file mode 100644 index 506ad285..00000000 Binary files a/public/gfx/world_flags/ie.gif and /dev/null differ diff --git a/public/gfx/world_flags/il.gif b/public/gfx/world_flags/il.gif deleted file mode 100644 index c8483ae5..00000000 Binary files a/public/gfx/world_flags/il.gif and /dev/null differ diff --git a/public/gfx/world_flags/in.gif b/public/gfx/world_flags/in.gif deleted file mode 100644 index 1cd80272..00000000 Binary files a/public/gfx/world_flags/in.gif and /dev/null differ diff --git a/public/gfx/world_flags/io.gif b/public/gfx/world_flags/io.gif deleted file mode 100644 index de7e7ab3..00000000 Binary files a/public/gfx/world_flags/io.gif and /dev/null differ diff --git a/public/gfx/world_flags/iq.gif b/public/gfx/world_flags/iq.gif deleted file mode 100644 index c34fe3c4..00000000 Binary files a/public/gfx/world_flags/iq.gif and /dev/null differ diff --git a/public/gfx/world_flags/ir.gif b/public/gfx/world_flags/ir.gif deleted file mode 100644 index 156040fc..00000000 Binary files a/public/gfx/world_flags/ir.gif and /dev/null differ diff --git a/public/gfx/world_flags/is.gif b/public/gfx/world_flags/is.gif deleted file mode 100644 index b42502de..00000000 Binary files a/public/gfx/world_flags/is.gif and /dev/null differ diff --git a/public/gfx/world_flags/it.gif b/public/gfx/world_flags/it.gif deleted file mode 100644 index d79e90e9..00000000 Binary files a/public/gfx/world_flags/it.gif and /dev/null differ diff --git a/public/gfx/world_flags/jm.gif b/public/gfx/world_flags/jm.gif deleted file mode 100644 index 0bed67c2..00000000 Binary files a/public/gfx/world_flags/jm.gif and /dev/null differ diff --git a/public/gfx/world_flags/jo.gif b/public/gfx/world_flags/jo.gif deleted file mode 100644 index 03daf8af..00000000 Binary files a/public/gfx/world_flags/jo.gif and /dev/null differ diff --git a/public/gfx/world_flags/jp.gif b/public/gfx/world_flags/jp.gif deleted file mode 100644 index 444c1d05..00000000 Binary files a/public/gfx/world_flags/jp.gif and /dev/null differ diff --git a/public/gfx/world_flags/ke.gif b/public/gfx/world_flags/ke.gif deleted file mode 100644 index c2b5d45c..00000000 Binary files a/public/gfx/world_flags/ke.gif and /dev/null differ diff --git a/public/gfx/world_flags/kg.gif b/public/gfx/world_flags/kg.gif deleted file mode 100644 index 72a4d412..00000000 Binary files a/public/gfx/world_flags/kg.gif and /dev/null differ diff --git a/public/gfx/world_flags/kh.gif b/public/gfx/world_flags/kh.gif deleted file mode 100644 index 30a18315..00000000 Binary files a/public/gfx/world_flags/kh.gif and /dev/null differ diff --git a/public/gfx/world_flags/ki.gif b/public/gfx/world_flags/ki.gif deleted file mode 100644 index 4a0751a2..00000000 Binary files a/public/gfx/world_flags/ki.gif and /dev/null differ diff --git a/public/gfx/world_flags/km.gif b/public/gfx/world_flags/km.gif deleted file mode 100644 index 5859595e..00000000 Binary files a/public/gfx/world_flags/km.gif and /dev/null differ diff --git a/public/gfx/world_flags/kn.gif b/public/gfx/world_flags/kn.gif deleted file mode 100644 index bb9cc34a..00000000 Binary files a/public/gfx/world_flags/kn.gif and /dev/null differ diff --git a/public/gfx/world_flags/kp.gif b/public/gfx/world_flags/kp.gif deleted file mode 100644 index 6e0ca09e..00000000 Binary files a/public/gfx/world_flags/kp.gif and /dev/null differ diff --git a/public/gfx/world_flags/kr.gif b/public/gfx/world_flags/kr.gif deleted file mode 100644 index 1cddbe75..00000000 Binary files a/public/gfx/world_flags/kr.gif and /dev/null differ diff --git a/public/gfx/world_flags/kw.gif b/public/gfx/world_flags/kw.gif deleted file mode 100644 index 1efc7347..00000000 Binary files a/public/gfx/world_flags/kw.gif and /dev/null differ diff --git a/public/gfx/world_flags/ky.gif b/public/gfx/world_flags/ky.gif deleted file mode 100644 index d3d02ee4..00000000 Binary files a/public/gfx/world_flags/ky.gif and /dev/null differ diff --git a/public/gfx/world_flags/kz.gif b/public/gfx/world_flags/kz.gif deleted file mode 100644 index 24baebe0..00000000 Binary files a/public/gfx/world_flags/kz.gif and /dev/null differ diff --git a/public/gfx/world_flags/la.gif b/public/gfx/world_flags/la.gif deleted file mode 100644 index d14cf4d8..00000000 Binary files a/public/gfx/world_flags/la.gif and /dev/null differ diff --git a/public/gfx/world_flags/lb.gif b/public/gfx/world_flags/lb.gif deleted file mode 100644 index 003d83af..00000000 Binary files a/public/gfx/world_flags/lb.gif and /dev/null differ diff --git a/public/gfx/world_flags/lc.gif b/public/gfx/world_flags/lc.gif deleted file mode 100644 index f5fe5bff..00000000 Binary files a/public/gfx/world_flags/lc.gif and /dev/null differ diff --git a/public/gfx/world_flags/li.gif b/public/gfx/world_flags/li.gif deleted file mode 100644 index 713c58e1..00000000 Binary files a/public/gfx/world_flags/li.gif and /dev/null differ diff --git a/public/gfx/world_flags/lk.gif b/public/gfx/world_flags/lk.gif deleted file mode 100644 index 1b3ee7f5..00000000 Binary files a/public/gfx/world_flags/lk.gif and /dev/null differ diff --git a/public/gfx/world_flags/lr.gif b/public/gfx/world_flags/lr.gif deleted file mode 100644 index 435af9e5..00000000 Binary files a/public/gfx/world_flags/lr.gif and /dev/null differ diff --git a/public/gfx/world_flags/ls.gif b/public/gfx/world_flags/ls.gif deleted file mode 100644 index 427ae957..00000000 Binary files a/public/gfx/world_flags/ls.gif and /dev/null differ diff --git a/public/gfx/world_flags/lt.gif b/public/gfx/world_flags/lt.gif deleted file mode 100644 index dee9c601..00000000 Binary files a/public/gfx/world_flags/lt.gif and /dev/null differ diff --git a/public/gfx/world_flags/lu.gif b/public/gfx/world_flags/lu.gif deleted file mode 100644 index 7d7293ed..00000000 Binary files a/public/gfx/world_flags/lu.gif and /dev/null differ diff --git a/public/gfx/world_flags/lv.gif b/public/gfx/world_flags/lv.gif deleted file mode 100644 index 17e71b7e..00000000 Binary files a/public/gfx/world_flags/lv.gif and /dev/null differ diff --git a/public/gfx/world_flags/ly.gif b/public/gfx/world_flags/ly.gif deleted file mode 100644 index a654c30a..00000000 Binary files a/public/gfx/world_flags/ly.gif and /dev/null differ diff --git a/public/gfx/world_flags/ma.gif b/public/gfx/world_flags/ma.gif deleted file mode 100644 index fc784119..00000000 Binary files a/public/gfx/world_flags/ma.gif and /dev/null differ diff --git a/public/gfx/world_flags/mc.gif b/public/gfx/world_flags/mc.gif deleted file mode 100644 index 02a7c8e1..00000000 Binary files a/public/gfx/world_flags/mc.gif and /dev/null differ diff --git a/public/gfx/world_flags/md.gif b/public/gfx/world_flags/md.gif deleted file mode 100644 index e4b8a7e3..00000000 Binary files a/public/gfx/world_flags/md.gif and /dev/null differ diff --git a/public/gfx/world_flags/me.gif b/public/gfx/world_flags/me.gif deleted file mode 100644 index a260453c..00000000 Binary files a/public/gfx/world_flags/me.gif and /dev/null differ diff --git a/public/gfx/world_flags/mg.gif b/public/gfx/world_flags/mg.gif deleted file mode 100644 index a91b577d..00000000 Binary files a/public/gfx/world_flags/mg.gif and /dev/null differ diff --git a/public/gfx/world_flags/mh.gif b/public/gfx/world_flags/mh.gif deleted file mode 100644 index 92f5f485..00000000 Binary files a/public/gfx/world_flags/mh.gif and /dev/null differ diff --git a/public/gfx/world_flags/mk.gif b/public/gfx/world_flags/mk.gif deleted file mode 100644 index 7aeb8311..00000000 Binary files a/public/gfx/world_flags/mk.gif and /dev/null differ diff --git a/public/gfx/world_flags/ml.gif b/public/gfx/world_flags/ml.gif deleted file mode 100644 index 53d6f490..00000000 Binary files a/public/gfx/world_flags/ml.gif and /dev/null differ diff --git a/public/gfx/world_flags/mm.gif b/public/gfx/world_flags/mm.gif deleted file mode 100644 index 9e0a2756..00000000 Binary files a/public/gfx/world_flags/mm.gif and /dev/null differ diff --git a/public/gfx/world_flags/mn.gif b/public/gfx/world_flags/mn.gif deleted file mode 100644 index dff8ea5a..00000000 Binary files a/public/gfx/world_flags/mn.gif and /dev/null differ diff --git a/public/gfx/world_flags/mo.gif b/public/gfx/world_flags/mo.gif deleted file mode 100644 index 66cf5b4f..00000000 Binary files a/public/gfx/world_flags/mo.gif and /dev/null differ diff --git a/public/gfx/world_flags/mp.gif b/public/gfx/world_flags/mp.gif deleted file mode 100644 index 73b7147e..00000000 Binary files a/public/gfx/world_flags/mp.gif and /dev/null differ diff --git a/public/gfx/world_flags/mq.gif b/public/gfx/world_flags/mq.gif deleted file mode 100644 index 570bc5dd..00000000 Binary files a/public/gfx/world_flags/mq.gif and /dev/null differ diff --git a/public/gfx/world_flags/mr.gif b/public/gfx/world_flags/mr.gif deleted file mode 100644 index f52fcf09..00000000 Binary files a/public/gfx/world_flags/mr.gif and /dev/null differ diff --git a/public/gfx/world_flags/ms.gif b/public/gfx/world_flags/ms.gif deleted file mode 100644 index 5e5a67aa..00000000 Binary files a/public/gfx/world_flags/ms.gif and /dev/null differ diff --git a/public/gfx/world_flags/mt.gif b/public/gfx/world_flags/mt.gif deleted file mode 100644 index 45c709f2..00000000 Binary files a/public/gfx/world_flags/mt.gif and /dev/null differ diff --git a/public/gfx/world_flags/mu.gif b/public/gfx/world_flags/mu.gif deleted file mode 100644 index 081ab453..00000000 Binary files a/public/gfx/world_flags/mu.gif and /dev/null differ diff --git a/public/gfx/world_flags/mv.gif b/public/gfx/world_flags/mv.gif deleted file mode 100644 index 46b63875..00000000 Binary files a/public/gfx/world_flags/mv.gif and /dev/null differ diff --git a/public/gfx/world_flags/mw.gif b/public/gfx/world_flags/mw.gif deleted file mode 100644 index ad045a09..00000000 Binary files a/public/gfx/world_flags/mw.gif and /dev/null differ diff --git a/public/gfx/world_flags/mx.gif b/public/gfx/world_flags/mx.gif deleted file mode 100644 index ddc75d04..00000000 Binary files a/public/gfx/world_flags/mx.gif and /dev/null differ diff --git a/public/gfx/world_flags/my.gif b/public/gfx/world_flags/my.gif deleted file mode 100644 index fc7d5236..00000000 Binary files a/public/gfx/world_flags/my.gif and /dev/null differ diff --git a/public/gfx/world_flags/mz.gif b/public/gfx/world_flags/mz.gif deleted file mode 100644 index 7d635082..00000000 Binary files a/public/gfx/world_flags/mz.gif and /dev/null differ diff --git a/public/gfx/world_flags/na.gif b/public/gfx/world_flags/na.gif deleted file mode 100644 index c0babe72..00000000 Binary files a/public/gfx/world_flags/na.gif and /dev/null differ diff --git a/public/gfx/world_flags/nc.gif b/public/gfx/world_flags/nc.gif deleted file mode 100644 index b1e91b9a..00000000 Binary files a/public/gfx/world_flags/nc.gif and /dev/null differ diff --git a/public/gfx/world_flags/ne.gif b/public/gfx/world_flags/ne.gif deleted file mode 100644 index ff4eaf07..00000000 Binary files a/public/gfx/world_flags/ne.gif and /dev/null differ diff --git a/public/gfx/world_flags/nf.gif b/public/gfx/world_flags/nf.gif deleted file mode 100644 index c83424c2..00000000 Binary files a/public/gfx/world_flags/nf.gif and /dev/null differ diff --git a/public/gfx/world_flags/ng.gif b/public/gfx/world_flags/ng.gif deleted file mode 100644 index bdde7cb3..00000000 Binary files a/public/gfx/world_flags/ng.gif and /dev/null differ diff --git a/public/gfx/world_flags/ni.gif b/public/gfx/world_flags/ni.gif deleted file mode 100644 index d05894d0..00000000 Binary files a/public/gfx/world_flags/ni.gif and /dev/null differ diff --git a/public/gfx/world_flags/nl.gif b/public/gfx/world_flags/nl.gif deleted file mode 100644 index c1c8f46d..00000000 Binary files a/public/gfx/world_flags/nl.gif and /dev/null differ diff --git a/public/gfx/world_flags/no.gif b/public/gfx/world_flags/no.gif deleted file mode 100644 index 6202d1f3..00000000 Binary files a/public/gfx/world_flags/no.gif and /dev/null differ diff --git a/public/gfx/world_flags/none.png b/public/gfx/world_flags/none.png deleted file mode 100644 index 1fc86ad4..00000000 Binary files a/public/gfx/world_flags/none.png and /dev/null differ diff --git a/public/gfx/world_flags/np.gif b/public/gfx/world_flags/np.gif deleted file mode 100644 index 1096893a..00000000 Binary files a/public/gfx/world_flags/np.gif and /dev/null differ diff --git a/public/gfx/world_flags/nr.gif b/public/gfx/world_flags/nr.gif deleted file mode 100644 index 2e4c0c5c..00000000 Binary files a/public/gfx/world_flags/nr.gif and /dev/null differ diff --git a/public/gfx/world_flags/nu.gif b/public/gfx/world_flags/nu.gif deleted file mode 100644 index 618210a7..00000000 Binary files a/public/gfx/world_flags/nu.gif and /dev/null differ diff --git a/public/gfx/world_flags/null.gif b/public/gfx/world_flags/null.gif deleted file mode 100644 index 742879c9..00000000 Binary files a/public/gfx/world_flags/null.gif and /dev/null differ diff --git a/public/gfx/world_flags/nz.gif b/public/gfx/world_flags/nz.gif deleted file mode 100644 index 028a5dc6..00000000 Binary files a/public/gfx/world_flags/nz.gif and /dev/null differ diff --git a/public/gfx/world_flags/om.gif b/public/gfx/world_flags/om.gif deleted file mode 100644 index 2b8c7750..00000000 Binary files a/public/gfx/world_flags/om.gif and /dev/null differ diff --git a/public/gfx/world_flags/pa.gif b/public/gfx/world_flags/pa.gif deleted file mode 100644 index d518b2f9..00000000 Binary files a/public/gfx/world_flags/pa.gif and /dev/null differ diff --git a/public/gfx/world_flags/pe.gif b/public/gfx/world_flags/pe.gif deleted file mode 100644 index 3bc76390..00000000 Binary files a/public/gfx/world_flags/pe.gif and /dev/null differ diff --git a/public/gfx/world_flags/pf.gif b/public/gfx/world_flags/pf.gif deleted file mode 100644 index 849297a5..00000000 Binary files a/public/gfx/world_flags/pf.gif and /dev/null differ diff --git a/public/gfx/world_flags/pg.gif b/public/gfx/world_flags/pg.gif deleted file mode 100644 index 2d20b078..00000000 Binary files a/public/gfx/world_flags/pg.gif and /dev/null differ diff --git a/public/gfx/world_flags/ph.gif b/public/gfx/world_flags/ph.gif deleted file mode 100644 index 12b380ac..00000000 Binary files a/public/gfx/world_flags/ph.gif and /dev/null differ diff --git a/public/gfx/world_flags/pk.gif b/public/gfx/world_flags/pk.gif deleted file mode 100644 index f3f62c2e..00000000 Binary files a/public/gfx/world_flags/pk.gif and /dev/null differ diff --git a/public/gfx/world_flags/pl.gif b/public/gfx/world_flags/pl.gif deleted file mode 100644 index bf106463..00000000 Binary files a/public/gfx/world_flags/pl.gif and /dev/null differ diff --git a/public/gfx/world_flags/pm.gif b/public/gfx/world_flags/pm.gif deleted file mode 100644 index 99bf6fdb..00000000 Binary files a/public/gfx/world_flags/pm.gif and /dev/null differ diff --git a/public/gfx/world_flags/pn.gif b/public/gfx/world_flags/pn.gif deleted file mode 100644 index 4bc86a1d..00000000 Binary files a/public/gfx/world_flags/pn.gif and /dev/null differ diff --git a/public/gfx/world_flags/pr.gif b/public/gfx/world_flags/pr.gif deleted file mode 100644 index 6d5d5896..00000000 Binary files a/public/gfx/world_flags/pr.gif and /dev/null differ diff --git a/public/gfx/world_flags/ps.gif b/public/gfx/world_flags/ps.gif deleted file mode 100644 index 6afa3b71..00000000 Binary files a/public/gfx/world_flags/ps.gif and /dev/null differ diff --git a/public/gfx/world_flags/pt.gif b/public/gfx/world_flags/pt.gif deleted file mode 100644 index e735f740..00000000 Binary files a/public/gfx/world_flags/pt.gif and /dev/null differ diff --git a/public/gfx/world_flags/pw.gif b/public/gfx/world_flags/pw.gif deleted file mode 100644 index 5854510f..00000000 Binary files a/public/gfx/world_flags/pw.gif and /dev/null differ diff --git a/public/gfx/world_flags/py.gif b/public/gfx/world_flags/py.gif deleted file mode 100644 index f2e66af7..00000000 Binary files a/public/gfx/world_flags/py.gif and /dev/null differ diff --git a/public/gfx/world_flags/qa.gif b/public/gfx/world_flags/qa.gif deleted file mode 100644 index 2e843ff9..00000000 Binary files a/public/gfx/world_flags/qa.gif and /dev/null differ diff --git a/public/gfx/world_flags/re.gif b/public/gfx/world_flags/re.gif deleted file mode 100644 index 43d0b801..00000000 Binary files a/public/gfx/world_flags/re.gif and /dev/null differ diff --git a/public/gfx/world_flags/ro.gif b/public/gfx/world_flags/ro.gif deleted file mode 100644 index f5d5f125..00000000 Binary files a/public/gfx/world_flags/ro.gif and /dev/null differ diff --git a/public/gfx/world_flags/rs.gif b/public/gfx/world_flags/rs.gif deleted file mode 100644 index 3bd1fb2f..00000000 Binary files a/public/gfx/world_flags/rs.gif and /dev/null differ diff --git a/public/gfx/world_flags/ru.gif b/public/gfx/world_flags/ru.gif deleted file mode 100644 index b525c462..00000000 Binary files a/public/gfx/world_flags/ru.gif and /dev/null differ diff --git a/public/gfx/world_flags/rw.gif b/public/gfx/world_flags/rw.gif deleted file mode 100644 index 0d095f7a..00000000 Binary files a/public/gfx/world_flags/rw.gif and /dev/null differ diff --git a/public/gfx/world_flags/sa.gif b/public/gfx/world_flags/sa.gif deleted file mode 100644 index 179961b6..00000000 Binary files a/public/gfx/world_flags/sa.gif and /dev/null differ diff --git a/public/gfx/world_flags/sb.gif b/public/gfx/world_flags/sb.gif deleted file mode 100644 index 8f5ff837..00000000 Binary files a/public/gfx/world_flags/sb.gif and /dev/null differ diff --git a/public/gfx/world_flags/sc.gif b/public/gfx/world_flags/sc.gif deleted file mode 100644 index 31b47677..00000000 Binary files a/public/gfx/world_flags/sc.gif and /dev/null differ diff --git a/public/gfx/world_flags/sd.gif b/public/gfx/world_flags/sd.gif deleted file mode 100644 index 53ae214f..00000000 Binary files a/public/gfx/world_flags/sd.gif and /dev/null differ diff --git a/public/gfx/world_flags/se.gif b/public/gfx/world_flags/se.gif deleted file mode 100644 index 80f62852..00000000 Binary files a/public/gfx/world_flags/se.gif and /dev/null differ diff --git a/public/gfx/world_flags/sg.gif b/public/gfx/world_flags/sg.gif deleted file mode 100644 index 5663d39f..00000000 Binary files a/public/gfx/world_flags/sg.gif and /dev/null differ diff --git a/public/gfx/world_flags/sh.gif b/public/gfx/world_flags/sh.gif deleted file mode 100644 index dcc7f3bc..00000000 Binary files a/public/gfx/world_flags/sh.gif and /dev/null differ diff --git a/public/gfx/world_flags/si.gif b/public/gfx/world_flags/si.gif deleted file mode 100644 index 23852b50..00000000 Binary files a/public/gfx/world_flags/si.gif and /dev/null differ diff --git a/public/gfx/world_flags/sj.gif b/public/gfx/world_flags/sj.gif deleted file mode 100644 index 6202d1f3..00000000 Binary files a/public/gfx/world_flags/sj.gif and /dev/null differ diff --git a/public/gfx/world_flags/sk.gif b/public/gfx/world_flags/sk.gif deleted file mode 100644 index 1b3f22ba..00000000 Binary files a/public/gfx/world_flags/sk.gif and /dev/null differ diff --git a/public/gfx/world_flags/sl.gif b/public/gfx/world_flags/sl.gif deleted file mode 100644 index f0f34923..00000000 Binary files a/public/gfx/world_flags/sl.gif and /dev/null differ diff --git a/public/gfx/world_flags/sm.gif b/public/gfx/world_flags/sm.gif deleted file mode 100644 index 04d98de5..00000000 Binary files a/public/gfx/world_flags/sm.gif and /dev/null differ diff --git a/public/gfx/world_flags/sn.gif b/public/gfx/world_flags/sn.gif deleted file mode 100644 index 6dac8709..00000000 Binary files a/public/gfx/world_flags/sn.gif and /dev/null differ diff --git a/public/gfx/world_flags/so.gif b/public/gfx/world_flags/so.gif deleted file mode 100644 index f1961694..00000000 Binary files a/public/gfx/world_flags/so.gif and /dev/null differ diff --git a/public/gfx/world_flags/sr.gif b/public/gfx/world_flags/sr.gif deleted file mode 100644 index 0f7499ad..00000000 Binary files a/public/gfx/world_flags/sr.gif and /dev/null differ diff --git a/public/gfx/world_flags/st.gif b/public/gfx/world_flags/st.gif deleted file mode 100644 index 4f1e6e09..00000000 Binary files a/public/gfx/world_flags/st.gif and /dev/null differ diff --git a/public/gfx/world_flags/sv.gif b/public/gfx/world_flags/sv.gif deleted file mode 100644 index 2d7b159a..00000000 Binary files a/public/gfx/world_flags/sv.gif and /dev/null differ diff --git a/public/gfx/world_flags/sy.gif b/public/gfx/world_flags/sy.gif deleted file mode 100644 index dc8bd509..00000000 Binary files a/public/gfx/world_flags/sy.gif and /dev/null differ diff --git a/public/gfx/world_flags/sz.gif b/public/gfx/world_flags/sz.gif deleted file mode 100644 index f37aaf80..00000000 Binary files a/public/gfx/world_flags/sz.gif and /dev/null differ diff --git a/public/gfx/world_flags/tc.gif b/public/gfx/world_flags/tc.gif deleted file mode 100644 index 11a8c232..00000000 Binary files a/public/gfx/world_flags/tc.gif and /dev/null differ diff --git a/public/gfx/world_flags/td.gif b/public/gfx/world_flags/td.gif deleted file mode 100644 index 7aa8a10d..00000000 Binary files a/public/gfx/world_flags/td.gif and /dev/null differ diff --git a/public/gfx/world_flags/tf.gif b/public/gfx/world_flags/tf.gif deleted file mode 100644 index 51a43250..00000000 Binary files a/public/gfx/world_flags/tf.gif and /dev/null differ diff --git a/public/gfx/world_flags/tg.gif b/public/gfx/world_flags/tg.gif deleted file mode 100644 index ca6b4e77..00000000 Binary files a/public/gfx/world_flags/tg.gif and /dev/null differ diff --git a/public/gfx/world_flags/th.gif b/public/gfx/world_flags/th.gif deleted file mode 100644 index 01307924..00000000 Binary files a/public/gfx/world_flags/th.gif and /dev/null differ diff --git a/public/gfx/world_flags/tj.gif b/public/gfx/world_flags/tj.gif deleted file mode 100644 index 2fe38d4a..00000000 Binary files a/public/gfx/world_flags/tj.gif and /dev/null differ diff --git a/public/gfx/world_flags/tk.gif b/public/gfx/world_flags/tk.gif deleted file mode 100644 index 3d3a727f..00000000 Binary files a/public/gfx/world_flags/tk.gif and /dev/null differ diff --git a/public/gfx/world_flags/tl.gif b/public/gfx/world_flags/tl.gif deleted file mode 100644 index df22d582..00000000 Binary files a/public/gfx/world_flags/tl.gif and /dev/null differ diff --git a/public/gfx/world_flags/tm.gif b/public/gfx/world_flags/tm.gif deleted file mode 100644 index 36d0994f..00000000 Binary files a/public/gfx/world_flags/tm.gif and /dev/null differ diff --git a/public/gfx/world_flags/tn.gif b/public/gfx/world_flags/tn.gif deleted file mode 100644 index 917d4288..00000000 Binary files a/public/gfx/world_flags/tn.gif and /dev/null differ diff --git a/public/gfx/world_flags/to.gif b/public/gfx/world_flags/to.gif deleted file mode 100644 index d7ed4d11..00000000 Binary files a/public/gfx/world_flags/to.gif and /dev/null differ diff --git a/public/gfx/world_flags/tr.gif b/public/gfx/world_flags/tr.gif deleted file mode 100644 index e407d553..00000000 Binary files a/public/gfx/world_flags/tr.gif and /dev/null differ diff --git a/public/gfx/world_flags/tt.gif b/public/gfx/world_flags/tt.gif deleted file mode 100644 index 47d3b806..00000000 Binary files a/public/gfx/world_flags/tt.gif and /dev/null differ diff --git a/public/gfx/world_flags/tv.gif b/public/gfx/world_flags/tv.gif deleted file mode 100644 index 3c338277..00000000 Binary files a/public/gfx/world_flags/tv.gif and /dev/null differ diff --git a/public/gfx/world_flags/tw.gif b/public/gfx/world_flags/tw.gif deleted file mode 100644 index 4faf08a3..00000000 Binary files a/public/gfx/world_flags/tw.gif and /dev/null differ diff --git a/public/gfx/world_flags/tz.gif b/public/gfx/world_flags/tz.gif deleted file mode 100644 index 82b52ca2..00000000 Binary files a/public/gfx/world_flags/tz.gif and /dev/null differ diff --git a/public/gfx/world_flags/ua.gif b/public/gfx/world_flags/ua.gif deleted file mode 100644 index 5d6cd83f..00000000 Binary files a/public/gfx/world_flags/ua.gif and /dev/null differ diff --git a/public/gfx/world_flags/ug.gif b/public/gfx/world_flags/ug.gif deleted file mode 100644 index 58b731ad..00000000 Binary files a/public/gfx/world_flags/ug.gif and /dev/null differ diff --git a/public/gfx/world_flags/um.gif b/public/gfx/world_flags/um.gif deleted file mode 100644 index 3b4c8483..00000000 Binary files a/public/gfx/world_flags/um.gif and /dev/null differ diff --git a/public/gfx/world_flags/us.gif b/public/gfx/world_flags/us.gif deleted file mode 100644 index 8f198f73..00000000 Binary files a/public/gfx/world_flags/us.gif and /dev/null differ diff --git a/public/gfx/world_flags/uy.gif b/public/gfx/world_flags/uy.gif deleted file mode 100644 index 12848c74..00000000 Binary files a/public/gfx/world_flags/uy.gif and /dev/null differ diff --git a/public/gfx/world_flags/uz.gif b/public/gfx/world_flags/uz.gif deleted file mode 100644 index dc9daeca..00000000 Binary files a/public/gfx/world_flags/uz.gif and /dev/null differ diff --git a/public/gfx/world_flags/va.gif b/public/gfx/world_flags/va.gif deleted file mode 100644 index 2bd74468..00000000 Binary files a/public/gfx/world_flags/va.gif and /dev/null differ diff --git a/public/gfx/world_flags/vc.gif b/public/gfx/world_flags/vc.gif deleted file mode 100644 index 48213816..00000000 Binary files a/public/gfx/world_flags/vc.gif and /dev/null differ diff --git a/public/gfx/world_flags/ve.gif b/public/gfx/world_flags/ve.gif deleted file mode 100644 index 19ce6c14..00000000 Binary files a/public/gfx/world_flags/ve.gif and /dev/null differ diff --git a/public/gfx/world_flags/vg.gif b/public/gfx/world_flags/vg.gif deleted file mode 100644 index 1fc0f96e..00000000 Binary files a/public/gfx/world_flags/vg.gif and /dev/null differ diff --git a/public/gfx/world_flags/vi.gif b/public/gfx/world_flags/vi.gif deleted file mode 100644 index 66f9e746..00000000 Binary files a/public/gfx/world_flags/vi.gif and /dev/null differ diff --git a/public/gfx/world_flags/vn.gif b/public/gfx/world_flags/vn.gif deleted file mode 100644 index f1e20c94..00000000 Binary files a/public/gfx/world_flags/vn.gif and /dev/null differ diff --git a/public/gfx/world_flags/vu.gif b/public/gfx/world_flags/vu.gif deleted file mode 100644 index 8a8b2b06..00000000 Binary files a/public/gfx/world_flags/vu.gif and /dev/null differ diff --git a/public/gfx/world_flags/wf.gif b/public/gfx/world_flags/wf.gif deleted file mode 100644 index eaa954b1..00000000 Binary files a/public/gfx/world_flags/wf.gif and /dev/null differ diff --git a/public/gfx/world_flags/ws.gif b/public/gfx/world_flags/ws.gif deleted file mode 100644 index a51f939e..00000000 Binary files a/public/gfx/world_flags/ws.gif and /dev/null differ diff --git a/public/gfx/world_flags/ye.gif b/public/gfx/world_flags/ye.gif deleted file mode 100644 index 7b0183d0..00000000 Binary files a/public/gfx/world_flags/ye.gif and /dev/null differ diff --git a/public/gfx/world_flags/yt.gif b/public/gfx/world_flags/yt.gif deleted file mode 100644 index a2267c05..00000000 Binary files a/public/gfx/world_flags/yt.gif and /dev/null differ diff --git a/public/gfx/world_flags/za.gif b/public/gfx/world_flags/za.gif deleted file mode 100644 index ede52589..00000000 Binary files a/public/gfx/world_flags/za.gif and /dev/null differ diff --git a/public/gfx/world_flags/zm.gif b/public/gfx/world_flags/zm.gif deleted file mode 100644 index b2851d2b..00000000 Binary files a/public/gfx/world_flags/zm.gif and /dev/null differ diff --git a/public/gfx/world_flags/zw.gif b/public/gfx/world_flags/zw.gif deleted file mode 100644 index 02901f62..00000000 Binary files a/public/gfx/world_flags/zw.gif and /dev/null differ diff --git a/public/gfx/world_flags/zz.gif b/public/gfx/world_flags/zz.gif deleted file mode 100644 index b666c63c..00000000 Binary files a/public/gfx/world_flags/zz.gif and /dev/null differ diff --git a/public/gfx/xmasLogo.jpg b/public/gfx/xmasLogo.jpg deleted file mode 100644 index e3d73fd4..00000000 Binary files a/public/gfx/xmasLogo.jpg and /dev/null differ diff --git a/public/gfx/xmasLogoT.gif b/public/gfx/xmasLogoT.gif deleted file mode 100644 index b1fb1994..00000000 Binary files a/public/gfx/xmasLogoT.gif and /dev/null differ diff --git a/public/gfx/xmasLogoT.jpg b/public/gfx/xmasLogoT.jpg deleted file mode 100644 index b1fb1994..00000000 Binary files a/public/gfx/xmasLogoT.jpg and /dev/null differ diff --git a/public/gfx/xmasRight.jpg b/public/gfx/xmasRight.jpg deleted file mode 100644 index d0fad913..00000000 Binary files a/public/gfx/xmasRight.jpg and /dev/null differ diff --git a/public/gfx/xmas_sb.jpg b/public/gfx/xmas_sb.jpg deleted file mode 100644 index c5f0ec13..00000000 Binary files a/public/gfx/xmas_sb.jpg and /dev/null differ diff --git a/public/gfx/xmastree.gif b/public/gfx/xmastree.gif deleted file mode 100644 index 3868402a..00000000 Binary files a/public/gfx/xmastree.gif and /dev/null differ diff --git a/public/gfx/xmastree_big.jpg b/public/gfx/xmastree_big.jpg deleted file mode 100644 index b37cc779..00000000 Binary files a/public/gfx/xmastree_big.jpg and /dev/null differ diff --git a/resources/css/app.css b/resources/css/app.css index b5c61c95..40fa5a9e 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -1,3 +1,65 @@ @tailwind base; @tailwind components; @tailwind utilities; + +.form-label { + @apply block text-sm text-soft mb-1; +} + +.form-input { + @apply w-full bg-deep border border-nova-500/30 rounded-lg px-4 py-2 + text-white placeholder-gray-500 + focus:outline-none focus:ring-2 focus:ring-accent; +} + +.form-textarea { + @apply w-full bg-deep border border-nova-500/30 rounded-lg px-4 py-2 + text-white resize-none + focus:outline-none focus:ring-2 focus:ring-accent; +} + +.form-file { + @apply w-full text-sm text-soft + file:bg-panel file:border-0 file:px-4 file:py-2 + file:rounded-lg file:text-white + hover:file:bg-nova-600/40; +} + +.btn-primary { + @apply bg-accent text-deep px-6 py-2 rounded-lg + font-medium hover:brightness-110 transition; +} + +.btn-secondary { + @apply bg-nova-500/30 text-white px-5 py-2 rounded-lg + hover:bg-nova-500/50 transition; +} + +@layer components { + /* Ensure plain inputs, textareas and selects match the dark form styles + so we don't end up with white backgrounds + white text. */ + input, + input[type="text"], + input[type="email"], + input[type="password"], + textarea, + select { + @apply bg-deep text-white border border-nova-500/30 rounded-lg px-4 py-2 + placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-accent; + } + + /* Keep file inputs styled separately (file controls use .form-file class). + This prevents the native file button from inheriting the same padding. */ + input[type="file"] { + @apply bg-transparent text-soft p-0; + } +} + + +@layer base { + *,:before,:after { + box-sizing: border-box; + border: 0 solid transparent; + } +} + diff --git a/resources/js/Pages/Admin/UploadQueue.jsx b/resources/js/Pages/Admin/UploadQueue.jsx new file mode 100644 index 00000000..540b80d2 --- /dev/null +++ b/resources/js/Pages/Admin/UploadQueue.jsx @@ -0,0 +1,6 @@ +import React from 'react' +import AdminUploadQueue from '../../components/admin/AdminUploadQueue' + +export default function UploadQueuePage() { + return +} diff --git a/resources/js/Pages/Upload/Index.jsx b/resources/js/Pages/Upload/Index.jsx new file mode 100644 index 00000000..515351d1 --- /dev/null +++ b/resources/js/Pages/Upload/Index.jsx @@ -0,0 +1,1035 @@ +import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react' +import { usePage } from '@inertiajs/react' +import TagInput from '../../components/tags/TagInput' +import UploadWizard from '../../components/upload/UploadWizard' + +const phases = { + idle: 'idle', + initializing: 'initializing', + ready: 'ready', + uploading: 'uploading', + finishing: 'finishing', + polling: 'polling', + cancelling: 'cancelling', + success: 'success', + error: 'error', +} + +const initialState = { + phase: phases.idle, + sessionId: null, + uploadToken: null, + file: null, + filePreviewUrl: null, + previewUrl: null, + progress: 0, + pipelineStatus: null, + failureReason: null, + error: null, + cancelledAt: null, + notices: [], + artworkId: null, + draftId: null, + metadata: { + title: '', + type: '', + category: '', + tags: '', + description: '', + licenseAccepted: false, + }, +} + +const STORAGE_VERSION = 1 + +function storageKey(userId) { + return `sb.upload.session.${userId}.v${STORAGE_VERSION}` +} + +function readStoredSession(userId) { + try { + const raw = window.localStorage.getItem(storageKey(userId)) + if (!raw) return null + const parsed = JSON.parse(raw) + if (!parsed || typeof parsed !== 'object') return null + return parsed + } catch (error) { + return null + } +} + +function writeStoredSession(userId, payload) { + try { + window.localStorage.setItem(storageKey(userId), JSON.stringify(payload)) + } catch (error) { + // ignore write failures + } +} + +function clearStoredSession(userId) { + try { + window.localStorage.removeItem(storageKey(userId)) + } catch (error) { + // ignore removal failures + } +} + +function reducer(state, action) { + switch (action.type) { + case 'SET_DRAFT': + return { ...state, draftId: action.draftId, artworkId: action.artworkId ?? state.artworkId } + case 'SET_FILE': + return { ...state, file: action.file, filePreviewUrl: action.previewUrl, error: null, cancelledAt: null } + case 'SET_METADATA': + return { ...state, metadata: { ...state.metadata, ...action.payload } } + case 'INIT_START': + return { ...state, phase: phases.initializing, error: null, cancelledAt: null } + case 'INIT_SUCCESS': + return { ...state, phase: phases.ready, sessionId: action.sessionId, uploadToken: action.uploadToken, pipelineStatus: action.status } + case 'RESTORE_SESSION': + return { ...state, phase: phases.ready, sessionId: action.sessionId, uploadToken: action.uploadToken, pipelineStatus: action.status ?? state.pipelineStatus } + case 'RESUME_SESSION': + return { ...state, phase: phases.polling, sessionId: action.sessionId, pipelineStatus: action.status ?? state.pipelineStatus } + case 'INIT_ERROR': + return { ...state, phase: phases.error, error: action.error } + case 'UPLOAD_START': + return { ...state, phase: phases.uploading, progress: 0, error: null } + case 'UPLOAD_PROGRESS': + return { ...state, progress: action.progress } + case 'UPLOAD_ERROR': + return { ...state, phase: phases.error, error: action.error } + case 'FINISH_START': + return { ...state, phase: phases.finishing, error: null } + case 'FINISH_SUCCESS': + return { ...state, phase: phases.polling, pipelineStatus: action.status, previewUrl: action.previewUrl ?? null } + case 'FINISH_ERROR': + return { ...state, phase: phases.error, error: action.error } + case 'CANCEL_START': + return { ...state, phase: phases.cancelling, error: null } + case 'CANCEL_SUCCESS': + return { ...state, phase: phases.idle, cancelledAt: Date.now() } + case 'CLEAR_CANCELLED': + return { ...state, cancelledAt: null } + case 'CANCEL_ERROR': + return { ...state, phase: phases.error, error: action.error } + case 'STATUS_UPDATE': + return { ...state, pipelineStatus: action.status, progress: action.progress ?? state.progress, failureReason: action.failureReason ?? null } + case 'STATUS_ERROR': + return { ...state, phase: phases.error, error: action.error } + case 'SUCCESS': + return { ...state, phase: phases.success } + case 'RESET': + return { ...initialState, draftId: state.draftId, cancelledAt: state.cancelledAt } + case 'PUSH_NOTICE': + return { ...state, notices: [...state.notices, action.notice] } + case 'REMOVE_NOTICE': + return { ...state, notices: state.notices.filter((notice) => notice.id !== action.id) } + default: + return state + } +} + +const MAX_CHUNK_RETRIES = 3 +const RETRY_DELAY_MS = 900 + +function normalizeUiTag(rawTag) { + const raw = String(rawTag ?? '').trim().toLowerCase() + if (!raw) return '' + + return raw + .replace(/\s+/g, '-') + .replace(/[^a-z0-9_-]/g, '') + .replace(/-+/g, '-') + .replace(/_+/g, '_') + .replace(/^[-_]+|[-_]+$/g, '') + .slice(0, 32) +} + +function parseUiTags(csvValue) { + return String(csvValue ?? '') + .split(/[\n,]+/) + .map((item) => normalizeUiTag(item)) + .filter(Boolean) +} + +function getTypeKey(ct) { + if (!ct) return 'default' + if (ct.slug && typeof ct.slug === 'string') { + return ct.slug.toLowerCase().replace(/\s+/g, '_').replace(/[^a-z0-9_]/g, '') + } + return String(ct.name || '').toLowerCase().replace(/\s+/g, '_').replace(/[^a-z0-9_]/g, '') +} + +function useUploadMachine({ draftId, filesCdnUrl, chunkSize, userId }) { + const [state, dispatch] = useReducer(reducer, { ...initialState, draftId }) + const pollRef = useRef(null) + + const extractErrorMessage = useCallback((error, fallback) => { + const message = error?.response?.data?.message + if (message && typeof message === 'string') return message + const errors = error?.response?.data?.errors + if (errors && typeof errors === 'object') { + const firstKey = Object.keys(errors)[0] + if (firstKey && Array.isArray(errors[firstKey]) && errors[firstKey][0]) { + return errors[firstKey][0] + } + } + return fallback + }, []) + + const pushNotice = useCallback((type, message) => { + const id = `${Date.now()}-${Math.random().toString(16).slice(2)}` + dispatch({ type: 'PUSH_NOTICE', notice: { id, type, message } }) + window.setTimeout(() => { + dispatch({ type: 'REMOVE_NOTICE', id }) + }, 4500) + }, []) + + const previewUrl = useMemo(() => { + if (state.previewUrl) return state.previewUrl + if (!state.filePreviewUrl) return null + return state.filePreviewUrl + }, [state.previewUrl, state.filePreviewUrl]) + + const stopPolling = useCallback(() => { + if (pollRef.current) { + window.clearInterval(pollRef.current) + pollRef.current = null + } + }, []) + + const startPolling = useCallback(() => { + if (!state.sessionId) return + stopPolling() + pollRef.current = window.setInterval(async () => { + try { + const res = await window.axios.get(`/api/uploads/status/${state.sessionId}`, { + headers: state.uploadToken ? { 'X-Upload-Token': state.uploadToken } : undefined, + params: state.uploadToken ? { upload_token: state.uploadToken } : undefined, + }) + const data = res.data || {} + dispatch({ + type: 'STATUS_UPDATE', + status: data.status, + progress: typeof data.progress === 'number' ? data.progress : state.progress, + failureReason: data.failure_reason, + }) + + if (data.status === 'processed') { + dispatch({ type: 'SUCCESS' }) + stopPolling() + } + + if (data.failure_reason) { + dispatch({ type: 'STATUS_ERROR', error: data.failure_reason }) + stopPolling() + } + } catch (error) { + dispatch({ type: 'STATUS_ERROR', error: 'Status check failed.' }) + stopPolling() + } + }, 2500) + }, [state.sessionId, state.uploadToken, state.progress, stopPolling]) + + useEffect(() => { + if (draftId && !state.sessionId) { + dispatch({ type: 'RESUME_SESSION', sessionId: draftId, status: 'resuming' }) + } + }, [draftId, state.sessionId]) + + useEffect(() => { + if (state.phase === phases.polling) { + startPolling() + } + + return () => stopPolling() + }, [state.phase, startPolling, stopPolling]) + + useEffect(() => { + return () => { + if (state.filePreviewUrl) { + URL.revokeObjectURL(state.filePreviewUrl) + } + } + }, [state.filePreviewUrl]) + + const initSession = useCallback(async () => { + dispatch({ type: 'INIT_START' }) + try { + const res = await window.axios.post('/api/uploads/init', { client: 'web' }) + const data = res.data || {} + dispatch({ + type: 'INIT_SUCCESS', + sessionId: data.session_id, + uploadToken: data.upload_token, + status: data.status, + }) + if (userId && data.session_id && data.upload_token && state.file) { + writeStoredSession(userId, { + session_id: data.session_id, + upload_token: data.upload_token, + file_name: state.file.name, + file_size: state.file.size, + updated_at: Date.now(), + }) + } + return { sessionId: data.session_id, uploadToken: data.upload_token } + } catch (error) { + const message = extractErrorMessage(error, 'Failed to initialize upload session.') + dispatch({ type: 'INIT_ERROR', error: message }) + pushNotice('error', message) + return null + } + }, [state.file, userId, extractErrorMessage, pushNotice]) + + const createDraft = useCallback(async () => { + if (state.artworkId) return state.artworkId + try { + const res = await window.axios.post('/api/artworks', { + title: state.metadata.title, + category: state.metadata.category, + tags: state.metadata.tags, + description: state.metadata.description, + license: state.metadata.licenseAccepted, + }) + + const data = res.data || {} + const artworkId = data.artwork_id ?? data.id + if (artworkId) { + dispatch({ type: 'SET_DRAFT', draftId: state.draftId, artworkId }) + return artworkId + } + throw new Error('missing_artwork_id') + } catch (error) { + const message = extractErrorMessage(error, 'Unable to create draft metadata.') + dispatch({ type: 'FINISH_ERROR', error: message }) + pushNotice('error', message) + return null + } + }, [state.artworkId, state.metadata, state.draftId, extractErrorMessage, pushNotice]) + + const syncArtworkTags = useCallback(async (artworkId) => { + const tags = Array.from(new Set(parseUiTags(state.metadata.tags))) + if (tags.length === 0) { + return true + } + + try { + await window.axios.put(`/api/artworks/${artworkId}/tags`, { tags }) + return true + } catch (error) { + const message = extractErrorMessage(error, 'Tag sync failed. Upload will continue.') + pushNotice('error', message) + return false + } + }, [state.metadata.tags, extractErrorMessage, pushNotice]) + + const fetchStatus = useCallback(async (sessionId, uploadToken) => { + const res = await window.axios.get(`/api/uploads/status/${sessionId}`, { + headers: uploadToken ? { 'X-Upload-Token': uploadToken } : undefined, + params: uploadToken ? { upload_token: uploadToken } : undefined, + }) + return res.data || {} + }, []) + + const validateStoredSession = useCallback(async (file) => { + if (!userId) return null + const stored = readStoredSession(userId) + if (!stored) return null + + if (stored.file_name !== file.name || stored.file_size !== file.size) { + clearStoredSession(userId) + return null + } + + try { + const data = await fetchStatus(stored.session_id, stored.upload_token) + if (!data || !data.session_id) { + clearStoredSession(userId) + return null + } + dispatch({ type: 'RESTORE_SESSION', sessionId: stored.session_id, uploadToken: stored.upload_token, status: data.status }) + return { sessionId: stored.session_id, uploadToken: stored.upload_token } + } catch (error) { + clearStoredSession(userId) + return null + } + }, [fetchStatus, userId]) + + const uploadChunk = useCallback(async (sessionId, uploadToken, blob, offset, totalSize, attempt) => { + const payload = new FormData() + payload.append('session_id', sessionId) + payload.append('offset', String(offset)) + payload.append('chunk_size', String(blob.size)) + payload.append('total_size', String(totalSize)) + payload.append('chunk', blob) + payload.append('upload_token', uploadToken) + + try { + const res = await window.axios.post('/api/uploads/chunk', payload, { + headers: uploadToken ? { 'X-Upload-Token': uploadToken } : undefined, + }) + + const data = res.data || {} + if (typeof data.progress === 'number') { + dispatch({ type: 'UPLOAD_PROGRESS', progress: data.progress }) + } + + return data + } catch (error) { + if (attempt < MAX_CHUNK_RETRIES) { + await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS * (attempt + 1))) + return uploadChunk(sessionId, uploadToken, blob, offset, totalSize, attempt + 1) + } + throw error + } + }, []) + + const uploadFile = useCallback(async (sessionId, uploadToken, file) => { + dispatch({ type: 'UPLOAD_START' }) + + let status + try { + status = await fetchStatus(sessionId, uploadToken) + } catch (error) { + const message = extractErrorMessage(error, 'Unable to resume upload.') + dispatch({ type: 'UPLOAD_ERROR', error: message }) + pushNotice('error', message) + return false + } + + let offset = Number(status.received_bytes || 0) + const totalSize = file.size + if (offset > totalSize) offset = 0 + + while (offset < totalSize) { + const nextOffset = Math.min(offset + chunkSize, totalSize) + const chunk = file.slice(offset, nextOffset) + + try { + const data = await uploadChunk(sessionId, uploadToken, chunk, offset, totalSize, 0) + offset = Number(data.received_bytes ?? nextOffset) + if (offset < nextOffset) { + offset = nextOffset + } + } catch (error) { + const message = extractErrorMessage(error, 'File upload failed. Please retry.') + dispatch({ type: 'UPLOAD_ERROR', error: message }) + pushNotice('error', message) + return false + } + } + + return true + }, [chunkSize, fetchStatus, uploadChunk]) + + const finishUpload = useCallback(async (sessionId, uploadToken, artworkId) => { + dispatch({ type: 'FINISH_START' }) + try { + const res = await window.axios.post( + '/api/uploads/finish', + { session_id: sessionId, artwork_id: artworkId, upload_token: uploadToken }, + { headers: { 'X-Upload-Token': uploadToken } } + ) + const data = res.data || {} + const previewPath = data.preview_path + const previewUrl = previewPath ? `${filesCdnUrl}/${previewPath}` : null + dispatch({ type: 'FINISH_SUCCESS', status: data.status, previewUrl }) + if (userId) { + clearStoredSession(userId) + } + return true + } catch (error) { + const message = extractErrorMessage(error, 'Upload finalization failed.') + dispatch({ type: 'FINISH_ERROR', error: message }) + pushNotice('error', message) + return false + } + }, [filesCdnUrl, userId]) + + const startUpload = useCallback(async () => { + if (!state.file) { + const message = 'Please select a file first.' + dispatch({ type: 'UPLOAD_ERROR', error: message }) + pushNotice('error', message) + return + } + + if (!state.metadata.title.trim()) { + const message = 'Title is required to start the upload.' + dispatch({ type: 'UPLOAD_ERROR', error: message }) + pushNotice('error', message) + return + } + + if (!state.metadata.type) { + const message = 'Please select a Type.' + dispatch({ type: 'UPLOAD_ERROR', error: message }) + pushNotice('error', message) + return + } + + if (!state.metadata.category) { + const message = 'Please select a Category.' + dispatch({ type: 'UPLOAD_ERROR', error: message }) + pushNotice('error', message) + return + } + + if (parseUiTags(state.metadata.tags).length === 0) { + const message = 'Please add at least one tag.' + dispatch({ type: 'UPLOAD_ERROR', error: message }) + pushNotice('error', message) + return + } + + if (!state.metadata.description.trim()) { + const message = 'Please provide a description.' + dispatch({ type: 'UPLOAD_ERROR', error: message }) + pushNotice('error', message) + return + } + + if (!state.metadata.licenseAccepted) { + const message = 'You must confirm ownership of the artwork.' + dispatch({ type: 'UPLOAD_ERROR', error: message }) + pushNotice('error', message) + return + } + + let init = null + if (userId) { + init = await validateStoredSession(state.file) + } + + if (!init) { + init = await initSession() + } + + if (!init) return + + const artworkId = await createDraft() + if (!artworkId) return + + await syncArtworkTags(artworkId) + + const ok = await uploadFile(init.sessionId, init.uploadToken, state.file) + if (!ok) return + + await finishUpload(init.sessionId, init.uploadToken, artworkId) + }, [state.file, state.metadata, initSession, createDraft, syncArtworkTags, uploadFile, finishUpload, validateStoredSession, userId, pushNotice]) + + const cancelUpload = useCallback(async () => { + dispatch({ type: 'CANCEL_START' }) + + if (!state.sessionId || !state.uploadToken) { + if (userId) { + clearStoredSession(userId) + } + dispatch({ type: 'CANCEL_SUCCESS' }) + dispatch({ type: 'RESET' }) + return + } + + try { + await window.axios.post( + '/api/uploads/cancel', + { session_id: state.sessionId, upload_token: state.uploadToken }, + { headers: { 'X-Upload-Token': state.uploadToken } } + ) + } catch (error) { + // ignore error, always reset local state to avoid leaking session info + } + + if (userId) { + clearStoredSession(userId) + } + dispatch({ type: 'CANCEL_SUCCESS' }) + dispatch({ type: 'RESET' }) + }, [state.sessionId, state.uploadToken, userId]) + + return { + state, + dispatch, + previewUrl, + startUpload, + initSession, + cancelUpload, + pushNotice, + } +} + +export default function UploadPage({ draftId, filesCdnUrl, chunkSize }) { + const { props } = usePage() + + const windowFlags = window?.SKINBASE_FLAGS || {} + const propFlagRaw = props?.feature_flags?.uploads_v2 + const windowFlagRaw = (windowFlags?.uploads && windowFlags.uploads.v2) ?? windowFlags?.uploads_v2 + + const toBooleanFlag = (value) => { + if (typeof value === 'boolean') return value + if (typeof value === 'number') return value === 1 + if (typeof value === 'string') { + const normalized = value.trim().toLowerCase() + return ['1', 'true', 'yes', 'on'].includes(normalized) + } + return false + } + + const uploadsV2Enabled = toBooleanFlag(propFlagRaw) || toBooleanFlag(windowFlagRaw) + + if (uploadsV2Enabled) { + return ( +
+
+ +
+
+ ) + } + + const userId = props?.auth?.user?.id ?? null + const suggestedTags = Array.isArray(props?.suggested_tags) ? props.suggested_tags : [] + const safeChunkSize = Math.max(1, Number(chunkSize || 0)) + const { state, dispatch, previewUrl, startUpload, cancelUpload } = useUploadMachine({ draftId, filesCdnUrl, chunkSize: safeChunkSize, userId }) + const fileInputRef = useRef(null) + const [confirmCancel, setConfirmCancel] = useState(false) + const [contentTypes, setContentTypes] = useState([]) + const [selectedParentCategory, setSelectedParentCategory] = useState(null) + + const availableTypes = useMemo(() => (props?.content_types && Array.isArray(props.content_types)) ? props.content_types : contentTypes, [props, contentTypes]) + const selectedType = useMemo( + () => availableTypes.find((t) => String(t.id) === String(state.metadata.type)), + [availableTypes, state.metadata.type] + ) + const categoryOptions = useMemo(() => selectedType?.categories || [], [selectedType]) + const hasAtLeastOneTag = useMemo(() => parseUiTags(state.metadata.tags).length > 0, [state.metadata.tags]) + + useEffect(() => { + // Prefer server-provided props, else try fetching from API endpoints + if (props?.content_types && Array.isArray(props.content_types)) { + setContentTypes(props.content_types) + return + } + + let mounted = true + ;(async () => { + try { + const res = await window.axios.get('/api/content-types') + if (!mounted) return + setContentTypes(res.data || []) + } catch (e) { + // ignore, content types optional here + } + })() + + return () => { mounted = false } + }, [props]) + + const onFileSelect = useCallback((file) => { + if (!file) return + const preview = URL.createObjectURL(file) + dispatch({ type: 'SET_FILE', file, previewUrl: preview }) + }, [dispatch]) + + const onDrop = useCallback((event) => { + event.preventDefault() + const file = event.dataTransfer.files?.[0] + onFileSelect(file) + }, [onFileSelect]) + + const onBrowse = useCallback(() => { + fileInputRef.current?.click() + }, []) + + const onChange = useCallback((event) => { + const file = event.target.files?.[0] + onFileSelect(file) + }, [onFileSelect]) + + const statusLabel = state.pipelineStatus || state.phase + + useEffect(() => { + if (!confirmCancel) return + const timer = window.setTimeout(() => { + setConfirmCancel(false) + }, 5000) + return () => window.clearTimeout(timer) + }, [confirmCancel]) + + useEffect(() => { + if (!state.cancelledAt) return + const timer = window.setTimeout(() => { + dispatch({ type: 'CLEAR_CANCELLED' }) + }, 3500) + return () => window.clearTimeout(timer) + }, [state.cancelledAt, dispatch]) + + return ( +
+
+ {state.notices.length > 0 && ( +
+ {state.notices.map((notice) => ( +
+ {notice.message} +
+ ))} +
+ )} +
+
+
+
+

Upload artwork

+ Secure pipeline +
+

All uploads are scanned, re-encoded, and published through the Skinbase pipeline.

+ +
e.preventDefault()} + onDrop={onDrop} + > +
+ +
+

Drag & drop your file

+

JPG, PNG, or WebP. Up to 50MB.

+ + +
+ + {state.file && ( +
+
+ Preview +
+
+
{state.file.name}
+
{(state.file.size / 1024 / 1024).toFixed(2)} MB
+
+
+ )} + +
+ +
+ +
+
+
+
Choose a type
+
Step 1: Pick what kind of artwork this is.
+
+ Type +
+ + {availableTypes.length === 0 ? ( +
+ No content types available. +
+ ) : ( +
+ {availableTypes.map((ct) => { + const active = String(ct.id) === String(state.metadata.type) + const iconKey = getTypeKey(ct) + const iconPath = `/gfx/mascot_${iconKey}.webp` + return ( + + ) + })} +
+ )} +
+ +
+
+
+
Choose a category
+
Step 2: Pick a subcategory inside the type.
+
+ Category +
+ + {!selectedType ? ( +
+ Select a type first to see categories. +
+ ) : categoryOptions.length === 0 ? ( +
+ No categories available for {selectedType.name}. +
+ ) : ( +
+
+ {categoryOptions.map((cat) => { + const isSelected = String(cat.id) === String(state.metadata.category) + const isExpanded = String(cat.id) === String(selectedParentCategory) + const hasChildren = Array.isArray(cat.children) && cat.children.length > 0 + return ( + + ) + })} +
+ + {selectedParentCategory && (() => { + const parent = categoryOptions.find((c) => String(c.id) === String(selectedParentCategory)) + if (!parent || !Array.isArray(parent.children) || parent.children.length === 0) return null + return ( +
+
+
+
Subcategories for {parent.name}
+
Choose a subcategory below
+
+ +
+
+ {parent.children.map((child) => { + const activeChild = String(child.id) === String(state.metadata.category) + return ( + + ) + })} +
+
+ ) + })()} +
+ )} +
+ +
+ Tags +
+ { + dispatch({ type: 'SET_METADATA', payload: { tags: nextTags.join(', ') } }) + }} + suggestedTags={suggestedTags} + maxTags={15} + minLength={2} + maxLength={32} + searchEndpoint="/api/tags/search" + popularEndpoint="/api/tags/popular" + placeholder="Type tags (e.g. cyberpunk, city)" + /> +
+
+ +
+ + +
+ + +
+ + +
+ + +
+ +
+
-
- mlist ?? 0) ? 'checked' : '' }}> Mailing list
- friend_upload_notice ?? 0) ? 'checked' : '' }}> Friends upload notice + + +
+
-
- - -
+ -
- - -
- -
- -
-
-
- - @if(!empty($user->icon)) -
- @endif -
- -
-
- -
- -
-
- - @if(!empty($user->picture)) -
- @endif -
- -
-
- - + + +
+ +

+ Change Password +

+ +
+ @csrf + @method('PUT') + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + + +
+ +
+
- - - - -
- -

Change password

-
- @csrf -
- - -
-
- - -
-
- - -
- - -
- +
+ @endsection diff --git a/resources/views/tags/show.blade.php b/resources/views/tags/show.blade.php new file mode 100644 index 00000000..e0be5081 --- /dev/null +++ b/resources/views/tags/show.blade.php @@ -0,0 +1,37 @@ +@extends('layouts.legacy') + +@section('content') +
+
+
+

Tag: {{ $tag->name }}

+

Browse artworks tagged with “{{ $tag->name }}”.

+
+
+ +
+
+ @if($artworks->isEmpty()) +
No artworks found for this tag.
+ @else +
+ @foreach($artworks as $artwork) + + @endforeach +
+ +
+ {{ $artworks->links('pagination::bootstrap-3') }} +
+ @endif +
+
+
+@endsection diff --git a/resources/views/upload.blade.php b/resources/views/upload.blade.php new file mode 100644 index 00000000..4b73d9ee --- /dev/null +++ b/resources/views/upload.blade.php @@ -0,0 +1,39 @@ +@extends('layouts.nova') + +@push('head') + + + + + @vite(['resources/js/entry-topbar.jsx','resources/js/upload.jsx']) + + + +@endpush + +@section('content') + @inertia +@endsection diff --git a/routes/api.php b/routes/api.php index 734d8040..dfbe9062 100644 --- a/routes/api.php +++ b/routes/api.php @@ -32,4 +32,99 @@ Route::prefix('v1')->name('api.v1.')->group(function () { // Category artworks (Category route-model binding uses slug) Route::get('categories/{category}/artworks', [\App\Http\Controllers\Api\ArtworkController::class, 'categoryArtworks']) ->name('categories.artworks'); + + // Personalized feed (auth required) + Route::middleware(['web', 'auth'])->get('feed', [\App\Http\Controllers\Api\FeedController::class, 'index']) + ->name('feed'); +}); + +Route::middleware(['web', 'auth'])->prefix('artworks')->name('api.artworks.')->group(function () { + Route::post('/', [\App\Http\Controllers\Api\ArtworkController::class, 'store']) + ->name('store'); +}); + +Route::middleware(['web', 'auth'])->prefix('uploads')->name('api.uploads.')->group(function () { + Route::post('init', [\App\Http\Controllers\Api\UploadController::class, 'init']) + ->middleware('throttle:uploads-init') + ->name('init'); + + Route::post('preload', [\App\Http\Controllers\Api\UploadController::class, 'preload']) + ->middleware('throttle:uploads-init') + ->name('preload'); + + Route::post('{id}/autosave', [\App\Http\Controllers\Api\UploadController::class, 'autosave']) + ->middleware('throttle:uploads-finish') + ->name('autosave'); + + Route::post('{id}/publish', [\App\Http\Controllers\Api\UploadController::class, 'publish']) + ->middleware('throttle:uploads-finish') + ->name('publish'); + + Route::get('{id}/status', [\App\Http\Controllers\Api\UploadController::class, 'processingStatus']) + ->middleware('throttle:uploads-status') + ->name('processing-status'); + + Route::post('chunk', [\App\Http\Controllers\Api\UploadController::class, 'chunk']) + ->middleware('throttle:uploads-init') + ->name('chunk'); + + Route::post('finish', [\App\Http\Controllers\Api\UploadController::class, 'finish']) + ->middleware('throttle:uploads-finish') + ->name('finish'); + + Route::post('cancel', [\App\Http\Controllers\Api\UploadController::class, 'cancel']) + ->middleware('throttle:uploads-finish') + ->name('cancel'); + + Route::get('status/{id}', [\App\Http\Controllers\Api\UploadController::class, 'status']) + ->middleware('throttle:uploads-status') + ->name('status'); +}); + +Route::middleware(['web', 'auth', 'admin.moderation'])->prefix('admin/uploads')->name('api.admin.uploads.')->group(function () { + Route::get('pending', [\App\Http\Controllers\Api\Admin\UploadModerationController::class, 'pending']) + ->name('pending'); + + Route::post('{id}/approve', [\App\Http\Controllers\Api\Admin\UploadModerationController::class, 'approve']) + ->whereUuid('id') + ->name('approve'); + + Route::post('{id}/reject', [\App\Http\Controllers\Api\Admin\UploadModerationController::class, 'reject']) + ->whereUuid('id') + ->name('reject'); +}); + +Route::middleware(['web', 'auth', 'admin.moderation'])->prefix('admin/reports')->name('api.admin.reports.')->group(function () { + Route::get('similar-artworks', [\App\Http\Controllers\Api\Admin\SimilarArtworkReportController::class, 'index']) + ->name('similar-artworks'); + + Route::get('feed-performance', [\App\Http\Controllers\Api\Admin\FeedPerformanceReportController::class, 'index']) + ->name('feed-performance'); +}); + +Route::post('analytics/similar-artworks', [\App\Http\Controllers\Api\SimilarArtworkAnalyticsController::class, 'store']) + ->middleware('throttle:uploads-status') + ->name('api.analytics.similar-artworks.store'); + +Route::middleware(['web', 'auth'])->post('analytics/feed', [\App\Http\Controllers\Api\FeedAnalyticsController::class, 'store']) + ->middleware('throttle:uploads-status') + ->name('api.analytics.feed.store'); + +Route::middleware(['web', 'auth'])->prefix('discovery')->name('api.discovery.')->group(function () { + Route::post('events', [\App\Http\Controllers\Api\DiscoveryEventController::class, 'store']) + ->middleware('throttle:uploads-status') + ->name('events.store'); +}); + +// Tag system (auth-protected; 404-only ownership checks handled in requests/controllers) +Route::middleware(['web', 'auth'])->prefix('tags')->name('api.tags.')->group(function () { + Route::get('search', [\App\Http\Controllers\Api\TagController::class, 'search'])->name('search'); + Route::get('popular', [\App\Http\Controllers\Api\TagController::class, 'popular'])->name('popular'); +}); + +Route::middleware(['web', 'auth'])->prefix('artworks')->name('api.artworks.tags.')->group(function () { + Route::get('{id}/tags', [\App\Http\Controllers\Api\ArtworkTagController::class, 'index'])->whereNumber('id')->name('index'); + Route::post('{id}/tags', [\App\Http\Controllers\Api\ArtworkTagController::class, 'store'])->whereNumber('id')->name('store'); + Route::put('{id}/tags', [\App\Http\Controllers\Api\ArtworkTagController::class, 'update'])->whereNumber('id')->name('update'); + Route::delete('{id}/tags/{tag}', [\App\Http\Controllers\Api\ArtworkTagController::class, 'destroy'])->whereNumber('id')->name('destroy'); }); diff --git a/routes/console.php b/routes/console.php index 3c9adf1a..5d3e087e 100644 --- a/routes/console.php +++ b/routes/console.php @@ -2,7 +2,15 @@ use Illuminate\Foundation\Inspiring; use Illuminate\Support\Facades\Artisan; +use App\Uploads\Services\CleanupService; Artisan::command('inspire', function () { $this->comment(Inspiring::quote()); })->purpose('Display an inspiring quote'); + +Artisan::command('uploads:cleanup {--limit=100 : Maximum drafts to clean in one run}', function (): void { + $limit = (int) $this->option('limit'); + $deleted = app(CleanupService::class)->cleanupStaleDrafts($limit); + + $this->info("Uploads cleanup deleted {$deleted} draft(s)."); +})->purpose('Delete stale draft uploads and temporary files'); diff --git a/routes/legacy.php b/routes/legacy.php index 03018ca8..6c9d9309 100644 --- a/routes/legacy.php +++ b/routes/legacy.php @@ -46,25 +46,6 @@ Route::get('/news/{id}/{slug?}', [NewsController::class, 'show'])->where('id', ' Route::get('/categories', [CategoryController::class, 'index'])->name('legacy.categories'); Route::get('/category/{group}/{slug?}/{id?}', [CategoryController::class, 'show'])->name('legacy.category'); -// Short legacy routes for top-level category URLs like /Photography/3 -// Short legacy routes for top-level category URLs (mapped to CategoryController@show) -/* -Route::get('/Photography/{id}', [CategoryController::class, 'show']) - ->defaults('group', 'Photography') - ->where('id', '\\d+'); - -Route::get('/Wallpapers/{id}', [CategoryController::class, 'show']) - ->defaults('group', 'Wallpapers') - ->where('id', '\\d+'); - -Route::get('/Skins/{id}', [CategoryController::class, 'show']) - ->defaults('group', 'Skins') - ->where('id', '\\d+'); - -Route::get('/Other/{id}', [CategoryController::class, 'show']) - ->defaults('group', 'Other') - ->where('id', '\\d+'); -*/ Route::get('/browse', [BrowseController::class, 'index'])->name('legacy.browse'); Route::get('/featured', [FeaturedArtworksController::class, 'index'])->name('legacy.featured'); Route::get('/featured-artworks', [FeaturedArtworksController::class, 'index'])->name('legacy.featured_artworks'); @@ -104,9 +85,6 @@ Route::middleware('auth')->get('/recieved-comments', [ReceivedCommentsController // User account settings (legacy /user) Route::middleware('auth')->match(['get','post'], '/user', [LegacyUserController::class, 'index'])->name('legacy.user'); -// Content-type landing pages (legacy look) -Route::get('/photography', [PhotographyController::class, 'index'])->name('legacy.photography'); - Route::get('/today-in-history', [TodayInHistoryController::class, 'index'])->name('legacy.today_in_history'); Route::get('/today-downloads', [TodayDownloadsController::class, 'index'])->name('legacy.today_downloads'); diff --git a/routes/web.php b/routes/web.php index 40038cb3..013a97c3 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,8 +1,12 @@ prefix('dashboard')->name('dashboard.')->group(func Route::middleware('auth')->group(function () { Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit'); - Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update'); + Route::match(['post','put','patch'], '/profile', [ProfileController::class, 'update'])->name('profile.update'); Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy'); + // Password change endpoint (accepts POST or PUT from legacy and new forms) + Route::match(['post', 'put'], '/profile/password', [ProfileController::class, 'password'])->name('profile.password'); + // Avatar upload (backend only) - processes and stores avatars + Route::post('/avatar/upload', [AvatarController::class, 'upload'])->name('avatar.upload'); +}); + +Route::middleware(['auth'])->group(function () { + Route::get('/upload', function () { + $contentTypes = ContentType::with(['rootCategories.children'])->get()->map(function ($ct) { + return [ + 'id' => $ct->id, + 'name' => $ct->name, + 'categories' => $ct->rootCategories->map(function ($c) { + return [ + 'id' => $c->id, + 'name' => $c->name, + 'children' => $c->children->map(function ($ch) { + return ['id' => $ch->id, 'name' => $ch->name]; + })->values()->all(), + ]; + })->values()->all(), + ]; + })->values()->all(); + + return Inertia::render('Upload/Index', [ + 'draftId' => null, + 'content_types' => $contentTypes, + 'suggested_tags' => [], + 'filesCdnUrl' => config('cdn.files_url'), + 'chunkSize' => (int) config('uploads.chunk.max_bytes', 5242880), + 'feature_flags' => [ + 'uploads_v2' => (bool) config('features.uploads_v2', false), + ], + ]); + })->name('upload'); + + Route::get('/upload/draft/{id}', function (string $id) { + $contentTypes = ContentType::with(['rootCategories.children'])->get()->map(function ($ct) { + return [ + 'id' => $ct->id, + 'name' => $ct->name, + 'categories' => $ct->rootCategories->map(function ($c) { + return [ + 'id' => $c->id, + 'name' => $c->name, + 'children' => $c->children->map(function ($ch) { + return ['id' => $ch->id, 'name' => $ch->name]; + })->values()->all(), + ]; + })->values()->all(), + ]; + })->values()->all(); + + return Inertia::render('Upload/Index', [ + 'draftId' => $id, + 'content_types' => $contentTypes, + 'suggested_tags' => [], + 'filesCdnUrl' => config('cdn.files_url'), + 'chunkSize' => (int) config('uploads.chunk.max_bytes', 5242880), + 'feature_flags' => [ + 'uploads_v2' => (bool) config('features.uploads_v2', false), + ], + ]); + })->whereUuid('id')->name('upload.draft'); }); require __DIR__.'/auth.php'; +Route::get('/tag/{tag:slug}', [\App\Http\Controllers\Web\TagController::class, 'show']) + ->where('tag', '[a-z0-9\-]+') + ->name('tags.show'); + Route::view('/blank', 'blank')->name('blank'); -// Artwork public show (slug-based). This must come before the category route so the artwork -// slug (last segment) is matched correctly while allowing multi-segment category paths. -Route::get('/{contentTypeSlug}/{categoryPath}/{artwork}', [\App\Http\Controllers\ArtworkController::class, 'show']) - ->where([ - 'contentTypeSlug' => 'photography|wallpapers|skins|other', - 'categoryPath' => '.*', - 'artwork' => '[A-Za-z0-9\-]+' - ]) +// Bind the artwork route parameter to a model if it exists, otherwise return null +use App\Models\Artwork; +Route::bind('artwork', function ($value) { + return Artwork::where('slug', $value)->first(); +}); + +// Universal content router: handles content-type roots, nested categories and artwork slugs. +// Keep the explicit /photography route above (if present) so the legacy controller can continue +// to serve photography's root page. This catch-all route delegates to a controller that +// will forward to the appropriate existing controller (artwork or category handlers). +// Provide a named route alias for legacy artwork URL generation used in tests. +Route::get('/{contentTypeSlug}/{categoryPath}/{artwork}', [\App\Http\Controllers\ContentRouterController::class, 'handle']) + ->where('contentTypeSlug', 'photography|wallpapers|skins|other') + ->where('categoryPath', '[^/]+(?:/[^/]+)*') ->name('artworks.show'); -// New slug-based category routes (e.g., /photography/audio/winamp) -Route::get('/{contentTypeSlug}/{categoryPath?}', [\App\Http\Controllers\CategoryPageController::class, 'show']) +Route::get('/{contentTypeSlug}/{path?}', [\App\Http\Controllers\ContentRouterController::class, 'handle']) ->where('contentTypeSlug', 'photography|wallpapers|skins|other') - ->where('categoryPath', '.*') - ->name('category.slug'); + ->where('path', '.*') + ->name('content.route'); + + -use App\Http\Controllers\ManageController; Route::middleware(['auth'])->group(function () { Route::get('/manage', [ManageController::class, 'index'])->name('manage'); @@ -59,6 +137,10 @@ Route::middleware(['auth'])->group(function () { // Admin routes for artworks (separated from public routes) Route::middleware(['auth'])->prefix('admin')->name('admin.')->group(function () { + Route::get('uploads/moderation', function () { + return Inertia::render('Admin/UploadQueue'); + })->middleware('admin.moderation')->name('uploads.moderation'); + Route::resource('artworks', \App\Http\Controllers\Admin\ArtworkController::class)->except(['show']); }); diff --git a/scripts/check_intervention.php b/scripts/check_intervention.php new file mode 100644 index 00000000..1edbc899 --- /dev/null +++ b/scripts/check_intervention.php @@ -0,0 +1,10 @@ +getMessage() . PHP_EOL; +} diff --git a/scripts/inspect_autotag_jobs.php b/scripts/inspect_autotag_jobs.php new file mode 100644 index 00000000..d357918c --- /dev/null +++ b/scripts/inspect_autotag_jobs.php @@ -0,0 +1,58 @@ +make(Illuminate\Contracts\Console\Kernel::class)->bootstrap(); + +use Illuminate\Support\Facades\DB; + +function printSection($title) { + echo "\n===== $title =====\n"; +} + +printSection('Recent queued jobs (jobs table)'); +$jobs = DB::table('jobs')->where('payload', 'like', '%AutoTagArtworkJob%')->orderByDesc('id')->limit(10)->get(); +if (count($jobs) === 0) { + echo "No queued AutoTagArtworkJob entries found.\n"; +} else { + foreach ($jobs as $j) { + echo "--- job id: {$j->id} | queued_at: " . ($j->available_at ?? $j->created_at ?? '') . "\n"; + $payload = isset($j->payload) ? $j->payload : ''; + echo substr($payload, 0, 2000) . "\n\n"; + } +} + +printSection('Recent failed jobs (failed_jobs table)'); +$failed = DB::table('failed_jobs')->where('payload', 'like', '%AutoTagArtworkJob%')->orderByDesc('id')->limit(10)->get(); +if (count($failed) === 0) { + echo "No failed AutoTagArtworkJob entries found.\n"; +} else { + foreach ($failed as $f) { + echo "--- failed id: {$f->id} | connection: {$f->connection} | failed_at: {$f->failed_at}\n"; + $payload = isset($f->payload) ? $f->payload : ''; + echo substr($payload, 0, 2000) . "\n\n"; + } +} + +printSection('Recent Laravel logs (last 200 lines)'); +$logs = glob(__DIR__ . '/../storage/logs/*.log'); +if ($logs === false || count($logs) === 0) { + echo "No log files found.\n"; +} else { + usort($logs, function($a, $b){ return filemtime($b) <=> filemtime($a); }); + $latest = $logs[0]; + echo "Latest log: " . basename($latest) . "\n\n"; + $lines = file($latest, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + if ($lines === false) { + echo "Unable to read log file.\n"; + } else { + $tail = array_slice($lines, -200); + foreach ($tail as $line) { + echo $line . "\n"; + } + } +} + +echo "\nDone.\n"; diff --git a/scripts/repair_broken_artworks.php b/scripts/repair_broken_artworks.php new file mode 100644 index 00000000..25f27cd9 --- /dev/null +++ b/scripts/repair_broken_artworks.php @@ -0,0 +1,138 @@ +make(Illuminate\Contracts\Console\Kernel::class)->bootstrap(); + +$options = getopt('', ['id::', 'limit::', 'publish']); +$id = isset($options['id']) ? (int) $options['id'] : null; +$limit = isset($options['limit']) ? max(1, (int) $options['limit']) : 25; +$publish = array_key_exists('publish', $options); + +$brokenQuery = Artwork::query()->where(function ($query): void { + $query->where('file_path', 'pending') + ->orWhereNull('hash') + ->orWhereNull('file_ext') + ->orWhereNull('thumb_ext') + ->orWhere('file_name', 'pending') + ->orWhere('file_size', 0) + ->orWhere('width', '<=', 1) + ->orWhere('height', '<=', 1); +}); + +if ($id && $id > 0) { + $brokenQuery->whereKey($id); +} + +$rows = $brokenQuery->orderBy('id')->limit($limit)->get(); +if ($rows->isEmpty()) { + fwrite(STDOUT, "No matching broken artworks found.\n"); + exit(0); +} + +$storageRoot = rtrim((string) config('uploads.storage_root'), DIRECTORY_SEPARATOR); +$fixed = 0; +$skipped = 0; + +$makeUniqueSlug = static function (Artwork $artwork, string $title): string { + $base = Str::slug($title); + if ($base === '') { + $base = 'artwork-' . $artwork->id; + } + + $slug = $base; + $suffix = 2; + while (Artwork::query()->where('slug', $slug)->where('id', '!=', $artwork->id)->exists()) { + $slug = $base . '-' . $suffix; + $suffix++; + } + + return $slug; +}; + +foreach ($rows as $artwork) { + $files = DB::table('artwork_files') + ->where('artwork_id', $artwork->id) + ->get(['variant', 'path', 'mime', 'size']) + ->keyBy('variant'); + + $orig = $files->get('orig'); + if (! $orig || empty($orig->path)) { + fwrite(STDOUT, "[SKIP] {$artwork->id}: no orig variant in artwork_files\n"); + $skipped++; + continue; + } + + $origPath = (string) $orig->path; + $absolute = $storageRoot . DIRECTORY_SEPARATOR . str_replace(['/', '\\\\'], DIRECTORY_SEPARATOR, $origPath); + + $hash = null; + $fileSize = (int) ($orig->size ?? 0); + $width = (int) $artwork->width; + $height = (int) $artwork->height; + + if (is_file($absolute)) { + $hash = hash_file('sha256', $absolute) ?: null; + $actualSize = @filesize($absolute); + if (is_int($actualSize) && $actualSize > 0) { + $fileSize = $actualSize; + } + + $dimensions = @getimagesize($absolute); + if (is_array($dimensions) && isset($dimensions[0], $dimensions[1])) { + $width = max(1, (int) $dimensions[0]); + $height = max(1, (int) $dimensions[1]); + } + } + + $ext = strtolower((string) pathinfo($origPath, PATHINFO_EXTENSION)); + if ($ext === '') { + $ext = 'webp'; + } + + $title = trim((string) ($artwork->title ?? '')); + if ($title === '') { + $title = 'Artwork ' . $artwork->id; + } + + $slug = $makeUniqueSlug($artwork, $title); + + $updates = [ + 'title' => $title, + 'slug' => $slug, + 'file_name' => basename($origPath), + 'file_path' => $origPath, + 'file_size' => max(1, $fileSize), + 'mime_type' => (string) ($orig->mime ?: 'image/webp'), + 'hash' => $hash ?: (string) ($artwork->hash ?? ''), + 'file_ext' => $ext, + 'thumb_ext' => $ext, + 'width' => max(1, $width), + 'height' => max(1, $height), + ]; + + if ($publish) { + $updates['is_public'] = true; + $updates['is_approved'] = true; + $updates['published_at'] = $artwork->published_at ?: now(); + } + + if (empty($updates['hash'])) { + fwrite(STDOUT, "[SKIP] {$artwork->id}: hash could not be recovered from file\n"); + $skipped++; + continue; + } + + Artwork::query()->whereKey($artwork->id)->update($updates); + fwrite(STDOUT, "[FIXED] {$artwork->id}: {$updates['file_path']} | hash=" . substr((string) $updates['hash'], 0, 12) . "...\n"); + $fixed++; +} + +fwrite(STDOUT, "Done. fixed={$fixed} skipped={$skipped}\n"); +exit(0); diff --git a/scripts/verify_upload_publish.php b/scripts/verify_upload_publish.php new file mode 100644 index 00000000..cdff5d93 --- /dev/null +++ b/scripts/verify_upload_publish.php @@ -0,0 +1,98 @@ +make(Illuminate\Contracts\Console\Kernel::class)->bootstrap(); + +$options = getopt('', ['id::', 'limit::']); +$id = isset($options['id']) ? (int) $options['id'] : null; +$limit = isset($options['limit']) ? max(1, (int) $options['limit']) : 5; + +$query = Artwork::query()->orderByDesc('id'); +if ($id && $id > 0) { + $query->whereKey($id); +} + +$rows = $query->limit($limit)->get(); + +if ($rows->isEmpty()) { + fwrite(STDOUT, "No artwork rows found.\n"); + exit(1); +} + +$requiredFields = [ + 'title', + 'slug', + 'file_name', + 'file_path', + 'hash', + 'file_ext', + 'thumb_ext', + 'mime_type', + 'file_size', + 'published_at', +]; + +$hasFailure = false; + +foreach ($rows as $artwork) { + $missing = []; + + foreach ($requiredFields as $field) { + $value = $artwork->{$field}; + if ($value === null || $value === '' || $value === 'pending') { + $missing[] = $field; + } + } + + if (! (bool) $artwork->is_public) { + $missing[] = 'is_public'; + } + + if (! (bool) $artwork->is_approved) { + $missing[] = 'is_approved'; + } + + if ((int) $artwork->width <= 1) { + $missing[] = 'width'; + } + + if ((int) $artwork->height <= 1) { + $missing[] = 'height'; + } + + $publishedAt = $artwork->published_at instanceof Carbon + ? $artwork->published_at->toDateTimeString() + : (string) $artwork->published_at; + + fwrite(STDOUT, str_repeat('-', 72) . "\n"); + fwrite(STDOUT, "artwork_id: {$artwork->id}\n"); + fwrite(STDOUT, "title : " . (string) $artwork->title . "\n"); + fwrite(STDOUT, "slug : " . (string) $artwork->slug . "\n"); + fwrite(STDOUT, "file_path : " . (string) $artwork->file_path . "\n"); + fwrite(STDOUT, "hash : " . (string) $artwork->hash . "\n"); + fwrite(STDOUT, "file_ext : " . (string) $artwork->file_ext . " | thumb_ext: " . (string) $artwork->thumb_ext . "\n"); + fwrite(STDOUT, "visible : is_public=" . ((int) (bool) $artwork->is_public) . " is_approved=" . ((int) (bool) $artwork->is_approved) . "\n"); + fwrite(STDOUT, "published : " . ($publishedAt !== '' ? $publishedAt : 'NULL') . "\n"); + + if ($missing !== []) { + $hasFailure = true; + fwrite(STDOUT, "status : FAIL (missing/invalid: " . implode(', ', array_unique($missing)) . ")\n"); + } else { + fwrite(STDOUT, "status : OK\n"); + } +} + +fwrite(STDOUT, str_repeat('-', 72) . "\n"); +if ($hasFailure) { + fwrite(STDOUT, "Result: FAIL\n"); + exit(2); +} + +fwrite(STDOUT, "Result: OK\n"); +exit(0); diff --git a/scripts/vision-smoke.ps1 b/scripts/vision-smoke.ps1 new file mode 100644 index 00000000..5a57973b --- /dev/null +++ b/scripts/vision-smoke.ps1 @@ -0,0 +1,237 @@ +param( + [string]$ProjectRoot = (Resolve-Path (Join-Path $PSScriptRoot ".." )).Path, + [string]$EnvFile = ".env", + [string]$SampleImageUrl = "https://files.skinbase.org/img/aa/bb/cc/md.webp", + [switch]$SkipAnalyze +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +function Write-Info([string]$Message) { + Write-Host "[INFO] $Message" -ForegroundColor Cyan +} + +function Write-Ok([string]$Message) { + Write-Host "[OK] $Message" -ForegroundColor Green +} + +function Write-Fail([string]$Message) { + Write-Host "[FAIL] $Message" -ForegroundColor Red +} + +function Get-EnvMap([string]$Root, [string]$RelativeEnvFile) { + $map = @{} + + $envPath = Join-Path $Root $RelativeEnvFile + if (-not (Test-Path $envPath)) { + $fallback = Join-Path $Root ".env.example" + if (Test-Path $fallback) { + Write-Info "Env file '$RelativeEnvFile' not found. Falling back to .env.example." + $envPath = $fallback + } else { + throw "Neither '$RelativeEnvFile' nor '.env.example' was found in $Root" + } + } + + Get-Content -Path $envPath | ForEach-Object { + $line = $_.Trim() + if ($line -eq "" -or $line.StartsWith("#")) { return } + $idx = $line.IndexOf("=") + if ($idx -lt 1) { return } + + $key = $line.Substring(0, $idx).Trim() + $val = $line.Substring($idx + 1).Trim() + + if ($val.StartsWith('"') -and $val.EndsWith('"') -and $val.Length -ge 2) { + $val = $val.Substring(1, $val.Length - 2) + } + + if (-not $map.ContainsKey($key)) { + $map[$key] = $val + } + } + + return $map +} + +function Get-Setting([hashtable]$Map, [string]$Key, [string]$Default = "") { + $fromProcess = [Environment]::GetEnvironmentVariable($Key) + if (-not [string]::IsNullOrWhiteSpace($fromProcess)) { + return $fromProcess.Trim() + } + + if ($Map.ContainsKey($Key)) { + return [string]$Map[$Key] + } + + return $Default +} + +function Test-Truthy([string]$Value, [bool]$Default = $false) { + if ([string]::IsNullOrWhiteSpace($Value)) { return $Default } + + switch ($Value.Trim().ToLowerInvariant()) { + "1" { return $true } + "true" { return $true } + "yes" { return $true } + "on" { return $true } + "0" { return $false } + "false" { return $false } + "no" { return $false } + "off" { return $false } + default { return $Default } + } +} + +function Join-Url([string]$Base, [string]$Path) { + $left = $Base.TrimEnd('/') + $right = $Path.TrimStart('/') + return "$left/$right" +} + +function Invoke-Health([string]$Name, [string]$BaseUrl) { + if ([string]::IsNullOrWhiteSpace($BaseUrl)) { + throw "$Name base URL is empty" + } + + $url = Join-Url $BaseUrl "/health" + Write-Info "Checking $Name health: $url" + + try { + $response = Invoke-WebRequest -Uri $url -Method GET -TimeoutSec 10 -UseBasicParsing + } catch { + throw "$Name health request failed: $($_.Exception.Message)" + } + + if ($response.StatusCode -lt 200 -or $response.StatusCode -ge 300) { + throw "$Name health returned status $($response.StatusCode)" + } + + Write-Ok "$Name health check passed" +} + +function Invoke-Analyze([string]$ClipBaseUrl, [string]$AnalyzeEndpoint, [string]$ImageUrl) { + if ([string]::IsNullOrWhiteSpace($ClipBaseUrl)) { + throw "CLIP base URL is empty" + } + + $url = Join-Url $ClipBaseUrl $AnalyzeEndpoint + Write-Info "Running sample CLIP analyze call: $url" + + $payload = @{ + image_url = $ImageUrl + } | ConvertTo-Json -Depth 4 + + try { + $response = Invoke-WebRequest -Uri $url -Method POST -ContentType "application/json" -Body $payload -TimeoutSec 15 -UseBasicParsing + } catch { + throw "CLIP analyze request failed: $($_.Exception.Message)" + } + + if ($response.StatusCode -lt 200 -or $response.StatusCode -ge 300) { + throw "CLIP analyze returned status $($response.StatusCode)" + } + + $json = $null + try { + $json = $response.Content | ConvertFrom-Json + } catch { + throw "CLIP analyze response is not valid JSON" + } + + $hasTags = $false + if ($json -is [System.Collections.IEnumerable] -and -not ($json -is [string])) { + $hasTags = $true + } + if ($null -ne $json.tags) { $hasTags = $true } + if ($null -ne $json.data) { $hasTags = $true } + + if (-not $hasTags) { + throw "CLIP analyze response does not contain expected tags/data payload" + } + + Write-Ok "Sample CLIP analyze call passed" +} + +function Test-NonBlockingPublish([string]$Root) { + Write-Info "Validating non-blocking publish path (code assertions)" + + $uploadController = Join-Path $Root "app/Http/Controllers/Api/UploadController.php" + $derivativesJob = Join-Path $Root "app/Jobs/GenerateDerivativesJob.php" + + if (-not (Test-Path $uploadController)) { throw "Missing file: $uploadController" } + if (-not (Test-Path $derivativesJob)) { throw "Missing file: $derivativesJob" } + + $uploadText = Get-Content -Raw -Path $uploadController + $jobText = Get-Content -Raw -Path $derivativesJob + + if ($uploadText -notmatch "AutoTagArtworkJob::dispatch\(") { + throw "UploadController does not dispatch AutoTagArtworkJob" + } + + if ($jobText -notmatch "AutoTagArtworkJob::dispatch\(") { + throw "GenerateDerivativesJob does not dispatch AutoTagArtworkJob" + } + + if ($uploadText -match "dispatchSync\(" -or $jobText -match "dispatchSync\(") { + throw "Found dispatchSync in publish path; auto-tagging must remain async" + } + + if ($uploadText -match "Illuminate\\Support\\Facades\\Http" -or $uploadText -match "Http::") { + throw "UploadController appears to call external vision HTTP directly" + } + + Write-Ok "Non-blocking publish path validation passed" +} + +$failed = $false + +try { + Write-Info "Vision smoke test starting" + Write-Info "Project root: $ProjectRoot" + + $envMap = Get-EnvMap -Root $ProjectRoot -RelativeEnvFile $EnvFile + + $visionEnabled = Test-Truthy (Get-Setting -Map $envMap -Key "VISION_ENABLED" -Default "true") $true + if (-not $visionEnabled) { + throw "VISION_ENABLED=false. Vision integration is disabled; smoke check cannot continue." + } + + $clipBaseUrl = Get-Setting -Map $envMap -Key "CLIP_BASE_URL" + $clipAnalyzeEndpoint = Get-Setting -Map $envMap -Key "CLIP_ANALYZE_ENDPOINT" -Default "/analyze" + + $yoloEnabled = Test-Truthy (Get-Setting -Map $envMap -Key "YOLO_ENABLED" -Default "true") $true + $yoloBaseUrl = Get-Setting -Map $envMap -Key "YOLO_BASE_URL" + + Invoke-Health -Name "CLIP" -BaseUrl $clipBaseUrl + + if ($yoloEnabled) { + if ([string]::IsNullOrWhiteSpace($yoloBaseUrl)) { + Write-Info "YOLO is enabled but YOLO_BASE_URL is empty; skipping YOLO /health check." + } else { + Invoke-Health -Name "YOLO" -BaseUrl $yoloBaseUrl + } + } else { + Write-Info "YOLO is disabled; skipping YOLO /health check." + } + + if ($SkipAnalyze) { + Write-Info "Skipping sample analyze call (SkipAnalyze set)." + } else { + Invoke-Analyze -ClipBaseUrl $clipBaseUrl -AnalyzeEndpoint $clipAnalyzeEndpoint -ImageUrl $SampleImageUrl + } + + Test-NonBlockingPublish -Root $ProjectRoot + + Write-Ok "Vision smoke test completed successfully" +} catch { + $failed = $true + Write-Fail $_.Exception.Message +} + +if ($failed) { + exit 1 +} + +exit 0 diff --git a/tailwind.config.js b/tailwind.config.js index c29eb1a1..838c8585 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -11,6 +11,24 @@ export default { theme: { extend: { + colors: { + nova: { + 50: '#EAF0F7', // almost white blue + 100: '#D6E0EE', + 200: '#B3C3DD', + 300: '#8FA5C9', + 400: '#6C87B4', + 500: '#4A6A9A', + 600: '#35537B', + 700: '#233B5A', + 800: '#15243A', + 900: '#0F1724', // main background + }, + deep: '#0F1724', + panel: '#151E2E', + soft: '#7A8CA5', + accent: '#E07A21', + }, fontFamily: { sans: ['Figtree', ...defaultTheme.fontFamily.sans], }, diff --git a/tests/Feature/Admin/FeedPerformanceReportTest.php b/tests/Feature/Admin/FeedPerformanceReportTest.php new file mode 100644 index 00000000..c429a37b --- /dev/null +++ b/tests/Feature/Admin/FeedPerformanceReportTest.php @@ -0,0 +1,104 @@ +create(['role' => 'admin']); + + $artworkA = Artwork::factory()->create(['title' => 'Feed Artwork A']); + $artworkB = Artwork::factory()->create(['title' => 'Feed Artwork B']); + + $metricDate = now()->subDay()->toDateString(); + + DB::table('feed_daily_metrics')->insert([ + [ + 'metric_date' => $metricDate, + 'algo_version' => 'clip-cosine-v1', + 'source' => 'personalized', + 'impressions' => 10, + 'clicks' => 4, + 'saves' => 2, + 'ctr' => 0.4, + 'save_rate' => 0.5, + 'dwell_0_5' => 1, + 'dwell_5_30' => 1, + 'dwell_30_120' => 1, + 'dwell_120_plus' => 1, + 'created_at' => now(), + 'updated_at' => now(), + ], + ]); + + DB::table('feed_events')->insert([ + [ + 'event_date' => $metricDate, + 'event_type' => 'feed_impression', + 'user_id' => $admin->id, + 'artwork_id' => $artworkA->id, + 'position' => 1, + 'algo_version' => 'clip-cosine-v1', + 'source' => 'personalized', + 'dwell_seconds' => null, + 'occurred_at' => now()->subDay(), + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'event_date' => $metricDate, + 'event_type' => 'feed_click', + 'user_id' => $admin->id, + 'artwork_id' => $artworkA->id, + 'position' => 1, + 'algo_version' => 'clip-cosine-v1', + 'source' => 'personalized', + 'dwell_seconds' => 12, + 'occurred_at' => now()->subDay(), + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'event_date' => $metricDate, + 'event_type' => 'feed_click', + 'user_id' => $admin->id, + 'artwork_id' => $artworkB->id, + 'position' => 2, + 'algo_version' => 'clip-cosine-v1', + 'source' => 'personalized', + 'dwell_seconds' => 7, + 'occurred_at' => now()->subDay(), + 'created_at' => now(), + 'updated_at' => now(), + ], + ]); + + $response = $this->actingAs($admin)->getJson('/api/admin/reports/feed-performance?from=' . $metricDate . '&to=' . $metricDate); + + $response->assertOk(); + $response->assertJsonPath('meta.from', $metricDate); + $response->assertJsonPath('meta.to', $metricDate); + + $rows = collect($response->json('by_algo_source')); + expect($rows->count())->toBe(1); + expect($rows->first()['algo_version'])->toBe('clip-cosine-v1'); + expect($rows->first()['source'])->toBe('personalized'); + expect((float) $rows->first()['ctr'])->toBe(0.4); + + $top = collect($response->json('top_clicked_artworks')); + expect($top->isNotEmpty())->toBeTrue(); + expect((int) $top->first()['artwork_id'])->toBe($artworkA->id); +}); + +it('non-admin is denied feed performance report endpoint', function () { + $user = User::factory()->create(['role' => 'user']); + + $response = $this->actingAs($user)->getJson('/api/admin/reports/feed-performance'); + + $response->assertStatus(403); +}); diff --git a/tests/Feature/Admin/SimilarArtworkReportTest.php b/tests/Feature/Admin/SimilarArtworkReportTest.php new file mode 100644 index 00000000..186e3403 --- /dev/null +++ b/tests/Feature/Admin/SimilarArtworkReportTest.php @@ -0,0 +1,99 @@ +create(['role' => 'admin']); + + $sourceA = Artwork::factory()->create(['title' => 'Source A']); + $similarA = Artwork::factory()->create(['title' => 'Similar A']); + $sourceB = Artwork::factory()->create(['title' => 'Source B']); + $similarB = Artwork::factory()->create(['title' => 'Similar B']); + + $inRangeDate = now()->subDay()->toDateString(); + $outRangeDate = now()->subDays(5)->toDateString(); + + DB::table('similar_artwork_events')->insert([ + [ + 'event_date' => $inRangeDate, + 'event_type' => 'impression', + 'algo_version' => 'clip-cosine-v1', + 'source_artwork_id' => $sourceA->id, + 'similar_artwork_id' => $similarA->id, + 'position' => 1, + 'items_count' => 4, + 'occurred_at' => now()->subDay(), + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'event_date' => $inRangeDate, + 'event_type' => 'click', + 'algo_version' => 'clip-cosine-v1', + 'source_artwork_id' => $sourceA->id, + 'similar_artwork_id' => $similarA->id, + 'position' => 1, + 'items_count' => null, + 'occurred_at' => now()->subDay(), + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'event_date' => $inRangeDate, + 'event_type' => 'impression', + 'algo_version' => 'clip-cosine-v2', + 'source_artwork_id' => $sourceB->id, + 'similar_artwork_id' => $similarB->id, + 'position' => 2, + 'items_count' => 4, + 'occurred_at' => now()->subDay(), + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'event_date' => $outRangeDate, + 'event_type' => 'click', + 'algo_version' => 'clip-cosine-v1', + 'source_artwork_id' => $sourceA->id, + 'similar_artwork_id' => $similarA->id, + 'position' => 1, + 'items_count' => null, + 'occurred_at' => now()->subDays(5), + 'created_at' => now(), + 'updated_at' => now(), + ], + ]); + + $response = $this->actingAs($admin)->getJson('/api/admin/reports/similar-artworks?from=' . $inRangeDate . '&to=' . $inRangeDate); + + $response->assertOk(); + $response->assertJsonPath('meta.from', $inRangeDate); + $response->assertJsonPath('meta.to', $inRangeDate); + + $byAlgo = collect($response->json('by_algo_version')); + expect($byAlgo->count())->toBe(2); + + $v1 = $byAlgo->firstWhere('algo_version', 'clip-cosine-v1'); + expect($v1['impressions'])->toBe(1); + expect($v1['clicks'])->toBe(1); + expect((float) $v1['ctr'])->toBe(1.0); + + $top = collect($response->json('top_similarities')); + expect($top->isNotEmpty())->toBeTrue(); + expect($top->first()['source_artwork_id'])->toBe($sourceA->id); + expect($top->first()['similar_artwork_id'])->toBe($similarA->id); + expect((float) $top->first()['ctr'])->toBe(1.0); +}); + +it('non-admin is denied similar artwork report endpoint', function () { + $user = User::factory()->create(['role' => 'user']); + + $response = $this->actingAs($user)->getJson('/api/admin/reports/similar-artworks'); + + $response->assertStatus(403); +}); diff --git a/tests/Feature/Admin/UploadModerationTest.php b/tests/Feature/Admin/UploadModerationTest.php new file mode 100644 index 00000000..7b50779c --- /dev/null +++ b/tests/Feature/Admin/UploadModerationTest.php @@ -0,0 +1,168 @@ +insertGetId([ + 'name' => 'Photography', + 'slug' => 'photography-' . Str::lower(Str::random(6)), + 'description' => null, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + return DB::table('categories')->insertGetId([ + 'content_type_id' => $contentTypeId, + 'parent_id' => null, + 'name' => 'Moderation', + 'slug' => 'moderation-' . Str::lower(Str::random(6)), + 'description' => null, + 'image' => null, + 'is_active' => true, + 'sort_order' => 0, + 'created_at' => now(), + 'updated_at' => now(), + ]); +} + +function createModerationDraft(int $userId, int $categoryId, array $overrides = []): string +{ + $uploadId = (string) Str::uuid(); + + DB::table('uploads')->insert(array_merge([ + 'id' => $uploadId, + 'user_id' => $userId, + 'type' => 'image', + 'status' => 'draft', + 'processing_state' => 'ready', + 'moderation_status' => 'pending', + 'title' => 'Pending Moderation Upload', + 'category_id' => $categoryId, + 'is_scanned' => true, + 'has_tags' => true, + 'preview_path' => "tmp/drafts/{$uploadId}/preview.webp", + 'created_at' => now(), + 'updated_at' => now(), + ], $overrides)); + + return $uploadId; +} + +function addReadyMainFile(string $uploadId, string $hash = 'aabbccddeeff00112233'): void +{ + Storage::disk('local')->put("tmp/drafts/{$uploadId}/main/main.jpg", 'jpg'); + Storage::disk('local')->put("tmp/drafts/{$uploadId}/preview.webp", 'preview'); + + DB::table('upload_files')->insert([ + 'upload_id' => $uploadId, + 'path' => "tmp/drafts/{$uploadId}/main/main.jpg", + 'type' => 'main', + 'hash' => $hash, + 'size' => 3, + 'mime' => 'image/jpeg', + 'created_at' => now(), + ]); +} + +it('admin sees pending uploads', function () { + $admin = User::factory()->create(['role' => 'admin']); + $owner = User::factory()->create(); + $categoryId = createModerationCategory(); + + createModerationDraft($owner->id, $categoryId, ['title' => 'First Pending']); + createModerationDraft($owner->id, $categoryId, ['title' => 'Second Pending']); + + $response = $this->actingAs($admin)->getJson('/api/admin/uploads/pending'); + + $response->assertOk(); + $response->assertJsonCount(2, 'data'); +}); + +it('non-admin is denied moderation API access', function () { + $user = User::factory()->create(['role' => 'user']); + + $response = $this->actingAs($user)->getJson('/api/admin/uploads/pending'); + + $response->assertStatus(403); +}); + +it('approve works', function () { + $admin = User::factory()->create(['role' => 'moderator']); + $owner = User::factory()->create(); + $categoryId = createModerationCategory(); + $uploadId = createModerationDraft($owner->id, $categoryId); + + $response = $this->actingAs($admin)->postJson("/api/admin/uploads/{$uploadId}/approve", [ + 'note' => 'Looks good.', + ]); + + $response->assertOk(); + + $row = DB::table('uploads')->where('id', $uploadId)->first([ + 'moderation_status', + 'moderation_note', + 'moderated_by', + 'moderated_at', + ]); + + expect($row->moderation_status)->toBe('approved'); + expect($row->moderation_note)->toBe('Looks good.'); + expect((int) $row->moderated_by)->toBe((int) $admin->id); + expect($row->moderated_at)->not->toBeNull(); +}); + +it('reject works', function () { + $admin = User::factory()->create(['role' => 'admin']); + $owner = User::factory()->create(); + $categoryId = createModerationCategory(); + $uploadId = createModerationDraft($owner->id, $categoryId); + + $response = $this->actingAs($admin)->postJson("/api/admin/uploads/{$uploadId}/reject", [ + 'note' => 'Policy violation.', + ]); + + $response->assertOk(); + + $row = DB::table('uploads')->where('id', $uploadId)->first([ + 'status', + 'processing_state', + 'moderation_status', + 'moderation_note', + 'moderated_by', + 'moderated_at', + ]); + + expect($row->status)->toBe('rejected'); + expect($row->processing_state)->toBe('rejected'); + expect($row->moderation_status)->toBe('rejected'); + expect($row->moderation_note)->toBe('Policy violation.'); + expect((int) $row->moderated_by)->toBe((int) $admin->id); + expect($row->moderated_at)->not->toBeNull(); +}); + +it('user cannot publish without approval', function () { + Storage::fake('local'); + + $owner = User::factory()->create(['role' => 'user']); + $categoryId = createModerationCategory(); + $uploadId = createModerationDraft($owner->id, $categoryId, [ + 'moderation_status' => 'pending', + 'title' => 'Blocked Publish', + ]); + + addReadyMainFile($uploadId); + + $response = $this->actingAs($owner)->postJson("/api/uploads/{$uploadId}/publish"); + + $response->assertStatus(422); + $response->assertJsonFragment([ + 'message' => 'Upload requires moderation approval before publish.', + ]); +}); diff --git a/tests/Feature/Analytics/FeedAnalyticsTest.php b/tests/Feature/Analytics/FeedAnalyticsTest.php new file mode 100644 index 00000000..cce41f1c --- /dev/null +++ b/tests/Feature/Analytics/FeedAnalyticsTest.php @@ -0,0 +1,138 @@ +create(); + $artwork = Artwork::factory()->create(); + + $response = $this->actingAs($user)->postJson('/api/analytics/feed', [ + 'event_type' => 'feed_click', + 'artwork_id' => $artwork->id, + 'position' => 3, + 'algo_version' => 'clip-cosine-v1', + 'source' => 'personalized', + 'dwell_seconds' => 27, + ]); + + $response->assertOk()->assertJson(['success' => true]); + + $this->assertDatabaseHas('feed_events', [ + 'user_id' => $user->id, + 'artwork_id' => $artwork->id, + 'event_type' => 'feed_click', + 'position' => 3, + 'algo_version' => 'clip-cosine-v1', + 'source' => 'personalized', + 'dwell_seconds' => 27, + ]); +}); + +it('aggregates daily feed analytics with ctr save-rate and dwell buckets', function () { + $user = User::factory()->create(); + + $artworkA = Artwork::factory()->create(); + $artworkB = Artwork::factory()->create(); + + $metricDate = now()->subDay()->toDateString(); + + DB::table('feed_events')->insert([ + [ + 'event_date' => $metricDate, + 'event_type' => 'feed_impression', + 'user_id' => $user->id, + 'artwork_id' => $artworkA->id, + 'position' => 1, + 'algo_version' => 'clip-cosine-v1', + 'source' => 'personalized', + 'dwell_seconds' => null, + 'occurred_at' => now()->subDay(), + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'event_date' => $metricDate, + 'event_type' => 'feed_impression', + 'user_id' => $user->id, + 'artwork_id' => $artworkB->id, + 'position' => 2, + 'algo_version' => 'clip-cosine-v1', + 'source' => 'personalized', + 'dwell_seconds' => null, + 'occurred_at' => now()->subDay(), + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'event_date' => $metricDate, + 'event_type' => 'feed_click', + 'user_id' => $user->id, + 'artwork_id' => $artworkA->id, + 'position' => 1, + 'algo_version' => 'clip-cosine-v1', + 'source' => 'personalized', + 'dwell_seconds' => 3, + 'occurred_at' => now()->subDay(), + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'event_date' => $metricDate, + 'event_type' => 'feed_click', + 'user_id' => $user->id, + 'artwork_id' => $artworkB->id, + 'position' => 2, + 'algo_version' => 'clip-cosine-v1', + 'source' => 'personalized', + 'dwell_seconds' => 35, + 'occurred_at' => now()->subDay(), + 'created_at' => now(), + 'updated_at' => now(), + ], + ]); + + DB::table('user_discovery_events')->insert([ + 'event_id' => '33333333-3333-3333-3333-333333333333', + 'user_id' => $user->id, + 'artwork_id' => $artworkA->id, + 'category_id' => null, + 'event_type' => 'favorite', + 'event_version' => 'event-v1', + 'algo_version' => 'clip-cosine-v1', + 'weight' => 1, + 'event_date' => $metricDate, + 'occurred_at' => now()->subDay(), + 'meta' => null, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + $this->artisan('analytics:aggregate-feed', ['--date' => $metricDate])->assertSuccessful(); + + $this->assertDatabaseHas('feed_daily_metrics', [ + 'metric_date' => $metricDate, + 'algo_version' => 'clip-cosine-v1', + 'source' => 'personalized', + 'impressions' => 2, + 'clicks' => 2, + 'saves' => 1, + 'dwell_0_5' => 1, + 'dwell_30_120' => 1, + ]); + + $metric = DB::table('feed_daily_metrics') + ->where('metric_date', $metricDate) + ->where('algo_version', 'clip-cosine-v1') + ->where('source', 'personalized') + ->first(); + + expect((float) $metric->ctr)->toBe(1.0); + expect((float) $metric->save_rate)->toBe(0.5); +}); diff --git a/tests/Feature/Analytics/FeedEvaluationCommandsTest.php b/tests/Feature/Analytics/FeedEvaluationCommandsTest.php new file mode 100644 index 00000000..b8faaca4 --- /dev/null +++ b/tests/Feature/Analytics/FeedEvaluationCommandsTest.php @@ -0,0 +1,93 @@ +subDay()->toDateString(); + + DB::table('feed_daily_metrics')->insert([ + [ + 'metric_date' => $metricDate, + 'algo_version' => 'clip-cosine-v1', + 'source' => 'personalized', + 'impressions' => 100, + 'clicks' => 20, + 'saves' => 6, + 'ctr' => 0.2, + 'save_rate' => 0.3, + 'dwell_0_5' => 4, + 'dwell_5_30' => 8, + 'dwell_30_120' => 5, + 'dwell_120_plus' => 3, + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'metric_date' => $metricDate, + 'algo_version' => 'clip-cosine-v2', + 'source' => 'personalized', + 'impressions' => 100, + 'clicks' => 22, + 'saves' => 8, + 'ctr' => 0.22, + 'save_rate' => 0.36, + 'dwell_0_5' => 3, + 'dwell_5_30' => 9, + 'dwell_30_120' => 6, + 'dwell_120_plus' => 4, + 'created_at' => now(), + 'updated_at' => now(), + ], + ]); + + $this->artisan('analytics:evaluate-feed-weights', ['--from' => $metricDate, '--to' => $metricDate]) + ->assertSuccessful(); +}); + +it('compares baseline and candidate feed algos', function () { + $metricDate = now()->subDay()->toDateString(); + + DB::table('feed_daily_metrics')->insert([ + [ + 'metric_date' => $metricDate, + 'algo_version' => 'clip-cosine-v1', + 'source' => 'personalized', + 'impressions' => 100, + 'clicks' => 20, + 'saves' => 6, + 'ctr' => 0.2, + 'save_rate' => 0.3, + 'dwell_0_5' => 4, + 'dwell_5_30' => 8, + 'dwell_30_120' => 5, + 'dwell_120_plus' => 3, + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'metric_date' => $metricDate, + 'algo_version' => 'clip-cosine-v2', + 'source' => 'personalized', + 'impressions' => 100, + 'clicks' => 24, + 'saves' => 10, + 'ctr' => 0.24, + 'save_rate' => 0.416, + 'dwell_0_5' => 3, + 'dwell_5_30' => 8, + 'dwell_30_120' => 7, + 'dwell_120_plus' => 6, + 'created_at' => now(), + 'updated_at' => now(), + ], + ]); + + $this->artisan('analytics:compare-feed-ab', [ + 'baseline' => 'clip-cosine-v1', + 'candidate' => 'clip-cosine-v2', + '--from' => $metricDate, + '--to' => $metricDate, + ])->assertSuccessful(); +}); diff --git a/tests/Feature/Analytics/SimilarArtworkAnalyticsTest.php b/tests/Feature/Analytics/SimilarArtworkAnalyticsTest.php new file mode 100644 index 00000000..094c9601 --- /dev/null +++ b/tests/Feature/Analytics/SimilarArtworkAnalyticsTest.php @@ -0,0 +1,72 @@ +create(); + + $source = Artwork::factory()->create(['user_id' => $author->id]); + $similar = Artwork::factory()->create(['user_id' => $author->id]); + + $response = $this->postJson('/api/analytics/similar-artworks', [ + 'event_type' => 'click', + 'algo_version' => 'clip-cosine-v1', + 'source_artwork_id' => $source->id, + 'similar_artwork_id' => $similar->id, + 'position' => 2, + ]); + + $response->assertOk()->assertJson(['success' => true]); + + $this->assertDatabaseHas('similar_artwork_events', [ + 'event_type' => 'click', + 'algo_version' => 'clip-cosine-v1', + 'source_artwork_id' => $source->id, + 'similar_artwork_id' => $similar->id, + 'position' => 2, + ]); +}); + +it('aggregates daily analytics counts by algo version', function () { + DB::table('similar_artwork_events')->insert([ + [ + 'event_date' => now()->subDay()->toDateString(), + 'event_type' => 'impression', + 'algo_version' => 'clip-cosine-v1', + 'source_artwork_id' => Artwork::factory()->create()->id, + 'similar_artwork_id' => null, + 'position' => null, + 'items_count' => 8, + 'occurred_at' => now()->subDay(), + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'event_date' => now()->subDay()->toDateString(), + 'event_type' => 'click', + 'algo_version' => 'clip-cosine-v1', + 'source_artwork_id' => Artwork::factory()->create()->id, + 'similar_artwork_id' => Artwork::factory()->create()->id, + 'position' => 1, + 'items_count' => null, + 'occurred_at' => now()->subDay(), + 'created_at' => now(), + 'updated_at' => now(), + ], + ]); + + $this->artisan('analytics:aggregate-similar-artworks', ['--date' => now()->subDay()->toDateString()]) + ->assertSuccessful(); + + $this->assertDatabaseHas('similar_artwork_daily_metrics', [ + 'metric_date' => now()->subDay()->toDateString(), + 'algo_version' => 'clip-cosine-v1', + 'impressions' => 1, + 'clicks' => 1, + ]); +}); diff --git a/tests/Feature/ArtworkJsonLdTest.php b/tests/Feature/ArtworkJsonLdTest.php new file mode 100644 index 00000000..b4e16073 --- /dev/null +++ b/tests/Feature/ArtworkJsonLdTest.php @@ -0,0 +1,117 @@ +create(['name' => 'Schema Author']); + + $contentType = ContentType::create([ + 'name' => 'Photography', + 'slug' => 'photography', + 'description' => 'Photography content', + ]); + + $category = Category::create([ + 'content_type_id' => $contentType->id, + 'parent_id' => null, + 'name' => 'Abstract', + 'slug' => 'abstract-' . Str::lower(Str::random(5)), + 'description' => 'Abstract works', + 'is_active' => true, + 'sort_order' => 0, + ]); + + $artwork = Artwork::factory()->create([ + 'user_id' => $user->id, + 'title' => 'Schema Ready Artwork', + 'slug' => 'schema-ready-artwork', + 'description' => 'Artwork description for schema test.', + 'mime_type' => 'image/jpeg', + 'published_at' => now()->subMinute(), + 'is_public' => true, + 'is_approved' => true, + ]); + + $artwork->categories()->attach($category->id); + + $tagA = Tag::create(['name' => 'neon', 'slug' => 'neon', 'usage_count' => 0, 'is_active' => true]); + $tagB = Tag::create(['name' => 'city', 'slug' => 'city', 'usage_count' => 0, 'is_active' => true]); + $artwork->tags()->attach([ + $tagA->id => ['source' => 'user', 'confidence' => 0.9], + $tagB->id => ['source' => 'user', 'confidence' => 0.8], + ]); + + $html = view('artworks.show', ['artwork' => $artwork])->render(); + + expect($html) + ->toContain('application/ld+json') + ->toContain('"@type":"ImageObject"') + ->toContain('"name":"Schema Ready Artwork"') + ->toContain('"keywords":["neon","city"]'); +}); + +it('renders JSON-LD via routed artwork show endpoint', function () { + $user = User::factory()->create(['name' => 'Schema Route Author']); + + $contentType = ContentType::create([ + 'name' => 'Photography', + 'slug' => 'photography', + 'description' => 'Photography content', + ]); + + $category = Category::create([ + 'content_type_id' => $contentType->id, + 'parent_id' => null, + 'name' => 'Abstract', + 'slug' => 'abstract-route', + 'description' => 'Abstract works', + 'is_active' => true, + 'sort_order' => 0, + ]); + + $artwork = Artwork::factory()->create([ + 'user_id' => $user->id, + 'title' => 'Schema Route Artwork', + 'slug' => 'schema-route-artwork', + 'description' => 'Artwork description for routed schema test.', + 'mime_type' => 'image/png', + 'published_at' => now()->subMinute(), + 'is_public' => true, + 'is_approved' => true, + ]); + + $artwork->categories()->attach($category->id); + + $tag = Tag::create(['name' => 'route-tag', 'slug' => 'route-tag', 'usage_count' => 0, 'is_active' => true]); + $artwork->tags()->attach([ + $tag->id => ['source' => 'user', 'confidence' => 0.95], + ]); + + $url = route('artworks.show', [ + 'contentTypeSlug' => $contentType->slug, + 'categoryPath' => $category->slug, + 'artwork' => $artwork->slug, + ]); + + expect($url)->toContain('/photography/abstract-route/schema-route-artwork'); + + $matchedRoute = app('router')->getRoutes()->match(Request::create($url, 'GET')); + expect($matchedRoute->getName())->toBe('artworks.show'); + + $response = $this->get($url); + + $response->assertOk(); + $response->assertSee('application/ld+json', false); + $response->assertSee('"@type":"ImageObject"', false); + $response->assertSee('"name":"Schema Route Artwork"', false); + $response->assertSee('"keywords":["route-tag"]', false); +}); diff --git a/tests/Feature/AutoTagArtworkJobTest.php b/tests/Feature/AutoTagArtworkJobTest.php new file mode 100644 index 00000000..fd4d380f --- /dev/null +++ b/tests/Feature/AutoTagArtworkJobTest.php @@ -0,0 +1,76 @@ +set('vision.enabled', true); + config()->set('vision.clip.base_url', 'https://clip.local'); + config()->set('vision.clip.endpoint', '/analyze'); + config()->set('vision.yolo.enabled', false); + config()->set('cdn.files_url', 'https://files.local'); + + Http::fake([ + 'https://clip.local/analyze' => Http::response([ + ['tag' => 'Cyber Punk', 'confidence' => 0.42], + ['tag' => 'City', 'confidence' => 0.31], + ], 200), + ]); + + $artwork = Artwork::factory()->create(); + $hash = 'abcdef123456'; + + (new AutoTagArtworkJob($artwork->id, $hash))->handle(app(\App\Services\TagService::class), app(\App\Services\TagNormalizer::class)); + + expect(Tag::query()->whereIn('slug', ['cyber-punk', 'city'])->count())->toBe(2); + expect($artwork->tags()->pluck('slug')->all())->toContain('cyber-punk', 'city'); +}); + +it('optionally calls YOLO for photography', function () { + config()->set('vision.enabled', true); + config()->set('vision.clip.base_url', 'https://clip.local'); + config()->set('vision.yolo.base_url', 'https://yolo.local'); + config()->set('vision.yolo.enabled', true); + config()->set('vision.yolo.photography_only', true); + config()->set('cdn.files_url', 'https://files.local'); + + Http::fake([ + 'https://clip.local/analyze' => Http::response([['tag' => 'tree', 'confidence' => 0.2]], 200), + 'https://yolo.local/analyze' => Http::response(['objects' => [['label' => 'person', 'confidence' => 0.9]]], 200), + ]); + + $photoType = ContentType::query()->create(['name' => 'Photography', 'slug' => 'photography', 'description' => '']); + $cat = Category::query()->create(['content_type_id' => $photoType->id, 'parent_id' => null, 'name' => 'Test', 'slug' => 'test', 'description' => '', 'image' => null, 'is_active' => true, 'sort_order' => 0]); + + $artwork = Artwork::factory()->create(); + $artwork->categories()->attach($cat->id); + + $hash = 'abcdef123456'; + (new AutoTagArtworkJob($artwork->id, $hash))->handle(app(\App\Services\TagService::class), app(\App\Services\TagNormalizer::class)); + + expect($artwork->tags()->pluck('slug')->all())->toContain('tree', 'person'); +}); + +it('does not throw on CLIP 4xx and never blocks publish', function () { + config()->set('vision.enabled', true); + config()->set('vision.clip.base_url', 'https://clip.local'); + config()->set('vision.yolo.enabled', false); + config()->set('cdn.files_url', 'https://files.local'); + + Http::fake([ + 'https://clip.local/analyze' => Http::response(['message' => 'bad'], 422), + ]); + + $artwork = Artwork::factory()->create(); + $hash = 'abcdef123456'; + + (new AutoTagArtworkJob($artwork->id, $hash))->handle(app(\App\Services\TagService::class), app(\App\Services\TagNormalizer::class)); + + expect($artwork->tags()->count())->toBe(0); +}); diff --git a/tests/Feature/AvatarUploadTest.php b/tests/Feature/AvatarUploadTest.php new file mode 100644 index 00000000..aafbf672 --- /dev/null +++ b/tests/Feature/AvatarUploadTest.php @@ -0,0 +1,15 @@ +postJson(route('avatar.upload')); + $response->assertStatus(401); + } +} diff --git a/tests/Feature/ContentRouterControllerTest.php b/tests/Feature/ContentRouterControllerTest.php new file mode 100644 index 00000000..4fa59c75 --- /dev/null +++ b/tests/Feature/ContentRouterControllerTest.php @@ -0,0 +1,56 @@ +create([ + 'slug' => 'bound-model-artwork', + 'is_public' => true, + 'is_approved' => true, + 'published_at' => now()->subMinute(), + ]); + + $request = Request::create('/photography/abstract/bound-model-artwork', 'GET'); + + $response = app(ContentRouterController::class)->handle( + $request, + 'photography', + 'abstract', + $artwork + ); + + expect($response)->toBeInstanceOf(View::class); + expect($response->name())->toBe('artworks.show'); + expect($response->getData()['artwork']->id)->toBe($artwork->id); +}); + +it('binds routed artwork model and renders published artwork page', function () { + $artwork = Artwork::factory()->create([ + 'title' => 'Routed Binding Artwork', + 'slug' => 'routed-binding-artwork', + 'is_public' => true, + 'is_approved' => true, + 'published_at' => now()->subMinute(), + ]); + + $url = route('artworks.show', [ + 'contentTypeSlug' => 'photography', + 'categoryPath' => 'abstract', + 'artwork' => $artwork->slug, + ]); + + $matchedRoute = app('router')->getRoutes()->match(Request::create($url, 'GET')); + app('router')->substituteBindings($matchedRoute); + expect($matchedRoute->parameter('artwork'))->toBeInstanceOf(Artwork::class); + expect($matchedRoute->parameter('artwork')->id)->toBe($artwork->id); + + $this->get($url) + ->assertOk() + ->assertSee('Routed Binding Artwork'); +}); diff --git a/tests/Feature/Discovery/DiscoveryEventIngestionTest.php b/tests/Feature/Discovery/DiscoveryEventIngestionTest.php new file mode 100644 index 00000000..e7b537f7 --- /dev/null +++ b/tests/Feature/Discovery/DiscoveryEventIngestionTest.php @@ -0,0 +1,48 @@ +create(); + $artwork = Artwork::factory()->create(); + + $response = $this->actingAs($user)->postJson('/api/discovery/events', [ + 'event_type' => 'view', + 'artwork_id' => $artwork->id, + 'meta' => ['source' => 'artwork_show'], + ]); + + $response + ->assertStatus(202) + ->assertJsonPath('queued', true) + ->assertJsonPath('algo_version', (string) config('discovery.algo_version')); + + Queue::assertPushed(IngestUserDiscoveryEventJob::class, function (IngestUserDiscoveryEventJob $job) use ($user, $artwork): bool { + return $job->userId === $user->id + && $job->artworkId === $artwork->id + && $job->eventType === 'view'; + }); +}); + +it('validates discovery event payload', function () { + $user = User::factory()->create(); + $artwork = Artwork::factory()->create(); + + $response = $this->actingAs($user)->postJson('/api/discovery/events', [ + 'event_type' => 'impression', + 'artwork_id' => $artwork->id, + ]); + + $response->assertStatus(422); + $response->assertJsonValidationErrors(['event_type']); +}); diff --git a/tests/Feature/Discovery/FeedEndpointTest.php b/tests/Feature/Discovery/FeedEndpointTest.php new file mode 100644 index 00000000..73afca42 --- /dev/null +++ b/tests/Feature/Discovery/FeedEndpointTest.php @@ -0,0 +1,113 @@ +create(); + + $artworkA = Artwork::factory()->create(['is_public' => true, 'is_approved' => true, 'published_at' => now()->subMinutes(3)]); + $artworkB = Artwork::factory()->create(['is_public' => true, 'is_approved' => true, 'published_at' => now()->subMinutes(2)]); + $artworkC = Artwork::factory()->create(['is_public' => true, 'is_approved' => true, 'published_at' => now()->subMinutes(1)]); + + UserRecommendationCache::query()->create([ + 'user_id' => $user->id, + 'algo_version' => (string) config('discovery.algo_version'), + 'cache_version' => (string) config('discovery.cache_version'), + 'recommendations_json' => [ + 'items' => [ + ['artwork_id' => $artworkA->id, 'score' => 0.9, 'source' => 'profile'], + ['artwork_id' => $artworkB->id, 'score' => 0.8, 'source' => 'profile'], + ['artwork_id' => $artworkC->id, 'score' => 0.7, 'source' => 'profile'], + ], + ], + 'generated_at' => now(), + 'expires_at' => now()->addMinutes(30), + ]); + + $first = $this->actingAs($user)->getJson('/api/v1/feed?limit=2'); + + $first->assertOk(); + $first->assertJsonPath('meta.cache_status', 'hit'); + expect(count((array) $first->json('data')))->toBe(2); + + $nextCursor = $first->json('meta.next_cursor'); + expect($nextCursor)->not->toBeNull(); + + $second = $this->actingAs($user)->getJson('/api/v1/feed?limit=2&cursor=' . urlencode((string) $nextCursor)); + + $second->assertOk(); + expect(count((array) $second->json('data')))->toBe(1); + expect($second->json('meta.next_cursor'))->toBeNull(); +}); + +it('dispatches async regeneration on cache miss and returns cold start items', function () { + Queue::fake(); + + $user = User::factory()->create(); + + $artworkA = Artwork::factory()->create(['is_public' => true, 'is_approved' => true, 'published_at' => now()->subMinutes(3)]); + $artworkB = Artwork::factory()->create(['is_public' => true, 'is_approved' => true, 'published_at' => now()->subMinutes(2)]); + + DB::table('artwork_stats')->insert([ + ['artwork_id' => $artworkA->id, 'views' => 100, 'downloads' => 30, 'favorites' => 10, 'rating_avg' => 0, 'rating_count' => 0], + ['artwork_id' => $artworkB->id, 'views' => 80, 'downloads' => 10, 'favorites' => 5, 'rating_avg' => 0, 'rating_count' => 0], + ]); + + $response = $this->actingAs($user)->getJson('/api/v1/feed?limit=10'); + + $response->assertOk(); + expect(count((array) $response->json('data')))->toBeGreaterThan(0); + expect((string) $response->json('meta.cache_status'))->toContain('miss'); + + Queue::assertPushed(RegenerateUserRecommendationCacheJob::class, function (RegenerateUserRecommendationCacheJob $job) use ($user): bool { + return $job->userId === $user->id; + }); +}); + +it('applies diversity guard to avoid near-duplicates in cold start fallback', function () { + Queue::fake(); + + $user = User::factory()->create(); + + $artworkA = Artwork::factory()->create(['is_public' => true, 'is_approved' => true, 'published_at' => now()->subMinutes(3)]); + $artworkB = Artwork::factory()->create(['is_public' => true, 'is_approved' => true, 'published_at' => now()->subMinutes(2)]); + $artworkC = Artwork::factory()->create(['is_public' => true, 'is_approved' => true, 'published_at' => now()->subMinutes(1)]); + + DB::table('artwork_stats')->insert([ + ['artwork_id' => $artworkA->id, 'views' => 200, 'downloads' => 20, 'favorites' => 5, 'rating_avg' => 0, 'rating_count' => 0], + ['artwork_id' => $artworkB->id, 'views' => 190, 'downloads' => 18, 'favorites' => 4, 'rating_avg' => 0, 'rating_count' => 0], + ['artwork_id' => $artworkC->id, 'views' => 180, 'downloads' => 12, 'favorites' => 3, 'rating_avg' => 0, 'rating_count' => 0], + ]); + + DB::table('artwork_similarities')->insert([ + 'artwork_id' => $artworkA->id, + 'similar_artwork_id' => $artworkB->id, + 'model' => 'clip', + 'model_version' => 'v1', + 'algo_version' => (string) config('discovery.algo_version'), + 'rank' => 1, + 'score' => 0.991, + 'generated_at' => now(), + 'created_at' => now(), + 'updated_at' => now(), + ]); + + $response = $this->actingAs($user)->getJson('/api/v1/feed?limit=10'); + + $response->assertOk(); + + $ids = collect((array) $response->json('data'))->pluck('id')->all(); + + expect(in_array($artworkA->id, $ids, true) && in_array($artworkB->id, $ids, true))->toBeFalse(); + expect(in_array($artworkC->id, $ids, true))->toBeTrue(); +}); diff --git a/tests/Feature/ProfileTest.php b/tests/Feature/ProfileTest.php index 2bacbbd6..5b10ce47 100644 --- a/tests/Feature/ProfileTest.php +++ b/tests/Feature/ProfileTest.php @@ -3,28 +3,28 @@ use App\Models\User; test('profile page is displayed', function () { - $user = User::factory()->create(); + $user = User::factory()->create(['email' => null]); - $response = $this - ->actingAs($user) - ->get('/profile'); + $response = $this + ->actingAs($user) + ->get('/profile'); $response->assertOk(); }); test('profile information can be updated', function () { - $user = User::factory()->create(); + $user = User::factory()->create(['email' => null]); $response = $this ->actingAs($user) - ->patch('/profile', [ + ->patch('/profile', [ 'name' => 'Test User', 'email' => 'test@example.com', ]); - $response - ->assertSessionHasNoErrors() - ->assertRedirect('/profile'); + $response + ->assertSessionHasNoErrors() + ->assertRedirect('/user'); $user->refresh(); @@ -38,14 +38,14 @@ test('email verification status is unchanged when the email address is unchanged $response = $this ->actingAs($user) - ->patch('/profile', [ + ->patch('/profile', [ 'name' => 'Test User', 'email' => $user->email, ]); - $response - ->assertSessionHasNoErrors() - ->assertRedirect('/profile'); + $response + ->assertSessionHasNoErrors() + ->assertRedirect('/user'); $this->assertNotNull($user->refresh()->email_verified_at); }); @@ -55,13 +55,13 @@ test('user can delete their account', function () { $response = $this ->actingAs($user) - ->delete('/profile', [ + ->delete('/profile', [ 'password' => 'password', ]); - $response - ->assertSessionHasNoErrors() - ->assertRedirect('/'); + $response + ->assertSessionHasNoErrors() + ->assertRedirect('/'); $this->assertGuest(); // User should be soft-deleted, not permanently removed @@ -74,13 +74,13 @@ test('correct password must be provided to delete account', function () { $response = $this ->actingAs($user) ->from('/profile') - ->delete('/profile', [ + ->delete('/profile', [ 'password' => 'wrong-password', ]); - $response - ->assertSessionHasErrorsIn('userDeletion', 'password') - ->assertRedirect('/profile'); + $response + ->assertSessionHasErrorsIn('userDeletion', 'password') + ->assertRedirect('/profile'); $this->assertNotNull($user->fresh()); }); diff --git a/tests/Feature/SimilarArtworksBlockTest.php b/tests/Feature/SimilarArtworksBlockTest.php new file mode 100644 index 00000000..26ba3d42 --- /dev/null +++ b/tests/Feature/SimilarArtworksBlockTest.php @@ -0,0 +1,120 @@ + 'Photography', + 'slug' => 'photography', + 'description' => 'Photography content', + ]); + + $category = Category::create([ + 'content_type_id' => $contentType->id, + 'parent_id' => null, + 'name' => 'Abstract', + 'slug' => 'abstract-similar', + 'description' => 'Abstract works', + 'is_active' => true, + 'sort_order' => 0, + ]); + + return [$contentType, $category]; +} + +it('renders similar artworks block when similarities exist with algo version and CDN thumbnails', function () { + [$contentType, $category] = createContentTypeAndCategoryForSimilarTests(); + + $author = User::factory()->create(); + + $source = Artwork::factory()->create([ + 'user_id' => $author->id, + 'title' => 'Source Artwork', + 'slug' => 'source-artwork', + 'hash' => 'aa11bb22cc33', + 'thumb_ext' => 'webp', + 'published_at' => now()->subMinute(), + 'is_public' => true, + 'is_approved' => true, + ]); + + $similar = Artwork::factory()->create([ + 'user_id' => $author->id, + 'title' => 'Similar Artwork', + 'slug' => 'similar-artwork', + 'hash' => 'bb22cc33dd44', + 'thumb_ext' => 'webp', + 'published_at' => now()->subMinute(), + 'is_public' => true, + 'is_approved' => true, + ]); + + $source->categories()->attach($category->id); + $similar->categories()->attach($category->id); + + DB::table('artwork_similarities')->insert([ + 'artwork_id' => $source->id, + 'similar_artwork_id' => $similar->id, + 'model' => 'clip', + 'model_version' => 'v1', + 'algo_version' => 'clip-cosine-v1', + 'rank' => 1, + 'score' => 0.9234567, + 'generated_at' => now(), + 'created_at' => now(), + 'updated_at' => now(), + ]); + + $url = route('artworks.show', [ + 'contentTypeSlug' => $contentType->slug, + 'categoryPath' => $category->slug, + 'artwork' => $source->slug, + ]); + + $response = $this->get($url); + + $response->assertOk(); + $response->assertSee('Similar artworks'); + $response->assertSee('data-algo-version="clip-cosine-v1"', false); + $response->assertSee((string) $similar->thumb_url, false); + $response->assertSee('https://files.skinbase.org', false); +}); + +it('hides similar artworks block when no similarities exist', function () { + [$contentType, $category] = createContentTypeAndCategoryForSimilarTests(); + + $author = User::factory()->create(); + + $source = Artwork::factory()->create([ + 'user_id' => $author->id, + 'title' => 'Lonely Artwork', + 'slug' => 'lonely-artwork', + 'hash' => 'cc33dd44ee55', + 'thumb_ext' => 'webp', + 'published_at' => now()->subMinute(), + 'is_public' => true, + 'is_approved' => true, + ]); + + $source->categories()->attach($category->id); + + $url = route('artworks.show', [ + 'contentTypeSlug' => $contentType->slug, + 'categoryPath' => $category->slug, + 'artwork' => $source->slug, + ]); + + $response = $this->get($url); + + $response->assertOk(); + $response->assertDontSee('Similar artworks', false); + $response->assertDontSee('data-similar-analytics', false); +}); diff --git a/tests/Feature/TagSystemTest.php b/tests/Feature/TagSystemTest.php new file mode 100644 index 00000000..3b404dcd --- /dev/null +++ b/tests/Feature/TagSystemTest.php @@ -0,0 +1,100 @@ +normalize(' Cyber Punk!! '))->toBe('cyber-punk'); + expect($n->normalize("🚀 Rocket "))->toBe('rocket'); + expect($n->normalize(''))->toBe(''); +}); + +it('prevents duplicate tags and duplicate pivots for user tags', function () { + $service = app(TagService::class); + $artwork = Artwork::factory()->create(); + + $service->attachUserTags($artwork, ['CyberPunk', ' cyberpunk ', 'CYBERPUNK']); + + expect(Tag::query()->count())->toBe(1); + expect($artwork->tags()->count())->toBe(1); + expect(Tag::first()->usage_count)->toBe(1); +}); + +it('attaches AI tags with source and confidence without blocking existing user tags', function () { + $service = app(TagService::class); + $artwork = Artwork::factory()->create(); + + $service->attachUserTags($artwork, ['city']); + $service->attachAiTags($artwork, [ + ['tag' => 'city', 'confidence' => 0.2], + ['tag' => 'cyberpunk', 'confidence' => 0.42], + ]); + + $artwork->load('tags'); + $city = $artwork->tags->firstWhere('slug', 'city'); + $cyber = $artwork->tags->firstWhere('slug', 'cyberpunk'); + + expect($city)->not->toBeNull(); + expect($city->pivot->source)->toBe('user'); + expect($city->pivot->confidence)->toBeNull(); + + expect($cyber)->not->toBeNull(); + expect($cyber->pivot->source)->toBe('ai'); + expect($cyber->pivot->confidence)->toBeFloat(); +}); + +it('syncs user tags and maintains usage counts', function () { + $service = app(TagService::class); + $artwork = Artwork::factory()->create(); + + $service->attachUserTags($artwork, ['one', 'two']); + expect(Tag::query()->whereIn('slug', ['one', 'two'])->pluck('usage_count', 'slug')->all()) + ->toMatchArray(['one' => 1, 'two' => 1]); + + $service->syncTags($artwork, ['two', 'three']); + $artwork->refresh(); + + expect($artwork->tags()->pluck('slug')->all())->toContain('two', 'three'); + + $counts = Tag::query()->whereIn('slug', ['one', 'two', 'three'])->pluck('usage_count', 'slug')->all(); + expect($counts['one'])->toBe(0); + expect($counts['two'])->toBe(1); + expect($counts['three'])->toBe(1); +}); + +it('enforces pivot integrity (single row per artwork-tag) and user precedence', function () { + $service = app(TagService::class); + $artwork = Artwork::factory()->create(); + + $service->attachAiTags($artwork, [['tag' => 'future', 'confidence' => 0.31]]); + $service->attachUserTags($artwork, ['future']); + + $artwork->load('tags'); + $future = $artwork->tags->firstWhere('slug', 'future'); + + expect($future)->not->toBeNull(); + expect($future->pivot->source)->toBe('user'); + expect($future->pivot->confidence)->toBeNull(); + expect(DB::table('artwork_tag')->where('artwork_id', $artwork->id)->where('tag_id', $future->id)->count())->toBe(1); +}); + +it('cleans up pivots and decrements usage counts when artwork is force deleted', function () { + $service = app(TagService::class); + $artwork = Artwork::factory()->create(); + + $service->attachUserTags($artwork, ['a', 'b']); + $tagIds = Tag::query()->pluck('id')->all(); + + expect(DB::table('artwork_tag')->where('artwork_id', $artwork->id)->count())->toBe(2); + $artwork->forceDelete(); + + expect(DB::table('artwork_tag')->whereIn('tag_id', $tagIds)->count())->toBe(0); + expect(Tag::query()->whereIn('id', $tagIds)->sum('usage_count'))->toBe(0); +}); diff --git a/tests/Feature/Uploads/ArchiveUploadSecurityTest.php b/tests/Feature/Uploads/ArchiveUploadSecurityTest.php new file mode 100644 index 00000000..240dfc4c --- /dev/null +++ b/tests/Feature/Uploads/ArchiveUploadSecurityTest.php @@ -0,0 +1,212 @@ + */ +$tempArchives = []; + +afterEach(function () use (&$tempArchives): void { + foreach ($tempArchives as $path) { + if (is_file($path)) { + @unlink($path); + } + } + + $tempArchives = []; +}); + +/** + * @param array $entries + * @param (callable(\ZipArchive,string):void)|null $entryCallback + */ +function makeArchiveUpload(array $entries, array &$tempArchives, ?callable $entryCallback = null): UploadedFile +{ + if (! class_exists(\ZipArchive::class)) { + test()->markTestSkipped('ZipArchive extension is required.'); + } + + $path = tempnam(sys_get_temp_dir(), 'sb_upload_zip_'); + if ($path === false) { + throw new \RuntimeException('Failed to allocate temp archive path.'); + } + + $tempArchives[] = $path; + + $zip = new \ZipArchive(); + if ($zip->open($path, \ZipArchive::OVERWRITE | \ZipArchive::CREATE) !== true) { + throw new \RuntimeException('Failed to create test zip archive.'); + } + + foreach ($entries as $name => $content) { + $zip->addFromString($name, $content); + if ($entryCallback !== null) { + $entryCallback($zip, $name); + } + } + + $zip->close(); + + return new UploadedFile($path, 'archive.zip', 'application/zip', null, true); +} + +it('rejects archive with zip slip path during preload', function () use (&$tempArchives) { + Storage::fake('local'); + $user = User::factory()->create(); + + $archive = makeArchiveUpload([ + '../evil.txt' => 'x', + ], $tempArchives); + + $screenshot = UploadedFile::fake()->image('screen.jpg', 800, 600); + + $response = $this->actingAs($user)->postJson('/api/uploads/preload', [ + 'main' => $archive, + 'screenshots' => [$screenshot], + ]); + + $response->assertStatus(422) + ->assertJsonPath('message', 'Archive inspection failed.'); + + expect(strtolower((string) $response->json('reason')))->toContain('path'); +}); + +it('rejects archive with symlink during preload', function () use (&$tempArchives) { + Storage::fake('local'); + $user = User::factory()->create(); + + $archive = makeArchiveUpload([ + 'safe/readme.txt' => 'ok', + 'safe/link' => 'target', + ], $tempArchives, function (\ZipArchive $zip, string $entryName): void { + if ($entryName === 'safe/link') { + $zip->setExternalAttributesName($entryName, \ZipArchive::OPSYS_UNIX, 0120777 << 16); + } + }); + + $screenshot = UploadedFile::fake()->image('screen.jpg', 800, 600); + + $response = $this->actingAs($user)->postJson('/api/uploads/preload', [ + 'main' => $archive, + 'screenshots' => [$screenshot], + ]); + + $response->assertStatus(422) + ->assertJsonPath('message', 'Archive inspection failed.'); + + expect(strtolower((string) $response->json('reason')))->toContain('symlink'); +}); + +it('rejects archive with deep nesting during preload', function () use (&$tempArchives) { + Storage::fake('local'); + $user = User::factory()->create(); + + $archive = makeArchiveUpload([ + 'a/b/c/d/e/f/file.txt' => 'deep', + ], $tempArchives); + + $screenshot = UploadedFile::fake()->image('screen.jpg', 800, 600); + + $response = $this->actingAs($user)->postJson('/api/uploads/preload', [ + 'main' => $archive, + 'screenshots' => [$screenshot], + ]); + + $response->assertStatus(422) + ->assertJsonPath('message', 'Archive inspection failed.'); + + expect(strtolower((string) $response->json('reason')))->toContain('depth'); +}); + +it('rejects archive with too many files during preload', function () use (&$tempArchives) { + Storage::fake('local'); + $user = User::factory()->create(); + + $entries = []; + for ($index = 0; $index < 5001; $index++) { + $entries['f' . $index . '.txt'] = 'x'; + } + + $archive = makeArchiveUpload($entries, $tempArchives); + $screenshot = UploadedFile::fake()->image('screen.jpg', 800, 600); + + $response = $this->actingAs($user)->postJson('/api/uploads/preload', [ + 'main' => $archive, + 'screenshots' => [$screenshot], + ]); + + $response->assertStatus(422) + ->assertJsonPath('message', 'Archive inspection failed.'); + + expect((string) $response->json('reason'))->toContain('5000'); +}); + +it('rejects archive with executable inside during preload', function () use (&$tempArchives) { + Storage::fake('local'); + $user = User::factory()->create(); + + $archive = makeArchiveUpload([ + 'safe/readme.txt' => 'ok', + 'safe/run.exe' => 'MZ', + ], $tempArchives); + + $screenshot = UploadedFile::fake()->image('screen.jpg', 800, 600); + + $response = $this->actingAs($user)->postJson('/api/uploads/preload', [ + 'main' => $archive, + 'screenshots' => [$screenshot], + ]); + + $response->assertStatus(422) + ->assertJsonPath('message', 'Archive inspection failed.'); + + expect(strtolower((string) $response->json('reason')))->toContain('blocked'); +}); + +it('rejects archive with zip bomb ratio during preload', function () use (&$tempArchives) { + Storage::fake('local'); + $user = User::factory()->create(); + + $archive = makeArchiveUpload([ + 'payload.txt' => str_repeat('A', 6 * 1024 * 1024), + ], $tempArchives); + + $screenshot = UploadedFile::fake()->image('screen.jpg', 800, 600); + + $response = $this->actingAs($user)->postJson('/api/uploads/preload', [ + 'main' => $archive, + 'screenshots' => [$screenshot], + ]); + + $response->assertStatus(422) + ->assertJsonPath('message', 'Archive inspection failed.'); + + expect(strtolower((string) $response->json('reason')))->toContain('ratio'); +}); + +it('accepts valid archive during preload', function () use (&$tempArchives) { + Storage::fake('local'); + $user = User::factory()->create(); + + $archive = makeArchiveUpload([ + 'skins/theme/readme.txt' => 'hello', + 'skins/theme/layout.ini' => 'v=1', + ], $tempArchives); + + $screenshot = UploadedFile::fake()->image('screen.jpg', 800, 600); + + $response = $this->actingAs($user)->postJson('/api/uploads/preload', [ + 'main' => $archive, + 'screenshots' => [$screenshot], + ]); + + $response->assertOk()->assertJsonStructure([ + 'upload_id', + 'status', + 'expires_at', + ]); +}); diff --git a/tests/Feature/Uploads/PreviewGenerationJobTest.php b/tests/Feature/Uploads/PreviewGenerationJobTest.php new file mode 100644 index 00000000..84b1476c --- /dev/null +++ b/tests/Feature/Uploads/PreviewGenerationJobTest.php @@ -0,0 +1,47 @@ +create(); + $uploadId = (string) Str::uuid(); + + DB::table('uploads')->insert([ + 'id' => $uploadId, + 'user_id' => $user->id, + 'type' => 'archive', + 'status' => 'draft', + 'is_scanned' => true, + 'has_tags' => false, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + // archive path with no screenshot uses placeholder path in PreviewService + $job = new PreviewGenerationJob($uploadId); + $job->handle(app(\App\Services\Upload\PreviewService::class)); + + $this->assertDatabaseHas('uploads', [ + 'id' => $uploadId, + ]); + + Bus::assertDispatched(TagAnalysisJob::class, function (TagAnalysisJob $queuedJob) use ($uploadId) { + $reflect = new ReflectionClass($queuedJob); + $property = $reflect->getProperty('uploadId'); + $property->setAccessible(true); + + return $property->getValue($queuedJob) === $uploadId; + }); +}); diff --git a/tests/Feature/Uploads/UploadAutosaveTest.php b/tests/Feature/Uploads/UploadAutosaveTest.php new file mode 100644 index 00000000..7cfa1cf8 --- /dev/null +++ b/tests/Feature/Uploads/UploadAutosaveTest.php @@ -0,0 +1,165 @@ +insertGetId([ + 'name' => 'Photography', + 'slug' => 'photography-' . Str::lower(Str::random(6)), + 'description' => null, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + return DB::table('categories')->insertGetId([ + 'content_type_id' => $contentTypeId, + 'parent_id' => null, + 'name' => 'Nature', + 'slug' => 'nature-' . Str::lower(Str::random(6)), + 'description' => null, + 'image' => null, + 'is_active' => true, + 'sort_order' => 0, + 'created_at' => now(), + 'updated_at' => now(), + ]); +} + +function createDraftUploadForAutosave(int $userId, string $status = 'draft'): string +{ + $id = (string) Str::uuid(); + + DB::table('uploads')->insert([ + 'id' => $id, + 'user_id' => $userId, + 'type' => 'image', + 'status' => $status, + 'title' => 'Original Title', + 'description' => 'Original Description', + 'license' => 'default', + 'nsfw' => false, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + return $id; +} + +it('owner can autosave', function () { + Storage::fake('local'); + + $owner = User::factory()->create(); + $categoryId = createCategoryForAutosaveTests(); + $uploadId = createDraftUploadForAutosave($owner->id); + + $response = $this->actingAs($owner)->postJson("/api/uploads/{$uploadId}/autosave", [ + 'title' => 'Updated Title', + 'category_id' => $categoryId, + 'description' => 'Updated Description', + 'tags' => ['night', 'city'], + 'license' => 'cc-by', + 'nsfw' => true, + ]); + + $response->assertOk()->assertJsonStructure([ + 'success', + 'updated_at', + ])->assertJson([ + 'success' => true, + ]); + + $this->assertDatabaseHas('uploads', [ + 'id' => $uploadId, + 'title' => 'Updated Title', + 'category_id' => $categoryId, + 'description' => 'Updated Description', + 'license' => 'cc-by', + 'nsfw' => 1, + ]); + + $row = DB::table('uploads')->where('id', $uploadId)->first(); + expect(json_decode((string) $row->tags, true))->toBe(['night', 'city']); +}); + +it('partial update works', function () { + Storage::fake('local'); + + $owner = User::factory()->create(); + $uploadId = createDraftUploadForAutosave($owner->id); + + $before = DB::table('uploads')->where('id', $uploadId)->first(); + + $response = $this->actingAs($owner)->postJson("/api/uploads/{$uploadId}/autosave", [ + 'title' => 'Only Title Changed', + ]); + + $response->assertOk()->assertJson([ + 'success' => true, + ]); + + $after = DB::table('uploads')->where('id', $uploadId)->first(); + + expect($after->title)->toBe('Only Title Changed'); + expect($after->description)->toBe($before->description); + expect($after->license)->toBe($before->license); +}); + +it('guest denied', function () { + Storage::fake('local'); + + $owner = User::factory()->create(); + $uploadId = createDraftUploadForAutosave($owner->id); + + $response = $this->postJson("/api/uploads/{$uploadId}/autosave", [ + 'title' => 'Nope', + ]); + + expect(in_array($response->getStatusCode(), [401, 403]))->toBeTrue(); +}); + +it('other user denied', function () { + Storage::fake('local'); + + $owner = User::factory()->create(); + $other = User::factory()->create(); + $uploadId = createDraftUploadForAutosave($owner->id); + + $response = $this->actingAs($other)->postJson("/api/uploads/{$uploadId}/autosave", [ + 'title' => 'Hacker Update', + ]); + + $response->assertStatus(403); +}); + +it('published upload rejected', function () { + Storage::fake('local'); + + $owner = User::factory()->create(); + $uploadId = createDraftUploadForAutosave($owner->id, 'published'); + + $response = $this->actingAs($owner)->postJson("/api/uploads/{$uploadId}/autosave", [ + 'title' => 'Should Not Save', + ]); + + $response->assertStatus(422); +}); + +it('invalid category rejected', function () { + Storage::fake('local'); + + $owner = User::factory()->create(); + $uploadId = createDraftUploadForAutosave($owner->id); + + $response = $this->actingAs($owner)->postJson("/api/uploads/{$uploadId}/autosave", [ + 'category_id' => 999999, + ]); + + $response->assertStatus(422)->assertJsonValidationErrors(['category_id']); +}); diff --git a/tests/Feature/Uploads/UploadCleanupCommandTest.php b/tests/Feature/Uploads/UploadCleanupCommandTest.php new file mode 100644 index 00000000..0897d23e --- /dev/null +++ b/tests/Feature/Uploads/UploadCleanupCommandTest.php @@ -0,0 +1,89 @@ + $id, + 'user_id' => User::factory()->create()->id, + 'type' => 'image', + 'status' => 'draft', + 'title' => null, + 'slug' => null, + 'category_id' => null, + 'description' => null, + 'tags' => null, + 'license' => null, + 'nsfw' => false, + 'is_scanned' => false, + 'has_tags' => false, + 'preview_path' => null, + 'published_at' => null, + 'final_path' => null, + 'expires_at' => null, + 'created_at' => now(), + 'updated_at' => now(), + ]; + + DB::table('uploads')->insert(array_merge($defaults, $overrides)); + + return $id; +} + +it('runs uploads cleanup command and deletes stale drafts', function () { + Storage::fake('local'); + + $expiredId = createCleanupUpload([ + 'status' => 'draft', + 'expires_at' => now()->subMinute(), + ]); + + $activeId = createCleanupUpload([ + 'status' => 'draft', + 'expires_at' => now()->addHours(2), + 'updated_at' => now()->subHours(2), + ]); + + Storage::disk('local')->put("tmp/drafts/{$expiredId}/meta.json", '{}'); + Storage::disk('local')->put("tmp/drafts/{$activeId}/meta.json", '{}'); + + $code = Artisan::call('uploads:cleanup'); + + expect($code)->toBe(0); + expect(Artisan::output())->toContain('Uploads cleanup deleted 1 draft(s).'); + + expect(DB::table('uploads')->where('id', $expiredId)->exists())->toBeFalse(); + expect(DB::table('uploads')->where('id', $activeId)->where('status', 'draft')->exists())->toBeTrue(); + expect(Storage::disk('local')->exists("tmp/drafts/{$expiredId}/meta.json"))->toBeFalse(); + expect(Storage::disk('local')->exists("tmp/drafts/{$activeId}/meta.json"))->toBeTrue(); +}); + +it('respects command limit option', function () { + Storage::fake('local'); + + for ($index = 0; $index < 5; $index++) { + $uploadId = createCleanupUpload([ + 'status' => 'draft', + 'updated_at' => now()->subHours(26), + ]); + + Storage::disk('local')->put("tmp/drafts/{$uploadId}/meta.json", '{}'); + } + + $code = Artisan::call('uploads:cleanup', ['--limit' => 2]); + + expect($code)->toBe(0); + expect(Artisan::output())->toContain('Uploads cleanup deleted 2 draft(s).'); + + expect(DB::table('uploads')->count())->toBe(3); +}); diff --git a/tests/Feature/Uploads/UploadFeatureFlagTest.php b/tests/Feature/Uploads/UploadFeatureFlagTest.php new file mode 100644 index 00000000..b40dfe1d --- /dev/null +++ b/tests/Feature/Uploads/UploadFeatureFlagTest.php @@ -0,0 +1,30 @@ + false]); + + $user = User::factory()->create(); + + $response = $this->actingAs($user)->get('/upload'); + + $response->assertOk(); + $response->assertSee('window.SKINBASE_FLAGS', false); + $response->assertSee('uploads_v2: false', false); +}); + +it('injects uploads v2 flag as true when enabled', function () { + config(['features.uploads_v2' => true]); + + $user = User::factory()->create(); + + $response = $this->actingAs($user)->get('/upload'); + + $response->assertOk(); + $response->assertSee('window.SKINBASE_FLAGS', false); + $response->assertSee('uploads_v2: true', false); +}); diff --git a/tests/Feature/Uploads/UploadPreloadTest.php b/tests/Feature/Uploads/UploadPreloadTest.php new file mode 100644 index 00000000..8e97ee6a --- /dev/null +++ b/tests/Feature/Uploads/UploadPreloadTest.php @@ -0,0 +1,191 @@ +open($path, \ZipArchive::OVERWRITE | \ZipArchive::CREATE) !== true) { + throw new \RuntimeException('Unable to create temporary zip file.'); + } + + $zip->addFromString('skins/theme/readme.txt', 'safe'); + $zip->addFromString('skins/theme/colors.ini', 'accent=blue'); + $zip->close(); + + return new UploadedFile($path, 'pack.zip', 'application/zip', null, true); +} + +it('authenticated user can preload image', function () { + Storage::fake('local'); + $user = User::factory()->create(); + + $main = UploadedFile::fake()->image('main.jpg', 1200, 800); + + $response = $this + ->actingAs($user) + ->postJson('/api/uploads/preload', [ + 'main' => $main, + ]); + + $response->assertOk()->assertJsonStructure([ + 'upload_id', + 'status', + 'expires_at', + ]); + + $uploadId = $response->json('upload_id'); + + $this->assertDatabaseHas('uploads', [ + 'id' => $uploadId, + 'user_id' => $user->id, + 'type' => 'image', + 'status' => 'draft', + ]); + + $this->assertDatabaseHas('upload_files', [ + 'upload_id' => $uploadId, + 'type' => 'main', + ]); + + Storage::disk('local')->assertExists("tmp/drafts/{$uploadId}/meta.json"); + expect(Storage::disk('local')->allFiles("tmp/drafts/{$uploadId}"))->not->toBeEmpty(); +}); + +it('authenticated user can preload archive with screenshot', function () { + Storage::fake('local'); + $user = User::factory()->create(); + + $main = makeValidArchiveUpload(); + $screenshot = UploadedFile::fake()->image('screen1.jpg', 800, 600); + + $response = $this + ->actingAs($user) + ->postJson('/api/uploads/preload', [ + 'main' => $main, + 'screenshots' => [$screenshot], + ]); + + $response->assertOk()->assertJsonStructure([ + 'upload_id', + 'status', + 'expires_at', + ]); + + $uploadId = $response->json('upload_id'); + + $this->assertDatabaseHas('uploads', [ + 'id' => $uploadId, + 'user_id' => $user->id, + 'type' => 'archive', + 'status' => 'draft', + ]); + + $this->assertDatabaseHas('upload_files', [ + 'upload_id' => $uploadId, + 'type' => 'main', + ]); + + $this->assertDatabaseHas('upload_files', [ + 'upload_id' => $uploadId, + 'type' => 'screenshot', + ]); + + Storage::disk('local')->assertExists("tmp/drafts/{$uploadId}/meta.json"); + expect(Storage::disk('local')->allFiles("tmp/drafts/{$uploadId}"))->not->toBeEmpty(); +}); + +it('guest is rejected', function () { + Storage::fake('local'); + + $main = UploadedFile::fake()->image('main.jpg', 1200, 800); + + $response = $this->postJson('/api/uploads/preload', [ + 'main' => $main, + ]); + + expect(in_array($response->getStatusCode(), [401, 403]))->toBeTrue(); +}); + +it('missing main file fails', function () { + Storage::fake('local'); + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->postJson('/api/uploads/preload', []); + + $response->assertStatus(422)->assertJsonValidationErrors(['main']); +}); + +it('archive without screenshot fails', function () { + Storage::fake('local'); + $user = User::factory()->create(); + + $main = UploadedFile::fake()->create('pack.zip', 1024, 'application/zip'); + + $response = $this + ->actingAs($user) + ->postJson('/api/uploads/preload', [ + 'main' => $main, + ]); + + $response->assertStatus(422)->assertJsonValidationErrors(['screenshots']); +}); + +it('invalid file type is rejected', function () { + Storage::fake('local'); + $user = User::factory()->create(); + + $main = UploadedFile::fake()->create('notes.txt', 4, 'text/plain'); + + $response = $this + ->actingAs($user) + ->postJson('/api/uploads/preload', [ + 'main' => $main, + ]); + + $response->assertStatus(422)->assertJsonValidationErrors(['main']); +}); + +it('preload dispatches VirusScanJob', function () { + Storage::fake('local'); + Bus::fake(); + + $user = User::factory()->create(); + $main = UploadedFile::fake()->image('main.jpg', 1200, 800); + + $response = $this + ->actingAs($user) + ->postJson('/api/uploads/preload', [ + 'main' => $main, + ]); + + $response->assertOk()->assertJsonStructure([ + 'upload_id', + 'status', + 'expires_at', + ]); + + $uploadId = $response->json('upload_id'); + + Bus::assertDispatched(VirusScanJob::class, function (VirusScanJob $job) use ($uploadId) { + $reflect = new \ReflectionClass($job); + $property = $reflect->getProperty('uploadId'); + $property->setAccessible(true); + + return $property->getValue($job) === $uploadId; + }); +}); diff --git a/tests/Feature/Uploads/UploadProcessingLifecycleTest.php b/tests/Feature/Uploads/UploadProcessingLifecycleTest.php new file mode 100644 index 00000000..fdd46a36 --- /dev/null +++ b/tests/Feature/Uploads/UploadProcessingLifecycleTest.php @@ -0,0 +1,108 @@ + $id, + 'user_id' => $userId, + 'type' => 'archive', + 'status' => 'draft', + 'processing_state' => 'pending_scan', + 'is_scanned' => false, + 'has_tags' => false, + 'created_at' => now(), + 'updated_at' => now(), + ]; + + DB::table('uploads')->insert(array_merge($defaults, $overrides)); + + return $id; +} + +it('moves through explicit processing state lifecycle', function () { + Storage::fake('local'); + Bus::fake(); + + $user = User::factory()->create(); + $uploadId = createUploadForLifecycle($user->id); + + $mainPath = "tmp/drafts/{$uploadId}/main/archive.zip"; + Storage::disk('local')->put($mainPath, 'archive-bytes'); + + DB::table('upload_files')->insert([ + 'upload_id' => $uploadId, + 'path' => $mainPath, + 'type' => 'main', + 'hash' => 'aa11bb22cc33dd44', + 'size' => 100, + 'mime' => 'application/zip', + 'created_at' => now(), + ]); + + (new VirusScanJob($uploadId))->handle(app(UploadScanService::class)); + expect(DB::table('uploads')->where('id', $uploadId)->value('processing_state'))->toBe('generating_preview'); + + (new PreviewGenerationJob($uploadId))->handle(app(PreviewService::class)); + expect(DB::table('uploads')->where('id', $uploadId)->value('processing_state'))->toBe('analyzing_tags'); + + (new TagAnalysisJob($uploadId))->handle(app(TagAnalysisService::class)); + expect(DB::table('uploads')->where('id', $uploadId)->value('processing_state'))->toBe('ready'); + expect((bool) DB::table('uploads')->where('id', $uploadId)->value('has_tags'))->toBeTrue(); +}); + +it('does not regress processing state when jobs rerun', function () { + Storage::fake('local'); + Bus::fake(); + + $user = User::factory()->create(); + $uploadId = (string) Str::uuid(); + + DB::table('uploads')->insert([ + 'id' => $uploadId, + 'user_id' => $user->id, + 'type' => 'archive', + 'status' => 'draft', + 'processing_state' => 'ready', + 'is_scanned' => true, + 'has_tags' => true, + 'preview_path' => "tmp/drafts/{$uploadId}/preview.webp", + 'created_at' => now(), + 'updated_at' => now(), + ]); + + $mainPath = "tmp/drafts/{$uploadId}/main/archive.zip"; + Storage::disk('local')->put($mainPath, 'archive-bytes'); + + DB::table('upload_files')->insert([ + 'upload_id' => $uploadId, + 'path' => $mainPath, + 'type' => 'main', + 'hash' => 'ee11bb22cc33dd44', + 'size' => 100, + 'mime' => 'application/zip', + 'created_at' => now(), + ]); + + (new VirusScanJob($uploadId))->handle(app(UploadScanService::class)); + (new PreviewGenerationJob($uploadId))->handle(app(PreviewService::class)); + (new TagAnalysisJob($uploadId))->handle(app(TagAnalysisService::class)); + + expect(DB::table('uploads')->where('id', $uploadId)->value('processing_state'))->toBe('ready'); +}); diff --git a/tests/Feature/Uploads/UploadPublishEndpointTest.php b/tests/Feature/Uploads/UploadPublishEndpointTest.php new file mode 100644 index 00000000..871aaca3 --- /dev/null +++ b/tests/Feature/Uploads/UploadPublishEndpointTest.php @@ -0,0 +1,143 @@ +insertGetId([ + 'name' => 'Photography', + 'slug' => 'photography-' . Str::lower(Str::random(6)), + 'description' => null, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + return DB::table('categories')->insertGetId([ + 'content_type_id' => $contentTypeId, + 'parent_id' => null, + 'name' => 'Street', + 'slug' => 'street-' . Str::lower(Str::random(6)), + 'description' => null, + 'image' => null, + 'is_active' => true, + 'sort_order' => 0, + 'created_at' => now(), + 'updated_at' => now(), + ]); +} + +function createReadyDraftForPublishEndpoint(int $ownerId, int $categoryId, string $status = 'draft'): array +{ + $uploadId = (string) Str::uuid(); + $hash = 'aabbccddeeff00112233'; + + DB::table('uploads')->insert([ + 'id' => $uploadId, + 'user_id' => $ownerId, + 'type' => 'image', + 'status' => $status, + 'moderation_status' => 'approved', + 'title' => 'Publish Endpoint Test', + 'category_id' => $categoryId, + 'is_scanned' => true, + 'has_tags' => true, + 'preview_path' => "tmp/drafts/{$uploadId}/preview.webp", + 'created_at' => now(), + 'updated_at' => now(), + ]); + + Storage::disk('local')->put("tmp/drafts/{$uploadId}/main/main.jpg", 'jpg'); + Storage::disk('local')->put("tmp/drafts/{$uploadId}/preview.webp", 'preview'); + + DB::table('upload_files')->insert([ + 'upload_id' => $uploadId, + 'path' => "tmp/drafts/{$uploadId}/main/main.jpg", + 'type' => 'main', + 'hash' => $hash, + 'size' => 3, + 'mime' => 'image/jpeg', + 'created_at' => now(), + ]); + + return [$uploadId, $hash]; +} + +it('owner can publish valid draft', function () { + Storage::fake('local'); + + $owner = User::factory()->create(); + $categoryId = createCategoryForPublishEndpointTests(); + [$uploadId, $hash] = createReadyDraftForPublishEndpoint($owner->id, $categoryId); + + $response = $this->actingAs($owner)->postJson("/api/uploads/{$uploadId}/publish"); + + $response->assertOk()->assertJsonStructure([ + 'success', + 'upload_id', + 'status', + 'published_at', + 'final_path', + ])->assertJson([ + 'success' => true, + 'upload_id' => $uploadId, + 'status' => 'published', + 'final_path' => 'files/artworks/aa/bb/' . $hash, + ]); +}); + +it('guest denied', function () { + Storage::fake('local'); + + $owner = User::factory()->create(); + $categoryId = createCategoryForPublishEndpointTests(); + [$uploadId] = createReadyDraftForPublishEndpoint($owner->id, $categoryId); + + $response = $this->postJson("/api/uploads/{$uploadId}/publish"); + + expect(in_array($response->getStatusCode(), [401, 403]))->toBeTrue(); +}); + +it('other user denied', function () { + Storage::fake('local'); + + $owner = User::factory()->create(); + $other = User::factory()->create(); + $categoryId = createCategoryForPublishEndpointTests(); + [$uploadId] = createReadyDraftForPublishEndpoint($owner->id, $categoryId); + + $response = $this->actingAs($other)->postJson("/api/uploads/{$uploadId}/publish"); + + $response->assertStatus(403); +}); + +it('incomplete draft rejected', function () { + Storage::fake('local'); + + $owner = User::factory()->create(); + $categoryId = createCategoryForPublishEndpointTests(); + [$uploadId] = createReadyDraftForPublishEndpoint($owner->id, $categoryId); + + DB::table('uploads')->where('id', $uploadId)->update(['title' => null]); + + $response = $this->actingAs($owner)->postJson("/api/uploads/{$uploadId}/publish"); + + $response->assertStatus(422); +}); + +it('already published rejected', function () { + Storage::fake('local'); + + $owner = User::factory()->create(); + $categoryId = createCategoryForPublishEndpointTests(); + [$uploadId] = createReadyDraftForPublishEndpoint($owner->id, $categoryId, 'published'); + + $response = $this->actingAs($owner)->postJson("/api/uploads/{$uploadId}/publish"); + + $response->assertStatus(422); +}); diff --git a/tests/Feature/Uploads/UploadPublishTest.php b/tests/Feature/Uploads/UploadPublishTest.php new file mode 100644 index 00000000..87bedb5b --- /dev/null +++ b/tests/Feature/Uploads/UploadPublishTest.php @@ -0,0 +1,264 @@ +insertGetId([ + 'name' => 'Photography', + 'slug' => 'photography-' . Str::lower(Str::random(6)), + 'description' => null, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + return DB::table('categories')->insertGetId([ + 'content_type_id' => $contentTypeId, + 'parent_id' => null, + 'name' => 'Urban', + 'slug' => 'urban-' . Str::lower(Str::random(6)), + 'description' => null, + 'image' => null, + 'is_active' => true, + 'sort_order' => 0, + 'created_at' => now(), + 'updated_at' => now(), + ]); +} + +it('publishes upload and moves draft files', function () { + Storage::fake('local'); + + $user = User::factory()->create(); + $categoryId = createCategoryForUploadPublishFeatureTests(); + $uploadId = (string) Str::uuid(); + $hash = 'aabbccddeeff00112233'; + + DB::table('uploads')->insert([ + 'id' => $uploadId, + 'user_id' => $user->id, + 'type' => 'image', + 'status' => 'draft', + 'moderation_status' => 'approved', + 'title' => 'Night City', + 'category_id' => $categoryId, + 'is_scanned' => true, + 'has_tags' => true, + 'preview_path' => "tmp/drafts/{$uploadId}/preview.webp", + 'created_at' => now(), + 'updated_at' => now(), + ]); + + Storage::disk('local')->put("tmp/drafts/{$uploadId}/main/night-city.jpg", 'jpg-binary'); + Storage::disk('local')->put("tmp/drafts/{$uploadId}/preview.webp", 'preview'); + Storage::disk('local')->put("tmp/drafts/{$uploadId}/thumb.webp", 'thumb'); + + DB::table('upload_files')->insert([ + [ + 'upload_id' => $uploadId, + 'path' => "tmp/drafts/{$uploadId}/main/night-city.jpg", + 'type' => 'main', + 'hash' => $hash, + 'size' => 10, + 'mime' => 'image/jpeg', + 'created_at' => now(), + ], + [ + 'upload_id' => $uploadId, + 'path' => "tmp/drafts/{$uploadId}/preview.webp", + 'type' => 'preview', + 'hash' => null, + 'size' => 7, + 'mime' => 'image/webp', + 'created_at' => now(), + ], + ]); + + $published = app(PublishService::class)->publish($uploadId, $user); + + expect($published)->toBeInstanceOf(Upload::class); + expect($published->status)->toBe('published'); + expect($published->published_at)->not->toBeNull(); + expect($published->final_path)->toBe('files/artworks/aa/bb/' . $hash); + + Storage::disk('local')->assertMissing("tmp/drafts/{$uploadId}/main/night-city.jpg"); + Storage::disk('local')->assertExists('files/artworks/aa/bb/' . $hash . '/main/night-city.jpg'); + + $updatedMain = DB::table('upload_files') + ->where('upload_id', $uploadId) + ->where('type', 'main') + ->value('path'); + expect($updatedMain)->toBe('files/artworks/aa/bb/' . $hash . '/main/night-city.jpg'); +}); + +it('does not delete temp files on publish failure', function () { + Storage::fake('local'); + + $user = User::factory()->create(); + $categoryId = createCategoryForUploadPublishFeatureTests(); + $uploadId = (string) Str::uuid(); + + DB::table('uploads')->insert([ + 'id' => $uploadId, + 'user_id' => $user->id, + 'type' => 'image', + 'status' => 'draft', + 'moderation_status' => 'approved', + 'title' => 'Will Fail', + 'category_id' => $categoryId, + 'is_scanned' => true, + 'has_tags' => true, + 'preview_path' => "tmp/drafts/{$uploadId}/preview.webp", + 'created_at' => now(), + 'updated_at' => now(), + ]); + + Storage::disk('local')->put("tmp/drafts/{$uploadId}/main/file.jpg", 'jpg-binary'); + Storage::disk('local')->put("tmp/drafts/{$uploadId}/preview.webp", 'preview'); + + // missing hash should trigger failure and preserve temp files + DB::table('upload_files')->insert([ + 'upload_id' => $uploadId, + 'path' => "tmp/drafts/{$uploadId}/main/file.jpg", + 'type' => 'main', + 'hash' => null, + 'size' => 10, + 'mime' => 'image/jpeg', + 'created_at' => now(), + ]); + + expect(fn () => app(PublishService::class)->publish($uploadId, $user)) + ->toThrow(RuntimeException::class); + + Storage::disk('local')->assertExists("tmp/drafts/{$uploadId}/main/file.jpg"); + $status = DB::table('uploads')->where('id', $uploadId)->value('status'); + expect($status)->toBe('draft'); +}); + +it('publish persists generated slug when missing', function () { + Storage::fake('local'); + + $user = User::factory()->create(); + $categoryId = createCategoryForUploadPublishFeatureTests(); + $uploadId = (string) Str::uuid(); + $hash = '0011aabbccddeeff2233'; + + DB::table('uploads')->insert([ + 'id' => $uploadId, + 'user_id' => $user->id, + 'type' => 'image', + 'status' => 'draft', + 'moderation_status' => 'approved', + 'processing_state' => 'ready', + 'title' => 'My Amazing Artwork', + 'slug' => null, + 'category_id' => $categoryId, + 'is_scanned' => true, + 'has_tags' => true, + 'preview_path' => "tmp/drafts/{$uploadId}/preview.webp", + 'created_at' => now(), + 'updated_at' => now(), + ]); + + Storage::disk('local')->put("tmp/drafts/{$uploadId}/main/file.jpg", 'jpg-binary'); + Storage::disk('local')->put("tmp/drafts/{$uploadId}/preview.webp", 'preview'); + + DB::table('upload_files')->insert([ + 'upload_id' => $uploadId, + 'path' => "tmp/drafts/{$uploadId}/main/file.jpg", + 'type' => 'main', + 'hash' => $hash, + 'size' => 10, + 'mime' => 'image/jpeg', + 'created_at' => now(), + ]); + + app(PublishService::class)->publish($uploadId, $user); + + expect(DB::table('uploads')->where('id', $uploadId)->value('slug'))->toBe('my-amazing-artwork'); +}); + +it('publish slug uniqueness appends numeric suffix for published uploads', function () { + Storage::fake('local'); + + $user = User::factory()->create(); + $categoryId = createCategoryForUploadPublishFeatureTests(); + + $firstUploadId = (string) Str::uuid(); + $secondUploadId = (string) Str::uuid(); + + DB::table('uploads')->insert([ + [ + 'id' => $firstUploadId, + 'user_id' => $user->id, + 'type' => 'image', + 'status' => 'draft', + 'moderation_status' => 'approved', + 'processing_state' => 'ready', + 'title' => 'Duplicate Title', + 'slug' => null, + 'category_id' => $categoryId, + 'is_scanned' => true, + 'has_tags' => true, + 'preview_path' => "tmp/drafts/{$firstUploadId}/preview.webp", + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'id' => $secondUploadId, + 'user_id' => $user->id, + 'type' => 'image', + 'status' => 'draft', + 'moderation_status' => 'approved', + 'processing_state' => 'ready', + 'title' => 'Duplicate Title', + 'slug' => null, + 'category_id' => $categoryId, + 'is_scanned' => true, + 'has_tags' => true, + 'preview_path' => "tmp/drafts/{$secondUploadId}/preview.webp", + 'created_at' => now(), + 'updated_at' => now(), + ], + ]); + + Storage::disk('local')->put("tmp/drafts/{$firstUploadId}/main/file.jpg", 'first'); + Storage::disk('local')->put("tmp/drafts/{$firstUploadId}/preview.webp", 'preview'); + Storage::disk('local')->put("tmp/drafts/{$secondUploadId}/main/file.jpg", 'second'); + Storage::disk('local')->put("tmp/drafts/{$secondUploadId}/preview.webp", 'preview'); + + DB::table('upload_files')->insert([ + [ + 'upload_id' => $firstUploadId, + 'path' => "tmp/drafts/{$firstUploadId}/main/file.jpg", + 'type' => 'main', + 'hash' => 'aa11bb22cc33dd44', + 'size' => 10, + 'mime' => 'image/jpeg', + 'created_at' => now(), + ], + [ + 'upload_id' => $secondUploadId, + 'path' => "tmp/drafts/{$secondUploadId}/main/file.jpg", + 'type' => 'main', + 'hash' => 'ee11ff22cc33dd44', + 'size' => 10, + 'mime' => 'image/jpeg', + 'created_at' => now(), + ], + ]); + + app(PublishService::class)->publish($firstUploadId, $user); + app(PublishService::class)->publish($secondUploadId, $user); + + expect(DB::table('uploads')->where('id', $firstUploadId)->value('slug'))->toBe('duplicate-title'); + expect(DB::table('uploads')->where('id', $secondUploadId)->value('slug'))->toBe('duplicate-title-2'); +}); diff --git a/tests/Feature/Uploads/UploadQuotaTest.php b/tests/Feature/Uploads/UploadQuotaTest.php new file mode 100644 index 00000000..2d3f567c --- /dev/null +++ b/tests/Feature/Uploads/UploadQuotaTest.php @@ -0,0 +1,196 @@ + $id, + 'user_id' => $userId, + 'type' => 'image', + 'status' => 'draft', + 'title' => null, + 'slug' => null, + 'category_id' => null, + 'description' => null, + 'tags' => null, + 'license' => null, + 'nsfw' => false, + 'is_scanned' => false, + 'has_tags' => false, + 'preview_path' => null, + 'published_at' => null, + 'final_path' => null, + 'expires_at' => null, + 'created_at' => now(), + 'updated_at' => now(), + ]; + + DB::table('uploads')->insert(array_merge($defaults, $overrides)); + + return $id; +} + +function attachMainUploadFileForQuota(string $uploadId, int $size, string $hash = 'hash-main'): void +{ + DB::table('upload_files')->insert([ + 'upload_id' => $uploadId, + 'path' => "tmp/drafts/{$uploadId}/main/file.bin", + 'type' => 'main', + 'hash' => $hash, + 'size' => $size, + 'mime' => 'application/octet-stream', + 'created_at' => now(), + ]); +} + +it('enforces draft count limit', function () { + Storage::fake('local'); + config(['uploads.draft_quota.max_drafts_per_user' => 1]); + + $user = User::factory()->create(); + createUploadRowForQuota($user->id, ['status' => 'draft']); + + $main = UploadedFile::fake()->image('wallpaper.jpg', 600, 400); + + $response = $this->actingAs($user)->postJson('/api/uploads/preload', [ + 'main' => $main, + ]); + + $response->assertStatus(429) + ->assertJsonPath('message', 'draft_limit') + ->assertJsonPath('code', 'draft_limit'); +}); + +it('enforces draft storage limit', function () { + Storage::fake('local'); + config([ + 'uploads.draft_quota.max_drafts_per_user' => 20, + 'uploads.draft_quota.max_draft_storage_mb_per_user' => 1, + ]); + + $user = User::factory()->create(); + + $existingDraftId = createUploadRowForQuota($user->id, ['status' => 'draft']); + attachMainUploadFileForQuota($existingDraftId, 400 * 1024, 'existing-hash'); + + $main = UploadedFile::fake()->create('large.jpg', 700, 'image/jpeg'); + + $response = $this->actingAs($user)->postJson('/api/uploads/preload', [ + 'main' => $main, + ]); + + $response->assertStatus(413) + ->assertJsonPath('message', 'storage_limit') + ->assertJsonPath('code', 'storage_limit'); +}); + +it('blocks duplicate hash when policy is block', function () { + Storage::fake('local'); + config([ + 'uploads.draft_quota.max_drafts_per_user' => 20, + 'uploads.draft_quota.duplicate_hash_policy' => 'block', + ]); + + $owner = User::factory()->create(); + $uploader = User::factory()->create(); + + $main = UploadedFile::fake()->image('dupe.jpg', 400, 400); + $hash = hash_file('sha256', $main->getPathname()); + + $publishedUploadId = createUploadRowForQuota($owner->id, [ + 'status' => 'published', + 'published_at' => now()->subMinute(), + ]); + + attachMainUploadFileForQuota($publishedUploadId, (int) $main->getSize(), $hash); + + $response = $this->actingAs($uploader)->postJson('/api/uploads/preload', [ + 'main' => $main, + ]); + + $response->assertStatus(422) + ->assertJsonPath('message', 'duplicate_upload') + ->assertJsonPath('code', 'duplicate_upload'); +}); + +it('allows duplicate hash and returns warning when policy is warn', function () { + Storage::fake('local'); + config([ + 'uploads.draft_quota.max_drafts_per_user' => 20, + 'uploads.draft_quota.duplicate_hash_policy' => 'warn', + ]); + + $owner = User::factory()->create(); + $uploader = User::factory()->create(); + + $main = UploadedFile::fake()->image('dupe-warn.jpg', 400, 400); + $hash = hash_file('sha256', $main->getPathname()); + + $publishedUploadId = createUploadRowForQuota($owner->id, [ + 'status' => 'published', + 'published_at' => now()->subMinute(), + ]); + + attachMainUploadFileForQuota($publishedUploadId, (int) $main->getSize(), $hash); + + $response = $this->actingAs($uploader)->postJson('/api/uploads/preload', [ + 'main' => $main, + ]); + + $response->assertOk() + ->assertJsonStructure(['upload_id', 'status', 'expires_at', 'warnings']) + ->assertJsonPath('warnings.0', 'duplicate_hash'); +}); + +it('does not count published uploads as drafts', function () { + Storage::fake('local'); + config(['uploads.draft_quota.max_drafts_per_user' => 1]); + + $user = User::factory()->create(); + createUploadRowForQuota($user->id, [ + 'status' => 'published', + 'published_at' => now()->subHour(), + ]); + + $main = UploadedFile::fake()->image('new.jpg', 640, 480); + + $response = $this->actingAs($user)->postJson('/api/uploads/preload', [ + 'main' => $main, + ]); + + $response->assertOk()->assertJsonStructure([ + 'upload_id', + 'status', + 'expires_at', + ]); +}); + +it('returns stable machine codes for quota errors', function () { + Storage::fake('local'); + config(['uploads.draft_quota.max_drafts_per_user' => 1]); + + $user = User::factory()->create(); + createUploadRowForQuota($user->id, ['status' => 'draft']); + + $main = UploadedFile::fake()->image('machine-code.jpg', 600, 400); + + $response = $this->actingAs($user)->postJson('/api/uploads/preload', [ + 'main' => $main, + ]); + + $response->assertStatus(429) + ->assertJson([ + 'message' => 'draft_limit', + 'code' => 'draft_limit', + ]); +}); diff --git a/tests/Feature/Uploads/UploadStatusTest.php b/tests/Feature/Uploads/UploadStatusTest.php new file mode 100644 index 00000000..64c88b66 --- /dev/null +++ b/tests/Feature/Uploads/UploadStatusTest.php @@ -0,0 +1,129 @@ + $id, + 'user_id' => $userId, + 'type' => 'image', + 'status' => 'draft', + 'title' => null, + 'slug' => null, + 'category_id' => null, + 'description' => null, + 'tags' => null, + 'license' => null, + 'nsfw' => false, + 'is_scanned' => false, + 'has_tags' => false, + 'preview_path' => null, + 'published_at' => null, + 'final_path' => null, + 'expires_at' => null, + 'created_at' => now(), + 'updated_at' => now(), + ]; + + DB::table('uploads')->insert(array_merge($defaults, $overrides)); + + return $id; +} + +it('owner sees processing status payload', function () { + $owner = User::factory()->create(); + $uploadId = createUploadForStatusTests($owner->id, [ + 'status' => 'draft', + 'processing_state' => 'analyzing_tags', + 'is_scanned' => true, + 'preview_path' => 'tmp/drafts/preview.webp', + 'has_tags' => false, + ]); + + $response = $this->actingAs($owner)->getJson("/api/uploads/{$uploadId}/status"); + + $response->assertOk()->assertJson([ + 'id' => $uploadId, + 'status' => 'draft', + 'is_scanned' => true, + 'preview_ready' => true, + 'has_tags' => false, + 'processing_state' => 'analyzing_tags', + ]); +}); + +it('other user is denied', function () { + $owner = User::factory()->create(); + $other = User::factory()->create(); + + $uploadId = createUploadForStatusTests($owner->id); + + $response = $this->actingAs($other)->getJson("/api/uploads/{$uploadId}/status"); + + $response->assertStatus(403); +}); + +it('returns explicit processing states', function (array $input, string $expectedState) { + $owner = User::factory()->create(); + + $uploadId = createUploadForStatusTests($owner->id, $input); + + $response = $this->actingAs($owner)->getJson("/api/uploads/{$uploadId}/status"); + + $response->assertOk()->assertJsonPath('processing_state', $expectedState); +}) + ->with([ + 'pending scan' => [[ + 'status' => 'draft', + 'processing_state' => 'pending_scan', + ], 'pending_scan'], + 'scanning status' => [[ + 'status' => 'scanning', + 'processing_state' => 'scanning', + ], 'scanning'], + 'generating preview' => [[ + 'status' => 'draft', + 'processing_state' => 'generating_preview', + ], 'generating_preview'], + 'analyzing tags' => [[ + 'status' => 'draft', + 'processing_state' => 'analyzing_tags', + ], 'analyzing_tags'], + 'ready' => [[ + 'status' => 'draft', + 'processing_state' => 'ready', + ], 'ready'], + ]); + +it('returns rejected processing step when upload is rejected', function () { + $owner = User::factory()->create(); + $uploadId = createUploadForStatusTests($owner->id, [ + 'status' => 'rejected', + 'processing_state' => 'rejected', + ]); + + $response = $this->actingAs($owner)->getJson("/api/uploads/{$uploadId}/status"); + + $response->assertOk()->assertJsonPath('processing_state', 'rejected'); +}); + +it('returns published processing step when upload is published', function () { + $owner = User::factory()->create(); + $uploadId = createUploadForStatusTests($owner->id, [ + 'status' => 'published', + 'processing_state' => 'published', + 'published_at' => now()->subMinute(), + ]); + + $response = $this->actingAs($owner)->getJson("/api/uploads/{$uploadId}/status"); + + $response->assertOk()->assertJsonPath('processing_state', 'published'); +}); diff --git a/tests/Feature/Uploads/VirusScanJobTest.php b/tests/Feature/Uploads/VirusScanJobTest.php new file mode 100644 index 00000000..53cfcc0e --- /dev/null +++ b/tests/Feature/Uploads/VirusScanJobTest.php @@ -0,0 +1,60 @@ +create(); + $uploadId = (string) Str::uuid(); + + DB::table('uploads')->insert([ + 'id' => $uploadId, + 'user_id' => $user->id, + 'type' => 'image', + 'status' => 'draft', + 'is_scanned' => false, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + $mainPath = "tmp/drafts/{$uploadId}/main/main.jpg"; + Storage::disk('local')->put($mainPath, 'fake-image-content'); + + DB::table('upload_files')->insert([ + 'upload_id' => $uploadId, + 'path' => $mainPath, + 'type' => 'main', + 'hash' => null, + 'size' => 18, + 'mime' => 'image/jpeg', + 'created_at' => now(), + ]); + + $job = new VirusScanJob($uploadId); + $job->handle(app(UploadScanService::class)); + + $this->assertDatabaseHas('uploads', [ + 'id' => $uploadId, + 'is_scanned' => 1, + ]); + + Bus::assertDispatched(PreviewGenerationJob::class, function (PreviewGenerationJob $queuedJob) use ($uploadId) { + $reflect = new ReflectionClass($queuedJob); + $property = $reflect->getProperty('uploadId'); + $property->setAccessible(true); + + return $property->getValue($queuedJob) === $uploadId; + }); +}); diff --git a/tests/Unit/Discovery/FeedOfflineEvaluationServiceTest.php b/tests/Unit/Discovery/FeedOfflineEvaluationServiceTest.php new file mode 100644 index 00000000..af1f9f24 --- /dev/null +++ b/tests/Unit/Discovery/FeedOfflineEvaluationServiceTest.php @@ -0,0 +1,120 @@ +subDay()->toDateString(); + + DB::table('feed_daily_metrics')->insert([ + 'metric_date' => $metricDate, + 'algo_version' => 'clip-cosine-v1', + 'source' => 'personalized', + 'impressions' => 100, + 'clicks' => 20, + 'saves' => 8, + 'ctr' => 0.2, + 'save_rate' => 0.4, + 'dwell_0_5' => 3, + 'dwell_5_30' => 7, + 'dwell_30_120' => 6, + 'dwell_120_plus' => 4, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + $result = app(FeedOfflineEvaluationService::class)->evaluateAlgo('clip-cosine-v1', $metricDate, $metricDate); + + expect((string) $result['algo_version'])->toBe('clip-cosine-v1'); + expect((float) $result['ctr'])->toBe(0.2); + expect((float) $result['save_rate'])->toBe(0.4); + expect((float) $result['long_dwell_share'])->toBe(0.5); + expect((float) $result['bounce_rate'])->toBe(0.15); + expect((float) $result['objective_score'])->toBeGreaterThan(0); +}); + +it('compares baseline vs candidate with delta and lift', function () { + $metricDate = now()->subDay()->toDateString(); + + DB::table('feed_daily_metrics')->insert([ + [ + 'metric_date' => $metricDate, + 'algo_version' => 'clip-cosine-v1', + 'source' => 'personalized', + 'impressions' => 100, + 'clicks' => 20, + 'saves' => 6, + 'ctr' => 0.2, + 'save_rate' => 0.3, + 'dwell_0_5' => 4, + 'dwell_5_30' => 8, + 'dwell_30_120' => 5, + 'dwell_120_plus' => 3, + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'metric_date' => $metricDate, + 'algo_version' => 'clip-cosine-v2', + 'source' => 'personalized', + 'impressions' => 100, + 'clicks' => 25, + 'saves' => 10, + 'ctr' => 0.25, + 'save_rate' => 0.4, + 'dwell_0_5' => 3, + 'dwell_5_30' => 8, + 'dwell_30_120' => 8, + 'dwell_120_plus' => 6, + 'created_at' => now(), + 'updated_at' => now(), + ], + ]); + + $comparison = app(FeedOfflineEvaluationService::class) + ->compareBaselineCandidate('clip-cosine-v1', 'clip-cosine-v2', $metricDate, $metricDate); + + expect((float) $comparison['delta']['objective_score'])->toBeGreaterThan(0.0); + expect((float) $comparison['delta']['ctr'])->toBeGreaterThan(0.0); + expect((float) $comparison['delta']['save_rate'])->toBeGreaterThan(0.0); +}); + +it('treats save_rate as informational when configured', function () { + $metricDate = now()->subDay()->toDateString(); + + config()->set('discovery.evaluation.objective_weights', [ + 'ctr' => 0.45, + 'save_rate' => 0.35, + 'long_dwell_share' => 0.25, + 'bounce_rate_penalty' => 0.15, + ]); + config()->set('discovery.evaluation.save_rate_informational', true); + + DB::table('feed_daily_metrics')->insert([ + 'metric_date' => $metricDate, + 'algo_version' => 'clip-cosine-v1', + 'source' => 'personalized', + 'impressions' => 100, + 'clicks' => 20, + 'saves' => 8, + 'ctr' => 0.2, + 'save_rate' => 0.4, + 'dwell_0_5' => 3, + 'dwell_5_30' => 7, + 'dwell_30_120' => 6, + 'dwell_120_plus' => 4, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + $result = app(FeedOfflineEvaluationService::class)->evaluateAlgo('clip-cosine-v1', $metricDate, $metricDate); + + expect((float) $result['save_rate'])->toBe(0.4); + expect((float) $result['objective_score'])->toBe(0.226471); +}); diff --git a/tests/Unit/Discovery/PersonalizedFeedServiceTest.php b/tests/Unit/Discovery/PersonalizedFeedServiceTest.php new file mode 100644 index 00000000..4e8a05a9 --- /dev/null +++ b/tests/Unit/Discovery/PersonalizedFeedServiceTest.php @@ -0,0 +1,76 @@ +create(); + + $artworkA = Artwork::factory()->create(['is_public' => true, 'is_approved' => true, 'published_at' => now()->subMinutes(2)]); + $artworkB = Artwork::factory()->create(['is_public' => true, 'is_approved' => true, 'published_at' => now()->subMinutes(1)]); + + DB::table('artwork_stats')->insert([ + ['artwork_id' => $artworkA->id, 'views' => 120, 'downloads' => 30, 'favorites' => 2, 'rating_avg' => 0, 'rating_count' => 0], + ['artwork_id' => $artworkB->id, 'views' => 100, 'downloads' => 20, 'favorites' => 1, 'rating_avg' => 0, 'rating_count' => 0], + ]); + + app(PersonalizedFeedService::class)->regenerateCacheForUser($user->id, (string) config('discovery.algo_version')); + + $cache = UserRecommendationCache::query() + ->where('user_id', $user->id) + ->where('algo_version', (string) config('discovery.algo_version')) + ->first(); + + expect($cache)->not->toBeNull(); + expect($cache?->generated_at)->not->toBeNull(); + expect($cache?->expires_at)->not->toBeNull(); + + $items = (array) ($cache?->recommendations_json['items'] ?? []); + expect(count($items))->toBeGreaterThan(0); + expect((int) ($items[0]['artwork_id'] ?? 0))->toBeGreaterThan(0); +}); + +it('uses rollout gate g100 to select candidate algo version', function () { + $user = User::factory()->create(); + + config()->set('discovery.rollout.enabled', true); + config()->set('discovery.rollout.baseline_algo_version', 'clip-cosine-v1'); + config()->set('discovery.rollout.candidate_algo_version', 'clip-cosine-v2'); + config()->set('discovery.rollout.active_gate', 'g100'); + config()->set('discovery.rollout.gates.g100.percentage', 100); + config()->set('discovery.rollout.force_algo_version', ''); + + app(PersonalizedFeedService::class)->regenerateCacheForUser($user->id); + + $cache = UserRecommendationCache::query()->where('user_id', $user->id)->first(); + + expect($cache)->not->toBeNull(); + expect((string) $cache?->algo_version)->toBe('clip-cosine-v2'); +}); + +it('forces rollback algo version when force toggle is set', function () { + $user = User::factory()->create(); + + config()->set('discovery.rollout.enabled', true); + config()->set('discovery.rollout.baseline_algo_version', 'clip-cosine-v1'); + config()->set('discovery.rollout.candidate_algo_version', 'clip-cosine-v2'); + config()->set('discovery.rollout.active_gate', 'g100'); + config()->set('discovery.rollout.gates.g100.percentage', 100); + config()->set('discovery.rollout.force_algo_version', 'clip-cosine-v1'); + + app(PersonalizedFeedService::class)->regenerateCacheForUser($user->id); + + $cache = UserRecommendationCache::query()->where('user_id', $user->id)->first(); + + expect($cache)->not->toBeNull(); + expect((string) $cache?->algo_version)->toBe('clip-cosine-v1'); +}); diff --git a/tests/Unit/Discovery/UserInterestProfileServiceTest.php b/tests/Unit/Discovery/UserInterestProfileServiceTest.php new file mode 100644 index 00000000..878fa957 --- /dev/null +++ b/tests/Unit/Discovery/UserInterestProfileServiceTest.php @@ -0,0 +1,86 @@ +set('discovery.decay.half_life_hours', 72); + config()->set('discovery.weights.view', 1.0); + + $service = app(UserInterestProfileService::class); + + $user = User::factory()->create(); + + $contentType = ContentType::create([ + 'name' => 'Digital Art', + 'slug' => 'digital-art', + 'description' => 'Digital artworks', + ]); + + $categoryA = Category::create([ + 'content_type_id' => $contentType->id, + 'parent_id' => null, + 'name' => 'Sci-Fi', + 'slug' => 'sci-fi', + 'description' => 'Sci-Fi category', + 'is_active' => true, + 'sort_order' => 0, + ]); + + $categoryB = Category::create([ + 'content_type_id' => $contentType->id, + 'parent_id' => null, + 'name' => 'Fantasy', + 'slug' => 'fantasy', + 'description' => 'Fantasy category', + 'is_active' => true, + 'sort_order' => 0, + ]); + + $artworkA = Artwork::factory()->create(); + $artworkB = Artwork::factory()->create(); + + $t0 = CarbonImmutable::parse('2026-02-14 00:00:00'); + + $service->applyEvent( + userId: $user->id, + eventType: 'view', + artworkId: $artworkA->id, + categoryId: $categoryA->id, + occurredAt: $t0, + eventId: '11111111-1111-1111-1111-111111111111', + algoVersion: 'clip-cosine-v1' + ); + + $service->applyEvent( + userId: $user->id, + eventType: 'view', + artworkId: $artworkB->id, + categoryId: $categoryB->id, + occurredAt: $t0->addHours(72), + eventId: '22222222-2222-2222-2222-222222222222', + algoVersion: 'clip-cosine-v1' + ); + + $profile = \App\Models\UserInterestProfile::query()->where('user_id', $user->id)->firstOrFail(); + + expect((int) $profile->event_count)->toBe(2); + + $normalized = (array) $profile->normalized_scores_json; + + expect($normalized)->toHaveKey('category:' . $categoryA->id); + expect($normalized)->toHaveKey('category:' . $categoryB->id); + + expect((float) $normalized['category:' . $categoryA->id])->toBeGreaterThan(0.30)->toBeLessThan(0.35); + expect((float) $normalized['category:' . $categoryB->id])->toBeGreaterThan(0.65)->toBeLessThan(0.70); +}); diff --git a/tests/Unit/Uploads/ArchiveInspectorServiceTest.php b/tests/Unit/Uploads/ArchiveInspectorServiceTest.php new file mode 100644 index 00000000..96fa5042 --- /dev/null +++ b/tests/Unit/Uploads/ArchiveInspectorServiceTest.php @@ -0,0 +1,168 @@ + */ + private array $tempFiles = []; + + protected function tearDown(): void + { + foreach ($this->tempFiles as $file) { + if (is_file($file)) { + @unlink($file); + } + } + + parent::tearDown(); + } + + public function test_rejects_zip_slip_path(): void + { + $archive = $this->makeZip([ + '../evil.txt' => 'x', + ]); + + $result = app(ArchiveInspectorService::class)->inspect($archive); + + $this->assertFalse($result->valid); + $this->assertStringContainsString('path traversal', (string) $result->reason); + } + + public function test_rejects_symlink_entries(): void + { + $archive = $this->makeZipWithCallback([ + 'safe/file.txt' => 'ok', + 'safe/link' => 'target', + ], function (ZipArchive $zip, string $entryName): void { + if ($entryName === 'safe/link') { + $zip->setExternalAttributesName($entryName, ZipArchive::OPSYS_UNIX, 0120777 << 16); + } + }); + + $result = app(ArchiveInspectorService::class)->inspect($archive); + + $this->assertFalse($result->valid); + $this->assertStringContainsString('symlink', strtolower((string) $result->reason)); + } + + public function test_rejects_deep_nesting(): void + { + $archive = $this->makeZip([ + 'a/b/c/d/e/f/file.txt' => 'too deep', + ]); + + $result = app(ArchiveInspectorService::class)->inspect($archive); + + $this->assertFalse($result->valid); + $this->assertStringContainsString('depth', strtolower((string) $result->reason)); + } + + public function test_rejects_too_many_files(): void + { + $entries = []; + for ($index = 0; $index < 5001; $index++) { + $entries['f' . $index . '.txt'] = 'x'; + } + + $archive = $this->makeZip($entries); + + $result = app(ArchiveInspectorService::class)->inspect($archive); + + $this->assertFalse($result->valid); + $this->assertStringContainsString('5000', (string) $result->reason); + } + + public function test_rejects_executable_extensions(): void + { + $archive = $this->makeZip([ + 'skins/readme.txt' => 'ok', + 'skins/run.exe' => 'MZ', + ]); + + $result = app(ArchiveInspectorService::class)->inspect($archive); + + $this->assertFalse($result->valid); + $this->assertStringContainsString('blocked', strtolower((string) $result->reason)); + } + + public function test_rejects_zip_bomb_ratio(): void + { + $archive = $this->makeZip([ + 'payload.txt' => str_repeat('A', 6 * 1024 * 1024), + ]); + + $result = app(ArchiveInspectorService::class)->inspect($archive); + + $this->assertFalse($result->valid); + $this->assertStringContainsString('ratio', strtolower((string) $result->reason)); + } + + public function test_valid_archive_passes(): void + { + $archive = $this->makeZip([ + 'skins/theme/readme.txt' => 'safe', + 'skins/theme/colors.ini' => 'accent=blue', + ]); + + $result = app(ArchiveInspectorService::class)->inspect($archive); + + $this->assertInstanceOf(InspectionResult::class, $result); + $this->assertTrue($result->valid); + $this->assertNull($result->reason); + $this->assertIsArray($result->stats); + $this->assertArrayHasKey('files', $result->stats); + $this->assertArrayHasKey('depth', $result->stats); + $this->assertArrayHasKey('size', $result->stats); + $this->assertArrayHasKey('ratio', $result->stats); + } + + /** + * @param array $entries + */ + private function makeZip(array $entries): string + { + return $this->makeZipWithCallback($entries, null); + } + + /** + * @param array $entries + * @param (callable(ZipArchive,string):void)|null $entryCallback + */ + private function makeZipWithCallback(array $entries, ?callable $entryCallback): string + { + if (! class_exists(ZipArchive::class)) { + $this->markTestSkipped('ZipArchive extension is required.'); + } + + $path = tempnam(sys_get_temp_dir(), 'sb_zip_'); + if ($path === false) { + throw new \RuntimeException('Unable to create temporary zip path.'); + } + + $this->tempFiles[] = $path; + + $zip = new ZipArchive(); + if ($zip->open($path, ZipArchive::OVERWRITE | ZipArchive::CREATE) !== true) { + throw new \RuntimeException('Unable to open temporary zip for writing.'); + } + + foreach ($entries as $name => $content) { + $zip->addFromString($name, $content); + + if ($entryCallback !== null) { + $entryCallback($zip, $name); + } + } + + $zip->close(); + + return $path; + } +} diff --git a/tests/Unit/Uploads/CleanupServiceTest.php b/tests/Unit/Uploads/CleanupServiceTest.php new file mode 100644 index 00000000..bff9b9e2 --- /dev/null +++ b/tests/Unit/Uploads/CleanupServiceTest.php @@ -0,0 +1,139 @@ + $id, + 'user_id' => User::factory()->create()->id, + 'type' => 'image', + 'status' => 'draft', + 'title' => null, + 'slug' => null, + 'category_id' => null, + 'description' => null, + 'tags' => null, + 'license' => null, + 'nsfw' => false, + 'is_scanned' => false, + 'has_tags' => false, + 'preview_path' => null, + 'published_at' => null, + 'final_path' => null, + 'expires_at' => null, + 'created_at' => now(), + 'updated_at' => now(), + ]; + + DB::table('uploads')->insert(array_merge($defaults, $overrides)); + + return $id; + } + + public function test_deletes_expired_draft_uploads_and_returns_count(): void + { + Storage::fake('local'); + + $uploadId = $this->insertUploadRow([ + 'status' => 'draft', + 'expires_at' => now()->subMinute(), + ]); + + Storage::disk('local')->put("tmp/drafts/{$uploadId}/meta.json", '{}'); + + $deleted = app(CleanupService::class)->cleanupStaleDrafts(); + + $this->assertSame(1, $deleted); + $this->assertFalse(DB::table('uploads')->where('id', $uploadId)->exists()); + } + + public function test_keeps_active_drafts_untouched(): void + { + Storage::fake('local'); + + $uploadId = $this->insertUploadRow([ + 'status' => 'draft', + 'expires_at' => now()->addDay(), + 'updated_at' => now()->subHours(2), + ]); + + Storage::disk('local')->put("tmp/drafts/{$uploadId}/meta.json", '{}'); + + $deleted = app(CleanupService::class)->cleanupStaleDrafts(); + + $this->assertSame(0, $deleted); + $this->assertTrue(DB::table('uploads')->where('id', $uploadId)->exists()); + $this->assertTrue(Storage::disk('local')->exists("tmp/drafts/{$uploadId}/meta.json")); + } + + public function test_removes_temp_folder_when_deleting_stale_drafts(): void + { + Storage::fake('local'); + + $uploadId = $this->insertUploadRow([ + 'status' => 'draft', + 'updated_at' => now()->subHours(25), + ]); + + Storage::disk('local')->put("tmp/drafts/{$uploadId}/main/file.bin", 'x'); + $this->assertTrue(Storage::disk('local')->exists("tmp/drafts/{$uploadId}/main/file.bin")); + + $deleted = app(CleanupService::class)->cleanupStaleDrafts(); + + $this->assertSame(1, $deleted); + $this->assertFalse(Storage::disk('local')->exists("tmp/drafts/{$uploadId}/main/file.bin")); + } + + public function test_enforces_hard_cleanup_limit_of_100_per_run(): void + { + Storage::fake('local'); + + for ($index = 0; $index < 120; $index++) { + $uploadId = $this->insertUploadRow([ + 'status' => 'draft', + 'updated_at' => now()->subHours(30), + ]); + + Storage::disk('local')->put("tmp/drafts/{$uploadId}/meta.json", '{}'); + } + + $deleted = app(CleanupService::class)->cleanupStaleDrafts(999); + + $this->assertSame(100, $deleted); + $this->assertSame(20, DB::table('uploads')->count()); + } + + public function test_never_deletes_published_uploads(): void + { + Storage::fake('local'); + + $uploadId = $this->insertUploadRow([ + 'status' => 'published', + 'updated_at' => now()->subDays(5), + 'published_at' => now()->subDays(4), + ]); + + Storage::disk('local')->put("tmp/drafts/{$uploadId}/meta.json", '{}'); + + $deleted = app(CleanupService::class)->cleanupStaleDrafts(); + + $this->assertSame(0, $deleted); + $this->assertTrue(DB::table('uploads')->where('id', $uploadId)->where('status', 'published')->exists()); + $this->assertTrue(Storage::disk('local')->exists("tmp/drafts/{$uploadId}/meta.json")); + } +} diff --git a/tests/Unit/Uploads/PublishServiceTest.php b/tests/Unit/Uploads/PublishServiceTest.php new file mode 100644 index 00000000..41d868fa --- /dev/null +++ b/tests/Unit/Uploads/PublishServiceTest.php @@ -0,0 +1,102 @@ +insertGetId([ + 'name' => 'Skins', + 'slug' => 'skins-' . Str::lower(Str::random(6)), + 'description' => null, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + return DB::table('categories')->insertGetId([ + 'content_type_id' => $contentTypeId, + 'parent_id' => null, + 'name' => 'Winamp', + 'slug' => 'winamp-' . Str::lower(Str::random(6)), + 'description' => null, + 'image' => null, + 'is_active' => true, + 'sort_order' => 0, + 'created_at' => now(), + 'updated_at' => now(), + ]); +} + +it('rejects publish when user is not owner', function () { + Storage::fake('local'); + + $owner = User::factory()->create(); + $other = User::factory()->create(); + $categoryId = createCategoryForPublishTests(); + $uploadId = (string) Str::uuid(); + + DB::table('uploads')->insert([ + 'id' => $uploadId, + 'user_id' => $owner->id, + 'type' => 'image', + 'status' => 'draft', + 'moderation_status' => 'approved', + 'title' => 'City Lights', + 'category_id' => $categoryId, + 'is_scanned' => true, + 'has_tags' => true, + 'preview_path' => "tmp/drafts/{$uploadId}/preview.webp", + 'created_at' => now(), + 'updated_at' => now(), + ]); + + $service = app(PublishService::class); + + expect(fn () => $service->publish($uploadId, $other)) + ->toThrow(RuntimeException::class, 'You do not own this upload.'); +}); + +it('rejects archive publish without screenshots', function () { + Storage::fake('local'); + + $owner = User::factory()->create(); + $categoryId = createCategoryForPublishTests(); + $uploadId = (string) Str::uuid(); + + DB::table('uploads')->insert([ + 'id' => $uploadId, + 'user_id' => $owner->id, + 'type' => 'archive', + 'status' => 'draft', + 'moderation_status' => 'approved', + 'title' => 'Skin Pack', + 'category_id' => $categoryId, + 'is_scanned' => true, + 'has_tags' => true, + 'preview_path' => "tmp/drafts/{$uploadId}/preview.webp", + 'created_at' => now(), + 'updated_at' => now(), + ]); + + DB::table('upload_files')->insert([ + 'upload_id' => $uploadId, + 'path' => "tmp/drafts/{$uploadId}/main/pack.zip", + 'type' => 'main', + 'hash' => 'aabbccddeeff0011', + 'size' => 1024, + 'mime' => 'application/zip', + 'created_at' => now(), + ]); + + $service = app(PublishService::class); + + expect(fn () => $service->publish($uploadId, $owner)) + ->toThrow(RuntimeException::class, 'Archive uploads require at least one screenshot.'); +}); diff --git a/tests/Unit/Uploads/UploadDraftServiceTest.php b/tests/Unit/Uploads/UploadDraftServiceTest.php new file mode 100644 index 00000000..897fe868 --- /dev/null +++ b/tests/Unit/Uploads/UploadDraftServiceTest.php @@ -0,0 +1,130 @@ +user = User::factory()->create(); + + // Provide a dummy clamav scanner binding so any scanning calls are mocked + $this->app->instance('clamav', new class { + public function scan(string $path): bool + { + return true; + } + }); + + $filesystem = $this->app->make(FilesystemManager::class); + $this->service = new UploadDraftService($filesystem, 'local'); + } + + public function test_createDraft_creates_directory_and_writes_meta() + { + $result = $this->service->createDraft(['title' => 'Test Draft', 'user_id' => $this->user->id, 'type' => 'image']); + + $this->assertArrayHasKey('id', $result); + $id = $result['id']; + + Storage::disk('local')->assertExists("tmp/drafts/{$id}"); + Storage::disk('local')->assertExists("tmp/drafts/{$id}/meta.json"); + + $meta = json_decode(Storage::disk('local')->get("tmp/drafts/{$id}/meta.json"), true); + $this->assertSame('Test Draft', $meta['title']); + $this->assertSame($id, $meta['id']); + } + + public function test_storeMainFile_saves_file_and_updates_meta() + { + $draft = $this->service->createDraft(['user_id' => $this->user->id, 'type' => 'image']); + $id = $draft['id']; + + $file = UploadedFile::fake()->create('song.mp3', 1500, 'audio/mpeg'); + + $info = $this->service->storeMainFile($id, $file); + + $this->assertArrayHasKey('path', $info); + Storage::disk('local')->assertExists($info['path']); + + $meta = json_decode(Storage::disk('local')->get("tmp/drafts/{$id}/meta.json"), true); + $this->assertArrayHasKey('main_file', $meta); + $this->assertSame($info['hash'], $meta['main_file']['hash']); + } + + public function test_storeScreenshot_saves_file_and_appends_meta() + { + $draft = $this->service->createDraft(['user_id' => $this->user->id, 'type' => 'image']); + $id = $draft['id']; + + $img = UploadedFile::fake()->image('thumb.jpg', 640, 480); + + $info = $this->service->storeScreenshot($id, $img); + + $this->assertArrayHasKey('path', $info); + Storage::disk('local')->assertExists($info['path']); + + $meta = json_decode(Storage::disk('local')->get("tmp/drafts/{$id}/meta.json"), true); + $this->assertArrayHasKey('screenshots', $meta); + $this->assertCount(1, $meta['screenshots']); + $this->assertSame($info['hash'], $meta['screenshots'][0]['hash']); + } + + public function test_calculateHash_for_local_file_and_storage_path() + { + $file = UploadedFile::fake()->create('doc.pdf', 10); + $realPath = $file->getRealPath(); + + $expected = hash_file('sha256', $realPath); + $this->assertSame($expected, $this->service->calculateHash($realPath)); + + // Store into drafts and calculate by storage path + $draft = $this->service->createDraft(['user_id' => $this->user->id, 'type' => 'image']); + $id = $draft['id']; + $info = $this->service->storeMainFile($id, $file); + + $storageHash = $this->service->calculateHash($info['path']); + $storedContents = Storage::disk('local')->get($info['path']); + $this->assertSame(hash('sha256', $storedContents), $storageHash); + } + + public function test_setExpiration_writes_expires_at_in_meta() + { + $draft = $this->service->createDraft(['user_id' => $this->user->id, 'type' => 'image']); + $id = $draft['id']; + + $when = Carbon::now()->addDays(3); + $ok = $this->service->setExpiration($id, $when); + $this->assertTrue($ok); + + $meta = json_decode(Storage::disk('local')->get("tmp/drafts/{$id}/meta.json"), true); + $this->assertArrayHasKey('expires_at', $meta); + $this->assertSame($when->toISOString(), $meta['expires_at']); + } + + public function test_calculateHash_throws_for_missing_file() + { + $this->expectException(\RuntimeException::class); + $this->service->calculateHash('this/path/does/not/exist'); + } +} diff --git a/vite.config.js b/vite.config.js index 83c5dfb2..02557dc4 100644 --- a/vite.config.js +++ b/vite.config.js @@ -8,9 +8,17 @@ export default defineConfig({ 'resources/css/app.css', 'resources/js/app.js', 'resources/scss/nova.scss', - 'resources/js/nova.js' + 'resources/js/nova.js', + 'resources/js/entry-topbar.jsx', + 'resources/js/upload.jsx' ], refresh: true, }), ], + test: { + environment: 'jsdom', + globals: true, + setupFiles: ['resources/js/test/setupTests.js'], + include: ['resources/js/**/*.test.{js,jsx}'], + }, });