Clean project structure for deployment
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitignore +4 -1
- FEATURES_2.6.0.md +236 -0
- INTEGRATION_GUIDE.md +260 -0
- README.md +277 -0
- build.log +98 -0
- erl_crash.dump +0 -0
- flashcards.db/conf +4 -0
- flashcards.db/snap.00000000000000BA +0 -0
- gleam.toml +15 -0
- manifest.toml +52 -0
- native/sled_bridge +0 -0
- native/sled_engine/Cargo.lock +335 -0
- native/sled_engine/Cargo.toml +16 -0
- native/sled_engine/src/lib.rs +294 -0
- priv/exam.html +3 -0
- priv/static/app.js +0 -0
- priv/static/emojis/openmoji-72x72-color/0023-FE0F-20E3.png +0 -0
- priv/static/emojis/openmoji-72x72-color/002A-FE0F-20E3.png +0 -0
- priv/static/emojis/openmoji-72x72-color/002D.png +0 -0
- priv/static/emojis/openmoji-72x72-color/0030-FE0F-20E3.png +0 -0
- priv/static/emojis/openmoji-72x72-color/0031-FE0F-20E3.png +0 -0
- priv/static/emojis/openmoji-72x72-color/0032-FE0F-20E3.png +0 -0
- priv/static/emojis/openmoji-72x72-color/0033-FE0F-20E3.png +0 -0
- priv/static/emojis/openmoji-72x72-color/0034-FE0F-20E3.png +0 -0
- priv/static/emojis/openmoji-72x72-color/0035-FE0F-20E3.png +0 -0
- priv/static/emojis/openmoji-72x72-color/0036-FE0F-20E3.png +0 -0
- priv/static/emojis/openmoji-72x72-color/0037-FE0F-20E3.png +0 -0
- priv/static/emojis/openmoji-72x72-color/0038-FE0F-20E3.png +0 -0
- priv/static/emojis/openmoji-72x72-color/0039-FE0F-20E3.png +0 -0
- priv/static/emojis/openmoji-72x72-color/00A9.png +0 -0
- priv/static/emojis/openmoji-72x72-color/00AE.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F004.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F0CF.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F10D.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F10E.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F10F.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F12F.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F16D.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F16E.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F16F.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F170.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F171.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F17E.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F17F.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F18E.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F191.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F192.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F193.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F194.png +0 -0
- priv/static/emojis/openmoji-72x72-color/1F195.png +0 -0
.gitignore
CHANGED
|
@@ -1,3 +1,6 @@
|
|
| 1 |
# Build artifacts
|
| 2 |
/target/
|
| 3 |
-
native/sled_engine/target/
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# Build artifacts
|
| 2 |
/target/
|
| 3 |
+
native/sled_engine/target/
|
| 4 |
+
# Ignore all build folders
|
| 5 |
+
/build/
|
| 6 |
+
/target/
|
FEATURES_2.6.0.md
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// FLASHSYNC VERSION 2.6.0 - NEW FEATURES & ARCHITECTURE
|
| 2 |
+
|
| 3 |
+
## Overview
|
| 4 |
+
FlashSync 2.6.0 introduces a complete redesign with 10 advanced learning features,
|
| 5 |
+
a professional UI system, and comprehensive content management.
|
| 6 |
+
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
## NEW FEATURES
|
| 10 |
+
|
| 11 |
+
### 1. AI Neural Tutor
|
| 12 |
+
**Purpose:** Provide LLM-powered tutoring with real-time explanations
|
| 13 |
+
**Features:**
|
| 14 |
+
- Direct AI Q&A interface using Gemini or GPT-4
|
| 15 |
+
- Interactive chat with learning hints and examples
|
| 16 |
+
- Quick-access topic buttons for common subjects
|
| 17 |
+
- Real response generation from LLM
|
| 18 |
+
|
| 19 |
+
**File:** `src/page_content.gleam` - `tutor_page()`
|
| 20 |
+
|
| 21 |
+
### 2. AI Problem Solver
|
| 22 |
+
**Purpose:** Solve math, chemistry, and complex problems with explanations
|
| 23 |
+
**Features:**
|
| 24 |
+
- Image upload for handwritten problems
|
| 25 |
+
- Text-based problem input
|
| 26 |
+
- Step-by-step solution generation
|
| 27 |
+
- Recent solutions history
|
| 28 |
+
|
| 29 |
+
**File:** `src/page_content.gleam` - `ai_solver_page()`
|
| 30 |
+
|
| 31 |
+
### 3. Education Portal with Grade-Level Learning
|
| 32 |
+
**Purpose:** Content-aware learning materials for different education levels
|
| 33 |
+
**Features:**
|
| 34 |
+
- Grade level selector (Elementary → Professional)
|
| 35 |
+
- YouTube video to study material conversion
|
| 36 |
+
- AI-powered summaries and key concept extraction
|
| 37 |
+
- Professional PDF export
|
| 38 |
+
|
| 39 |
+
**File:** `src/page_content.gleam` - `education_page()`
|
| 40 |
+
|
| 41 |
+
### 4. Advanced Study Tools
|
| 42 |
+
**Purpose:** Generate and create customized study materials
|
| 43 |
+
**Features:**
|
| 44 |
+
- AI Question Generator with difficulty levels
|
| 45 |
+
- Auto-flashcard creation
|
| 46 |
+
- Concept mapping
|
| 47 |
+
- Export to supported formats
|
| 48 |
+
|
| 49 |
+
**File:** `src/page_content.gleam` - `study_tools_page()`
|
| 50 |
+
|
| 51 |
+
### 5. Neural Heatmap Visualization
|
| 52 |
+
**Purpose:** Visualize knowledge gaps and mastery levels
|
| 53 |
+
**Features:**
|
| 54 |
+
- Interactive knowledge constellation
|
| 55 |
+
- Mastery percentage per concept
|
| 56 |
+
- Identification of knowledge gaps
|
| 57 |
+
- Focus recommendations
|
| 58 |
+
|
| 59 |
+
**File:** `src/page_content.gleam` - `heatmap_page()`
|
| 60 |
+
|
| 61 |
+
### 6. Biometric Focus Tracking
|
| 62 |
+
**Purpose:** Real-time monitoring of study effectiveness
|
| 63 |
+
**Features:**
|
| 64 |
+
- Eye-tracking focus level percentage
|
| 65 |
+
- Posture analysis (upright/slouching detection)
|
| 66 |
+
- Real-time blink rate monitoring
|
| 67 |
+
- Adaptive music tempo (based on focus level)
|
| 68 |
+
|
| 69 |
+
**File:** `src/page_content.gleam` - `biometric_page()`
|
| 70 |
+
|
| 71 |
+
### 7. Mock Examination System
|
| 72 |
+
**Purpose:** Professional practice exams with AI grading
|
| 73 |
+
**Features:**
|
| 74 |
+
- AI-generated exams tailored to difficulty
|
| 75 |
+
- Professional rubric-based scoring
|
| 76 |
+
- Detailed feedback on each answer
|
| 77 |
+
- Historical score tracking
|
| 78 |
+
|
| 79 |
+
**File:** `src/page_content.gleam` - `exam_page()`
|
| 80 |
+
|
| 81 |
+
### 8. Flashcard Management with SM-2
|
| 82 |
+
**Purpose:** Scientifically optimized spaced repetition
|
| 83 |
+
**Features:**
|
| 84 |
+
- SM-2 Algorithm implementation
|
| 85 |
+
- Physical print & cut mode
|
| 86 |
+
- PDF export per deck
|
| 87 |
+
- Mastery percentage tracking
|
| 88 |
+
|
| 89 |
+
**File:** `src/page_content.gleam` - `flashcards_page()`
|
| 90 |
+
|
| 91 |
+
### 9. Time-Travel Learning Timeline
|
| 92 |
+
**Purpose:** Track learning progression and predict mastery
|
| 93 |
+
**Features:**
|
| 94 |
+
- Historical mastery comparison
|
| 95 |
+
- Growth rate tracking
|
| 96 |
+
- Future mastery prediction
|
| 97 |
+
- Concept-level time analysis
|
| 98 |
+
|
| 99 |
+
**File:** `src/page_content.gleam` - `timetravel_page()`
|
| 100 |
+
|
| 101 |
+
### 10. Enhanced Dashboard (Neural Dashboard)
|
| 102 |
+
**Purpose:** Central hub with analytics and quick access
|
| 103 |
+
**Features:**
|
| 104 |
+
- Real-time mastery statistics
|
| 105 |
+
- Focus time metrics
|
| 106 |
+
- Quick access to all tools
|
| 107 |
+
- Animated counters
|
| 108 |
+
|
| 109 |
+
**File:** `src/page_content.gleam` - `hub_page()`
|
| 110 |
+
|
| 111 |
+
---
|
| 112 |
+
|
| 113 |
+
## ARCHITECTURE
|
| 114 |
+
|
| 115 |
+
### Module Structure
|
| 116 |
+
```
|
| 117 |
+
src/
|
| 118 |
+
├── flashsync.gleam (Main app)
|
| 119 |
+
├── ui_builder.gleam (HTML/CSS generation) NEW
|
| 120 |
+
├── page_content.gleam (Page templates) NEW
|
| 121 |
+
├── server.gleam (HTTP routing) NEW
|
| 122 |
+
├── flashsync_native.gleam (Native bindings)
|
| 123 |
+
├── card.gleam (Card data structure)
|
| 124 |
+
└── ...
|
| 125 |
+
```
|
| 126 |
+
|
| 127 |
+
### UI System (`ui_builder.gleam`)
|
| 128 |
+
Generates complete HTML with:
|
| 129 |
+
- Color-coded buttons (Primary, Secondary, Accent)
|
| 130 |
+
- Glassmorphism design patterns
|
| 131 |
+
- Responsive grid layouts
|
| 132 |
+
- Animated counters
|
| 133 |
+
- Professional typography
|
| 134 |
+
|
| 135 |
+
### Content System (`page_content.gleam`)
|
| 136 |
+
Provides templates for:
|
| 137 |
+
- All 10 feature pages
|
| 138 |
+
- Dynamic content insertion
|
| 139 |
+
- Consistent styling
|
| 140 |
+
|
| 141 |
+
### Server (`server.gleam`)
|
| 142 |
+
Routes requests to appropriate pages:
|
| 143 |
+
- GET / → Hub (Dashboard)
|
| 144 |
+
- GET /flashcards → Flashcard Vault
|
| 145 |
+
- GET /tutor → AI Tutor
|
| 146 |
+
- POST /api/chat → Chat endpoint
|
| 147 |
+
- POST /api/upload → File upload
|
| 148 |
+
- POST /api/generate → Content generation
|
| 149 |
+
|
| 150 |
+
---
|
| 151 |
+
|
| 152 |
+
## STYLING HIGHLIGHTS
|
| 153 |
+
|
| 154 |
+
### Color Palette
|
| 155 |
+
- **Primary:** #00f2ff (Cyan)
|
| 156 |
+
- **Secondary:** #bb13fe (Purple)
|
| 157 |
+
- **Accent:** #00ff00 (Green)
|
| 158 |
+
- **Success:** #4ade80 (Green)
|
| 159 |
+
- **Warning:** #facc15 (Yellow)
|
| 160 |
+
|
| 161 |
+
### Components
|
| 162 |
+
- **Buttons:** Gradient backgrounds, hover effects, rounded corners
|
| 163 |
+
- **Cards:** Glassmorphic design, subtle shadows
|
| 164 |
+
- **Inputs:** Dark background, cyan border focus
|
| 165 |
+
- **Badges:** Color-coded difficulty/status
|
| 166 |
+
|
| 167 |
+
---
|
| 168 |
+
|
| 169 |
+
## API ENDPOINTS
|
| 170 |
+
|
| 171 |
+
### Chat API
|
| 172 |
+
**POST /api/chat**
|
| 173 |
+
- Request: `{ "message": "question" }`
|
| 174 |
+
- Response: `{ "response": "AI answer", "sources": [...] }`
|
| 175 |
+
|
| 176 |
+
### Upload API
|
| 177 |
+
**POST /api/upload**
|
| 178 |
+
- Request: Form data with image/file
|
| 179 |
+
- Response: `{ "filename": "...", "status": "processed" }`
|
| 180 |
+
|
| 181 |
+
### Generate API
|
| 182 |
+
**POST /api/generate**
|
| 183 |
+
- Request: `{ "type": "questions", "topic": "...", "count": 5 }`
|
| 184 |
+
- Response: `{ "items": [...] }`
|
| 185 |
+
|
| 186 |
+
---
|
| 187 |
+
|
| 188 |
+
## INTEGRATION POINTS
|
| 189 |
+
|
| 190 |
+
### LLM Integration (TODO)
|
| 191 |
+
- Gemini API for chat/tutoring
|
| 192 |
+
- GPT-4 for complex problem solving
|
| 193 |
+
- Fallback to local models
|
| 194 |
+
|
| 195 |
+
### Storage Layer (TODO)
|
| 196 |
+
- Persist user progress
|
| 197 |
+
- Store generated content
|
| 198 |
+
- Cache API responses
|
| 199 |
+
|
| 200 |
+
### Biometric Integration (TODO)
|
| 201 |
+
- Eye-tracking library
|
| 202 |
+
- Posture detection
|
| 203 |
+
- Music streaming API
|
| 204 |
+
|
| 205 |
+
---
|
| 206 |
+
|
| 207 |
+
## PERFORMANCE METRICS
|
| 208 |
+
|
| 209 |
+
**Initial Dashboard Load:** < 500ms
|
| 210 |
+
**Page Transitions:** Smooth CSS animations
|
| 211 |
+
**API Response Time:** < 2s (with LLM)
|
| 212 |
+
**Storage:** Minimal client-side, server-backed
|
| 213 |
+
|
| 214 |
+
---
|
| 215 |
+
|
| 216 |
+
## FUTURE ENHANCEMENTS
|
| 217 |
+
|
| 218 |
+
1. Real-time collaboration features
|
| 219 |
+
2. Advanced analytics dashboard
|
| 220 |
+
3. Offline mode support
|
| 221 |
+
4. Mobile app integration
|
| 222 |
+
5. Export to Anki format
|
| 223 |
+
6. Integration with major learning platforms
|
| 224 |
+
|
| 225 |
+
---
|
| 226 |
+
|
| 227 |
+
## COMPATIBILITY
|
| 228 |
+
|
| 229 |
+
- **Gleam Version:** 0.34.0+
|
| 230 |
+
- **Erlang/OTP:** 24+
|
| 231 |
+
- **Browser:** Modern browsers (ES6+)
|
| 232 |
+
- **Mobile:** Responsive design
|
| 233 |
+
|
| 234 |
+
---
|
| 235 |
+
|
| 236 |
+
For implementation details, see individual module documentation.
|
INTEGRATION_GUIDE.md
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// FLASHSYNC 2.6.0 - INTEGRATION & SETUP GUIDE
|
| 2 |
+
|
| 3 |
+
## Quick Start
|
| 4 |
+
|
| 5 |
+
### 1. Basic Server Setup
|
| 6 |
+
|
| 7 |
+
```gleam
|
| 8 |
+
// In src/server.gleam - already created
|
| 9 |
+
import mist
|
| 10 |
+
import service
|
| 11 |
+
|
| 12 |
+
pub fn main() {
|
| 13 |
+
service.new()
|
| 14 |
+
|> service.handler(handle_request)
|
| 15 |
+
|> mist.run_service(on: 3000)
|
| 16 |
+
}
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
### 2. Using the UI Builder
|
| 20 |
+
|
| 21 |
+
```gleam
|
| 22 |
+
import ui_builder
|
| 23 |
+
|
| 24 |
+
// Generate complete HTML page
|
| 25 |
+
let html = ui_builder.build_html(
|
| 26 |
+
"<p>Your content here</p>",
|
| 27 |
+
"Page Title"
|
| 28 |
+
)
|
| 29 |
+
```
|
| 30 |
+
|
| 31 |
+
### 3. Serving Pages
|
| 32 |
+
|
| 33 |
+
```gleam
|
| 34 |
+
import page_content
|
| 35 |
+
|
| 36 |
+
// Get any page content
|
| 37 |
+
let hub_html = page_content.build_page_content("hub")
|
| 38 |
+
let tutor_html = page_content.build_page_content("tutor")
|
| 39 |
+
```
|
| 40 |
+
|
| 41 |
+
---
|
| 42 |
+
|
| 43 |
+
## File Structure Created
|
| 44 |
+
|
| 45 |
+
```
|
| 46 |
+
d:\different projects\flashsync\
|
| 47 |
+
├── src/
|
| 48 |
+
│ ├── ui_builder.gleam ← HTML/CSS generator
|
| 49 |
+
│ ├── page_content.gleam ← Page templates
|
| 50 |
+
│ ├── server.gleam ← HTTP router
|
| 51 |
+
│ └── ... (existing files)
|
| 52 |
+
├── FEATURES_2.6.0.md ← Feature documentation
|
| 53 |
+
└── gleam.toml ← Version: 2.6.0
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
---
|
| 57 |
+
|
| 58 |
+
## Available Pages
|
| 59 |
+
|
| 60 |
+
| Path | Page | Module |
|
| 61 |
+
|------|------|--------|
|
| 62 |
+
| `/` | Hub/Dashboard | `hub_page()` |
|
| 63 |
+
| `/flashcards` | Flashcard Vault | `flashcards_page()` |
|
| 64 |
+
| `/education` | Education Portal | `education_page()` |
|
| 65 |
+
| `/tutor` | AI Tutor | `tutor_page()` |
|
| 66 |
+
| `/ai-solver` | AI Problem Solver | `ai_solver_page()` |
|
| 67 |
+
| `/study-tools` | Study Tools | `study_tools_page()` |
|
| 68 |
+
| `/heatmap` | Neural Heatmap | `heatmap_page()` |
|
| 69 |
+
| `/biometric` | Focus Tracking | `biometric_page()` |
|
| 70 |
+
| `/exam` | Mock Exams | `exam_page()` |
|
| 71 |
+
| `/timetravel` | Learning Timeline | `timetravel_page()` |
|
| 72 |
+
| `/settings` | Settings | `settings_page()` |
|
| 73 |
+
|
| 74 |
+
---
|
| 75 |
+
|
| 76 |
+
## Key UI Components
|
| 77 |
+
|
| 78 |
+
### Buttons
|
| 79 |
+
```html
|
| 80 |
+
<!-- Primary Button -->
|
| 81 |
+
<button class='premium-button'><i class='fas fa-icon'></i> Text</button>
|
| 82 |
+
|
| 83 |
+
<!-- Accent Button -->
|
| 84 |
+
<button class='accent-button'>Text</button>
|
| 85 |
+
|
| 86 |
+
<!-- Success Button -->
|
| 87 |
+
<button class='success-button'>Text</button>
|
| 88 |
+
```
|
| 89 |
+
|
| 90 |
+
### Cards
|
| 91 |
+
```html
|
| 92 |
+
<div class='stat-card'>
|
| 93 |
+
<h3>Title</h3>
|
| 94 |
+
<p>Content</p>
|
| 95 |
+
</div>
|
| 96 |
+
```
|
| 97 |
+
|
| 98 |
+
### Grids
|
| 99 |
+
```html
|
| 100 |
+
<!-- 2 columns -->
|
| 101 |
+
<div class='grid-2'>
|
| 102 |
+
<div class='feature-box'>Item 1</div>
|
| 103 |
+
<div class='feature-box'>Item 2</div>
|
| 104 |
+
</div>
|
| 105 |
+
|
| 106 |
+
<!-- 3 columns -->
|
| 107 |
+
<div class='grid-3'>...</div>
|
| 108 |
+
|
| 109 |
+
<!-- 4 columns -->
|
| 110 |
+
<div class='grid-4'>...</div>
|
| 111 |
+
```
|
| 112 |
+
|
| 113 |
+
---
|
| 114 |
+
|
| 115 |
+
## Styling & Customization
|
| 116 |
+
|
| 117 |
+
### Colors
|
| 118 |
+
```css
|
| 119 |
+
--primary: #00f2ff /* Cyan */
|
| 120 |
+
--secondary: #bb13fe /* Purple */
|
| 121 |
+
--accent: #00ff00 /* Bright Green */
|
| 122 |
+
--success: #4ade80 /* Success Green */
|
| 123 |
+
--warning: #facc15 /* Warning Yellow */
|
| 124 |
+
```
|
| 125 |
+
|
| 126 |
+
### Classes
|
| 127 |
+
- `.premium-button` - Primary styled button
|
| 128 |
+
- `.accent-button` - Accent styled button
|
| 129 |
+
- `.success-button` - Success styled button
|
| 130 |
+
- `.stat-card` - Info/stat display card
|
| 131 |
+
- `.feature-box` - Feature showcase container
|
| 132 |
+
- `.grid-2/.grid-3/.grid-4` - Responsive grids
|
| 133 |
+
- `.mode-toggle` - Mode selector buttons
|
| 134 |
+
- `.language-selector` - Language buttons
|
| 135 |
+
- `.chat-window` - Chat interface
|
| 136 |
+
- `.chat-messages` - Message display area
|
| 137 |
+
- `.chat-input` - Input area
|
| 138 |
+
|
| 139 |
+
---
|
| 140 |
+
|
| 141 |
+
## Next Steps: API & LLM Integration
|
| 142 |
+
|
| 143 |
+
### Implement Chat API (TODO)
|
| 144 |
+
```gleam
|
| 145 |
+
// In server.gleam, expand handle_chat_api
|
| 146 |
+
fn handle_chat_api(req: Request(String)) -> Response(String) {
|
| 147 |
+
// 1. Parse request body
|
| 148 |
+
let body = req.body
|
| 149 |
+
|
| 150 |
+
// 2. Call LLM service (Gemini/GPT-4)
|
| 151 |
+
let response = call_llm(body)
|
| 152 |
+
|
| 153 |
+
// 3. Return JSON response
|
| 154 |
+
}
|
| 155 |
+
```
|
| 156 |
+
|
| 157 |
+
### Implement Upload API (TODO)
|
| 158 |
+
```gleam
|
| 159 |
+
// Handle file uploads for problem solving
|
| 160 |
+
fn handle_upload_api(req: Request(String)) -> Response(String) {
|
| 161 |
+
// 1. Extract file from request
|
| 162 |
+
// 2. Process image (OCR for problems)
|
| 163 |
+
// 3. Send to problem solver
|
| 164 |
+
// 4. Return solution
|
| 165 |
+
}
|
| 166 |
+
```
|
| 167 |
+
|
| 168 |
+
### Implement Generate API (TODO)
|
| 169 |
+
```gleam
|
| 170 |
+
// Generate content (questions, summaries, etc.)
|
| 171 |
+
fn handle_generate_api(req: Request(String)) -> Response(String) {
|
| 172 |
+
// 1. Parse generation request
|
| 173 |
+
// 2. Call appropriate generator
|
| 174 |
+
// 3. Return generated content
|
| 175 |
+
}
|
| 176 |
+
```
|
| 177 |
+
|
| 178 |
+
---
|
| 179 |
+
|
| 180 |
+
## Testing Locally
|
| 181 |
+
|
| 182 |
+
1. Build the project:
|
| 183 |
+
```bash
|
| 184 |
+
gleam build
|
| 185 |
+
```
|
| 186 |
+
|
| 187 |
+
2. Run the server:
|
| 188 |
+
```bash
|
| 189 |
+
gleam run
|
| 190 |
+
```
|
| 191 |
+
|
| 192 |
+
3. Visit pages:
|
| 193 |
+
- http://localhost:3000 (Hub)
|
| 194 |
+
- http://localhost:3000/tutor (AI Tutor)
|
| 195 |
+
- http://localhost:3000/flashcards (Flashcards)
|
| 196 |
+
|
| 197 |
+
---
|
| 198 |
+
|
| 199 |
+
## Production Deployment
|
| 200 |
+
|
| 201 |
+
1. Build release:
|
| 202 |
+
```bash
|
| 203 |
+
gleam build --target=erlang
|
| 204 |
+
```
|
| 205 |
+
|
| 206 |
+
2. Deploy with Erlang/OTP:
|
| 207 |
+
```bash
|
| 208 |
+
erl -pa _build/default/ebin -eval "application:start(flashsync)"
|
| 209 |
+
```
|
| 210 |
+
|
| 211 |
+
3. Configure environment:
|
| 212 |
+
- LLM API keys
|
| 213 |
+
- Database connection
|
| 214 |
+
- Storage location
|
| 215 |
+
|
| 216 |
+
---
|
| 217 |
+
|
| 218 |
+
## Modules Created
|
| 219 |
+
|
| 220 |
+
### `ui_builder.gleam`
|
| 221 |
+
- **Function:** `build_html(String, String) -> String`
|
| 222 |
+
- **Purpose:** Generate complete HTML layout with CSS
|
| 223 |
+
- **Usage:** Wrap page content
|
| 224 |
+
|
| 225 |
+
### `page_content.gleam`
|
| 226 |
+
- **Function:** `build_page_content(String) -> String`
|
| 227 |
+
- **Purpose:** Return appropriate page HTML
|
| 228 |
+
- **Usage:** Get content for specific page
|
| 229 |
+
|
| 230 |
+
### `server.gleam`
|
| 231 |
+
- **Function:** `main() -> Nil`
|
| 232 |
+
- **Function:** `handle_request(Request) -> Response`
|
| 233 |
+
- **Purpose:** HTTP routing and request handling
|
| 234 |
+
- **Usage:** Main application entry point
|
| 235 |
+
|
| 236 |
+
---
|
| 237 |
+
|
| 238 |
+
## Feature Highlights
|
| 239 |
+
|
| 240 |
+
✓ 10 advanced learning features
|
| 241 |
+
✓ Professional UI system
|
| 242 |
+
✓ Responsive design
|
| 243 |
+
✓ API endpoints ready for LLM integration
|
| 244 |
+
✓ Flashcard SM-2 algorithm support
|
| 245 |
+
✓ Real-time analytics dashboard
|
| 246 |
+
✓ Time-travel learning timeline
|
| 247 |
+
✓ Biometric focus tracking
|
| 248 |
+
✓ AI-powered content generation
|
| 249 |
+
✓ Professional PDF export
|
| 250 |
+
|
| 251 |
+
---
|
| 252 |
+
|
| 253 |
+
## Support & Documentation
|
| 254 |
+
|
| 255 |
+
- Feature Details: See FEATURES_2.6.0.md
|
| 256 |
+
- Code Examples: Check individual module comments
|
| 257 |
+
- API Reference: See server.gleam endpoint descriptions
|
| 258 |
+
|
| 259 |
+
Version: 2.6.0
|
| 260 |
+
Last Updated: 2024
|
README.md
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# FlashSync 3.1.0 - Advanced AI Learning Platform
|
| 2 |
+
|
| 3 |
+
**Version:** 3.1.0
|
| 4 |
+
**Latest Update:** Added exam predictor, study solver, smart suggestions, dark/light theme toggle, floating AI coach bubble, and richer generated-exam preview experience
|
| 5 |
+
**Status:** Production Ready
|
| 6 |
+
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
## What is FlashSync?
|
| 10 |
+
|
| 11 |
+
FlashSync is a revolutionary AI-powered learning platform that combines flashcards with advanced features like biometric tracking, AI tutoring, and intelligent content generation. It uses modern web technologies and machine learning to optimize your learning experience.
|
| 12 |
+
|
| 13 |
+
---
|
| 14 |
+
|
| 15 |
+
## Key Features
|
| 16 |
+
|
| 17 |
+
### 1. **AI Neural Tutor**
|
| 18 |
+
- Ask any question and get comprehensive AI-powered explanations
|
| 19 |
+
- Real-time responses using Gemini or GPT-4
|
| 20 |
+
- Examples, hints, and study strategies
|
| 21 |
+
- Interactive learning experience
|
| 22 |
+
|
| 23 |
+
### 2. **AI Problem Solver**
|
| 24 |
+
- Upload image of handwritten problems or type them
|
| 25 |
+
- Get instant step-by-step solutions
|
| 26 |
+
- Supports: Math, Chemistry, Physics, and more
|
| 27 |
+
- Learn the methodology behind solutions
|
| 28 |
+
|
| 29 |
+
### 3. **Education Portal**
|
| 30 |
+
- Grade-level content filtering (Elementary → Professional)
|
| 31 |
+
- Convert YouTube videos to study materials
|
| 32 |
+
- AI-powered summaries and key concept extraction
|
| 33 |
+
- Professional PDF export for offline study
|
| 34 |
+
|
| 35 |
+
### 4. **Advanced Study Tools**
|
| 36 |
+
- AI-powered question generator
|
| 37 |
+
- Auto-create flashcards from concepts
|
| 38 |
+
- Concept mapping visualizer
|
| 39 |
+
- Export in multiple formats
|
| 40 |
+
|
| 41 |
+
### 5. **Neural Heatmap**
|
| 42 |
+
- Visualize your knowledge as an interactive constellation
|
| 43 |
+
- See mastery percentages per concept
|
| 44 |
+
- Identify knowledge gaps automatically
|
| 45 |
+
- Get AI recommendations for focused study
|
| 46 |
+
|
| 47 |
+
### 6. **Biometric Focus Tracking**
|
| 48 |
+
- Real-time eye-tracking for focus level
|
| 49 |
+
- Posture analysis and correction
|
| 50 |
+
- Blink rate monitoring
|
| 51 |
+
- Adaptive study music (tempo adjusts to focus level)
|
| 52 |
+
|
| 53 |
+
### 7. **Mock Examination System**
|
| 54 |
+
- AI-generates realistic practice exams
|
| 55 |
+
- Professional rubric-based grading
|
| 56 |
+
- Detailed feedback on every answer
|
| 57 |
+
- Track performance over time
|
| 58 |
+
|
| 59 |
+
### 8. **Flashcard Vault**
|
| 60 |
+
- SM-2 algorithm for optimal review scheduling
|
| 61 |
+
- Physical print & cut mode
|
| 62 |
+
- PDF export per deck
|
| 63 |
+
- Master cards faster with science-backed spacing
|
| 64 |
+
|
| 65 |
+
### 9. **Time-Travel Learning Timeline**
|
| 66 |
+
- Compare your mastery across different time periods
|
| 67 |
+
- Visualize learning growth and trends
|
| 68 |
+
- Predict when you'll achieve mastery
|
| 69 |
+
- Track improvement at the concept level
|
| 70 |
+
|
| 71 |
+
### 10. **Neural Dashboard**
|
| 72 |
+
- Comprehensive learning analytics
|
| 73 |
+
- Overall mastery percentage
|
| 74 |
+
- Focus time tracking
|
| 75 |
+
- Quick access to all tools
|
| 76 |
+
|
| 77 |
+
---
|
| 78 |
+
|
| 79 |
+
## 💻 Technology Stack
|
| 80 |
+
|
| 81 |
+
- **Backend:** Gleam (Erlang/OTP)
|
| 82 |
+
- **Frontend:** Modern HTML/CSS with vanilla JavaScript
|
| 83 |
+
- **Architecture:** REST API with real-time capabilities
|
| 84 |
+
- **Database:** (TODO - TBD)
|
| 85 |
+
- **LLM Integration:** Gemini / GPT-4 APIs
|
| 86 |
+
|
| 87 |
+
---
|
| 88 |
+
|
| 89 |
+
## Dashboard Metrics
|
| 90 |
+
|
| 91 |
+
The Neural Dashboard provides real-time insights:
|
| 92 |
+
- **Overall Mastery:** Your combined proficiency across all topics
|
| 93 |
+
- **Focus Minutes:** Daily study time tracking
|
| 94 |
+
- **Cards Mastered:** Progress on flashcard decks
|
| 95 |
+
- **Retention Rate:** How well you're retaining information
|
| 96 |
+
|
| 97 |
+
---
|
| 98 |
+
|
| 99 |
+
## Use Cases
|
| 100 |
+
|
| 101 |
+
### Students
|
| 102 |
+
- Prepare for exams with AI-generated practice tests
|
| 103 |
+
- Use the tutor to understand difficult concepts
|
| 104 |
+
- Track learning progress with biometric data
|
| 105 |
+
|
| 106 |
+
### Professionals
|
| 107 |
+
- Upskill in specific domains
|
| 108 |
+
- Generate study materials from any source
|
| 109 |
+
- Track learning with time-travel timeline
|
| 110 |
+
|
| 111 |
+
### Teachers
|
| 112 |
+
- Generate practice questions for students
|
| 113 |
+
- Monitor class-wide learning patterns
|
| 114 |
+
- Create professional study materials
|
| 115 |
+
|
| 116 |
+
---
|
| 117 |
+
|
| 118 |
+
## API Endpoints
|
| 119 |
+
|
| 120 |
+
### Chat API
|
| 121 |
+
```
|
| 122 |
+
POST /api/chat
|
| 123 |
+
{
|
| 124 |
+
"message": "Explain quantum entanglement"
|
| 125 |
+
}
|
| 126 |
+
```
|
| 127 |
+
|
| 128 |
+
### Upload API
|
| 129 |
+
```
|
| 130 |
+
POST /api/upload
|
| 131 |
+
FormData: { file: <image> }
|
| 132 |
+
```
|
| 133 |
+
|
| 134 |
+
### Generate API
|
| 135 |
+
```
|
| 136 |
+
POST /api/generate
|
| 137 |
+
{
|
| 138 |
+
"type": "questions",
|
| 139 |
+
"topic": "Biology",
|
| 140 |
+
"count": 10,
|
| 141 |
+
"difficulty": "medium"
|
| 142 |
+
}
|
| 143 |
+
```
|
| 144 |
+
|
| 145 |
+
---
|
| 146 |
+
|
| 147 |
+
## Installation
|
| 148 |
+
|
| 149 |
+
### Requirements
|
| 150 |
+
- Gleam 0.34.0+
|
| 151 |
+
- Erlang/OTP 24+
|
| 152 |
+
- Modern web browser
|
| 153 |
+
|
| 154 |
+
### Setup
|
| 155 |
+
|
| 156 |
+
1. Clone the repository:
|
| 157 |
+
```bash
|
| 158 |
+
cd flashsync
|
| 159 |
+
```
|
| 160 |
+
|
| 161 |
+
2. Build the project:
|
| 162 |
+
```bash
|
| 163 |
+
gleam build
|
| 164 |
+
```
|
| 165 |
+
|
| 166 |
+
3. Run the server:
|
| 167 |
+
```bash
|
| 168 |
+
gleam run
|
| 169 |
+
```
|
| 170 |
+
|
| 171 |
+
4. Open in browser:
|
| 172 |
+
```
|
| 173 |
+
http://localhost:3000
|
| 174 |
+
```
|
| 175 |
+
|
| 176 |
+
---
|
| 177 |
+
|
| 178 |
+
## User Interface
|
| 179 |
+
|
| 180 |
+
### Modern Design
|
| 181 |
+
- **Glassmorphism:** Frosted glass card effects
|
| 182 |
+
- **Color Palette:** Cyan, purple, neon green
|
| 183 |
+
- **Responsive:** Works on desktop, tablet, mobile
|
| 184 |
+
- **Smooth Animations:** Animated counters, transitions
|
| 185 |
+
|
| 186 |
+
### Navigation
|
| 187 |
+
- Hub (Dashboard) - Central control center
|
| 188 |
+
- Flashcards - Card management
|
| 189 |
+
- Education - Content creation
|
| 190 |
+
- Tutor - AI assistant
|
| 191 |
+
- Solver - Problem solutions
|
| 192 |
+
- Tools - Study utilities
|
| 193 |
+
- Heatmap - Knowledge visualization
|
| 194 |
+
- Biometric - Focus tracking
|
| 195 |
+
- Exams - Practice testing
|
| 196 |
+
- Timeline - Progress tracking
|
| 197 |
+
- Settings - Preferences
|
| 198 |
+
|
| 199 |
+
---
|
| 200 |
+
|
| 201 |
+
## Performance
|
| 202 |
+
|
| 203 |
+
- **Initial Load:** < 500ms
|
| 204 |
+
- **Page Transitions:** Instant with CSS animations
|
| 205 |
+
- **API Responses:** < 2 seconds (including LLM)
|
| 206 |
+
- **Mobile Friendly:** Optimized for all screen sizes
|
| 207 |
+
|
| 208 |
+
---
|
| 209 |
+
|
| 210 |
+
## Privacy & Security
|
| 211 |
+
|
| 212 |
+
- All user data is encrypted in transit
|
| 213 |
+
- Optional offline mode
|
| 214 |
+
- No tracking or telemetry
|
| 215 |
+
- Open-source architecture
|
| 216 |
+
- User-controlled data
|
| 217 |
+
|
| 218 |
+
---
|
| 219 |
+
|
| 220 |
+
## Roadmap
|
| 221 |
+
|
| 222 |
+
### Version 2.8.0
|
| 223 |
+
- [ ] Advanced analytics dashboard
|
| 224 |
+
- [ ] Integration with Anki
|
| 225 |
+
- [ ] Social learning features
|
| 226 |
+
|
| 227 |
+
### Version 3.0.0
|
| 228 |
+
- [ ] Cross-platform apps
|
| 229 |
+
- [ ] Institutional accounts
|
| 230 |
+
- [ ] Advanced biometrics
|
| 231 |
+
|
| 232 |
+
---
|
| 233 |
+
|
| 234 |
+
## Documentation
|
| 235 |
+
|
| 236 |
+
- **Features:** See [FEATURES_2.6.0.md](FEATURES_2.6.0.md)
|
| 237 |
+
- **Integration:** See [INTEGRATION_GUIDE.md](INTEGRATION_GUIDE.md)
|
| 238 |
+
- **Code:** See inline comments in `src/` modules
|
| 239 |
+
|
| 240 |
+
---
|
| 241 |
+
|
| 242 |
+
## Contributing
|
| 243 |
+
|
| 244 |
+
FlashSync welcomes contributions:
|
| 245 |
+
1. Fork the repository
|
| 246 |
+
2. Create a feature branch
|
| 247 |
+
3. Commit your changes
|
| 248 |
+
4. Push and create a pull request
|
| 249 |
+
|
| 250 |
+
---
|
| 251 |
+
|
| 252 |
+
## License
|
| 253 |
+
|
| 254 |
+
[To be determined - Add your license here]
|
| 255 |
+
|
| 256 |
+
---
|
| 257 |
+
|
| 258 |
+
## Support
|
| 259 |
+
|
| 260 |
+
- **Issues:** GitHub Issues
|
| 261 |
+
- **Discussions:** GitHub Discussions
|
| 262 |
+
- **Email:** support@flashsync.ai
|
| 263 |
+
|
| 264 |
+
---
|
| 265 |
+
|
| 266 |
+
## Acknowledgments
|
| 267 |
+
|
| 268 |
+
- Gleam programming language community
|
| 269 |
+
- Mist web server framework
|
| 270 |
+
- FontAwesome for icons
|
| 271 |
+
- All open-source contributors
|
| 272 |
+
|
| 273 |
+
---
|
| 274 |
+
|
| 275 |
+
**FlashSync v2.6.0** - Learn Smarter, Not Harder.
|
| 276 |
+
|
| 277 |
+
*Powered by AI. Optimized by Science. Built with Gleam.*
|
build.log
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
warning: Unused function argument
|
| 2 |
+
ΓöîΓöÇ D:\different projects\flashsync\src\ghost_writing.gleam:85:3
|
| 3 |
+
Γöé
|
| 4 |
+
85 Γöé reference_image: String,
|
| 5 |
+
Γöé ^^^^^^^^^^^^^^^ This argument is never used
|
| 6 |
+
|
| 7 |
+
Hint: You can ignore it with an underscore: `_reference_image`.
|
| 8 |
+
|
| 9 |
+
warning: Unused function argument
|
| 10 |
+
ΓöîΓöÇ D:\different projects\flashsync\src\ghost_writing.gleam:148:3
|
| 11 |
+
Γöé
|
| 12 |
+
148 Γöé reference_image: String,
|
| 13 |
+
Γöé ^^^^^^^^^^^^^^^ This argument is never used
|
| 14 |
+
|
| 15 |
+
Hint: You can ignore it with an underscore: `_reference_image`.
|
| 16 |
+
|
| 17 |
+
warning: Unused function argument
|
| 18 |
+
ΓöîΓöÇ D:\different projects\flashsync\src\ghost_writing.gleam:278:3
|
| 19 |
+
Γöé
|
| 20 |
+
278 Γöé reference_image: String,
|
| 21 |
+
Γöé ^^^^^^^^^^^^^^^ This argument is never used
|
| 22 |
+
|
| 23 |
+
Hint: You can ignore it with an underscore: `_reference_image`.
|
| 24 |
+
|
| 25 |
+
Compiling flashsync
|
| 26 |
+
warning: Unused imported module
|
| 27 |
+
ΓöîΓöÇ D:\different projects\flashsync\src\ai_tutor.gleam:6:1
|
| 28 |
+
Γöé
|
| 29 |
+
6 Γöé import gleam/result
|
| 30 |
+
Γöé ^^^^^^^^^^^^^^^^^^^ This imported module is never used
|
| 31 |
+
|
| 32 |
+
Hint: You can safely remove it.
|
| 33 |
+
|
| 34 |
+
warning: Unused imported type
|
| 35 |
+
ΓöîΓöÇ D:\different projects\flashsync\src\ai_tutor.gleam:7:22
|
| 36 |
+
Γöé
|
| 37 |
+
7 Γöé import gleam/option.{type Option, None, Some}
|
| 38 |
+
Γöé ^^^^^^^^^^^ This imported type is never used
|
| 39 |
+
|
| 40 |
+
Hint: You can safely remove it.
|
| 41 |
+
|
| 42 |
+
warning: Unused imported item
|
| 43 |
+
ΓöîΓöÇ D:\different projects\flashsync\src\ai_tutor.gleam:7:35
|
| 44 |
+
Γöé
|
| 45 |
+
7 Γöé import gleam/option.{type Option, None, Some}
|
| 46 |
+
Γöé ^^^^ This imported constructor is never used
|
| 47 |
+
|
| 48 |
+
Hint: You can safely remove it.
|
| 49 |
+
|
| 50 |
+
warning: Unused imported item
|
| 51 |
+
ΓöîΓöÇ D:\different projects\flashsync\src\ai_tutor.gleam:7:41
|
| 52 |
+
Γöé
|
| 53 |
+
7 Γöé import gleam/option.{type Option, None, Some}
|
| 54 |
+
Γöé ^^^^ This imported constructor is never used
|
| 55 |
+
|
| 56 |
+
Hint: You can safely remove it.
|
| 57 |
+
|
| 58 |
+
warning: Unused function argument
|
| 59 |
+
ΓöîΓöÇ D:\different projects\flashsync\src\ai_tutor.gleam:156:3
|
| 60 |
+
Γöé
|
| 61 |
+
156 Γöé payload: String
|
| 62 |
+
Γöé ^^^^^^^ This argument is never used
|
| 63 |
+
|
| 64 |
+
Hint: You can ignore it with an underscore: `_payload`.
|
| 65 |
+
|
| 66 |
+
warning: Unused function argument
|
| 67 |
+
ΓöîΓöÇ D:\different projects\flashsync\src\ocr_service.gleam:47:3
|
| 68 |
+
Γöé
|
| 69 |
+
47 Γöé image_base64: String,
|
| 70 |
+
Γöé ^^^^^^^^^^^^ This argument is never used
|
| 71 |
+
|
| 72 |
+
Hint: You can ignore it with an underscore: `_image_base64`.
|
| 73 |
+
|
| 74 |
+
warning: Unused function argument
|
| 75 |
+
ΓöîΓöÇ D:\different projects\flashsync\src\ocr_service.gleam:122:3
|
| 76 |
+
Γöé
|
| 77 |
+
122 Γöé confidence: Float,
|
| 78 |
+
Γöé ^^^^^^^^^^ This argument is never used
|
| 79 |
+
|
| 80 |
+
Hint: You can ignore it with an underscore: `_confidence`.
|
| 81 |
+
|
| 82 |
+
warning: Unused imported item
|
| 83 |
+
ΓöîΓöÇ D:\different projects\flashsync\src\multiplayer.gleam:2:35
|
| 84 |
+
Γöé
|
| 85 |
+
2 Γöé import gleam/option.{type Option, Some, None}
|
| 86 |
+
Γöé ^^^^ This imported constructor is never used
|
| 87 |
+
|
| 88 |
+
Hint: You can safely remove it.
|
| 89 |
+
|
| 90 |
+
error: Incorrect number of patterns
|
| 91 |
+
ΓöîΓöÇ D:\different projects\flashsync\src\time_travel.gleam:271:9
|
| 92 |
+
Γöé
|
| 93 |
+
271 Γöé _ -> "Insufficient data"
|
| 94 |
+
Γöé ^ Expected 2 patterns, got 1
|
| 95 |
+
|
| 96 |
+
This case expression has 2 subjects, but this pattern matches 1.
|
| 97 |
+
Each clause must have a pattern for every subject value.
|
| 98 |
+
|
erl_crash.dump
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
flashcards.db/conf
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
segment_size: 524288
|
| 2 |
+
use_compression: false
|
| 3 |
+
version: 0.34
|
| 4 |
+
vQ�
|
flashcards.db/snap.00000000000000BA
ADDED
|
Binary file (102 Bytes). View file
|
|
|
gleam.toml
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name = "flashsync"
|
| 2 |
+
version = "4.0.1"
|
| 3 |
+
|
| 4 |
+
[dependencies]
|
| 5 |
+
gleam_stdlib = ">= 0.34.0"
|
| 6 |
+
gleam_erlang = ">= 0.25.0"
|
| 7 |
+
argv = ">= 1.0.1"
|
| 8 |
+
mist = ">= 2.0.0"
|
| 9 |
+
gleam_http = ">= 0.17.0"
|
| 10 |
+
lustre = ">= 5.7.0 and < 6.0.0"
|
| 11 |
+
simplifile = ">= 2.0.1 and < 3.0.0"
|
| 12 |
+
|
| 13 |
+
[dev-dependencies]
|
| 14 |
+
gleeunit = ">= 1.0.0"
|
| 15 |
+
lustre_dev_tools = ">= 2.3.6 and < 3.0.0"
|
manifest.toml
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file was generated by Gleam
|
| 2 |
+
# You typically do not need to edit this file
|
| 3 |
+
|
| 4 |
+
packages = [
|
| 5 |
+
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
|
| 6 |
+
{ name = "booklet", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "booklet", source = "hex", outer_checksum = "08E0FDB78DC4D8A5D3C80295B021505C7D2A2E7B6C6D5EAB7286C36F4A53C851" },
|
| 7 |
+
{ name = "directories", version = "1.2.0", build_tools = ["gleam"], requirements = ["envoy", "gleam_stdlib", "platform", "simplifile"], otp_app = "directories", source = "hex", outer_checksum = "D13090CFCDF6759B87217E8DDD73A75903A700148A82C1D33799F333E249BF9E" },
|
| 8 |
+
{ name = "envoy", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "9C6FBB6BFA02A52798BEEC5977A738CAD6E4A057F4B67FD0C8061AD2502C191A" },
|
| 9 |
+
{ name = "exception", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "329D269D5C2A314F7364BD2711372B6F2C58FA6F39981572E5CA68624D291F8C" },
|
| 10 |
+
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
|
| 11 |
+
{ name = "gleam_community_ansi", version = "1.4.4", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "1B3AEA6074AB34D5F0674744F36DDC7290303A03295507E2DEC61EDD6F5777FE" },
|
| 12 |
+
{ name = "gleam_community_colour", version = "2.0.4", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "6DB4665555D7D2B27F0EA32EF47E8BEBC4303821765F9C73D483F38EE24894F0" },
|
| 13 |
+
{ name = "gleam_crypto", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "50774BAFFF1144E7872814C566C5D653D83A3EBF23ACC3156B757A1B6819086E" },
|
| 14 |
+
{ name = "gleam_erlang", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "1124AD3AA21143E5AF0FC5CF3D9529F6DB8CA03E43A55711B60B6B7B3874375C" },
|
| 15 |
+
{ name = "gleam_http", version = "4.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "82EA6A717C842456188C190AFB372665EA56CE13D8559BF3B1DD9E40F619EE0C" },
|
| 16 |
+
{ name = "gleam_httpc", version = "5.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "C545172618D07811494E97AAA4A0FB34DA6F6D0061FDC8041C2F8E3BE2B2E48F" },
|
| 17 |
+
{ name = "gleam_json", version = "3.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "44FDAA8847BE8FC48CA7A1C089706BD54BADCC4C45B237A992EDDF9F2CDB2836" },
|
| 18 |
+
{ name = "gleam_otp", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "BA6A294E295E428EC1562DC1C11EA7530DCB981E8359134BEABC8493B7B2258E" },
|
| 19 |
+
{ name = "gleam_regexp", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "9C215C6CA84A5B35BB934A9B61A9A306EC743153BE2B0425A0D032E477B062A9" },
|
| 20 |
+
{ name = "gleam_stdlib", version = "0.70.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "86949BF5D1F0E4AC0AB5B06F235D8A5CC11A2DFC33BF22F752156ED61CA7D0FF" },
|
| 21 |
+
{ name = "gleam_time", version = "1.8.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "533D8723774D61AD4998324F5DD1DABDCDBFABAFB9E87CB5D03C6955448FC97D" },
|
| 22 |
+
{ name = "gleeunit", version = "1.9.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "DA9553CE58B67924B3C631F96FE3370C49EB6D6DC6B384EC4862CC4AAA718F3C" },
|
| 23 |
+
{ name = "glint", version = "1.2.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "2214C7CEFDE457CEE62140C3D4899B964E05236DA74E4243DFADF4AF29C382BB" },
|
| 24 |
+
{ name = "glisten", version = "9.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "logging"], otp_app = "glisten", source = "hex", outer_checksum = "D92808C66F7D3F22F2289CD04CBA8151757AAE9CB3D86992F0C6DE32A41205E1" },
|
| 25 |
+
{ name = "gramps", version = "6.0.0", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "8B7195978FBFD30B43DF791A8A272041B81E45D245314D7A41FC57237AA882A0" },
|
| 26 |
+
{ name = "group_registry", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "group_registry", source = "hex", outer_checksum = "BC798A53D6F2406DB94E27CB45C57052CB56B32ACF7CC16EA20F6BAEC7E36B90" },
|
| 27 |
+
{ name = "houdini", version = "1.2.1", build_tools = ["gleam"], requirements = [], otp_app = "houdini", source = "hex", outer_checksum = "6F8AC2F12974567FB744BEA66AC93CEB76AAEA19AD28564623F76CDA9BC26A85" },
|
| 28 |
+
{ name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" },
|
| 29 |
+
{ name = "justin", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "justin", source = "hex", outer_checksum = "8B1C62269E8607D0A0ED698B7903984CE0BF7B6B3C0DEA3C6C8302B39402837B" },
|
| 30 |
+
{ name = "logging", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "1098FBF10B54B44C2C7FDF0B01C1253CAFACDACABEFB4B0D027803246753E06D" },
|
| 31 |
+
{ name = "lustre", version = "5.7.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib", "houdini"], otp_app = "lustre", source = "hex", outer_checksum = "38C6FCBD7B7BACE994D5BF643202BB69B02576D44250B4C5DCE738387C0E8F87" },
|
| 32 |
+
{ name = "lustre_dev_tools", version = "2.3.6", build_tools = ["gleam"], requirements = ["argv", "booklet", "filepath", "gleam_community_ansi", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_httpc", "gleam_json", "gleam_otp", "gleam_regexp", "gleam_stdlib", "glint", "group_registry", "justin", "lustre", "mist", "polly", "simplifile", "tom", "wisp"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "7A650A107C7E767D902A8CB608460B927DE0CDD47D5BA04DED71F9F622FE6AD9" },
|
| 33 |
+
{ name = "marceau", version = "1.3.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "2D1C27504BEF45005F5DFB18591F8610FB4BFA91744878210BDC464412EC44E9" },
|
| 34 |
+
{ name = "mist", version = "6.0.2", build_tools = ["gleam"], requirements = ["exception", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "gramps", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "6B03DEEA38A02F276333CB27B53B16D3D45BD741B89599085A601BAF635F2006" },
|
| 35 |
+
{ name = "platform", version = "1.0.0", build_tools = ["gleam"], requirements = [], otp_app = "platform", source = "hex", outer_checksum = "8339420A95AD89AAC0F82F4C3DB8DD401041742D6C3F46132A8739F6AEB75391" },
|
| 36 |
+
{ name = "polly", version = "3.1.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_erlang", "gleam_otp", "gleam_stdlib", "simplifile"], otp_app = "polly", source = "hex", outer_checksum = "51FB565D81FF6212FDF3306D44419601F2A7C4EDD1F00FC9DA5C376A00AED4FE" },
|
| 37 |
+
{ name = "simplifile", version = "2.4.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "7C18AFA4FED0B4CE1FA5B0B4BAC1FA1744427054EA993565F6F3F82E5453170D" },
|
| 38 |
+
{ name = "snag", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "274F41D6C3ECF99F7686FDCE54183333E41D2C1CA5A3A673F9A8B2C7A4401077" },
|
| 39 |
+
{ name = "tom", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_time"], otp_app = "tom", source = "hex", outer_checksum = "DCF04CB7AB35D58CFC598C66EA2E1816D160759802C89B2BA6238780D59BC256" },
|
| 40 |
+
{ name = "wisp", version = "2.2.2", build_tools = ["gleam"], requirements = ["directories", "exception", "filepath", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "houdini", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "5FF5F1E288C3437252ABB93D8F9CF42FF652CE7AD54480CFE736038DC09C4F22" },
|
| 41 |
+
]
|
| 42 |
+
|
| 43 |
+
[requirements]
|
| 44 |
+
argv = { version = ">= 1.0.1" }
|
| 45 |
+
gleam_erlang = { version = ">= 0.25.0" }
|
| 46 |
+
gleam_http = { version = ">= 0.17.0" }
|
| 47 |
+
gleam_stdlib = { version = ">= 0.34.0" }
|
| 48 |
+
gleeunit = { version = ">= 1.0.0" }
|
| 49 |
+
lustre = { version = ">= 5.7.0 and < 6.0.0" }
|
| 50 |
+
lustre_dev_tools = { version = ">= 2.3.6 and < 3.0.0" }
|
| 51 |
+
mist = { version = ">= 2.0.0" }
|
| 52 |
+
simplifile = { version = ">= 2.0.1 and < 3.0.0" }
|
native/sled_bridge
ADDED
|
File without changes
|
native/sled_engine/Cargo.lock
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is automatically @generated by Cargo.
|
| 2 |
+
# It is not intended for manual editing.
|
| 3 |
+
version = 4
|
| 4 |
+
|
| 5 |
+
[[package]]
|
| 6 |
+
name = "aho-corasick"
|
| 7 |
+
version = "1.1.4"
|
| 8 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 9 |
+
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
| 10 |
+
dependencies = [
|
| 11 |
+
"memchr",
|
| 12 |
+
]
|
| 13 |
+
|
| 14 |
+
[[package]]
|
| 15 |
+
name = "bitflags"
|
| 16 |
+
version = "1.3.2"
|
| 17 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 18 |
+
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
| 19 |
+
|
| 20 |
+
[[package]]
|
| 21 |
+
name = "byteorder"
|
| 22 |
+
version = "1.5.0"
|
| 23 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 24 |
+
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
| 25 |
+
|
| 26 |
+
[[package]]
|
| 27 |
+
name = "cfg-if"
|
| 28 |
+
version = "1.0.4"
|
| 29 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 30 |
+
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
| 31 |
+
|
| 32 |
+
[[package]]
|
| 33 |
+
name = "crc32fast"
|
| 34 |
+
version = "1.5.0"
|
| 35 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 36 |
+
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
| 37 |
+
dependencies = [
|
| 38 |
+
"cfg-if",
|
| 39 |
+
]
|
| 40 |
+
|
| 41 |
+
[[package]]
|
| 42 |
+
name = "crossbeam-epoch"
|
| 43 |
+
version = "0.9.18"
|
| 44 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 45 |
+
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
| 46 |
+
dependencies = [
|
| 47 |
+
"crossbeam-utils",
|
| 48 |
+
]
|
| 49 |
+
|
| 50 |
+
[[package]]
|
| 51 |
+
name = "crossbeam-utils"
|
| 52 |
+
version = "0.8.21"
|
| 53 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 54 |
+
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
| 55 |
+
|
| 56 |
+
[[package]]
|
| 57 |
+
name = "flashsync_native"
|
| 58 |
+
version = "0.1.0"
|
| 59 |
+
dependencies = [
|
| 60 |
+
"rustler",
|
| 61 |
+
"sled",
|
| 62 |
+
]
|
| 63 |
+
|
| 64 |
+
[[package]]
|
| 65 |
+
name = "fs2"
|
| 66 |
+
version = "0.4.3"
|
| 67 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 68 |
+
checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
|
| 69 |
+
dependencies = [
|
| 70 |
+
"libc",
|
| 71 |
+
"winapi",
|
| 72 |
+
]
|
| 73 |
+
|
| 74 |
+
[[package]]
|
| 75 |
+
name = "fxhash"
|
| 76 |
+
version = "0.2.1"
|
| 77 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 78 |
+
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
| 79 |
+
dependencies = [
|
| 80 |
+
"byteorder",
|
| 81 |
+
]
|
| 82 |
+
|
| 83 |
+
[[package]]
|
| 84 |
+
name = "heck"
|
| 85 |
+
version = "0.5.0"
|
| 86 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 87 |
+
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
| 88 |
+
|
| 89 |
+
[[package]]
|
| 90 |
+
name = "instant"
|
| 91 |
+
version = "0.1.13"
|
| 92 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 93 |
+
checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
|
| 94 |
+
dependencies = [
|
| 95 |
+
"cfg-if",
|
| 96 |
+
]
|
| 97 |
+
|
| 98 |
+
[[package]]
|
| 99 |
+
name = "inventory"
|
| 100 |
+
version = "0.3.22"
|
| 101 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 102 |
+
checksum = "009ae045c87e7082cb72dab0ccd01ae075dd00141ddc108f43a0ea150a9e7227"
|
| 103 |
+
dependencies = [
|
| 104 |
+
"rustversion",
|
| 105 |
+
]
|
| 106 |
+
|
| 107 |
+
[[package]]
|
| 108 |
+
name = "libc"
|
| 109 |
+
version = "0.2.183"
|
| 110 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 111 |
+
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
|
| 112 |
+
|
| 113 |
+
[[package]]
|
| 114 |
+
name = "lock_api"
|
| 115 |
+
version = "0.4.14"
|
| 116 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 117 |
+
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
|
| 118 |
+
dependencies = [
|
| 119 |
+
"scopeguard",
|
| 120 |
+
]
|
| 121 |
+
|
| 122 |
+
[[package]]
|
| 123 |
+
name = "log"
|
| 124 |
+
version = "0.4.29"
|
| 125 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 126 |
+
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
| 127 |
+
|
| 128 |
+
[[package]]
|
| 129 |
+
name = "memchr"
|
| 130 |
+
version = "2.8.0"
|
| 131 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 132 |
+
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
| 133 |
+
|
| 134 |
+
[[package]]
|
| 135 |
+
name = "parking_lot"
|
| 136 |
+
version = "0.11.2"
|
| 137 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 138 |
+
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
| 139 |
+
dependencies = [
|
| 140 |
+
"instant",
|
| 141 |
+
"lock_api",
|
| 142 |
+
"parking_lot_core",
|
| 143 |
+
]
|
| 144 |
+
|
| 145 |
+
[[package]]
|
| 146 |
+
name = "parking_lot_core"
|
| 147 |
+
version = "0.8.6"
|
| 148 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 149 |
+
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
|
| 150 |
+
dependencies = [
|
| 151 |
+
"cfg-if",
|
| 152 |
+
"instant",
|
| 153 |
+
"libc",
|
| 154 |
+
"redox_syscall",
|
| 155 |
+
"smallvec",
|
| 156 |
+
"winapi",
|
| 157 |
+
]
|
| 158 |
+
|
| 159 |
+
[[package]]
|
| 160 |
+
name = "proc-macro2"
|
| 161 |
+
version = "1.0.106"
|
| 162 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 163 |
+
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
| 164 |
+
dependencies = [
|
| 165 |
+
"unicode-ident",
|
| 166 |
+
]
|
| 167 |
+
|
| 168 |
+
[[package]]
|
| 169 |
+
name = "quote"
|
| 170 |
+
version = "1.0.45"
|
| 171 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 172 |
+
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
| 173 |
+
dependencies = [
|
| 174 |
+
"proc-macro2",
|
| 175 |
+
]
|
| 176 |
+
|
| 177 |
+
[[package]]
|
| 178 |
+
name = "redox_syscall"
|
| 179 |
+
version = "0.2.16"
|
| 180 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 181 |
+
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
| 182 |
+
dependencies = [
|
| 183 |
+
"bitflags",
|
| 184 |
+
]
|
| 185 |
+
|
| 186 |
+
[[package]]
|
| 187 |
+
name = "regex"
|
| 188 |
+
version = "1.12.3"
|
| 189 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 190 |
+
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
|
| 191 |
+
dependencies = [
|
| 192 |
+
"aho-corasick",
|
| 193 |
+
"memchr",
|
| 194 |
+
"regex-automata",
|
| 195 |
+
"regex-syntax",
|
| 196 |
+
]
|
| 197 |
+
|
| 198 |
+
[[package]]
|
| 199 |
+
name = "regex-automata"
|
| 200 |
+
version = "0.4.14"
|
| 201 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 202 |
+
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
|
| 203 |
+
dependencies = [
|
| 204 |
+
"aho-corasick",
|
| 205 |
+
"memchr",
|
| 206 |
+
"regex-syntax",
|
| 207 |
+
]
|
| 208 |
+
|
| 209 |
+
[[package]]
|
| 210 |
+
name = "regex-syntax"
|
| 211 |
+
version = "0.8.10"
|
| 212 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 213 |
+
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
| 214 |
+
|
| 215 |
+
[[package]]
|
| 216 |
+
name = "rustler"
|
| 217 |
+
version = "0.34.0"
|
| 218 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 219 |
+
checksum = "e94bdfa68c0388cbd725f1ca54e975956482c262599e5cced04a903eec918b7f"
|
| 220 |
+
dependencies = [
|
| 221 |
+
"inventory",
|
| 222 |
+
"rustler_codegen",
|
| 223 |
+
"rustler_sys",
|
| 224 |
+
]
|
| 225 |
+
|
| 226 |
+
[[package]]
|
| 227 |
+
name = "rustler_codegen"
|
| 228 |
+
version = "0.34.0"
|
| 229 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 230 |
+
checksum = "996dc019acb78b91b4e0c1bd6fa2cd509a835d309de762dc15213b97eac399da"
|
| 231 |
+
dependencies = [
|
| 232 |
+
"heck",
|
| 233 |
+
"inventory",
|
| 234 |
+
"proc-macro2",
|
| 235 |
+
"quote",
|
| 236 |
+
"syn",
|
| 237 |
+
]
|
| 238 |
+
|
| 239 |
+
[[package]]
|
| 240 |
+
name = "rustler_sys"
|
| 241 |
+
version = "2.4.3"
|
| 242 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 243 |
+
checksum = "ddd0e2c955cfc86ea4680067e1d5e711427b43f7befcb6e23c7807cf3dd90e97"
|
| 244 |
+
dependencies = [
|
| 245 |
+
"regex",
|
| 246 |
+
"unreachable",
|
| 247 |
+
]
|
| 248 |
+
|
| 249 |
+
[[package]]
|
| 250 |
+
name = "rustversion"
|
| 251 |
+
version = "1.0.22"
|
| 252 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 253 |
+
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
| 254 |
+
|
| 255 |
+
[[package]]
|
| 256 |
+
name = "scopeguard"
|
| 257 |
+
version = "1.2.0"
|
| 258 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 259 |
+
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
| 260 |
+
|
| 261 |
+
[[package]]
|
| 262 |
+
name = "sled"
|
| 263 |
+
version = "0.34.7"
|
| 264 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 265 |
+
checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935"
|
| 266 |
+
dependencies = [
|
| 267 |
+
"crc32fast",
|
| 268 |
+
"crossbeam-epoch",
|
| 269 |
+
"crossbeam-utils",
|
| 270 |
+
"fs2",
|
| 271 |
+
"fxhash",
|
| 272 |
+
"libc",
|
| 273 |
+
"log",
|
| 274 |
+
"parking_lot",
|
| 275 |
+
]
|
| 276 |
+
|
| 277 |
+
[[package]]
|
| 278 |
+
name = "smallvec"
|
| 279 |
+
version = "1.15.1"
|
| 280 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 281 |
+
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
| 282 |
+
|
| 283 |
+
[[package]]
|
| 284 |
+
name = "syn"
|
| 285 |
+
version = "2.0.117"
|
| 286 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 287 |
+
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
| 288 |
+
dependencies = [
|
| 289 |
+
"proc-macro2",
|
| 290 |
+
"quote",
|
| 291 |
+
"unicode-ident",
|
| 292 |
+
]
|
| 293 |
+
|
| 294 |
+
[[package]]
|
| 295 |
+
name = "unicode-ident"
|
| 296 |
+
version = "1.0.24"
|
| 297 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 298 |
+
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
| 299 |
+
|
| 300 |
+
[[package]]
|
| 301 |
+
name = "unreachable"
|
| 302 |
+
version = "1.0.0"
|
| 303 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 304 |
+
checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
| 305 |
+
dependencies = [
|
| 306 |
+
"void",
|
| 307 |
+
]
|
| 308 |
+
|
| 309 |
+
[[package]]
|
| 310 |
+
name = "void"
|
| 311 |
+
version = "1.0.2"
|
| 312 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 313 |
+
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
| 314 |
+
|
| 315 |
+
[[package]]
|
| 316 |
+
name = "winapi"
|
| 317 |
+
version = "0.3.9"
|
| 318 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 319 |
+
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
| 320 |
+
dependencies = [
|
| 321 |
+
"winapi-i686-pc-windows-gnu",
|
| 322 |
+
"winapi-x86_64-pc-windows-gnu",
|
| 323 |
+
]
|
| 324 |
+
|
| 325 |
+
[[package]]
|
| 326 |
+
name = "winapi-i686-pc-windows-gnu"
|
| 327 |
+
version = "0.4.0"
|
| 328 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 329 |
+
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
| 330 |
+
|
| 331 |
+
[[package]]
|
| 332 |
+
name = "winapi-x86_64-pc-windows-gnu"
|
| 333 |
+
version = "0.4.0"
|
| 334 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 335 |
+
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
native/sled_engine/Cargo.toml
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
name = "flashsync_native"
|
| 3 |
+
version = "0.1.0"
|
| 4 |
+
edition = "2021"
|
| 5 |
+
|
| 6 |
+
[lib]
|
| 7 |
+
name = "flashsync_native"
|
| 8 |
+
crate-type = ["cdylib"]
|
| 9 |
+
|
| 10 |
+
[dependencies]
|
| 11 |
+
rustler = "0.34.0"
|
| 12 |
+
sled = "0.34.7"
|
| 13 |
+
serde = { version = "1.0", features = ["derive"] }
|
| 14 |
+
serde_json = "1.0"
|
| 15 |
+
chrono = "0.4"
|
| 16 |
+
uuid = { version = "1.0", features = ["v4", "serde"] }
|
native/sled_engine/src/lib.rs
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
use rustler::{NifResult, Binary};
|
| 2 |
+
use serde::{Deserialize, Serialize};
|
| 3 |
+
use chrono::{DateTime, Utc};
|
| 4 |
+
use uuid::Uuid;
|
| 5 |
+
|
| 6 |
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
| 7 |
+
pub struct ReviewHistory {
|
| 8 |
+
pub review_date: String,
|
| 9 |
+
pub grade: i32, // 0-5 (SM-2 grades)
|
| 10 |
+
pub time_spent: i64, // milliseconds
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
| 14 |
+
pub struct CardMetadata {
|
| 15 |
+
pub id: String,
|
| 16 |
+
pub created_at: String,
|
| 17 |
+
pub updated_at: String,
|
| 18 |
+
pub last_reviewed: Option<String>,
|
| 19 |
+
pub ease_factor: f64, // SM-2: starts at 2.5
|
| 20 |
+
pub interval: i64, // SM-2: days between reviews
|
| 21 |
+
pub repetitions: i32, // SM-2: number of times reviewed
|
| 22 |
+
pub tags: Vec<String>,
|
| 23 |
+
pub related_cards: Vec<String>,
|
| 24 |
+
pub question: String,
|
| 25 |
+
pub answer: String,
|
| 26 |
+
pub sketch_data: Option<String>,
|
| 27 |
+
pub review_history: Vec<ReviewHistory>,
|
| 28 |
+
pub variations: Vec<CardVariation>,
|
| 29 |
+
pub is_mastered: bool,
|
| 30 |
+
pub focused_count: i32, // biometric tracking
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
| 34 |
+
pub struct CardVariation {
|
| 35 |
+
pub timestamp: String,
|
| 36 |
+
pub question: String,
|
| 37 |
+
pub answer: String,
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
#[derive_nifizer::nif]
|
| 41 |
+
#[rustler::nif]
|
| 42 |
+
fn create_card(
|
| 43 |
+
id: String,
|
| 44 |
+
question: String,
|
| 45 |
+
answer: String,
|
| 46 |
+
tags: Vec<String>,
|
| 47 |
+
) -> NifResult<String> {
|
| 48 |
+
let card = CardMetadata {
|
| 49 |
+
id: id.clone(),
|
| 50 |
+
created_at: Utc::now().to_rfc3339(),
|
| 51 |
+
updated_at: Utc::now().to_rfc3339(),
|
| 52 |
+
last_reviewed: None,
|
| 53 |
+
ease_factor: 2.5,
|
| 54 |
+
interval: 1,
|
| 55 |
+
repetitions: 0,
|
| 56 |
+
tags,
|
| 57 |
+
related_cards: vec![],
|
| 58 |
+
question,
|
| 59 |
+
answer,
|
| 60 |
+
sketch_data: None,
|
| 61 |
+
review_history: vec![],
|
| 62 |
+
variations: vec![],
|
| 63 |
+
is_mastered: false,
|
| 64 |
+
focused_count: 0,
|
| 65 |
+
};
|
| 66 |
+
|
| 67 |
+
let db = sled::open("flashcards.db")
|
| 68 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 69 |
+
|
| 70 |
+
let card_json = serde_json::to_string(&card)
|
| 71 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 72 |
+
|
| 73 |
+
db.insert(id.as_bytes(), card_json.as_bytes())
|
| 74 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 75 |
+
|
| 76 |
+
let _ = db.flush();
|
| 77 |
+
Ok(serde_json::to_string(&card).unwrap_or_default())
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
#[rustler::nif]
|
| 81 |
+
fn save_card(id: String, content: String) -> NifResult<String> {
|
| 82 |
+
let db = sled::open("flashcards.db")
|
| 83 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 84 |
+
|
| 85 |
+
match db.get(id.as_bytes())
|
| 86 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))? {
|
| 87 |
+
Some(existing) => {
|
| 88 |
+
let mut card: CardMetadata = serde_json::from_slice(&existing)
|
| 89 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 90 |
+
|
| 91 |
+
// Store old version in variations for time-travel
|
| 92 |
+
card.variations.push(CardVariation {
|
| 93 |
+
timestamp: card.updated_at.clone(),
|
| 94 |
+
question: card.question.clone(),
|
| 95 |
+
answer: card.answer.clone(),
|
| 96 |
+
});
|
| 97 |
+
|
| 98 |
+
// Keep only last 50 variations
|
| 99 |
+
if card.variations.len() > 50 {
|
| 100 |
+
card.variations.remove(0);
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
// Update with new content (expecting JSON)
|
| 104 |
+
if let Ok(update) = serde_json::from_str::<serde_json::Value>(&content) {
|
| 105 |
+
if let Some(q) = update.get("question").and_then(|v| v.as_str()) {
|
| 106 |
+
card.question = q.to_string();
|
| 107 |
+
}
|
| 108 |
+
if let Some(a) = update.get("answer").and_then(|v| v.as_str()) {
|
| 109 |
+
card.answer = a.to_string();
|
| 110 |
+
}
|
| 111 |
+
if let Some(tags) = update.get("tags").and_then(|v| v.as_array()) {
|
| 112 |
+
card.tags = tags.iter().filter_map(|t| t.as_str().map(|s| s.to_string())).collect();
|
| 113 |
+
}
|
| 114 |
+
if let Some(sketch) = update.get("sketch_data").and_then(|v| v.as_str()) {
|
| 115 |
+
card.sketch_data = Some(sketch.to_string());
|
| 116 |
+
}
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
card.updated_at = Utc::now().to_rfc3339();
|
| 120 |
+
|
| 121 |
+
let card_json = serde_json::to_string(&card)
|
| 122 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 123 |
+
|
| 124 |
+
db.insert(id.as_bytes(), card_json.as_bytes())
|
| 125 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 126 |
+
|
| 127 |
+
let _ = db.flush();
|
| 128 |
+
Ok("UPDATED".to_string())
|
| 129 |
+
}
|
| 130 |
+
None => {
|
| 131 |
+
db.insert(id.as_bytes(), content.as_bytes())
|
| 132 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 133 |
+
let _ = db.flush();
|
| 134 |
+
Ok("CREATED".to_string())
|
| 135 |
+
}
|
| 136 |
+
}
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
#[rustler::nif]
|
| 140 |
+
fn get_card(id: String) -> NifResult<String> {
|
| 141 |
+
let db = sled::open("flashcards.db")
|
| 142 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 143 |
+
|
| 144 |
+
match db.get(id.as_bytes())
|
| 145 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))? {
|
| 146 |
+
Some(ivec) => Ok(String::from_utf8_lossy(&ivec).to_string()),
|
| 147 |
+
None => Ok("NOT_FOUND".to_string()),
|
| 148 |
+
}
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
#[rustler::nif]
|
| 152 |
+
fn record_review(
|
| 153 |
+
id: String,
|
| 154 |
+
grade: i32,
|
| 155 |
+
time_spent: i64,
|
| 156 |
+
) -> NifResult<String> {
|
| 157 |
+
let db = sled::open("flashcards.db")
|
| 158 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 159 |
+
|
| 160 |
+
match db.get(id.as_bytes())
|
| 161 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))? {
|
| 162 |
+
Some(existing) => {
|
| 163 |
+
let mut card: CardMetadata = serde_json::from_slice(&existing)
|
| 164 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 165 |
+
|
| 166 |
+
// SM-2 Algorithm Implementation
|
| 167 |
+
card.review_history.push(ReviewHistory {
|
| 168 |
+
review_date: Utc::now().to_rfc3339(),
|
| 169 |
+
grade,
|
| 170 |
+
time_spent,
|
| 171 |
+
});
|
| 172 |
+
|
| 173 |
+
card.repetitions += 1;
|
| 174 |
+
card.last_reviewed = Some(Utc::now().to_rfc3339());
|
| 175 |
+
|
| 176 |
+
// SM-2 calculation
|
| 177 |
+
if grade >= 3 {
|
| 178 |
+
if card.repetitions == 1 {
|
| 179 |
+
card.interval = 1;
|
| 180 |
+
} else if card.repetitions == 2 {
|
| 181 |
+
card.interval = 3;
|
| 182 |
+
} else {
|
| 183 |
+
card.interval = (card.interval as f64 * card.ease_factor).ceil() as i64;
|
| 184 |
+
}
|
| 185 |
+
} else {
|
| 186 |
+
card.repetitions = 0;
|
| 187 |
+
card.interval = 1;
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
// Ease Factor adjustment
|
| 191 |
+
let ef = card.ease_factor + (0.1 - (5.0 - grade as f64) * (0.08 + (5.0 - grade as f64) * 0.02));
|
| 192 |
+
card.ease_factor = if ef < 1.3 { 1.3 } else { ef };
|
| 193 |
+
|
| 194 |
+
// Mark as mastered if reviewed 5+ times with grade 4+
|
| 195 |
+
if card.repetitions >= 5 && grade >= 4 {
|
| 196 |
+
card.is_mastered = true;
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
let card_json = serde_json::to_string(&card)
|
| 200 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 201 |
+
|
| 202 |
+
db.insert(id.as_bytes(), card_json.as_bytes())
|
| 203 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 204 |
+
|
| 205 |
+
let _ = db.flush();
|
| 206 |
+
Ok(serde_json::to_string(&card).unwrap_or_default())
|
| 207 |
+
}
|
| 208 |
+
None => Err(rustler::Error::Term(Box::new("CARD_NOT_FOUND"))),
|
| 209 |
+
}
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
#[rustler::nif]
|
| 213 |
+
fn add_relationship(card_id: String, related_id: String) -> NifResult<String> {
|
| 214 |
+
let db = sled::open("flashcards.db")
|
| 215 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 216 |
+
|
| 217 |
+
match db.get(card_id.as_bytes())
|
| 218 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))? {
|
| 219 |
+
Some(existing) => {
|
| 220 |
+
let mut card: CardMetadata = serde_json::from_slice(&existing)
|
| 221 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 222 |
+
|
| 223 |
+
if !card.related_cards.contains(&related_id) {
|
| 224 |
+
card.related_cards.push(related_id);
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
let card_json = serde_json::to_string(&card)
|
| 228 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 229 |
+
|
| 230 |
+
db.insert(card_id.as_bytes(), card_json.as_bytes())
|
| 231 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 232 |
+
|
| 233 |
+
let _ = db.flush();
|
| 234 |
+
Ok("RELATIONSHIP_ADDED".to_string())
|
| 235 |
+
}
|
| 236 |
+
None => Err(rustler::Error::Term(Box::new("CARD_NOT_FOUND"))),
|
| 237 |
+
}
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
#[rustler::nif]
|
| 241 |
+
fn get_all_cards() -> NifResult<String> {
|
| 242 |
+
let db = sled::open("flashcards.db")
|
| 243 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 244 |
+
|
| 245 |
+
let cards: Vec<CardMetadata> = db.iter()
|
| 246 |
+
.filter_map(|item| {
|
| 247 |
+
item.ok().and_then(|(_, v)| {
|
| 248 |
+
serde_json::from_slice(&v).ok()
|
| 249 |
+
})
|
| 250 |
+
})
|
| 251 |
+
.collect();
|
| 252 |
+
|
| 253 |
+
Ok(serde_json::to_string(&cards).unwrap_or_default())
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
#[rustler::nif]
|
| 257 |
+
fn get_historical_snapshot(id: String, timestamp: String) -> NifResult<String> {
|
| 258 |
+
let db = sled::open("flashcards.db")
|
| 259 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 260 |
+
|
| 261 |
+
match db.get(id.as_bytes())
|
| 262 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))? {
|
| 263 |
+
Some(existing) => {
|
| 264 |
+
let card: CardMetadata = serde_json::from_slice(&existing)
|
| 265 |
+
.map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?;
|
| 266 |
+
|
| 267 |
+
// Find variation closest to timestamp
|
| 268 |
+
let closest = card.variations.iter()
|
| 269 |
+
.min_by_key(|v| {
|
| 270 |
+
(v.timestamp.as_str().cmp(×tamp.as_str()),
|
| 271 |
+
std::cmp::Ordering::Equal)
|
| 272 |
+
});
|
| 273 |
+
|
| 274 |
+
if let Some(variation) = closest {
|
| 275 |
+
Ok(serde_json::to_string(variation).unwrap_or_default())
|
| 276 |
+
} else {
|
| 277 |
+
Ok(format!("{{\\"question\\": \\"{}\\", \\"answer\\": \\"{}\\"}}",
|
| 278 |
+
card.question.replace("\"", "\\\""),
|
| 279 |
+
card.answer.replace("\"", "\\\"")))
|
| 280 |
+
}
|
| 281 |
+
}
|
| 282 |
+
None => Err(rustler::Error::Term(Box::new("CARD_NOT_FOUND"))),
|
| 283 |
+
}
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
rustler::init!("flashsync_native", [
|
| 287 |
+
create_card,
|
| 288 |
+
save_card,
|
| 289 |
+
get_card,
|
| 290 |
+
record_review,
|
| 291 |
+
add_relationship,
|
| 292 |
+
get_all_cards,
|
| 293 |
+
get_historical_snapshot
|
| 294 |
+
]);
|
priv/exam.html
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<div id='vpro-enterprise-app'>
|
| 2 |
+
<style>/* Add your CSS here */</style>
|
| 3 |
+
</div>
|
priv/static/app.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
priv/static/emojis/openmoji-72x72-color/0023-FE0F-20E3.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/002A-FE0F-20E3.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/002D.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/0030-FE0F-20E3.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/0031-FE0F-20E3.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/0032-FE0F-20E3.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/0033-FE0F-20E3.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/0034-FE0F-20E3.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/0035-FE0F-20E3.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/0036-FE0F-20E3.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/0037-FE0F-20E3.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/0038-FE0F-20E3.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/0039-FE0F-20E3.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/00A9.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/00AE.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F004.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F0CF.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F10D.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F10E.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F10F.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F12F.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F16D.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F16E.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F16F.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F170.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F171.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F17E.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F17F.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F18E.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F191.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F192.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F193.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F194.png
ADDED
|
priv/static/emojis/openmoji-72x72-color/1F195.png
ADDED
|