Compare commits

..

No commits in common. "main" and "soccer" have entirely different histories.
main ... soccer

296 changed files with 7125 additions and 32366 deletions

View File

@ -1,75 +0,0 @@
name: Build and Deploy
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: linux_amd64
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install dependencies
run: npm ci
timeout-minutes: 5
- name: Build Front End
run: npm run build
timeout-minutes: 10
env:
NODE_OPTIONS: '--max-old-space-size=4096'
VITE_AUTH0_CLIENTID: ${{ secrets.VITE_AUTH0_CLIENTID }}
VITE_AUTH0_DOMAIN: ${{ secrets.VITE_AUTH0_DOMAIN }}
- name: Stop Service
run: |
sudo rc-service immersive stop || true
- name: Deploy to /opt/immersive
run: |
# Ensure group write so we can delete old files
sudo chmod -R g+w /opt/immersive || true
# Remove old files except data directory and env file
find /opt/immersive -mindepth 1 -maxdepth 1 ! -name 'data' ! -name '.env.production' -exec rm -rf {} +
# Copy built files to target
cp -r . /opt/immersive/
# Remove unnecessary directories
rm -rf /opt/immersive/.git /opt/immersive/.github
# Set permissions on start.sh and ensure group write for future deploys
chmod +x /opt/immersive/start.sh
sudo chmod -R g+w /opt/immersive
# Set ownership to immersive user
sudo chown -R immersive:immersive /opt/immersive
- name: Create Environment File
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
NEW_RELIC_LICENSE_KEY: ${{ secrets.NEW_RELIC_LICENSE_KEY }}
run: |
# Create .env.production with secrets (only accessible by immersive user)
echo "# Auto-generated by CI/CD - Do not edit manually" > /opt/immersive/.env.production
echo "ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}" >> /opt/immersive/.env.production
echo "CLOUDFLARE_ACCOUNT_ID=${CLOUDFLARE_ACCOUNT_ID}" >> /opt/immersive/.env.production
echo "CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN}" >> /opt/immersive/.env.production
echo "NEW_RELIC_LICENSE_KEY=${NEW_RELIC_LICENSE_KEY}" >> /opt/immersive/.env.production
# Secure the environment file
sudo chown immersive:immersive /opt/immersive/.env.production
sudo chmod 600 /opt/immersive/.env.production
- name: Start Service
run: |
sudo rc-service immersive start

View File

