start_point
|
@ -0,0 +1 @@
|
||||||
|
/target
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="EMPTY_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/lavina_bridge.iml" filepath="$PROJECT_DIR$/.idea/lavina_bridge.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "lavina_bridge"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
http = "1.1.0"
|
||||||
|
warp = "0.3"
|
||||||
|
reqwest= { version = "0.12.5", features = ["json"] }
|
||||||
|
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
serde_yaml = "0.9.1"
|
||||||
|
|
||||||
|
log = "0.4.22"
|
||||||
|
env_logger = "0.11.5"
|
||||||
|
|
||||||
|
config = "0.14.0"
|
|
@ -0,0 +1,8 @@
|
||||||
|
local_server_address = "127.0.0.1"
|
||||||
|
|
||||||
|
#bridge_host = "127.0.0.1"
|
||||||
|
bridge_port = "3030"
|
||||||
|
|
||||||
|
#lavina_host = "127.0.0.1"
|
||||||
|
lavina_http_port = 8080
|
||||||
|
lavina_irc_port = 6667
|
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 210 KiB |
|
@ -0,0 +1,23 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
use config::{Config, File};
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct AppConfig {
|
||||||
|
pub local_server_address: String,
|
||||||
|
pub bridge_port: u16,
|
||||||
|
pub lavina_http_port: u16,
|
||||||
|
pub lavina_irc_port: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
pub fn load_config() -> AppConfig {
|
||||||
|
let settings = Config::builder()
|
||||||
|
.add_source(File::with_name("config.toml"))
|
||||||
|
.build().unwrap();
|
||||||
|
|
||||||
|
settings
|
||||||
|
.try_deserialize()
|
||||||
|
.unwrap()
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
pub mod service;
|
||||||
|
|
||||||
|
|
||||||
|
pub use crate::models::models::User;
|
|
@ -0,0 +1,57 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
use crate::lavina_clients::http_client::LavinaHttpClient;
|
||||||
|
pub use crate::models::models::User;
|
||||||
|
use serde_json::json;
|
||||||
|
use warp::Filter;
|
||||||
|
use crate::lavina_clients::errors::*;
|
||||||
|
|
||||||
|
pub struct CreateUserService {
|
||||||
|
lavina_client: LavinaHttpClient,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreateUserService {
|
||||||
|
pub fn new(laina_http_client: LavinaHttpClient) -> Self {
|
||||||
|
CreateUserService { lavina_client: laina_http_client }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_user(&self, user: User) -> Result<impl warp::Reply, warp::Rejection> {
|
||||||
|
match self.lavina_client.new_player(&user.login, &user.password).await {
|
||||||
|
Ok(()) => {
|
||||||
|
let response = json!({"create_result": "User created"});
|
||||||
|
Ok::<_, warp::Rejection>(warp::reply::json(&response))
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("Error creating user: {:?}", err);
|
||||||
|
let error_response = match err {
|
||||||
|
PlayerError::UserAlreadyExists(ref name) => {
|
||||||
|
json!({"error": format!("User '{}' already exists", name)})
|
||||||
|
}
|
||||||
|
PlayerError::RequestError(_) => {
|
||||||
|
json!({"error": "Error during request to lavina"})
|
||||||
|
}
|
||||||
|
PlayerError::Other(ref msg) => {
|
||||||
|
json!({"error": format!("Unknown error: {}", msg)})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok::<_, warp::Rejection>(warp::reply::json(&error_response))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn create_user_route(self: Arc<Self>) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
|
||||||
|
warp::path("create-user")
|
||||||
|
.and(warp::post())
|
||||||
|
.and(warp::body::json())
|
||||||
|
.and_then({
|
||||||
|
let user_manager = Arc::clone(&self); // Клонируем Arc для использования в асинхронном блоке
|
||||||
|
move |user: User| {
|
||||||
|
let user_manager = Arc::clone(&user_manager);
|
||||||
|
async move {
|
||||||
|
user_manager.create_user(user).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
use reqwest::Error as ReqwestError;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum PlayerError {
|
||||||
|
UserAlreadyExists(String),
|
||||||
|
RequestError(ReqwestError),
|
||||||
|
Other(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for PlayerError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
PlayerError::UserAlreadyExists(name) => write!(f, "Пользователь с именем '{}' уже существует", name),
|
||||||
|
PlayerError::RequestError(err) => write!(f, "Ошибка запроса: {}", err),
|
||||||
|
PlayerError::Other(msg) => write!(f, "Ошибка: {}", msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ReqwestError> for PlayerError {
|
||||||
|
fn from(err: ReqwestError) -> PlayerError {
|
||||||
|
PlayerError::RequestError(err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
use crate::lavina_clients::errors::*;
|
||||||
|
use reqwest::Client;
|
||||||
|
use crate::configuration::AppConfig;
|
||||||
|
|
||||||
|
pub struct LavinaHttpClient {
|
||||||
|
client: Client,
|
||||||
|
create_player_url: String,
|
||||||
|
set_password_url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LavinaHttpClient {
|
||||||
|
pub fn new(config: &AppConfig) -> Self {
|
||||||
|
LavinaHttpClient {
|
||||||
|
client: Client::new(),
|
||||||
|
|
||||||
|
create_player_url: format!(
|
||||||
|
"http://{}:{}/mgmt/create_player",
|
||||||
|
config.local_server_address, config.lavina_http_port
|
||||||
|
),
|
||||||
|
set_password_url: format!(
|
||||||
|
"http://{}:{}/mgmt/set_password",
|
||||||
|
config.local_server_address, config.lavina_http_port
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub async fn new_player(&self, name: &str, password: &str) -> Result<(), PlayerError> {
|
||||||
|
let mut create_query = std::collections::HashMap::new();
|
||||||
|
create_query.insert("name", name);
|
||||||
|
|
||||||
|
let create_user_response = self.client.post(&self.create_player_url)
|
||||||
|
.json(&create_query).send().await.map_err(PlayerError::from)?;
|
||||||
|
|
||||||
|
let response_message = create_user_response.text().await.map_err(PlayerError::from)?;
|
||||||
|
|
||||||
|
if response_message.contains("error returned from database: (code: 2067) UNIQUE constraint failed: users.name") {
|
||||||
|
log::info!("User {:?} already exists. Response from server: {:?}", name, response_message);
|
||||||
|
return Err(PlayerError::UserAlreadyExists(name.to_string()));
|
||||||
|
} else {
|
||||||
|
log::info!("Created user. Response: {:?}", response_message);
|
||||||
|
self.set_password(name, password).await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_password(&self, name: &str, password: &str) -> Result<(), PlayerError> {
|
||||||
|
let mut set_pass_query = std::collections::HashMap::new();
|
||||||
|
set_pass_query.insert("player_name", name);
|
||||||
|
set_pass_query.insert("password", password);
|
||||||
|
|
||||||
|
let set_password_response = self.client.post(&self.set_password_url)
|
||||||
|
.json(&set_pass_query).send().await.map_err(PlayerError::from)?;
|
||||||
|
|
||||||
|
let _ = set_password_response.text().await.map_err(PlayerError::from)?;
|
||||||
|
log::info!("Password set for user: {:?}", name);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod http_client;
|
||||||
|
pub mod errors;
|
|
@ -0,0 +1,65 @@
|
||||||
|
mod lavina_clients;
|
||||||
|
mod create_user;
|
||||||
|
mod models;
|
||||||
|
mod configuration;
|
||||||
|
|
||||||
|
use warp::Filter;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use log::Level;
|
||||||
|
|
||||||
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
|
|
||||||
|
|
||||||
|
#[macro_use] extern crate log;
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
|
||||||
|
env_logger::Builder::from_default_env()
|
||||||
|
.filter_level(Level::Info.to_level_filter())
|
||||||
|
.init();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let config = configuration::load_config();
|
||||||
|
|
||||||
|
println!("Local Server Address: {}", config.local_server_address);
|
||||||
|
println!("Server Host: {}", config.bridge_port);
|
||||||
|
println!("Lavina HTTP Address: {}", config.lavina_http_port);
|
||||||
|
println!("Lavina IRC Address: {}", config.lavina_irc_port);
|
||||||
|
|
||||||
|
|
||||||
|
let lavina_http_client = lavina_clients::http_client::LavinaHttpClient::new(&config);
|
||||||
|
let create_user_service = create_user::service::CreateUserService::new(lavina_http_client);
|
||||||
|
|
||||||
|
let hello = warp::path::end()
|
||||||
|
.map(|| warp::reply::html("Hello, World!"));
|
||||||
|
|
||||||
|
let images_dir = std::env::current_dir()
|
||||||
|
.expect("Не удалось получить текущую директорию")
|
||||||
|
.join("images");
|
||||||
|
|
||||||
|
let images = warp::path("images")
|
||||||
|
.and(warp::fs::dir(images_dir));
|
||||||
|
|
||||||
|
let webpages_files = std::env::current_dir()
|
||||||
|
.expect("Не удалось получить текущую директорию")
|
||||||
|
.join("webpages");
|
||||||
|
|
||||||
|
let webpages_routes = warp::path("webpages")
|
||||||
|
.and(warp::fs::dir(webpages_files));
|
||||||
|
|
||||||
|
let create_user_route = Arc::new(create_user_service).create_user_route();
|
||||||
|
|
||||||
|
let routes = hello
|
||||||
|
.or(images)
|
||||||
|
.or(webpages_routes)
|
||||||
|
.or(create_user_route);
|
||||||
|
|
||||||
|
let ip_addr: IpAddr = config.local_server_address.parse().expect("REASON");
|
||||||
|
let socket_addr = SocketAddr::new(ip_addr, config.bridge_port);
|
||||||
|
|
||||||
|
warp::serve(routes)
|
||||||
|
.run(socket_addr)
|
||||||
|
.await;
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod models;
|
|
@ -0,0 +1,9 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub struct User {
|
||||||
|
pub login: String,
|
||||||
|
pub password: String,
|
||||||
|
}
|
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 210 KiB |
|
@ -0,0 +1,73 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
<title>My Website Title</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="welcome-to">
|
||||||
|
<h1>Welcome to</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="shimmering-name">
|
||||||
|
<h1>Lavina</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<img class="slowpoke-moves" src="/images/slowpoke_blinking.gif" alt="this slowpoke moves" width="250"/>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="login">
|
||||||
|
|
||||||
|
<form class="login__form" onsubmit="">
|
||||||
|
<h1 class="login__title">Log In</h1>
|
||||||
|
|
||||||
|
<div class="login__inputs">
|
||||||
|
<div class="login__box">
|
||||||
|
<input type="text" id="login" placeholder="Login" required class="login__input"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="login__box">
|
||||||
|
<input type="password" placeholder="Password" required class="login__input"
|
||||||
|
on:input=move |ev| { set_pwd(event_target_value(&ev))}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<button type="submit" class="login__button">Start messaging</button>
|
||||||
|
|
||||||
|
<div class="login__register">
|
||||||
|
Dont have an account? <a href="#">Register</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
<form class="login__form" onsubmit="">
|
||||||
|
<h1 class="login__title">Log In</h1>
|
||||||
|
|
||||||
|
<div class="login__inputs">
|
||||||
|
<div class="login__box">
|
||||||
|
<input type="text" id="login" placeholder="Login" required class="login__input"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="login__box">
|
||||||
|
<input type="password" placeholder="Password" required class="login__input"
|
||||||
|
on:input=move |ev| { set_pwd(event_target_value(&ev))}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<button type="submit" class="login__button">Start messaging</button>
|
||||||
|
|
||||||
|
<div class="login__register">
|
||||||
|
Dont have an account? <a href="#">Register</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,51 @@
|
||||||
|
|
||||||
|
async function newPlayer(name, password) {
|
||||||
|
const urlCreatePlayer = 'http://127.0.0.1:8080/mgmt/create_player';
|
||||||
|
const urlSetPassword = 'http://127.0.0.1:8080/mgmt/set_password';
|
||||||
|
|
||||||
|
const createQuery = {
|
||||||
|
name: name
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const createResponse = await fetch(urlCreatePlayer, {
|
||||||
|
method: 'POST',
|
||||||
|
mode: 'no-cors',
|
||||||
|
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(createQuery)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!createResponse.ok) {
|
||||||
|
throw new Error(`Ошибка создания игрока: ${createResponse.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const setPasswordQuery = {
|
||||||
|
player_name: name,
|
||||||
|
password: password
|
||||||
|
};
|
||||||
|
|
||||||
|
const passwordResponse = await fetch(urlSetPassword, {
|
||||||
|
method: 'POST',
|
||||||
|
mode: 'no-cors',
|
||||||
|
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(setPasswordQuery)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!passwordResponse.ok) {
|
||||||
|
throw new Error(`Ошибка установки пароля: ${passwordResponse.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Игрок успешно создан и пароль установлен.');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Произошла ошибка:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Пример вызова функции
|
||||||
|
newPlayer('Igrogee', 'ПарольИгрока');
|
|
@ -0,0 +1,369 @@
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
input::placeholder{
|
||||||
|
opacity: 0.5;
|
||||||
|
font-size: 75%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
input {
|
||||||
|
font-size: 17px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
/* background-image: linear-gradient(to bottom, #8221fa, #4221fa);
|
||||||
|
*/ background-image: linear-gradient(to bottom, #3b116e, #221475);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
background-attachment:fixed;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
font: 13px 'Arial', sans-serif;
|
||||||
|
line-height: 1.5em;
|
||||||
|
color: #FFFFFF;
|
||||||
|
min-width: 399px;
|
||||||
|
max-width: 799px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
display: grid;
|
||||||
|
gap: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin: 0;
|
||||||
|
padding: 14px 14px 14px 14px;
|
||||||
|
/* border: 0;
|
||||||
|
*/ background: none;
|
||||||
|
font-size: 99%;
|
||||||
|
font-family: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
:focus {
|
||||||
|
outline: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slowpoke-moves {
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shimmering-name {
|
||||||
|
margin-top: 55px;
|
||||||
|
color: rgb(218, 218, 218);
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 36px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-to {
|
||||||
|
margin-top: 30px;
|
||||||
|
color: rgb(200, 200, 200, 0.6);
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 22px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.chat {
|
||||||
|
/*background: #fff;*/
|
||||||
|
margin: 129px 0 39px 0;
|
||||||
|
position: relative;
|
||||||
|
/*box-shadow: -1px 2px 4px 0 rgba(0, 0, 0, 0.2), -1px 25px 49px 0 rgba(0, 0, 0, 0.1);*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat h1 {
|
||||||
|
position: absolute;
|
||||||
|
top: -146px;
|
||||||
|
width: 99%;
|
||||||
|
font-size: 50px;
|
||||||
|
font-weight: 349;
|
||||||
|
text-align: center;
|
||||||
|
padding: 14px 0px;
|
||||||
|
color: rgba(242, 245, 248, 0.479);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
margin: 0;
|
||||||
|
padding: 14px 14px 14px 59px;
|
||||||
|
list-style: none;
|
||||||
|
border-radius: 20px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.message li {
|
||||||
|
position: relative;
|
||||||
|
font-size: 23px;
|
||||||
|
border-bottom: 0px solid #ededed;
|
||||||
|
border-radius: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enter-message {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 10px;
|
||||||
|
width: 800px;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 23px;
|
||||||
|
font-family: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
line-height: 1.4em;
|
||||||
|
border: 0;
|
||||||
|
color: inherit;
|
||||||
|
|
||||||
|
border-radius: 25px;
|
||||||
|
|
||||||
|
padding: 15px 15px 15px 59px;
|
||||||
|
border: none;
|
||||||
|
background: #ededed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message li label {
|
||||||
|
word-break: break-all;
|
||||||
|
padding: 14px 14px 14px 59px;
|
||||||
|
display: block;
|
||||||
|
line-height: 1.2;
|
||||||
|
transition: color -0.6s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Styles for the remove button */
|
||||||
|
.message li .remove {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: -1px;
|
||||||
|
right: 25px;
|
||||||
|
bottom: -1px;
|
||||||
|
width: 39px;
|
||||||
|
height: 39px;
|
||||||
|
font-size: 29px;
|
||||||
|
color: #cc9a9a;
|
||||||
|
transition: color -0.2s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hover styles for the remove button */
|
||||||
|
.message li .remove:hover {
|
||||||
|
color: #af4246;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pseudo-element content for the remove button */
|
||||||
|
.message li .remove:after {
|
||||||
|
content: '×';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Show the remove button on hover */
|
||||||
|
.message li:hover .remove {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*=============== VARIABLES CSS ===============*/
|
||||||
|
:root {
|
||||||
|
/*========== Colors ==========*/
|
||||||
|
/*Color mode HSL(hue, saturation, lightness)*/
|
||||||
|
--white-color: hsl(0, 0%, 100%);
|
||||||
|
--black-color: hsl(0, 0%, 0%);
|
||||||
|
|
||||||
|
/*========== Font and typography ==========*/
|
||||||
|
/*.5rem = 8px | 1rem = 16px ...*/
|
||||||
|
--body-font: "Poppins", sans-serif;
|
||||||
|
--h1-font-size: 2rem;
|
||||||
|
--normal-font-size: 1rem;
|
||||||
|
--small-font-size: .813rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*=============== BASE ===============*/
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0;
|
||||||
|
/* margin: 0; */
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-family: var(--body-font);
|
||||||
|
font-size: var(--normal-font-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*=============== LOGIN ===============*/
|
||||||
|
.login {
|
||||||
|
position: relative;
|
||||||
|
margin-top: -6px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__bg {
|
||||||
|
position: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
object-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__form {
|
||||||
|
position: center;
|
||||||
|
background-color: hsla(0, 0%, 100%, .01);
|
||||||
|
border: 2px solid hsla(0, 0%, 100%, .7);
|
||||||
|
padding: 2.5rem 1rem;
|
||||||
|
color: var(--white-color);
|
||||||
|
border-radius: 1rem;
|
||||||
|
backdrop-filter: blur(16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__title {
|
||||||
|
text-align: center;
|
||||||
|
font-size: var(--h1-font-size);
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__inputs,
|
||||||
|
.login__box {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__inputs {
|
||||||
|
row-gap: 1.25rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-size: 50px
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__box {
|
||||||
|
grid-template-columns: 1fr max-content;
|
||||||
|
column-gap: .75rem;
|
||||||
|
align-items: center;
|
||||||
|
border: 2px solid hsla(0, 0%, 100%, .7);
|
||||||
|
padding-inline: 1.25rem;
|
||||||
|
border-radius: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__input,
|
||||||
|
.login__button {
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__input {
|
||||||
|
width: 100%;
|
||||||
|
background: none;
|
||||||
|
color: var(--white-color);
|
||||||
|
padding-block: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__input::placeholder {
|
||||||
|
color: var(--white-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__box i {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__check,
|
||||||
|
.login__check-box {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__check {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-size: var(--small-font-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__check-box {
|
||||||
|
column-gap: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__check-input {
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
accent-color: var(--white-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__forgot {
|
||||||
|
color: var(--white-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__forgot:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.login__button {
|
||||||
|
margin-top: 30px;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
padding: 1.1rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
|
||||||
|
opacity: 1.0;
|
||||||
|
transition: 0.5s;
|
||||||
|
|
||||||
|
border: 2px solid black;
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
border-color: #04AA6D;
|
||||||
|
|
||||||
|
border-radius: 4rem;
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
animation: fading-border-animation 4s linear infinite;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__button:hover {
|
||||||
|
background-color: white;
|
||||||
|
color: black;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fading-border-animation {
|
||||||
|
0% {border-color:rgba(255,255,255,0.3);}
|
||||||
|
50% {border-color:rgba(255,255,255,1.0);}
|
||||||
|
100% {border-color:rgba(255,255,255,0.3);}
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__register {
|
||||||
|
font-size: var(--small-font-size);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__register a {
|
||||||
|
color: var(--white-color);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login__register a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*=============== BREAKPOINTS ===============*/
|
||||||
|
/* For medium devices */
|
||||||
|
@media screen and (min-width: 576px) {
|
||||||
|
.login {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.login__form {
|
||||||
|
width: 420px;
|
||||||
|
padding-inline: 2.5rem;
|
||||||
|
}
|
||||||
|
.login__title {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 210 KiB |
After Width: | Height: | Size: 100 KiB |
|
@ -0,0 +1,68 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>JsBook</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.active {
|
||||||
|
background-color: green;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
font-size: medium;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
position: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<img id="output" src="../images/1.png" alt="">
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<nav>
|
||||||
|
<button id="1" class="active">1</button>
|
||||||
|
<button id="2">2</button>
|
||||||
|
<button id="3">3</button>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
const output = document.getElementById("output");
|
||||||
|
const buttons = document.querySelectorAll('nav button');
|
||||||
|
console.log(buttons);
|
||||||
|
|
||||||
|
let active = buttons[0];
|
||||||
|
console.log(active);
|
||||||
|
|
||||||
|
function showImage() {
|
||||||
|
current = this;
|
||||||
|
|
||||||
|
output.src = '../images/' + this.id + '.jpg';
|
||||||
|
buttons.forEach ( (el) => {
|
||||||
|
el == this ? el.className = 'active' : el.className = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons.forEach (
|
||||||
|
(el) => {
|
||||||
|
el.addEventListener('click', showImage)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
</script>
|
|
@ -0,0 +1,17 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>JsBook</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Пересчет величин</h1>
|
||||||
|
<script type="text/javascript">
|
||||||
|
const ins = window.prompt("Дюймы");
|
||||||
|
const cens = ins * 2.54;
|
||||||
|
window.document.write('<p>', cens, '</p>');
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,37 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>JsBook</title>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
background-color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-decoration:wavy;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Список</h1>
|
||||||
|
<h2>fsdfss</h2>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function listValues() {
|
||||||
|
window.document.write('<ul>');
|
||||||
|
for (i=0; i<arguments.length; i++){
|
||||||
|
window.document.write('<li>', arguments[i], '</li>');
|
||||||
|
console.log(arguments[i])};
|
||||||
|
window.document.write('</ul>');
|
||||||
|
}
|
||||||
|
|
||||||
|
listValues('Html', 'Css', 'Js', 'keke', 'sdew');
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>JsBook</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<iframe src="example2.html" frameborder="1"></iframe>
|
||||||
|
<input type="date">
|
||||||
|
<h1>Список</h1>
|
||||||
|
<script type="text/javascript">
|
||||||
|
let person = {
|
||||||
|
"keke": 100,
|
||||||
|
"lol": "lol_value",
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in person){
|
||||||
|
document.write('<br/>', i, ': ', person[i]);
|
||||||
|
console.log('----------------')
|
||||||
|
console.log(person[i]);}
|
||||||
|
|
||||||
|
throw new TypeError('LLLLLLL')
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
var x = document.getElementById("login");
|
||||||
|
var y = document.getElementById("register");
|
||||||
|
var z = document.getElementById("btn");
|
||||||
|
|
||||||
|
function register_form() {
|
||||||
|
x.style.left = "-400px";
|
||||||
|
y.style.left = "50px";
|
||||||
|
z.style.left = "120px";
|
||||||
|
}
|
||||||
|
|
||||||
|
function login_form() {
|
||||||
|
x.style.left = "50px";
|
||||||
|
y.style.left = "450px";
|
||||||
|
z.style.left = "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("login").addEventListener("submit", async function(event) {
|
||||||
|
|
||||||
|
var username = document.getElementById("login_input").value;
|
||||||
|
var password = document.getElementById("password_input").value;
|
||||||
|
|
||||||
|
await newPlayer(username, password);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
const host = '127.0.0.1'
|
||||||
|
|
||||||
|
// Функция newPlayer
|
||||||
|
async function newPlayer(name, password) {
|
||||||
|
const urlCreatePlayer = 'http://'+host+':8080/mgmt/create_player';
|
||||||
|
const urlSetPassword = 'http://'+host+':8080/mgmt/set_password';
|
||||||
|
|
||||||
|
console.info(urlCreatePlayer);
|
||||||
|
const createQuery = {
|
||||||
|
name: name
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
alert('Ready?');
|
||||||
|
|
||||||
|
fetch(urlCreatePlayer, {
|
||||||
|
method: 'POST',
|
||||||
|
mode: 'no-cors',
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: JSON.stringify(createQuery)
|
||||||
|
});
|
||||||
|
|
||||||
|
alert('User created');
|
||||||
|
|
||||||
|
const setPasswordQuery = {
|
||||||
|
player_name: name,
|
||||||
|
password: password
|
||||||
|
};
|
||||||
|
|
||||||
|
fetch(urlSetPassword, {
|
||||||
|
method: 'POST',
|
||||||
|
mode: 'no-cors',
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: JSON.stringify(setPasswordQuery)
|
||||||
|
});
|
||||||
|
|
||||||
|
alert('Password setted');
|
||||||
|
console.info('Игрок успешно создан и пароль установлен.');
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Произошла ошибка: ${error}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
alert('End of creation');
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Document</title>
|
||||||
|
<link rel="stylesheet" href="test_style.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="hero">
|
||||||
|
<div class="form-box">
|
||||||
|
<div class="button-box">
|
||||||
|
<div id="btn"></div>
|
||||||
|
<button type="button" class="log-reg-button" onclick="login_form()">Log In</button>
|
||||||
|
<button type="button" class="log-reg-button" onclick="register_form()">Register</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="social-icons">
|
||||||
|
<img src="../images/telegram-icon-2048x2048-l6ni6sux.png" alt="">
|
||||||
|
<img src="../images/telegram-icon-2048x2048-l6ni6sux.png" alt="">
|
||||||
|
<img src="../images/telegram-icon-2048x2048-l6ni6sux.png" alt="">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form id="login" class="input-group">
|
||||||
|
<input type="text" id="login_input" class="input-field" placeholder="Login" required>
|
||||||
|
<input type="text" id="password_input" class="input-field" placeholder="Password" required>
|
||||||
|
<input type="checkbox" class="checkbox"><span>Remember Password</span>
|
||||||
|
<button type="submit" class="submit-btn">Log In</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<form id="register" class="input-group">
|
||||||
|
<input type="text" class="input-field" placeholder="Login" required>
|
||||||
|
<input type="email" class="input-field" placeholder="Email" required>
|
||||||
|
<input type="text" class="input-field" placeholder="Password" required>
|
||||||
|
<input type="checkbox" class="checkbox"><span>I argee to the terms</span>
|
||||||
|
<button type="submit" class="submit-btn">Register</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script src="js_script.js"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,119 @@
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background-image: url("http://127.0.0.1:3030/images/rain.jpg");
|
||||||
|
background-position: center;
|
||||||
|
background-size: cover;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-box {
|
||||||
|
width: 380px;
|
||||||
|
height: 480px;
|
||||||
|
position: relative;
|
||||||
|
margin: 6% auto;
|
||||||
|
background: rgb(255,255,255, 0.9);;
|
||||||
|
padding: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
backdrop-filter: blur(16px);
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-box {
|
||||||
|
width: 220px;
|
||||||
|
margin: 35px auto;
|
||||||
|
position: relative;
|
||||||
|
box-shadow: 0 0 20px 9px #ff61241f;
|
||||||
|
border-radius: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-reg-button {
|
||||||
|
padding: 10px 30px;
|
||||||
|
cursor: pointer;
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
outline: none;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#btn {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 100px;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(to right, #ff105f, #ffad06);
|
||||||
|
border-radius: 30px;
|
||||||
|
transition: .5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-icons {
|
||||||
|
margin: 30px auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-icons img {
|
||||||
|
width: 30px;
|
||||||
|
margin: 0 12px;
|
||||||
|
box-shadow: 0 0 20px 0 #7f7f7f2d;
|
||||||
|
cursor: pointer;
|
||||||
|
filter: saturate(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group{
|
||||||
|
top: 180px;
|
||||||
|
position: absolute;
|
||||||
|
width: 280px;
|
||||||
|
transition: .5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.input-field {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px 0;
|
||||||
|
margin: 5px 0;
|
||||||
|
border-left: 0;
|
||||||
|
border-right: 0;
|
||||||
|
border-top: 0;
|
||||||
|
border-bottom: 1px solid #999;
|
||||||
|
outline: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-btn {
|
||||||
|
width: 85%;
|
||||||
|
padding: 10px 30px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
background: linear-gradient(to right, #ff105f, #ffad06);
|
||||||
|
border: 0;
|
||||||
|
outline: none;
|
||||||
|
border-radius: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox {
|
||||||
|
margin: 30px 10px 30px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: #777;
|
||||||
|
font-size: 12px;
|
||||||
|
bottom: 68px;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#login {
|
||||||
|
left: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#register {
|
||||||
|
left: 450px;
|
||||||
|
}
|