├── Lpaydat ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── rust-toolchain.toml ├── scripts │ └── precompute_moves.rs ├── src │ ├── contract.rs │ ├── direction.rs │ ├── game.rs │ ├── lib.rs │ ├── moves.rs │ ├── random.rs │ ├── service.rs │ └── state.rs └── web-frontend │ ├── .gitignore │ ├── .vscode │ └── extensions.json │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── public │ └── vite.svg │ ├── src │ ├── App.svelte │ ├── app.css │ ├── assets │ │ └── svelte.svg │ ├── components │ │ ├── Board.svelte │ │ ├── BoardTile.svelte │ │ ├── Game.svelte │ │ ├── Header.svelte │ │ ├── Introduction.svelte │ │ └── MoveLogs.svelte │ ├── lib │ │ └── client.ts │ ├── main.ts │ └── vite-env.d.ts │ ├── svelte.config.js │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── README.md └── winrhcp ├── linera-token-frontend ├── README.md ├── package.json ├── public │ └── index.html └── src │ ├── App.js │ ├── components │ └── CreateToken.js │ ├── index.js │ └── services │ └── lineraService.js └── linera_token_creation ├── Cargo.toml ├── README.md └── src ├── contract.rs ├── errors.rs ├── main.rs ├── types.rs └── views.rs /Lpaydat/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | moves_data.rs 3 | todo.md -------------------------------------------------------------------------------- /Lpaydat/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "game2048" 3 | version = "0.1.0" 4 | authors = ["LPAYDAT "] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | async-graphql = { version = "=7.0.2", default-features = false } 9 | linera-sdk = "0.12.1" 10 | serde = { version = "1.0", features = ["derive"] } 11 | lazy_static = "1.4" 12 | 13 | [dev-dependencies] 14 | linera-sdk = { version = "0.12.1", features = ["test"] } 15 | 16 | [[bin]] 17 | name = "game2048_contract" 18 | path = "src/contract.rs" 19 | 20 | [[bin]] 21 | name = "game2048_service" 22 | path = "src/service.rs" 23 | 24 | [[bin]] 25 | name = "precompute_moves" 26 | path = "scripts/precompute_moves.rs" 27 | 28 | [profile.release] 29 | debug = true 30 | lto = true 31 | opt-level = 'z' 32 | strip = 'debuginfo' 33 | -------------------------------------------------------------------------------- /Lpaydat/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.80.0" 3 | components = [ "clippy", "rustfmt", "rust-src" ] 4 | targets = [ "wasm32-unknown-unknown" ] 5 | profile = "minimal" 6 | -------------------------------------------------------------------------------- /Lpaydat/scripts/precompute_moves.rs: -------------------------------------------------------------------------------- 1 | use game2048::Moves; 2 | use std::fs::File; 3 | use std::io::Write; 4 | 5 | fn main() { 6 | let mut left_moves = vec![0u64; 65536]; 7 | let mut right_moves = vec![0u64; 65536]; 8 | let mut up_moves = vec![0u64; 65536]; 9 | let mut down_moves = vec![0u64; 65536]; 10 | let mut scores = vec![0u64; 65536]; 11 | 12 | for row in 0..65536 { 13 | // break row into cells 14 | let mut line = [ 15 | (row) & 0xF, 16 | (row >> 4) & 0xF, 17 | (row >> 8) & 0xF, 18 | (row >> 12) & 0xF, 19 | ]; 20 | 21 | // calculate score for given row 22 | let mut s = 0; 23 | 24 | for &tile in &line { 25 | if tile > 1 { 26 | s += (tile - 1) * (2 << tile) 27 | } 28 | } 29 | 30 | scores[row as usize] = s; 31 | 32 | let mut i = 0; 33 | 34 | // perform a move to the left using current {row} as board 35 | // generates 4 output moves for up, down, left and right by transposing and reversing 36 | // this result. 37 | while i < 3 { 38 | // initial counter for the cell next to the current one (j) 39 | let mut j = i + 1; 40 | 41 | // find the next non-zero cell index 42 | while j < 4 { 43 | if line[j] != 0 { 44 | break; 45 | }; 46 | j += 1; 47 | } 48 | 49 | // if j is out of bounds (> 3), all other cells are empty and we are done looping 50 | if j == 4 { 51 | break; 52 | }; 53 | 54 | // this is the part responsible for skipping empty (0 value) cells 55 | // if the current cell is zero, shift the next non-zero cell to position i 56 | // and retry this entry until line[i] becomes non-zero 57 | if line[i] == 0 { 58 | line[i] = line[j]; 59 | line[j] = 0; 60 | continue; 61 | 62 | // otherwise, if the current cell and next cell are the same, merge them 63 | } else if line[i] == line[j] { 64 | if line[i] != 0xF { 65 | line[i] += 1 66 | }; 67 | line[j] = 0; 68 | } 69 | 70 | // finally, move to the next (or current, if i was 0) row 71 | i += 1; 72 | } 73 | 74 | // put the new row after merging back together into a "merged" row 75 | let result = (line[0]) | (line[1] << 4) | (line[2] << 8) | (line[3] << 12); 76 | 77 | // right and down use normal row and result variables. 78 | // for left and up, we create a reverse of the row and result. 79 | let rev_row = 80 | (row >> 12) & 0x000F | (row >> 4) & 0x00F0 | (row << 4) & 0x0F00 | (row << 12) & 0xF000; 81 | let rev_res = (result >> 12) & 0x000F 82 | | (result >> 4) & 0x00F0 83 | | (result << 4) & 0x0F00 84 | | (result << 12) & 0xF000; 85 | 86 | // results are keyed by row / reverse row index. 87 | let row_idx = row as usize; 88 | let rev_idx = rev_row as usize; 89 | 90 | right_moves[row_idx] = row ^ result; 91 | left_moves[rev_idx] = rev_row ^ rev_res; 92 | up_moves[rev_idx] = Moves::column_from(rev_row) ^ Moves::column_from(rev_res); 93 | down_moves[row_idx] = Moves::column_from(row) ^ Moves::column_from(result); 94 | } 95 | 96 | let mut file = File::create("moves_data.rs").unwrap(); 97 | writeln!( 98 | file, 99 | "pub const LEFT_MOVES: [u64; 65536] = {:?};", 100 | left_moves 101 | ) 102 | .unwrap(); 103 | writeln!( 104 | file, 105 | "pub const RIGHT_MOVES: [u64; 65536] = {:?};", 106 | right_moves 107 | ) 108 | .unwrap(); 109 | writeln!(file, "pub const UP_MOVES: [u64; 65536] = {:?};", up_moves).unwrap(); 110 | writeln!( 111 | file, 112 | "pub const DOWN_MOVES: [u64; 65536] = {:?};", 113 | down_moves 114 | ) 115 | .unwrap(); 116 | writeln!(file, "pub const SCORES: [u64; 65536] = {:?};", scores).unwrap(); 117 | } 118 | -------------------------------------------------------------------------------- /Lpaydat/src/contract.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_main)] 2 | 3 | // mod game; 4 | mod state; 5 | 6 | use std::str::FromStr; 7 | 8 | use linera_sdk::{ 9 | base::{ChainId, WithContractAbi}, 10 | views::{RootView, View}, 11 | Contract, ContractRuntime, 12 | }; 13 | 14 | use self::state::Game2048; 15 | use game2048::{gen_range, Game, Message, Operation}; 16 | 17 | pub struct Game2048Contract { 18 | state: Game2048, 19 | runtime: ContractRuntime, 20 | } 21 | 22 | linera_sdk::contract!(Game2048Contract); 23 | 24 | impl WithContractAbi for Game2048Contract { 25 | type Abi = game2048::Game2048Abi; 26 | } 27 | 28 | impl Contract for Game2048Contract { 29 | type Message = Message; 30 | type Parameters = (); 31 | type InstantiationArgument = u16; 32 | 33 | async fn load(runtime: ContractRuntime) -> Self { 34 | let state = Game2048::load(runtime.root_view_storage_context()) 35 | .await 36 | .expect("Failed to load state"); 37 | Game2048Contract { state, runtime } 38 | } 39 | 40 | async fn instantiate(&mut self, seed: Self::InstantiationArgument) { 41 | self.runtime.application_parameters(); 42 | 43 | // Initialize a default game entry if it doesn't exist 44 | let game_id = seed; // Example game ID 45 | if self 46 | .state 47 | .games 48 | .load_entry_or_insert(&game_id) 49 | .await 50 | .is_err() 51 | { 52 | let game = self.state.games.load_entry_mut(&game_id).await.unwrap(); 53 | game.game_id.set(game_id); 54 | game.board.set(0); // Set a default board value, e.g., an empty board 55 | } 56 | } 57 | 58 | async fn execute_operation(&mut self, operation: Self::Operation) -> Self::Response { 59 | match operation { 60 | Operation::NewGame { seed } => { 61 | let seed = self.get_seed(seed); 62 | let new_board = Game::new(seed).board; 63 | let game = self.state.games.load_entry_mut(&seed).await.unwrap(); 64 | 65 | game.game_id.set(seed); 66 | game.board.set(new_board); 67 | 68 | self.send_message(seed, new_board, 0, false); 69 | } 70 | Operation::EndGame { game_id } => { 71 | let board = self.state.games.load_entry_mut(&game_id).await.unwrap(); 72 | board.is_ended.set(true); 73 | } 74 | Operation::MakeMove { game_id, direction } => { 75 | let seed = self.get_seed(0); 76 | let board = self.state.games.load_entry_mut(&game_id).await.unwrap(); 77 | 78 | let is_ended = board.is_ended.get(); 79 | if !is_ended { 80 | let mut game = Game { 81 | board: *board.board.get(), 82 | seed, 83 | }; 84 | 85 | let new_board = Game::execute(&mut game, direction); 86 | let is_ended = Game::is_ended(new_board); 87 | let score = Game::score(new_board); 88 | 89 | board.board.set(new_board); 90 | board.score.set(score); 91 | if is_ended { 92 | board.is_ended.set(true); 93 | } 94 | 95 | self.send_message(game_id, new_board, score, is_ended); 96 | } 97 | } 98 | } 99 | } 100 | 101 | async fn execute_message(&mut self, _message: Self::Message) {} 102 | 103 | async fn store(mut self) { 104 | self.state.save().await.expect("Failed to save state"); 105 | } 106 | } 107 | 108 | impl Game2048Contract { 109 | fn get_seed(&mut self, init_seed: u16) -> u16 { 110 | if init_seed != 0 { 111 | init_seed 112 | } else { 113 | let block_height = self.runtime.block_height().to_string(); 114 | gen_range(&block_height, 0, u16::MAX) 115 | } 116 | } 117 | 118 | fn send_message(&mut self, game_id: u16, board: u64, score: u64, is_ended: bool) { 119 | let chain_id = 120 | ChainId::from_str("256e1dbc00482ddd619c293cc0df94d366afe7980022bb22d99e33036fd465dd") 121 | .unwrap(); 122 | self.runtime 123 | .prepare_message(Message::Game { 124 | game_id, 125 | board, 126 | score, 127 | is_ended, 128 | }) 129 | .send_to(chain_id); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /Lpaydat/src/direction.rs: -------------------------------------------------------------------------------- 1 | use async_graphql::scalar; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Clone, Debug, Deserialize, Serialize)] 5 | pub enum Direction { 6 | Up, 7 | Down, 8 | Left, 9 | Right, 10 | } 11 | 12 | scalar!(Direction); 13 | -------------------------------------------------------------------------------- /Lpaydat/src/game.rs: -------------------------------------------------------------------------------- 1 | use crate::{gen_range, Direction, ROW_MASK}; 2 | use lazy_static::lazy_static; 3 | use std::ops::Add; 4 | include!("../moves_data.rs"); 5 | 6 | /// Struct that contains all available moves per row for up, down, right and left. 7 | /// Also stores the score for a given row. 8 | /// 9 | /// Moves are stored as power values for tiles. 10 | /// if a power value is `> 0`, print the tile value using `2 << tile` where tile is any 4-bit 11 | /// "nybble" otherwise print a `0` instead. 12 | pub struct Moves { 13 | pub left: &'static [u64; 65536], 14 | pub right: &'static [u64; 65536], 15 | pub down: &'static [u64; 65536], 16 | pub up: &'static [u64; 65536], 17 | pub scores: &'static [u64; 65536], 18 | } 19 | 20 | lazy_static! { 21 | /// Constructs a new `tfe::Moves`. 22 | /// 23 | /// `Moves` stores `right`, `left`, `up`, and `down` moves per row. 24 | /// e.g. left: `0x0011 -> 0x2000` and right: `0x0011 -> 0x0002`. 25 | /// 26 | /// Also stores the `scores` per row. 27 | /// The score of a row is the sum of the tile and all intermediate tile merges. 28 | /// e.g. row `0x0002` has a score of `4` and row `0x0003` has a score of `16`. 29 | static ref MOVES: Moves = { 30 | Moves { 31 | left: &LEFT_MOVES, 32 | right: &RIGHT_MOVES, 33 | down: &DOWN_MOVES, 34 | up: &UP_MOVES, 35 | scores: &SCORES, 36 | } 37 | }; 38 | } 39 | 40 | /// Struct used to play a single game of 2048. 41 | /// 42 | /// `tfe::Game` uses a single `u64` as board value. 43 | /// The board itself is divided into rows (x4 16 bit "row" per "board") which are 44 | /// divided into tiles (4x 4 bit "nybbles" per "row"). 45 | /// 46 | /// All manipulations are done using bit-shifts and a precomputed table of moves and scores. 47 | /// Every move is stored as four lookups total, one for each row. The result of XOR'ing each row 48 | /// back into the board at the right position is the output board. 49 | pub struct Game { 50 | pub board: u64, 51 | pub seed: u16, 52 | } 53 | impl Game { 54 | /// Constructs a new `tfe::Game`. 55 | /// 56 | /// `Game` stores a board internally as a `u64`. 57 | /// 58 | /// # Examples 59 | /// 60 | /// Simple example: 61 | /// 62 | /// ``` 63 | /// use tfe::Game; 64 | /// 65 | /// let mut game = Game::new(); 66 | /// # println!("{:016x}", game.board); 67 | /// ``` 68 | /// 69 | /// Accessing board value: 70 | /// 71 | /// ``` 72 | /// use tfe::Game; 73 | /// 74 | /// let mut game = Game::new(); 75 | /// println!("{:016x}", game.board); 76 | /// ``` 77 | pub fn new(seed: u16) -> Self { 78 | let mut game = Game { 79 | board: 0x0000_0000_0000_0000_u64, 80 | seed, 81 | }; 82 | 83 | game.board |= Self::spawn_tile(game.board, game.seed); 84 | game.board |= Self::spawn_tile(game.board, game.seed + 1); 85 | 86 | game 87 | } 88 | 89 | /// Returns `board` moved in given `direction`. 90 | /// 91 | /// - When `Direction::Left`, return board moved left 92 | /// - When `Direction::Right`, return board moved right 93 | /// - When `Direction::Down`, return board moved down 94 | /// - When `Direction::Up`, return board moved up 95 | /// 96 | /// # Examples 97 | /// 98 | /// Simple example: 99 | /// 100 | /// ``` 101 | /// use tfe::{Game, Direction}; 102 | /// 103 | /// let board = 0x0000_0000_0022_1100; 104 | /// let moved = Game::execute(board, &[Direction::Left]); 105 | /// 106 | /// // | 0 | 0 | 0 | 0 | | 0 | 0 | 0 | 0 | 107 | /// // | 0 | 0 | 0 | 0 | => | 0 | 0 | 0 | 0 | 108 | /// // | 0 | 0 | 4 | 4 | | 8 | 0 | 0 | 0 | 109 | /// // | 2 | 2 | 0 | 0 | | 4 | 0 | 0 | 0 | 110 | /// 111 | /// assert_eq!(board, 0x0000_0000_0022_1100); 112 | /// assert_eq!(moved, 0x0000_0000_3000_2000); 113 | /// ``` 114 | pub fn execute(&mut self, direction: Direction) -> u64 { 115 | let mut current_board = self.board; 116 | current_board = match direction { 117 | Direction::Left => Self::move_left(current_board), 118 | Direction::Right => Self::move_right(current_board), 119 | Direction::Down => Self::move_down(current_board), 120 | Direction::Up => Self::move_up(current_board), 121 | }; 122 | 123 | if current_board != self.board { 124 | current_board = current_board | Self::spawn_tile(current_board, self.seed) 125 | } 126 | 127 | current_board 128 | } 129 | 130 | /// Converts a 64-bit board representation to a 4x4 matrix of u16 values. 131 | /// 132 | /// This function takes a u64 board representation where each 4 bits represent 133 | /// a tile value, and converts it into a 2D array (matrix) of u16 values. 134 | /// 135 | /// # Arguments 136 | /// 137 | /// * `board` - A u64 representing the game board, where each 4 bits encode a tile. 138 | /// 139 | /// # Returns 140 | /// 141 | /// A 4x4 array of u16 values, where each value represents the actual tile value. 142 | /// For example, a value of 3 represents 2^3 = 8. 143 | /// 144 | /// # Example 145 | /// 146 | /// ``` 147 | /// let board = 0x0000_0000_0022_1100; // represents a board with 1, 1, 2, 2 in the bottom two rows 148 | /// let matrix = Game::convert_to_matrix(board); 149 | /// assert_eq!(matrix, [ 150 | /// [0, 0, 0, 0], 151 | /// [0, 0, 0, 0], 152 | /// [0, 0, 2, 2], 153 | /// [1, 1, 0, 0] 154 | /// ]); 155 | /// ``` 156 | pub fn convert_to_matrix(board: u64) -> [[u16; 4]; 4] { 157 | let mut matrix = [[0u16; 4]; 4]; 158 | for i in 0..16 { 159 | let value = ((board >> (i * 4)) & 0xF) as u8; 160 | // Correct the indexing to avoid swapping left and right 161 | matrix[3 - (i / 4)][3 - (i % 4)] = if value > 0 { value.into() } else { 0 }; 162 | } 163 | matrix 164 | } 165 | 166 | /// Determines if the game has ended. 167 | /// 168 | /// The game is considered ended if: 169 | /// 1. Any tile on the board has reached the value of 2048. 170 | /// 2. No moves in any direction (left, right, up, down) result in a change in the board. 171 | /// 172 | /// # Arguments 173 | /// 174 | /// * `board` - A `u64` representing the current state of the game board. 175 | /// 176 | /// # Returns 177 | /// 178 | /// * `true` if the game is ended, either by reaching 2048 or having no possible moves left. 179 | /// * `false` otherwise. 180 | /// 181 | /// # Examples 182 | /// 183 | /// ``` 184 | /// use tfe::Game; 185 | /// 186 | /// let board = 0x0000_0000_0000_0B00; // A board with a tile value of 2048 187 | /// assert!(Game::is_ended(board)); // Game should be ended 188 | /// 189 | /// let board = 0x0000_0000_0000_0000; // An empty board 190 | /// assert!(!Game::is_ended(board)); // Game should not be ended 191 | /// ``` 192 | pub fn is_ended(board: u64) -> bool { 193 | // Check if any tile has reached 2048 194 | for i in 0..16 { 195 | let tile_value = (board >> (i * 4)) & 0xF; 196 | if tile_value == 11 { 197 | // 2^11 = 2048 198 | return true; 199 | } 200 | } 201 | 202 | // Check if any move changes the board 203 | let left = Self::move_left(board); 204 | let right = Self::move_right(board); 205 | let up = Self::move_up(board); 206 | let down = Self::move_down(board); 207 | 208 | if board == left && board == right && board == up && board == down { 209 | return true; 210 | } 211 | 212 | false 213 | } 214 | 215 | /// Returns a transposed board where rows are transformed into columns and vice versa. 216 | /// 217 | /// ``` 218 | /// use tfe::Game; 219 | /// 220 | /// // | F | E | D | C | | F | B | 7 | 3 | 221 | /// // | B | A | 9 | 8 | => | E | A | 6 | 2 | 222 | /// // | 7 | 6 | 5 | 4 | | D | 9 | 5 | 1 | 223 | /// // | 3 | 2 | 1 | 0 | | C | 8 | 4 | 0 | 224 | /// 225 | /// assert_eq!(Game::transpose(0xFEDC_BA98_7654_3210), 0xFB73_EA62_D951_C840); 226 | /// ``` 227 | pub fn transpose(board: u64) -> u64 { 228 | let a1 = board & 0xF0F0_0F0F_F0F0_0F0F_u64; 229 | let a2 = board & 0x0000_F0F0_0000_F0F0_u64; 230 | let a3 = board & 0x0F0F_0000_0F0F_0000_u64; 231 | 232 | let a = a1 | (a2 << 12) | (a3 >> 12); 233 | 234 | let b1 = a & 0xFF00_FF00_00FF_00FF_u64; 235 | let b2 = a & 0x00FF_00FF_0000_0000_u64; 236 | let b3 = a & 0x0000_0000_FF00_FF00_u64; 237 | 238 | b1 | (b2 >> 24) | (b3 << 24) 239 | } 240 | 241 | /// Returns a `u64` board moved up. 242 | /// This is the same as calling `Game::execute(board, &Direction::Up)`; 243 | /// 244 | /// # Examples 245 | /// 246 | /// ``` 247 | /// use tfe::Game; 248 | /// 249 | /// let board = 0x0000_0000_0000_0011_u64; 250 | /// let result = Game::move_up(board); 251 | /// 252 | /// // | 0 | 0 | 0 | 0 | | 0 | 0 | 1 | 1 | 253 | /// // | 0 | 0 | 0 | 0 | => | 0 | 0 | 0 | 0 | 254 | /// // | 0 | 0 | 0 | 0 | | 0 | 0 | 0 | 0 | 255 | /// // | 0 | 0 | 1 | 1 | | 0 | 0 | 0 | 0 | 256 | /// 257 | /// assert_eq!(result, 0x0011_0000_0000_0000); 258 | /// ``` 259 | pub fn move_up(board: u64) -> u64 { 260 | let mut result = board; 261 | let transposed = Self::transpose(board); 262 | 263 | result ^= MOVES.up[((transposed) & ROW_MASK) as usize]; 264 | result ^= MOVES.up[((transposed >> 16) & ROW_MASK) as usize] << 4; 265 | result ^= MOVES.up[((transposed >> 32) & ROW_MASK) as usize] << 8; 266 | result ^= MOVES.up[((transposed >> 48) & ROW_MASK) as usize] << 12; 267 | 268 | result 269 | } 270 | 271 | /// Returns a `u64` board moved down. 272 | /// This is the same as calling `Game::execute(board, &Direction::Down)`; 273 | /// 274 | /// # Examples 275 | /// 276 | /// ``` 277 | /// use tfe::Game; 278 | /// 279 | /// let board = 0x0011_0000_0000_0011_u64; 280 | /// let result = Game::move_down(board); 281 | /// 282 | /// // | 0 | 0 | 1 | 1 | | 0 | 0 | 0 | 0 | 283 | /// // | 0 | 0 | 0 | 0 | => | 0 | 0 | 0 | 0 | 284 | /// // | 0 | 0 | 0 | 0 | | 0 | 0 | 0 | 0 | 285 | /// // | 0 | 0 | 1 | 1 | | 0 | 0 | 2 | 2 | 286 | /// 287 | /// assert_eq!(result, 0x0000_0000_0000_0022); 288 | /// ``` 289 | pub fn move_down(board: u64) -> u64 { 290 | let mut result = board; 291 | let transposed = Self::transpose(board); 292 | 293 | result ^= MOVES.down[((transposed) & ROW_MASK) as usize]; 294 | result ^= MOVES.down[((transposed >> 16) & ROW_MASK) as usize] << 4; 295 | result ^= MOVES.down[((transposed >> 32) & ROW_MASK) as usize] << 8; 296 | result ^= MOVES.down[((transposed >> 48) & ROW_MASK) as usize] << 12; 297 | 298 | result 299 | } 300 | 301 | /// Returns a `u64` board moved right. 302 | /// This is the same as calling `Game::execute(board, &Direction::Right)`; 303 | /// 304 | /// # Examples 305 | /// 306 | /// ``` 307 | /// use tfe::Game; 308 | /// 309 | /// let board = 0x0000_0000_0000_2211_u64; 310 | /// let result = Game::move_right(board); 311 | /// 312 | /// // | 0 | 0 | 0 | 0 | | 0 | 0 | 0 | 0 | 313 | /// // | 0 | 0 | 0 | 0 | => | 0 | 0 | 0 | 0 | 314 | /// // | 0 | 0 | 0 | 0 | | 0 | 0 | 0 | 0 | 315 | /// // | 2 | 2 | 1 | 1 | | 0 | 0 | 3 | 2 | 316 | /// 317 | /// assert_eq!(result, 0x0000_0000_0000_0032); 318 | /// ``` 319 | pub fn move_right(board: u64) -> u64 { 320 | let mut result = board; 321 | 322 | result ^= MOVES.right[((board) & ROW_MASK) as usize]; 323 | result ^= MOVES.right[((board >> 16) & ROW_MASK) as usize] << 16; 324 | result ^= MOVES.right[((board >> 32) & ROW_MASK) as usize] << 32; 325 | result ^= MOVES.right[((board >> 48) & ROW_MASK) as usize] << 48; 326 | 327 | result 328 | } 329 | 330 | /// Returns a `u64` board moved left. 331 | /// This is the same as calling `Game::execute(board, &Direction::Left)`; 332 | /// 333 | /// # Examples 334 | /// 335 | /// ``` 336 | /// use tfe::Game; 337 | /// 338 | /// let board = 0x0000_0000_0000_2211_u64; 339 | /// let result = Game::move_left(board); 340 | /// 341 | /// // | 0 | 0 | 0 | 0 | | 0 | 0 | 0 | 0 | 342 | /// // | 0 | 0 | 0 | 0 | => | 0 | 0 | 0 | 0 | 343 | /// // | 0 | 0 | 0 | 0 | | 0 | 0 | 0 | 0 | 344 | /// // | 2 | 2 | 1 | 1 | | 3 | 2 | 0 | 0 | 345 | /// 346 | /// assert_eq!(result, 0x0000_0000_0000_3200); 347 | /// ``` 348 | pub fn move_left(board: u64) -> u64 { 349 | let mut result: u64 = board; 350 | 351 | result ^= MOVES.left[((board) & ROW_MASK) as usize]; 352 | result ^= MOVES.left[((board >> 16) & ROW_MASK) as usize] << 16; 353 | result ^= MOVES.left[((board >> 32) & ROW_MASK) as usize] << 32; 354 | result ^= MOVES.left[((board >> 48) & ROW_MASK) as usize] << 48; 355 | 356 | result 357 | } 358 | 359 | /// Returns the count of tiles with a value of `0`. 360 | /// 361 | /// # Examples 362 | /// 363 | /// ``` 364 | /// use tfe::Game; 365 | /// 366 | /// let board = 0x0000_0000_0000_2211_u64; 367 | /// let result = Game::count_empty(board); 368 | /// 369 | /// assert_eq!(result, 12); 370 | /// ``` 371 | pub fn count_empty(board: u64) -> u16 { 372 | let mut empty = 0; 373 | 374 | for i in 0..16 { 375 | if ((board >> (i * 4)) & 0xF) == 0 { 376 | empty += 1 377 | } 378 | } 379 | 380 | empty 381 | } 382 | 383 | /// Returns the sum of 4 lookups in `table` for each "row" in `board`. 384 | pub fn table_helper>(board: u64, table: &[T]) -> T { 385 | table[((board) & ROW_MASK) as usize].clone() 386 | + table[((board >> 16) & ROW_MASK) as usize].clone() 387 | + table[((board >> 32) & ROW_MASK) as usize].clone() 388 | + table[((board >> 48) & ROW_MASK) as usize].clone() 389 | } 390 | 391 | /// Returns the score of a given `board`. 392 | /// The score of a single tile is the sum of the tile value and all intermediate merged tiles. 393 | pub fn score(board: u64) -> u64 { 394 | Self::table_helper(board, MOVES.scores) 395 | } 396 | 397 | /// Returns a `2` with 90% chance and `4` with 10% chance. 398 | pub fn tile(seed: u16) -> u64 { 399 | if gen_range(&seed.to_string(), 0, 10) == 10 { 400 | 2 401 | } else { 402 | 1 403 | } 404 | } 405 | 406 | /// Returns a `1` shifted to the position of any `0` bit in `board` randomly. 407 | pub fn spawn_tile(board: u64, seed: u16) -> u64 { 408 | let mut tmp = board; 409 | let mut idx = gen_range(&seed.to_string(), 0, Self::count_empty(board)); 410 | let mut t = Self::tile(seed); 411 | 412 | loop { 413 | while (tmp & 0xF) != 0 { 414 | tmp >>= 4; 415 | t <<= 4; 416 | } 417 | 418 | if idx == 0 { 419 | break; 420 | } else { 421 | idx -= 1 422 | } 423 | 424 | tmp >>= 4; 425 | t <<= 4 426 | } 427 | 428 | t 429 | } 430 | } 431 | -------------------------------------------------------------------------------- /Lpaydat/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod direction; 2 | mod game; 3 | mod moves; 4 | mod random; 5 | 6 | pub use crate::direction::Direction; 7 | pub use crate::game::Game; 8 | pub use crate::moves::{Moves, COL_MASK, ROW_MASK}; 9 | pub use crate::random::gen_range; 10 | use async_graphql::{Request, Response}; 11 | use linera_sdk::{ 12 | base::{ContractAbi, ServiceAbi}, 13 | graphql::GraphQLMutationRoot, 14 | }; 15 | use serde::{Deserialize, Serialize}; 16 | 17 | pub struct Game2048Abi; 18 | 19 | impl ContractAbi for Game2048Abi { 20 | type Operation = Operation; 21 | type Response = (); 22 | } 23 | 24 | impl ServiceAbi for Game2048Abi { 25 | type Query = Request; 26 | type QueryResponse = Response; 27 | } 28 | 29 | #[derive(Debug, Deserialize, Serialize, GraphQLMutationRoot)] 30 | pub enum Operation { 31 | NewGame { seed: u16 }, 32 | EndGame { game_id: u16 }, 33 | MakeMove { game_id: u16, direction: Direction }, 34 | } 35 | 36 | #[derive(Debug, Deserialize, Serialize)] 37 | pub enum Message { 38 | Game { 39 | game_id: u16, 40 | board: u64, 41 | score: u64, 42 | is_ended: bool, 43 | }, 44 | } 45 | -------------------------------------------------------------------------------- /Lpaydat/src/moves.rs: -------------------------------------------------------------------------------- 1 | /// A mask with a single section of 16 bits set to 0. 2 | /// Used to extract a "horizontal slice" out of a 64 bit integer. 3 | pub static ROW_MASK: u64 = 0xFFFF; 4 | 5 | /// A `u64` mask with 4 sections each starting after the n * 16th bit. 6 | /// Used to extract a "vertical slice" out of a 64 bit integer. 7 | pub static COL_MASK: u64 = 0x000F_000F_000F_000F_u64; 8 | 9 | /// Struct that contains all available moves per row for up, down, right and left. 10 | /// Also stores the score for a given row. 11 | /// 12 | /// Moves are stored as power values for tiles. 13 | /// if a power value is `> 0`, print the tile value using `2 << tile` where tile is any 4-bit 14 | /// "nybble" otherwise print a `0` instead. 15 | pub struct Moves { 16 | pub left: Vec, 17 | pub right: Vec, 18 | pub down: Vec, 19 | pub up: Vec, 20 | pub scores: Vec, 21 | } 22 | 23 | impl Moves { 24 | /// Returns the 4th bit from each row in given board OR'd. 25 | pub fn column_from(board: u64) -> u64 { 26 | (board | (board << 12) | (board << 24) | (board << 36)) & COL_MASK 27 | } 28 | 29 | /// Constructs a new `Moves` instance. 30 | /// 31 | /// `Moves` stores `right`, `left`, `up`, and `down` moves per row. 32 | /// Also stores the `scores` per row. 33 | pub fn new() -> Moves { 34 | // initialization of move tables 35 | let mut left_moves = vec![0; 65536]; 36 | let mut right_moves = vec![0; 65536]; 37 | let mut up_moves = vec![0; 65536]; 38 | let mut down_moves = vec![0; 65536]; 39 | let mut scores = vec![0; 65536]; 40 | 41 | for row in 0..65536 { 42 | // break row into cells 43 | let mut line = [ 44 | (row) & 0xF, 45 | (row >> 4) & 0xF, 46 | (row >> 8) & 0xF, 47 | (row >> 12) & 0xF, 48 | ]; 49 | 50 | // calculate score for given row 51 | let mut s = 0; 52 | 53 | for &tile in &line { 54 | if tile > 1 { 55 | s += (tile - 1) * (2 << tile) 56 | } 57 | } 58 | 59 | scores[row as usize] = s; 60 | 61 | let mut i = 0; 62 | 63 | // perform a move to the left using current {row} as board 64 | while i < 3 { 65 | let mut j = i + 1; 66 | 67 | while j < 4 { 68 | if line[j] != 0 { 69 | break; 70 | }; 71 | j += 1; 72 | } 73 | 74 | if j == 4 { 75 | break; 76 | }; 77 | 78 | if line[i] == 0 { 79 | line[i] = line[j]; 80 | line[j] = 0; 81 | continue; 82 | } else if line[i] == line[j] { 83 | if line[i] != 0xF { 84 | line[i] += 1 85 | }; 86 | line[j] = 0; 87 | } 88 | 89 | i += 1; 90 | } 91 | 92 | let result = (line[0]) | (line[1] << 4) | (line[2] << 8) | (line[3] << 12); 93 | 94 | let rev_row = (row >> 12) & 0x000F 95 | | (row >> 4) & 0x00F0 96 | | (row << 4) & 0x0F00 97 | | (row << 12) & 0xF000; 98 | let rev_res = (result >> 12) & 0x000F 99 | | (result >> 4) & 0x00F0 100 | | (result << 4) & 0x0F00 101 | | (result << 12) & 0xF000; 102 | 103 | let row_idx = row as usize; 104 | let rev_idx = rev_row as usize; 105 | 106 | right_moves[row_idx] = row ^ result; 107 | left_moves[rev_idx] = rev_row ^ rev_res; 108 | up_moves[rev_idx] = Moves::column_from(rev_row) ^ Moves::column_from(rev_res); 109 | down_moves[row_idx] = Moves::column_from(row) ^ Moves::column_from(result); 110 | } 111 | 112 | Moves { 113 | left: left_moves, 114 | right: right_moves, 115 | down: down_moves, 116 | up: up_moves, 117 | scores, 118 | } 119 | } 120 | } 121 | 122 | impl Default for Moves { 123 | fn default() -> Self { 124 | Moves::new() 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /Lpaydat/src/random.rs: -------------------------------------------------------------------------------- 1 | use std::collections::hash_map::DefaultHasher; 2 | use std::hash::{Hash, Hasher}; 3 | 4 | // Function to generate a random number based on a string input 5 | // and within a specified range defined by min and max. 6 | pub fn gen_range(input: &str, min: u16, max: u16) -> u16 { 7 | // Hash the input string to create a seed 8 | let mut hasher = DefaultHasher::new(); 9 | input.hash(&mut hasher); 10 | let seed = hasher.finish(); 11 | 12 | // Calculate the range 13 | let range = max - min; 14 | 15 | // Use the seed to get a number within the range using modulus 16 | (seed % range as u64) as u16 + min 17 | } 18 | -------------------------------------------------------------------------------- /Lpaydat/src/service.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_main)] 2 | 3 | mod state; 4 | 5 | use std::sync::Arc; 6 | 7 | use self::state::Game2048; 8 | use async_graphql::{EmptySubscription, Object, Schema, SimpleObject}; 9 | use game2048::{Direction, Game, Operation}; 10 | use linera_sdk::{base::WithServiceAbi, bcs, views::View, Service, ServiceRuntime}; 11 | 12 | pub struct Game2048Service { 13 | state: Arc, 14 | // runtime: Arc>>, 15 | } 16 | 17 | linera_sdk::service!(Game2048Service); 18 | 19 | impl WithServiceAbi for Game2048Service { 20 | type Abi = game2048::Game2048Abi; 21 | } 22 | 23 | impl Service for Game2048Service { 24 | type Parameters = (); 25 | 26 | async fn new(runtime: ServiceRuntime) -> Self { 27 | let state = Game2048::load(runtime.root_view_storage_context()) 28 | .await 29 | .expect("Failed to load state"); 30 | Game2048Service { 31 | state: Arc::new(state), 32 | // runtime: Arc::new(Mutex::new(runtime)), 33 | } 34 | } 35 | 36 | async fn handle_query(&self, query: Self::Query) -> Self::QueryResponse { 37 | let schema = Schema::build( 38 | QueryRoot { 39 | state: self.state.clone(), 40 | // runtime: self.runtime.clone(), 41 | }, 42 | MutationRoot, 43 | EmptySubscription, 44 | ) 45 | .finish(); 46 | schema.execute(query).await 47 | } 48 | } 49 | 50 | struct QueryRoot { 51 | state: Arc, 52 | // runtime: Arc>>, 53 | } 54 | 55 | #[derive(SimpleObject)] 56 | struct GameState { 57 | game_id: u16, 58 | board: [[u16; 4]; 4], 59 | is_ended: bool, 60 | score: u64, 61 | } 62 | 63 | #[Object] 64 | impl QueryRoot { 65 | async fn game(&self, game_id: u16) -> Option { 66 | if let Ok(Some(game)) = self.state.games.try_load_entry(&game_id).await { 67 | let game_state = GameState { 68 | game_id: *game.game_id.get(), 69 | board: Game::convert_to_matrix(*game.board.get()), 70 | is_ended: *game.is_ended.get(), 71 | score: *game.score.get(), 72 | }; 73 | Some(game_state) 74 | } else { 75 | None 76 | } 77 | } 78 | } 79 | 80 | struct MutationRoot; 81 | 82 | #[Object] 83 | impl MutationRoot { 84 | async fn new_game(&self, seed: Option) -> Vec { 85 | let seed = seed.unwrap_or(0); 86 | bcs::to_bytes(&Operation::NewGame { seed }).unwrap() 87 | } 88 | 89 | async fn make_move(&self, game_id: u16, direction: Direction) -> Vec { 90 | let operation = Operation::MakeMove { game_id, direction }; 91 | bcs::to_bytes(&operation).unwrap() 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Lpaydat/src/state.rs: -------------------------------------------------------------------------------- 1 | use async_graphql::{scalar, SimpleObject}; 2 | use linera_sdk::views::{ 3 | linera_views, CollectionView, RegisterView, RootView, View, ViewStorageContext, 4 | }; 5 | use serde::{Deserialize, Serialize}; 6 | 7 | #[derive(Debug, Default, Deserialize, Serialize)] 8 | pub enum GameStatus { 9 | #[default] 10 | Active, 11 | Ended, 12 | } 13 | scalar!(GameStatus); 14 | 15 | #[derive(View, SimpleObject)] 16 | #[view(context = "ViewStorageContext")] 17 | pub struct GameState { 18 | pub game_id: RegisterView, 19 | pub board: RegisterView, 20 | pub score: RegisterView, 21 | pub is_ended: RegisterView, 22 | } 23 | 24 | #[derive(RootView, SimpleObject)] 25 | #[view(context = "ViewStorageContext")] 26 | pub struct Game2048 { 27 | pub games: CollectionView, 28 | // leaderboard 29 | } 30 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["svelte.svelte-vscode"] 3 | } 4 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/README.md: -------------------------------------------------------------------------------- 1 | # Svelte + TS + Vite 2 | 3 | This template should help get you started developing with Svelte and TypeScript in Vite. 4 | 5 | ## Recommended IDE Setup 6 | 7 | [VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). 8 | 9 | ## Need an official Svelte framework? 10 | 11 | Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more. 12 | 13 | ## Technical considerations 14 | 15 | **Why use this over SvelteKit?** 16 | 17 | - It brings its own routing solution which might not be preferable for some users. 18 | - It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app. 19 | 20 | This template contains as little as possible to get started with Vite + TypeScript + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project. 21 | 22 | Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate. 23 | 24 | **Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?** 25 | 26 | Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash references keeps the default TypeScript setting of accepting type information from the entire workspace, while also adding `svelte` and `vite/client` type information. 27 | 28 | **Why include `.vscode/extensions.json`?** 29 | 30 | Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project. 31 | 32 | **Why enable `allowJs` in the TS template?** 33 | 34 | While `allowJs: false` would indeed prevent the use of `.js` files in the project, it does not prevent the use of JavaScript syntax in `.svelte` files. In addition, it would force `checkJs: false`, bringing the worst of both worlds: not being able to guarantee the entire codebase is TypeScript, and also having worse typechecking for the existing JavaScript. In addition, there are valid use cases in which a mixed codebase may be relevant. 35 | 36 | **Why is HMR not preserving my local component state?** 37 | 38 | HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the details [here](https://github.com/rixo/svelte-hmr#svelte-hmr). 39 | 40 | If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR. 41 | 42 | ```ts 43 | // store.ts 44 | // An extremely simple external store 45 | import { writable } from 'svelte/store' 46 | export default writable(0) 47 | ``` 48 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Linera 2048 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "game2048", 3 | "version": "0.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "game2048", 9 | "version": "0.0.0", 10 | "dependencies": { 11 | "@urql/svelte": "^4.2.1", 12 | "graphql": "^16.9.0", 13 | "graphql-ws": "^5.16.0", 14 | "urql": "^4.1.0" 15 | }, 16 | "devDependencies": { 17 | "@sveltejs/vite-plugin-svelte": "^3.1.2", 18 | "@tsconfig/svelte": "^5.0.4", 19 | "svelte": "^4.2.19", 20 | "svelte-check": "^4.0.4", 21 | "tslib": "^2.7.0", 22 | "typescript": "^5.5.3", 23 | "vite": "^5.4.8" 24 | } 25 | }, 26 | "node_modules/@0no-co/graphql.web": { 27 | "version": "1.0.8", 28 | "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.0.8.tgz", 29 | "integrity": "sha512-8BG6woLtDMvXB9Ajb/uE+Zr/U7y4qJ3upXi0JQHZmsKUJa7HjF/gFvmL2f3/mSmfZoQGRr9VoY97LCX2uaFMzA==", 30 | "license": "MIT", 31 | "peerDependencies": { 32 | "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" 33 | }, 34 | "peerDependenciesMeta": { 35 | "graphql": { 36 | "optional": true 37 | } 38 | } 39 | }, 40 | "node_modules/@ampproject/remapping": { 41 | "version": "2.3.0", 42 | "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", 43 | "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", 44 | "license": "Apache-2.0", 45 | "dependencies": { 46 | "@jridgewell/gen-mapping": "^0.3.5", 47 | "@jridgewell/trace-mapping": "^0.3.24" 48 | }, 49 | "engines": { 50 | "node": ">=6.0.0" 51 | } 52 | }, 53 | "node_modules/@esbuild/aix-ppc64": { 54 | "version": "0.21.5", 55 | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", 56 | "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", 57 | "cpu": [ 58 | "ppc64" 59 | ], 60 | "dev": true, 61 | "license": "MIT", 62 | "optional": true, 63 | "os": [ 64 | "aix" 65 | ], 66 | "engines": { 67 | "node": ">=12" 68 | } 69 | }, 70 | "node_modules/@esbuild/android-arm": { 71 | "version": "0.21.5", 72 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", 73 | "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", 74 | "cpu": [ 75 | "arm" 76 | ], 77 | "dev": true, 78 | "license": "MIT", 79 | "optional": true, 80 | "os": [ 81 | "android" 82 | ], 83 | "engines": { 84 | "node": ">=12" 85 | } 86 | }, 87 | "node_modules/@esbuild/android-arm64": { 88 | "version": "0.21.5", 89 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", 90 | "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", 91 | "cpu": [ 92 | "arm64" 93 | ], 94 | "dev": true, 95 | "license": "MIT", 96 | "optional": true, 97 | "os": [ 98 | "android" 99 | ], 100 | "engines": { 101 | "node": ">=12" 102 | } 103 | }, 104 | "node_modules/@esbuild/android-x64": { 105 | "version": "0.21.5", 106 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", 107 | "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", 108 | "cpu": [ 109 | "x64" 110 | ], 111 | "dev": true, 112 | "license": "MIT", 113 | "optional": true, 114 | "os": [ 115 | "android" 116 | ], 117 | "engines": { 118 | "node": ">=12" 119 | } 120 | }, 121 | "node_modules/@esbuild/darwin-arm64": { 122 | "version": "0.21.5", 123 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", 124 | "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", 125 | "cpu": [ 126 | "arm64" 127 | ], 128 | "dev": true, 129 | "license": "MIT", 130 | "optional": true, 131 | "os": [ 132 | "darwin" 133 | ], 134 | "engines": { 135 | "node": ">=12" 136 | } 137 | }, 138 | "node_modules/@esbuild/darwin-x64": { 139 | "version": "0.21.5", 140 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", 141 | "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", 142 | "cpu": [ 143 | "x64" 144 | ], 145 | "dev": true, 146 | "license": "MIT", 147 | "optional": true, 148 | "os": [ 149 | "darwin" 150 | ], 151 | "engines": { 152 | "node": ">=12" 153 | } 154 | }, 155 | "node_modules/@esbuild/freebsd-arm64": { 156 | "version": "0.21.5", 157 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", 158 | "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", 159 | "cpu": [ 160 | "arm64" 161 | ], 162 | "dev": true, 163 | "license": "MIT", 164 | "optional": true, 165 | "os": [ 166 | "freebsd" 167 | ], 168 | "engines": { 169 | "node": ">=12" 170 | } 171 | }, 172 | "node_modules/@esbuild/freebsd-x64": { 173 | "version": "0.21.5", 174 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", 175 | "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", 176 | "cpu": [ 177 | "x64" 178 | ], 179 | "dev": true, 180 | "license": "MIT", 181 | "optional": true, 182 | "os": [ 183 | "freebsd" 184 | ], 185 | "engines": { 186 | "node": ">=12" 187 | } 188 | }, 189 | "node_modules/@esbuild/linux-arm": { 190 | "version": "0.21.5", 191 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", 192 | "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", 193 | "cpu": [ 194 | "arm" 195 | ], 196 | "dev": true, 197 | "license": "MIT", 198 | "optional": true, 199 | "os": [ 200 | "linux" 201 | ], 202 | "engines": { 203 | "node": ">=12" 204 | } 205 | }, 206 | "node_modules/@esbuild/linux-arm64": { 207 | "version": "0.21.5", 208 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", 209 | "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", 210 | "cpu": [ 211 | "arm64" 212 | ], 213 | "dev": true, 214 | "license": "MIT", 215 | "optional": true, 216 | "os": [ 217 | "linux" 218 | ], 219 | "engines": { 220 | "node": ">=12" 221 | } 222 | }, 223 | "node_modules/@esbuild/linux-ia32": { 224 | "version": "0.21.5", 225 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", 226 | "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", 227 | "cpu": [ 228 | "ia32" 229 | ], 230 | "dev": true, 231 | "license": "MIT", 232 | "optional": true, 233 | "os": [ 234 | "linux" 235 | ], 236 | "engines": { 237 | "node": ">=12" 238 | } 239 | }, 240 | "node_modules/@esbuild/linux-loong64": { 241 | "version": "0.21.5", 242 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", 243 | "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", 244 | "cpu": [ 245 | "loong64" 246 | ], 247 | "dev": true, 248 | "license": "MIT", 249 | "optional": true, 250 | "os": [ 251 | "linux" 252 | ], 253 | "engines": { 254 | "node": ">=12" 255 | } 256 | }, 257 | "node_modules/@esbuild/linux-mips64el": { 258 | "version": "0.21.5", 259 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", 260 | "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", 261 | "cpu": [ 262 | "mips64el" 263 | ], 264 | "dev": true, 265 | "license": "MIT", 266 | "optional": true, 267 | "os": [ 268 | "linux" 269 | ], 270 | "engines": { 271 | "node": ">=12" 272 | } 273 | }, 274 | "node_modules/@esbuild/linux-ppc64": { 275 | "version": "0.21.5", 276 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", 277 | "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", 278 | "cpu": [ 279 | "ppc64" 280 | ], 281 | "dev": true, 282 | "license": "MIT", 283 | "optional": true, 284 | "os": [ 285 | "linux" 286 | ], 287 | "engines": { 288 | "node": ">=12" 289 | } 290 | }, 291 | "node_modules/@esbuild/linux-riscv64": { 292 | "version": "0.21.5", 293 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", 294 | "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", 295 | "cpu": [ 296 | "riscv64" 297 | ], 298 | "dev": true, 299 | "license": "MIT", 300 | "optional": true, 301 | "os": [ 302 | "linux" 303 | ], 304 | "engines": { 305 | "node": ">=12" 306 | } 307 | }, 308 | "node_modules/@esbuild/linux-s390x": { 309 | "version": "0.21.5", 310 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", 311 | "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", 312 | "cpu": [ 313 | "s390x" 314 | ], 315 | "dev": true, 316 | "license": "MIT", 317 | "optional": true, 318 | "os": [ 319 | "linux" 320 | ], 321 | "engines": { 322 | "node": ">=12" 323 | } 324 | }, 325 | "node_modules/@esbuild/linux-x64": { 326 | "version": "0.21.5", 327 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", 328 | "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", 329 | "cpu": [ 330 | "x64" 331 | ], 332 | "dev": true, 333 | "license": "MIT", 334 | "optional": true, 335 | "os": [ 336 | "linux" 337 | ], 338 | "engines": { 339 | "node": ">=12" 340 | } 341 | }, 342 | "node_modules/@esbuild/netbsd-x64": { 343 | "version": "0.21.5", 344 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", 345 | "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", 346 | "cpu": [ 347 | "x64" 348 | ], 349 | "dev": true, 350 | "license": "MIT", 351 | "optional": true, 352 | "os": [ 353 | "netbsd" 354 | ], 355 | "engines": { 356 | "node": ">=12" 357 | } 358 | }, 359 | "node_modules/@esbuild/openbsd-x64": { 360 | "version": "0.21.5", 361 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", 362 | "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", 363 | "cpu": [ 364 | "x64" 365 | ], 366 | "dev": true, 367 | "license": "MIT", 368 | "optional": true, 369 | "os": [ 370 | "openbsd" 371 | ], 372 | "engines": { 373 | "node": ">=12" 374 | } 375 | }, 376 | "node_modules/@esbuild/sunos-x64": { 377 | "version": "0.21.5", 378 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", 379 | "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", 380 | "cpu": [ 381 | "x64" 382 | ], 383 | "dev": true, 384 | "license": "MIT", 385 | "optional": true, 386 | "os": [ 387 | "sunos" 388 | ], 389 | "engines": { 390 | "node": ">=12" 391 | } 392 | }, 393 | "node_modules/@esbuild/win32-arm64": { 394 | "version": "0.21.5", 395 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", 396 | "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", 397 | "cpu": [ 398 | "arm64" 399 | ], 400 | "dev": true, 401 | "license": "MIT", 402 | "optional": true, 403 | "os": [ 404 | "win32" 405 | ], 406 | "engines": { 407 | "node": ">=12" 408 | } 409 | }, 410 | "node_modules/@esbuild/win32-ia32": { 411 | "version": "0.21.5", 412 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", 413 | "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", 414 | "cpu": [ 415 | "ia32" 416 | ], 417 | "dev": true, 418 | "license": "MIT", 419 | "optional": true, 420 | "os": [ 421 | "win32" 422 | ], 423 | "engines": { 424 | "node": ">=12" 425 | } 426 | }, 427 | "node_modules/@esbuild/win32-x64": { 428 | "version": "0.21.5", 429 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", 430 | "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", 431 | "cpu": [ 432 | "x64" 433 | ], 434 | "dev": true, 435 | "license": "MIT", 436 | "optional": true, 437 | "os": [ 438 | "win32" 439 | ], 440 | "engines": { 441 | "node": ">=12" 442 | } 443 | }, 444 | "node_modules/@jridgewell/gen-mapping": { 445 | "version": "0.3.5", 446 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", 447 | "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", 448 | "license": "MIT", 449 | "dependencies": { 450 | "@jridgewell/set-array": "^1.2.1", 451 | "@jridgewell/sourcemap-codec": "^1.4.10", 452 | "@jridgewell/trace-mapping": "^0.3.24" 453 | }, 454 | "engines": { 455 | "node": ">=6.0.0" 456 | } 457 | }, 458 | "node_modules/@jridgewell/resolve-uri": { 459 | "version": "3.1.2", 460 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 461 | "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 462 | "license": "MIT", 463 | "engines": { 464 | "node": ">=6.0.0" 465 | } 466 | }, 467 | "node_modules/@jridgewell/set-array": { 468 | "version": "1.2.1", 469 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", 470 | "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", 471 | "license": "MIT", 472 | "engines": { 473 | "node": ">=6.0.0" 474 | } 475 | }, 476 | "node_modules/@jridgewell/sourcemap-codec": { 477 | "version": "1.5.0", 478 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", 479 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", 480 | "license": "MIT" 481 | }, 482 | "node_modules/@jridgewell/trace-mapping": { 483 | "version": "0.3.25", 484 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", 485 | "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", 486 | "license": "MIT", 487 | "dependencies": { 488 | "@jridgewell/resolve-uri": "^3.1.0", 489 | "@jridgewell/sourcemap-codec": "^1.4.14" 490 | } 491 | }, 492 | "node_modules/@rollup/rollup-android-arm-eabi": { 493 | "version": "4.24.0", 494 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz", 495 | "integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==", 496 | "cpu": [ 497 | "arm" 498 | ], 499 | "dev": true, 500 | "license": "MIT", 501 | "optional": true, 502 | "os": [ 503 | "android" 504 | ] 505 | }, 506 | "node_modules/@rollup/rollup-android-arm64": { 507 | "version": "4.24.0", 508 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz", 509 | "integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==", 510 | "cpu": [ 511 | "arm64" 512 | ], 513 | "dev": true, 514 | "license": "MIT", 515 | "optional": true, 516 | "os": [ 517 | "android" 518 | ] 519 | }, 520 | "node_modules/@rollup/rollup-darwin-arm64": { 521 | "version": "4.24.0", 522 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz", 523 | "integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==", 524 | "cpu": [ 525 | "arm64" 526 | ], 527 | "dev": true, 528 | "license": "MIT", 529 | "optional": true, 530 | "os": [ 531 | "darwin" 532 | ] 533 | }, 534 | "node_modules/@rollup/rollup-darwin-x64": { 535 | "version": "4.24.0", 536 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz", 537 | "integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==", 538 | "cpu": [ 539 | "x64" 540 | ], 541 | "dev": true, 542 | "license": "MIT", 543 | "optional": true, 544 | "os": [ 545 | "darwin" 546 | ] 547 | }, 548 | "node_modules/@rollup/rollup-linux-arm-gnueabihf": { 549 | "version": "4.24.0", 550 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz", 551 | "integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==", 552 | "cpu": [ 553 | "arm" 554 | ], 555 | "dev": true, 556 | "license": "MIT", 557 | "optional": true, 558 | "os": [ 559 | "linux" 560 | ] 561 | }, 562 | "node_modules/@rollup/rollup-linux-arm-musleabihf": { 563 | "version": "4.24.0", 564 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz", 565 | "integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==", 566 | "cpu": [ 567 | "arm" 568 | ], 569 | "dev": true, 570 | "license": "MIT", 571 | "optional": true, 572 | "os": [ 573 | "linux" 574 | ] 575 | }, 576 | "node_modules/@rollup/rollup-linux-arm64-gnu": { 577 | "version": "4.24.0", 578 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz", 579 | "integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==", 580 | "cpu": [ 581 | "arm64" 582 | ], 583 | "dev": true, 584 | "license": "MIT", 585 | "optional": true, 586 | "os": [ 587 | "linux" 588 | ] 589 | }, 590 | "node_modules/@rollup/rollup-linux-arm64-musl": { 591 | "version": "4.24.0", 592 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz", 593 | "integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==", 594 | "cpu": [ 595 | "arm64" 596 | ], 597 | "dev": true, 598 | "license": "MIT", 599 | "optional": true, 600 | "os": [ 601 | "linux" 602 | ] 603 | }, 604 | "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { 605 | "version": "4.24.0", 606 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz", 607 | "integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==", 608 | "cpu": [ 609 | "ppc64" 610 | ], 611 | "dev": true, 612 | "license": "MIT", 613 | "optional": true, 614 | "os": [ 615 | "linux" 616 | ] 617 | }, 618 | "node_modules/@rollup/rollup-linux-riscv64-gnu": { 619 | "version": "4.24.0", 620 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz", 621 | "integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==", 622 | "cpu": [ 623 | "riscv64" 624 | ], 625 | "dev": true, 626 | "license": "MIT", 627 | "optional": true, 628 | "os": [ 629 | "linux" 630 | ] 631 | }, 632 | "node_modules/@rollup/rollup-linux-s390x-gnu": { 633 | "version": "4.24.0", 634 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz", 635 | "integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==", 636 | "cpu": [ 637 | "s390x" 638 | ], 639 | "dev": true, 640 | "license": "MIT", 641 | "optional": true, 642 | "os": [ 643 | "linux" 644 | ] 645 | }, 646 | "node_modules/@rollup/rollup-linux-x64-gnu": { 647 | "version": "4.24.0", 648 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz", 649 | "integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==", 650 | "cpu": [ 651 | "x64" 652 | ], 653 | "dev": true, 654 | "license": "MIT", 655 | "optional": true, 656 | "os": [ 657 | "linux" 658 | ] 659 | }, 660 | "node_modules/@rollup/rollup-linux-x64-musl": { 661 | "version": "4.24.0", 662 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz", 663 | "integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==", 664 | "cpu": [ 665 | "x64" 666 | ], 667 | "dev": true, 668 | "license": "MIT", 669 | "optional": true, 670 | "os": [ 671 | "linux" 672 | ] 673 | }, 674 | "node_modules/@rollup/rollup-win32-arm64-msvc": { 675 | "version": "4.24.0", 676 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz", 677 | "integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==", 678 | "cpu": [ 679 | "arm64" 680 | ], 681 | "dev": true, 682 | "license": "MIT", 683 | "optional": true, 684 | "os": [ 685 | "win32" 686 | ] 687 | }, 688 | "node_modules/@rollup/rollup-win32-ia32-msvc": { 689 | "version": "4.24.0", 690 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz", 691 | "integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==", 692 | "cpu": [ 693 | "ia32" 694 | ], 695 | "dev": true, 696 | "license": "MIT", 697 | "optional": true, 698 | "os": [ 699 | "win32" 700 | ] 701 | }, 702 | "node_modules/@rollup/rollup-win32-x64-msvc": { 703 | "version": "4.24.0", 704 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz", 705 | "integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==", 706 | "cpu": [ 707 | "x64" 708 | ], 709 | "dev": true, 710 | "license": "MIT", 711 | "optional": true, 712 | "os": [ 713 | "win32" 714 | ] 715 | }, 716 | "node_modules/@sveltejs/vite-plugin-svelte": { 717 | "version": "3.1.2", 718 | "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.2.tgz", 719 | "integrity": "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==", 720 | "dev": true, 721 | "license": "MIT", 722 | "dependencies": { 723 | "@sveltejs/vite-plugin-svelte-inspector": "^2.1.0", 724 | "debug": "^4.3.4", 725 | "deepmerge": "^4.3.1", 726 | "kleur": "^4.1.5", 727 | "magic-string": "^0.30.10", 728 | "svelte-hmr": "^0.16.0", 729 | "vitefu": "^0.2.5" 730 | }, 731 | "engines": { 732 | "node": "^18.0.0 || >=20" 733 | }, 734 | "peerDependencies": { 735 | "svelte": "^4.0.0 || ^5.0.0-next.0", 736 | "vite": "^5.0.0" 737 | } 738 | }, 739 | "node_modules/@sveltejs/vite-plugin-svelte-inspector": { 740 | "version": "2.1.0", 741 | "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.1.0.tgz", 742 | "integrity": "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==", 743 | "dev": true, 744 | "license": "MIT", 745 | "dependencies": { 746 | "debug": "^4.3.4" 747 | }, 748 | "engines": { 749 | "node": "^18.0.0 || >=20" 750 | }, 751 | "peerDependencies": { 752 | "@sveltejs/vite-plugin-svelte": "^3.0.0", 753 | "svelte": "^4.0.0 || ^5.0.0-next.0", 754 | "vite": "^5.0.0" 755 | } 756 | }, 757 | "node_modules/@tsconfig/svelte": { 758 | "version": "5.0.4", 759 | "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-5.0.4.tgz", 760 | "integrity": "sha512-BV9NplVgLmSi4mwKzD8BD/NQ8erOY/nUE/GpgWe2ckx+wIQF5RyRirn/QsSSCPeulVpc3RA/iJt6DpfTIZps0Q==", 761 | "dev": true, 762 | "license": "MIT" 763 | }, 764 | "node_modules/@types/estree": { 765 | "version": "1.0.6", 766 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", 767 | "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", 768 | "license": "MIT" 769 | }, 770 | "node_modules/@urql/core": { 771 | "version": "5.0.6", 772 | "resolved": "https://registry.npmjs.org/@urql/core/-/core-5.0.6.tgz", 773 | "integrity": "sha512-38rgSDqVNihFDauw1Pm9V7XLWIKuK8V9CKgrUF7/xEKinze8ENKP1ZeBhkG+dxWzJan7CHK+SLl46kAdvZwIlA==", 774 | "license": "MIT", 775 | "dependencies": { 776 | "@0no-co/graphql.web": "^1.0.5", 777 | "wonka": "^6.3.2" 778 | } 779 | }, 780 | "node_modules/@urql/svelte": { 781 | "version": "4.2.1", 782 | "resolved": "https://registry.npmjs.org/@urql/svelte/-/svelte-4.2.1.tgz", 783 | "integrity": "sha512-tzjt5qElu6EF4ns+AWLUFvvGFH+bDGEgLStHQTBu76puQcMCW374MrjxWM9lKA6lfA7iUyu1KXkIRhxNy09l4Q==", 784 | "license": "MIT", 785 | "dependencies": { 786 | "@urql/core": "^5.0.0", 787 | "wonka": "^6.3.2" 788 | }, 789 | "peerDependencies": { 790 | "@urql/core": "^5.0.0", 791 | "svelte": "^3.0.0 || ^4.0.0 || ^5.0.0" 792 | } 793 | }, 794 | "node_modules/acorn": { 795 | "version": "8.13.0", 796 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz", 797 | "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==", 798 | "license": "MIT", 799 | "bin": { 800 | "acorn": "bin/acorn" 801 | }, 802 | "engines": { 803 | "node": ">=0.4.0" 804 | } 805 | }, 806 | "node_modules/aria-query": { 807 | "version": "5.3.2", 808 | "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", 809 | "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", 810 | "license": "Apache-2.0", 811 | "engines": { 812 | "node": ">= 0.4" 813 | } 814 | }, 815 | "node_modules/axobject-query": { 816 | "version": "4.1.0", 817 | "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", 818 | "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", 819 | "license": "Apache-2.0", 820 | "engines": { 821 | "node": ">= 0.4" 822 | } 823 | }, 824 | "node_modules/chokidar": { 825 | "version": "4.0.1", 826 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", 827 | "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", 828 | "dev": true, 829 | "license": "MIT", 830 | "dependencies": { 831 | "readdirp": "^4.0.1" 832 | }, 833 | "engines": { 834 | "node": ">= 14.16.0" 835 | }, 836 | "funding": { 837 | "url": "https://paulmillr.com/funding/" 838 | } 839 | }, 840 | "node_modules/code-red": { 841 | "version": "1.0.4", 842 | "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", 843 | "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", 844 | "license": "MIT", 845 | "dependencies": { 846 | "@jridgewell/sourcemap-codec": "^1.4.15", 847 | "@types/estree": "^1.0.1", 848 | "acorn": "^8.10.0", 849 | "estree-walker": "^3.0.3", 850 | "periscopic": "^3.1.0" 851 | } 852 | }, 853 | "node_modules/css-tree": { 854 | "version": "2.3.1", 855 | "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", 856 | "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", 857 | "license": "MIT", 858 | "dependencies": { 859 | "mdn-data": "2.0.30", 860 | "source-map-js": "^1.0.1" 861 | }, 862 | "engines": { 863 | "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" 864 | } 865 | }, 866 | "node_modules/debug": { 867 | "version": "4.3.7", 868 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", 869 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", 870 | "dev": true, 871 | "license": "MIT", 872 | "dependencies": { 873 | "ms": "^2.1.3" 874 | }, 875 | "engines": { 876 | "node": ">=6.0" 877 | }, 878 | "peerDependenciesMeta": { 879 | "supports-color": { 880 | "optional": true 881 | } 882 | } 883 | }, 884 | "node_modules/deepmerge": { 885 | "version": "4.3.1", 886 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", 887 | "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", 888 | "dev": true, 889 | "license": "MIT", 890 | "engines": { 891 | "node": ">=0.10.0" 892 | } 893 | }, 894 | "node_modules/esbuild": { 895 | "version": "0.21.5", 896 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", 897 | "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", 898 | "dev": true, 899 | "hasInstallScript": true, 900 | "license": "MIT", 901 | "bin": { 902 | "esbuild": "bin/esbuild" 903 | }, 904 | "engines": { 905 | "node": ">=12" 906 | }, 907 | "optionalDependencies": { 908 | "@esbuild/aix-ppc64": "0.21.5", 909 | "@esbuild/android-arm": "0.21.5", 910 | "@esbuild/android-arm64": "0.21.5", 911 | "@esbuild/android-x64": "0.21.5", 912 | "@esbuild/darwin-arm64": "0.21.5", 913 | "@esbuild/darwin-x64": "0.21.5", 914 | "@esbuild/freebsd-arm64": "0.21.5", 915 | "@esbuild/freebsd-x64": "0.21.5", 916 | "@esbuild/linux-arm": "0.21.5", 917 | "@esbuild/linux-arm64": "0.21.5", 918 | "@esbuild/linux-ia32": "0.21.5", 919 | "@esbuild/linux-loong64": "0.21.5", 920 | "@esbuild/linux-mips64el": "0.21.5", 921 | "@esbuild/linux-ppc64": "0.21.5", 922 | "@esbuild/linux-riscv64": "0.21.5", 923 | "@esbuild/linux-s390x": "0.21.5", 924 | "@esbuild/linux-x64": "0.21.5", 925 | "@esbuild/netbsd-x64": "0.21.5", 926 | "@esbuild/openbsd-x64": "0.21.5", 927 | "@esbuild/sunos-x64": "0.21.5", 928 | "@esbuild/win32-arm64": "0.21.5", 929 | "@esbuild/win32-ia32": "0.21.5", 930 | "@esbuild/win32-x64": "0.21.5" 931 | } 932 | }, 933 | "node_modules/estree-walker": { 934 | "version": "3.0.3", 935 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", 936 | "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", 937 | "license": "MIT", 938 | "dependencies": { 939 | "@types/estree": "^1.0.0" 940 | } 941 | }, 942 | "node_modules/fdir": { 943 | "version": "6.4.2", 944 | "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.2.tgz", 945 | "integrity": "sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==", 946 | "dev": true, 947 | "license": "MIT", 948 | "peerDependencies": { 949 | "picomatch": "^3 || ^4" 950 | }, 951 | "peerDependenciesMeta": { 952 | "picomatch": { 953 | "optional": true 954 | } 955 | } 956 | }, 957 | "node_modules/fsevents": { 958 | "version": "2.3.3", 959 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 960 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 961 | "dev": true, 962 | "hasInstallScript": true, 963 | "license": "MIT", 964 | "optional": true, 965 | "os": [ 966 | "darwin" 967 | ], 968 | "engines": { 969 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 970 | } 971 | }, 972 | "node_modules/graphql": { 973 | "version": "16.9.0", 974 | "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", 975 | "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", 976 | "license": "MIT", 977 | "engines": { 978 | "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" 979 | } 980 | }, 981 | "node_modules/graphql-ws": { 982 | "version": "5.16.0", 983 | "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.16.0.tgz", 984 | "integrity": "sha512-Ju2RCU2dQMgSKtArPbEtsK5gNLnsQyTNIo/T7cZNp96niC1x0KdJNZV0TIoilceBPQwfb5itrGl8pkFeOUMl4A==", 985 | "license": "MIT", 986 | "workspaces": [ 987 | "website" 988 | ], 989 | "engines": { 990 | "node": ">=10" 991 | }, 992 | "peerDependencies": { 993 | "graphql": ">=0.11 <=16" 994 | } 995 | }, 996 | "node_modules/is-reference": { 997 | "version": "3.0.2", 998 | "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", 999 | "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", 1000 | "license": "MIT", 1001 | "dependencies": { 1002 | "@types/estree": "*" 1003 | } 1004 | }, 1005 | "node_modules/js-tokens": { 1006 | "version": "4.0.0", 1007 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 1008 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 1009 | "license": "MIT", 1010 | "peer": true 1011 | }, 1012 | "node_modules/kleur": { 1013 | "version": "4.1.5", 1014 | "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", 1015 | "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", 1016 | "dev": true, 1017 | "license": "MIT", 1018 | "engines": { 1019 | "node": ">=6" 1020 | } 1021 | }, 1022 | "node_modules/locate-character": { 1023 | "version": "3.0.0", 1024 | "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", 1025 | "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", 1026 | "license": "MIT" 1027 | }, 1028 | "node_modules/loose-envify": { 1029 | "version": "1.4.0", 1030 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 1031 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 1032 | "license": "MIT", 1033 | "peer": true, 1034 | "dependencies": { 1035 | "js-tokens": "^3.0.0 || ^4.0.0" 1036 | }, 1037 | "bin": { 1038 | "loose-envify": "cli.js" 1039 | } 1040 | }, 1041 | "node_modules/magic-string": { 1042 | "version": "0.30.12", 1043 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", 1044 | "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", 1045 | "license": "MIT", 1046 | "dependencies": { 1047 | "@jridgewell/sourcemap-codec": "^1.5.0" 1048 | } 1049 | }, 1050 | "node_modules/mdn-data": { 1051 | "version": "2.0.30", 1052 | "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", 1053 | "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", 1054 | "license": "CC0-1.0" 1055 | }, 1056 | "node_modules/mri": { 1057 | "version": "1.2.0", 1058 | "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", 1059 | "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", 1060 | "dev": true, 1061 | "license": "MIT", 1062 | "engines": { 1063 | "node": ">=4" 1064 | } 1065 | }, 1066 | "node_modules/ms": { 1067 | "version": "2.1.3", 1068 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1069 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1070 | "dev": true, 1071 | "license": "MIT" 1072 | }, 1073 | "node_modules/nanoid": { 1074 | "version": "3.3.7", 1075 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", 1076 | "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", 1077 | "dev": true, 1078 | "funding": [ 1079 | { 1080 | "type": "github", 1081 | "url": "https://github.com/sponsors/ai" 1082 | } 1083 | ], 1084 | "license": "MIT", 1085 | "bin": { 1086 | "nanoid": "bin/nanoid.cjs" 1087 | }, 1088 | "engines": { 1089 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 1090 | } 1091 | }, 1092 | "node_modules/periscopic": { 1093 | "version": "3.1.0", 1094 | "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", 1095 | "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", 1096 | "license": "MIT", 1097 | "dependencies": { 1098 | "@types/estree": "^1.0.0", 1099 | "estree-walker": "^3.0.0", 1100 | "is-reference": "^3.0.0" 1101 | } 1102 | }, 1103 | "node_modules/picocolors": { 1104 | "version": "1.1.1", 1105 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 1106 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 1107 | "dev": true, 1108 | "license": "ISC" 1109 | }, 1110 | "node_modules/postcss": { 1111 | "version": "8.4.47", 1112 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", 1113 | "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", 1114 | "dev": true, 1115 | "funding": [ 1116 | { 1117 | "type": "opencollective", 1118 | "url": "https://opencollective.com/postcss/" 1119 | }, 1120 | { 1121 | "type": "tidelift", 1122 | "url": "https://tidelift.com/funding/github/npm/postcss" 1123 | }, 1124 | { 1125 | "type": "github", 1126 | "url": "https://github.com/sponsors/ai" 1127 | } 1128 | ], 1129 | "license": "MIT", 1130 | "dependencies": { 1131 | "nanoid": "^3.3.7", 1132 | "picocolors": "^1.1.0", 1133 | "source-map-js": "^1.2.1" 1134 | }, 1135 | "engines": { 1136 | "node": "^10 || ^12 || >=14" 1137 | } 1138 | }, 1139 | "node_modules/react": { 1140 | "version": "18.3.1", 1141 | "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", 1142 | "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", 1143 | "license": "MIT", 1144 | "peer": true, 1145 | "dependencies": { 1146 | "loose-envify": "^1.1.0" 1147 | }, 1148 | "engines": { 1149 | "node": ">=0.10.0" 1150 | } 1151 | }, 1152 | "node_modules/readdirp": { 1153 | "version": "4.0.2", 1154 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", 1155 | "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", 1156 | "dev": true, 1157 | "license": "MIT", 1158 | "engines": { 1159 | "node": ">= 14.16.0" 1160 | }, 1161 | "funding": { 1162 | "type": "individual", 1163 | "url": "https://paulmillr.com/funding/" 1164 | } 1165 | }, 1166 | "node_modules/rollup": { 1167 | "version": "4.24.0", 1168 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz", 1169 | "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==", 1170 | "dev": true, 1171 | "license": "MIT", 1172 | "dependencies": { 1173 | "@types/estree": "1.0.6" 1174 | }, 1175 | "bin": { 1176 | "rollup": "dist/bin/rollup" 1177 | }, 1178 | "engines": { 1179 | "node": ">=18.0.0", 1180 | "npm": ">=8.0.0" 1181 | }, 1182 | "optionalDependencies": { 1183 | "@rollup/rollup-android-arm-eabi": "4.24.0", 1184 | "@rollup/rollup-android-arm64": "4.24.0", 1185 | "@rollup/rollup-darwin-arm64": "4.24.0", 1186 | "@rollup/rollup-darwin-x64": "4.24.0", 1187 | "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", 1188 | "@rollup/rollup-linux-arm-musleabihf": "4.24.0", 1189 | "@rollup/rollup-linux-arm64-gnu": "4.24.0", 1190 | "@rollup/rollup-linux-arm64-musl": "4.24.0", 1191 | "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0", 1192 | "@rollup/rollup-linux-riscv64-gnu": "4.24.0", 1193 | "@rollup/rollup-linux-s390x-gnu": "4.24.0", 1194 | "@rollup/rollup-linux-x64-gnu": "4.24.0", 1195 | "@rollup/rollup-linux-x64-musl": "4.24.0", 1196 | "@rollup/rollup-win32-arm64-msvc": "4.24.0", 1197 | "@rollup/rollup-win32-ia32-msvc": "4.24.0", 1198 | "@rollup/rollup-win32-x64-msvc": "4.24.0", 1199 | "fsevents": "~2.3.2" 1200 | } 1201 | }, 1202 | "node_modules/sade": { 1203 | "version": "1.8.1", 1204 | "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", 1205 | "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", 1206 | "dev": true, 1207 | "license": "MIT", 1208 | "dependencies": { 1209 | "mri": "^1.1.0" 1210 | }, 1211 | "engines": { 1212 | "node": ">=6" 1213 | } 1214 | }, 1215 | "node_modules/source-map-js": { 1216 | "version": "1.2.1", 1217 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", 1218 | "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", 1219 | "license": "BSD-3-Clause", 1220 | "engines": { 1221 | "node": ">=0.10.0" 1222 | } 1223 | }, 1224 | "node_modules/svelte": { 1225 | "version": "4.2.19", 1226 | "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz", 1227 | "integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==", 1228 | "license": "MIT", 1229 | "dependencies": { 1230 | "@ampproject/remapping": "^2.2.1", 1231 | "@jridgewell/sourcemap-codec": "^1.4.15", 1232 | "@jridgewell/trace-mapping": "^0.3.18", 1233 | "@types/estree": "^1.0.1", 1234 | "acorn": "^8.9.0", 1235 | "aria-query": "^5.3.0", 1236 | "axobject-query": "^4.0.0", 1237 | "code-red": "^1.0.3", 1238 | "css-tree": "^2.3.1", 1239 | "estree-walker": "^3.0.3", 1240 | "is-reference": "^3.0.1", 1241 | "locate-character": "^3.0.0", 1242 | "magic-string": "^0.30.4", 1243 | "periscopic": "^3.1.0" 1244 | }, 1245 | "engines": { 1246 | "node": ">=16" 1247 | } 1248 | }, 1249 | "node_modules/svelte-check": { 1250 | "version": "4.0.5", 1251 | "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.0.5.tgz", 1252 | "integrity": "sha512-icBTBZ3ibBaywbXUat3cK6hB5Du+Kq9Z8CRuyLmm64XIe2/r+lQcbuBx/IQgsbrC+kT2jQ0weVpZSSRIPwB6jQ==", 1253 | "dev": true, 1254 | "license": "MIT", 1255 | "dependencies": { 1256 | "@jridgewell/trace-mapping": "^0.3.25", 1257 | "chokidar": "^4.0.1", 1258 | "fdir": "^6.2.0", 1259 | "picocolors": "^1.0.0", 1260 | "sade": "^1.7.4" 1261 | }, 1262 | "bin": { 1263 | "svelte-check": "bin/svelte-check" 1264 | }, 1265 | "engines": { 1266 | "node": ">= 18.0.0" 1267 | }, 1268 | "peerDependencies": { 1269 | "svelte": "^4.0.0 || ^5.0.0-next.0", 1270 | "typescript": ">=5.0.0" 1271 | } 1272 | }, 1273 | "node_modules/svelte-hmr": { 1274 | "version": "0.16.0", 1275 | "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz", 1276 | "integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==", 1277 | "dev": true, 1278 | "license": "ISC", 1279 | "engines": { 1280 | "node": "^12.20 || ^14.13.1 || >= 16" 1281 | }, 1282 | "peerDependencies": { 1283 | "svelte": "^3.19.0 || ^4.0.0" 1284 | } 1285 | }, 1286 | "node_modules/tslib": { 1287 | "version": "2.8.0", 1288 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", 1289 | "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", 1290 | "dev": true, 1291 | "license": "0BSD" 1292 | }, 1293 | "node_modules/typescript": { 1294 | "version": "5.6.3", 1295 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", 1296 | "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", 1297 | "dev": true, 1298 | "license": "Apache-2.0", 1299 | "bin": { 1300 | "tsc": "bin/tsc", 1301 | "tsserver": "bin/tsserver" 1302 | }, 1303 | "engines": { 1304 | "node": ">=14.17" 1305 | } 1306 | }, 1307 | "node_modules/urql": { 1308 | "version": "4.1.0", 1309 | "resolved": "https://registry.npmjs.org/urql/-/urql-4.1.0.tgz", 1310 | "integrity": "sha512-NfbfTvxy1sM89EQAJWm89qJZihUWk7BSMfrWgfljFXLOf+e7RK7DtV/Tbg2+82HnCG2x3LcEOJenxiFSYEC+bw==", 1311 | "license": "MIT", 1312 | "dependencies": { 1313 | "@urql/core": "^5.0.0", 1314 | "wonka": "^6.3.2" 1315 | }, 1316 | "peerDependencies": { 1317 | "@urql/core": "^5.0.0", 1318 | "react": ">= 16.8.0" 1319 | } 1320 | }, 1321 | "node_modules/vite": { 1322 | "version": "5.4.9", 1323 | "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.9.tgz", 1324 | "integrity": "sha512-20OVpJHh0PAM0oSOELa5GaZNWeDjcAvQjGXy2Uyr+Tp+/D2/Hdz6NLgpJLsarPTA2QJ6v8mX2P1ZfbsSKvdMkg==", 1325 | "dev": true, 1326 | "license": "MIT", 1327 | "dependencies": { 1328 | "esbuild": "^0.21.3", 1329 | "postcss": "^8.4.43", 1330 | "rollup": "^4.20.0" 1331 | }, 1332 | "bin": { 1333 | "vite": "bin/vite.js" 1334 | }, 1335 | "engines": { 1336 | "node": "^18.0.0 || >=20.0.0" 1337 | }, 1338 | "funding": { 1339 | "url": "https://github.com/vitejs/vite?sponsor=1" 1340 | }, 1341 | "optionalDependencies": { 1342 | "fsevents": "~2.3.3" 1343 | }, 1344 | "peerDependencies": { 1345 | "@types/node": "^18.0.0 || >=20.0.0", 1346 | "less": "*", 1347 | "lightningcss": "^1.21.0", 1348 | "sass": "*", 1349 | "sass-embedded": "*", 1350 | "stylus": "*", 1351 | "sugarss": "*", 1352 | "terser": "^5.4.0" 1353 | }, 1354 | "peerDependenciesMeta": { 1355 | "@types/node": { 1356 | "optional": true 1357 | }, 1358 | "less": { 1359 | "optional": true 1360 | }, 1361 | "lightningcss": { 1362 | "optional": true 1363 | }, 1364 | "sass": { 1365 | "optional": true 1366 | }, 1367 | "sass-embedded": { 1368 | "optional": true 1369 | }, 1370 | "stylus": { 1371 | "optional": true 1372 | }, 1373 | "sugarss": { 1374 | "optional": true 1375 | }, 1376 | "terser": { 1377 | "optional": true 1378 | } 1379 | } 1380 | }, 1381 | "node_modules/vitefu": { 1382 | "version": "0.2.5", 1383 | "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", 1384 | "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", 1385 | "dev": true, 1386 | "license": "MIT", 1387 | "peerDependencies": { 1388 | "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" 1389 | }, 1390 | "peerDependenciesMeta": { 1391 | "vite": { 1392 | "optional": true 1393 | } 1394 | } 1395 | }, 1396 | "node_modules/wonka": { 1397 | "version": "6.3.4", 1398 | "resolved": "https://registry.npmjs.org/wonka/-/wonka-6.3.4.tgz", 1399 | "integrity": "sha512-CjpbqNtBGNAeyNS/9W6q3kSkKE52+FjIj7AkFlLr11s/VWGUu6a2CdYSdGxocIhIVjaW/zchesBQUKPVU69Cqg==", 1400 | "license": "MIT" 1401 | } 1402 | } 1403 | } 1404 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "game2048", 3 | "private": true, 4 | "author": "lpaydat ", 5 | "version": "0.0.0", 6 | "type": "module", 7 | "scripts": { 8 | "dev": "vite", 9 | "build": "vite build", 10 | "preview": "vite preview", 11 | "check": "svelte-check --tsconfig ./tsconfig.json && tsc -p tsconfig.node.json" 12 | }, 13 | "devDependencies": { 14 | "@sveltejs/vite-plugin-svelte": "^3.1.2", 15 | "@tsconfig/svelte": "^5.0.4", 16 | "svelte": "^4.2.19", 17 | "svelte-check": "^4.0.4", 18 | "tslib": "^2.7.0", 19 | "typescript": "^5.5.3", 20 | "vite": "^5.4.8" 21 | }, 22 | "dependencies": { 23 | "@urql/svelte": "^4.2.1", 24 | "graphql": "^16.9.0", 25 | "graphql-ws": "^5.16.0", 26 | "urql": "^4.1.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/src/App.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 70 | 71 |
72 |
73 |

2048

74 | made with ❤️ lpaydat 75 |
76 |
77 | 78 |
79 |
80 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/src/app.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | .card { 39 | padding: 2em; 40 | } 41 | 42 | #app { 43 | max-width: 1280px; 44 | margin: 0 auto; 45 | text-align: center; 46 | } 47 | 48 | button { 49 | border-radius: 8px; 50 | border: 1px solid transparent; 51 | padding: 0.6em 1.2em; 52 | font-size: 1em; 53 | font-weight: 500; 54 | font-family: inherit; 55 | background-color: #1a1a1a; 56 | cursor: pointer; 57 | transition: border-color 0.25s; 58 | } 59 | button:hover { 60 | border-color: #646cff; 61 | } 62 | button:focus, 63 | button:focus-visible { 64 | outline: 4px auto -webkit-focus-ring-color; 65 | } 66 | 67 | @media (prefers-color-scheme: light) { 68 | :root { 69 | color: #213547; 70 | background-color: #ffffff; 71 | } 72 | a:hover { 73 | color: #747bff; 74 | } 75 | button { 76 | background-color: #f9f9f9; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/src/assets/svelte.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/src/components/Board.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 32 | 33 |
34 | {#each [...Array(board.length ** 2).keys()] as box} 35 |
36 | {/each} 37 |
38 | {#each board.reduce((acc, row) => acc.concat(row), []) as value, index} 39 | 40 | {/each} 41 |
42 |
43 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/src/components/BoardTile.svelte: -------------------------------------------------------------------------------- 1 | 87 | 88 | 89 |
92 | {value !== 0 ? 2 ** value : ''} 93 |
94 | 95 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/src/components/Game.svelte: -------------------------------------------------------------------------------- 1 | 134 | 135 | 136 | 137 | 138 | 139 |
140 |
141 | {#if $game.data?.game} 142 |
143 | 144 | {#if $game.data?.game?.isEnded} 145 |
146 |

{getOverlayMessage($game.data?.game?.board)}

147 |
148 | {/if} 149 |
150 | {:else} 151 | 152 | {/if} 153 |
154 | 155 | 156 | 157 | 186 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/src/components/Header.svelte: -------------------------------------------------------------------------------- 1 | 16 | 17 | 59 | 60 |
61 | 62 |
63 |
64 |
Score
65 |
{value}
66 |
67 |
68 |
Best
69 |
{bestScore < value ? value : bestScore}
70 |
71 |
72 |
73 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/src/components/Introduction.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 37 | 38 | 46 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/src/components/MoveLogs.svelte: -------------------------------------------------------------------------------- 1 | 15 | 16 | 42 | 43 | 52 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/src/lib/client.ts: -------------------------------------------------------------------------------- 1 | import { createClient as createWSClient } from "graphql-ws"; 2 | 3 | import { cacheExchange, Client, fetchExchange, subscriptionExchange } from "@urql/svelte"; 4 | 5 | export const getClient = (chainId: string, applicationId: string, port: string) => { 6 | const wsClient = createWSClient({ 7 | url: `ws://localhost:${port}/ws`, 8 | }); 9 | 10 | return new Client({ 11 | url: `http://localhost:${port}/chains/${chainId}/applications/${applicationId}`, 12 | exchanges: [ 13 | cacheExchange, 14 | fetchExchange, 15 | subscriptionExchange({ 16 | forwardSubscription(request) { 17 | const input = { ...request, query: request.query || "" }; 18 | return { 19 | subscribe(sink) { 20 | const unsubscribe = wsClient.subscribe(input, sink); 21 | return { unsubscribe }; 22 | }, 23 | }; 24 | }, 25 | }), 26 | ], 27 | }); 28 | }; 29 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/src/main.ts: -------------------------------------------------------------------------------- 1 | import './app.css' 2 | import App from './App.svelte' 3 | 4 | const app = new App({ 5 | target: document.getElementById('app')!, 6 | }) 7 | 8 | export default app 9 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/svelte.config.js: -------------------------------------------------------------------------------- 1 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' 2 | 3 | export default { 4 | // Consult https://svelte.dev/docs#compile-time-svelte-preprocess 5 | // for more information about preprocessors 6 | preprocess: vitePreprocess(), 7 | } 8 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/svelte/tsconfig.json", 3 | "compilerOptions": { 4 | "target": "ESNext", 5 | "useDefineForClassFields": true, 6 | "module": "ESNext", 7 | "resolveJsonModule": true, 8 | /** 9 | * Typecheck JS in `.svelte` and `.js` files by default. 10 | * Disable checkJs if you'd like to use dynamic types in JS. 11 | * Note that setting allowJs false does not prevent the use 12 | * of JS in `.svelte` files. 13 | */ 14 | "allowJs": true, 15 | "checkJs": true, 16 | "isolatedModules": true, 17 | "moduleDetection": "force" 18 | }, 19 | "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 5 | "skipLibCheck": true, 6 | "module": "ESNext", 7 | "moduleResolution": "bundler", 8 | "strict": true, 9 | "noEmit": false 10 | }, 11 | "include": ["vite.config.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /Lpaydat/web-frontend/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import { svelte } from '@sveltejs/vite-plugin-svelte' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [svelte()], 7 | }) 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linera x Intract: VoyagerX Campaign 2 | 3 | Welcome to the **Linera x Intract: VoyagerX** campaign repository. This repository is designed for developers to submit Linera-based dApps as part of [the VoyagerX campaign](https://www.intract.io/quest/66e94a18b9abe1e27f18b0a5). Participants can earn rewards and contribute to the growing Linera ecosystem. 4 | 5 | For more details on how to participate, visit our [Wiki](https://github.com/linera-io/intract-voyagerx/wiki). 6 | -------------------------------------------------------------------------------- /winrhcp/linera-token-frontend/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linera-io/intract-voyagerx/127de500002a21b3523d77fc6bc27097d580e50e/winrhcp/linera-token-frontend/README.md -------------------------------------------------------------------------------- /winrhcp/linera-token-frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linera-fun-frontend", 3 | "version": "1.0.0", 4 | "description": "Frontend for Linera.fun - A token creation dApp on Linera blockchain", 5 | "main": "index.js", 6 | "dependencies": { 7 | "react": "^17.0.2", 8 | "react-dom": "^17.0.2", 9 | "axios": "^0.21.1" 10 | }, 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build", 14 | "test": "react-scripts test", 15 | "eject": "react-scripts eject" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /winrhcp/linera-token-frontend/public/index.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linera-io/intract-voyagerx/127de500002a21b3523d77fc6bc27097d580e50e/winrhcp/linera-token-frontend/public/index.html -------------------------------------------------------------------------------- /winrhcp/linera-token-frontend/src/App.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import CreateToken from "./components/CreateToken"; 3 | 4 | function App() { 5 | return ( 6 |
7 |

Linera.fun - Token Creation dApp

8 | 9 |
10 | ); 11 | } 12 | 13 | export default App; 14 | -------------------------------------------------------------------------------- /winrhcp/linera-token-frontend/src/components/CreateToken.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { createToken } from "../services/lineraService"; 3 | 4 | function CreateToken() { 5 | const [name, setName] = useState(""); 6 | const [symbol, setSymbol] = useState(""); 7 | const [totalSupply, setTotalSupply] = useState(""); 8 | const [message, setMessage] = useState(""); 9 | 10 | const handleCreateToken = async () => { 11 | const result = await createToken(name, symbol, parseInt(totalSupply)); 12 | setMessage(result ? "Token created successfully!" : "Error creating token."); 13 | }; 14 | 15 | return ( 16 |
17 |

Create Token

18 | setName(e.target.value)} 23 | /> 24 | setSymbol(e.target.value)} 29 | /> 30 | setTotalSupply(e.target.value)} 35 | /> 36 | 37 |

{message}

38 |
39 | ); 40 | } 41 | 42 | export default CreateToken; 43 | -------------------------------------------------------------------------------- /winrhcp/linera-token-frontend/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import App from "./App"; 4 | 5 | ReactDOM.render(, document.getElementById("root")); 6 | -------------------------------------------------------------------------------- /winrhcp/linera-token-frontend/src/services/lineraService.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | const BASE_URL = "http://127.0.0.1:8080"; // Update to your backend URL 4 | 5 | export const createToken = async (name, symbol, totalSupply) => { 6 | try { 7 | const response = await axios.post(`${BASE_URL}/create_token`, { 8 | name, 9 | symbol, 10 | total_supply: totalSupply, 11 | }); 12 | return response.data; 13 | } catch (error) { 14 | console.error("Token creation error:", error); 15 | return { success: false, message: error.message }; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /winrhcp/linera_token_creation/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "linera_token_creation" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | linera-sdk = "0.12.1" 8 | serde = { version = "1.0", features = ["derive"] } 9 | serde_json = "1.0" 10 | actix-web = "4.0" 11 | tokio = { version = "1", features = ["full"] } -------------------------------------------------------------------------------- /winrhcp/linera_token_creation/README.md: -------------------------------------------------------------------------------- 1 | ### Linera.fun 2 | 3 | Linera.fun is a decentralized application built on the Linera blockchain, designed to make token creation fun, accessible, and community-driven. Inspired by platforms like Pump.fun, Linera.fun enables anyone to create tokens easily, leveraging the unique scalability and speed of the Linera network. Whether you're creating tokens for community engagement, social events, or personal projects, Linera.fun makes it possible in just a few steps. 4 | 5 | ### Key Features 6 | - Effortless Token Creation: Create tokens by entering basic information (token name, symbol, and supply) in a quick, user-friendly interface. 7 | - Powered by Linera: Built on Linera’s innovative blockchain, ensuring low fees, high throughput, and seamless transaction experiences. 8 | - Instant Liquidity: Tokens are immediately tradable within the Linera ecosystem, allowing rapid community interaction and engagement. 9 | - Designed for Community and Virality: Like memecoins on other platforms, tokens created on Linera.fun can gain popularity through community-driven, social dynamics. -------------------------------------------------------------------------------- /winrhcp/linera_token_creation/src/contract.rs: -------------------------------------------------------------------------------- 1 | use linera_sdk::Contract; 2 | use crate::views::TokenView; 3 | use crate::types::Token; 4 | use serde::{Deserialize, Serialize}; 5 | 6 | pub async fn create_token(name: &str, symbol: &str, total_supply: u32) -> Result<(), String> { 7 | let mut view = TokenView::load().await; 8 | view.create_token(name, symbol, total_supply); 9 | view.save().await.map_err(|_| "Error saving token".to_string()) 10 | } 11 | -------------------------------------------------------------------------------- /winrhcp/linera_token_creation/src/errors.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub enum TokenError { 3 | BlockchainError, 4 | } 5 | -------------------------------------------------------------------------------- /winrhcp/linera_token_creation/src/main.rs: -------------------------------------------------------------------------------- 1 | mod contract; 2 | mod views; 3 | mod types; 4 | mod errors; 5 | 6 | use actix_web::{post, web, App, HttpServer, Responder, HttpResponse}; 7 | use serde::Deserialize; 8 | use crate::contract::create_token; 9 | use crate::types::TokenRequest; 10 | 11 | #[post("/create_token")] 12 | async fn create_token_endpoint(req: web::Json) -> impl Responder { 13 | let token_name = &req.name; 14 | let token_symbol = &req.symbol; 15 | let total_supply = req.total_supply; 16 | 17 | match create_token(token_name, token_symbol, total_supply).await { 18 | Ok(_) => HttpResponse::Ok().json("Token created successfully"), 19 | Err(err) => HttpResponse::BadRequest().json(format!("Error: {:?}", err)), 20 | } 21 | } 22 | 23 | #[actix_web::main] 24 | async fn main() -> std::io::Result<()> { 25 | HttpServer::new(|| { 26 | App::new() 27 | .service(create_token_endpoint) 28 | }) 29 | .bind("127.0.0.1:8080")? 30 | .run() 31 | .await 32 | } 33 | -------------------------------------------------------------------------------- /winrhcp/linera_token_creation/src/types.rs: -------------------------------------------------------------------------------- 1 | use serde::{Serialize, Deserialize}; 2 | use std::collections::HashMap; 3 | 4 | #[derive(Serialize, Deserialize, Debug)] 5 | pub struct Token { 6 | pub name: String, 7 | pub symbol: String, 8 | pub total_supply: u32, 9 | pub balances: HashMap, 10 | } 11 | 12 | #[derive(Deserialize)] 13 | pub struct TokenRequest { 14 | pub name: String, 15 | pub symbol: String, 16 | pub total_supply: u32, 17 | } 18 | -------------------------------------------------------------------------------- /winrhcp/linera_token_creation/src/views.rs: -------------------------------------------------------------------------------- 1 | use linera_sdk::View; 2 | use crate::types::Token; 3 | use std::collections::HashMap; 4 | 5 | #[derive(View)] 6 | pub struct TokenView { 7 | pub tokens: HashMap, 8 | } 9 | 10 | impl TokenView { 11 | pub fn create_token(&mut self, name: &str, symbol: &str, total_supply: u32) { 12 | let token = Token { 13 | name: name.to_string(), 14 | symbol: symbol.to_string(), 15 | total_supply, 16 | balances: HashMap::new(), 17 | }; 18 | self.tokens.insert(name.to_string(), token); 19 | } 20 | } 21 | --------------------------------------------------------------------------------