@ -1,19 +0,0 @@
name: Node.js CI
on:
push:
branches: [ "deepdiagram" ]
pull_request:
branches: [ "deepdiagram" ]
jobs:
build:
runs-on: self-hosted
steps:
- uses: actions/checkout@v2
- name: Use Node.js 20.x
uses: actions/setup-node@v2
with:
node-version: 20.x
- run: cp -r ./dist/* /var/www/deepdiagram

View File

@ -1,50 +0,0 @@
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
name: Node.js Github Side
on:
push:
branches: [ "deepdiagram" ]
pull_request:
branches: [ "deepdiagram" ]
jobs:
build:
name: build app
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 20.x
uses: actions/setup-node@v2
with:
node-version: 20.x
cache-dependency-path: package-lock.json
- run: echo "test"
- run: npm ci
- run: npm run build
env:
VITE_SYNCDB_ENDPOINT: ${{ secrets.VITE_SYNCDB_ENDPOINT }}
VITE_USER_ENDPOINT: ${{ secrets.VITE_USER_ENDPOINT }}
VITE_CREATE_ENDPOINT: ${{ secrets.VITE_CREATE_ENDPOINT }}
NODE_OPTIONS: --max-old-space-size=4096
- name: Archive production artifacts
uses: actions/upload-artifact@v4
with:
name: upload-dist
path: ./dist
overwrite: true
deploy:
name: deploy on linode
needs: build
runs-on: self-hosted
steps:
- name: get artifact
uses: actions/download-artifact@v4
with:
name: upload-dist
path: dist
- run: pwd
- run: cp -r ./dist/* /var/www/deepdiagram/

2
.gitignore vendored
View File

@ -25,5 +25,3 @@ dist-ssr
# Local Netlify folder
.netlify
/data/
/.env.production

View File

@ -1,280 +0,0 @@
# Alpine Linux Service Setup
This guide covers installing and running Immersive as a service on Alpine Linux using OpenRC.
## Prerequisites
```bash
# Update packages
apk update
# Install Node.js 18+ and npm
apk add nodejs npm
# Install build dependencies (required for native modules like leveldown)
apk add python3 make g++ git
# Verify Node version (must be >= 18)
node --version
```
## Create Service User
Create a dedicated user to run the service (security best practice):
```bash
# Create immersive group and user (no login shell, no home directory)
addgroup -S immersive
adduser -S -G immersive -H -s /sbin/nologin immersive
# Create directories with proper ownership
mkdir -p /opt/immersive
mkdir -p /var/log/immersive
mkdir -p /var/run/immersive
chown -R immersive:immersive /opt/immersive
chown -R immersive:immersive /var/log/immersive
chown -R immersive:immersive /var/run/immersive
```
## Installation
```bash
# Create application directory
mkdir -p /opt/immersive
cd /opt/immersive
# Clone or copy the application
git clone <your-repo-url> .
# OR copy files manually
# Install dependencies
npm ci --production=false
# Build the application
NODE_OPTIONS='--max-old-space-size=4096' npm run build
# Copy Havok physics WASM (if not already done by build)
npm run havok
# Create data directory for PouchDB
mkdir -p /opt/immersive/data
# Set ownership to immersive user
chown -R immersive:immersive /opt/immersive
```
## Start Script
The `start.sh` script is included in the repository. After deployment, ensure it's executable:
```bash
chmod +x /opt/immersive/start.sh
```
The script sets up the environment and starts the Node.js server, logging output to `/var/log/immersive/`.
## OpenRC Service
Create `/etc/init.d/immersive`:
```bash
#!/sbin/openrc-run
name="immersive"
description="Immersive WebXR Diagramming Application"
command="/opt/immersive/start.sh"
command_user="immersive:immersive"
command_background="yes"
pidfile="/var/run/immersive/immersive.pid"
directory="/opt/immersive"
output_log="/var/log/immersive/app.log"
error_log="/var/log/immersive/error.log"
depend() {
need net
after firewall
}
start_pre() {
checkpath --directory --owner immersive:immersive --mode 0755 /var/log/immersive
checkpath --directory --owner immersive:immersive --mode 0755 /var/run/immersive
checkpath --file --owner immersive:immersive --mode 0644 /var/log/immersive/app.log
checkpath --file --owner immersive:immersive --mode 0644 /var/log/immersive/error.log
}
```
Make it executable and enable:
```bash
chmod +x /etc/init.d/immersive
rc-update add immersive default
```
## Service Management
```bash
# Start the service
rc-service immersive start
# Stop the service
rc-service immersive stop
# Restart the service
rc-service immersive restart
# Check status
rc-service immersive status
# View logs
tail -f /var/log/immersive/app.log
tail -f /var/log/immersive/error.log
```
## Log Rotation
Create `/etc/logrotate.d/immersive`:
```
/var/log/immersive/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0644 immersive immersive
postrotate
rc-service immersive restart > /dev/null 2>&1 || true
endscript
}
```
Install logrotate if not present:
```bash
apk add logrotate
```
## Environment Variables
Create `/opt/immersive/.env.production` for production settings:
```bash
# Server
NODE_ENV=production
PORT=3001
# Auth0 (if using authentication)
# VITE_AUTH0_DOMAIN=your-domain.auth0.com
# VITE_AUTH0_CLIENT_ID=your-client-id
# Database sync endpoint (optional)
# VITE_SYNCDB_ENDPOINT=https://your-couchdb-server.com
```
## Firewall (if using iptables)
```bash
# Allow port 3001
iptables -A INPUT -p tcp --dport 3001 -j ACCEPT
# Save rules
rc-service iptables save
```
## Reverse Proxy (Optional)
If using nginx as a reverse proxy:
```bash
apk add nginx
```
Create `/etc/nginx/http.d/immersive.conf`:
```nginx
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
```
Enable and start nginx:
```bash
rc-update add nginx default
rc-service nginx start
```
## Gitea CI/CD Runner (Optional)
If using a Gitea Actions runner to deploy, grant the runner user write access to `/opt/immersive`:
```bash
# Add gitea-runner to immersive group
adduser gitea-runner immersive
# Set group write permissions on /opt/immersive
chmod -R g+w /opt/immersive
# Ensure new files inherit group ownership
chmod g+s /opt/immersive
# Allow runner to manage the service
# Add to /etc/sudoers.d/gitea-runner:
echo 'gitea-runner ALL=(ALL) NOPASSWD: /sbin/rc-service immersive *' > /etc/sudoers.d/gitea-runner
echo 'gitea-runner ALL=(ALL) NOPASSWD: /bin/chown -R immersive\:immersive /opt/immersive' >> /etc/sudoers.d/gitea-runner
chmod 440 /etc/sudoers.d/gitea-runner
```
The GitHub Actions workflow in `.github/workflows/build.yml` will handle deployment automatically on push to main.
## Troubleshooting
**Service fails to start:**
```bash
# Check logs
cat /var/log/immersive/error.log
# Run manually as immersive user to see errors
su -s /bin/sh immersive -c "cd /opt/immersive && NODE_ENV=production node server.js"
```
**Native module errors (leveldown):**
```bash
# Rebuild native modules
cd /opt/immersive
npm rebuild leveldown
```
**Permission issues:**
```bash
# Ensure proper ownership (must be immersive user)
chown -R immersive:immersive /opt/immersive
chown -R immersive:immersive /var/log/immersive
chown -R immersive:immersive /var/run/immersive
chmod -R 755 /opt/immersive
```
**Port already in use:**
```bash
# Find process using port 3001
lsof -i :3001
# Or
netstat -tlnp | grep 3001
```

137
CLAUDE.md
View File

@ -1,137 +0,0 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
This is "immersive" - a WebXR/VR diagramming application built with BabylonJS and React. It allows users to create and interact with 3D diagrams in both standard web browsers and VR environments, with real-time collaboration via PouchDB sync.
## Build and Development Commands
### Development
- `npm run dev` - Start Vite dev server on port 3001 (DO NOT USE per user instructions)
- `npm run build` - Build production bundle (includes version bump)
- `npm run preview` - Preview production build on port 3001
- `npm test` - Run tests with Vitest
- `npm run socket` - Start WebSocket server for collaboration (port 8080)
- `npm run serverBuild` - Compile TypeScript server code
- `npm run havok` - Copy Havok physics WASM files to Vite deps
### Testing
- Run all tests: `npm test`
- No single test command is configured; tests use Vitest
## Architecture
### Core Technologies
- **BabylonJS 8.x**: 3D engine with WebXR support and Havok physics
- **React + Mantine**: UI framework for 2D interface and settings
- **PouchDB**: Client-side database with CouchDB sync for collaboration
- **Auth0**: Authentication provider
- **Vite**: Build tool and dev server
### Key Architecture Patterns
#### Singleton Scene Management
The application uses a singleton pattern for the BabylonJS Scene via `DefaultScene` (src/defaultScene.ts). Always access the scene through `DefaultScene.Scene` rather than creating new instances.
#### Observable-Based Event System
The application heavily uses BabylonJS Observables for event handling:
- **DiagramManager.onDiagramEventObservable**: Central hub for diagram entity changes
- **DiagramManager.onUserEventObservable**: User position/state updates for multiplayer
- **AppConfig.onConfigChangedObservable**: Application settings changes
- **controllerObservable**: VR controller input events
Event observers use a mask system (`DiagramEventObserverMask`) to distinguish:
- `FROM_DB`: Events coming from database sync (shouldn't trigger database writes)
- `TO_DB`: Events that should be persisted to database
#### Diagram Entity System
All 3D objects in the scene are represented by `DiagramEntity` types (src/diagram/types/diagramEntity.ts):
- Entities have a template reference (e.g., `#image-template`)
- Managed by `DiagramManager` which maintains a Map of `DiagramObject` instances
- Changes propagate through the Observable system to database and other clients
#### VR Controller Architecture
Controllers inherit from `AbstractController` with specialized implementations:
- `LeftController`: Menu interactions, navigation
- `RightController`: Object manipulation, selection
- Controllers communicate via `controllerObservable` with `ControllerEvent` messages
- `Rigplatform` manages the player rig and handles locomotion
#### Database & Sync
- `PouchdbPersistenceManager` (src/integration/database/pouchdbPersistenceManager.ts) handles all persistence
- Supports optional encryption via `Encryption` class
- Syncs to remote CouchDB via proxy (configured in vite.config.ts)
- URL pattern `/db/public/:db` or `/db/private/:db` determines database name
- Uses `presence.ts` for broadcasting user positions over WebSocket
### Project Structure
- `src/vrcore/`: Engine initialization and core VR setup
- `src/controllers/`: VR controller implementations and input handling
- `src/diagram/`: 3D diagram entities, management, and scene interaction
- `src/integration/`: Database sync, encryption, and presence system
- `src/menus/`: In-VR 3D menus (not React components)
- `src/objects/`: Reusable 3D objects (buttons, handles, avatars)
- `src/react/`: React UI components for 2D interface
- `src/util/`: Shared utilities and configuration
- `server/`: WebSocket server for real-time presence
### Configuration System
Two configuration systems exist (being migrated):
1. **AppConfig class** (src/util/appConfig.ts): Observable-based config with typed properties
2. **ConfigType** (bottom of appConfig.ts): Legacy localStorage-based config
Settings include snapping values, physics toggles, fly mode, and turn snap angles.
## Important Development Notes
### Proxy Configuration
The dev and preview servers proxy certain routes to production:
- `/sync/*` - Database sync endpoint
- `/create-db` - Database creation
- `/api/images` - Image uploads
### Physics System
- Uses Havok physics engine (requires WASM file via `npm run havok`)
- Physics can be enabled/disabled via AppConfig
- `customPhysics.ts` provides helper functions
### WebGPU Support
The engine initializer supports both WebGL and WebGPU backends via the `useWebGpu` parameter.
### Encryption
Databases can be optionally encrypted. The `Encryption` class handles AES encryption with password-derived keys. Salt is stored in metadata document.
### Environment Variables
- `VITE_USER_ENDPOINT`: User authentication endpoint
- `VITE_SYNCDB_ENDPOINT`: Remote database sync endpoint
Check `.env.local` for local configuration.
## Naming Conventions
### Tool and Material Naming
**Material Names:** Materials follow the pattern `material-{color}` where `{color}` is the hex color string (e.g., `material-#ff0000` for red).
**Tool Mesh Names:** Tools use the pattern `tool-{toolType}-{color}`:
- Example: `tool-BOX-#ff0000` (red box tool)
- ToolTypes: `BOX`, `SPHERE`, `CYLINDER`, `CONE`, `PLANE`, `PERSON`
**Tool Instance Names:** `tool-instance-{toolType}-{color}` (e.g., `tool-instance-BOX-#ff0000`)
**Implementation details:**
- 16 predefined toolbox colors (see docs/NAMING_CONVENTIONS.md)
- Materials created in `src/toolbox/functions/buildColor.ts`
- Tool meshes created in `src/toolbox/functions/buildTool.ts`
- When extracting colors from materials, use: `emissiveColor || diffuseColor` (priority order)
### Rendering Modes
Three rendering modes affect material properties:
1. **Lightmap with Lighting**: Uses `diffuseColor` + `lightmapTexture` (expensive)
2. **Unlit with Emissive Texture** (default): Uses `emissiveColor` + `emissiveTexture` (lightmap)
3. **Flat Emissive**: Uses only `emissiveColor` (fastest)
See `src/util/renderingMode.ts` and `src/util/lightmapGenerator.ts` for implementation.

View File

@ -1,403 +0,0 @@
# Express.js API Server Plan
## Goal
Add an Express.js backend server to handle API routes (starting with Claude API), with support for either combined or split deployment.
## Advantages Over Next.js Migration
- **Minimal frontend changes** - only API URL configuration
- **No routing changes** - keep react-router-dom as-is
- **Flexible deployment** - combined or split frontend/backend
- **Already partially exists** - `server.js` in root has Express + vite-express scaffolding
## Deployment Options
### Option A: Combined (Single Server)
```
Express Server (vite-express)
├── Serves static files from dist/
└── Handles /api/* routes
```
- Simpler setup, one deployment
- Good for: VPS, Railway, Fly.io, DigitalOcean App Platform
### Option B: Split (Separate Hosts)
```
Static Host (CDN) API Server (Node.js)
├── Cloudflare Pages ├── Railway
├── Netlify ├── Fly.io
├── Vercel ├── AWS Lambda
└── S3 + CloudFront └── Any VPS
Serves dist/ Handles /api/*
```
- Better scalability, cheaper static hosting
- Good for: High traffic, global CDN distribution
---
## Current State
### Existing `server.js` (incomplete)
```javascript
import express from "express";
import ViteExpress from "vite-express";
import dotenv from "dotenv";
import expressProxy from "express-http-proxy";
dotenv.config();
const app = express();
app.use("/api", expressProxy("local.immersiveidea.com"));
ViteExpress.listen(app, process.env.PORT || 3001, () => console.log("Server is listening..."));
```
### Missing Dependencies
The following packages are imported but not in package.json:
- `express`
- `vite-express`
- `express-http-proxy`
- `dotenv`
---
## Implementation Plan
### Phase 1: Install Dependencies
```bash
npm install express vite-express dotenv cors
```
- `express` - Web framework
- `vite-express` - Vite integration for combined deployment
- `dotenv` - Environment variable loading
- `cors` - Cross-origin support for split deployment
### Phase 2: Create API Routes Structure
Create a modular API structure:
```
server/
├── server.js # Existing WebSocket server (keep as-is)
├── api/
│ ├── index.js # Main API router
│ └── claude.js # Claude API proxy route
```
### Phase 3: Update Root `server.js`
Replace the current incomplete server.js with:
```javascript
import express from "express";
import ViteExpress from "vite-express";
import cors from "cors";
import dotenv from "dotenv";
import apiRoutes from "./server/api/index.js";
dotenv.config();
const app = express();
// CORS configuration for split deployment
// In combined mode, same-origin requests don't need CORS
const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(",") || [];
if (allowedOrigins.length > 0) {
app.use(cors({
origin: allowedOrigins,
credentials: true,
}));
}
app.use(express.json());
// API routes
app.use("/api", apiRoutes);
// Check if running in API-only mode (split deployment)
const apiOnly = process.env.API_ONLY === "true";
if (apiOnly) {
// API-only mode: no static file serving
app.listen(process.env.PORT || 3000, () => {
console.log(`API server running on port ${process.env.PORT || 3000}`);
});
} else {
// Combined mode: Vite handles static files + SPA
ViteExpress.listen(app, process.env.PORT || 3001, () => {
console.log(`Server running on port ${process.env.PORT || 3001}`);
});
}
```
### Phase 4: Create API Router
**`server/api/index.js`**:
```javascript
import { Router } from "express";
import claudeRouter from "./claude.js";
const router = Router();
// Claude API proxy
router.use("/claude", claudeRouter);
// Health check
router.get("/health", (req, res) => {
res.json({ status: "ok" });
});
export default router;
```
**`server/api/claude.js`**:
```javascript
import { Router } from "express";
const router = Router();
const ANTHROPIC_API_URL = "https://api.anthropic.com";
router.post("/*", async (req, res) => {
const apiKey = process.env.ANTHROPIC_API_KEY;
if (!apiKey) {
return res.status(500).json({ error: "API key not configured" });
}
// Get the path after /api/claude (e.g., /v1/messages)
const path = req.params[0] || req.path;
try {
const response = await fetch(`${ANTHROPIC_API_URL}${path}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": apiKey,
"anthropic-version": "2023-06-01",
},
body: JSON.stringify(req.body),
});
const data = await response.json();
res.status(response.status).json(data);
} catch (error) {
console.error("Claude API error:", error);
res.status(500).json({ error: "Failed to proxy request to Claude API" });
}
});
export default router;
```
### Phase 5: Update Vite Config
Remove the Claude proxy from `vite.config.ts` since Express handles it now.
**Before** (lines 41-56):
```javascript
'^/api/claude': {
target: 'https://api.anthropic.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api\/claude/, ''),
configure: (proxy) => {
proxy.on('proxyReq', (proxyReq) => {
const apiKey = env.ANTHROPIC_API_KEY;
// ...
});
}
}
```
**After**: Remove this block entirely. The Express server handles `/api/claude/*`.
Keep the other proxies (`/sync/*`, `/create-db`, `/api/images`) - they still proxy to deepdiagram.com in dev mode.
### Phase 6: Add API URL Configuration (for Split Deployment)
Create a utility to get the API base URL:
**`src/util/apiConfig.ts`**:
```typescript
// API base URL - empty string for same-origin (combined deployment)
// Set VITE_API_URL for split deployment (e.g., "https://api.yourdomain.com")
export const API_BASE_URL = import.meta.env.VITE_API_URL || '';
export function apiUrl(path: string): string {
return `${API_BASE_URL}${path}`;
}
```
**Update `src/react/services/diagramAI.ts`**:
```typescript
import { apiUrl } from '../../util/apiConfig';
// Change from:
const response = await fetch('/api/claude/v1/messages', { ... });
// To:
const response = await fetch(apiUrl('/api/claude/v1/messages'), { ... });
```
This change is backward-compatible:
- **Combined deployment**: `VITE_API_URL` is empty, calls go to same origin
- **Split deployment**: `VITE_API_URL=https://api.example.com`, calls go to API server
### Phase 7: Update package.json Scripts
```json
"scripts": {
"dev": "node server.js",
"build": "node versionBump.js && vite build",
"start": "NODE_ENV=production node server.js",
"start:api": "API_ONLY=true node server.js",
"test": "vitest",
"socket": "node server/server.js",
"serverBuild": "cd server && tsc"
}
```
**Changes:**
- `dev`: Runs Express + vite-express (serves Vite in dev mode)
- `start`: Combined mode - serves dist/ + API
- `start:api`: API-only mode for split deployment
- Removed `preview` (use `start` instead)
---
## File Changes Summary
| Action | File | Description |
|--------|------|-------------|
| Modify | `package.json` | Add dependencies, update scripts |
| Modify | `server.js` | Full Express server with CORS + API routes |
| Create | `server/api/index.js` | Main API router |
| Create | `server/api/claude.js` | Claude API proxy endpoint |
| Create | `src/util/apiConfig.ts` | API URL configuration utility |
| Modify | `src/react/services/diagramAI.ts` | Use apiUrl() for API calls |
| Modify | `vite.config.ts` | Remove `/api/claude` proxy block |
---
## How vite-express Works
`vite-express` is a simple integration that:
1. **Development**: Runs Vite's dev server as middleware, providing HMR
2. **Production**: Serves the built `dist/` folder as static files
This means:
- One server handles both API and frontend
- No CORS issues (same origin)
- HMR works in development
- Production-ready with `vite build`
---
## Production Deployment
### Option A: Combined Deployment
Single server handles both frontend and API:
```bash
# Build frontend
npm run build
# Start combined server (serves dist/ + API)
npm run start
```
**Environment variables (.env)**:
```bash
PORT=3001
ANTHROPIC_API_KEY=sk-ant-...
```
The Express server will:
1. Handle `/api/*` routes directly
2. Serve static files from `dist/`
3. Fall back to `dist/index.html` for SPA routing
### Option B: Split Deployment
Separate hosting for frontend (CDN) and API (Node server):
**API Server:**
```bash
# Start API-only server
npm run start:api
```
**Environment variables (.env for API server)**:
```bash
PORT=3000
API_ONLY=true
ANTHROPIC_API_KEY=sk-ant-...
ALLOWED_ORIGINS=https://your-frontend.com,https://www.your-frontend.com
```
**Frontend (Static Host):**
```bash
# Build with API URL configured
VITE_API_URL=https://api.yourdomain.com npm run build
# Deploy dist/ to your static host (Cloudflare Pages, Netlify, etc.)
```
**Environment variables (.env.production for frontend build)**:
```bash
VITE_API_URL=https://api.yourdomain.com
```
### Deployment Examples
| Deployment | Frontend | API Server | Cost |
|------------|----------|------------|------|
| Combined | Railway | (same) | ~$5/mo |
| Combined | Fly.io | (same) | Free tier |
| Split | Cloudflare Pages (free) | Railway ($5/mo) | ~$5/mo |
| Split | Netlify (free) | Fly.io (free) | Free |
| Split | Vercel (free) | AWS Lambda | Pay-per-use |
---
## Future API Routes
To add more API routes, create new files in `server/api/`:
```javascript
// server/api/index.js
import claudeRouter from "./claude.js";
import imagesRouter from "./images.js"; // future
import authRouter from "./auth.js"; // future
router.use("/claude", claudeRouter);
router.use("/images", imagesRouter);
router.use("/auth", authRouter);
```
---
## Migration Order
1. `npm install express vite-express dotenv cors`
2. Create `server/api/index.js`
3. Create `server/api/claude.js`
4. Create `src/util/apiConfig.ts`
5. Update `src/react/services/diagramAI.ts` to use `apiUrl()`
6. Update `server.js` (root) with full Express + CORS setup
7. Remove `/api/claude` proxy from `vite.config.ts`
8. Update `package.json` scripts
9. Test combined: `npm run dev` and verify Claude API works
10. (Optional) Test split: Set `VITE_API_URL` and `API_ONLY=true`
---
## Notes
- **WebSocket server unchanged**: `server/server.js` (port 8080) runs separately
- **Minimal frontend changes**: Only `diagramAI.ts` updated to use `apiUrl()`
- **Environment variables**: `ANTHROPIC_API_KEY` already in `.env.local`
- **Node version**: Requires Node 18+ for native `fetch`
- **CORS**: Only enabled when `ALLOWED_ORIGINS` is set (split deployment)
- **Backward compatible**: Works as combined deployment by default

View File

@ -1,30 +0,0 @@
Permissions Conditions Limitations
Commercial use
Distribution
Modification
Private use
License and copyright notice
Liability
Warranty
MIT License
Copyright (c) [2024] [Michael Mainguy]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,167 +0,0 @@
# Vite to Next.js Migration Plan
## Goal
Migrate from Vite to Next.js App Router to get proper API route support, with minimal changes to existing code.
## Configuration
- **Router**: App Router with `'use client'` on all pages
- **Rendering**: CSR only (no SSR) - simplifies migration since BabylonJS can't SSR
- **API Routes**: Claude API now, structured for future expansion
- **External Proxies**: Keep sync/create-db/images as Next.js rewrites to deepdiagram.com
---
## Phase 1: Setup (No Breaking Changes)
### 1.1 Install Next.js
```bash
npm install next
```
### 1.2 Create `next.config.js`
```javascript
/** @type {import('next').NextConfig} */
const nextConfig = {
async rewrites() {
return [
{ source: '/sync/:path*', destination: 'https://www.deepdiagram.com/sync/:path*' },
{ source: '/create-db', destination: 'https://www.deepdiagram.com/create-db' },
{ source: '/api/images', destination: 'https://www.deepdiagram.com/api/images' },
];
},
webpack: (config, { isServer }) => {
config.experiments = { ...config.experiments, asyncWebAssembly: true };
return config;
},
};
module.exports = nextConfig;
```
### 1.3 Update `tsconfig.json`
Add path alias:
```json
"baseUrl": ".",
"paths": { "@/*": ["./*"] }
```
---
## Phase 2: Create New Files
### 2.1 `src/react/providers.tsx` (extract from webApp.tsx)
- Move Auth0Provider and FeatureProvider wrapping here
- Add `'use client'` directive
- Handle window/document checks for SSR safety
### 2.2 `app/layout.tsx`
- Root layout with html/body tags
- Metadata (title, favicon from current index.html)
- Import global CSS
### 2.3 `app/globals.css`
```css
@import '../src/react/styles.css';
@import '@mantine/core/styles.css';
```
### 2.4 `app/api/claude/[...path]/route.ts`
- POST handler that proxies to api.anthropic.com
- Injects `ANTHROPIC_API_KEY` from env
- Adds `x-api-key` and `anthropic-version` headers
### 2.5 Page files (all with `'use client'`)
| Route | File | Component |
|-------|------|-----------|
| `/` | `app/page.tsx` | About |
| `/documentation` | `app/documentation/page.tsx` | Documentation |
| `/examples` | `app/examples/page.tsx` | Examples |
| `/pricing` | `app/pricing/page.tsx` | Pricing |
| `/db/[visibility]/[db]` | `app/db/[visibility]/[db]/page.tsx` | VrExperience |
| 404 | `app/not-found.tsx` | NotFound |
### 2.6 `src/react/components/ProtectedPage.tsx`
- Next.js version of route protection
- Uses `useRouter` from `next/navigation` for redirects
---
## Phase 3: Modify Existing Files
### 3.1 `src/react/pages/vrExperience.tsx`
**Changes:**
- Remove `useParams()` from react-router-dom
- Accept `visibility` and `db` as props instead
- Replace `useNavigate()` with `useRouter()` from `next/navigation`
### 3.2 `src/react/pageHeader.tsx`
**Changes:**
- Replace `import {Link} from "react-router-dom"` with `import Link from "next/link"`
- Change `to={item.href}` to `href={item.href}` on Link components
### 3.3 `src/react/marketing/about.tsx`
**Changes:**
- Replace `useNavigate()` with `useRouter()` from `next/navigation`
- Change `navigate('/path')` to `router.push('/path')`
### 3.4 `package.json`
```json
"scripts": {
"dev": "next dev -p 3001",
"build": "node versionBump.js && next build",
"start": "next start -p 3001",
"test": "vitest",
"socket": "node server/server.js",
"serverBuild": "cd server && tsc"
}
```
---
## Phase 4: Delete Old Files
| File | Reason |
|------|--------|
| `vite.config.ts` | Replaced by next.config.js |
| `index.html` | Next.js generates HTML |
| `src/webApp.ts` | Entry point no longer needed |
| `src/react/webRouter.tsx` | Replaced by app/ routing |
| `src/react/webApp.tsx` | Logic moved to providers.tsx |
| `src/react/components/ProtectedRoute.tsx` | Replaced by ProtectedPage.tsx |
---
## Critical Files to Modify
- `src/react/pages/vrExperience.tsx` - useParams -> props
- `src/react/pageHeader.tsx` - react-router Link -> Next.js Link
- `src/react/marketing/about.tsx` - useNavigate -> useRouter
- `src/react/webApp.tsx` - extract to providers.tsx
- `package.json` - scripts update
- `tsconfig.json` - path aliases
---
## Migration Order
1. Install next, create next.config.js
2. Update tsconfig.json
3. Create app/globals.css
4. Create src/react/providers.tsx
5. Create app/layout.tsx
6. Create app/api/claude/[...path]/route.ts
7. Create src/react/components/ProtectedPage.tsx
8. Modify vrExperience.tsx (accept props)
9. Create all app/*/page.tsx files
10. Modify pageHeader.tsx (Next.js Link)
11. Modify about.tsx (useRouter)
12. Update package.json scripts
13. Delete old files (vite.config.ts, index.html, webApp.ts, webRouter.tsx, webApp.tsx)
14. Test all routes
---
## Notes
- **Havok WASM**: Move `HavokPhysics.wasm` to `public/` folder
- **react-router-dom**: Can be removed from dependencies after migration
- **vite devDependencies**: Can be removed (vite, vite-plugin-cp)

View File

@ -1,224 +0,0 @@
# Immersive - Product Roadmap
## Vision
Transform immersive into an accessible, intuitive WebXR diagramming platform that delivers a frictionless onboarding experience and sustainable growth path.
---
## Phase 1: Onboarding & User Experience (Q1 2025)
### 1.1 Frictionless Entry
**Goal:** Reduce barriers to entry for new users
- [ ] Redesign landing page to clearly guide users to immersive experience
- [ ] Create one-click "Enter VR" / "Try Demo" workflow
- [ ] Optimize initial load time and progressive loading
- [ ] Add clear device compatibility messaging (desktop/VR)
- [ ] Implement guest mode with no sign-in required for basic exploration
### 1.2 Marketing Content
**Goal:** Communicate value proposition effectively
- [ ] Create 3-5 demo videos showcasing key features (30-60 seconds each)
- Creating a basic diagram
- VR interaction showcase
- Collaboration features
- Template usage
- [ ] Develop tutorial video (2-3 minutes) explaining core workflows
- [ ] Autoplay video carousel on landing page
- [ ] Write marketing copy for landing page
- Hero section with clear value proposition
- Feature highlights
- Use case examples
- Call-to-action
### 1.3 In-Experience Tutorial
**Goal:** Replace external tutorial with immersive learning
- [ ] Remove existing external tutorial system
- [ ] Design in-VR tutorial experience with interactive steps
- [ ] Implement progressive disclosure (teach as users interact)
- [ ] Add contextual tooltips and hints in 3D space
- [ ] Create "first-time user" detection and guided walkthrough
- [ ] Add skip/replay tutorial options
### 1.4 Template System
**Goal:** Provide starting points for new users
- [ ] Design template/example diagram system
- [ ] Create 5-10 starter templates:
- Simple organizational chart
- Project workflow diagram
- Concept mapping example
- Architecture diagram
- Spatial layout example
- [ ] Build template browser UI (2D and VR)
- [ ] Implement "New from Template" workflow
- [ ] Add template preview/thumbnail generation
---
## Phase 2: Collaboration & Sync (Q2 2025)
### 2.1 Cross-Device Sharing
**Goal:** Enable seamless content sharing between desktop and Quest
- [ ] Research device-to-device sync options (WebRTC, local network)
- [ ] Design sync architecture without backend dependency
- [ ] Implement user content sync for signed-in users
- [ ] Add fallback to server-based sync when needed
- [ ] Create device pairing UI/workflow
- [ ] Test sync reliability across desktop ↔ Quest
- [ ] Add conflict resolution for simultaneous edits
---
## Phase 3: Immersion & Environment (Q2-Q3 2025)
### 3.1 Audio Integration
**Goal:** Enhance presence with ambient soundscapes
- [ ] Source/create ambient audio assets
- Nature sounds (birds, wind, water)
- Office ambience
- Abstract/focus music
- [ ] Implement spatial audio system
- [ ] Add audio settings (volume, on/off, environment selection)
- [ ] Create audio manager for seamless transitions
- [ ] Add positional audio for collaboration (optional user voices)
### 3.2 Environment System
**Goal:** Provide varied immersive environments
- [ ] Design environment switching architecture
- [ ] Create environment presets:
- Outdoor/nature scene
- Modern office
- Abstract/minimal space
- Workshop/studio
- [ ] Implement skybox and lighting variations
- [ ] Build environment selector UI (2D and VR)
- [ ] Optimize environment assets for performance
- [ ] Add environment-specific audio pairing
---
## Phase 4: User Feedback & Polish (Q3 2025)
### 4.1 In-VR Feedback Mechanism
**Goal:** Enable users to provide feedback without leaving VR
- [ ] Design in-VR feedback form/interface
- [ ] Implement voice-to-text option (VR accessibility)
- [ ] Add screenshot/recording attachment capability
- [ ] Create feedback submission backend
- [ ] Build feedback review dashboard
- [ ] Add "Report Bug" quick action in VR menu
### 4.2 Keyboard Improvements
**Goal:** Improve text input experience
- [ ] Test system keyboard integration (Quest/desktop)
- [ ] Evaluate custom keyboard vs. native keyboard UX
- [ ] Implement system keyboard fallback where supported
- [ ] Optimize keyboard positioning in VR space
- [ ] Add keyboard shortcuts for power users (desktop)
---
## Phase 5: Growth & Monetization (Q4 2025)
### 5.1 Marketing Roadmap
**Goal:** Build sustainable user acquisition
- [ ] Define target audience segments
- Educators
- Remote teams
- Designers/architects
- Knowledge workers
- [ ] Create content marketing strategy
- Blog posts on use cases
- Social media showcase
- Community building (Discord/Reddit)
- [ ] Develop SEO optimization plan
- [ ] Plan partnership outreach (VR communities, productivity tools)
- [ ] Create referral/sharing incentives
- [ ] Build analytics dashboard for user metrics
### 5.2 Monetization Strategy
**Goal:** Establish path to sustainability
**Potential Revenue Streams:**
- [ ] Freemium model research
- Free tier: Limited diagrams, basic features
- Pro tier: Unlimited diagrams, advanced features, collaboration
- [ ] Team/Enterprise pricing
- Private deployment options
- Admin controls
- Priority support
- [ ] Template marketplace
- Premium templates
- Community submissions (revenue share)
- [ ] Educational licensing
- Institutional pricing
- Classroom management features
**Implementation:**
- [ ] Define pricing tiers and feature gates
- [ ] Integrate payment processing (Stripe)
- [ ] Build subscription management UI
- [ ] Implement feature flags for tier differentiation
- [ ] Create upgrade prompts and conversion flow
- [ ] Add usage analytics for pricing optimization
---
## Success Metrics
### Phase 1-2 (Onboarding)
- Time to first diagram creation < 2 minutes
- Tutorial completion rate > 60%
- Return user rate (7-day) > 30%
### Phase 3-4 (Engagement)
- Average session duration > 15 minutes
- User satisfaction score > 4/5
- Feedback submission rate (active users) > 10%
### Phase 5 (Growth)
- Monthly active users growth > 20% MoM
- Free-to-paid conversion rate > 5%
- Customer acquisition cost < lifetime value
---
## Technical Debt & Infrastructure
### Ongoing Priorities
- [ ] Migration from legacy ConfigType to AppConfig
- [ ] Performance optimization (target 90fps in VR)
- [ ] Accessibility improvements (WCAG compliance)
- [ ] Testing coverage > 70%
- [ ] Documentation for contributors
- [ ] CI/CD pipeline enhancements
---
## Notes
**Dependencies:**
- Auth0 for user authentication
- PouchDB/CouchDB for data persistence
- BabylonJS 8.x for rendering
- Vite for build tooling
**Platform Support:**
- Desktop browsers (Chrome, Firefox, Edge)
- Meta Quest 2/3/Pro
- Future: PSVR2, Vision Pro (evaluate demand)
**Review Cadence:** Quarterly roadmap review and adjustment based on user feedback and metrics.
---
*Last Updated: 2025-11-19*

View File

@ -1,150 +0,0 @@
# Self-Hosted Diagram Sharing with Express-PouchDB
## Requirements (Confirmed)
- **Storage**: In-memory (ephemeral) - lost on server restart
- **Content**: Copy current diagram entities when creating share
- **Expiration**: No expiration - links work until server restart
- **Encryption**: None - keep it simple, anyone with link can access
## Architecture
```
┌─────────────────────────────────────────────────┐
│ Express Server (port 3001) │
├─────────────────────────────────────────────────┤
│ /api/share/* → Share management API │
│ /pouchdb/* → express-pouchdb (sync) │
│ /share/:uuid → Client share route │
│ /api/* → Existing API routes │
│ /* → Vite static files │
└─────────────────────────────────────────────────┘
└── In-Memory PouchDB (per share UUID)
```
## Implementation Steps
### Phase 1: Server-Side Setup
#### 1.1 Add Dependencies
```bash
npm install express-pouchdb pouchdb-adapter-memory
```
#### 1.2 Create PouchDB Server Service
**New file: `server/services/pouchdbServer.js`**
- Initialize PouchDB with memory adapter
- Track active share databases in a Map
- Export `getShareDB(shareId)`, `shareExists(shareId)`, `createPouchDBMiddleware()`
#### 1.3 Create Share API
**New file: `server/api/share.js`**
- `POST /api/share/create` - Generate UUID, create in-memory DB, copy entities
- `GET /api/share/:id/exists` - Check if share exists
- `GET /api/share/stats` - Debug endpoint for active shares
#### 1.4 Update API Router
**Edit: `server/api/index.js`**
- Add `import shareRouter from "./share.js"`
- Mount at `router.use("/share", shareRouter)`
#### 1.5 Mount Express-PouchDB
**Edit: `server.js`**
- Import `createPouchDBMiddleware` from pouchdbServer.js
- Mount at `app.use("/pouchdb", createPouchDBMiddleware())`
---
### Phase 2: Client-Side Integration
#### 2.1 Update URL Parsing
**Edit: `src/util/functions/getPath.ts`**
- Add `getPathInfo()` function returning `{ dbName, isShare, shareId }`
- Detect `/share/:uuid` pattern
#### 2.2 Update PouchDB Persistence Manager
**Edit: `src/integration/database/pouchdbPersistenceManager.ts`**
In `initLocal()`:
- Call `getPathInfo()` to detect share URLs
- If share: use `share-{uuid}` as local DB name, call `beginShareSync()`
Add new method `beginShareSync(shareId)`:
- Check share exists via `/api/share/:id/exists`
- Connect to `${origin}/pouchdb/share-${shareId}`
- Set up presence with `share-${shareId}` as DB name
- Begin live sync (no encryption)
#### 2.3 Add React Route
**Edit: `src/react/webRouter.tsx`**
- Add route `{ path: "/share/:uuid", element: <VrExperience isShare={true} /> }`
- No ProtectedRoute wrapper (public access)
#### 2.4 Add Share Button Handler
**Edit: `src/react/pages/vrExperience.tsx`**
- Add `isShare` prop
- Add `handleShare()` function:
1. Get all entities from local PouchDB
2. POST to `/api/share/create` with entities
3. Copy resulting URL to clipboard
4. Show confirmation
---
### Phase 3: Presence Integration
The WebSocket presence system already routes by database name. Since shares use `share-{uuid}` as the database name, presence works automatically.
**Edit: `server/server.js`** (WebSocket server)
- Update `originIsAllowed()` to allow localhost for development
---
## Files to Modify
| File | Action | Purpose |
|------|--------|---------|
| `package.json` | Edit | Add express-pouchdb, pouchdb-adapter-memory |
| `server.js` | Edit | Mount /pouchdb middleware |
| `server/api/index.js` | Edit | Add share router |
| `server/services/pouchdbServer.js` | Create | PouchDB memory initialization |
| `server/api/share.js` | Create | Share API endpoints |
| `server/server.js` | Edit | Allow localhost origins |
| `src/util/functions/getPath.ts` | Edit | Add getPathInfo() |
| `src/integration/database/pouchdbPersistenceManager.ts` | Edit | Add share sync logic |
| `src/react/webRouter.tsx` | Edit | Add /share/:uuid route |
| `src/react/pages/vrExperience.tsx` | Edit | Add share button handler |
| `src/util/featureConfig.ts` | Edit | Enable shareCollaborate feature |
---
## User Flow
### Creating a Share
1. User has a diagram open at `/db/public/mydiagram`
2. Clicks "Share" button
3. Client fetches all entities from local PouchDB
4. POSTs to `/api/share/create` with entities
5. Server creates in-memory DB, copies entities, returns UUID
6. Client copies `https://server.com/share/{uuid}` to clipboard
7. User shares link with collaborators
### Joining a Share
1. User navigates to `https://server.com/share/{uuid}`
2. React Router renders VrExperience with `isShare=true`
3. PouchdbPersistenceManager detects share URL
4. Checks `/api/share/:uuid/exists` - returns true
5. Creates local PouchDB `share-{uuid}`
6. Connects to `/pouchdb/share-{uuid}` for sync
7. Entities replicate to local, render in scene
8. Presence WebSocket connects with `share-{uuid}` as room
---
## Future Authentication (Not Implemented Now)
Structure allows easy addition later:
- express-pouchdb middleware can be wrapped with auth middleware
- Share API can require JWT/session tokens
- Could add password-protected shares
- Could add read-only vs read-write permissions

View File

@ -1,179 +0,0 @@
# Future Sync Strategy: Keeping Local and Public Clones in Sync
## Current State (v1)
- Sharing creates a **ONE-TIME COPY** from local to public
- Copies diverge independently after sharing
- No automatic sync between local and public versions
- Local diagrams are browser-only (IndexedDB via PouchDB)
- Public diagrams sync with server via express-pouchdb
### URL Scheme
| Route | Sync | Access | Status |
|-------|------|--------|--------|
| `/db/local/:id` | None | Browser-only | Implemented |
| `/db/public/:id` | Yes | Anyone | Implemented |
| `/db/private/:id` | Yes | Authorized users | Route only (no auth) |
## Future Options
### Option 1: Manual Push/Pull (Recommended for v2)
Add explicit user-triggered sync between local and public copies.
**Features:**
- "Push to Public" button - sends local changes to public copy
- "Pull from Public" button - gets public changes into local
- Track `lastSyncedAt` timestamp
- Show indicator when copies have diverged
- Conflict resolution: Last write wins (simple) or user choice (advanced)
**Pros:**
- User stays in control
- Clear mental model
- Simple to implement incrementally
**Cons:**
- Manual effort required
- Risk of forgetting to sync
### Option 2: Automatic Background Sync
Continuous bidirectional sync between local and public copies.
**Features:**
- Real-time sync like Google Docs
- Works across devices
- Offline-first with automatic merge
**Pros:**
- Seamless experience
- Always up to date
**Cons:**
- Complex conflict resolution (may need CRDTs)
- Higher performance overhead
- Harder to reason about state
### Option 3: Fork/Branch Model
One-way relationship: local is "draft", public is "published".
**Features:**
- Push only (local → public)
- No pull mechanism
- Public is the "source of truth" once published
**Pros:**
- Clear mental model
- No merge conflicts
- Simple implementation
**Cons:**
- Cannot incorporate public changes back to local
- Multiple people can't collaborate on draft
## Recommended Implementation (v2)
Implement **Option 1 (Manual Push/Pull)** as it provides the best balance of user control and simplicity.
### Data Model Changes
Add to diagram directory entry:
```typescript
interface DiagramEntry {
_id: string;
name: string;
description: string;
storageType: 'local' | 'public' | 'private';
createdAt: string;
// New fields for sync tracking
publicCopyId?: string; // ID of the public clone (if shared)
lastPushedAt?: string; // When changes were last pushed to public
lastPulledAt?: string; // When public changes were last pulled
publicVersion?: number; // Version number of public copy at last sync
}
```
### API Endpoints
```typescript
// Push local changes to public
POST /api/sync/push
Body: { localDbName: string, publicDbName: string }
Response: { success: boolean, documentsUpdated: number }
// Pull public changes to local
POST /api/sync/pull
Body: { localDbName: string, publicDbName: string }
Response: { success: boolean, documentsUpdated: number }
// Check if copies have diverged
GET /api/sync/status?local={localDbName}&public={publicDbName}
Response: {
diverged: boolean,
localChanges: number,
publicChanges: number,
lastSyncedAt: string
}
```
### UI Components
1. **Sync Status Indicator**
- Shows in header when viewing a local diagram that has a public copy
- Green check: In sync
- Orange dot: Changes pending
- Red warning: Conflicts detected
2. **Push/Pull Buttons**
- In hamburger menu under "Share" section
- "Push to Public" - shows confirmation with change count
- "Pull from Public" - shows confirmation with change count
3. **Divergence Warning Badge**
- Shows on diagram card in Manage Diagrams modal
- Indicates when local and public have diverged
4. **Conflict Resolution Dialog**
- Shows when both local and public have changes to same entity
- Options: Keep Local, Keep Public, Keep Both (creates duplicate)
### Implementation Phases
**Phase 1: Tracking**
- Add `publicCopyId` when sharing local → public
- Track sharing relationship in directory
**Phase 2: Push**
- Implement push from local to public
- Overwrite public with local changes
- Update `lastPushedAt` timestamp
**Phase 3: Pull**
- Implement pull from public to local
- Merge public changes into local
- Update `lastPulledAt` timestamp
**Phase 4: Status**
- Implement divergence detection
- Add UI indicators
- Show sync status in Manage Diagrams
**Phase 5: Conflict Resolution**
- Detect entity-level conflicts
- Show resolution dialog
- Allow user to choose resolution strategy
## Migration Notes
Existing diagrams without `storageType` are treated as `public` for backwards compatibility. When such diagrams are loaded, the UI should work correctly but sync tracking features won't be available until the diagram metadata is updated.
## Security Considerations
- Push/pull operations should validate that the user has access to both databases
- Public databases remain world-readable/writable
- Private database sync will require authentication tokens
- Rate limiting should be applied to sync operations

View File

@ -1,297 +0,0 @@
# VR Configuration Panel Implementation Plan
## Overview
Create an immersive WebXR configuration panel that mirrors the 2D ConfigModal functionality using BabylonJS AdvancedDynamicTexture (ADT). The panel will allow users to adjust all application settings directly in VR.
## Recommended Approach: AdvancedDynamicTexture (ADT)
**Why ADT?**
- Most common approach for WebXR UI in BabylonJS
- Existing pattern in codebase (see `src/menus/configMenu.ts`)
- Good balance of simplicity and functionality
- Native support for text, buttons, sliders, and dropdowns
- Easy integration with existing Handle pattern
**Estimated Effort**: 150-200 lines of code, 4-8 hours implementation time
## File Structure
```
src/menus/
├── vrConfigPanel.ts (NEW - main implementation)
└── configMenu.ts (REFERENCE - existing VR config example)
src/diagram/
└── diagramMenuManager.ts (MODIFY - add toolbox button)
src/util/
└── appConfig.ts (USE - singleton for config management)
```
## Implementation Phases
### Phase 1: Core Panel Setup
- [ ] Create `src/menus/vrConfigPanel.ts` file
- [ ] Implement class structure following Handle pattern:
```typescript
export class VRConfigPanel {
private _scene: Scene;
private _handleMesh: Mesh;
private _advancedTexture: AdvancedDynamicTexture;
private _configObserver: Observer<AppConfigType>;
constructor(scene: Scene) {
// Initialize panel
}
public get handleMesh(): Mesh {
return this._handleMesh;
}
public show(): void {
this._handleMesh.setEnabled(true);
}
public hide(): void {
this._handleMesh.setEnabled(false);
}
public dispose(): void {
// Cleanup
}
}
```
- [ ] Create base mesh (plane) for panel backing
- [ ] Set up AdvancedDynamicTexture with appropriate resolution (1024x1024 or 2048x2048)
- [ ] Position panel at comfortable viewing distance (0.5-0.7m from camera)
- [ ] Make panel grabbable via Handle pattern
**Reference Files**:
- `src/menus/inputTextView.ts` - Handle pattern implementation
- `src/menus/configMenu.ts` - ADT usage example
### Phase 2: UI Layout Structure
- [ ] Create main container (StackPanel for vertical layout)
- [ ] Add title text at top ("Configuration")
- [ ] Create 5 section containers (one for each config group):
1. Location Snap
2. Rotation Snap
3. Fly Mode
4. Snap Turn
5. Label Rendering Mode
- [ ] Style containers with padding and spacing
- [ ] Add visual separators between sections
**ADT Components to Use**:
- `StackPanel` - Main vertical container
- `TextBlock` - Labels and section titles
- `Rectangle` - Containers and separators
**Reference**: `src/menus/configMenu.ts:44-89` for existing layout patterns
### Phase 3: Location Snap Section
- [ ] Add "Location Snap" label
- [ ] Create enable/disable toggle button
- Shows "Enabled" or "Disabled"
- Updates `appConfigInstance` on click
- [ ] Add RadioGroup for snap values:
- Options: 1cm (.01), 5cm (.05), 10cm (.1), 50cm (.5), 1m (1)
- Default: 10cm (.1)
- Disable when snap is off
- [ ] Wire up to `appConfigInstance.setGridSnap(value)`
- [ ] Subscribe to config changes to update UI
**ADT Components**:
- `Button` - Toggle switch
- `RadioButton` + `TextBlock` - Value selection
- Color coding: enabled (green/myColor), disabled (gray)
**Reference ConfigModal**: `src/react/pages/configModal.tsx:83-94`
### Phase 4: Rotation Snap Section
- [ ] Add "Rotation Snap" label
- [ ] Create enable/disable toggle button
- [ ] Add RadioGroup for rotation values:
- Options: 22.5°, 45°, 90°, 180°, 360°
- Default: 90°
- Disable when snap is off
- [ ] Wire up to `appConfigInstance.setRotateSnap(value)`
- [ ] Subscribe to config changes to update UI
**Reference ConfigModal**: `src/react/pages/configModal.tsx:96-108`
### Phase 5: Fly Mode Section
- [ ] Add "Fly Mode" label
- [ ] Create toggle button
- Shows "Fly Mode Enabled" or "Fly Mode Disabled"
- [ ] Wire up to `appConfigInstance.setFlyMode(value)`
- [ ] Subscribe to config changes to update UI
**Reference ConfigModal**: `src/react/pages/configModal.tsx:109-112`
### Phase 6: Snap Turn Section
- [ ] Add "Snap Turn" label
- [ ] Create enable/disable toggle button
- [ ] Add RadioGroup for snap turn angles:
- Options: 22.5°, 45°, 90°, 180°, 360°
- Default: 45°
- Disable when snap is off
- [ ] Wire up to `appConfigInstance.setTurnSnap(value)`
- [ ] Subscribe to config changes to update UI
**Reference ConfigModal**: `src/react/pages/configModal.tsx:113-125`
### Phase 7: Label Rendering Mode Section
- [ ] Add "Label Rendering Mode" label
- [ ] Create RadioGroup for rendering modes:
- Fixed
- Billboard (Always Face Camera)
- Dynamic (Coming Soon) - disabled
- Distance-based (Coming Soon) - disabled
- [ ] Wire up to `appConfigInstance.setLabelRenderingMode(value)`
- [ ] Subscribe to config changes to update UI
- [ ] Style disabled options with gray text
**Reference ConfigModal**: `src/react/pages/configModal.tsx:126-135`
### Phase 8: Integration with Toolbox
- [ ] Modify `src/diagram/diagramMenuManager.ts` to instantiate VRConfigPanel
- [ ] Add "Config" button to toolbox (similar to "Exit VR" button pattern)
- [ ] Wire up button click to show/hide panel
- [ ] Position panel relative to camera when shown (see `positionComponentsRelativeToCamera`)
- [ ] Add parent relationship to platform for movement tracking
**Reference**:
- `src/diagram/diagramMenuManager.ts:85-97` - Exit button creation
- `src/util/functions/groundMeshObserver.ts:127-222` - Component positioning
### Phase 9: Observable Integration
- [ ] Subscribe to `appConfigInstance.onConfigChangedObservable` in constructor
- [ ] Update all UI elements when config changes externally
- [ ] Ensure Observable cleanup in dispose() method
- [ ] Test config changes from both VR panel and 2D ConfigModal
**Pattern**:
```typescript
this._configObserver = appConfigInstance.onConfigChangedObservable.add((config) => {
// Update UI elements to reflect new config
this.updateLocationSnapUI(config.locationSnap);
this.updateRotationSnapUI(config.rotateSnap);
// ... etc
});
```
### Phase 10: Testing & Polish
- [ ] Test all toggle switches update config correctly
- [ ] Test all radio button selections update config correctly
- [ ] Verify config changes propagate to DiagramObjects (label mode, snap behavior)
- [ ] Test panel positioning in VR (comfortable viewing distance)
- [ ] Test panel grabbability via Handle
- [ ] Verify panel follows platform movement
- [ ] Test config persistence (localStorage)
- [ ] Test config synchronization between VR panel and 2D ConfigModal
- [ ] Add visual feedback for button clicks (color changes, animations)
- [ ] Ensure proper cleanup on panel disposal
- [ ] Test in both WebXR and desktop modes
## Code Patterns to Follow
### 1. Toggle Button Pattern
```typescript
const toggleButton = Button.CreateSimpleButton("toggle", "Enabled");
toggleButton.width = "200px";
toggleButton.height = "40px";
toggleButton.color = "white";
toggleButton.background = "green";
toggleButton.onPointerClickObservable.add(() => {
const newValue = !currentValue;
toggleButton.textBlock.text = newValue ? "Enabled" : "Disabled";
toggleButton.background = newValue ? "green" : "gray";
appConfigInstance.setSomeSetting(newValue);
});
```
### 2. RadioGroup Pattern
```typescript
const radioGroup = new SelectionPanel("snapValues");
const options = [
{ value: 0.01, label: "1cm" },
{ value: 0.1, label: "10cm" },
// ... more options
];
options.forEach(option => {
const radio = new RadioButton();
radio.width = "20px";
radio.height = "20px";
radio.isChecked = (option.value === currentValue);
radio.onIsCheckedChangedObservable.add((checked) => {
if (checked) {
appConfigInstance.setGridSnap(option.value);
}
});
// Add label next to radio button
});
```
### 3. Config Observer Pattern
```typescript
this._configObserver = appConfigInstance.onConfigChangedObservable.add((config) => {
this.updateUIFromConfig(config);
});
// In dispose():
if (this._configObserver) {
appConfigInstance.onConfigChangedObservable.remove(this._configObserver);
}
```
## Key Integration Points
### AppConfig Singleton
- Import: `import {appConfigInstance} from "../util/appConfig";`
- Read: `appConfigInstance.current.locationSnap`
- Write: `appConfigInstance.setGridSnap(0.1)`
- Subscribe: `appConfigInstance.onConfigChangedObservable.add(callback)`
### DiagramMenuManager
- Instantiate panel: `this._vrConfigPanel = new VRConfigPanel(this._scene);`
- Add button to toolbox: Follow exit button pattern in `setupExitButton()`
- Show panel: `this._vrConfigPanel.show();`
- Position panel: Follow pattern in `groundMeshObserver.ts:127-222`
### Handle Pattern
- Make panel grabbable by controllers
- Parent to platform for world movement
- Use `_handleMesh` as root for entire panel UI
## Reference Files
1. **src/menus/configMenu.ts** - Existing VR config implementation with ADT
2. **src/menus/inputTextView.ts** - Handle pattern and ADT setup
3. **src/react/pages/configModal.tsx** - UI structure and config sections
4. **src/util/appConfig.ts** - Config singleton and setter methods
5. **src/diagram/diagramMenuManager.ts** - Toolbox button creation
6. **src/util/functions/groundMeshObserver.ts** - Component positioning
## Success Criteria
- [ ] All 5 config sections implemented and functional
- [ ] Config changes in VR panel update appConfigInstance
- [ ] Config changes propagate to all DiagramObjects
- [ ] Panel is grabbable and repositionable
- [ ] Panel follows platform movement
- [ ] Config persists to localStorage
- [ ] Synchronized with 2D ConfigModal
- [ ] Comfortable viewing experience in VR
- [ ] No memory leaks (proper Observable cleanup)
## Notes
- Start hidden (only show when user clicks toolbox button)
- Position at ~0.5m in front of camera when opened
- Use Y-axis billboard mode to keep panel upright but allow rotation
- Consider adding "Close" button at bottom of panel
- Match color scheme with existing UI (myColor theme)
- Test with both left and right controller grabbing

View File

@ -1,138 +0,0 @@
# Naming Conventions
## Tool and Material Naming
This document describes the naming conventions used for tools, materials, and related entities in the immersive WebXR application.
## Material Naming
Materials follow a consistent naming pattern based on their color:
**Format:** `material-{color}`
**Where:**
- `{color}` is the hex string representation of the material's color (e.g., `#ff0000` for red)
**Examples:**
- `material-#ff0000` - Red material
- `material-#00ff00` - Green material
- `material-#222222` - Dark gray material
**Implementation:**
```typescript
const material = new StandardMaterial("material-" + color.toHexString(), scene);
```
**Location:** Materials are created in:
- `src/toolbox/functions/buildColor.ts` - For toolbox color swatches
- `src/diagram/functions/buildMeshFromDiagramEntity.ts` - Fallback material creation via `buildMissingMaterial()`
## Tool Mesh Naming
Tool meshes use a compound naming pattern that includes both the tool type and color:
**Format:** `tool-{toolId}`
**Where:**
- `{toolId}` = `{toolType}-{color}`
- `{toolType}` is a value from the `ToolType` enum (e.g., `BOX`, `SPHERE`, `CYLINDER`, `CONE`, `PLANE`, `PERSON`)
- `{color}` is the hex string representation of the tool's color
**Examples:**
- `tool-BOX-#ff0000` - Red box tool
- `tool-SPHERE-#00ff00` - Green sphere tool
- `tool-CYLINDER-#0000ff` - Blue cylinder tool
- `tool-PLANE-#ffff00` - Yellow plane tool
**Implementation:**
```typescript
function toolId(tool: ToolType, color: Color3) {
return tool + "-" + color.toHexString();
}
const newItem = await buildMesh(tool, `tool-${id}`, colorParent.getScene());
// For example: `tool-BOX-#ff0000`
```
**Location:** Tool meshes are created in `src/toolbox/functions/buildTool.ts`
## Tool Colors
The application uses 16 predefined colors for the toolbox:
```typescript
const colors: string[] = [
"#222222", "#8b4513", "#006400", "#778899", // Row 1: Dark gray, Brown, Dark green, Light slate gray
"#4b0082", "#ff0000", "#ffa500", "#ffff00", // Row 2: Indigo, Red, Orange, Yellow
"#00ff00", "#00ffff", "#0000ff", "#ff00ff", // Row 3: Green, Cyan, Blue, Magenta
"#1e90ff", "#98fb98", "#ffe4b5", "#ff69b4" // Row 4: Dodger blue, Pale green, Moccasin, Hot pink
]
```
## Tool Types
Available tool types from the `ToolType` enum:
- `BOX` - Cube mesh
- `SPHERE` - Sphere mesh
- `CYLINDER` - Cylinder mesh
- `CONE` - Cone mesh
- `PLANE` - Flat plane mesh
- `PERSON` - Person/avatar mesh
## Material Color Access
When accessing material colors, use this priority order to handle both current and legacy materials:
```typescript
// For StandardMaterial
const stdMat = material as StandardMaterial;
const materialColor = stdMat.emissiveColor || stdMat.diffuseColor;
// Current rendering uses emissiveColor
// Legacy materials may have diffuseColor instead
```
## Rendering Modes
Materials can be rendered in three different modes, affecting how color properties are used:
### 1. Lightmap with Lighting
- Uses `diffuseColor` + `lightmapTexture`
- `disableLighting = false`
- Most expensive performance-wise
- Provides lighting illusion with actual lighting calculations
### 2. Unlit with Emissive Texture (Default)
- Uses `emissiveColor` + `emissiveTexture` (lightmap)
- `disableLighting = true`
- Best balance of visual quality and performance
- Provides lighting illusion without lighting calculations
### 3. Flat Emissive
- Uses only `emissiveColor`
- `disableLighting = true`
- Best performance
- No lighting illusion, flat shading
## Instance Naming
Instanced meshes (created from tool templates) follow this pattern:
**Format:** `tool-instance-{toolId}`
**Example:**
```typescript
const instance = new InstancedMesh("tool-instance-" + id, newItem);
// For example: `tool-instance-BOX-#ff0000`
```
These instances share materials with their source mesh and are used for visual feedback before creating actual diagram entities.
## Related Files
- `src/toolbox/functions/buildTool.ts` - Tool mesh creation and naming
- `src/toolbox/functions/buildColor.ts` - Material creation and color management
- `src/diagram/functions/buildMeshFromDiagramEntity.ts` - Diagram entity instantiation
- `src/toolbox/types/toolType.ts` - ToolType enum definition
- `src/util/lightmapGenerator.ts` - Lightmap texture generation and caching
- `src/util/renderingMode.ts` - Rendering mode enum and labels

View File

@ -2,58 +2,95 @@
<html>
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<meta content="An immersive vr diagramming experience based using webxr version 0.0.8-14 (2024-12-29Z)"
name="description">
<meta content="width=device-width, initial-scale=1, height=device-height" name="viewport">
<!--<link href="/styles.css" rel="stylesheet"> -->
<link href="/assets/dasfad/favicon-32x32.png" rel="icon" sizes="32x32" type="image/png">
<link href="/assets/dasfad/favicon-16x16.png" rel="icon" sizes="16x16" type="image/png">
<link href="/assets/dasfad/favicon-96x96.png" rel="icon" sizes="96x96" type="image/png">
<link as="fetch" href="/node_modules/.vite/deps/HavokPhysics.wasm" rel="preload">
<title>DASFAD</title>
<!-- <link as="script" href="/newRelic.js" rel="preload">
<script defer src="/newRelic.js"></script> -->
<link href="/manifest.webmanifest" rel="manifest"/>
<!--<script src='/niceware.js'></script>-->
<title>Deep Diagram</title>
<style>
body {
}
.loader {
position: fixed;
left: 0px;
top: 0px;
width: 200px;
height: 200px;
display: flex;
justify-content: center;
align-content: center;
flex-direction: column;
z-index: -1;
/*noinspection CssUnknownTarget*/
background: url("/spinner.gif");
background-position: center;
background-repeat: no-repeat;
text-align: center;
}
#questLaunch {
position: fixed;
top: 30px;
right: 30px;
padding: 10px;
background: #000;
color: #fff;
font-size: 1.5em;
z-index: 100;
}
#download {
position: fixed;
z-index: 11;
width: 200px;
height: 20px;
position: absolute;
bottom: 50px;
left: 16px;
padding: 10px;
background: #000;
color: #fff;
}
</style>
<link as="script" href="/newRelic.js" rel="preload">
<script src="/newRelic.js"></script>
<meta content="width=device-width, initial-scale=1, height=device-height" name="viewport">
<meta content="An immersive vr diagramming experience based on a-frame and webxr" name="description">
<link href="/assets/favicon-16x16.png" rel=icon sizes="16x16" type="image/png">
<link href="/assets/favicon-32x32.png" rel=icon sizes="32x32" type="image/png">
<link href="/assets/favicon-96x96.png" rel=icon sizes="96x96" type="image/png">
<link href="/manifest.webmanifest" rel="manifest"/>
<script src='/niceware.js'></script>
</head>
<body>
<!--<div class="loader" id="loader">Loading...</div> -->
<div id="questLaunch"><a href="https://www.oculus.com/open_url/?url=https://www.deepdiagram.com/" target="_blank">Launch
On Quest</a>
</div>
<div id="download"><a href="#" id="downloadLink">Download Model</a></div>
<script>
/* if (typeof navigator.serviceWorker !== 'undefined') {
if (localStorage.getItem('serviceWorkerVersion') !== '11') {
caches.keys().then(cacheNames => {
cacheNames.forEach(cacheName => {
caches.delete(cacheName);
});
});
localStorage.setItem('serviceWorkerVersion', '11');
/*
var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition
var SpeechGrammarList = SpeechGrammarList || window.webkitSpeechGrammarList
var SpeechRecognitionEvent = SpeechRecognitionEvent || webkitSpeechRecognitionEvent
var recognition = new SpeechRecognition();
recognition.continuous = false;
recognition.lang = 'en-US';
recognition.interimResults = true;
recognition.maxAlternatives = 1;
recognition.onresult = function(event) {
console.log(event.results[0][0].transcript);
}
navigator.serviceWorker.register('/sw.js', {updateViaCache: 'none'});
recognition.onend = function() {
console.log("recognition ended");
recognition.start();
}
console.log("starting recognition");
recognition.start();
*/
</script>
<div class="webApp" id="webApp">
</div>
<script defer src="/src/webApp.ts" type="module"></script>
<!--<video id="feed" controls="" autoplay="" name="media"><source src="https://listen.broadcastify.com/1drb2xhywkg8nvz.mp3?nc=49099&amp;xan=xtf9912b41c" type="audio/mpeg"></video> -->
<!--
<div class="scene">
<canvas id="gameCanvas"></canvas>
</div>
-->
<!--<script defer src="/src/vrApp.ts" type="module"></script>-->
<script type="module" src="./src/app.ts"></script>
</body>
</html>

View File

@ -0,0 +1,49 @@
import {Handler, HandlerContext, HandlerEvent} from "@netlify/functions";
import axios from 'axios';
export const handler: Handler = async (event: HandlerEvent, context: HandlerContext) => {
try {
switch (event.httpMethod) {
case 'POST':
const apiKey = event.headers['api-key'];
const query = event.body;
const response = await axios.post('https://api.newrelic.com/graphql',
query,
{headers: {'Api-Key': apiKey, 'Content-Type': 'application/json'}});
const data = await response.data;
return {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': 'https://cameras.immersiveidea.com',
'Access-Control-Allow-Credentials': 'true'
},
statusCode: 200,
body: JSON.stringify(data)
}
break;
case 'OPTIONS':
const headers = {
'Access-Control-Allow-Origin': 'https://cameras.immersiveidea.com',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Headers': 'content-type, api-key',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE'
};
return {
statusCode: 204,
headers
}
break;
default:
return {
statusCode: 405,
body: 'Method Not Allowed'
}
}
} catch (error) {
console.log(error);
return {
statusCode: 500,
body: JSON.stringify(error)
}
}
};

View File

@ -0,0 +1,13 @@
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "Node",
"lib": [
"esnext"
],
"types": [
"@cloudflare/workers-types"
]
}
}

View File

@ -0,0 +1,22 @@
import {Handler, HandlerContext, HandlerEvent} from "@netlify/functions";
import axios from 'axios';
export const handler: Handler = async (event: HandlerEvent, context: HandlerContext) => {
try {
const response = await axios.post('https://api.assemblyai.com/v2/realtime/token', // use account token to get a temp user token
{expires_in: 3600}, // can set a TTL timer in seconds.
{headers: {authorization: process.env.VOICE_TOKEN}});
const data = await response.data;
return {
headers: {'Content-Type': 'application/json'},
statusCode: 200,
body: JSON.stringify(data)
}
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify(error)
}
}
};

View File

@ -1,48 +0,0 @@
'use strict'
// Load .env.local first (has the secrets), then .env as fallback
require('dotenv').config({ path: '.env.local' });
require('dotenv').config();
/**
* New Relic Node.js APM Configuration
*
* This file configures the New Relic agent for backend monitoring.
* Requires NEW_RELIC_LICENSE_KEY environment variable to be set.
*
* Distributed tracing is enabled to correlate with browser agent traces.
*/
exports.config = {
app_name: ['dasfad-backend'],
license_key: process.env.NEW_RELIC_LICENSE_KEY,
distributed_tracing: {
enabled: true
},
logging: {
level: 'info'
},
application_logging: {
enabled: true,
forwarding: {
enabled: true,
max_samples_stored: 10000
},
local_decorating: {
enabled: true
}
},
allow_all_headers: true,
attributes: {
exclude: [
'request.headers.cookie',
'request.headers.authorization',
'request.headers.proxyAuthorization',
'request.headers.setCookie*',
'request.headers.x*',
'response.headers.cookie',
'response.headers.authorization',
'response.headers.proxyAuthorization',
'response.headers.setCookie*',
'response.headers.x*'
]
}
}

9837
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,82 +1,48 @@
{
"name": "immersive",
"private": true,
"version": "0.0.8-48",
"version": "0.0.1",
"type": "module",
"license": "MIT",
"engines": {
"node": ">=18.0.0"
},
"scripts": {
"dev": "node -r newrelic server.js",
"test": "vitest",
"build": "node versionBump.js && vite build",
"start": "NODE_ENV=production node -r newrelic server.js",
"start:api": "API_ONLY=true node -r newrelic server.js",
"socket": "node server/server.js",
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"serve": "node server.js",
"serverBuild": "cd server && tsc",
"havok": "cp ./node_modules/@babylonjs/havok/lib/esm/HavokPhysics.wasm ./node_modules/.vite/deps"
},
"dependencies": {
"@auth0/auth0-react": "^2.2.4",
"@babylonjs/core": "^8.16.2",
"@babylonjs/gui": "^8.16.2",
"@babylonjs/havok": "1.3.4",
"@babylonjs/inspector": "^8.16.2",
"@babylonjs/loaders": "^8.16.2",
"@babylonjs/materials": "^8.16.2",
"@babylonjs/serializers": "^8.16.2",
"@emotion/react": "^11.13.0",
"@giphy/js-fetch-api": "^5.6.0",
"@giphy/react-components": "^9.6.0",
"@mantine/core": "^7.17.8",
"@mantine/form": "^7.17.8",
"@mantine/hooks": "^7.17.8",
"@maptiler/client": "1.8.1",
"@newrelic/browser-agent": "^1.306.0",
"@picovoice/cobra-web": "^2.0.3",
"@picovoice/eagle-web": "^1.0.0",
"@picovoice/web-voice-processor": "^4.0.9",
"@tabler/icons-react": "^3.14.0",
"@babylonjs/core": "^6.21.2",
"@babylonjs/gui": "^6.21.2",
"@babylonjs/havok": "1.1.4",
"@babylonjs/inspector": "^6.21.2",
"@babylonjs/loaders": "^6.21.2",
"@babylonjs/serializers": "^6.21.2",
"@cloudflare/workers-types": "^4.20230821.0",
"@netlify/functions": "^1.6.0",
"@typed-mxgraph/typed-mxgraph": "^1.0.8",
"@types/node": "^18.14.0",
"@types/react": "^18.2.72",
"@types/react-dom": "^18.2.22",
"axios": "^1.10.0",
"canvas-hypertxt": "1.0.3",
"cors": "^2.8.5",
"dotenv": "^17.2.3",
"events": "^3.3.0",
"express": "^5.2.1",
"express-pouchdb": "^4.2.0",
"hash-wasm": "4.11.0",
"dexie": "^3.2.4",
"dexie-observable": "^4.0.1-beta.13",
"earcut": "^2.2.4",
"hls.js": "^1.1.4",
"js-crypto-aes": "1.0.6",
"leveldown": "^6.1.1",
"loglevel": "^1.9.1",
"meaningful-string": "^1.4.0",
"newrelic": "^13.9.1",
"peer-lite": "2.0.2",
"pouchdb": "^8.0.1",
"pouchdb-adapter-leveldb": "^9.0.0",
"pouchdb-adapter-memory": "^9.0.0",
"pouchdb-find": "^8.0.1",
"loglevel": "^1.8.1",
"mxgraph": "^4.2.2",
"niceware": "^4.0.0",
"p2p-data-channel": "^1.10.7",
"query-string": "^8.1.0",
"react-router-dom": "^6.26.1",
"recordrtc": "^5.6.0",
"rfc4648": "^1.5.3",
"recordrtc": "^5.6.2",
"ring-client-api": "11.7.7",
"round": "^2.0.1",
"uint8-to-b64": "^1.0.2",
"use-pouchdb": "^2.0.2",
"uuid": "^9.0.1",
"vite-express": "^0.21.1",
"websocket": "^1.0.34",
"websocket-ts": "^2.1.5"
"uuid": "^9.0.0"
},
"devDependencies": {
"@types/dom-to-image": "^2.6.7",
"typescript": "^4.9.5",
"vite": "^5.2.9",
"vite-plugin-cp": "^1.0.0",
"vitest": "^1.4.0"
"vite": "^4.4.9",
"vite-plugin-api": "^0.1.11",
"vite-plugin-cp": "^1.0.0"
}
}

BIN
public/Big Dripper_1.wav Normal file

Binary file not shown.

View File

@ -1 +0,0 @@
/db/* /index.html 200

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

View File

@ -1,40 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="3200"
height="1355.480324331485" viewBox="0 0 3200 1355.480324331485">
<g transform="scale(10) translate(10, 10)">
<defs id="SvgjsDefs1385">
<linearGradient id="SvgjsLinearGradient1390">
<stop id="SvgjsStop1391" stop-color="#905e26" offset="0"></stop>
<stop id="SvgjsStop1392" stop-color="#f5ec9b" offset="0.5"></stop>
<stop id="SvgjsStop1393" stop-color="#905e26" offset="1"></stop>
</linearGradient>
<linearGradient id="SvgjsLinearGradient1394">
<stop id="SvgjsStop1395" stop-color="#905e26" offset="0"></stop>
<stop id="SvgjsStop1396" stop-color="#f5ec9b" offset="0.5"></stop>
<stop id="SvgjsStop1397" stop-color="#905e26" offset="1"></stop>
</linearGradient>
</defs>
<g id="SvgjsG1386" featureKey="aMgJeN-0"
transform="matrix(1.5610770874511997,0,0,1.5610770874511997,71.94613967240352,-53.841545411371435)"
fill="url(#SvgjsLinearGradient1390)">
<path xmlns="http://www.w3.org/2000/svg"
d="M29.399,57.112c0.615,0.308,1.077,0.846,1.077,1.383c0,1.039-1.038,1.961-1.999,1.462l-15.223-7.881 c-0.846-0.499-1.576-0.808-1.576-1.884c0-1.115,0.692-1.385,1.576-1.922l15.223-7.881c1.038-0.346,1.999,0.424,1.999,1.462 c0,0.575-0.461,1.114-1.077,1.423l-13.761,6.918L29.399,57.112z"></path>
<path xmlns="http://www.w3.org/2000/svg"
d="M29.033,60.209c-0.208,0-0.413-0.052-0.608-0.152l-15.223-7.881c-0.086-0.05-0.165-0.095-0.242-0.141 c-0.748-0.431-1.395-0.804-1.395-1.843c0-1.057,0.594-1.406,1.346-1.849c0.093-0.054,0.187-0.11,0.284-0.169l15.229-7.885 c0.195-0.066,0.377-0.097,0.558-0.097c0.9,0,1.606,0.728,1.606,1.658c0,0.587-0.437,1.172-1.139,1.522l-13.562,6.818l13.562,6.818 c0.691,0.346,1.139,0.93,1.139,1.484C30.588,59.407,29.861,60.209,29.033,60.209z M28.982,40.419c-0.156,0-0.314,0.026-0.47,0.078 L13.306,48.37c-0.091,0.057-0.188,0.113-0.281,0.167c-0.743,0.439-1.234,0.728-1.234,1.655c0,0.91,0.537,1.219,1.281,1.648 c0.079,0.045,0.158,0.09,0.239,0.139l15.217,7.877c0.162,0.084,0.332,0.127,0.504,0.127c0.697,0,1.33-0.709,1.33-1.488 c0-0.465-0.407-0.98-1.014-1.283l-13.962-7.02l13.962-7.02c0.616-0.308,1.014-0.828,1.014-1.321 C30.363,41.048,29.756,40.419,28.982,40.419z"></path>
<path xmlns="http://www.w3.org/2000/svg"
d="M46.385,64.416c-0.231,0.691-0.922,1.077-1.614,0.961c-0.769-0.153-1.269-0.885-1.154-1.692 c0-0.076,0.039-0.191,0.077-0.307l9.88-27.831c0.23-0.692,0.922-1.038,1.614-0.923c0.73,0.154,1.269,0.885,1.153,1.652 c0,0.078-0.039,0.193-0.077,0.27L46.385,64.416z"></path>
<path xmlns="http://www.w3.org/2000/svg"
d="M45.016,65.511c-0.088,0-0.177-0.008-0.263-0.022c-0.837-0.167-1.371-0.949-1.247-1.819 c-0.001-0.076,0.038-0.193,0.079-0.318l9.883-27.842c0.207-0.618,0.778-1.02,1.457-1.02c0.094,0,0.188,0.009,0.281,0.023 c0.812,0.172,1.369,0.97,1.247,1.781c0.001,0.086-0.047,0.22-0.087,0.302l-9.875,27.856C46.281,65.084,45.688,65.511,45.016,65.511z M54.925,34.715c-0.58,0-1.068,0.34-1.244,0.867l-9.88,27.833c-0.035,0.104-0.07,0.213-0.07,0.27 c-0.108,0.767,0.349,1.439,1.062,1.582c0.071,0.012,0.147,0.018,0.223,0.018c0.575,0,1.083-0.363,1.263-0.904l9.881-27.872 c0.041-0.085,0.07-0.182,0.07-0.231c0.105-0.712-0.373-1.396-1.064-1.543C55.089,34.722,55.007,34.715,54.925,34.715z"></path>
<path xmlns="http://www.w3.org/2000/svg"
d="M84.362,50.192L70.6,43.274c-0.614-0.309-1.075-0.848-1.075-1.423c0-1.038,1.037-1.962,1.998-1.462l15.223,7.881 c0.885,0.537,1.576,0.807,1.576,1.922c0,1.076-0.73,1.385-1.576,1.884l-15.223,7.881c-0.961,0.499-1.998-0.423-1.998-1.462 c0-0.537,0.461-1.075,1.075-1.383L84.362,50.192z"></path>
<path xmlns="http://www.w3.org/2000/svg"
d="M70.967,60.209c-0.828,0-1.556-0.802-1.556-1.714c0-0.555,0.447-1.139,1.139-1.484l13.562-6.818L70.55,43.374 c-0.702-0.352-1.139-0.936-1.139-1.522c0-0.913,0.728-1.714,1.556-1.714c0.209,0,0.413,0.051,0.608,0.152l15.223,7.881 c0.104,0.062,0.198,0.119,0.29,0.173c0.753,0.442,1.347,0.792,1.347,1.849c0,1.039-0.646,1.412-1.395,1.843 c-0.078,0.046-0.157,0.091-0.237,0.138l-15.228,7.884C71.38,60.157,71.176,60.209,70.967,60.209z M70.967,40.363 c-0.696,0-1.33,0.709-1.33,1.488c0,0.493,0.397,1.013,1.014,1.321l13.962,7.02l-13.962,7.02c-0.606,0.305-1.014,0.82-1.014,1.283 c0,0.779,0.634,1.488,1.33,1.488c0.172,0,0.342-0.043,0.504-0.127l15.223-7.88c0.075-0.046,0.155-0.091,0.233-0.136 c0.744-0.43,1.282-0.738,1.282-1.648c0-0.928-0.491-1.216-1.235-1.655c-0.093-0.054-0.188-0.11-0.287-0.17l-15.216-7.876 C71.309,40.405,71.139,40.363,70.967,40.363z"></path>
</g>
<g id="SvgjsG1387" featureKey="8L6ael-0"
transform="matrix(3.168568052463937,0,0,3.168568052463937,-5.1330821487142195,52.17667742743372)"
fill="url(#SvgjsLinearGradient1394)">
<path d="M10.56 5.52 q1.22 0.46 2.2 1.48 q2.1 2.12 2.1 5.41 t-2.1 5.43 q-0.98 1.02 -2.2 1.48 q-1.26 0.52 -2.58 0.52 l-5.66 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.49 l0 -1.44 q0 -0.3 0.21 -0.51 t0.49 -0.21 l5.6 0 q1.78 0 2.89 -1.3 t1.11 -3.26 t-1.11 -3.26 t-2.89 -1.3 l-5.6 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.51 l0 -1.44 q0 -0.28 0.21 -0.49 t0.49 -0.21 l5.66 0 q1.32 0 2.58 0.52 z M32.208 18.86 q0.14 0.32 -0.07 0.65 t-0.57 0.33 l-13.32 0 q-0.18 0 -0.34 -0.09 t-0.24 -0.23 q-0.22 -0.32 -0.06 -0.66 l0.62 -1.46 q0.08 -0.2 0.26 -0.32 t0.38 -0.12 l9.32 0 l-3.28 -7.84 l-2.68 6.4 q-0.08 0.2 -0.25 0.31 t-0.39 0.11 l-1.68 0 q-0.38 0 -0.6 -0.32 q-0.08 -0.14 -0.1 -0.32 t0.04 -0.34 l4.06 -9.52 q0.08 -0.2 0.25 -0.32 t0.39 -0.12 l1.92 0 q0.22 0 0.39 0.12 t0.25 0.32 z M45.535999999999994 12.42 q0.86 0.54 1.31 1.32 t0.45 1.74 q0 2.26 -1.72 3.46 q-1.16 0.84 -3.14 1.06 l-0.08 0 q-0.28 0 -0.46 -0.18 q-0.24 -0.22 -0.24 -0.52 l0 -1.44 q0 -0.26 0.18 -0.46 t0.44 -0.24 q0.94 -0.1 1.46 -0.44 q0.4 -0.24 0.54 -0.62 q0.08 -0.22 0.08 -0.56 q0 -0.22 -0.08 -0.38 t-0.28 -0.3 q-0.58 -0.4 -1.5 -0.68 l-0.32 -0.1 q-1 -0.28 -1.84 -0.46 q-0.18 -0.04 -0.58 -0.14 l-0.22 -0.06 q-0.72 -0.18 -1.52 -0.5 q-1.18 -0.5 -1.94 -1.26 q-0.88 -0.88 -0.88 -2.32 q0 -1.98 1.52 -3.22 q1.04 -0.88 2.92 -1.12 q0.32 -0.04 0.55 0.18 t0.23 0.52 l0 1.44 q0 0.26 -0.16 0.46 t-0.41 0.23 t-0.51 0.11 q-0.58 0.22 -0.82 0.43 t-0.34 0.43 q-0.1 0.34 -0.1 0.64 q0 0.16 0.18 0.34 q0.28 0.28 0.82 0.5 q0.24 0.1 0.84 0.3 l2.5 0.62 l0.12 0.04 q0.94 0.26 1.36 0.4 q0.94 0.32 1.64 0.78 z M42.196 7.9 q-0.24 -0.06 -0.39 -0.25 t-0.15 -0.45 l0 -1.46 q0 -0.32 0.26 -0.54 q0.1 -0.1 0.26 -0.13 t0.3 -0.01 q1.76 0.28 2.86 1.2 q1.5 1.24 1.6 3.16 q0.02 0.28 -0.19 0.51 t-0.51 0.23 l-1.56 0 q-0.26 0 -0.46 -0.18 t-0.22 -0.44 q-0.08 -0.52 -0.34 -0.86 q-0.42 -0.5 -1.3 -0.76 q-0.06 0 -0.08 -0.02 l-0.08 0 z M39.855999999999995 17.08 q0.24 0.04 0.4 0.24 t0.16 0.44 l0 1.48 q0 0.32 -0.24 0.54 q-0.2 0.16 -0.46 0.16 l-0.1 0 q-1.86 -0.28 -3.06 -1.22 q-1.56 -1.24 -1.76 -3.46 q-0.04 -0.32 0.18 -0.55 t0.52 -0.23 l1.58 0 q0.28 0 0.48 0.19 t0.22 0.47 q0.06 1 0.98 1.54 q0.42 0.24 1.1 0.4 z M60.88399999999999 11.12 q0.3 0 0.51 0.21 t0.21 0.51 l0 1.48 q0 0.28 -0.21 0.49 t-0.51 0.21 l-6.58 0 l0 5.12 q0 0.28 -0.2 0.49 t-0.5 0.21 l-1.52 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.49 l0 -7.3 q0 -0.3 0.21 -0.51 t0.49 -0.21 l8.8 0 z M61.78399999999999 5 q0.28 0 0.49 0.21 t0.21 0.49 l0 1.46 q0 0.3 -0.21 0.51 t-0.49 0.21 l-9.7 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.51 l0 -1.46 q0 -0.28 0.21 -0.49 t0.49 -0.21 l9.7 0 z M79.512 18.86 q0.14 0.32 -0.07 0.65 t-0.57 0.33 l-13.32 0 q-0.18 0 -0.34 -0.09 t-0.24 -0.23 q-0.22 -0.32 -0.06 -0.66 l0.62 -1.46 q0.08 -0.2 0.26 -0.32 t0.38 -0.12 l9.32 0 l-3.28 -7.84 l-2.68 6.4 q-0.08 0.2 -0.25 0.31 t-0.39 0.11 l-1.68 0 q-0.38 0 -0.6 -0.32 q-0.08 -0.14 -0.1 -0.32 t0.04 -0.34 l4.06 -9.52 q0.08 -0.2 0.25 -0.32 t0.39 -0.12 l1.92 0 q0.22 0 0.39 0.12 t0.25 0.32 z M92 5.52 q1.22 0.46 2.2 1.48 q2.1 2.12 2.1 5.41 t-2.1 5.43 q-0.98 1.02 -2.2 1.48 q-1.26 0.52 -2.58 0.52 l-5.66 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.49 l0 -1.44 q0 -0.3 0.21 -0.51 t0.49 -0.21 l5.6 0 q1.78 0 2.89 -1.3 t1.11 -3.26 t-1.11 -3.26 t-2.89 -1.3 l-5.6 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.51 l0 -1.44 q0 -0.28 0.21 -0.49 t0.49 -0.21 l5.66 0 q1.32 0 2.58 0.52 z"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

View File

@ -1,912 +0,0 @@
%!PS-Adobe-3.0 EPSF-3.0
%Produced by poppler pdftops version: 22.05.0 (http://poppler.freedesktop.org)
%%Creator: Chromium
%%LanguageLevel: 3
%%DocumentSuppliedResources: (atend)
%%BoundingBox: 0 0 2400 1018
%%HiResBoundingBox: 0 0 2400 1017.12
%%DocumentSuppliedResources: (atend)
%%EndComments
%%BeginProlog
%%BeginResource: procset xpdf 3.00 0
%%Copyright: Copyright 1996-2011, 2022 Glyph & Cog, LLC
/xpdf 75 dict def xpdf begin
% PDF special state
/pdfDictSize 15 def
/pdfSetup {
/setpagedevice where {
pop 2 dict begin
/Policies 1 dict dup begin /PageSize 6 def end def
{ /Duplex true def } if
currentdict end setpagedevice
} {
pop
} ifelse
} def
/pdfSetupPaper {
% Change paper size, but only if different from previous paper size otherwise
% duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size
% so we use the same when checking if the size changes.
/setpagedevice where {
pop currentpagedevice
/PageSize known {
2 copy
currentpagedevice /PageSize get aload pop
exch 4 1 roll
sub abs 5 gt
3 1 roll
sub abs 5 gt
or
} {
true
} ifelse
{
2 array astore
2 dict begin
/PageSize exch def
/ImagingBBox null def
currentdict end
setpagedevice
} {
pop pop
} ifelse
} {
pop
} ifelse
} def
/pdfStartPage {
pdfDictSize dict begin
/pdfFillCS [] def
/pdfFillXform {} def
/pdfStrokeCS [] def
/pdfStrokeXform {} def
/pdfFill [0] def
/pdfStroke [0] def
/pdfFillOP false def
/pdfStrokeOP false def
/pdfOPM false def
/pdfLastFill false def
/pdfLastStroke false def
/pdfTextMat [1 0 0 1 0 0] def
/pdfFontSize 0 def
/pdfCharSpacing 0 def
/pdfTextRender 0 def
/pdfPatternCS false def
/pdfTextRise 0 def
/pdfWordSpacing 0 def
/pdfHorizScaling 1 def
/pdfTextClipPath [] def
} def
/pdfEndPage { end } def
% PDF color state
/opm { dup /pdfOPM exch def
/setoverprintmode where{pop setoverprintmode}{pop}ifelse } def
/cs { /pdfFillXform exch def dup /pdfFillCS exch def
setcolorspace } def
/CS { /pdfStrokeXform exch def dup /pdfStrokeCS exch def
setcolorspace } def
/sc { pdfLastFill not { pdfFillCS setcolorspace } if
dup /pdfFill exch def aload pop pdfFillXform setcolor
/pdfLastFill true def /pdfLastStroke false def } def
/SC { pdfLastStroke not { pdfStrokeCS setcolorspace } if
dup /pdfStroke exch def aload pop pdfStrokeXform setcolor
/pdfLastStroke true def /pdfLastFill false def } def
/op { /pdfFillOP exch def
pdfLastFill { pdfFillOP setoverprint } if } def
/OP { /pdfStrokeOP exch def
pdfLastStroke { pdfStrokeOP setoverprint } if } def
/fCol {
pdfLastFill not {
pdfFillCS setcolorspace
pdfFill aload pop pdfFillXform setcolor
pdfFillOP setoverprint
/pdfLastFill true def /pdfLastStroke false def
} if
} def
/sCol {
pdfLastStroke not {
pdfStrokeCS setcolorspace
pdfStroke aload pop pdfStrokeXform setcolor
pdfStrokeOP setoverprint
/pdfLastStroke true def /pdfLastFill false def
} if
} def
% build a font
/pdfMakeFont {
4 3 roll findfont
4 2 roll matrix scale makefont
dup length dict begin
{ 1 index /FID ne { def } { pop pop } ifelse } forall
/Encoding exch def
currentdict
end
definefont pop
} def
/pdfMakeFont16 {
exch findfont
dup length dict begin
{ 1 index /FID ne { def } { pop pop } ifelse } forall
/WMode exch def
currentdict
end
definefont pop
} def
/pdfMakeFont16L3 {
1 index /CIDFont resourcestatus {
pop pop 1 index /CIDFont findresource /CIDFontType known
} {
false
} ifelse
{
0 eq { /Identity-H } { /Identity-V } ifelse
exch 1 array astore composefont pop
} {
pdfMakeFont16
} ifelse
} def
% graphics state operators
/q { gsave pdfDictSize dict begin } def
/Q {
end grestore
/pdfLastFill where {
pop
pdfLastFill {
pdfFillOP setoverprint
} {
pdfStrokeOP setoverprint
} ifelse
} if
/pdfOPM where {
pop
pdfOPM /setoverprintmode where{pop setoverprintmode}{pop}ifelse
} if
} def
/cm { concat } def
/d { setdash } def
/i { setflat } def
/j { setlinejoin } def
/J { setlinecap } def
/M { setmiterlimit } def
/w { setlinewidth } def
% path segment operators
/m { moveto } def
/l { lineto } def
/c { curveto } def
/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto
neg 0 rlineto closepath } def
/h { closepath } def
% path painting operators
/S { sCol stroke } def
/Sf { fCol stroke } def
/f { fCol fill } def
/f* { fCol eofill } def
% clipping operators
/W { clip newpath } def
/W* { eoclip newpath } def
/Ws { strokepath clip newpath } def
% text state operators
/Tc { /pdfCharSpacing exch def } def
/Tf { dup /pdfFontSize exch def
dup pdfHorizScaling mul exch matrix scale
pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put
exch findfont exch makefont setfont } def
/Tr { /pdfTextRender exch def } def
/Tp { /pdfPatternCS exch def } def
/Ts { /pdfTextRise exch def } def
/Tw { /pdfWordSpacing exch def } def
/Tz { /pdfHorizScaling exch def } def
% text positioning operators
/Td { pdfTextMat transform moveto } def
/Tm { /pdfTextMat exch def } def
% text string operators
/xyshow where {
pop
/xyshow2 {
dup length array
0 2 2 index length 1 sub {
2 index 1 index 2 copy get 3 1 roll 1 add get
pdfTextMat dtransform
4 2 roll 2 copy 6 5 roll put 1 add 3 1 roll dup 4 2 roll put
} for
exch pop
xyshow
} def
}{
/xyshow2 {
currentfont /FontType get 0 eq {
0 2 3 index length 1 sub {
currentpoint 4 index 3 index 2 getinterval show moveto
2 copy get 2 index 3 2 roll 1 add get
pdfTextMat dtransform rmoveto
} for
} {
0 1 3 index length 1 sub {
currentpoint 4 index 3 index 1 getinterval show moveto
2 copy 2 mul get 2 index 3 2 roll 2 mul 1 add get
pdfTextMat dtransform rmoveto
} for
} ifelse
pop pop
} def
} ifelse
/cshow where {
pop
/xycp {
0 3 2 roll
{
pop pop currentpoint 3 2 roll
1 string dup 0 4 3 roll put false charpath moveto
2 copy get 2 index 2 index 1 add get
pdfTextMat dtransform rmoveto
2 add
} exch cshow
pop pop
} def
}{
/xycp {
currentfont /FontType get 0 eq {
0 2 3 index length 1 sub {
currentpoint 4 index 3 index 2 getinterval false charpath moveto
2 copy get 2 index 3 2 roll 1 add get
pdfTextMat dtransform rmoveto
} for
} {
0 1 3 index length 1 sub {
currentpoint 4 index 3 index 1 getinterval false charpath moveto
2 copy 2 mul get 2 index 3 2 roll 2 mul 1 add get
pdfTextMat dtransform rmoveto
} for
} ifelse
pop pop
} def
} ifelse
/Tj {
fCol
0 pdfTextRise pdfTextMat dtransform rmoveto
currentpoint 4 2 roll
pdfTextRender 1 and 0 eq {
2 copy xyshow2
} if
pdfTextRender 3 and dup 1 eq exch 2 eq or {
3 index 3 index moveto
2 copy
currentfont /FontType get 3 eq { fCol } { sCol } ifelse
xycp currentpoint stroke moveto
} if
pdfTextRender 4 and 0 ne {
4 2 roll moveto xycp
/pdfTextClipPath [ pdfTextClipPath aload pop
{/moveto cvx}
{/lineto cvx}
{/curveto cvx}
{/closepath cvx}
pathforall ] def
currentpoint newpath moveto
} {
pop pop pop pop
} ifelse
0 pdfTextRise neg pdfTextMat dtransform rmoveto
} def
/TJm { 0.001 mul pdfFontSize mul pdfHorizScaling mul neg 0
pdfTextMat dtransform rmoveto } def
/TJmV { 0.001 mul pdfFontSize mul neg 0 exch
pdfTextMat dtransform rmoveto } def
/Tclip { pdfTextClipPath cvx exec clip newpath
/pdfTextClipPath [] def } def
/Tclip* { pdfTextClipPath cvx exec eoclip newpath
/pdfTextClipPath [] def } def
% Level 2/3 image operators
/pdfImBuf 100 string def
/pdfImStr {
2 copy exch length lt {
2 copy get exch 1 add exch
} {
()
} ifelse
} def
/skipEOD {
{ currentfile pdfImBuf readline
not { pop exit } if
(%-EOD-) eq { exit } if } loop
} def
/pdfIm { image skipEOD } def
/pdfMask {
/ReusableStreamDecode filter
skipEOD
/maskStream exch def
} def
/pdfMaskEnd { maskStream closefile } def
/pdfMaskInit {
/maskArray exch def
/maskIdx 0 def
} def
/pdfMaskSrc {
maskIdx maskArray length lt {
maskArray maskIdx get
/maskIdx maskIdx 1 add def
} {
()
} ifelse
} def
/pdfImM { fCol imagemask skipEOD } def
/pr { 2 index 2 index 3 2 roll putinterval 4 add } def
/pdfImClip {
gsave
0 2 4 index length 1 sub {
dup 4 index exch 2 copy
get 5 index div put
1 add 3 index exch 2 copy
get 3 index div put
} for
pop pop rectclip
} def
/pdfImClipEnd { grestore } def
% shading operators
/colordelta {
false 0 1 3 index length 1 sub {
dup 4 index exch get 3 index 3 2 roll get sub abs 0.004 gt {
pop true
} if
} for
exch pop exch pop
} def
/funcCol { func n array astore } def
/funcSH {
dup 0 eq {
true
} {
dup 6 eq {
false
} {
4 index 4 index funcCol dup
6 index 4 index funcCol dup
3 1 roll colordelta 3 1 roll
5 index 5 index funcCol dup
3 1 roll colordelta 3 1 roll
6 index 8 index funcCol dup
3 1 roll colordelta 3 1 roll
colordelta or or or
} ifelse
} ifelse
{
1 add
4 index 3 index add 0.5 mul exch 4 index 3 index add 0.5 mul exch
6 index 6 index 4 index 4 index 4 index funcSH
2 index 6 index 6 index 4 index 4 index funcSH
6 index 2 index 4 index 6 index 4 index funcSH
5 3 roll 3 2 roll funcSH pop pop
} {
pop 3 index 2 index add 0.5 mul 3 index 2 index add 0.5 mul
funcCol sc
dup 4 index exch mat transform m
3 index 3 index mat transform l
1 index 3 index mat transform l
mat transform l pop pop h f*
} ifelse
} def
/axialCol {
dup 0 lt {
pop t0
} {
dup 1 gt {
pop t1
} {
dt mul t0 add
} ifelse
} ifelse
func n array astore
} def
/axialSH {
dup 0 eq {
true
} {
dup 8 eq {
false
} {
2 index axialCol 2 index axialCol colordelta
} ifelse
} ifelse
{
1 add 3 1 roll 2 copy add 0.5 mul
dup 4 3 roll exch 4 index axialSH
exch 3 2 roll axialSH
} {
pop 2 copy add 0.5 mul
axialCol sc
exch dup dx mul x0 add exch dy mul y0 add
3 2 roll dup dx mul x0 add exch dy mul y0 add
dx abs dy abs ge {
2 copy yMin sub dy mul dx div add yMin m
yMax sub dy mul dx div add yMax l
2 copy yMax sub dy mul dx div add yMax l
yMin sub dy mul dx div add yMin l
h f*
} {
exch 2 copy xMin sub dx mul dy div add xMin exch m
xMax sub dx mul dy div add xMax exch l
exch 2 copy xMax sub dx mul dy div add xMax exch l
xMin sub dx mul dy div add xMin exch l
h f*
} ifelse
} ifelse
} def
/radialCol {
dup t0 lt {
pop t0
} {
dup t1 gt {
pop t1
} if
} ifelse
func n array astore
} def
/radialSH {
dup 0 eq {
true
} {
dup 8 eq {
false
} {
2 index dt mul t0 add radialCol
2 index dt mul t0 add radialCol colordelta
} ifelse
} ifelse
{
1 add 3 1 roll 2 copy add 0.5 mul
dup 4 3 roll exch 4 index radialSH
exch 3 2 roll radialSH
} {
pop 2 copy add 0.5 mul dt mul t0 add
radialCol sc
encl {
exch dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add
0 360 arc h
dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add
360 0 arcn h f
} {
2 copy
dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add
a1 a2 arcn
dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add
a2 a1 arcn h
dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add
a1 a2 arc
dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add
a2 a1 arc h f
} ifelse
} ifelse
} def
end
%%EndResource
/CIDInit /ProcSet findresource begin
10 dict begin
begincmap
/CMapType 1 def
/CMapName /Identity-H def
/CIDSystemInfo 3 dict dup begin
/Registry (Adobe) def
/Ordering (Identity) def
/Supplement 0 def
end def
1 begincodespacerange
<0000> <ffff>
endcodespacerange
0 usefont
1 begincidrange
<0000> <ffff> 0
endcidrange
endcmap
currentdict CMapName exch /CMap defineresource pop
end
10 dict begin
begincmap
/CMapType 1 def
/CMapName /Identity-V def
/CIDSystemInfo 3 dict dup begin
/Registry (Adobe) def
/Ordering (Identity) def
/Supplement 0 def
end def
/WMode 1 def
1 begincodespacerange
<0000> <ffff>
endcodespacerange
0 usefont
1 begincidrange
<0000> <ffff> 0
endcidrange
endcmap
currentdict CMapName exch /CMap defineresource pop
end
end
%%EndProlog
%%BeginSetup
xpdf begin
%%EndSetup
pdfStartPage
%%EndPageSetup
[] 0 d
1 i
0 j
0 J
10 M
1 w
/DeviceGray {} cs
[0] sc
/DeviceGray {} CS
[0] SC
false op
false OP
{} settransfer
0 0 2400 1017.12 re
W
q
[0.24 0 0 -0.24 0 1017.12] cm
q
0 0 10000 4234.375 re
W*
q
[48.783241 0 0 48.766369 2560.8376 -1369.56274] cm
29.399 57.112 m
30.014 57.419998 30.476 57.958 30.476 58.494999 c
30.476 59.534 29.438 60.455997 28.476999 59.957001 c
13.254 52.076 l
12.408 51.577 11.678 51.268002 11.678 50.192001 c
11.678 49.077 12.37 48.807003 13.254 48.27 c
28.476999 40.389 l
29.514999 40.042999 30.476 40.813 30.476 41.851002 c
30.476 42.426003 30.014999 42.965 29.399 43.274002 c
15.638 50.192001 l
29.399 57.112 l
h
f
29.033001 60.209 m
28.825001 60.209 28.620001 60.157001 28.425001 60.056999 c
13.202002 52.175999 l
13.116001 52.125999 13.037002 52.080997 12.960002 52.035 c
12.212002 51.604 11.565002 51.230999 11.565002 50.192001 c
11.565002 49.135002 12.159002 48.786003 12.911002 48.343002 c
13.004003 48.289001 13.098002 48.233002 13.195003 48.174004 c
28.424004 40.289001 l
28.619003 40.223 28.801004 40.192001 28.982004 40.192001 c
29.882004 40.192001 30.588005 40.920002 30.588005 41.850002 c
30.588005 42.437004 30.151005 43.022003 29.449005 43.372002 c
15.887005 50.190002 l
29.449005 57.008003 l
30.140005 57.354004 30.588005 57.938004 30.588005 58.492004 c
30.587999 59.407001 29.861 60.209 29.033001 60.209 c
h
28.982 40.418999 m
28.826 40.418999 28.668001 40.445 28.512001 40.496998 c
13.306 48.369999 l
13.215 48.426998 13.118 48.482998 13.025 48.536999 c
12.282 48.975998 11.790999 49.264999 11.790999 50.191998 c
11.790999 51.101997 12.327999 51.410999 13.072 51.839996 c
13.151 51.884995 13.23 51.929996 13.311 51.978996 c
28.528 59.855995 l
28.690001 59.939995 28.860001 59.982994 29.032 59.982994 c
29.729 59.982994 30.362 59.273994 30.362 58.494995 c
30.362 58.029995 29.955 57.514996 29.348 57.211994 c
15.386 50.191994 l
29.348 43.171993 l
29.963999 42.863995 30.362 42.343994 30.362 41.850994 c
30.363001 41.048 29.756001 40.418999 28.982 40.418999 c
h
f
46.384998 64.416 m
46.153999 65.107002 45.462997 65.493004 44.771 65.376999 c
44.001999 65.223999 43.501999 64.491997 43.617001 63.684998 c
43.617001 63.608997 43.656002 63.493996 43.694 63.377998 c
53.574001 35.546997 l
53.804001 34.854996 54.496002 34.508999 55.188 34.623997 c
55.917999 34.777996 56.457001 35.508995 56.341 36.275997 c
56.341 36.353996 56.301998 36.468998 56.264 36.545998 c
46.384998 64.416 l
h
f
45.015999 65.511002 m
44.927998 65.511002 44.839001 65.502998 44.752998 65.488998 c
43.915997 65.321999 43.382 64.540001 43.505997 63.669998 c
43.504997 63.593998 43.543995 63.476997 43.584995 63.351997 c
53.467995 35.509998 l
53.674995 34.891998 54.245995 34.489998 54.924995 34.489998 c
55.018997 34.489998 55.112995 34.498997 55.205994 34.512997 c
56.017994 34.684998 56.574993 35.482998 56.452995 36.293995 c
56.453995 36.379993 56.405994 36.513996 56.365993 36.595993 c
46.490993 64.451996 l
46.280998 65.084 45.688 65.511002 45.015999 65.511002 c
h
54.924999 34.715 m
54.344997 34.715 53.856998 35.055 53.681 35.582001 c
43.800999 63.415001 l
43.765999 63.519001 43.730999 63.628002 43.730999 63.685001 c
43.622997 64.452003 44.079998 65.124001 44.792999 65.266998 c
44.863998 65.278999 44.939999 65.284996 45.015999 65.284996 c
45.591 65.284996 46.098999 64.921997 46.278999 64.380997 c
56.16 36.508995 l
56.201 36.423996 56.23 36.326996 56.23 36.277996 c
56.334999 35.565994 55.856998 34.881996 55.166 34.734997 c
55.089001 34.722 55.007 34.715 54.924999 34.715 c
h
f
84.362 50.192001 m
70.599998 43.273998 l
69.986 42.964996 69.525002 42.425999 69.525002 41.850998 c
69.525002 40.813 70.562004 39.888996 71.523003 40.388996 c
86.746002 48.269997 l
87.631004 48.806995 88.321999 49.076996 88.321999 50.191998 c
88.321999 51.267998 87.591995 51.576996 86.746002 52.075996 c
71.523003 59.956997 l
70.562004 60.455997 69.525002 59.533997 69.525002 58.494995 c
69.525002 57.957996 69.986 57.419994 70.599998 57.111996 c
84.362 50.192001 l
h
f
70.967003 60.209 m
70.139 60.209 69.411003 59.407001 69.411003 58.494999 c
69.411003 57.939999 69.858002 57.355999 70.550003 57.010998 c
84.112 50.192997 l
70.550003 43.374001 l
69.848 43.021999 69.411003 42.438 69.411003 41.852001 c
69.411003 40.939003 70.139 40.138 70.967003 40.138 c
71.176003 40.138 71.380005 40.188999 71.575005 40.290001 c
86.798004 48.171001 l
86.902 48.233002 86.996002 48.290001 87.088005 48.344002 c
87.841003 48.786003 88.435005 49.136002 88.435005 50.193001 c
88.435005 51.232002 87.789001 51.605 87.040009 52.035999 c
86.962006 52.082001 86.883011 52.126999 86.803009 52.174 c
71.575012 60.057999 l
71.379997 60.157001 71.176003 60.209 70.967003 60.209 c
h
70.967003 40.362999 m
70.271004 40.362999 69.637001 41.071999 69.637001 41.850998 c
69.637001 42.343998 70.034004 42.863998 70.651001 43.171997 c
84.612999 50.191998 l
70.651001 57.211998 l
70.044998 57.516998 69.637001 58.031998 69.637001 58.494999 c
69.637001 59.273998 70.271004 59.982998 70.967003 59.982998 c
71.139 59.982998 71.309006 59.939999 71.471001 59.855999 c
86.694 51.975998 l
86.768997 51.929996 86.848999 51.884998 86.927002 51.839996 c
87.671005 51.409996 88.209 51.101997 88.209 50.191998 c
88.209 49.263996 87.718002 48.975998 86.973999 48.536999 c
86.880997 48.482998 86.785995 48.426998 86.686996 48.367001 c
71.470993 40.491001 l
71.308998 40.404999 71.139 40.362999 70.967003 40.362999 c
h
f
Q
q
[99.016907 0 0 98.982658 152.13266 1942.3326] cm
10.56 5.52 m
11.373334 5.826667 12.106668 6.32 12.76 7 c
14.160001 8.413333 14.860001 10.216666 14.860001 12.41 c
14.860001 14.603334 14.160001 16.413334 12.76 17.84 c
12.106668 18.52 11.373334 19.013334 10.56 19.32 c
9.72 19.666666 8.860001 19.84 7.980001 19.84 c
2.320001 19.84 l
2.133334 19.84 1.970001 19.77 1.830001 19.630001 c
1.690001 19.490002 1.620001 19.326668 1.620001 19.140001 c
1.620001 17.700001 l
1.620001 17.500002 1.690001 17.330002 1.830001 17.190001 c
1.970001 17.049999 2.133334 16.98 2.320001 16.980001 c
7.920001 16.980001 l
9.106668 16.980001 10.070001 16.546669 10.81 15.680001 c
11.55 14.813335 11.92 13.726667 11.92 12.420001 c
11.92 11.113335 11.55 10.026668 10.81 9.160001 c
10.070001 8.293334 9.106668 7.860001 7.920001 7.860001 c
2.320001 7.860001 l
2.133334 7.860001 1.970001 7.79 1.830001 7.650001 c
1.690001 7.510001 1.620001 7.340001 1.620001 7.14 c
1.620001 5.7 l
1.620001 5.513333 1.690001 5.35 1.830001 5.21 c
1.970001 5.07 2.133334 5 2.320001 5 c
7.980001 5 l
8.860001 5 9.72 5.173333 10.56 5.52 c
h
32.208 18.860001 m
32.301334 19.073334 32.278 19.290001 32.138 19.51 c
31.998001 19.73 31.808001 19.84 31.568001 19.84 c
18.248001 19.84 l
18.128 19.84 18.014668 19.809999 17.908001 19.75 c
17.801334 19.690001 17.721334 19.613333 17.668001 19.52 c
17.521336 19.306667 17.501335 19.086668 17.608002 18.860001 c
18.228003 17.400002 l
18.281336 17.266668 18.368002 17.160002 18.488003 17.080002 c
18.608004 17.000002 18.734669 16.960003 18.868002 16.960001 c
28.188002 16.960001 l
24.908001 9.120001 l
22.228001 15.520001 l
22.174667 15.653334 22.091333 15.756667 21.978001 15.830001 c
21.864668 15.903335 21.734667 15.940002 21.588001 15.940001 c
19.908001 15.940001 l
19.654669 15.940001 19.454668 15.833334 19.308001 15.620001 c
19.254667 15.526668 19.221334 15.420001 19.208 15.300001 c
19.194666 15.180001 19.208 15.066669 19.248001 14.960001 c
23.308001 5.440001 l
23.361334 5.306667 23.444668 5.200001 23.558001 5.12 c
23.671333 5.04 23.801334 5 23.948 5.000001 c
25.868 5.000001 l
26.014666 5.000001 26.144667 5.04 26.257999 5.12 c
26.371332 5.2 26.454666 5.306667 26.507999 5.440001 c
32.208 18.860001 l
h
45.535999 12.42 m
46.109333 12.78 46.546001 13.22 46.846001 13.74 c
47.146 14.259999 47.296001 14.839999 47.296001 15.48 c
47.296001 16.986666 46.722668 18.139999 45.576 18.939999 c
44.802666 19.499998 43.756001 19.853333 42.436001 19.999998 c
42.355999 19.999998 l
42.169334 19.999998 42.015999 19.939999 41.896 19.819998 c
41.736 19.673332 41.655998 19.499998 41.655998 19.299997 c
41.655998 17.859997 l
41.655998 17.686663 41.716 17.533331 41.835999 17.399998 c
41.955997 17.266665 42.102665 17.186665 42.275997 17.159998 c
42.902664 17.09333 43.389328 16.946665 43.735996 16.719997 c
44.002663 16.559998 44.182663 16.353331 44.275997 16.099997 c
44.32933 15.95333 44.355999 15.766663 44.355999 15.539996 c
44.355999 15.39333 44.32933 15.266663 44.275997 15.159996 c
44.222664 15.05333 44.12933 14.953329 43.995998 14.859996 c
43.609329 14.593329 43.109329 14.366663 42.495998 14.179996 c
42.175999 14.079995 l
41.509331 13.893329 40.896 13.739995 40.335999 13.619995 c
40.216 13.593328 40.022663 13.546661 39.755997 13.479995 c
39.535995 13.419994 l
39.055996 13.299995 38.549328 13.133327 38.015995 12.919994 c
37.229328 12.586661 36.582661 12.166661 36.075996 11.659994 c
35.48933 11.073327 35.195995 10.299995 35.195995 9.339994 c
35.195995 8.019995 35.702663 6.946661 36.715996 6.119994 c
37.409328 5.533328 38.382664 5.159994 39.635994 4.999994 c
39.849327 4.973328 40.032661 5.033328 40.185993 5.179994 c
40.339325 5.326661 40.415993 5.499994 40.415993 5.699994 c
40.415993 7.139994 l
40.415993 7.313327 40.362659 7.466661 40.255993 7.599994 c
40.149326 7.733328 40.012661 7.809994 39.845993 7.829994 c
39.679325 7.849994 39.509327 7.886661 39.335995 7.939994 c
38.949326 8.08666 38.675995 8.229994 38.515995 8.369994 c
38.355995 8.509995 38.242664 8.653328 38.175995 8.799995 c
38.109329 9.026661 38.075996 9.239995 38.075996 9.439995 c
38.075996 9.546661 38.135998 9.659995 38.255997 9.779995 c
38.442661 9.966662 38.715996 10.133328 39.075996 10.279995 c
39.235996 10.346662 39.515999 10.446662 39.915997 10.579995 c
42.415997 11.199995 l
42.535995 11.239995 l
43.162663 11.413328 43.615993 11.546661 43.895996 11.639995 c
44.522663 11.853328 45.069328 12.113328 45.535995 12.419994 c
45.535999 12.42 l
h
42.195999 7.9 m
42.035999 7.86 41.905998 7.776667 41.806 7.65 c
41.706001 7.523334 41.656002 7.373334 41.655998 7.2 c
41.655998 5.74 l
41.655998 5.526667 41.742664 5.346667 41.915997 5.2 c
41.982662 5.133334 42.069328 5.09 42.175995 5.07 c
42.282661 5.05 42.38266 5.046667 42.475994 5.06 c
43.649326 5.246667 44.602661 5.646667 45.335995 6.26 c
46.335995 7.086667 46.869328 8.14 46.935993 9.42 c
46.949326 9.606667 46.885994 9.776667 46.745995 9.93 c
46.605995 10.083334 46.435997 10.160001 46.235996 10.16 c
44.675995 10.16 l
44.502663 10.16 44.349331 10.099999 44.215996 9.98 c
44.082661 9.86 44.009327 9.713333 43.995995 9.54 c
43.942661 9.193334 43.829327 8.906667 43.655994 8.68 c
43.375996 8.346667 42.942661 8.093333 42.355995 7.92 c
42.315994 7.92 42.289326 7.913333 42.275993 7.9 c
42.195992 7.9 l
42.195999 7.9 l
h
39.855999 17.08 m
40.015999 17.106667 40.149334 17.186666 40.256001 17.32 c
40.362667 17.453333 40.416 17.599998 40.416 17.76 c
40.416 19.24 l
40.416 19.453333 40.335999 19.633333 40.175999 19.780001 c
40.042664 19.886667 39.889332 19.940001 39.716 19.940001 c
39.616001 19.940001 l
38.375999 19.753334 37.355999 19.346666 36.556 18.720001 c
35.515999 17.893335 34.929333 16.740002 34.796001 15.260001 c
34.769333 15.046668 34.829334 14.863335 34.976002 14.710001 c
35.122669 14.556667 35.296001 14.480001 35.496002 14.480001 c
37.076004 14.480001 l
37.262669 14.480001 37.422668 14.543335 37.556004 14.670001 c
37.689339 14.796667 37.762672 14.953334 37.776005 15.140001 c
37.816006 15.806668 38.142673 16.320002 38.756004 16.68 c
39.036003 16.84 39.402668 16.973333 39.856003 17.08 c
39.855999 17.08 l
h
60.883999 11.12 m
61.084 11.12 61.253998 11.19 61.393997 11.33 c
61.533997 11.47 61.603996 11.64 61.603996 11.84 c
61.603996 13.32 l
61.603996 13.506666 61.533997 13.669999 61.393997 13.81 c
61.253998 13.95 61.084 14.02 60.883999 14.02 c
54.304001 14.02 l
54.304001 19.139999 l
54.304001 19.326666 54.237335 19.49 54.104 19.629999 c
53.970665 19.769999 53.804001 19.839998 53.604 19.839998 c
52.084 19.839998 l
51.897335 19.839998 51.734001 19.769999 51.593998 19.629999 c
51.453995 19.49 51.383995 19.326666 51.383999 19.139999 c
51.383999 11.839999 l
51.383999 11.639999 51.453999 11.469999 51.593998 11.329999 c
51.733997 11.189999 51.897331 11.119999 52.084 11.119999 c
60.883999 11.119999 l
60.883999 11.12 l
h
61.784 5 m
61.970665 5 62.133999 5.07 62.274002 5.21 c
62.414005 5.35 62.484005 5.513333 62.484001 5.7 c
62.484001 7.16 l
62.484001 7.36 62.414001 7.53 62.274002 7.67 c
62.134003 7.81 61.970669 7.88 61.784 7.88 c
52.084 7.88 l
51.897335 7.88 51.734001 7.81 51.593998 7.67 c
51.453995 7.53 51.383995 7.36 51.383999 7.16 c
51.383999 5.7 l
51.383999 5.513333 51.453999 5.35 51.593998 5.21 c
51.733997 5.07 51.897331 5.000001 52.084 5 c
61.784 5 l
h
79.512001 18.860001 m
79.605331 19.073334 79.582001 19.290001 79.442001 19.51 c
79.302002 19.73 79.112 19.84 78.872002 19.84 c
65.552002 19.84 l
65.431999 19.84 65.318672 19.809999 65.212006 19.75 c
65.105339 19.690001 65.025345 19.613333 64.972008 19.52 c
64.82534 19.306667 64.805344 19.086668 64.91201 18.860001 c
65.532013 17.400002 l
65.58535 17.266668 65.672012 17.160002 65.792015 17.080002 c
65.912018 17.000002 66.038681 16.960003 66.172012 16.960001 c
75.492012 16.960001 l
72.212013 9.120001 l
69.532013 15.520001 l
69.478676 15.653334 69.395348 15.756667 69.282013 15.830001 c
69.168678 15.903335 69.038681 15.940002 68.892014 15.940001 c
67.212013 15.940001 l
66.958679 15.940001 66.758682 15.833334 66.612015 15.620001 c
66.558678 15.526668 66.525345 15.420001 66.512016 15.300001 c
66.498688 15.180001 66.512016 15.066669 66.552017 14.960001 c
70.612015 5.440001 l
70.665352 5.306667 70.74868 5.200001 70.862015 5.12 c
70.975349 5.04 71.105347 5 71.252014 5.000001 c
73.172012 5.000001 l
73.31868 5.000001 73.448677 5.04 73.562012 5.12 c
73.675346 5.2 73.758675 5.306667 73.812012 5.440001 c
79.512001 18.860001 l
h
92 5.52 m
92.813332 5.826667 93.546669 6.32 94.199997 7 c
95.599998 8.413333 96.299995 10.216666 96.299995 12.41 c
96.299995 14.603334 95.599998 16.413334 94.199997 17.84 c
93.546661 18.52 92.813332 19.013334 92 19.32 c
91.159996 19.666666 90.299995 19.84 89.419998 19.84 c
83.759995 19.84 l
83.573326 19.84 83.409996 19.77 83.269997 19.630001 c
83.129997 19.490002 83.059998 19.326668 83.059998 19.140001 c
83.059998 17.700001 l
83.059998 17.500002 83.129997 17.330002 83.269997 17.190001 c
83.409996 17.049999 83.573326 16.98 83.759995 16.980001 c
89.359993 16.980001 l
90.546661 16.980001 91.509995 16.546669 92.249992 15.680001 c
92.98999 14.813335 93.359993 13.726667 93.359993 12.420001 c
93.359993 11.113335 92.98999 10.026668 92.249992 9.160001 c
91.509995 8.293334 90.546661 7.860001 89.359993 7.860001 c
83.759995 7.860001 l
83.573326 7.860001 83.409996 7.79 83.269997 7.650001 c
83.129997 7.510001 83.059998 7.340001 83.059998 7.14 c
83.059998 5.7 l
83.059998 5.513333 83.129997 5.35 83.269997 5.21 c
83.409996 5.07 83.573326 5 83.759995 5 c
89.419998 5 l
90.299995 5 91.159996 5.173333 92 5.52 c
h
f
Q
Q
Q
showpage
%%PageTrailer
pdfEndPage
%%Trailer
end
%%DocumentSuppliedResources:
%%EOF

View File

@ -1,920 +0,0 @@
%!PS-Adobe-3.0 EPSF-3.0
%Produced by poppler pdftops version: 22.05.0 (http://poppler.freedesktop.org)
%%Creator: Chromium
%%LanguageLevel: 3
%%DocumentSuppliedResources: (atend)
%%BoundingBox: 0 0 2400 1018
%%HiResBoundingBox: 0 0 2400 1017.12
%%DocumentSuppliedResources: (atend)
%%EndComments
%%BeginProlog
%%BeginResource: procset xpdf 3.00 0
%%Copyright: Copyright 1996-2011, 2022 Glyph & Cog, LLC
/xpdf 75 dict def xpdf begin
% PDF special state
/pdfDictSize 15 def
/pdfSetup {
/setpagedevice where {
pop 2 dict begin
/Policies 1 dict dup begin /PageSize 6 def end def
{ /Duplex true def } if
currentdict end setpagedevice
} {
pop
} ifelse
} def
/pdfSetupPaper {
% Change paper size, but only if different from previous paper size otherwise
% duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size
% so we use the same when checking if the size changes.
/setpagedevice where {
pop currentpagedevice
/PageSize known {
2 copy
currentpagedevice /PageSize get aload pop
exch 4 1 roll
sub abs 5 gt
3 1 roll
sub abs 5 gt
or
} {
true
} ifelse
{
2 array astore
2 dict begin
/PageSize exch def
/ImagingBBox null def
currentdict end
setpagedevice
} {
pop pop
} ifelse
} {
pop
} ifelse
} def
/pdfStartPage {
pdfDictSize dict begin
/pdfFillCS [] def
/pdfFillXform {} def
/pdfStrokeCS [] def
/pdfStrokeXform {} def
/pdfFill [0] def
/pdfStroke [0] def
/pdfFillOP false def
/pdfStrokeOP false def
/pdfOPM false def
/pdfLastFill false def
/pdfLastStroke false def
/pdfTextMat [1 0 0 1 0 0] def
/pdfFontSize 0 def
/pdfCharSpacing 0 def
/pdfTextRender 0 def
/pdfPatternCS false def
/pdfTextRise 0 def
/pdfWordSpacing 0 def
/pdfHorizScaling 1 def
/pdfTextClipPath [] def
} def
/pdfEndPage { end } def
% PDF color state
/opm { dup /pdfOPM exch def
/setoverprintmode where{pop setoverprintmode}{pop}ifelse } def
/cs { /pdfFillXform exch def dup /pdfFillCS exch def
setcolorspace } def
/CS { /pdfStrokeXform exch def dup /pdfStrokeCS exch def
setcolorspace } def
/sc { pdfLastFill not { pdfFillCS setcolorspace } if
dup /pdfFill exch def aload pop pdfFillXform setcolor
/pdfLastFill true def /pdfLastStroke false def } def
/SC { pdfLastStroke not { pdfStrokeCS setcolorspace } if
dup /pdfStroke exch def aload pop pdfStrokeXform setcolor
/pdfLastStroke true def /pdfLastFill false def } def
/op { /pdfFillOP exch def
pdfLastFill { pdfFillOP setoverprint } if } def
/OP { /pdfStrokeOP exch def
pdfLastStroke { pdfStrokeOP setoverprint } if } def
/fCol {
pdfLastFill not {
pdfFillCS setcolorspace
pdfFill aload pop pdfFillXform setcolor
pdfFillOP setoverprint
/pdfLastFill true def /pdfLastStroke false def
} if
} def
/sCol {
pdfLastStroke not {
pdfStrokeCS setcolorspace
pdfStroke aload pop pdfStrokeXform setcolor
pdfStrokeOP setoverprint
/pdfLastStroke true def /pdfLastFill false def
} if
} def
% build a font
/pdfMakeFont {
4 3 roll findfont
4 2 roll matrix scale makefont
dup length dict begin
{ 1 index /FID ne { def } { pop pop } ifelse } forall
/Encoding exch def
currentdict
end
definefont pop
} def
/pdfMakeFont16 {
exch findfont
dup length dict begin
{ 1 index /FID ne { def } { pop pop } ifelse } forall
/WMode exch def
currentdict
end
definefont pop
} def
/pdfMakeFont16L3 {
1 index /CIDFont resourcestatus {
pop pop 1 index /CIDFont findresource /CIDFontType known
} {
false
} ifelse
{
0 eq { /Identity-H } { /Identity-V } ifelse
exch 1 array astore composefont pop
} {
pdfMakeFont16
} ifelse
} def
% graphics state operators
/q { gsave pdfDictSize dict begin } def
/Q {
end grestore
/pdfLastFill where {
pop
pdfLastFill {
pdfFillOP setoverprint
} {
pdfStrokeOP setoverprint
} ifelse
} if
/pdfOPM where {
pop
pdfOPM /setoverprintmode where{pop setoverprintmode}{pop}ifelse
} if
} def
/cm { concat } def
/d { setdash } def
/i { setflat } def
/j { setlinejoin } def
/J { setlinecap } def
/M { setmiterlimit } def
/w { setlinewidth } def
% path segment operators
/m { moveto } def
/l { lineto } def
/c { curveto } def
/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto
neg 0 rlineto closepath } def
/h { closepath } def
% path painting operators
/S { sCol stroke } def
/Sf { fCol stroke } def
/f { fCol fill } def
/f* { fCol eofill } def
% clipping operators
/W { clip newpath } def
/W* { eoclip newpath } def
/Ws { strokepath clip newpath } def
% text state operators
/Tc { /pdfCharSpacing exch def } def
/Tf { dup /pdfFontSize exch def
dup pdfHorizScaling mul exch matrix scale
pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put
exch findfont exch makefont setfont } def
/Tr { /pdfTextRender exch def } def
/Tp { /pdfPatternCS exch def } def
/Ts { /pdfTextRise exch def } def
/Tw { /pdfWordSpacing exch def } def
/Tz { /pdfHorizScaling exch def } def
% text positioning operators
/Td { pdfTextMat transform moveto } def
/Tm { /pdfTextMat exch def } def
% text string operators
/xyshow where {
pop
/xyshow2 {
dup length array
0 2 2 index length 1 sub {
2 index 1 index 2 copy get 3 1 roll 1 add get
pdfTextMat dtransform
4 2 roll 2 copy 6 5 roll put 1 add 3 1 roll dup 4 2 roll put
} for
exch pop
xyshow
} def
}{
/xyshow2 {
currentfont /FontType get 0 eq {
0 2 3 index length 1 sub {
currentpoint 4 index 3 index 2 getinterval show moveto
2 copy get 2 index 3 2 roll 1 add get
pdfTextMat dtransform rmoveto
} for
} {
0 1 3 index length 1 sub {
currentpoint 4 index 3 index 1 getinterval show moveto
2 copy 2 mul get 2 index 3 2 roll 2 mul 1 add get
pdfTextMat dtransform rmoveto
} for
} ifelse
pop pop
} def
} ifelse
/cshow where {
pop
/xycp {
0 3 2 roll
{
pop pop currentpoint 3 2 roll
1 string dup 0 4 3 roll put false charpath moveto
2 copy get 2 index 2 index 1 add get
pdfTextMat dtransform rmoveto
2 add
} exch cshow
pop pop
} def
}{
/xycp {
currentfont /FontType get 0 eq {
0 2 3 index length 1 sub {
currentpoint 4 index 3 index 2 getinterval false charpath moveto
2 copy get 2 index 3 2 roll 1 add get
pdfTextMat dtransform rmoveto
} for
} {
0 1 3 index length 1 sub {
currentpoint 4 index 3 index 1 getinterval false charpath moveto
2 copy 2 mul get 2 index 3 2 roll 2 mul 1 add get
pdfTextMat dtransform rmoveto
} for
} ifelse
pop pop
} def
} ifelse
/Tj {
fCol
0 pdfTextRise pdfTextMat dtransform rmoveto
currentpoint 4 2 roll
pdfTextRender 1 and 0 eq {
2 copy xyshow2
} if
pdfTextRender 3 and dup 1 eq exch 2 eq or {
3 index 3 index moveto
2 copy
currentfont /FontType get 3 eq { fCol } { sCol } ifelse
xycp currentpoint stroke moveto
} if
pdfTextRender 4 and 0 ne {
4 2 roll moveto xycp
/pdfTextClipPath [ pdfTextClipPath aload pop
{/moveto cvx}
{/lineto cvx}
{/curveto cvx}
{/closepath cvx}
pathforall ] def
currentpoint newpath moveto
} {
pop pop pop pop
} ifelse
0 pdfTextRise neg pdfTextMat dtransform rmoveto
} def
/TJm { 0.001 mul pdfFontSize mul pdfHorizScaling mul neg 0
pdfTextMat dtransform rmoveto } def
/TJmV { 0.001 mul pdfFontSize mul neg 0 exch
pdfTextMat dtransform rmoveto } def
/Tclip { pdfTextClipPath cvx exec clip newpath
/pdfTextClipPath [] def } def
/Tclip* { pdfTextClipPath cvx exec eoclip newpath
/pdfTextClipPath [] def } def
% Level 2/3 image operators
/pdfImBuf 100 string def
/pdfImStr {
2 copy exch length lt {
2 copy get exch 1 add exch
} {
()
} ifelse
} def
/skipEOD {
{ currentfile pdfImBuf readline
not { pop exit } if
(%-EOD-) eq { exit } if } loop
} def
/pdfIm { image skipEOD } def
/pdfMask {
/ReusableStreamDecode filter
skipEOD
/maskStream exch def
} def
/pdfMaskEnd { maskStream closefile } def
/pdfMaskInit {
/maskArray exch def
/maskIdx 0 def
} def
/pdfMaskSrc {
maskIdx maskArray length lt {
maskArray maskIdx get
/maskIdx maskIdx 1 add def
} {
()
} ifelse
} def
/pdfImM { fCol imagemask skipEOD } def
/pr { 2 index 2 index 3 2 roll putinterval 4 add } def
/pdfImClip {
gsave
0 2 4 index length 1 sub {
dup 4 index exch 2 copy
get 5 index div put
1 add 3 index exch 2 copy
get 3 index div put
} for
pop pop rectclip
} def
/pdfImClipEnd { grestore } def
% shading operators
/colordelta {
false 0 1 3 index length 1 sub {
dup 4 index exch get 3 index 3 2 roll get sub abs 0.004 gt {
pop true
} if
} for
exch pop exch pop
} def
/funcCol { func n array astore } def
/funcSH {
dup 0 eq {
true
} {
dup 6 eq {
false
} {
4 index 4 index funcCol dup
6 index 4 index funcCol dup
3 1 roll colordelta 3 1 roll
5 index 5 index funcCol dup
3 1 roll colordelta 3 1 roll
6 index 8 index funcCol dup
3 1 roll colordelta 3 1 roll
colordelta or or or
} ifelse
} ifelse
{
1 add
4 index 3 index add 0.5 mul exch 4 index 3 index add 0.5 mul exch
6 index 6 index 4 index 4 index 4 index funcSH
2 index 6 index 6 index 4 index 4 index funcSH
6 index 2 index 4 index 6 index 4 index funcSH
5 3 roll 3 2 roll funcSH pop pop
} {
pop 3 index 2 index add 0.5 mul 3 index 2 index add 0.5 mul
funcCol sc
dup 4 index exch mat transform m
3 index 3 index mat transform l
1 index 3 index mat transform l
mat transform l pop pop h f*
} ifelse
} def
/axialCol {
dup 0 lt {
pop t0
} {
dup 1 gt {
pop t1
} {
dt mul t0 add
} ifelse
} ifelse
func n array astore
} def
/axialSH {
dup 0 eq {
true
} {
dup 8 eq {
false
} {
2 index axialCol 2 index axialCol colordelta
} ifelse
} ifelse
{
1 add 3 1 roll 2 copy add 0.5 mul
dup 4 3 roll exch 4 index axialSH
exch 3 2 roll axialSH
} {
pop 2 copy add 0.5 mul
axialCol sc
exch dup dx mul x0 add exch dy mul y0 add
3 2 roll dup dx mul x0 add exch dy mul y0 add
dx abs dy abs ge {
2 copy yMin sub dy mul dx div add yMin m
yMax sub dy mul dx div add yMax l
2 copy yMax sub dy mul dx div add yMax l
yMin sub dy mul dx div add yMin l
h f*
} {
exch 2 copy xMin sub dx mul dy div add xMin exch m
xMax sub dx mul dy div add xMax exch l
exch 2 copy xMax sub dx mul dy div add xMax exch l
xMin sub dx mul dy div add xMin exch l
h f*
} ifelse
} ifelse
} def
/radialCol {
dup t0 lt {
pop t0
} {
dup t1 gt {
pop t1
} if
} ifelse
func n array astore
} def
/radialSH {
dup 0 eq {
true
} {
dup 8 eq {
false
} {
2 index dt mul t0 add radialCol
2 index dt mul t0 add radialCol colordelta
} ifelse
} ifelse
{
1 add 3 1 roll 2 copy add 0.5 mul
dup 4 3 roll exch 4 index radialSH
exch 3 2 roll radialSH
} {
pop 2 copy add 0.5 mul dt mul t0 add
radialCol sc
encl {
exch dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add
0 360 arc h
dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add
360 0 arcn h f
} {
2 copy
dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add
a1 a2 arcn
dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add
a2 a1 arcn h
dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add
a1 a2 arc
dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add
a2 a1 arc h f
} ifelse
} ifelse
} def
end
%%EndResource
/CIDInit /ProcSet findresource begin
10 dict begin
begincmap
/CMapType 1 def
/CMapName /Identity-H def
/CIDSystemInfo 3 dict dup begin
/Registry (Adobe) def
/Ordering (Identity) def
/Supplement 0 def
end def
1 begincodespacerange
<0000> <ffff>
endcodespacerange
0 usefont
1 begincidrange
<0000> <ffff> 0
endcidrange
endcmap
currentdict CMapName exch /CMap defineresource pop
end
10 dict begin
begincmap
/CMapType 1 def
/CMapName /Identity-V def
/CIDSystemInfo 3 dict dup begin
/Registry (Adobe) def
/Ordering (Identity) def
/Supplement 0 def
end def
/WMode 1 def
1 begincodespacerange
<0000> <ffff>
endcodespacerange
0 usefont
1 begincidrange
<0000> <ffff> 0
endcidrange
endcmap
currentdict CMapName exch /CMap defineresource pop
end
end
%%EndProlog
%%BeginSetup
xpdf begin
%%EndSetup
pdfStartPage
%%EndPageSetup
[] 0 d
1 i
0 j
0 J
10 M
1 w
/DeviceGray {} cs
[0] sc
/DeviceGray {} CS
[0] SC
false op
false OP
{} settransfer
0 0 2400 1017.12 re
W
q
[0.24 0 0 -0.24 0 1017.12] cm
q
0 0 10000 4234.375 re
W*
q
[48.783241 0 0 48.766369 2560.8376 -1369.56274] cm
/DeviceRGB {} CS
[1 1 1] SC
/DeviceRGB {} cs
[1 1 1] sc
29.399 57.112 m
30.014 57.419998 30.476 57.958 30.476 58.494999 c
30.476 59.534 29.438 60.455997 28.476999 59.957001 c
13.254 52.076 l
12.408 51.577 11.678 51.268002 11.678 50.192001 c
11.678 49.077 12.37 48.807003 13.254 48.27 c
28.476999 40.389 l
29.514999 40.042999 30.476 40.813 30.476 41.851002 c
30.476 42.426003 30.014999 42.965 29.399 43.274002 c
15.638 50.192001 l
29.399 57.112 l
h
f
29.033001 60.209 m
28.825001 60.209 28.620001 60.157001 28.425001 60.056999 c
13.202002 52.175999 l
13.116001 52.125999 13.037002 52.080997 12.960002 52.035 c
12.212002 51.604 11.565002 51.230999 11.565002 50.192001 c
11.565002 49.135002 12.159002 48.786003 12.911002 48.343002 c
13.004003 48.289001 13.098002 48.233002 13.195003 48.174004 c
28.424004 40.289001 l
28.619003 40.223 28.801004 40.192001 28.982004 40.192001 c
29.882004 40.192001 30.588005 40.920002 30.588005 41.850002 c
30.588005 42.437004 30.151005 43.022003 29.449005 43.372002 c
15.887005 50.190002 l
29.449005 57.008003 l
30.140005 57.354004 30.588005 57.938004 30.588005 58.492004 c
30.587999 59.407001 29.861 60.209 29.033001 60.209 c
h
28.982 40.418999 m
28.826 40.418999 28.668001 40.445 28.512001 40.496998 c
13.306 48.369999 l
13.215 48.426998 13.118 48.482998 13.025 48.536999 c
12.282 48.975998 11.790999 49.264999 11.790999 50.191998 c
11.790999 51.101997 12.327999 51.410999 13.072 51.839996 c
13.151 51.884995 13.23 51.929996 13.311 51.978996 c
28.528 59.855995 l
28.690001 59.939995 28.860001 59.982994 29.032 59.982994 c
29.729 59.982994 30.362 59.273994 30.362 58.494995 c
30.362 58.029995 29.955 57.514996 29.348 57.211994 c
15.386 50.191994 l
29.348 43.171993 l
29.963999 42.863995 30.362 42.343994 30.362 41.850994 c
30.363001 41.048 29.756001 40.418999 28.982 40.418999 c
h
f
46.384998 64.416 m
46.153999 65.107002 45.462997 65.493004 44.771 65.376999 c
44.001999 65.223999 43.501999 64.491997 43.617001 63.684998 c
43.617001 63.608997 43.656002 63.493996 43.694 63.377998 c
53.574001 35.546997 l
53.804001 34.854996 54.496002 34.508999 55.188 34.623997 c
55.917999 34.777996 56.457001 35.508995 56.341 36.275997 c
56.341 36.353996 56.301998 36.468998 56.264 36.545998 c
46.384998 64.416 l
h
f
45.015999 65.511002 m
44.927998 65.511002 44.839001 65.502998 44.752998 65.488998 c
43.915997 65.321999 43.382 64.540001 43.505997 63.669998 c
43.504997 63.593998 43.543995 63.476997 43.584995 63.351997 c
53.467995 35.509998 l
53.674995 34.891998 54.245995 34.489998 54.924995 34.489998 c
55.018997 34.489998 55.112995 34.498997 55.205994 34.512997 c
56.017994 34.684998 56.574993 35.482998 56.452995 36.293995 c
56.453995 36.379993 56.405994 36.513996 56.365993 36.595993 c
46.490993 64.451996 l
46.280998 65.084 45.688 65.511002 45.015999 65.511002 c
h
54.924999 34.715 m
54.344997 34.715 53.856998 35.055 53.681 35.582001 c
43.800999 63.415001 l
43.765999 63.519001 43.730999 63.628002 43.730999 63.685001 c
43.622997 64.452003 44.079998 65.124001 44.792999 65.266998 c
44.863998 65.278999 44.939999 65.284996 45.015999 65.284996 c
45.591 65.284996 46.098999 64.921997 46.278999 64.380997 c
56.16 36.508995 l
56.201 36.423996 56.23 36.326996 56.23 36.277996 c
56.334999 35.565994 55.856998 34.881996 55.166 34.734997 c
55.089001 34.722 55.007 34.715 54.924999 34.715 c
h
f
84.362 50.192001 m
70.599998 43.273998 l
69.986 42.964996 69.525002 42.425999 69.525002 41.850998 c
69.525002 40.813 70.562004 39.888996 71.523003 40.388996 c
86.746002 48.269997 l
87.631004 48.806995 88.321999 49.076996 88.321999 50.191998 c
88.321999 51.267998 87.591995 51.576996 86.746002 52.075996 c
71.523003 59.956997 l
70.562004 60.455997 69.525002 59.533997 69.525002 58.494995 c
69.525002 57.957996 69.986 57.419994 70.599998 57.111996 c
84.362 50.192001 l
h
f
70.967003 60.209 m
70.139 60.209 69.411003 59.407001 69.411003 58.494999 c
69.411003 57.939999 69.858002 57.355999 70.550003 57.010998 c
84.112 50.192997 l
70.550003 43.374001 l
69.848 43.021999 69.411003 42.438 69.411003 41.852001 c
69.411003 40.939003 70.139 40.138 70.967003 40.138 c
71.176003 40.138 71.380005 40.188999 71.575005 40.290001 c
86.798004 48.171001 l
86.902 48.233002 86.996002 48.290001 87.088005 48.344002 c
87.841003 48.786003 88.435005 49.136002 88.435005 50.193001 c
88.435005 51.232002 87.789001 51.605 87.040009 52.035999 c
86.962006 52.082001 86.883011 52.126999 86.803009 52.174 c
71.575012 60.057999 l
71.379997 60.157001 71.176003 60.209 70.967003 60.209 c
h
70.967003 40.362999 m
70.271004 40.362999 69.637001 41.071999 69.637001 41.850998 c
69.637001 42.343998 70.034004 42.863998 70.651001 43.171997 c
84.612999 50.191998 l
70.651001 57.211998 l
70.044998 57.516998 69.637001 58.031998 69.637001 58.494999 c
69.637001 59.273998 70.271004 59.982998 70.967003 59.982998 c
71.139 59.982998 71.309006 59.939999 71.471001 59.855999 c
86.694 51.975998 l
86.768997 51.929996 86.848999 51.884998 86.927002 51.839996 c
87.671005 51.409996 88.209 51.101997 88.209 50.191998 c
88.209 49.263996 87.718002 48.975998 86.973999 48.536999 c
86.880997 48.482998 86.785995 48.426998 86.686996 48.367001 c
71.470993 40.491001 l
71.308998 40.404999 71.139 40.362999 70.967003 40.362999 c
h
f
Q
q
[99.016907 0 0 98.982658 152.13266 1942.3326] cm
/DeviceRGB {} CS
[1 1 1] SC
/DeviceRGB {} cs
[1 1 1] sc
10.56 5.52 m
11.373334 5.826667 12.106668 6.32 12.76 7 c
14.160001 8.413333 14.860001 10.216666 14.860001 12.41 c
14.860001 14.603334 14.160001 16.413334 12.76 17.84 c
12.106668 18.52 11.373334 19.013334 10.56 19.32 c
9.72 19.666666 8.860001 19.84 7.980001 19.84 c
2.320001 19.84 l
2.133334 19.84 1.970001 19.77 1.830001 19.630001 c
1.690001 19.490002 1.620001 19.326668 1.620001 19.140001 c
1.620001 17.700001 l
1.620001 17.500002 1.690001 17.330002 1.830001 17.190001 c
1.970001 17.049999 2.133334 16.98 2.320001 16.980001 c
7.920001 16.980001 l
9.106668 16.980001 10.070001 16.546669 10.81 15.680001 c
11.55 14.813335 11.92 13.726667 11.92 12.420001 c
11.92 11.113335 11.55 10.026668 10.81 9.160001 c
10.070001 8.293334 9.106668 7.860001 7.920001 7.860001 c
2.320001 7.860001 l
2.133334 7.860001 1.970001 7.79 1.830001 7.650001 c
1.690001 7.510001 1.620001 7.340001 1.620001 7.14 c
1.620001 5.7 l
1.620001 5.513333 1.690001 5.35 1.830001 5.21 c
1.970001 5.07 2.133334 5 2.320001 5 c
7.980001 5 l
8.860001 5 9.72 5.173333 10.56 5.52 c
h
32.208 18.860001 m
32.301334 19.073334 32.278 19.290001 32.138 19.51 c
31.998001 19.73 31.808001 19.84 31.568001 19.84 c
18.248001 19.84 l
18.128 19.84 18.014668 19.809999 17.908001 19.75 c
17.801334 19.690001 17.721334 19.613333 17.668001 19.52 c
17.521336 19.306667 17.501335 19.086668 17.608002 18.860001 c
18.228003 17.400002 l
18.281336 17.266668 18.368002 17.160002 18.488003 17.080002 c
18.608004 17.000002 18.734669 16.960003 18.868002 16.960001 c
28.188002 16.960001 l
24.908001 9.120001 l
22.228001 15.520001 l
22.174667 15.653334 22.091333 15.756667 21.978001 15.830001 c
21.864668 15.903335 21.734667 15.940002 21.588001 15.940001 c
19.908001 15.940001 l
19.654669 15.940001 19.454668 15.833334 19.308001 15.620001 c
19.254667 15.526668 19.221334 15.420001 19.208 15.300001 c
19.194666 15.180001 19.208 15.066669 19.248001 14.960001 c
23.308001 5.440001 l
23.361334 5.306667 23.444668 5.200001 23.558001 5.12 c
23.671333 5.04 23.801334 5 23.948 5.000001 c
25.868 5.000001 l
26.014666 5.000001 26.144667 5.04 26.257999 5.12 c
26.371332 5.2 26.454666 5.306667 26.507999 5.440001 c
32.208 18.860001 l
h
45.535999 12.42 m
46.109333 12.78 46.546001 13.22 46.846001 13.74 c
47.146 14.259999 47.296001 14.839999 47.296001 15.48 c
47.296001 16.986666 46.722668 18.139999 45.576 18.939999 c
44.802666 19.499998 43.756001 19.853333 42.436001 19.999998 c
42.355999 19.999998 l
42.169334 19.999998 42.015999 19.939999 41.896 19.819998 c
41.736 19.673332 41.655998 19.499998 41.655998 19.299997 c
41.655998 17.859997 l
41.655998 17.686663 41.716 17.533331 41.835999 17.399998 c
41.955997 17.266665 42.102665 17.186665 42.275997 17.159998 c
42.902664 17.09333 43.389328 16.946665 43.735996 16.719997 c
44.002663 16.559998 44.182663 16.353331 44.275997 16.099997 c
44.32933 15.95333 44.355999 15.766663 44.355999 15.539996 c
44.355999 15.39333 44.32933 15.266663 44.275997 15.159996 c
44.222664 15.05333 44.12933 14.953329 43.995998 14.859996 c
43.609329 14.593329 43.109329 14.366663 42.495998 14.179996 c
42.175999 14.079995 l
41.509331 13.893329 40.896 13.739995 40.335999 13.619995 c
40.216 13.593328 40.022663 13.546661 39.755997 13.479995 c
39.535995 13.419994 l
39.055996 13.299995 38.549328 13.133327 38.015995 12.919994 c
37.229328 12.586661 36.582661 12.166661 36.075996 11.659994 c
35.48933 11.073327 35.195995 10.299995 35.195995 9.339994 c
35.195995 8.019995 35.702663 6.946661 36.715996 6.119994 c
37.409328 5.533328 38.382664 5.159994 39.635994 4.999994 c
39.849327 4.973328 40.032661 5.033328 40.185993 5.179994 c
40.339325 5.326661 40.415993 5.499994 40.415993 5.699994 c
40.415993 7.139994 l
40.415993 7.313327 40.362659 7.466661 40.255993 7.599994 c
40.149326 7.733328 40.012661 7.809994 39.845993 7.829994 c
39.679325 7.849994 39.509327 7.886661 39.335995 7.939994 c
38.949326 8.08666 38.675995 8.229994 38.515995 8.369994 c
38.355995 8.509995 38.242664 8.653328 38.175995 8.799995 c
38.109329 9.026661 38.075996 9.239995 38.075996 9.439995 c
38.075996 9.546661 38.135998 9.659995 38.255997 9.779995 c
38.442661 9.966662 38.715996 10.133328 39.075996 10.279995 c
39.235996 10.346662 39.515999 10.446662 39.915997 10.579995 c
42.415997 11.199995 l
42.535995 11.239995 l
43.162663 11.413328 43.615993 11.546661 43.895996 11.639995 c
44.522663 11.853328 45.069328 12.113328 45.535995 12.419994 c
45.535999 12.42 l
h
42.195999 7.9 m
42.035999 7.86 41.905998 7.776667 41.806 7.65 c
41.706001 7.523334 41.656002 7.373334 41.655998 7.2 c
41.655998 5.74 l
41.655998 5.526667 41.742664 5.346667 41.915997 5.2 c
41.982662 5.133334 42.069328 5.09 42.175995 5.07 c
42.282661 5.05 42.38266 5.046667 42.475994 5.06 c
43.649326 5.246667 44.602661 5.646667 45.335995 6.26 c
46.335995 7.086667 46.869328 8.14 46.935993 9.42 c
46.949326 9.606667 46.885994 9.776667 46.745995 9.93 c
46.605995 10.083334 46.435997 10.160001 46.235996 10.16 c
44.675995 10.16 l
44.502663 10.16 44.349331 10.099999 44.215996 9.98 c
44.082661 9.86 44.009327 9.713333 43.995995 9.54 c
43.942661 9.193334 43.829327 8.906667 43.655994 8.68 c
43.375996 8.346667 42.942661 8.093333 42.355995 7.92 c
42.315994 7.92 42.289326 7.913333 42.275993 7.9 c
42.195992 7.9 l
42.195999 7.9 l
h
39.855999 17.08 m
40.015999 17.106667 40.149334 17.186666 40.256001 17.32 c
40.362667 17.453333 40.416 17.599998 40.416 17.76 c
40.416 19.24 l
40.416 19.453333 40.335999 19.633333 40.175999 19.780001 c
40.042664 19.886667 39.889332 19.940001 39.716 19.940001 c
39.616001 19.940001 l
38.375999 19.753334 37.355999 19.346666 36.556 18.720001 c
35.515999 17.893335 34.929333 16.740002 34.796001 15.260001 c
34.769333 15.046668 34.829334 14.863335 34.976002 14.710001 c
35.122669 14.556667 35.296001 14.480001 35.496002 14.480001 c
37.076004 14.480001 l
37.262669 14.480001 37.422668 14.543335 37.556004 14.670001 c
37.689339 14.796667 37.762672 14.953334 37.776005 15.140001 c
37.816006 15.806668 38.142673 16.320002 38.756004 16.68 c
39.036003 16.84 39.402668 16.973333 39.856003 17.08 c
39.855999 17.08 l
h
60.883999 11.12 m
61.084 11.12 61.253998 11.19 61.393997 11.33 c
61.533997 11.47 61.603996 11.64 61.603996 11.84 c
61.603996 13.32 l
61.603996 13.506666 61.533997 13.669999 61.393997 13.81 c
61.253998 13.95 61.084 14.02 60.883999 14.02 c
54.304001 14.02 l
54.304001 19.139999 l
54.304001 19.326666 54.237335 19.49 54.104 19.629999 c
53.970665 19.769999 53.804001 19.839998 53.604 19.839998 c
52.084 19.839998 l
51.897335 19.839998 51.734001 19.769999 51.593998 19.629999 c
51.453995 19.49 51.383995 19.326666 51.383999 19.139999 c
51.383999 11.839999 l
51.383999 11.639999 51.453999 11.469999 51.593998 11.329999 c
51.733997 11.189999 51.897331 11.119999 52.084 11.119999 c
60.883999 11.119999 l
60.883999 11.12 l
h
61.784 5 m
61.970665 5 62.133999 5.07 62.274002 5.21 c
62.414005 5.35 62.484005 5.513333 62.484001 5.7 c
62.484001 7.16 l
62.484001 7.36 62.414001 7.53 62.274002 7.67 c
62.134003 7.81 61.970669 7.88 61.784 7.88 c
52.084 7.88 l
51.897335 7.88 51.734001 7.81 51.593998 7.67 c
51.453995 7.53 51.383995 7.36 51.383999 7.16 c
51.383999 5.7 l
51.383999 5.513333 51.453999 5.35 51.593998 5.21 c
51.733997 5.07 51.897331 5.000001 52.084 5 c
61.784 5 l
h
79.512001 18.860001 m
79.605331 19.073334 79.582001 19.290001 79.442001 19.51 c
79.302002 19.73 79.112 19.84 78.872002 19.84 c
65.552002 19.84 l
65.431999 19.84 65.318672 19.809999 65.212006 19.75 c
65.105339 19.690001 65.025345 19.613333 64.972008 19.52 c
64.82534 19.306667 64.805344 19.086668 64.91201 18.860001 c
65.532013 17.400002 l
65.58535 17.266668 65.672012 17.160002 65.792015 17.080002 c
65.912018 17.000002 66.038681 16.960003 66.172012 16.960001 c
75.492012 16.960001 l
72.212013 9.120001 l
69.532013 15.520001 l
69.478676 15.653334 69.395348 15.756667 69.282013 15.830001 c
69.168678 15.903335 69.038681 15.940002 68.892014 15.940001 c
67.212013 15.940001 l
66.958679 15.940001 66.758682 15.833334 66.612015 15.620001 c
66.558678 15.526668 66.525345 15.420001 66.512016 15.300001 c
66.498688 15.180001 66.512016 15.066669 66.552017 14.960001 c
70.612015 5.440001 l
70.665352 5.306667 70.74868 5.200001 70.862015 5.12 c
70.975349 5.04 71.105347 5 71.252014 5.000001 c
73.172012 5.000001 l
73.31868 5.000001 73.448677 5.04 73.562012 5.12 c
73.675346 5.2 73.758675 5.306667 73.812012 5.440001 c
79.512001 18.860001 l
h
92 5.52 m
92.813332 5.826667 93.546669 6.32 94.199997 7 c
95.599998 8.413333 96.299995 10.216666 96.299995 12.41 c
96.299995 14.603334 95.599998 16.413334 94.199997 17.84 c
93.546661 18.52 92.813332 19.013334 92 19.32 c
91.159996 19.666666 90.299995 19.84 89.419998 19.84 c
83.759995 19.84 l
83.573326 19.84 83.409996 19.77 83.269997 19.630001 c
83.129997 19.490002 83.059998 19.326668 83.059998 19.140001 c
83.059998 17.700001 l
83.059998 17.500002 83.129997 17.330002 83.269997 17.190001 c
83.409996 17.049999 83.573326 16.98 83.759995 16.980001 c
89.359993 16.980001 l
90.546661 16.980001 91.509995 16.546669 92.249992 15.680001 c
92.98999 14.813335 93.359993 13.726667 93.359993 12.420001 c
93.359993 11.113335 92.98999 10.026668 92.249992 9.160001 c
91.509995 8.293334 90.546661 7.860001 89.359993 7.860001 c
83.759995 7.860001 l
83.573326 7.860001 83.409996 7.79 83.269997 7.650001 c
83.129997 7.510001 83.059998 7.340001 83.059998 7.14 c
83.059998 5.7 l
83.059998 5.513333 83.129997 5.35 83.269997 5.21 c
83.409996 5.07 83.573326 5 83.759995 5 c
89.419998 5 l
90.299995 5 91.159996 5.173333 92 5.52 c
h
f
Q
Q
Q
showpage
%%PageTrailer
pdfEndPage
%%Trailer
end
%%DocumentSuppliedResources:
%%EOF

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1014 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 349 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

View File

@ -1,40 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="3200"
height="1355.480324331485" viewBox="0 0 3200 1355.480324331485">
<g transform="scale(10) translate(10, 10)">
<defs id="SvgjsDefs1385">
<linearGradient id="SvgjsLinearGradient1390">
<stop id="SvgjsStop1391" stop-color="#905e26" offset="0"/>
<stop id="SvgjsStop1392" stop-color="#f5ec9b" offset="0.5"/>
<stop id="SvgjsStop1393" stop-color="#905e26" offset="1"/>
</linearGradient>
<linearGradient id="SvgjsLinearGradient1394">
<stop id="SvgjsStop1395" stop-color="#905e26" offset="0"/>
<stop id="SvgjsStop1396" stop-color="#f5ec9b" offset="0.5"/>
<stop id="SvgjsStop1397" stop-color="#905e26" offset="1"/>
</linearGradient>
</defs>
<g id="SvgjsG1386" featureKey="aMgJeN-0"
transform="matrix(1.5610770874511997,0,0,1.5610770874511997,71.94613967240352,-53.841545411371435)"
fill="#000">
<path xmlns="http://www.w3.org/2000/svg"
d="M29.399,57.112c0.615,0.308,1.077,0.846,1.077,1.383c0,1.039-1.038,1.961-1.999,1.462l-15.223-7.881 c-0.846-0.499-1.576-0.808-1.576-1.884c0-1.115,0.692-1.385,1.576-1.922l15.223-7.881c1.038-0.346,1.999,0.424,1.999,1.462 c0,0.575-0.461,1.114-1.077,1.423l-13.761,6.918L29.399,57.112z"/>
<path xmlns="http://www.w3.org/2000/svg"
d="M29.033,60.209c-0.208,0-0.413-0.052-0.608-0.152l-15.223-7.881c-0.086-0.05-0.165-0.095-0.242-0.141 c-0.748-0.431-1.395-0.804-1.395-1.843c0-1.057,0.594-1.406,1.346-1.849c0.093-0.054,0.187-0.11,0.284-0.169l15.229-7.885 c0.195-0.066,0.377-0.097,0.558-0.097c0.9,0,1.606,0.728,1.606,1.658c0,0.587-0.437,1.172-1.139,1.522l-13.562,6.818l13.562,6.818 c0.691,0.346,1.139,0.93,1.139,1.484C30.588,59.407,29.861,60.209,29.033,60.209z M28.982,40.419c-0.156,0-0.314,0.026-0.47,0.078 L13.306,48.37c-0.091,0.057-0.188,0.113-0.281,0.167c-0.743,0.439-1.234,0.728-1.234,1.655c0,0.91,0.537,1.219,1.281,1.648 c0.079,0.045,0.158,0.09,0.239,0.139l15.217,7.877c0.162,0.084,0.332,0.127,0.504,0.127c0.697,0,1.33-0.709,1.33-1.488 c0-0.465-0.407-0.98-1.014-1.283l-13.962-7.02l13.962-7.02c0.616-0.308,1.014-0.828,1.014-1.321 C30.363,41.048,29.756,40.419,28.982,40.419z"/>
<path xmlns="http://www.w3.org/2000/svg"
d="M46.385,64.416c-0.231,0.691-0.922,1.077-1.614,0.961c-0.769-0.153-1.269-0.885-1.154-1.692 c0-0.076,0.039-0.191,0.077-0.307l9.88-27.831c0.23-0.692,0.922-1.038,1.614-0.923c0.73,0.154,1.269,0.885,1.153,1.652 c0,0.078-0.039,0.193-0.077,0.27L46.385,64.416z"/>
<path xmlns="http://www.w3.org/2000/svg"
d="M45.016,65.511c-0.088,0-0.177-0.008-0.263-0.022c-0.837-0.167-1.371-0.949-1.247-1.819 c-0.001-0.076,0.038-0.193,0.079-0.318l9.883-27.842c0.207-0.618,0.778-1.02,1.457-1.02c0.094,0,0.188,0.009,0.281,0.023 c0.812,0.172,1.369,0.97,1.247,1.781c0.001,0.086-0.047,0.22-0.087,0.302l-9.875,27.856C46.281,65.084,45.688,65.511,45.016,65.511z M54.925,34.715c-0.58,0-1.068,0.34-1.244,0.867l-9.88,27.833c-0.035,0.104-0.07,0.213-0.07,0.27 c-0.108,0.767,0.349,1.439,1.062,1.582c0.071,0.012,0.147,0.018,0.223,0.018c0.575,0,1.083-0.363,1.263-0.904l9.881-27.872 c0.041-0.085,0.07-0.182,0.07-0.231c0.105-0.712-0.373-1.396-1.064-1.543C55.089,34.722,55.007,34.715,54.925,34.715z"/>
<path xmlns="http://www.w3.org/2000/svg"
d="M84.362,50.192L70.6,43.274c-0.614-0.309-1.075-0.848-1.075-1.423c0-1.038,1.037-1.962,1.998-1.462l15.223,7.881 c0.885,0.537,1.576,0.807,1.576,1.922c0,1.076-0.73,1.385-1.576,1.884l-15.223,7.881c-0.961,0.499-1.998-0.423-1.998-1.462 c0-0.537,0.461-1.075,1.075-1.383L84.362,50.192z"/>
<path xmlns="http://www.w3.org/2000/svg"
d="M70.967,60.209c-0.828,0-1.556-0.802-1.556-1.714c0-0.555,0.447-1.139,1.139-1.484l13.562-6.818L70.55,43.374 c-0.702-0.352-1.139-0.936-1.139-1.522c0-0.913,0.728-1.714,1.556-1.714c0.209,0,0.413,0.051,0.608,0.152l15.223,7.881 c0.104,0.062,0.198,0.119,0.29,0.173c0.753,0.442,1.347,0.792,1.347,1.849c0,1.039-0.646,1.412-1.395,1.843 c-0.078,0.046-0.157,0.091-0.237,0.138l-15.228,7.884C71.38,60.157,71.176,60.209,70.967,60.209z M70.967,40.363 c-0.696,0-1.33,0.709-1.33,1.488c0,0.493,0.397,1.013,1.014,1.321l13.962,7.02l-13.962,7.02c-0.606,0.305-1.014,0.82-1.014,1.283 c0,0.779,0.634,1.488,1.33,1.488c0.172,0,0.342-0.043,0.504-0.127l15.223-7.88c0.075-0.046,0.155-0.091,0.233-0.136 c0.744-0.43,1.282-0.738,1.282-1.648c0-0.928-0.491-1.216-1.235-1.655c-0.093-0.054-0.188-0.11-0.287-0.17l-15.216-7.876 C71.309,40.405,71.139,40.363,70.967,40.363z"/>
</g>
<g id="SvgjsG1387" featureKey="8L6ael-0"
transform="matrix(3.168568052463937,0,0,3.168568052463937,-5.1330821487142195,52.17667742743372)"
fill="#000">
<path d="M10.56 5.52 q1.22 0.46 2.2 1.48 q2.1 2.12 2.1 5.41 t-2.1 5.43 q-0.98 1.02 -2.2 1.48 q-1.26 0.52 -2.58 0.52 l-5.66 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.49 l0 -1.44 q0 -0.3 0.21 -0.51 t0.49 -0.21 l5.6 0 q1.78 0 2.89 -1.3 t1.11 -3.26 t-1.11 -3.26 t-2.89 -1.3 l-5.6 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.51 l0 -1.44 q0 -0.28 0.21 -0.49 t0.49 -0.21 l5.66 0 q1.32 0 2.58 0.52 z M32.208 18.86 q0.14 0.32 -0.07 0.65 t-0.57 0.33 l-13.32 0 q-0.18 0 -0.34 -0.09 t-0.24 -0.23 q-0.22 -0.32 -0.06 -0.66 l0.62 -1.46 q0.08 -0.2 0.26 -0.32 t0.38 -0.12 l9.32 0 l-3.28 -7.84 l-2.68 6.4 q-0.08 0.2 -0.25 0.31 t-0.39 0.11 l-1.68 0 q-0.38 0 -0.6 -0.32 q-0.08 -0.14 -0.1 -0.32 t0.04 -0.34 l4.06 -9.52 q0.08 -0.2 0.25 -0.32 t0.39 -0.12 l1.92 0 q0.22 0 0.39 0.12 t0.25 0.32 z M45.535999999999994 12.42 q0.86 0.54 1.31 1.32 t0.45 1.74 q0 2.26 -1.72 3.46 q-1.16 0.84 -3.14 1.06 l-0.08 0 q-0.28 0 -0.46 -0.18 q-0.24 -0.22 -0.24 -0.52 l0 -1.44 q0 -0.26 0.18 -0.46 t0.44 -0.24 q0.94 -0.1 1.46 -0.44 q0.4 -0.24 0.54 -0.62 q0.08 -0.22 0.08 -0.56 q0 -0.22 -0.08 -0.38 t-0.28 -0.3 q-0.58 -0.4 -1.5 -0.68 l-0.32 -0.1 q-1 -0.28 -1.84 -0.46 q-0.18 -0.04 -0.58 -0.14 l-0.22 -0.06 q-0.72 -0.18 -1.52 -0.5 q-1.18 -0.5 -1.94 -1.26 q-0.88 -0.88 -0.88 -2.32 q0 -1.98 1.52 -3.22 q1.04 -0.88 2.92 -1.12 q0.32 -0.04 0.55 0.18 t0.23 0.52 l0 1.44 q0 0.26 -0.16 0.46 t-0.41 0.23 t-0.51 0.11 q-0.58 0.22 -0.82 0.43 t-0.34 0.43 q-0.1 0.34 -0.1 0.64 q0 0.16 0.18 0.34 q0.28 0.28 0.82 0.5 q0.24 0.1 0.84 0.3 l2.5 0.62 l0.12 0.04 q0.94 0.26 1.36 0.4 q0.94 0.32 1.64 0.78 z M42.196 7.9 q-0.24 -0.06 -0.39 -0.25 t-0.15 -0.45 l0 -1.46 q0 -0.32 0.26 -0.54 q0.1 -0.1 0.26 -0.13 t0.3 -0.01 q1.76 0.28 2.86 1.2 q1.5 1.24 1.6 3.16 q0.02 0.28 -0.19 0.51 t-0.51 0.23 l-1.56 0 q-0.26 0 -0.46 -0.18 t-0.22 -0.44 q-0.08 -0.52 -0.34 -0.86 q-0.42 -0.5 -1.3 -0.76 q-0.06 0 -0.08 -0.02 l-0.08 0 z M39.855999999999995 17.08 q0.24 0.04 0.4 0.24 t0.16 0.44 l0 1.48 q0 0.32 -0.24 0.54 q-0.2 0.16 -0.46 0.16 l-0.1 0 q-1.86 -0.28 -3.06 -1.22 q-1.56 -1.24 -1.76 -3.46 q-0.04 -0.32 0.18 -0.55 t0.52 -0.23 l1.58 0 q0.28 0 0.48 0.19 t0.22 0.47 q0.06 1 0.98 1.54 q0.42 0.24 1.1 0.4 z M60.88399999999999 11.12 q0.3 0 0.51 0.21 t0.21 0.51 l0 1.48 q0 0.28 -0.21 0.49 t-0.51 0.21 l-6.58 0 l0 5.12 q0 0.28 -0.2 0.49 t-0.5 0.21 l-1.52 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.49 l0 -7.3 q0 -0.3 0.21 -0.51 t0.49 -0.21 l8.8 0 z M61.78399999999999 5 q0.28 0 0.49 0.21 t0.21 0.49 l0 1.46 q0 0.3 -0.21 0.51 t-0.49 0.21 l-9.7 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.51 l0 -1.46 q0 -0.28 0.21 -0.49 t0.49 -0.21 l9.7 0 z M79.512 18.86 q0.14 0.32 -0.07 0.65 t-0.57 0.33 l-13.32 0 q-0.18 0 -0.34 -0.09 t-0.24 -0.23 q-0.22 -0.32 -0.06 -0.66 l0.62 -1.46 q0.08 -0.2 0.26 -0.32 t0.38 -0.12 l9.32 0 l-3.28 -7.84 l-2.68 6.4 q-0.08 0.2 -0.25 0.31 t-0.39 0.11 l-1.68 0 q-0.38 0 -0.6 -0.32 q-0.08 -0.14 -0.1 -0.32 t0.04 -0.34 l4.06 -9.52 q0.08 -0.2 0.25 -0.32 t0.39 -0.12 l1.92 0 q0.22 0 0.39 0.12 t0.25 0.32 z M92 5.52 q1.22 0.46 2.2 1.48 q2.1 2.12 2.1 5.41 t-2.1 5.43 q-0.98 1.02 -2.2 1.48 q-1.26 0.52 -2.58 0.52 l-5.66 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.49 l0 -1.44 q0 -0.3 0.21 -0.51 t0.49 -0.21 l5.6 0 q1.78 0 2.89 -1.3 t1.11 -3.26 t-1.11 -3.26 t-2.89 -1.3 l-5.6 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.51 l0 -1.44 q0 -0.28 0.21 -0.49 t0.49 -0.21 l5.66 0 q1.32 0 2.58 0.52 z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.0 KiB

View File

@ -1,40 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="3200"
height="1355.480324331485" viewBox="0 0 3200 1355.480324331485">
<g transform="scale(10) translate(10, 10)">
<defs id="SvgjsDefs1385">
<linearGradient id="SvgjsLinearGradient1390">
<stop id="SvgjsStop1391" stop-color="#905e26" offset="0"></stop>
<stop id="SvgjsStop1392" stop-color="#f5ec9b" offset="0.5"></stop>
<stop id="SvgjsStop1393" stop-color="#905e26" offset="1"></stop>
</linearGradient>
<linearGradient id="SvgjsLinearGradient1394">
<stop id="SvgjsStop1395" stop-color="#905e26" offset="0"></stop>
<stop id="SvgjsStop1396" stop-color="#f5ec9b" offset="0.5"></stop>
<stop id="SvgjsStop1397" stop-color="#905e26" offset="1"></stop>
</linearGradient>
</defs>
<g id="SvgjsG1386" featureKey="aMgJeN-0"
transform="matrix(1.5610770874511997,0,0,1.5610770874511997,71.94613967240352,-53.841545411371435)"
fill="url(#SvgjsLinearGradient1390)">
<path xmlns="http://www.w3.org/2000/svg"
d="M29.399,57.112c0.615,0.308,1.077,0.846,1.077,1.383c0,1.039-1.038,1.961-1.999,1.462l-15.223-7.881 c-0.846-0.499-1.576-0.808-1.576-1.884c0-1.115,0.692-1.385,1.576-1.922l15.223-7.881c1.038-0.346,1.999,0.424,1.999,1.462 c0,0.575-0.461,1.114-1.077,1.423l-13.761,6.918L29.399,57.112z"></path>
<path xmlns="http://www.w3.org/2000/svg"
d="M29.033,60.209c-0.208,0-0.413-0.052-0.608-0.152l-15.223-7.881c-0.086-0.05-0.165-0.095-0.242-0.141 c-0.748-0.431-1.395-0.804-1.395-1.843c0-1.057,0.594-1.406,1.346-1.849c0.093-0.054,0.187-0.11,0.284-0.169l15.229-7.885 c0.195-0.066,0.377-0.097,0.558-0.097c0.9,0,1.606,0.728,1.606,1.658c0,0.587-0.437,1.172-1.139,1.522l-13.562,6.818l13.562,6.818 c0.691,0.346,1.139,0.93,1.139,1.484C30.588,59.407,29.861,60.209,29.033,60.209z M28.982,40.419c-0.156,0-0.314,0.026-0.47,0.078 L13.306,48.37c-0.091,0.057-0.188,0.113-0.281,0.167c-0.743,0.439-1.234,0.728-1.234,1.655c0,0.91,0.537,1.219,1.281,1.648 c0.079,0.045,0.158,0.09,0.239,0.139l15.217,7.877c0.162,0.084,0.332,0.127,0.504,0.127c0.697,0,1.33-0.709,1.33-1.488 c0-0.465-0.407-0.98-1.014-1.283l-13.962-7.02l13.962-7.02c0.616-0.308,1.014-0.828,1.014-1.321 C30.363,41.048,29.756,40.419,28.982,40.419z"></path>
<path xmlns="http://www.w3.org/2000/svg"
d="M46.385,64.416c-0.231,0.691-0.922,1.077-1.614,0.961c-0.769-0.153-1.269-0.885-1.154-1.692 c0-0.076,0.039-0.191,0.077-0.307l9.88-27.831c0.23-0.692,0.922-1.038,1.614-0.923c0.73,0.154,1.269,0.885,1.153,1.652 c0,0.078-0.039,0.193-0.077,0.27L46.385,64.416z"></path>
<path xmlns="http://www.w3.org/2000/svg"
d="M45.016,65.511c-0.088,0-0.177-0.008-0.263-0.022c-0.837-0.167-1.371-0.949-1.247-1.819 c-0.001-0.076,0.038-0.193,0.079-0.318l9.883-27.842c0.207-0.618,0.778-1.02,1.457-1.02c0.094,0,0.188,0.009,0.281,0.023 c0.812,0.172,1.369,0.97,1.247,1.781c0.001,0.086-0.047,0.22-0.087,0.302l-9.875,27.856C46.281,65.084,45.688,65.511,45.016,65.511z M54.925,34.715c-0.58,0-1.068,0.34-1.244,0.867l-9.88,27.833c-0.035,0.104-0.07,0.213-0.07,0.27 c-0.108,0.767,0.349,1.439,1.062,1.582c0.071,0.012,0.147,0.018,0.223,0.018c0.575,0,1.083-0.363,1.263-0.904l9.881-27.872 c0.041-0.085,0.07-0.182,0.07-0.231c0.105-0.712-0.373-1.396-1.064-1.543C55.089,34.722,55.007,34.715,54.925,34.715z"></path>
<path xmlns="http://www.w3.org/2000/svg"
d="M84.362,50.192L70.6,43.274c-0.614-0.309-1.075-0.848-1.075-1.423c0-1.038,1.037-1.962,1.998-1.462l15.223,7.881 c0.885,0.537,1.576,0.807,1.576,1.922c0,1.076-0.73,1.385-1.576,1.884l-15.223,7.881c-0.961,0.499-1.998-0.423-1.998-1.462 c0-0.537,0.461-1.075,1.075-1.383L84.362,50.192z"></path>
<path xmlns="http://www.w3.org/2000/svg"
d="M70.967,60.209c-0.828,0-1.556-0.802-1.556-1.714c0-0.555,0.447-1.139,1.139-1.484l13.562-6.818L70.55,43.374 c-0.702-0.352-1.139-0.936-1.139-1.522c0-0.913,0.728-1.714,1.556-1.714c0.209,0,0.413,0.051,0.608,0.152l15.223,7.881 c0.104,0.062,0.198,0.119,0.29,0.173c0.753,0.442,1.347,0.792,1.347,1.849c0,1.039-0.646,1.412-1.395,1.843 c-0.078,0.046-0.157,0.091-0.237,0.138l-15.228,7.884C71.38,60.157,71.176,60.209,70.967,60.209z M70.967,40.363 c-0.696,0-1.33,0.709-1.33,1.488c0,0.493,0.397,1.013,1.014,1.321l13.962,7.02l-13.962,7.02c-0.606,0.305-1.014,0.82-1.014,1.283 c0,0.779,0.634,1.488,1.33,1.488c0.172,0,0.342-0.043,0.504-0.127l15.223-7.88c0.075-0.046,0.155-0.091,0.233-0.136 c0.744-0.43,1.282-0.738,1.282-1.648c0-0.928-0.491-1.216-1.235-1.655c-0.093-0.054-0.188-0.11-0.287-0.17l-15.216-7.876 C71.309,40.405,71.139,40.363,70.967,40.363z"></path>
</g>
<g id="SvgjsG1387" featureKey="8L6ael-0"
transform="matrix(3.168568052463937,0,0,3.168568052463937,-5.1330821487142195,52.17667742743372)"
fill="url(#SvgjsLinearGradient1394)">
<path d="M10.56 5.52 q1.22 0.46 2.2 1.48 q2.1 2.12 2.1 5.41 t-2.1 5.43 q-0.98 1.02 -2.2 1.48 q-1.26 0.52 -2.58 0.52 l-5.66 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.49 l0 -1.44 q0 -0.3 0.21 -0.51 t0.49 -0.21 l5.6 0 q1.78 0 2.89 -1.3 t1.11 -3.26 t-1.11 -3.26 t-2.89 -1.3 l-5.6 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.51 l0 -1.44 q0 -0.28 0.21 -0.49 t0.49 -0.21 l5.66 0 q1.32 0 2.58 0.52 z M32.208 18.86 q0.14 0.32 -0.07 0.65 t-0.57 0.33 l-13.32 0 q-0.18 0 -0.34 -0.09 t-0.24 -0.23 q-0.22 -0.32 -0.06 -0.66 l0.62 -1.46 q0.08 -0.2 0.26 -0.32 t0.38 -0.12 l9.32 0 l-3.28 -7.84 l-2.68 6.4 q-0.08 0.2 -0.25 0.31 t-0.39 0.11 l-1.68 0 q-0.38 0 -0.6 -0.32 q-0.08 -0.14 -0.1 -0.32 t0.04 -0.34 l4.06 -9.52 q0.08 -0.2 0.25 -0.32 t0.39 -0.12 l1.92 0 q0.22 0 0.39 0.12 t0.25 0.32 z M45.535999999999994 12.42 q0.86 0.54 1.31 1.32 t0.45 1.74 q0 2.26 -1.72 3.46 q-1.16 0.84 -3.14 1.06 l-0.08 0 q-0.28 0 -0.46 -0.18 q-0.24 -0.22 -0.24 -0.52 l0 -1.44 q0 -0.26 0.18 -0.46 t0.44 -0.24 q0.94 -0.1 1.46 -0.44 q0.4 -0.24 0.54 -0.62 q0.08 -0.22 0.08 -0.56 q0 -0.22 -0.08 -0.38 t-0.28 -0.3 q-0.58 -0.4 -1.5 -0.68 l-0.32 -0.1 q-1 -0.28 -1.84 -0.46 q-0.18 -0.04 -0.58 -0.14 l-0.22 -0.06 q-0.72 -0.18 -1.52 -0.5 q-1.18 -0.5 -1.94 -1.26 q-0.88 -0.88 -0.88 -2.32 q0 -1.98 1.52 -3.22 q1.04 -0.88 2.92 -1.12 q0.32 -0.04 0.55 0.18 t0.23 0.52 l0 1.44 q0 0.26 -0.16 0.46 t-0.41 0.23 t-0.51 0.11 q-0.58 0.22 -0.82 0.43 t-0.34 0.43 q-0.1 0.34 -0.1 0.64 q0 0.16 0.18 0.34 q0.28 0.28 0.82 0.5 q0.24 0.1 0.84 0.3 l2.5 0.62 l0.12 0.04 q0.94 0.26 1.36 0.4 q0.94 0.32 1.64 0.78 z M42.196 7.9 q-0.24 -0.06 -0.39 -0.25 t-0.15 -0.45 l0 -1.46 q0 -0.32 0.26 -0.54 q0.1 -0.1 0.26 -0.13 t0.3 -0.01 q1.76 0.28 2.86 1.2 q1.5 1.24 1.6 3.16 q0.02 0.28 -0.19 0.51 t-0.51 0.23 l-1.56 0 q-0.26 0 -0.46 -0.18 t-0.22 -0.44 q-0.08 -0.52 -0.34 -0.86 q-0.42 -0.5 -1.3 -0.76 q-0.06 0 -0.08 -0.02 l-0.08 0 z M39.855999999999995 17.08 q0.24 0.04 0.4 0.24 t0.16 0.44 l0 1.48 q0 0.32 -0.24 0.54 q-0.2 0.16 -0.46 0.16 l-0.1 0 q-1.86 -0.28 -3.06 -1.22 q-1.56 -1.24 -1.76 -3.46 q-0.04 -0.32 0.18 -0.55 t0.52 -0.23 l1.58 0 q0.28 0 0.48 0.19 t0.22 0.47 q0.06 1 0.98 1.54 q0.42 0.24 1.1 0.4 z M60.88399999999999 11.12 q0.3 0 0.51 0.21 t0.21 0.51 l0 1.48 q0 0.28 -0.21 0.49 t-0.51 0.21 l-6.58 0 l0 5.12 q0 0.28 -0.2 0.49 t-0.5 0.21 l-1.52 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.49 l0 -7.3 q0 -0.3 0.21 -0.51 t0.49 -0.21 l8.8 0 z M61.78399999999999 5 q0.28 0 0.49 0.21 t0.21 0.49 l0 1.46 q0 0.3 -0.21 0.51 t-0.49 0.21 l-9.7 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.51 l0 -1.46 q0 -0.28 0.21 -0.49 t0.49 -0.21 l9.7 0 z M79.512 18.86 q0.14 0.32 -0.07 0.65 t-0.57 0.33 l-13.32 0 q-0.18 0 -0.34 -0.09 t-0.24 -0.23 q-0.22 -0.32 -0.06 -0.66 l0.62 -1.46 q0.08 -0.2 0.26 -0.32 t0.38 -0.12 l9.32 0 l-3.28 -7.84 l-2.68 6.4 q-0.08 0.2 -0.25 0.31 t-0.39 0.11 l-1.68 0 q-0.38 0 -0.6 -0.32 q-0.08 -0.14 -0.1 -0.32 t0.04 -0.34 l4.06 -9.52 q0.08 -0.2 0.25 -0.32 t0.39 -0.12 l1.92 0 q0.22 0 0.39 0.12 t0.25 0.32 z M92 5.52 q1.22 0.46 2.2 1.48 q2.1 2.12 2.1 5.41 t-2.1 5.43 q-0.98 1.02 -2.2 1.48 q-1.26 0.52 -2.58 0.52 l-5.66 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.49 l0 -1.44 q0 -0.3 0.21 -0.51 t0.49 -0.21 l5.6 0 q1.78 0 2.89 -1.3 t1.11 -3.26 t-1.11 -3.26 t-2.89 -1.3 l-5.6 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.51 l0 -1.44 q0 -0.28 0.21 -0.49 t0.49 -0.21 l5.66 0 q1.32 0 2.58 0.52 z"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.1 KiB

View File

@ -1,40 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="3200"
height="1355.480324331485" viewBox="0 0 3200 1355.480324331485">
<rect fill="#292929" width="3200" height="1355.480324331485"/>
<g transform="scale(10) translate(10, 10)">
<defs id="SvgjsDefs1385">
<linearGradient id="SvgjsLinearGradient1390">
<stop id="SvgjsStop1391" stop-color="#905e26" offset="0"></stop>
<stop id="SvgjsStop1392" stop-color="#f5ec9b" offset="0.5"></stop>
<stop id="SvgjsStop1393" stop-color="#905e26" offset="1"></stop>
</linearGradient>
<linearGradient id="SvgjsLinearGradient1394">
<stop id="SvgjsStop1395" stop-color="#905e26" offset="0"></stop>
<stop id="SvgjsStop1396" stop-color="#f5ec9b" offset="0.5"></stop>
<stop id="SvgjsStop1397" stop-color="#905e26" offset="1"></stop>
</linearGradient>
</defs>
<g id="SvgjsG1386" featureKey="aMgJeN-0"
transform="matrix(1.5610770874511997,0,0,1.5610770874511997,71.94613967240352,-53.841545411371435)"
fill="url(#SvgjsLinearGradient1390)">
<path xmlns="http://www.w3.org/2000/svg"
d="M29.399,57.112c0.615,0.308,1.077,0.846,1.077,1.383c0,1.039-1.038,1.961-1.999,1.462l-15.223-7.881 c-0.846-0.499-1.576-0.808-1.576-1.884c0-1.115,0.692-1.385,1.576-1.922l15.223-7.881c1.038-0.346,1.999,0.424,1.999,1.462 c0,0.575-0.461,1.114-1.077,1.423l-13.761,6.918L29.399,57.112z"></path>
<path xmlns="http://www.w3.org/2000/svg"
d="M29.033,60.209c-0.208,0-0.413-0.052-0.608-0.152l-15.223-7.881c-0.086-0.05-0.165-0.095-0.242-0.141 c-0.748-0.431-1.395-0.804-1.395-1.843c0-1.057,0.594-1.406,1.346-1.849c0.093-0.054,0.187-0.11,0.284-0.169l15.229-7.885 c0.195-0.066,0.377-0.097,0.558-0.097c0.9,0,1.606,0.728,1.606,1.658c0,0.587-0.437,1.172-1.139,1.522l-13.562,6.818l13.562,6.818 c0.691,0.346,1.139,0.93,1.139,1.484C30.588,59.407,29.861,60.209,29.033,60.209z M28.982,40.419c-0.156,0-0.314,0.026-0.47,0.078 L13.306,48.37c-0.091,0.057-0.188,0.113-0.281,0.167c-0.743,0.439-1.234,0.728-1.234,1.655c0,0.91,0.537,1.219,1.281,1.648 c0.079,0.045,0.158,0.09,0.239,0.139l15.217,7.877c0.162,0.084,0.332,0.127,0.504,0.127c0.697,0,1.33-0.709,1.33-1.488 c0-0.465-0.407-0.98-1.014-1.283l-13.962-7.02l13.962-7.02c0.616-0.308,1.014-0.828,1.014-1.321 C30.363,41.048,29.756,40.419,28.982,40.419z"></path>
<path xmlns="http://www.w3.org/2000/svg"
d="M46.385,64.416c-0.231,0.691-0.922,1.077-1.614,0.961c-0.769-0.153-1.269-0.885-1.154-1.692 c0-0.076,0.039-0.191,0.077-0.307l9.88-27.831c0.23-0.692,0.922-1.038,1.614-0.923c0.73,0.154,1.269,0.885,1.153,1.652 c0,0.078-0.039,0.193-0.077,0.27L46.385,64.416z"></path>
<path xmlns="http://www.w3.org/2000/svg"
d="M45.016,65.511c-0.088,0-0.177-0.008-0.263-0.022c-0.837-0.167-1.371-0.949-1.247-1.819 c-0.001-0.076,0.038-0.193,0.079-0.318l9.883-27.842c0.207-0.618,0.778-1.02,1.457-1.02c0.094,0,0.188,0.009,0.281,0.023 c0.812,0.172,1.369,0.97,1.247,1.781c0.001,0.086-0.047,0.22-0.087,0.302l-9.875,27.856C46.281,65.084,45.688,65.511,45.016,65.511z M54.925,34.715c-0.58,0-1.068,0.34-1.244,0.867l-9.88,27.833c-0.035,0.104-0.07,0.213-0.07,0.27 c-0.108,0.767,0.349,1.439,1.062,1.582c0.071,0.012,0.147,0.018,0.223,0.018c0.575,0,1.083-0.363,1.263-0.904l9.881-27.872 c0.041-0.085,0.07-0.182,0.07-0.231c0.105-0.712-0.373-1.396-1.064-1.543C55.089,34.722,55.007,34.715,54.925,34.715z"></path>
<path xmlns="http://www.w3.org/2000/svg"
d="M84.362,50.192L70.6,43.274c-0.614-0.309-1.075-0.848-1.075-1.423c0-1.038,1.037-1.962,1.998-1.462l15.223,7.881 c0.885,0.537,1.576,0.807,1.576,1.922c0,1.076-0.73,1.385-1.576,1.884l-15.223,7.881c-0.961,0.499-1.998-0.423-1.998-1.462 c0-0.537,0.461-1.075,1.075-1.383L84.362,50.192z"></path>
<path xmlns="http://www.w3.org/2000/svg"
d="M70.967,60.209c-0.828,0-1.556-0.802-1.556-1.714c0-0.555,0.447-1.139,1.139-1.484l13.562-6.818L70.55,43.374 c-0.702-0.352-1.139-0.936-1.139-1.522c0-0.913,0.728-1.714,1.556-1.714c0.209,0,0.413,0.051,0.608,0.152l15.223,7.881 c0.104,0.062,0.198,0.119,0.29,0.173c0.753,0.442,1.347,0.792,1.347,1.849c0,1.039-0.646,1.412-1.395,1.843 c-0.078,0.046-0.157,0.091-0.237,0.138l-15.228,7.884C71.38,60.157,71.176,60.209,70.967,60.209z M70.967,40.363 c-0.696,0-1.33,0.709-1.33,1.488c0,0.493,0.397,1.013,1.014,1.321l13.962,7.02l-13.962,7.02c-0.606,0.305-1.014,0.82-1.014,1.283 c0,0.779,0.634,1.488,1.33,1.488c0.172,0,0.342-0.043,0.504-0.127l15.223-7.88c0.075-0.046,0.155-0.091,0.233-0.136 c0.744-0.43,1.282-0.738,1.282-1.648c0-0.928-0.491-1.216-1.235-1.655c-0.093-0.054-0.188-0.11-0.287-0.17l-15.216-7.876 C71.309,40.405,71.139,40.363,70.967,40.363z"></path>
</g>
<g id="SvgjsG1387" featureKey="8L6ael-0"
transform="matrix(3.168568052463937,0,0,3.168568052463937,-5.1330821487142195,52.17667742743372)"
fill="url(#SvgjsLinearGradient1394)">
<path d="M10.56 5.52 q1.22 0.46 2.2 1.48 q2.1 2.12 2.1 5.41 t-2.1 5.43 q-0.98 1.02 -2.2 1.48 q-1.26 0.52 -2.58 0.52 l-5.66 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.49 l0 -1.44 q0 -0.3 0.21 -0.51 t0.49 -0.21 l5.6 0 q1.78 0 2.89 -1.3 t1.11 -3.26 t-1.11 -3.26 t-2.89 -1.3 l-5.6 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.51 l0 -1.44 q0 -0.28 0.21 -0.49 t0.49 -0.21 l5.66 0 q1.32 0 2.58 0.52 z M32.208 18.86 q0.14 0.32 -0.07 0.65 t-0.57 0.33 l-13.32 0 q-0.18 0 -0.34 -0.09 t-0.24 -0.23 q-0.22 -0.32 -0.06 -0.66 l0.62 -1.46 q0.08 -0.2 0.26 -0.32 t0.38 -0.12 l9.32 0 l-3.28 -7.84 l-2.68 6.4 q-0.08 0.2 -0.25 0.31 t-0.39 0.11 l-1.68 0 q-0.38 0 -0.6 -0.32 q-0.08 -0.14 -0.1 -0.32 t0.04 -0.34 l4.06 -9.52 q0.08 -0.2 0.25 -0.32 t0.39 -0.12 l1.92 0 q0.22 0 0.39 0.12 t0.25 0.32 z M45.535999999999994 12.42 q0.86 0.54 1.31 1.32 t0.45 1.74 q0 2.26 -1.72 3.46 q-1.16 0.84 -3.14 1.06 l-0.08 0 q-0.28 0 -0.46 -0.18 q-0.24 -0.22 -0.24 -0.52 l0 -1.44 q0 -0.26 0.18 -0.46 t0.44 -0.24 q0.94 -0.1 1.46 -0.44 q0.4 -0.24 0.54 -0.62 q0.08 -0.22 0.08 -0.56 q0 -0.22 -0.08 -0.38 t-0.28 -0.3 q-0.58 -0.4 -1.5 -0.68 l-0.32 -0.1 q-1 -0.28 -1.84 -0.46 q-0.18 -0.04 -0.58 -0.14 l-0.22 -0.06 q-0.72 -0.18 -1.52 -0.5 q-1.18 -0.5 -1.94 -1.26 q-0.88 -0.88 -0.88 -2.32 q0 -1.98 1.52 -3.22 q1.04 -0.88 2.92 -1.12 q0.32 -0.04 0.55 0.18 t0.23 0.52 l0 1.44 q0 0.26 -0.16 0.46 t-0.41 0.23 t-0.51 0.11 q-0.58 0.22 -0.82 0.43 t-0.34 0.43 q-0.1 0.34 -0.1 0.64 q0 0.16 0.18 0.34 q0.28 0.28 0.82 0.5 q0.24 0.1 0.84 0.3 l2.5 0.62 l0.12 0.04 q0.94 0.26 1.36 0.4 q0.94 0.32 1.64 0.78 z M42.196 7.9 q-0.24 -0.06 -0.39 -0.25 t-0.15 -0.45 l0 -1.46 q0 -0.32 0.26 -0.54 q0.1 -0.1 0.26 -0.13 t0.3 -0.01 q1.76 0.28 2.86 1.2 q1.5 1.24 1.6 3.16 q0.02 0.28 -0.19 0.51 t-0.51 0.23 l-1.56 0 q-0.26 0 -0.46 -0.18 t-0.22 -0.44 q-0.08 -0.52 -0.34 -0.86 q-0.42 -0.5 -1.3 -0.76 q-0.06 0 -0.08 -0.02 l-0.08 0 z M39.855999999999995 17.08 q0.24 0.04 0.4 0.24 t0.16 0.44 l0 1.48 q0 0.32 -0.24 0.54 q-0.2 0.16 -0.46 0.16 l-0.1 0 q-1.86 -0.28 -3.06 -1.22 q-1.56 -1.24 -1.76 -3.46 q-0.04 -0.32 0.18 -0.55 t0.52 -0.23 l1.58 0 q0.28 0 0.48 0.19 t0.22 0.47 q0.06 1 0.98 1.54 q0.42 0.24 1.1 0.4 z M60.88399999999999 11.12 q0.3 0 0.51 0.21 t0.21 0.51 l0 1.48 q0 0.28 -0.21 0.49 t-0.51 0.21 l-6.58 0 l0 5.12 q0 0.28 -0.2 0.49 t-0.5 0.21 l-1.52 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.49 l0 -7.3 q0 -0.3 0.21 -0.51 t0.49 -0.21 l8.8 0 z M61.78399999999999 5 q0.28 0 0.49 0.21 t0.21 0.49 l0 1.46 q0 0.3 -0.21 0.51 t-0.49 0.21 l-9.7 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.51 l0 -1.46 q0 -0.28 0.21 -0.49 t0.49 -0.21 l9.7 0 z M79.512 18.86 q0.14 0.32 -0.07 0.65 t-0.57 0.33 l-13.32 0 q-0.18 0 -0.34 -0.09 t-0.24 -0.23 q-0.22 -0.32 -0.06 -0.66 l0.62 -1.46 q0.08 -0.2 0.26 -0.32 t0.38 -0.12 l9.32 0 l-3.28 -7.84 l-2.68 6.4 q-0.08 0.2 -0.25 0.31 t-0.39 0.11 l-1.68 0 q-0.38 0 -0.6 -0.32 q-0.08 -0.14 -0.1 -0.32 t0.04 -0.34 l4.06 -9.52 q0.08 -0.2 0.25 -0.32 t0.39 -0.12 l1.92 0 q0.22 0 0.39 0.12 t0.25 0.32 z M92 5.52 q1.22 0.46 2.2 1.48 q2.1 2.12 2.1 5.41 t-2.1 5.43 q-0.98 1.02 -2.2 1.48 q-1.26 0.52 -2.58 0.52 l-5.66 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.49 l0 -1.44 q0 -0.3 0.21 -0.51 t0.49 -0.21 l5.6 0 q1.78 0 2.89 -1.3 t1.11 -3.26 t-1.11 -3.26 t-2.89 -1.3 l-5.6 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.51 l0 -1.44 q0 -0.28 0.21 -0.49 t0.49 -0.21 l5.66 0 q1.32 0 2.58 0.52 z"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -1,40 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="3200"
height="1355.480324331485" viewBox="0 0 3200 1355.480324331485">
<g transform="scale(10) translate(10, 10)">
<defs id="SvgjsDefs1385">
<linearGradient id="SvgjsLinearGradient1390">
<stop id="SvgjsStop1391" stop-color="#905e26" offset="0"/>
<stop id="SvgjsStop1392" stop-color="#f5ec9b" offset="0.5"/>
<stop id="SvgjsStop1393" stop-color="#905e26" offset="1"/>
</linearGradient>
<linearGradient id="SvgjsLinearGradient1394">
<stop id="SvgjsStop1395" stop-color="#905e26" offset="0"/>
<stop id="SvgjsStop1396" stop-color="#f5ec9b" offset="0.5"/>
<stop id="SvgjsStop1397" stop-color="#905e26" offset="1"/>
</linearGradient>
</defs>
<g id="SvgjsG1386" featureKey="aMgJeN-0"
transform="matrix(1.5610770874511997,0,0,1.5610770874511997,71.94613967240352,-53.841545411371435)"
fill="#fff">
<path xmlns="http://www.w3.org/2000/svg"
d="M29.399,57.112c0.615,0.308,1.077,0.846,1.077,1.383c0,1.039-1.038,1.961-1.999,1.462l-15.223-7.881 c-0.846-0.499-1.576-0.808-1.576-1.884c0-1.115,0.692-1.385,1.576-1.922l15.223-7.881c1.038-0.346,1.999,0.424,1.999,1.462 c0,0.575-0.461,1.114-1.077,1.423l-13.761,6.918L29.399,57.112z"/>
<path xmlns="http://www.w3.org/2000/svg"
d="M29.033,60.209c-0.208,0-0.413-0.052-0.608-0.152l-15.223-7.881c-0.086-0.05-0.165-0.095-0.242-0.141 c-0.748-0.431-1.395-0.804-1.395-1.843c0-1.057,0.594-1.406,1.346-1.849c0.093-0.054,0.187-0.11,0.284-0.169l15.229-7.885 c0.195-0.066,0.377-0.097,0.558-0.097c0.9,0,1.606,0.728,1.606,1.658c0,0.587-0.437,1.172-1.139,1.522l-13.562,6.818l13.562,6.818 c0.691,0.346,1.139,0.93,1.139,1.484C30.588,59.407,29.861,60.209,29.033,60.209z M28.982,40.419c-0.156,0-0.314,0.026-0.47,0.078 L13.306,48.37c-0.091,0.057-0.188,0.113-0.281,0.167c-0.743,0.439-1.234,0.728-1.234,1.655c0,0.91,0.537,1.219,1.281,1.648 c0.079,0.045,0.158,0.09,0.239,0.139l15.217,7.877c0.162,0.084,0.332,0.127,0.504,0.127c0.697,0,1.33-0.709,1.33-1.488 c0-0.465-0.407-0.98-1.014-1.283l-13.962-7.02l13.962-7.02c0.616-0.308,1.014-0.828,1.014-1.321 C30.363,41.048,29.756,40.419,28.982,40.419z"/>
<path xmlns="http://www.w3.org/2000/svg"
d="M46.385,64.416c-0.231,0.691-0.922,1.077-1.614,0.961c-0.769-0.153-1.269-0.885-1.154-1.692 c0-0.076,0.039-0.191,0.077-0.307l9.88-27.831c0.23-0.692,0.922-1.038,1.614-0.923c0.73,0.154,1.269,0.885,1.153,1.652 c0,0.078-0.039,0.193-0.077,0.27L46.385,64.416z"/>
<path xmlns="http://www.w3.org/2000/svg"
d="M45.016,65.511c-0.088,0-0.177-0.008-0.263-0.022c-0.837-0.167-1.371-0.949-1.247-1.819 c-0.001-0.076,0.038-0.193,0.079-0.318l9.883-27.842c0.207-0.618,0.778-1.02,1.457-1.02c0.094,0,0.188,0.009,0.281,0.023 c0.812,0.172,1.369,0.97,1.247,1.781c0.001,0.086-0.047,0.22-0.087,0.302l-9.875,27.856C46.281,65.084,45.688,65.511,45.016,65.511z M54.925,34.715c-0.58,0-1.068,0.34-1.244,0.867l-9.88,27.833c-0.035,0.104-0.07,0.213-0.07,0.27 c-0.108,0.767,0.349,1.439,1.062,1.582c0.071,0.012,0.147,0.018,0.223,0.018c0.575,0,1.083-0.363,1.263-0.904l9.881-27.872 c0.041-0.085,0.07-0.182,0.07-0.231c0.105-0.712-0.373-1.396-1.064-1.543C55.089,34.722,55.007,34.715,54.925,34.715z"/>
<path xmlns="http://www.w3.org/2000/svg"
d="M84.362,50.192L70.6,43.274c-0.614-0.309-1.075-0.848-1.075-1.423c0-1.038,1.037-1.962,1.998-1.462l15.223,7.881 c0.885,0.537,1.576,0.807,1.576,1.922c0,1.076-0.73,1.385-1.576,1.884l-15.223,7.881c-0.961,0.499-1.998-0.423-1.998-1.462 c0-0.537,0.461-1.075,1.075-1.383L84.362,50.192z"/>
<path xmlns="http://www.w3.org/2000/svg"
d="M70.967,60.209c-0.828,0-1.556-0.802-1.556-1.714c0-0.555,0.447-1.139,1.139-1.484l13.562-6.818L70.55,43.374 c-0.702-0.352-1.139-0.936-1.139-1.522c0-0.913,0.728-1.714,1.556-1.714c0.209,0,0.413,0.051,0.608,0.152l15.223,7.881 c0.104,0.062,0.198,0.119,0.29,0.173c0.753,0.442,1.347,0.792,1.347,1.849c0,1.039-0.646,1.412-1.395,1.843 c-0.078,0.046-0.157,0.091-0.237,0.138l-15.228,7.884C71.38,60.157,71.176,60.209,70.967,60.209z M70.967,40.363 c-0.696,0-1.33,0.709-1.33,1.488c0,0.493,0.397,1.013,1.014,1.321l13.962,7.02l-13.962,7.02c-0.606,0.305-1.014,0.82-1.014,1.283 c0,0.779,0.634,1.488,1.33,1.488c0.172,0,0.342-0.043,0.504-0.127l15.223-7.88c0.075-0.046,0.155-0.091,0.233-0.136 c0.744-0.43,1.282-0.738,1.282-1.648c0-0.928-0.491-1.216-1.235-1.655c-0.093-0.054-0.188-0.11-0.287-0.17l-15.216-7.876 C71.309,40.405,71.139,40.363,70.967,40.363z"/>
</g>
<g id="SvgjsG1387" featureKey="8L6ael-0"
transform="matrix(3.168568052463937,0,0,3.168568052463937,-5.1330821487142195,52.17667742743372)"
fill="#fff">
<path d="M10.56 5.52 q1.22 0.46 2.2 1.48 q2.1 2.12 2.1 5.41 t-2.1 5.43 q-0.98 1.02 -2.2 1.48 q-1.26 0.52 -2.58 0.52 l-5.66 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.49 l0 -1.44 q0 -0.3 0.21 -0.51 t0.49 -0.21 l5.6 0 q1.78 0 2.89 -1.3 t1.11 -3.26 t-1.11 -3.26 t-2.89 -1.3 l-5.6 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.51 l0 -1.44 q0 -0.28 0.21 -0.49 t0.49 -0.21 l5.66 0 q1.32 0 2.58 0.52 z M32.208 18.86 q0.14 0.32 -0.07 0.65 t-0.57 0.33 l-13.32 0 q-0.18 0 -0.34 -0.09 t-0.24 -0.23 q-0.22 -0.32 -0.06 -0.66 l0.62 -1.46 q0.08 -0.2 0.26 -0.32 t0.38 -0.12 l9.32 0 l-3.28 -7.84 l-2.68 6.4 q-0.08 0.2 -0.25 0.31 t-0.39 0.11 l-1.68 0 q-0.38 0 -0.6 -0.32 q-0.08 -0.14 -0.1 -0.32 t0.04 -0.34 l4.06 -9.52 q0.08 -0.2 0.25 -0.32 t0.39 -0.12 l1.92 0 q0.22 0 0.39 0.12 t0.25 0.32 z M45.535999999999994 12.42 q0.86 0.54 1.31 1.32 t0.45 1.74 q0 2.26 -1.72 3.46 q-1.16 0.84 -3.14 1.06 l-0.08 0 q-0.28 0 -0.46 -0.18 q-0.24 -0.22 -0.24 -0.52 l0 -1.44 q0 -0.26 0.18 -0.46 t0.44 -0.24 q0.94 -0.1 1.46 -0.44 q0.4 -0.24 0.54 -0.62 q0.08 -0.22 0.08 -0.56 q0 -0.22 -0.08 -0.38 t-0.28 -0.3 q-0.58 -0.4 -1.5 -0.68 l-0.32 -0.1 q-1 -0.28 -1.84 -0.46 q-0.18 -0.04 -0.58 -0.14 l-0.22 -0.06 q-0.72 -0.18 -1.52 -0.5 q-1.18 -0.5 -1.94 -1.26 q-0.88 -0.88 -0.88 -2.32 q0 -1.98 1.52 -3.22 q1.04 -0.88 2.92 -1.12 q0.32 -0.04 0.55 0.18 t0.23 0.52 l0 1.44 q0 0.26 -0.16 0.46 t-0.41 0.23 t-0.51 0.11 q-0.58 0.22 -0.82 0.43 t-0.34 0.43 q-0.1 0.34 -0.1 0.64 q0 0.16 0.18 0.34 q0.28 0.28 0.82 0.5 q0.24 0.1 0.84 0.3 l2.5 0.62 l0.12 0.04 q0.94 0.26 1.36 0.4 q0.94 0.32 1.64 0.78 z M42.196 7.9 q-0.24 -0.06 -0.39 -0.25 t-0.15 -0.45 l0 -1.46 q0 -0.32 0.26 -0.54 q0.1 -0.1 0.26 -0.13 t0.3 -0.01 q1.76 0.28 2.86 1.2 q1.5 1.24 1.6 3.16 q0.02 0.28 -0.19 0.51 t-0.51 0.23 l-1.56 0 q-0.26 0 -0.46 -0.18 t-0.22 -0.44 q-0.08 -0.52 -0.34 -0.86 q-0.42 -0.5 -1.3 -0.76 q-0.06 0 -0.08 -0.02 l-0.08 0 z M39.855999999999995 17.08 q0.24 0.04 0.4 0.24 t0.16 0.44 l0 1.48 q0 0.32 -0.24 0.54 q-0.2 0.16 -0.46 0.16 l-0.1 0 q-1.86 -0.28 -3.06 -1.22 q-1.56 -1.24 -1.76 -3.46 q-0.04 -0.32 0.18 -0.55 t0.52 -0.23 l1.58 0 q0.28 0 0.48 0.19 t0.22 0.47 q0.06 1 0.98 1.54 q0.42 0.24 1.1 0.4 z M60.88399999999999 11.12 q0.3 0 0.51 0.21 t0.21 0.51 l0 1.48 q0 0.28 -0.21 0.49 t-0.51 0.21 l-6.58 0 l0 5.12 q0 0.28 -0.2 0.49 t-0.5 0.21 l-1.52 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.49 l0 -7.3 q0 -0.3 0.21 -0.51 t0.49 -0.21 l8.8 0 z M61.78399999999999 5 q0.28 0 0.49 0.21 t0.21 0.49 l0 1.46 q0 0.3 -0.21 0.51 t-0.49 0.21 l-9.7 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.51 l0 -1.46 q0 -0.28 0.21 -0.49 t0.49 -0.21 l9.7 0 z M79.512 18.86 q0.14 0.32 -0.07 0.65 t-0.57 0.33 l-13.32 0 q-0.18 0 -0.34 -0.09 t-0.24 -0.23 q-0.22 -0.32 -0.06 -0.66 l0.62 -1.46 q0.08 -0.2 0.26 -0.32 t0.38 -0.12 l9.32 0 l-3.28 -7.84 l-2.68 6.4 q-0.08 0.2 -0.25 0.31 t-0.39 0.11 l-1.68 0 q-0.38 0 -0.6 -0.32 q-0.08 -0.14 -0.1 -0.32 t0.04 -0.34 l4.06 -9.52 q0.08 -0.2 0.25 -0.32 t0.39 -0.12 l1.92 0 q0.22 0 0.39 0.12 t0.25 0.32 z M92 5.52 q1.22 0.46 2.2 1.48 q2.1 2.12 2.1 5.41 t-2.1 5.43 q-0.98 1.02 -2.2 1.48 q-1.26 0.52 -2.58 0.52 l-5.66 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.49 l0 -1.44 q0 -0.3 0.21 -0.51 t0.49 -0.21 l5.6 0 q1.78 0 2.89 -1.3 t1.11 -3.26 t-1.11 -3.26 t-2.89 -1.3 l-5.6 0 q-0.28 0 -0.49 -0.21 t-0.21 -0.51 l0 -1.44 q0 -0.28 0.21 -0.49 t0.49 -0.21 l5.66 0 q1.32 0 2.58 0.52 z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 896 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 867 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 661 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -1,8 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<g data-name="Layer 2">
<g data-name="video">
<rect width="24" height="24" opacity="0"/>
<path d="M21 7.15a1.7 1.7 0 0 0-1.85.3l-2.15 2V8a3 3 0 0 0-3-3H5a3 3 0 0 0-3 3v8a3 3 0 0 0 3 3h9a3 3 0 0 0 3-3v-1.45l2.16 2a1.74 1.74 0 0 0 1.16.45 1.68 1.68 0 0 0 .69-.15 1.6 1.6 0 0 0 1-1.48V8.63A1.6 1.6 0 0 0 21 7.15z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 438 B

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,300 +0,0 @@
# Object Export From Tinkercad Server 2015
mtllib obj.mtl
o obj_0
v 4 3.5 4
v 4 3.568 3.482
v 4 3.768 3
v 4 4.086 2.586
v 4 4.5 2.268
v 4 4.982 2.068
v 4 5.5 2
v 4 6.018 2.068
v 4 6.5 2.268
v 4 6.914 2.586
v 4 7.232 3
v 4 7.432 3.482
v 4 7.5 4
v 4 7.432 4.518
v 4 7.232 5
v 4 6.914 5.414
v 4 6.5 5.732
v 4 6.018 5.932
v 4 5.5 6
v 4 4.982 5.932
v 4 4.5 5.732
v 4 4.086 5.414
v 4 3.768 5
v 4 3.568 4.518
v -8.308 4.5 7.952
v 1 4.7272 4.2072
v -8.587 4.5 7.81
v 1 4.7 4
v -8.81 4.5 7.587
v 1 4.8072 4.4
v -8.952 4.5 7.308
v 1 4.9344 4.5656
v -9 4.5 7.0043
v 0.952 6.5 7.308
v 1 5.1 4.6928
v 1 6.5 7.0043
v 0.81 6.5 7.587
v 1 5.2928 4.7728
v 0.587 6.5 7.81
v 0.308 6.5 7.952
v 1 5.5 4.8
v 0.0033 6.5 8
v 1 5.7072 4.7728
v 1 5.9 4.6928
v 1 6.0656 4.5656
v 1 6.1928 4.4
v 1 4.5 7.0043
v 0.952 4.5 7.308
v 0.81 4.5 7.587
v 0.587 4.5 7.81
v 0.308 4.5 7.952
v 1 6.2728 4.2072
v 0.0033 4.5 8
v 1 6.3 4
v -8.0043 4.5 0
v -8.952 4.5 0.692
v -9 4.5 0.9967
v 1 6.2728 3.7928
v -8.81 4.5 0.413
v -8.587 4.5 0.19
v 1 6.1928 3.6
v -8.308 4.5 0.048
v 1 6.0656 3.4344
v 1 5.9 3.3072
v -8.0043 6.5 8
v -8.308 6.5 7.952
v 1 5.7072 3.2272
v -8.587 6.5 7.81
v 1 5.5 3.2
v -8.81 6.5 7.587
v -8.952 6.5 7.308
v 1 5.2928 3.2272
v -9 6.5 7.0043
v 1 5.1 3.3072
v 1 4.9344 3.4344
v 1 4.8072 3.6
v 1 4.7272 3.7928
v -9 6.5 0.9967
v -8.0043 4.5 8
v 0.81 6.5 0.413
v 0.587 6.5 0.19
v 0.952 6.5 0.692
v 1 6.5 0.9967
v 0.0033 6.5 0
v 0.0033 4.5 0
v 0.308 4.5 0.048
v -8.0043 6.5 0
v 0.587 4.5 0.19
v 0.81 4.5 0.413
v 0.952 4.5 0.692
v 1 4.5 0.9967
v -8.952 6.5 0.692
v -8.81 6.5 0.413
v -8.587 6.5 0.19
v -8.308 6.5 0.048
v 0.308 6.5 0.048
# 96 vertices
g group_0_8273816
usemtl color_8273816
s 0
f 1 2 3
f 1 3 4
f 1 4 5
f 1 5 6
f 1 6 7
f 1 7 8
f 1 8 9
f 1 9 10
f 1 10 11
f 1 11 12
f 1 12 13
f 1 13 14
f 1 14 15
f 1 15 16
f 1 16 17
f 1 17 18
f 1 18 19
f 1 19 20
f 1 20 21
f 1 21 22
f 1 22 23
f 1 23 24
f 28 1 26
f 24 26 1
f 23 30 26
f 23 26 24
f 22 32 30
f 22 30 23
f 32 22 35
f 21 35 22
f 49 48 37
f 35 21 38
f 20 38 21
f 19 41 38
f 19 38 20
f 41 19 43
f 18 43 19
f 34 48 36
f 17 44 43
f 17 43 18
f 34 37 48
f 16 45 44
f 16 44 17
f 49 37 39
f 45 16 46
f 15 46 16
f 53 40 42
f 36 48 47
f 49 39 50
f 51 50 40
f 39 40 50
f 46 15 52
f 14 52 15
f 40 53 51
f 52 54 36
f 83 36 54
f 54 58 83
f 58 61 83
f 61 63 83
f 93 60 59
f 64 83 63
f 69 72 91
f 72 74 91
f 73 33 71
f 74 75 91
f 75 76 91
f 25 65 66
f 66 68 27
f 66 27 25
f 29 27 70
f 68 70 27
f 91 76 77
f 91 77 28
f 70 71 31
f 70 31 29
f 71 33 31
f 65 25 79
f 57 33 78
f 73 78 33
f 42 65 53
f 53 65 79
f 81 88 86
f 80 89 88
f 80 88 81
f 89 80 90
f 82 90 80
f 82 83 90
f 91 90 83
f 84 86 85
f 55 87 85
f 84 85 87
f 95 87 55
f 86 91 85
f 88 91 86
f 89 90 88
f 91 88 90
f 92 56 78
f 93 56 92
f 94 60 93
f 94 95 60
f 62 60 95
f 56 55 57
f 91 57 85
f 62 95 55
f 55 85 57
f 59 55 56
f 60 62 59
f 55 59 62
f 78 56 57
f 93 59 56
f 29 31 27
f 33 27 31
f 27 33 25
f 13 54 52
f 13 52 14
f 54 13 58
f 12 58 13
f 49 50 57
f 51 57 50
f 53 57 51
f 79 33 53
f 61 58 11
f 12 11 58
f 63 61 10
f 11 10 61
f 10 9 64
f 10 64 63
f 49 57 48
f 91 47 57
f 25 33 79
f 57 53 33
f 47 48 57
f 9 8 67
f 9 67 64
f 96 73 81
f 84 73 96
f 69 67 7
f 8 7 67
f 80 81 73
f 7 6 72
f 7 72 69
f 74 72 5
f 6 5 72
f 93 92 94
f 78 94 92
f 95 78 87
f 65 42 83
f 75 74 4
f 5 4 74
f 66 83 68
f 70 68 83
f 4 3 76
f 4 76 75
f 39 37 40
f 42 40 37
f 42 37 34
f 3 2 77
f 3 77 76
f 34 36 42
f 28 77 1
f 2 1 77
f 36 83 42
f 65 83 66
f 71 70 83
f 73 71 83
f 82 80 73
f 83 82 73
f 87 78 84
f 94 78 95
f 73 84 78
f 96 86 84
f 81 86 96
f 67 69 83
f 64 67 83
f 69 91 83
f 91 28 47
f 28 26 47
f 26 30 47
f 30 32 47
f 38 41 47
f 32 35 47
f 35 38 47
f 41 36 47
f 41 43 36
f 43 44 36
f 44 45 36
f 45 46 36
f 46 52 36
# 188 faces
#end of obj_0

View File

@ -1,10 +0,0 @@
{
"objects": [
{
"name": "Server",
"id": "server",
"type": "glb",
"path": "models/server_racking_system.glb"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 821 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 688 KiB

View File

@ -1,3 +0,0 @@
"ID","NAME","POSITION-X","POSITION-Y","POSITION-Z", "ROTATION-X","ROTATION-Y","ROTATION-Z", "SCALE-X","SCALE-Y","SCALE-Z"
"id2533e7b6-118a-46d0-bad9-11e73462798b","Commerce",1,0,0,0,0,0,.1,.1,.1,
,Platform,1.3,0,0,0,0,0,.1,.1,.1,
Can't render this file because it has a wrong number of fields in line 2.

BIN
public/environment.env Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -1,17 +1,16 @@
{
"name": "Deep Diagram",
"display": "standalone",
"start_url": "https://www.deepdiagram.com",
"id": "com.deepdiagram",
"scope": "https://www.deepdiagram.com",
"start_url": "https://deepdiagram.com",
"scope": "https://deepdiagram.com",
"short_name": "Deep Diagram",
"theme_color": "#000000",
"background_color": "#000000",
"description": "An immersive mind mapping and diagramming tool that lets you create, share, and visualize data on the Oculus Quest and desktop browsers.",
"description": "Immersive diagraming tool to dig into deeper meaning behind your ideas",
"icons": [
{
"src": "/assets/Android.png",
"sizes": "196x196",
"src": "/assets/android-icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
@ -29,22 +28,22 @@
],
"screenshots": [
{
"src": "/assets/screenshot1.png",
"src": "/assets/com.oculus.browser-20230121-110512.jpg",
"sizes": "1024x1024",
"type": "image/png",
"label": "Example of a few boxes on the web"
"type": "image/jpeg",
"label": "Example 1"
},
{
"src": "/assets/screenshot2.png",
"src": "/assets/com.oculus.browser-20230121-110746.jpg",
"sizes": "1024x1024",
"type": "image/png",
"label": "Example of menus on the web"
"type": "image/jpeg",
"label": "Example 2"
},
{
"src": "/assets/screenshot3.png",
"src": "/assets/com.oculus.browser-20230121-111323.jpg",
"sizes": "1024x1024",
"type": "image/png",
"label": "Example showing the web app on the Oculus Quest"
"type": "image/jpeg",
"label": "Complex Architecture Diagram"
}
]
}

View File

@ -1,141 +0,0 @@
<html lang="">
<head>
<title>Deep Diagram Privacy Policy</title>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<meta content="width=device-width, initial-scale=1, height=device-height" name="viewport">
<link href="/styles.css" rel="stylesheet">
<link href="/assets/favicon-32x32.png" rel="icon" sizes="32x32" type="image/png">
<link href="/assets/favicon-16x16.png" rel="icon" sizes="16x16" type="image/png">
<link href="/assets/favicon-96x96.png" rel="icon" sizes="96x96" type="image/png">
<link as="script" href="/newRelic.js" rel="preload">
<script src="/newRelic.js"></script>
<style>
body * {
color: #FFFFFF;
}
div#privacyPolicy {
z-index: 1;
position: absolute;
width: 80%;
height: 80%;
top: 9%;
left: 9%;
overflow-y: scroll;
background-color: rgba(0, 0, .2, 0.6);
padding: 40px;
border-radius: 30px;
border-color: #FFD700;
border-style: solid;
}
h1 {
color: #FFf0d0;
text-align: left;
}
li {
font-size: smaller;
}
</style>
</head>
<body>
<img alt="background grid" id="loadingGrid" src="/assets/grid3.jpg"/>
<div id="privacyPolicy">
<p>
This privacy policy ("policy") will help you understand how Immersive Idea LLC. ("us", "we",
"our") uses and protects the data you provide to us when you visit and use https://www.deepdiagram.com
website.
</p>
We reserve the right to change this policy at any given time, of which you will be
promptly updated. If you want to make sure that you are up to date with the latest
changes, we advise you to frequently visit this page.
<p>
<h1>What User Data We Collect</h1>
<p>
When you visit the website, we may collect the following data:
<ul>
<li>Your IP address.</li>
<li>Your contact information and email address.</li>
<li>Other information such as interests and preferences.</li>
<li>Data profile regarding your online behavior on our website.</li>
</ul>
<h1>Why We Collect Your Data</h1>
<p>
We are collecting your data for several reasons:
</p>
<ul>
<li>To better understand your needs.</li>
<li>To improve our services and products.</li>
<li>To send you promotional emails containing the information we think you will find interesting.</li>
<li>To contact you to fill out surveys and participate in other types of market
research.
</li>
<li>To customize our website according to your online behavior and personal
preferences.
</li>
</ul>
<h1>
Safeguarding and Securing the Data
</h1>
<p>Immersive Idea LLC is committed to securing your data and keeping it confidential.</p>
<p>Immersive Idea LLC has done all in its power to prevent data theft, unauthorized access,
and disclosure by implementing the latest technologies and software, which help us
safeguard all the information we collect online.
</p>
<h1>Our Cookie Policy</h1>
<p>
Once you agree to allow our website to use cookies, you also agree to use the data it
collects regarding your online behavior (analyze web traffic, web pages you visit and
spend the most time on).
</p>
<p>
The data we collect by using cookies is used to customize our website to your needs.
After we use the data for statistical analysis, the data is completely removed from our
systems.
</p>
<p>
Please note that cookies don't allow us to gain control of your computer in any way.
They are strictly used to monitor which pages you find useful and which you do not so
that we can provide a better experience for you.
</p>
<p>
If you want to disable cookies, you can do it by accessing the settings of your internet
browser. You can visit https://www.internetcookies.com, which contains comprehensive
information on how to do this on a wide variety of browsers and devices.
</p>
<h1>Links to Other Websites</h1>
<p>
Our website may contain links that lead to other websites. If you click on these links
Immersive Idea LLC is not held responsible for your data and privacy protection. Visiting
those websites is not governed by this privacy policy agreement. Make sure to read the
privacy policy documentation of the website you go to from our website.
</p>
<h1>
Restricting the Collection of your Personal Data
</h1>
<p>
At some point, you might wish to restrict the use and collection of your personal data.
You can achieve this by doing the following:</p>
<p>
When you are filling the forms on the website, make sure to check if there is a box
which you can leave unchecked, if you don't want to disclose your personal information.
If you have already agreed to share your information with us, feel free to contact us via
email (support@immersiveidea.com) and we will be more than happy to change this for you.</p>
<p>
Immersive Idea LLC will not lease, sell or distribute your personal information to any third
parties, unless we have your permission. We might do so if the law forces us. Your
personal information will be used when we need to send you promotional materials if
you agree to this privacy policy.
</p>
<a href="https://www.deepdiagram.com">Home</a>
</div>
</body>
</html>

BIN
public/spinner.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 KiB

View File

@ -1,35 +0,0 @@
body {
width: 100vw;
height: 100vh;
margin: 0;
padding: 0;
background-color: #000;
background-image: url("/assets/grid6.jpg");
aspect-ratio: auto;
font-family: Roboto, sans-serif;
font-size: large;
color: #4444ee;
}
.scene {
width: 100vw;
height: 100vh;
overflow: hidden;
}
#gameCanvas {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
background: transparent;
}
#loadingGrid {
position: relative;
z-index: -1;
width: 100%;
height: 100%;
}

View File

@ -1,25 +1,12 @@
importScripts('https://storage.googleapis.com/workbox-cdn/releases/7.1.0/workbox-sw.js');
const VERSION = '0.0.8-19';
const CACHE = "deepdiagram";
const IMAGEDELIVERY_CACHE = "deepdiagram-images";
const MAPTILE_CACHE = 'maptiler';
const VERSION = '0';
const CACHE = "pwabuilder-offline";
const PRECACHE_ASSETS = [
'/grass1.jpeg',
'/loading-loading-forever.gif',
'/outdoor_field2.jpeg'
]
importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-sw.js');
// TODO: replace the following with the correct offline fallback page i.e.: const offlineFallbackPage = "offline.html";
const offlineFallbackPage = "/";
/*self.addEventListener('install', async (event) => {
self.skipWaiting();
});
self.addEventListener('activate', async (event) => {
self.skipWaiting();
self.clients.matchAll({
type: 'window'
}).then(windowClients => {
windowClients.forEach((windowClient) => {
windowClient.navigate(windowClient.url);
});
});
});
*/
self.addEventListener("message", (event) => {
if (event.data && event.data.type === "SKIP_WAITING") {
self.skipWaiting();
@ -27,74 +14,33 @@ self.addEventListener("message", (event) => {
});
/*self.addEventListener('install', async (event) => {
event.waitUntil(
caches.open(CACHE)
.then((cache) => cache.add(offlineFallbackPage))
);
});
*/
/*if (workbox.navigationPreload.isSupported()) {
workbox.navigationPreload.enable();
}*/
workbox.routing.registerRoute(
new RegExp('/.*\\.wasm'),
new RegExp('/.*\\.png'),
new workbox.strategies.StaleWhileRevalidate({
cacheName: CACHE
})
);
workbox.routing.registerRoute(
new RegExp('.*api.maptiler.com/.*'),
new workbox.strategies.CacheFirst({
plugins: [
new workbox.expiration.ExpirationPlugin({
maxEntries: 256,
maxAgeSeconds: 60 * 60 * 24 * 30,
purgeOnQuotaError: true,
matchOptions: {
ignoreVary: true
}
}),
new workbox.cacheableResponse.CacheableResponsePlugin({
statuses: [0, 200]
})
],
cacheName: MAPTILE_CACHE
})
);
/*workbox.routing.registerRoute(
new RegExp('/assets/.*'),
new RegExp('/.*\\.jpeg'),
new workbox.strategies.StaleWhileRevalidate({
cacheName: CACHE
})
);
*/
/*workbox.routing.registerRoute(
new RegExp('/db/.*'),
workbox.routing.registerRoute(
new RegExp('/.*\\.jpg'),
new workbox.strategies.StaleWhileRevalidate({
cacheName: CACHE
})
);
*/
workbox.routing.registerRoute(
new RegExp('/.*\\.glb'),
new workbox.strategies.StaleWhileRevalidate({
cacheName: CACHE
})
);
/*
workbox.routing.registerRoute(
new RegExp('/.*\\.css'),
new workbox.strategies.StaleWhileRevalidate({
cacheName: CACHE
})
);
*/
workbox.routing.registerRoute(
new RegExp('/login'),
new workbox.strategies.NetworkFirst()
)

View File

@ -1,245 +0,0 @@
{
"name": "demo",
"dbName": "demo",
"exportDate": "2025-11-20T14:32:58.031Z",
"version": "1.0",
"entities": [
{
"id": "id0c8fd8ad-7dc8-41fa-b61f-b22c2d2b3eb8",
"position": {
"x": 0.4000000059604645,
"y": 1,
"z": 2.9000000953674316
},
"rotation": {
"x": 0,
"y": 3.141592653589793,
"z": 0
},
"last_seen": "2025-11-20T14:30:54.865Z",
"template": "#cylinder-template",
"scale": {
"x": 0.1,
"y": 0.1,
"z": 0.1
},
"color": "#FF00FF",
"text": "db",
"_id": "id0c8fd8ad-7dc8-41fa-b61f-b22c2d2b3eb8"
},
{
"from": "ide476ec05-9aac-42c9-87f1-ba7f18141767",
"to": "idb75dff6c-e056-4a15-b179-adfb2bec793a",
"type": "entity",
"template": "#connection-template",
"color": "#000000",
"id": "id18bf9938-a0b7-4e65-bf91-38697064698a",
"_id": "id18bf9938-a0b7-4e65-bf91-38697064698a"
},
{
"from": "id5c0dab44-2ef8-406e-b0ca-3aeea5b820b9",
"to": "idb75dff6c-e056-4a15-b179-adfb2bec793a",
"type": "entity",
"template": "#connection-template",
"color": "#000000",
"id": "id47bf19b7-6263-44fa-b289-1f9f63aa6aff",
"_id": "id47bf19b7-6263-44fa-b289-1f9f63aa6aff"
},
{
"from": "id5c0dab44-2ef8-406e-b0ca-3aeea5b820b9",
"to": "idac543949-c285-4f4b-ab07-d6fd2bbf7bb5",
"type": "entity",
"template": "#connection-template",
"color": "#000000",
"id": "id50594820-ace6-44c7-be5c-2b0747549c75",
"_id": "id50594820-ace6-44c7-be5c-2b0747549c75"
},
{
"from": "id5c0dab44-2ef8-406e-b0ca-3aeea5b820b9",
"to": "id5c0dab44-2ef8-406e-b0ca-3aeea5b820b9",
"type": "entity",
"template": "#connection-template",
"color": "#000000",
"id": "id562bf787-0d11-413c-bc2d-194bf05275fd",
"_id": "id562bf787-0d11-413c-bc2d-194bf05275fd"
},
{
"from": "idb75dff6c-e056-4a15-b179-adfb2bec793a",
"to": "id0c8fd8ad-7dc8-41fa-b61f-b22c2d2b3eb8",
"type": "entity",
"template": "#connection-template",
"color": "#000000",
"id": "id5b622c06-95f1-4d04-b023-b1a6851d2107",
"_id": "id5b622c06-95f1-4d04-b023-b1a6851d2107"
},
{
"id": "id5c0dab44-2ef8-406e-b0ca-3aeea5b820b9",
"position": {
"x": 0.4000000059604645,
"y": 1.7000000476837158,
"z": 2.9000000953674316
},
"rotation": {
"x": 0,
"y": 3.141592653589793,
"z": 0
},
"last_seen": "2025-11-20T14:28:52.061Z",
"template": "#sphere-template",
"text": "browser",
"scale": {
"x": 0.1,
"y": 0.1,
"z": 0.1
},
"color": "#8B4513",
"_id": "id5c0dab44-2ef8-406e-b0ca-3aeea5b820b9"
},
{
"from": "idac543949-c285-4f4b-ab07-d6fd2bbf7bb5",
"to": "id5c0dab44-2ef8-406e-b0ca-3aeea5b820b9",
"type": "entity",
"template": "#connection-template",
"color": "#000000",
"id": "id6f4208a8-9b17-45a8-b030-83a80d7e09bf",
"_id": "id6f4208a8-9b17-45a8-b030-83a80d7e09bf"
},
{
"from": "idf1cf90c7-cc2f-4ccc-9bd6-274752f5b66f",
"to": "id5c0dab44-2ef8-406e-b0ca-3aeea5b820b9",
"type": "entity",
"template": "#connection-template",
"color": "#000000",
"id": "id7205d022-db34-4705-8e3b-930ae0351376",
"_id": "id7205d022-db34-4705-8e3b-930ae0351376"
},
{
"from": "idb75dff6c-e056-4a15-b179-adfb2bec793a",
"to": "ide476ec05-9aac-42c9-87f1-ba7f18141767",
"type": "entity",
"template": "#connection-template",
"color": "#000000",
"id": "id74b9b638-8148-4d98-a715-981f7aebd3bb",
"_id": "id74b9b638-8148-4d98-a715-981f7aebd3bb"
},
{
"from": "id0c8fd8ad-7dc8-41fa-b61f-b22c2d2b3eb8",
"to": "idb75dff6c-e056-4a15-b179-adfb2bec793a",
"type": "entity",
"template": "#connection-template",
"color": "#000000",
"id": "id7af34b2d-f790-45c9-9fce-6c627de1410e",
"_id": "id7af34b2d-f790-45c9-9fce-6c627de1410e"
},
{
"from": "id5c0dab44-2ef8-406e-b0ca-3aeea5b820b9",
"to": "idf1cf90c7-cc2f-4ccc-9bd6-274752f5b66f",
"type": "entity",
"template": "#connection-template",
"color": "#000000",
"id": "id8bdd38de-6ac9-44c1-95e9-015ed85c0b7a",
"_id": "id8bdd38de-6ac9-44c1-95e9-015ed85c0b7a"
},
{
"id": "idac543949-c285-4f4b-ab07-d6fd2bbf7bb5",
"position": {
"x": -0.6000000238418579,
"y": 1.7000000476837158,
"z": 2.799999952316284
},
"rotation": {
"x": -2.4492937051703357e-16,
"y": 3.141592653589793,
"z": -2.4492937051703357e-16
},
"last_seen": "2025-11-20T14:32:19.261Z",
"template": "#box-template",
"text": "api",
"scale": {
"x": 0.1,
"y": 0.1,
"z": 0.1
},
"color": "#0000FF",
"_id": "idac543949-c285-4f4b-ab07-d6fd2bbf7bb5"
},
{
"id": "idb75dff6c-e056-4a15-b179-adfb2bec793a",
"position": {
"x": 0.4000000059604645,
"y": 1.2999999523162842,
"z": 2.9000000953674316
},
"rotation": {
"x": 0,
"y": 3.141592653589793,
"z": 0
},
"last_seen": "2025-11-20T14:28:36.027Z",
"template": "#box-template",
"text": "server",
"scale": {
"x": 0.1,
"y": 0.1,
"z": 0.1
},
"color": "#006400",
"_id": "idb75dff6c-e056-4a15-b179-adfb2bec793a"
},
{
"from": "idb75dff6c-e056-4a15-b179-adfb2bec793a",
"to": "id5c0dab44-2ef8-406e-b0ca-3aeea5b820b9",
"type": "entity",
"template": "#connection-template",
"color": "#000000",
"id": "idd6098a95-f534-4126-9aad-9948fdc724c6",
"_id": "idd6098a95-f534-4126-9aad-9948fdc724c6"
},
{
"id": "ide476ec05-9aac-42c9-87f1-ba7f18141767",
"position": {
"x": -0.6000000238418579,
"y": 1.2999999523162842,
"z": 2.799999952316284
},
"rotation": {
"x": -2.4492931757747437e-16,
"y": 3.141592653589793,
"z": -6.429647808784774e-40
},
"last_seen": "2025-11-20T14:30:59.486Z",
"template": "#box-template",
"scale": {
"x": 0.1,
"y": 0.1,
"z": 0.1
},
"color": "#0000FF",
"text": "api",
"_id": "ide476ec05-9aac-42c9-87f1-ba7f18141767"
},
{
"id": "idf1cf90c7-cc2f-4ccc-9bd6-274752f5b66f",
"position": {
"x": 0.4000000059604645,
"y": 2.200000047683716,
"z": 3
},
"rotation": {
"x": -2.4492937051703357e-16,
"y": 3.141592653589793,
"z": -2.4492937051703357e-16
},
"last_seen": "2025-11-20T14:28:58.876Z",
"template": "#person-template",
"text": "user",
"scale": {
"x": 0.1,
"y": 0.1,
"z": 0.1
},
"color": "#FFE4B5",
"_id": "idf1cf90c7-cc2f-4ccc-9bd6-274752f5b66f"
}
]
}

Binary file not shown.

124
server.js
View File

@ -1,133 +1,15 @@
import express from "express";
import ViteExpress from "vite-express";
import cors from "cors";
import dotenv from "dotenv";
import newrelic from "newrelic";
import apiRoutes from "./server/api/index.js";
import { pouchApp, PouchDB } from "./server/services/databaseService.js";
import { dbAuthMiddleware } from "./server/middleware/dbAuth.js";
// Load .env.local first, then fall back to .env
dotenv.config({ path: '.env.local' });
import expressProxy from "express-http-proxy";
dotenv.config();
// Console shim to forward logs to New Relic while preserving local output
const originalConsole = {
log: console.log.bind(console),
error: console.error.bind(console),
warn: console.warn.bind(console),
info: console.info.bind(console)
};
function forwardToNewRelic(level, args) {
const message = args.map(arg =>
typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
).join(' ');
newrelic.recordLogEvent({
message,
level,
timestamp: Date.now()
});
}
console.log = (...args) => {
forwardToNewRelic('info', args);
originalConsole.log(...args);
};
console.error = (...args) => {
forwardToNewRelic('error', args);
originalConsole.error(...args);
};
console.warn = (...args) => {
forwardToNewRelic('warn', args);
originalConsole.warn(...args);
};
console.info = (...args) => {
forwardToNewRelic('info', args);
originalConsole.info(...args);
};
const app = express();
// CORS configuration for split deployment
// In combined mode, same-origin requests don't need CORS
const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(",") || [];
if (allowedOrigins.length > 0) {
app.use(cors({
origin: allowedOrigins,
credentials: true,
}));
}
app.use("/api", expressProxy("local.immersiveidea.com"));
// Parse JSON for all routes EXCEPT /pouchdb (express-pouchdb handles its own body parsing)
app.use((req, res, next) => {
if (req.path.startsWith('/pouchdb')) {
return next();
}
express.json()(req, res, next);
});
// API routes
app.use("/api", apiRoutes);
// Test endpoint to verify PouchDB is working
app.get("/pouchdb-test/:dbname", async (req, res) => {
try {
const dbName = req.params.dbname;
console.log(`[Test] Creating database: ${dbName}`);
const db = new PouchDB(dbName);
const info = await db.info();
console.log(`[Test] Database info:`, info);
// Try to add a test doc
const result = await db.put({ _id: 'test-doc', hello: 'world' });
console.log(`[Test] Added doc:`, result);
// Read it back
const doc = await db.get('test-doc');
console.log(`[Test] Got doc:`, doc);
res.json({ success: true, info, doc });
} catch (err) {
console.error(`[Test] Error:`, err);
res.status(500).json({ error: err.message, stack: err.stack });
}
});
// PouchDB database sync endpoint with auth middleware
// Public databases (/pouchdb/public-*) are accessible without auth
// Private databases (/pouchdb/private-*) require authentication
// Patch req.query for Express 5 compatibility with express-pouchdb
app.use("/pouchdb", dbAuthMiddleware, (req, res, next) => {
// Express 5 makes req.query read-only, but express-pouchdb needs to write to it
// Redefine as writable property
Object.defineProperty(req, 'query', {
value: { ...req.query },
writable: true,
configurable: true
});
next();
}, pouchApp, (err, req, res, next) => {
console.error('[PouchDB Error]', err);
res.status(500).json({ error: err.message, stack: err.stack });
});
// Check if running in API-only mode (split deployment)
const apiOnly = process.env.API_ONLY === "true";
if (apiOnly) {
// API-only mode: no static file serving
app.listen(process.env.PORT || 3000, () => {
console.log(`API server running on port ${process.env.PORT || 3000}`);
});
} else {
// Combined mode: Vite handles static files + SPA
ViteExpress.listen(app, process.env.PORT || 3001, () => {
console.log(`Server running on port ${process.env.PORT || 3001}`);
});
}
ViteExpress.listen(app, process.env.PORT || 3001, () => console.log("Server is listening..."));

View File

@ -1,178 +0,0 @@
import { Router } from "express";
import { getSession, addMessage, getConversationForAPI } from "../services/sessionStore.js";
import { trackUsage, getUsageSummary, formatCost, getSessionUsage } from "../services/usageTracker.js";
const router = Router();
const ANTHROPIC_API_URL = "https://api.anthropic.com";
/**
* Build entity context string for the system prompt
*/
function buildEntityContext(entities) {
if (!entities || entities.length === 0) {
return "\n\nThe diagram is currently empty.";
}
const entityList = entities.map(e => {
const shape = e.template?.replace('#', '').replace('-template', '') || 'unknown';
const pos = e.position || { x: 0, y: 0, z: 0 };
return `- ${e.text || '(no label)'} (${shape}, ${e.color || 'unknown'}) at (${pos.x?.toFixed(1)}, ${pos.y?.toFixed(1)}, ${pos.z?.toFixed(1)})`;
}).join('\n');
return `\n\n## Current Diagram State\nThe diagram currently contains ${entities.length} entities:\n${entityList}`;
}
// Express 5 uses named parameters for wildcards
router.post("/*path", async (req, res) => {
const requestStart = Date.now();
console.log(`[Claude API] ========== REQUEST START ==========`);
const apiKey = process.env.ANTHROPIC_API_KEY;
if (!apiKey) {
console.error(`[Claude API] ERROR: API key not configured`);
return res.status(500).json({ error: "API key not configured" });
}
// Get the path after /api/claude (e.g., /v1/messages)
// Express 5 returns path segments as an array
const pathParam = req.params.path;
const path = "/" + (Array.isArray(pathParam) ? pathParam.join("/") : pathParam || "");
console.log(`[Claude API] Path: ${path}`);
// Check for session-based request
const { sessionId, ...requestBody } = req.body;
let modifiedBody = requestBody;
console.log(`[Claude API] Session ID: ${sessionId || 'none'}`);
console.log(`[Claude API] Model: ${requestBody.model}`);
console.log(`[Claude API] Messages count: ${requestBody.messages?.length || 0}`);
if (sessionId) {
const session = getSession(sessionId);
if (session) {
console.log(`[Claude API] Session found: ${session.entities.length} entities, ${session.conversationHistory.length} messages in history`);
// Inject entity context into system prompt
if (modifiedBody.system) {
const entityContext = buildEntityContext(session.entities);
console.log(`[Claude API] Entity context added (${entityContext.length} chars)`);
modifiedBody.system += entityContext;
}
// Get conversation history and merge with current messages
const historyMessages = getConversationForAPI(sessionId);
if (historyMessages.length > 0 && modifiedBody.messages) {
// Filter out any duplicate messages (in case client sent history too)
const currentContent = modifiedBody.messages[modifiedBody.messages.length - 1]?.content;
const filteredHistory = historyMessages.filter(msg => msg.content !== currentContent);
modifiedBody.messages = [...filteredHistory, ...modifiedBody.messages];
console.log(`[Claude API] Merged ${filteredHistory.length} history + ${modifiedBody.messages.length - filteredHistory.length} new = ${modifiedBody.messages.length} total messages`);
}
} else {
console.log(`[Claude API] WARNING: Session ${sessionId} not found`);
}
}
try {
console.log(`[Claude API] Sending request to Anthropic API...`);
const fetchStart = Date.now();
const response = await fetch(`${ANTHROPIC_API_URL}${path}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": apiKey,
"anthropic-version": "2023-06-01",
},
body: JSON.stringify(modifiedBody),
});
const fetchDuration = Date.now() - fetchStart;
console.log(`[Claude API] Response received in ${fetchDuration}ms, status: ${response.status}`);
console.log(`[Claude API] Parsing response JSON...`);
const data = await response.json();
console.log(`[Claude API] Response parsed. Stop reason: ${data.stop_reason}, content blocks: ${data.content?.length || 0}`);
// Track and log token usage
if (data.usage) {
// Extract content for detailed tracking
const userMessage = requestBody.messages?.[requestBody.messages.length - 1];
const inputText = typeof userMessage?.content === 'string' ? userMessage.content : null;
const outputText = data.content
?.filter(c => c.type === 'text')
.map(c => c.text)
.join('\n') || null;
const toolCalls = data.content
?.filter(c => c.type === 'tool_use')
.map(c => ({ name: c.name, input: c.input })) || [];
const usageRecord = trackUsage(sessionId, modifiedBody.model, data.usage, {
inputText,
outputText,
toolCalls
});
console.log(`[Claude API] REQUEST USAGE: ${getUsageSummary(usageRecord)}`);
// Log cumulative session usage if session exists
if (sessionId) {
const sessionStats = getSessionUsage(sessionId);
if (sessionStats) {
console.log(`[Claude API] SESSION TOTALS (${sessionStats.requestCount} requests):`);
console.log(`[Claude API] Total input: ${sessionStats.totalInputTokens} tokens`);
console.log(`[Claude API] Total output: ${sessionStats.totalOutputTokens} tokens`);
console.log(`[Claude API] Total cost: ${formatCost(sessionStats.totalCost)}`);
}
}
}
if (data.error) {
console.error(`[Claude API] API returned error:`, data.error);
}
// If session exists and response is successful, store messages
if (sessionId && response.ok && data.content) {
const session = getSession(sessionId);
if (session) {
// Store the user message if it was new (only if it's a string, not tool results)
const userMessage = requestBody.messages?.[requestBody.messages.length - 1];
if (userMessage && userMessage.role === 'user' && typeof userMessage.content === 'string') {
addMessage(sessionId, {
role: 'user',
content: userMessage.content
});
console.log(`[Claude API] Stored user message to session`);
}
// Store the assistant response (text only, not tool use blocks)
const assistantContent = data.content
.filter(c => c.type === 'text')
.map(c => c.text)
.join('\n');
if (assistantContent) {
addMessage(sessionId, {
role: 'assistant',
content: assistantContent
});
console.log(`[Claude API] Stored assistant response to session (${assistantContent.length} chars)`);
}
}
}
const totalDuration = Date.now() - requestStart;
console.log(`[Claude API] ========== REQUEST COMPLETE (${totalDuration}ms) ==========`);
res.status(response.status).json(data);
} catch (error) {
const totalDuration = Date.now() - requestStart;
console.error(`[Claude API] ========== REQUEST FAILED (${totalDuration}ms) ==========`);
console.error(`[Claude API] Error:`, error);
console.error(`[Claude API] Error message:`, error.message);
console.error(`[Claude API] Error stack:`, error.stack);
res.status(500).json({ error: "Failed to proxy request to Claude API", details: error.message });
}
});
export default router;

View File

@ -1,213 +0,0 @@
import { Router } from "express";
import { getSession, addMessage, getConversationForAPI } from "../services/sessionStore.js";
import { trackUsage, getUsageSummary, formatCost, getSessionUsage } from "../services/usageTracker.js";
import { getCloudflareAccountId, getCloudflareApiToken } from "../services/providerConfig.js";
import {
claudeToolsToCloudflare,
claudeMessagesToCloudflare,
cloudflareResponseToClaude
} from "../services/toolConverter.js";
const router = Router();
/**
* Build entity context string for the system prompt
*/
function buildEntityContext(entities) {
if (!entities || entities.length === 0) {
return "\n\nThe diagram is currently empty.";
}
const entityList = entities.map(e => {
const shape = e.template?.replace('#', '').replace('-template', '') || 'unknown';
const pos = e.position || { x: 0, y: 0, z: 0 };
return `- ${e.text || '(no label)'} (${shape}, ${e.color || 'unknown'}) at (${pos.x?.toFixed(1)}, ${pos.y?.toFixed(1)}, ${pos.z?.toFixed(1)})`;
}).join('\n');
return `\n\n## Current Diagram State\nThe diagram currently contains ${entities.length} entities:\n${entityList}`;
}
// Express 5 uses named parameters for wildcards
router.post("/*path", async (req, res) => {
const requestStart = Date.now();
console.log(`[Cloudflare API] ========== REQUEST START ==========`);
const accountId = getCloudflareAccountId();
const apiToken = getCloudflareApiToken();
if (!accountId) {
console.error(`[Cloudflare API] ERROR: Account ID not configured`);
return res.status(500).json({ error: "Cloudflare account ID not configured" });
}
if (!apiToken) {
console.error(`[Cloudflare API] ERROR: API token not configured`);
return res.status(500).json({ error: "Cloudflare API token not configured" });
}
// Check for session-based request
const { sessionId, ...requestBody } = req.body;
let modifiedBody = { ...requestBody };
const model = requestBody.model;
console.log(`[Cloudflare API] Session ID: ${sessionId || 'none'}`);
console.log(`[Cloudflare API] Model: ${model}`);
console.log(`[Cloudflare API] Messages count: ${requestBody.messages?.length || 0}`);
// Build system prompt with entity context
let systemPrompt = modifiedBody.system || '';
if (sessionId) {
const session = getSession(sessionId);
if (session) {
console.log(`[Cloudflare API] Session found: ${session.entities.length} entities, ${session.conversationHistory.length} messages in history`);
// Inject entity context into system prompt
const entityContext = buildEntityContext(session.entities);
console.log(`[Cloudflare API] Entity context added (${entityContext.length} chars)`);
systemPrompt += entityContext;
// Get conversation history and merge with current messages
const historyMessages = getConversationForAPI(sessionId);
if (historyMessages.length > 0 && modifiedBody.messages) {
const currentContent = modifiedBody.messages[modifiedBody.messages.length - 1]?.content;
const filteredHistory = historyMessages.filter(msg => msg.content !== currentContent);
modifiedBody.messages = [...filteredHistory, ...modifiedBody.messages];
console.log(`[Cloudflare API] Merged ${filteredHistory.length} history + ${modifiedBody.messages.length - filteredHistory.length} new = ${modifiedBody.messages.length} total messages`);
}
} else {
console.log(`[Cloudflare API] WARNING: Session ${sessionId} not found`);
}
}
try {
// Convert to Cloudflare format
const cfMessages = claudeMessagesToCloudflare(modifiedBody.messages || [], systemPrompt);
const cfTools = modifiedBody.tools ? claudeToolsToCloudflare(modifiedBody.tools) : undefined;
// Build Cloudflare request body
const cfRequestBody = {
messages: cfMessages,
max_tokens: modifiedBody.max_tokens || 1024
};
// Only include tools if the model supports them
if (cfTools && cfTools.length > 0) {
cfRequestBody.tools = cfTools;
}
// Cloudflare endpoint: https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/{model}
const endpoint = `https://api.cloudflare.com/client/v4/accounts/${accountId}/ai/run/${model}`;
console.log(`[Cloudflare API] Sending request to: ${endpoint}`);
console.log(`[Cloudflare API] Request body messages: ${cfMessages.length}, tools: ${cfTools?.length || 0}`);
const requestBodyJson = JSON.stringify(cfRequestBody);
console.log(`[Cloudflare API] Full request body (${requestBodyJson.length} bytes):`);
console.log(requestBodyJson);
const fetchStart = Date.now();
const response = await fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${apiToken}`,
},
body: JSON.stringify(cfRequestBody),
});
const fetchDuration = Date.now() - fetchStart;
console.log(`[Cloudflare API] Response received in ${fetchDuration}ms, status: ${response.status}`);
console.log(`[Cloudflare API] Parsing response JSON...`);
const cfData = await response.json();
if (!cfData.success) {
console.error(`[Cloudflare API] API returned error:`, cfData.errors);
return res.status(response.status).json({
error: cfData.errors?.[0]?.message || "Cloudflare API error",
details: cfData.errors
});
}
// Convert Cloudflare response to Claude format
const data = cloudflareResponseToClaude(cfData, model);
console.log(`[Cloudflare API] Response converted. Stop reason: ${data.stop_reason}, content blocks: ${data.content?.length || 0}`);
// Track and log token usage
if (data.usage) {
// Extract content for detailed tracking
const userMessage = requestBody.messages?.[requestBody.messages.length - 1];
const inputText = typeof userMessage?.content === 'string' ? userMessage.content : null;
const outputText = data.content
?.filter(c => c.type === 'text')
.map(c => c.text)
.join('\n') || null;
const toolCalls = data.content
?.filter(c => c.type === 'tool_use')
.map(c => ({ name: c.name, input: c.input })) || [];
const usageRecord = trackUsage(sessionId, model, data.usage, {
inputText,
outputText,
toolCalls
});
console.log(`[Cloudflare API] REQUEST USAGE: ${getUsageSummary(usageRecord)}`);
// Log cumulative session usage if session exists
if (sessionId) {
const sessionStats = getSessionUsage(sessionId);
if (sessionStats) {
console.log(`[Cloudflare API] SESSION TOTALS (${sessionStats.requestCount} requests):`);
console.log(`[Cloudflare API] Total input: ${sessionStats.totalInputTokens} tokens`);
console.log(`[Cloudflare API] Total output: ${sessionStats.totalOutputTokens} tokens`);
console.log(`[Cloudflare API] Total cost: ${formatCost(sessionStats.totalCost)}`);
}
}
}
// If session exists and response is successful, store messages
if (sessionId && response.ok && data.content) {
const session = getSession(sessionId);
if (session) {
// Store the user message if it was new (only if it's a string, not tool results)
const userMessage = requestBody.messages?.[requestBody.messages.length - 1];
if (userMessage && userMessage.role === 'user' && typeof userMessage.content === 'string') {
addMessage(sessionId, {
role: 'user',
content: userMessage.content
});
console.log(`[Cloudflare API] Stored user message to session`);
}
// Store the assistant response (text only, not tool use blocks)
const assistantContent = data.content
.filter(c => c.type === 'text')
.map(c => c.text)
.join('\n');
if (assistantContent) {
addMessage(sessionId, {
role: 'assistant',
content: assistantContent
});
console.log(`[Cloudflare API] Stored assistant response to session (${assistantContent.length} chars)`);
}
}
}
const totalDuration = Date.now() - requestStart;
console.log(`[Cloudflare API] ========== REQUEST COMPLETE (${totalDuration}ms) ==========`);
res.status(response.status).json(data);
} catch (error) {
const totalDuration = Date.now() - requestStart;
console.error(`[Cloudflare API] ========== REQUEST FAILED (${totalDuration}ms) ==========`);
console.error(`[Cloudflare API] Error:`, error);
console.error(`[Cloudflare API] Error message:`, error.message);
console.error(`[Cloudflare API] Error stack:`, error.stack);
res.status(500).json({ error: "Failed to proxy request to Cloudflare API", details: error.message });
}
});
export default router;

View File

@ -1,30 +0,0 @@
import { Router } from "express";
import claudeRouter from "./claude.js";
import ollamaRouter from "./ollama.js";
import cloudflareRouter from "./cloudflare.js";
import sessionRouter from "./session.js";
import userRouter from "./user.js";
const router = Router();
// Session management
router.use("/session", sessionRouter);
// User features
router.use("/user", userRouter);
// Claude API proxy
router.use("/claude", claudeRouter);
// Ollama API proxy
router.use("/ollama", ollamaRouter);
// Cloudflare Workers AI proxy
router.use("/cloudflare", cloudflareRouter);
// Health check
router.get("/health", (req, res) => {
res.json({ status: "ok" });
});
export default router;

Some files were not shown because too many files have changed in this diff Show More