diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..66ad78a --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/Data +/Public/data +*.[Ss]ecrets.* +*.[Ss]ecret.* +*.deleted.* +/Python/websockets +__pycache__ +.sass-cache \ No newline at end of file diff --git a/Artbook/AnP_telegram.png b/Artbook/AnP_telegram.png new file mode 100755 index 0000000..911f643 Binary files /dev/null and b/Artbook/AnP_telegram.png differ diff --git a/Artbook/AnPv1.svg b/Artbook/AnPv1.svg new file mode 100755 index 0000000..7d13385 --- /dev/null +++ b/Artbook/AnPv1.svg @@ -0,0 +1,353 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Artbook/AnPv1.xcf b/Artbook/AnPv1.xcf new file mode 100755 index 0000000..9cea9f5 Binary files /dev/null and b/Artbook/AnPv1.xcf differ diff --git a/Artbook/images.svg b/Artbook/images.svg new file mode 100755 index 0000000..fa8d2ca --- /dev/null +++ b/Artbook/images.svg @@ -0,0 +1,68 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/Artbook/images.xcf b/Artbook/images.xcf new file mode 100755 index 0000000..a457992 Binary files /dev/null and b/Artbook/images.xcf differ diff --git a/JSON/AnP.routes.json b/JSON/AnP.routes.json new file mode 100644 index 0000000..d579b34 --- /dev/null +++ b/JSON/AnP.routes.json @@ -0,0 +1,4 @@ +[ + "get:/ /Public", + "post:/ai/new_message ai@new_message" +] \ No newline at end of file diff --git a/JSON/AnP.settings.json b/JSON/AnP.settings.json new file mode 100644 index 0000000..ebe075d --- /dev/null +++ b/JSON/AnP.settings.json @@ -0,0 +1,87 @@ +{ + + "AnP_start" : null, + "end_print_types" : ["UNKN", "EXCE", "ERRO"], + "root_projects_paths" : [], + "print_format" : "[{type}] {yyyy}{mm}{dd} {hh}{ii}{ss} [{line}]{file}({method}): {message}", + "exception_format" : " '[{line}]{file}({method})'{lines}\n\n{exception_message}", + "AnP_end" : null, + + "AnP_SettingsManager_start" : null, + "default_settings_files" : "/JSON/AnP.settings.json", + "default_secrets_files" : "/JSON/AnP.secrets.json", + "AnP_SettingsManager_end" : null, + + "AnP_I18NManager_start" : null, + "default_i18n_files" : [ + "/JSON/I18N/AnP.i18n.english.json", + "/JSON/I18N/AnP.i18n.espanol.json", + "/JSON/I18N/AnP.i18n.galego.json", + "/JSON/I18N/AnP.i18n.nihongo.json", + "/JSON/I18N/AnP.i18n.russkiy.json" + ], + "default_language" : "english", + "language" : "english", + "AnP_I18NManager_end" : null, + + "AnP_PrintTypesManager_start" : null, + "default_print_types" : [ + ["unkn", "unknown"], + ["info", "information"], + ["warn", "warning"], + ["erro", "error", "no", "wrong", "bad", "fail", "incorrect"], + [" ok ", "ok", "success", "good", "correct", "right", "yes"], + ["exce", "exception", "traceback", "trace"], + ["test", "debug", "comment", "log", "print"] + ], + "AnP_PrintTypesManager_end" : null, + + "AnP_TerminalManager_start" : null, + "AnP_TerminalManager_end" : null, + + "AnP_ModelsManager_start" : null, + "AnP_ModelsManager_end" : null, + + "AnP_ControllersManager_start" : null, + "default_controllers" : { + "ai" : "AIController" + }, + "AnP_ControllersManager_end" : null, + + "AnP_IndexesManager_start" : null, + "default_indexes" : [ + ["index.html", "index.htm", "index.w.md", "index.md"] + ], + "AnP_IndexesManager_end" : null, + + "AnP_RoutesManager_start" : null, + "default_routes_files" : "/JSON/AnP.routes.json", + "AnP_RoutesManager_end" : null, + + "AnP_HTTPServer_start" : null, + "http_server_host" : "", + "http_server_port" : 18000, + "AnP_HTTPServer_end" : null, + + "AnP_WebSocketServer_start" : null, + "web_socket_server_host" : "", + "web_socket_server_port" : 18765, + "AnP_WebSocketServer_end" : null, + + "AnP_TitlesManager_start" : null, + "default_titles_files" : [ + "/JSON/AnP.titles.json", + "/JSON/AnP.titles.secrets.json" + ], + "AnP_TitlesManager_end" : null, + + "AnP_AIModel_start" : null, + "titles_model" : "gemma3:1b", + "titles_temperature" : 0.0, + "titles_prompt_file" : "/MD/AnP.titles-prompt.md", + "responses_model" : "gemma3:1b", + "responses_temperature" : 7.0, + "response_with_titles_prompt_file" : "/MD/AnP.response-with-titles.md", + "AnP_AIModel_end" : null + +} \ No newline at end of file diff --git a/JSON/I18N/AnP.i18n.english.json b/JSON/I18N/AnP.i18n.english.json new file mode 100644 index 0000000..c713dda --- /dev/null +++ b/JSON/I18N/AnP.i18n.english.json @@ -0,0 +1,3 @@ +{ + "english" : {} +} \ No newline at end of file diff --git a/JSON/I18N/AnP.i18n.espanol.json b/JSON/I18N/AnP.i18n.espanol.json new file mode 100644 index 0000000..c5eb83e --- /dev/null +++ b/JSON/I18N/AnP.i18n.espanol.json @@ -0,0 +1,47 @@ +{ + "espanol" : { + + "AnP_start" : null, + "AnP_end" : null, + + "AnP_SettingsManager_start" : null, + "AnP_SettingsManager_end" : null, + + "AnP_I18NManager_start" : null, + "AnP_I18NManager_end" : null, + + "AnP_PrintTypesManager_start" : null, + "AnP_PrintTypesManager_end" : null, + + "AnP_TerminalManager_start" : null, + "terminal_manager_unknown_command" : "El comando '{command}' es desconocido.", + "terminal_manager_exception" : "Hubo una excepción al intentar procesar el comando '{command}'.", + "AnP_TerminalManager_end" : null, + + "AnP_ModelsManager_start" : null, + "AnP_ModelsManager_end" : null, + + "AnP_ControllersManager_start" : null, + "AnP_ControllersManager_end" : null, + + "AnP_IndexesManager_start" : null, + "AnP_IndexesManager_end" : null, + + "AnP_RoutesManager_start" : null, + "AnP_RoutesManager_end" : null, + + "AnP_WebSocketServerDriver_start" : null, + "web_socket_server_client_close_exception" : "El Web Socket Servidor '{host}:{port}' ha cerrado la conexión con el cliente '{key}'.", + "web_socket_server_client_connected" : "El cliente '{key}' se ha conectado al Web Socket Servidor '{host}:{port}' desde '{client_host}:{client_port}'.", + "web_socket_server_client_exception" : "Excepción al intentar procesar un mensaje de recepción del cliente '{key}' en el Web Socket Servidor '{host}:{port}'.", + "web_socket_server_client_disconnected" : "El cliente '{key}' se ha desconectado del Web Socket Servidor '{host}:{port}'.", + "AnP_WebSocketServerDriver_end" : null, + + "AnP_TitlesManager_start" : null, + "AnP_TitlesManager_end" : null, + + "AnP_AIModel_start" : null, + "AnP_AIModel_end" : null + + } +} \ No newline at end of file diff --git a/JSON/I18N/AnP.i18n.galego.json b/JSON/I18N/AnP.i18n.galego.json new file mode 100644 index 0000000..39f43be --- /dev/null +++ b/JSON/I18N/AnP.i18n.galego.json @@ -0,0 +1,3 @@ +{ + "galego" : {} +} \ No newline at end of file diff --git a/JSON/I18N/AnP.i18n.nihongo.json b/JSON/I18N/AnP.i18n.nihongo.json new file mode 100644 index 0000000..eff18c6 --- /dev/null +++ b/JSON/I18N/AnP.i18n.nihongo.json @@ -0,0 +1,3 @@ +{ + "nihongo" : {} +} \ No newline at end of file diff --git a/JSON/I18N/AnP.i18n.russkiy.json b/JSON/I18N/AnP.i18n.russkiy.json new file mode 100644 index 0000000..b765480 --- /dev/null +++ b/JSON/I18N/AnP.i18n.russkiy.json @@ -0,0 +1,3 @@ +{ + "russkiy" : {} +} \ No newline at end of file diff --git a/Public/ecma/Application/AnP.ecma.js b/Public/ecma/Application/AnP.ecma.js new file mode 100644 index 0000000..e44c964 --- /dev/null +++ b/Public/ecma/Application/AnP.ecma.js @@ -0,0 +1,191 @@ +"use strict"; + +import {FilesDriver} from "../Drivers/FilesDriver.ecma.js"; +import {PrintTypesManager} from "../Managers/PrintTypesManager.ecma.js"; +import {SettingsManager} from "../Managers/SettingsManager.ecma.js"; +import {I18NManager} from "../Managers/I18NManager.ecma.js"; +import {ThreadsManager} from "../Managers/ThreadsManager.ecma.js"; +import {UniqueKeysManager} from "../Managers/UniqueKeysManager.ecma.js"; +import {SessionsManager} from "../Managers/SessionsManager.ecma.js"; +import {ModelsManager} from "../Managers/ModelsManager.ecma.js"; +import {ViewsManager} from "../Managers/ViewsManager.ecma.js"; +import {RoutesManager} from "../Managers/RoutesManager.ecma.js"; +import {Components} from "./Components.ecma.js"; +import {Common} from "../Utils/Common.ecma.js"; +import {Check} from "../Utils/Checks.ecma.js"; + +/** + * @class AnP + * @constructor + * @param {?(Object.|Array)} [inputs = null] + * @param {?simple_callback} [callback = null] + * @returns {void} + * @access private + * @static + */ +export const AnP = (function(){ + + /** + * @callback simple_callback + * @returns {void} + */ + + /** + * @callback continue_callback + * @param {!boolean} ok + * @return {boolean} + */ + + /** + * @constructs AnP + * @param {?(Object.|Array)} [inputs = null] + * @param {?simple_callback} [callback = null] + * @returns {void} + * @access private + * @static + */ + const AnP = function(inputs = null, callback = null){ + + /** @type {AnP} */ + const self = this; + /** @type {boolean} */ + let started = false; + + /** @type {FilesDriver} */ + this.files = new FilesDriver(self); + /** @type {PrintTypesManager} */ + this.print_types = new PrintTypesManager(self); + /** @type {SettingsManager} */ + this.settings = new SettingsManager(self, inputs); + /** @type {I18NManager} */ + this.i18n = new I18NManager(self); + /** @type {ThreadsManager} */ + this.threads = new ThreadsManager(self); + /** @type {UniqueKeysManager} */ + this.unique_keys = new UniqueKeysManager(self); + /** @type {SessionsManager} */ + this.sessions = new SessionsManager(self); + /** @type {ModelsManager} */ + this.models = new ModelsManager(self); + /** @type {Components} */ + this.components = new Components(self); + /** @type {ViewsManager} */ + this.views = new ViewsManager(self); + /** @type {RoutesManager} */ + this.routes = new RoutesManager(self); + + /** + * @returns {void} + * @access private + */ + const constructor = () => { + + self.settings.get("autostart", null, true) && self.start(callback); + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.update = (callback = null) => { + Common.execute_array([ + "files", "settings", "print_types", "i18n", "threads", "models", "views", "routes" + ], (key, next) => { + self[key].update(next); + }, callback, true); + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.reset = (callback = null) => { + Common.execute_array([ + "files", "settings", "print_types", "i18n", "threads", "models", "views", "routes" + ], (key, next) => { + self[key].reset(next); + }, callback, true); + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.start = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(started){ + end(false); + return false; + }; + started = true; + + self.update(ok => { + if(ok !== false && self.settings.get("build_base_gui")){ + Common.preload(self.settings.get("position"), (position, asynchronous, ok) => { + if(position){ + Common.HTML(position, self.components.base.build()); + end(true); + }else + end(false); + }); + }else + end(ok); + }); + + return true; + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.close = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(!started){ + end(false); + return false; + }; + started = false; + + end(true); + + return true; + }; + + /** + * @param {!string} type + * @param {!(string|Array.)} message + * @param {?(Object.|Array)} [inputs = null] + * @param {!number} [i = 0] + * @return {void} + * @access public + */ + this.print = (type, message, inputs = null, i = 0) => {}; + + /** + * @param {!Error} exception + * @param {!(string|Array.)} message + * @param {?(Object.|Array)} [inputs = null] + * @param {!number} [i = 0] + * @return {void} + * @access public + */ + this.exception = (exception, message, inputs = null, i = 0) => {}; + + constructor(); + + }; + + return AnP; +})(); \ No newline at end of file diff --git a/Public/ecma/Application/Components.ecma.js b/Public/ecma/Application/Components.ecma.js new file mode 100644 index 0000000..e9180c9 --- /dev/null +++ b/Public/ecma/Application/Components.ecma.js @@ -0,0 +1,357 @@ +"use strict"; + +import {BaseComponent} from "../Components/BaseComponent.ecma.js"; +import {FormsComponent} from "../Components/FormsComponent.ecma.js"; +import {DatesComponent} from "../Components/DatesComponent.ecma.js"; +import {SelectsComponent} from "../Components/SelectsComponent.ecma.js"; +import {TablesComponent} from "../Components/TablesComponent.ecma.js"; +import {SessionMiniComponent} from "../Components/SessionMiniComponent.ecma.js"; +import {LicensesComponent} from "../Components/LicensesComponent.ecma.js"; +import {I18NComponent} from "../Components/I18NComponent.ecma.js"; +import { AIChatComponent } from "../Components/AIChatComponent.ecma.js"; +import {Common} from "../Utils/Common.ecma.js"; +import {Check} from "../Utils/Checks.ecma.js"; +import { + Span, Img, Button, Label, Input, Textarea, Div +} from "../Utils/HTMLDSL.ecma.js"; + +/** + * @typedef {import("../Application/AnP.ecma.js").AnP} AnP + */ + +/** + * @class Components + * @constructor + * @param {!AnP} anp + * @return {void} + * @access public + * @static + */ +export const Components = (function(){ + + /** + * @callback event_callback + * @param {!HTMLElement} element + * @param {!Event} event + * @return {any|null|void} + */ + + /** + * @constructs Components + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ + const Components = function(anp){ + + /** @type {Components} */ + const self = this; + + /** @type {BaseComponent} */ + this.base = new BaseComponent(anp); + /** @type {FormsComponent} */ + this.forms = new FormsComponent(anp); + /** @type {DatesComponent} */ + this.dates = new DatesComponent(anp); + /** @type {SelectsComponent} */ + this.selects = new SelectsComponent(anp); + /** @type {TablesComponent} */ + this.tables = new TablesComponent(anp); + /** @type {SessionMiniComponent} */ + this.session_mini = new SessionMiniComponent(anp); + /** @type {LicensesComponent} */ + this.licenses = new LicensesComponent(anp); + /** @type {I18NComponent} */ + this.i18n_selector = new I18NComponent(anp); + /** @type {AIChatComponent} */ + this.aichat = new AIChatComponent(anp); + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + /** + * @param {!(string|Array.)} keys + * @param {!(Object.|Array.)} inputs + * @returns {Object.} + * @access public + */ + this.set_attributes = (keys, inputs) => Common.get_array(keys).reduce((attributes, key) => { + + /** @type {any|null} */ + const value = Common.get_value(key, inputs, null); + + value !== null && (attributes[Common.get_array(key)[0]] = value); + + return attributes; + }, {}); + + /** + * + * @param {?(Object.|Array.)} [inputs = null] + * @returns {Array.} + */ + this.image = (inputs = null) => { + + /** @type {string|null} */ + const i18n = Common.get_value("i18n", inputs, null), + /** @type {string|null} */ + alternative = Common.get_value(["alt", "alternative"], inputs, null), + /** @type {string|null} */ + text = i18n ? anp.i18n.get([alternative, i18n], inputs) : alternative; + /** @type {Array.|string} */ + let sources = Common.get_value(["src", "source", "sources"], inputs, null); + + return Span({ + class : "image", + data_i : 0, + data_data : Common.base64_encode(Check.is_array(sources) ? sources : sources = [sources]) + }, [ + Img({ + src : sources[0], + on_load : (item, event) => { + item.parentNode.querySelector("span").style.backgroundImage = `url(${item.getAttribute("src")})`; + }, + on_error : (item, event) => { + + const i = Number(item.parentNode.getAttribute("data_i")) + 1; + + item.setAttribute("src", Common.json_decode(Common.base64_decode(item.parentNode.getAttribute("data-data")))[i]); + item.parentNode.setAttribute("data_i", i); + + }, + ...(i18n ? {data_i18n : i18n, data_i18n_without : true, alt : text} : text ? {alt : text} : {}) + }), + Span() + ]); + }; + + this.i18n = (i18n, tag = "span", variables = null) => [tag, { + data_i18n : i18n, + ...(variables ? {data_i18n_variables : Common.data_encode(variables)} : {}) + }, anp.i18n.get(i18n, variables)]; + + this.icon = (icon, tag = "span") => [tag, {data_icon : icon}]; + + this.button = (name, action, inputs = null) => { + + const text = anp.i18n.get(name, ( + Check.is_bool(inputs) ? {toogled : inputs} : + Check.is_string(inputs) ? {type : inputs} : + inputs)), + has_action = Check.is_function(action), + type = Check.is_string(action) ? action : Common.get_value("type", inputs, "button"), + toggled = Common.get_value("toggled", inputs, null); + + has_action || (action = null); + + return Button({ + type : type, + data_i18n : name, + data_i18n_without : true, + title : text, + ...( + toggled !== null ? { + data_toggled : toggled, + on_click : (button, event) => { + button.setAttribute("data_toggled", button.getAttribute("data_toggled") != "true"); + Common.execute(action, (button, event)); + } + } : + has_action ? {on_click : action} : + {}), + }, [ + self.icon(name), + self.i18n(name) + ]); + }; + + this.checkbox = (name, inputs = null) => Label({ + class : "checkbox", + data_i18n : name, + data_i18n_without : true, + title : anp.i18n.get(name), + }, [ + Input({ + type : "checkbox", + name : name, + checked : Common.get_value("checked", inputs, false), + ...self.set_attributes([ + ["on_change", "onchange"], + ["id", "identifier"] + ], inputs) + }), + self.icon("checkbox"), + self.i18n(name) + ]); + + this.radio = (name, inputs = null) => { + + const set = Common.get_value("set", inputs); + + return Label({ + class : "radio radio-button", + data_i18n : name, + data_i18n_without : true, + title : anp.i18n.get(name), + }, [ + Input({ + type : "radio", + name : set ? set + "[]" : name, + value : name, + checked : Common.get_value("checked", inputs, false), + ...self.set_attributes([ + ["on_change", "onchange"], + ["id", "identifier"] + ], inputs) + }), + self.icon("radio"), + self.i18n(name) + ]); + }; + + this.text = (name, inputs = null) => { + + const text = anp.i18n.get(name), + minimum_length = Common.get_value("minimum_length", inputs, null), + maximum_length = Common.get_value("maximum_length", inputs, null); + + return Span({ + class : "input input-text", + data_i18n : name, + data_i18n_without : true, + title : text + }, [ + Common.get_value("multiline", inputs, false) ? Textarea({ + name : name, + data_i18n : name, + data_i18n_without : true, + placeholder : text + "...", + ...self.set_attributes([ + ["id", "identifier"], + ["maxlength", "maximum_length"], + "pattern", + "value" + ], inputs) + }) : Input({ + type : "text", + name : name, + data_i18n : name, + data_i18n_without : true, + placeholder : text + "...", + ...self.set_attributes([ + ["id", "identifier"], + ["maxlength", "maximum_length"], + "pattern", + "value" + ], inputs) + }), + Span({class : "minimum", data_minimum : minimum_length}, "" + minimum_length), + Span({class : "length"}, "" + Common.get_value("value", inputs, "").length), + Span({class : "maximum", data_maximum : maximum_length}, "" + maximum_length) + ]); + }; + + this.password = (name, inputs = null) => { + + const text = anp.i18n.get(name), + minimum_length = Common.get_value("minimum_length", inputs, 0), + maximum_length = Common.get_value("maximum_length", inputs, 0); + + return Span({ + data_i18n : name, + data_i18n_without : true, + title : text + }, [ + Input({ + type : "password", + name : name, + data_i18n : name, + data_i18n_without : true, + placeholder : text + "...", + ...self.set_attributes([ + ["id", "identifier"], + ["maxlength", "maximum_length"], + "pattern", + "value" + ], inputs) + }), + Span({class : "minimum", data_minimum : minimum_length}, "" + minimum_length), + Span({class : "length"}, "" + Common.get_value("value", inputs, "").length), + Span({class : "maximum", data_maximum : maximum_length}, "" + maximum_length) + ]); + }; + + this.email = (name, inputs = null) => { + + const text = anp.i18n.get(name); + + return Span({ + data_i18n : name, + data_i18n_without : true, + title : text + }, [ + Input({ + type : "email", + name : name, + data_i18n : name, + data_i18n_without : true, + placeholder : text + "...", + pattern : "[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}$" + }) + ]); + }; + + this.number = (name, inputs = null) => { + + const text = anp.i18n.get(name), + minimum = Common.get_value("minimum", inputs, 0), + maximum = Common.get_value("maximum", inputs, 0), + value = Common.get_value("value", inputs, 0); + + return Span({ + data_i18n : name, + data_i18n_without : true, + title : text + }, [ + Input({ + type : "number", + name : name, + data_i18n : name, + data_i18n_without : true, + placeholder : text + "...", + ...self.set_attributes([ + ["id", "identifier"], + ["min", "minimum"], + ["max", "maximum"], + "step", + "value" + ], inputs) + }), + Span({class : "minimum", data_minimum : minimum}, "" + minimum), + Span({class : "value"}, "" + value), + Span({class : "maximum", data_maximum : maximum}, "" + maximum) + ]); + }; + + /** + * @param {!Array.|Array.]>>} buttons + * @param {?(Object.|Array.)} [inputs = null] + * @returns {Array.} + */ + this.buttons = (buttons, inputs = null) => Div({ + class : ["buttons"].concat(Common.get_array(Common.get_value("class", inputs, []))).join(" ").trim(), + ...Common.get_dictionary(inputs, false, ["class"]) + }, buttons.map(([name, action, inputs]) => ( + self.button(name, action, inputs) + ))); + + constructor(); + + }; + + return Components; +})(); \ No newline at end of file diff --git a/Public/ecma/Application/Event.ecma.js b/Public/ecma/Application/Event.ecma.js new file mode 100644 index 0000000..db849d5 --- /dev/null +++ b/Public/ecma/Application/Event.ecma.js @@ -0,0 +1,97 @@ +"use strict"; + +import {Common} from "../Utils/Common.ecma.js"; +import {Check} from "../Utils/Checks.ecma.js"; + +/** + * @class Event + * @constructor + * @param {boolean} [once = false] + * @param {boolean} [autoexecute = false] + * @returns {void} + * @access public + * @static + */ +export const Event = (function(){ + + /** + * @callback event_callback + * @param {...(any|null)} parameters + * @return {void} + */ + + /** + * @constructs Event + * @param {boolean} [once = false] + * @param {boolean} [autoexecute = false] + * @returns {void} + * @access public + * @static + */ + const Event = function(once = false, autoexecute = false){ + + /** @type {Event} */ + const self = this, + /** @type {Object.} */ + events = {}, + /** @type {number} */ + id_i = 0; + /** @type {boolean} */ + this.once = once; + /** @type {boolean} */ + this.autoexecute = autoexecute; + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + /** + * @param {...(any|null)} parameters + * @returns {Array.} + * @access public + */ + this.execute = (...parameters) => [...Object.entries(events)].map(([id, callback]) => { + + /** @type {any|null} */ + const response = Common.execute(callback, ...parameters); + + if(self.once) + delete events[id]; + + return response; + }); + + /** + * @param {!event_callback} callback + * @returns {number|null} + * @access public + */ + this.add = callback => { + if(Check.is_function(callback)){ + + events[++ id_i] = callback; + + return id_i; + }; + return null; + }; + + /** + * @param {!number} id + * @returns {boolean} + * @access public + */ + this.remove = id => { + if(events[id]){ + delete events[id]; + return true; + }; + return false; + }; + + }; + + return Event; +})(); \ No newline at end of file diff --git a/Public/ecma/Components/AIChatComponent.ecma.js b/Public/ecma/Components/AIChatComponent.ecma.js new file mode 100644 index 0000000..c4cb7b0 --- /dev/null +++ b/Public/ecma/Components/AIChatComponent.ecma.js @@ -0,0 +1,88 @@ +"use strict"; + +import {Fieldset, Section, Form, Div} from "../Utils/HTMLDSL.ecma.js"; +import {Common} from "../Utils/Common.ecma.js"; + +/** + * @typedef {import("../Application/AnP.ecma.js").AnP} AnP + */ + +/** + * @class AIChatComponent + * @constructor + * @param {!AnP} anp + * @returns {void} + * @access private + * @static + */ +export const AIChatComponent = (function(){ + + /** + * @constructs AIChatComponent + * @param {!AnP} anp + * @returns {void} + * @access private + * @static + */ + const AIChatComponent = function(anp){ + + /** @type {AIChatComponent} */ + const self = this; + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + this.build = (inputs = null) => { + + const name = Common.get_value("name", inputs, "aichat"); + + return Fieldset({class : "aichat"}, [ + anp.components.i18n(name, "legend"), + Section({class : "messages"}), + Form({ + method : "post", + action : "#", + on_submit : send, + on_key_down : check_keys + }, [ + anp.components.text("message", { + multiline : true + }), + anp.components.button("send", "submit") + ]) + ]); + }; + + const send = (item, event) => { + + const text_box = item.querySelector("[name=message]"), + text = text_box.value.trim(); + + event.preventDefault(); + + if(text){ + Common.HTML(".aichat .messages", Fieldset({ + class : "message", + data_type : "user" + }, [ + anp.components.i18n("user", "legend"), + Div({class : "content"}, text) + ])); + text_box.value = ""; + }; + + return false; + }; + + const check_keys = (item, event) => { + event.key == "Enter" && !event.shiftKey && send(item, event); + }; + + constructor(); + }; + + return AIChatComponent; +})(); \ No newline at end of file diff --git a/Public/ecma/Components/BaseComponent.ecma.js b/Public/ecma/Components/BaseComponent.ecma.js new file mode 100644 index 0000000..f0cb5b2 --- /dev/null +++ b/Public/ecma/Components/BaseComponent.ecma.js @@ -0,0 +1,279 @@ +"use strict"; + +import {RE} from "../Utils/Patterns.ecma.js"; +import {Common} from "../Utils/Common.ecma.js"; +import {Check} from "../Utils/Checks.ecma.js"; +import { + Div, Span, A, Img, Header, Footer, Main, H1, Nav, UL, LI +} from "../Utils/HTMLDSL.ecma.js"; + +/** + * @typedef {import("../Application/AnP.ecma.js").AnP} AnP + */ + +/** + * @class BaseComponent + * @constructor + * @param {!AnP} anp + * @return {void} + * @access public + * @static + */ +export const BaseComponent = (function(){ + + /** + * @constructs BaseComponent + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ + const BaseComponent = function(anp){ + + /** @type {BaseComponent} */ + const self = this, + /** @type {Object.>} */ + caches = {}; + /** @type {integer|null} */ + let thread = null, + /** @type {Array.} */ + zooms = [.25, .5, .75, 1.0, 1.5, 2.0]; + + /** + * @returns {void} + * @access private + */ + const constructor = () => { + + thread = anp.threads.add(thread_method, { + autostart : true, + bucle : true + }); + + }; + + /** + * @returns {void} + * @access private + */ + const thread_method = () => { + Object.entries(caches).forEach(([i, cache]) => { + + /** @type {HTMLDivElement} */ + const base = document.querySelector(".anp[data-i='" + i + "']"), + date = Date.now(); + + if(!base){ + delete caches[i]; + return; + }; + + /** @type {number} */ + const cells = Number(base.getAttribute("data-cells")), + /** @type {number} */ + zoom = Number(base.getAttribute("data-zoom")); + + if( + cache.x != base.offsetWidth || + cache.y != base.offsetHeight || + cache.cells != cells || + cache.zoom != zoom || + false){ + cache.x = base.offsetWidth; + cache.y = base.offsetHeight; + cache.cells = cells; + cache.zoom = zoom; + base.style.fontSize = ((cache.x < cache.y ? cache.x : cache.y) / (cells / zoom)) + "px"; + }; + + if(date - cache.last_time > 2000){ + + /** @type {string} */ + const gui_mode = Check.is_dark_mode() ? "dark" : "light", + /** @type {boolean} */ + is_mobile = Check.is_mobile(); + + cache.last_time = date; + + if(cache.gui_mode != gui_mode || cache.mobile != is_mobile){ + cache.gui_mode = gui_mode; + cache.mobile = is_mobile; + base.setAttribute("data-gui-mode", gui_mode); + base.setAttribute("data-is-mobile", is_mobile); + }; + + }; + + }); + }; + + /** + * @param {?(Object.|Array.)} [inputs = null] + * @return {Array.} + * @access public + */ + this.build = (inputs = null) => { + + /** @type {string} */ + const name = anp.settings.get(["application_name", "name"], inputs, "AnP"), + /** @type {string} */ + link = anp.settings.get(["application_link", "link"], inputs, "https://anp.k3y.pw/"), + /** @type {string} */ + git = anp.settings.get(["application_git", "git"], inputs, "https://git.k3y.pw/KyMAN/AnP/"), + /** @type {string} */ + logo = anp.settings.get(["application_logo", "logo"], inputs, "images/logo.webp"), + /** @type {string} */ + id = anp.unique_keys.create(), + /** @type {string} */ + gui_mode = Check.is_dark_mode() ? "dark" : "light", + /** @type {boolean} */ + is_mobile = Check.is_mobile(); + /** @type {number} */ + let i; + + while(caches[i = Math.random() * (1 << 28) | 0]); + + caches[i] = { + x : 0, + y : 0, + cells : anp.settings.get(["application_cells", "cells"], inputs, 40), + zoom : anp.settings.get(["application_zoom", "zoom"], inputs, 1.0), + gui_mode : gui_mode, + mobile : is_mobile, + last_time : Date.now() + }; + + return Div({ + id : id, + class : Common.unique(["anp", id].concat(anp.settings.get([ + "application_class", "class" + ], inputs, "").split(RE.WHITE_SPACES))).join(" ").trim(), + data_hash : id, + data_i : i, + data_cells : caches[i].cells, + data_zoom : caches[i].zoom, + data_forced_gui_mode : anp.settings.get(["application_gui_mode", "gui_mode"], inputs, "default"), // default, light, dark + data_gui_mode : gui_mode, // default, light, dark + data_is_mobile : is_mobile, + data_name : name, + data_link : link, + data_git : git, + data_logo : logo + }, [ + Header(null, [ + H1({title : name}, [ + A({href : link, target : "_blank"}, [ + anp.components.image({sources : [logo], alt : name}), + Span({class : "text"}, name) + ]) + ]), + Nav({class : "top-menu"}, [ + UL(null, anp.settings.get("main_menu", inputs, [ + ["home", "#"], + ["git", git, "_blank"] + ]).map(([name, link, target]) => LI({ + data_i18n : name, + data_i18n_without : true, + title : anp.i18n.get(name, inputs) + }, [ + A({ + href : link, + target : target || "_self" + }, [ + anp.components.icon(name), + anp.components.i18n(name) + ]) + ]))) + ]), + anp.components.session_mini.build() + ]), + Main(null, [ + anp.components.aichat.build(inputs) + ]), + Footer(null, [ + anp.components.buttons([ + ["zoom", change_zoom], + ["reset_zoom", reset_zoom], + ["gui_mode", change_gui_mode] + ], {class : "gui-controls"}), + anp.components.licenses.build(anp.settings.get(["application_licenses", "licenses"], inputs, { + copyright : [[2019, 2027], "KyMAN"], + cc_by_nc_sa_4 : [] + })), + anp.components.i18n_selector.build() + ]), + Div({class : "preloader"}) + ]); + }; + + /** + * @param {!HTMLElement} item + * @returns {HTMLDivElement|null} + * @access public + */ + this.get_from = item => { + + if(item) + while( + !item.classList.contains("anp") && + (item = item.parentElement) + ); + + return item; + }; + + /** + * @param {!HTMLElement} item + * @param {!Event} event + * @return {void} + * @access private + */ + const change_zoom = (item, event) => { + + /** @type {HTMLDivElement} */ + const base = self.get_from(item), + /** @type {number} */ + i = zooms.indexOf(Number(base.getAttribute("data-zoom"))); + + if(isNaN(i)) + base.setAttribute("data-zoom", 1.0); + else + base.setAttribute("data-zoom", zooms[(i + 1) % zooms.length]); + + }; + + /** + * @param {!HTMLElement} item + * @param {!Event} event + * @return {void} + * @access private + */ + const reset_zoom = (item, event) => { + self.get_from(item).setAttribute("data-zoom", 1.0); + }; + + /** + * @param {!HTMLElement} item + * @param {!Event} event + * @return {void} + * @access private + */ + const change_gui_mode = (item, event) => { + + /** @type {HTMLDivElement} */ + const base = self.get_from(item); + + base.setAttribute("data-forced-gui-mode", { + default : "light", + light : "dark", + dark : "default" + }[base.getAttribute("data-forced-gui-mode")]); + + }; + + constructor(); + + }; + + return BaseComponent; +})(); \ No newline at end of file diff --git a/Public/ecma/Components/DatesComponent.ecma.js b/Public/ecma/Components/DatesComponent.ecma.js new file mode 100644 index 0000000..17d699f --- /dev/null +++ b/Public/ecma/Components/DatesComponent.ecma.js @@ -0,0 +1,49 @@ +"use strict"; + +/** + * @class DatesComponent + * @constructor + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ +export const DatesComponent = (function(){ + + /** + * @constructs DatesComponent + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ + const DatesComponent = function(anp){ + + /** @type {DatesComponent} */ + const self = this; + + /** + * @returns {void} + * @access private + */ + const constructor = () => { + + setTimeout(() => { + anp.components.dates = self; + anp.components.date = self.build; + }, 0); + + }; + + /** + * @param {!(Object.|Array.)} inputs + * @return {Array.} + * @access public + */ + this.build = inputs => {}; + + constructor(); + }; + + return DatesComponent; +})(); \ No newline at end of file diff --git a/Public/ecma/Components/FormsComponent.ecma.js b/Public/ecma/Components/FormsComponent.ecma.js new file mode 100644 index 0000000..9872e28 --- /dev/null +++ b/Public/ecma/Components/FormsComponent.ecma.js @@ -0,0 +1,152 @@ +"use strict"; + +import {Fieldset, Div, Form, UL} from "../Utils/HTMLDSL.ecma.js"; + +/** + * @class FormsComponent + * @constructor + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ +export const FormsComponent = (function(){ + + /** + * @callback form_submit_callback + * @param {!HTMLElement} form + * @param {!Event} event + * @return {any|null|void} + */ + + /** + * @constructs FormsComponent + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ + const FormsComponent = function(anp){ + + /** @type {FormsComponent} */ + const self = this; + + /** + * @returns {void} + * @access private + */ + const constructor = () => { + + setTimeout(() => { + anp.components.forms = self; + anp.components.form = self.build; + }, 0); + + }; + + /** + * @param {string} name + * @param {!(Object.|Array.)} inputs + * @return {Array.} + * @access public + */ + this.build = (name, inputs) => { + + /** @type {form_submit_callback|null} */ + const submit = Common.get_value("submit", inputs, null); + + return Form({ + data_name : name, + method : Common.get_value("method", inputs, "post"), + action : Common.get_value("action", inputs, "#"), + ...(submit ? {on_submit : submit} : {}) + }, [ + Fieldset({class : "form"}, [ + anp.components.i18n(name, "legend"), + anp.components.i18n(name + "_description", "p"), + Div({class : "form-fields"}, Common.get_value("structure", inputs, []).map(([type, name, ...inputs], i) => { + + /** @type {string} */ + let id = anp.unique_keys.create(true), + /** @type {number} */ + l = inputs.length - 1; + + if(!Check.is_dictionary(inputs[l])){ + inputs.push({}); + l ++; + }; + inputs[l].id = id; + + return Div({ + data_field : name, + data_i : i + }, [ + Label({ + for : id, + data_i18n : name, + data_i18n_without : true, + title : anp.components.i18n(name, "label") + }, [ + anp.components.i18n(name), + anp.components.i18n(name + "_description"), + ]), + Span({class : "value"}, [ + anp.components[type](name, ...inputs) + ]), + UL({class : "errors"}) + ]); + })), + UL({class : "global-errors"}), + Div({class : "buttons"}, Common.get_value(["actions", "buttons"], inputs, []).concat( + anp.components.button(Common.get_value("submit_reset", inputs, "reset"), "reset"), + submit ? anp.components.button(Common.get_value("submit_name", inputs, "submit"), "submit") : null + )) + ]) + ]); + }; + + this.get = item => { + + if(item) + while(item.tagName.toLowerCase() != "form" && (item = item.parentElement)); + + return item; + }; + + this.get_values = form => [...self.get(form).querySelectorAll("[name]")].reduce((values, field) => { + + let name = field.getAttribute("name"); + const is_array = self.is_array(field), + tag = field.tagName.toLowerCase(), + type = field.getAttribute("type").toLowerCase().trim(); + + if(is_array){ + (values[name = name.slice(0, -2)] = values[name] || []).push(self.get_value(field)); + }else + values[name] = self.get_value(field); + + return values; + }, {}); + + this.is_array = input => input.getAttribute("name").endsWith("[]"); + + this.get_value = input => { + switch(input.tagName.toLowerCase()){ + case "select": + return input.multiple ? [...input.options].filter(option => option.selected).map(option => option.value) : input.value; + }; + switch(input.getAttribute("type")){ + case "checkbox": + case "radio": + return self.is_array(input) ? input.checked ? input.value : null : input.checked; + case "number": + return parseFloat(input.value) || 0; + }; + return input.value; + }; + + constructor(); + }; + + return FormsComponent; +})(); \ No newline at end of file diff --git a/Public/ecma/Components/I18NComponent.ecma.js b/Public/ecma/Components/I18NComponent.ecma.js new file mode 100644 index 0000000..ee76bfd --- /dev/null +++ b/Public/ecma/Components/I18NComponent.ecma.js @@ -0,0 +1,83 @@ +"use strict"; + +import {Common} from "../Utils/Common.ecma.js"; +import {Nav, Span, Img, UL, LI} from "../Utils/HTMLDSL.ecma.js"; + +/** + * @typedef {import("../Application/AnP.ecma.js").AnP} AnP + */ + +/** + * @constructs I18NComponent + * @param {!AnP} anp + * @return {void} + * @access public + * @static + */ +export const I18NComponent = (function(){ + + /** + * @constructs I18NComponent + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ + const I18NComponent = function(anp){ + + /** @type {I18NComponent} */ + const self = this; + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + /** + * @returns {Array.} + * @access public + */ + this.build = () => Nav({class : "i18n-selector"}, [ + UL(null, anp.settings.get("i18n_selector").map(([name, text, flag]) => LI({ + data_language : name, + data_selected : anp.i18n.is_language_selected(name), + on_click : change, + data_role : "link", + title : text + }, [ + Img({src : flag, alt : text}), + Span(null, text) + ]))) + ]); + + /** + * @param {!HTMLElement} item + * @param {!Event} event + * @return {void} + * @access private + */ + const change = (item, event) => { + if(anp.i18n.change(item.getAttribute("data-language"))){ + item.parentNode.childNodes.forEach(option => { + option.setAttribute("data-selected", option === item ? "true" : "false"); + }); + anp.components.base.get_from(item).querySelectorAll("[data-i18n]").forEach(element => { + + /** @type {string} */ + const text = anp.i18n.get(element.getAttribute("data-i18n"), Common.data_decode(element.getAttribute("data-i18n-variables"))); + + element.getAttribute("data-i18n-without") != "true" && (element.innerText = text); + element.hasAttribute("title") && (element.setAttribute("title", text)); + element.hasAttribute("placeholder") && (element.setAttribute("placeholder", text + "...")); + element.hasAttribute("alt") && (element.setAttribute("alt", text)); + + }); + }; + }; + + constructor(); + }; + + return I18NComponent; +})(); \ No newline at end of file diff --git a/Public/ecma/Components/LicensesComponent.ecma.js b/Public/ecma/Components/LicensesComponent.ecma.js new file mode 100644 index 0000000..83127f2 --- /dev/null +++ b/Public/ecma/Components/LicensesComponent.ecma.js @@ -0,0 +1,81 @@ +"use strict"; + +import {Common} from "../Utils/Common.ecma.js"; +import {Div, A} from "../Utils/HTMLDSL.ecma.js"; + +/** + * @typedef {import("../Application/AnP.ecma.js").AnP} AnP + */ + +/** + * @constructs LicensesComponent + * @param {!AnP} anp + * @return {void} + * @access public + * @static + */ +export const LicensesComponent = (function(){ + + /** + * @constructs LicensesComponent + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ + const LicensesComponent = function(anp){ + + /** @type {LicensesComponent} */ + const self = this; + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + /** + * @param {!Object.} licenses + * @returns {Array.} + * @access public + */ + this.build = licenses => Div({ + class : "licenses", + }, Object.entries(licenses).map(([name, inputs]) => ( + self[name] ? self[name](...Common.get_array(inputs)) : + null))); + + /** + * @param {!(number|[number, number])} years + * @param {!(string|Array.)} authors + * @returns {Array.} + * @access public + */ + this.copyright = (years, authors) => anp.components.i18n("copyright", "span", { + authors : Common.get_array(authors).join(", "), + years : Common.get_array(years).join("-") + }); + + /** + * @returns {Array.} + * @access public + */ + this.cc_by_nc_sa_4 = () => A({ + href : anp.settings.get("cc_by_nc_sa_4_link", null, "https://creativecommons.org/licenses/by-nc-sa/4.0/"), + target : "_blank", + data_i18n : "cc_by_nc_sa_4", + data_i18n_without : true, + title : anp.i18n.get("cc_by_nc_sa_4") + }, [ + anp.components.i18n("cc_by_nc_sa_4"), + anp.components.image({ + i18n : "cc_by_nc_sa_4", + sources : [anp.settings.get("cc_by_nc_sa_4_icon", null, "https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png")], + }) + ]) + + constructor(); + }; + + return LicensesComponent; +})(); \ No newline at end of file diff --git a/Public/ecma/Components/SelectsComponent.ecma.js b/Public/ecma/Components/SelectsComponent.ecma.js new file mode 100644 index 0000000..97b00f1 --- /dev/null +++ b/Public/ecma/Components/SelectsComponent.ecma.js @@ -0,0 +1,49 @@ +"use strict"; + +/** + * @class SelectsComponent + * @constructor + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ +export const SelectsComponent = (function(){ + + /** + * @constructs SelectsComponent + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ + const SelectsComponent = function(anp){ + + /** @type {SelectsComponent} */ + const self = this; + + /** + * @returns {void} + * @access private + */ + const constructor = () => { + + setTimeout(() => { + anp.components.dates = self; + anp.components.date = self.build; + }, 0); + + }; + + /** + * @param {!(Object.|Array.)} inputs + * @return {Array.} + * @access public + */ + this.build = inputs => {}; + + constructor(); + }; + + return SelectsComponent; +})(); \ No newline at end of file diff --git a/Public/ecma/Components/SessionMiniComponent.ecma.js b/Public/ecma/Components/SessionMiniComponent.ecma.js new file mode 100644 index 0000000..fca7234 --- /dev/null +++ b/Public/ecma/Components/SessionMiniComponent.ecma.js @@ -0,0 +1,79 @@ +"use strict"; + +import {Div, UL, LI, Span, Nav, A} from "../Utils/HTMLDSL.ecma.js"; + +/** + * @typedef {import("../Application/AnP.ecma.js").AnP} AnP + */ + +/** + * @class SessionMiniComponent + * @constructor + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ +export const SessionMiniComponent = (function(){ + + /** + * @constructs SessionMiniComponent + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ + const SessionMiniComponent = function(anp){ + + /** @type {SessionMiniComponent} */ + const self = this; + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + /** + * @returns {Array.} + * @access public + */ + this.build = () => Div({ + class : "sessions-mini", + data_status : "unlogged" + }, [ + anp.components.image({}), + UL({class : "info"}, Object.entries({ + user : "Guest", + ip : "::1" + }).map(([field, _default]) => LI({ + class : field, + data_i18n : field, + data_i18n_without : true, + title : anp.i18n.get(field), + }, [ + anp.components.icon(field), + anp.components.i18n(field), + Span({class : "value"}, _default) + ]))), + Nav({class : "actions"}, [ + UL(null, ["login", "register", "logout"].map(action => LI({class : action}, [ + A({ + href : "#/" + action, + data_i18n : action, + data_i18n_without : true, + title : anp.i18n.get(action) + }, [ + anp.components.icon(action), + anp.components.i18n(action) + ]) + ]))) + ]) + ]); + + constructor(); + + }; + + return SessionMiniComponent; +})(); \ No newline at end of file diff --git a/Public/ecma/Components/TablesComponent.ecma.js b/Public/ecma/Components/TablesComponent.ecma.js new file mode 100644 index 0000000..25b64cf --- /dev/null +++ b/Public/ecma/Components/TablesComponent.ecma.js @@ -0,0 +1,49 @@ +"use strict"; + +/** + * @class TablesComponent + * @constructor + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ +export const TablesComponent = (function(){ + + /** + * @constructs TablesComponent + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ + const TablesComponent = function(anp){ + + /** @type {TablesComponent} */ + const self = this; + + /** + * @returns {void} + * @access private + */ + const constructor = () => { + + setTimeout(() => { + anp.components.tables = self; + anp.components.table = self.build; + }, 0); + + }; + + /** + * @param {!(Object.|Array.)} inputs + * @return {Array.} + * @access public + */ + this.build = inputs => {}; + + constructor(); + }; + + return TablesComponent; +})(); \ No newline at end of file diff --git a/Public/ecma/Controllers/AIChatController.ecma.js b/Public/ecma/Controllers/AIChatController.ecma.js new file mode 100644 index 0000000..b2edc89 --- /dev/null +++ b/Public/ecma/Controllers/AIChatController.ecma.js @@ -0,0 +1,39 @@ +"use strict"; + +/** + * @typedef {import("../Application/AnP.ecma.js").AnP} AnP + */ + +/** + * @class AIChat + * @constructor + * @param {!AnP} anp + * @returns {void} + * @access private + * @static + */ +export const AIChat = (function(){ + + /** + * @constructs AIChat + * @param {!AnP} anp + * @returns {void} + * @access private + * @static + */ + const AIChat = function(anp){ + + /** @type {AIChat} */ + const self = this; + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + constructor(); + }; + + return AIChat; +})(); \ No newline at end of file diff --git a/Public/ecma/Controllers/SessionsController.ecma.js b/Public/ecma/Controllers/SessionsController.ecma.js new file mode 100644 index 0000000..acb618f --- /dev/null +++ b/Public/ecma/Controllers/SessionsController.ecma.js @@ -0,0 +1,45 @@ +"use strict"; + +/** + * @typedef {import("../Application/AnP.ecma.js").AnP} AnP + */ + +/** + * @class SessionsController + * @constructor + * @param {!AnP} anp + * @returns {void} + * @access private + * @static + */ +export const SessionsController = (function(){ + + /** + * @constructs SessionsController + * @param {!AnP} anp + * @returns {void} + * @access private + * @static + */ + const SessionsController = function(anp){ + + /** @type {SessionsController} */ + const self = this; + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + this.login = () => {}; + + this.logout = () => {}; + + this.register = () => {}; + + constructor(); + }; + + return SessionsController; +})(); \ No newline at end of file diff --git a/Public/ecma/Drivers/FilesDriver.ecma.js b/Public/ecma/Drivers/FilesDriver.ecma.js new file mode 100644 index 0000000..d83472d --- /dev/null +++ b/Public/ecma/Drivers/FilesDriver.ecma.js @@ -0,0 +1,310 @@ +"use strict"; + +import {Common} from "../Utils/Common.ecma.js"; +import {Check} from "../Utils/Checks.ecma.js"; + +/** + * @typedef {import("../Application/AnP.ecma.js").AnP} AnP + */ + +/** + * @class FilesDriver + * @constructor + * @param {!AnP} anp + * @param {?(Object.|Array)} [inputs = null] + * @returns {void} + * @access private + * @static + */ +export const FilesDriver = (function(){ + + /** + * @callback simple_callback + * @returns {void} + */ + + /** + * @callback continue_callback + * @param {!boolean} ok + * @return {boolean} + */ + + /** + * @callback ok_callback + * @param {!boolean} ok + * @return {void} + */ + + /** + * @callback load_callback + * @param {?string} content + * @param {!boolean} ok + * @return {void} + */ + + /** + * @callback load_json_callback + * @param {!Array.|Array.>} results + * @return {void} + */ + + /** + * @constructs FilesDriver + * @param {!AnP} anp + * @param {?(Object.|Array)} [inputs = null] + * @returns {void} + * @access private + * @static + */ + const FilesDriver = function(anp, inputs = null){ + + /** @type {FilesDriver} */ + const self = this; + /** @type {Array.} */ + let default_root_urls = [""], + /** @type {number} */ + default_timeout = 2000, + /** @type {boolean} */ + default_asynchronous = true, + /** @type {string} */ + default_method = "get", + /** @type {boolean} */ + started = false; + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.update = (callback = null) => { + + default_timeout = anp.settings.get(["files_driver_timeout", "timeout"], inputs, default_timeout); + default_asynchronous = anp.settings.get(["files_driver_asynchronous", "asynchronous"], inputs, default_asynchronous); + default_method = anp.settings.get(["files_driver_method", "method"], inputs, default_method); + + Common.execute(callback); + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.reset = (callback = null) => { + + default_root_urls = [""]; + default_timeout = 2000; + default_asynchronous = true; + + self.update(callback); + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.start = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(started){ + end(false); + return false; + }; + started = true; + + self.update(() => end(true)); + + return true; + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.close = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(!started){ + end(false); + return false; + }; + started = false; + + end(true); + + return true; + }; + + /** + * @param {!string} method + * @param {!string} url + * @param {!boolean} asynchronous + * @param {!number} timeout + * @param {?load_callback} [callback = null] + * @param {!Array.} root_urls + * @param {!number} [i = 0] + * @param {!Array.} [root_urls_done = []] + * @return {void} + * @access public + */ + const load_url_route = (method, url, asynchronous, timeout, callback, root_urls, i = 0, root_urls_done = []) => { + + if(i == root_urls.length){ + Common.execute(callback, null, false); + return; + }; + + /** @type {simple_callback} */ + const next = () => { + load_url_route(method, url, asynchronous, timeout, callback, root_urls, i + 1, root_urls_done.concat(root_urls[i])); + }; + + if(root_urls_done.includes(root_urls[i])){ + next(); + return; + }; + + /** @type {boolean} */ + let ended = false; + /** @type {XMLHttpRequest} */ + const ajax = new XMLHttpRequest(), + /** @type {ok_callback} */ + end = (ok = false) => { + if(ended) + return; + ended = true; + if(ok) + Common.execute(callback, ajax.responseText, true); + else + next(); + }, + /** @type {number} */ + date = Date.now(); + + ajax.open(method, root_urls[i] + url, asynchronous); + ajax.timeout = timeout; + ajax.onreadystatechange = () => { + if(ended) + return; + if(ajax.readyState == 4) + end((ajax.status >= 200 && ajax.status < 300) || [301, 302, 304].includes(ajax.status)); + else if(Date.now() - date >= timeout) + end(false); + }; + ajax.send(null); + + ajax.onload = end; + ajax.onerror = end; + ajax.ontimeout = end; + + }; + + /** + * @param {!string} url + * @param {?load_callback} [callback = null] + * @param {?(Object.|Array.)} [inputs = null] + * @return {void} + * @access public + */ + this.load = (url, callback, inputs = null) => { + load_url_route( + Common.get_value(["files_driver_method", "method"], inputs, "get").toLowerCase(), + url, + Common.get_value(["files_driver_asynchronous", "asynchronous"], inputs, default_asynchronous), + Common.get_value(["files_driver_timeout", "timeout"], inputs, default_timeout), + callback, + Common.get_value(["files_driver_root_urls", "root_urls"], inputs, []).concat(default_root_urls) + ); + }; + + /** + * @param {?any} data + * @param {!load_json_callback} callback + * @param {?(Object.|Array.)} [inputs = null] + * @return {void} + * @access public + */ + this.load_json = (data, callback, inputs = null) => { + + if(Check.is_bool(inputs)) + inputs = {only_dictionaries : inputs}; + + /** @type {boolean} */ + const only_dictionaries = Common.get_value([ + "files_driver_load_json_only_dictionaries", + "load_json_only_dictionaries", + "only_dictionaries" + ], Check.is_bool(inputs) ? inputs = { + only_dictionaries : inputs + } : inputs, false), + /** @type {Array.|Array.>} */ + results = [], + /** @type {simple_callback} */ + end = () => { + Common.execute(callback, results); + }; + + if(Check.is_dictionary(data)){ + results.push(data); + end(); + }else if(Check.is_array(data)){ + if(only_dictionaries){ + + /** @type {number} */ + const l = data.length; + /** @type {number} */ + let loaded = 0; + + for(let item of data) + self.load_json(item, subresults => { + results.push(...subresults); + ++ loaded == l && end(); + }, inputs); + + }else{ + results.push(data); + end(); + }; + }else if(Check.is_string(data)){ + + /** @type {Object.|Array.|null} */ + let json; + + if(Check.is_json(data, false) && (json = JSON.parse(data)) !== null) + self.load_json(json, subresults => { + results.push(...subresults); + end(); + }, inputs); + else + self.load(data, (content, ok) => { + self.load_json(content, subresults => { + results.push(...subresults); + end(); + }, inputs); + }, inputs); + + }else + end(); + + }; + + constructor(); + + }; + + return FilesDriver; +})(); \ No newline at end of file diff --git a/Public/ecma/Drivers/WebSocketsDriver.ecma.js b/Public/ecma/Drivers/WebSocketsDriver.ecma.js new file mode 100644 index 0000000..1c1478f --- /dev/null +++ b/Public/ecma/Drivers/WebSocketsDriver.ecma.js @@ -0,0 +1,18 @@ +"use strict"; + +export const WebSocketsDriver = (function(){ + + const WebSocketsDriver = function(anp){ + + const self = this, + clients = {}; + let client_i = 0; + + const constructor = () => {}; + + constructor(); + + }; + + return WebSocketsDriver; +})(); \ No newline at end of file diff --git a/Public/ecma/Managers/ControllersManager.ecma.js b/Public/ecma/Managers/ControllersManager.ecma.js new file mode 100644 index 0000000..75c9894 --- /dev/null +++ b/Public/ecma/Managers/ControllersManager.ecma.js @@ -0,0 +1,157 @@ +"use strict"; + +import {Check} from "../Utils/Checks.ecma.js"; +import {Common} from "../Utils/Common.ecma.js"; + +/** + * @typedef {import("../Application/AnP.ecma.js").AnP} AnP + */ + +/** + * @class ControllersManager + * @constructor + * @param {!AnP} anp + * @returns {void} + * @access private + * @static + */ +export const ControllersManager = (function(){ + + /** + * @callback continue_callback + * @param {!boolean} ok + * @return {boolean} + */ + + /** + * @callback action_callback + * @param {...(any|null)} parameters + * @return {void} + */ + + /** + * @constructs ControllersManager + * @param {!AnP} anp + * @returns {void} + * @access private + * @static + */ + const ControllersManager = function(anp){ + + /** @type {ControllersManager} */ + const self = this, + /** @type {Object.>} */ + controllers = {}; + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.update = (callback = null) => { + + Common.execute(callback); + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.reset = (callback = null) => { + + Common.clear_dictionary(controllers); + + self.update(callback); + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.start = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(started){ + end(false); + return false; + }; + started = true; + + self.update(end); + + return true; + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.close = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(!started){ + end(false); + return false; + }; + started = false; + + end(true); + + return true; + }; + + /** + * + * @param {?any} inputs + * @param {!boolean} [overwrite = false] + * @param {?default_callback} [callback = null] + */ + this.add = (inputs, overwrite = false, callback = null) => { + anp.files.load_json(inputs, data => { + Object.entries(data).forEach(([key, Controller]) => { + if(!Controller || (!overwrite && controllers[key])) + return; + if(Check.is_function(Controller)) + controllers[key] = new Controller(anp); + else if(Check.is_object(Controller)) + controllers[key] = Controller; + else if(Check.is_string(Controller)){ + + /** @type {Object.|Function|null} */ + const Model = anp.models.get(Controller); + + if(Check.is_object(Model)) + controllers[key] = Model; + else if(Check.is_function(Model)) + controllers[key] = new Model(anp); + + }; + }); + Common.execute(callback); + }, true); + }; + + this.execute = (name, action, ...parameters) => {}; + + constructor(); + + }; + + return ControllersManager; + +})(); \ No newline at end of file diff --git a/Public/ecma/Managers/I18NManager.ecma.js b/Public/ecma/Managers/I18NManager.ecma.js new file mode 100644 index 0000000..548016b --- /dev/null +++ b/Public/ecma/Managers/I18NManager.ecma.js @@ -0,0 +1,224 @@ +"use strict"; + +import {Common} from "../Utils/Common.ecma.js"; +import {Check} from "../Utils/Checks.ecma.js"; + +/** + * @typedef {import("../Application/AnP.ecma.js").AnP} AnP + */ + +/** + * @class I18NManager + * @constructor + * @param {!AnP} anp + * @returns {void} + * @access private + * @static + */ +export const I18NManager = (function(){ + + /** + * @callback simple_callback + * @returns {void} + */ + + /** + * @callback continue_callback + * @param {!boolean} ok + * @return {boolean} + */ + + /** + * @constructs I18NManager + * @param {!AnP} anp + * @returns {void} + * @access private + * @static + */ + const I18NManager = function(anp){ + + /** @type {!AnP} */ + const self = this, + /** @type {Object.>>} */ + sentences = {}; + /** @type {boolean} */ + let started = false, + /** @type {string} */ + language = "english", + /** @type {string} */ + default_language = "english"; + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.update = (callback = null) => { + Common.execute_array(["default_i18n_files", "i18n_files", "default_i18n", "i18n"], (key, next) => { + self.add(anp.settings.get(key), true, next); + }, callback, true); + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.reset = (callback = null) => { + + Common.clear_dictionary(sentences); + + self.update(callback); + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.start = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(started){ + end(false); + return false; + }; + started = true; + + self.update(() => end(true)); + + return true; + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.close = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(!started){ + end(false); + return false; + }; + started = false; + + end(true); + + return true; + }; + + /** + * @param {!(string|Array.)} texts + * @param {?(string|Array.)} languages + * @returns {string|Array.|null} + * @access private + */ + const get_sentence = (texts, languages) => { + + /** @type {Array.} */ + const keys = Common.get_keys(texts); + + if(keys.length){ + + /** @type {Array.} */ + const languages_done = []; + + for(let language_key of Common.get_keys(languages).concat( + [language, default_language], + Object.keys(sentences) + )){ + if(languages_done.includes(language_key)) + continue; + languages_done.push(language_key); + if(!sentences[language_key]) + continue; + for(let key of keys) + if(sentences[language_key][key] !== undefined) + return sentences[language_key][key]; + }; + + }; + return Common.get_texts(texts) + + }; + + /** + * @param {!(string|Array.)} texts + * @param {?(Object.|Array)} [subinputs = null] + * @param {?(string|Array.)} [languages = null] + * @returns {any|null} + * @access public + */ + this.get = (texts, inputs = null, languages = null) => { + + /** @type {string|Array.|null} */ + const sentence = get_sentence(texts, languages); + + return Common.string_variables(( + Check.is_array(sentence) ? sentence.join("") : + sentence), inputs); + }; + + /** + * @param {?any} inputs + * @param {!boolean} [overwrite = false] + * @param {?simple_callback} [callback = null] + * @return {void} + * @access public + */ + this.add = (inputs, overwrite = false, callback = null) => { + anp.files.load_json(inputs, data => { + for(let subinputs of data) + Object.entries(subinputs).forEach(([new_language, new_sentences]) => { + sentences[new_language] || (sentences[new_language] = {}); + Check.is_dictionary(new_sentences) && + Object.entries(new_sentences).filter(([key, _]) => !Check.is_mark_key(key)).forEach(([key, sentence]) => { + sentences[new_language][key] = sentence; + }); + }); + Common.execute(callback); + }, true); + }; + + /** + * @param {!string} new_language + * @return {boolean} + * @access public + */ + this.change = new_language => { + if(sentences[new_language] && new_language != language){ + language = new_language; + return true; + }; + return false; + }; + + /** + * @param {!string} check_language + * @returns {boolean} + * @access public + */ + this.is_language_selected = check_language => language == check_language; + + constructor(); + + }; + + /** @type {Object.} */ + I18NManager.DEFAULT_SETTINGS = {}; + + return I18NManager; +})(); \ No newline at end of file diff --git a/Public/ecma/Managers/ModelsManager.ecma.js b/Public/ecma/Managers/ModelsManager.ecma.js new file mode 100644 index 0000000..dec9a7a --- /dev/null +++ b/Public/ecma/Managers/ModelsManager.ecma.js @@ -0,0 +1,148 @@ +"use strict"; + +import {Check} from "../Utils/Checks.ecma.js"; +import {Common} from "../Utils/Common.ecma.js"; + +/** + * @typedef {import("../Application/AnP.ecma.js").AnP} AnP + */ + +/** + * @class ModelsManager + * @constructor + * @param {!AnP} anp + * @returns {void} + * @access private + * @static + */ +export const ModelsManager = (function(){ + + /** + * @callback default_callback + * @return {void} + */ + + /** + * @callback continue_callback + * @param {!boolean} ok + * @return {boolean} + */ + + /** + * @constructs ModelsManager + * @param {!AnP} anp + * @returns {void} + * @access private + * @static + */ + const ModelsManager = function(anp){ + + /** @type {ModelsManager} */ + const self = this, + /** @type {Object.|Function>} */ + models = {}; + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.update = (callback = null) => { + + Common.execute(callback); + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.reset = (callback = null) => { + + Common.clear_dictionary(models); + + self.update(callback); + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.start = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(started){ + end(false); + return false; + }; + started = true; + + self.update(end); + + return true; + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.close = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(!started){ + end(false); + return false; + }; + started = false; + + end(true); + + return true; + }; + + /** + * @param {?any} inputs + * @param {!boolean} [overwrite = false] + * @param {?default_callback} [callback = null] + * @return {void} + * @access public + */ + this.add = (inputs, overwrite = false, callback = null) => { + anp.files.load_json(inputs, data => { + Object.entries(data).forEach(([key, Model]) => { + Model && + (overwrite || !models[key]) && + (Check.is_function(Model) || Check.is_object(Model)) && + (models[key] = Model); + }); + Common.execute(callback); + }, true); + }; + + /** + * @param {!string} name + * @returns {Object.|Function|null} + */ + this.get = name => models[name] || null; + + constructor(); + + }; + + return ModelsManager; + +})(); \ No newline at end of file diff --git a/Public/ecma/Managers/PrintTypesManager.ecma.js b/Public/ecma/Managers/PrintTypesManager.ecma.js new file mode 100644 index 0000000..16137f4 --- /dev/null +++ b/Public/ecma/Managers/PrintTypesManager.ecma.js @@ -0,0 +1,185 @@ +"use strict"; + +import {Common} from "../Utils/Common.ecma.js"; +import {Check} from "../Utils/Checks.ecma.js"; + +/** + * @typedef {import("../Application/AnP.ecma.js").AnP} AnP + */ + +/** + * @class PrintTypesManager + * @constructor + * @param {!AnP} anp + * @returns {void} + * @access private + * @static + */ +export const PrintTypesManager = (function(){ + + /** + * @callback simple_callback + * @returns {void} + */ + + /** + * @callback continue_callback + * @param {!boolean} ok + * @return {boolean} + */ + + /** + * @constructs PrintTypesManager + * @param {!AnP} anp + * @returns {void} + * @access private + * @static + */ + const PrintTypesManager = function(anp){ + + /** @type {!AnP} */ + const self = this, + /** @type {Array.>} */ + types = [ + ["unkn", "unknown"] + ]; + /** @type {boolean} */ + let started = false; + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.update = (callback = null) => { + Common.execute_array(["default_print_types_files", "print_types_files", "default_print_types", "print_types"], (key, next) => { + self.add(anp.settings.get(key), true, next); + }, callback, true); + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.reset = (callback = null) => { + + types.splice(0, types.length); + + self.update(callback); + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.start = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(started){ + end(false); + return false; + }; + started = true; + + self.update(() => end(true)); + + return true; + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.close = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(!started){ + end(false); + return false; + }; + started = false; + + end(true); + + return true; + }; + + /** + * @param {!(string|Array.)} texts + * @param {?(Object.|Array)} [subinputs = null] + * @param {?(string|Array.)} [languages = null] + * @returns {any|null} + * @access public + */ + this.get = type => { + + type = type.toLowerCase(); + + for(let group of types) + if(group.includes(type)) + return group[0]; + return types[0][0]; + }; + + /** + * @param {?any} inputs + * @param {!boolean} [overwrite = false] + * @param {?simple_callback} [callback = null] + * @return {void} + * @access public + */ + this.add = (inputs, overwrite = false, callback = null) => { + anp.files.load_json(inputs, data => { + if(Check.is_array(data)){ + if(data.length && data.every(Check.is_key)){ + + /** @type {number} */ + let i = -1; + /** @type {number} */ + const l = types.length; + + data = data.map(type => type.toLowerCase()) + + for(; i < l; i ++) + if(data[0] == types[i][0]){ + types.push(...data.filter(type => !types.includes(type))); + break; + }; + + i == l && types.push(data); + + Common.execute(callback); + + }else{ + Common.execute_array(data.filter(subitem => !Check.is_dictionary(subitem)), (block, next) => { + self.add(block, overwrite, next); + }, callback); + }; + }else + Common.execute(callback); + }, false); + }; + + constructor(); + + }; + + /** @type {Object.} */ + PrintTypesManager.DEFAULT_SETTINGS = {}; + + return PrintTypesManager; +})(); \ No newline at end of file diff --git a/Public/ecma/Managers/RoutesManager.ecma.js b/Public/ecma/Managers/RoutesManager.ecma.js new file mode 100644 index 0000000..07456d3 --- /dev/null +++ b/Public/ecma/Managers/RoutesManager.ecma.js @@ -0,0 +1,151 @@ +"use strict"; + +import {Common} from "../Utils/Common.ecma.js"; +import {RouteModel} from "../Models/RouteModel.ecma.js"; + +/** + * @typedef {import("../AnP.ecma.js").AnP} AnP + */ + +/** + * @class RoutesManager + * @constructor + * @param {!AnP} anp + * @return {void} + * @access public + * @static + */ +export const RoutesManager = (function(){ + + /** + * @callback continue_callback + * @param {!boolean} ok + * @return {boolean} + */ + + /** + * @constructs RoutesManager + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ + const RoutesManager = function(anp){ + + /** @type {RoutesManager} */ + const self = this, + /** @type {Array.} */ + routes = []; + /** @type {boolean} */ + let started = false, + /** @type {string} */ + last_url = "", + /** @type {number|null} */ + thread = null; + + /** + * @returns {void} + * @access private + */ + const constructor = () => { + + thread = anp.threads.add(thread_method, { + bucle : true, + autoplay : true + }); + + }; + + /** + * @returns {void} + * @access private + */ + const thread_method = () => { + + /** @type {string} */ + const current_url = window.location.hash.substring(1); + + if(last_url != current_url){ + last_url = current_url; + self.go(last_url); + }; + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.update = (callback = null) => { + Common.execute_array(["default_routes_files", "routes_files", "default_routes", "routes"], (key, next) => { + self.add(anp.settings.get(key), true, next); + }, callback, true); + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.reset = (callback = null) => { + + routes.splice(0, routes.length); + + self.update(callback); + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.start = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(started){ + end(false); + return false; + }; + started = true; + + self.update(() => end(true)); + + return true; + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.close = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(!started){ + end(false); + return false; + }; + started = false; + + end(true); + + return true; + }; + + this.add = (inputs, overwrite = false, callback = null) => { + Common.execute(callback, true); + }; + + this.go = path => {}; + + constructor(); + }; + + return RoutesManager; +})(); \ No newline at end of file diff --git a/Public/ecma/Managers/SessionsManager.ecma.js b/Public/ecma/Managers/SessionsManager.ecma.js new file mode 100644 index 0000000..39c5e71 --- /dev/null +++ b/Public/ecma/Managers/SessionsManager.ecma.js @@ -0,0 +1,81 @@ +"use strict"; + +import {SessionModel} from "../Models/SessionModel.ecma.js"; + +/** + * @typedef {import("../Application/AnP.ecma.js").AnP} AnP + */ + +/** + * @class SessionsManager + * @constructor + * @param {!AnP} anp + * @return {void} + * @access public + * @static + */ +export const SessionsManager = (function(){ + + /** + * @constructs SessionsManager + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ + const SessionsManager = function(anp){ + + /** @type {SessionsManager} */ + const self = this, + /** @type {Object.} */ + sessions = {}; + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + /** + * @param {!(Object.|Array.)} inputs + * @return {number} + * @access public + */ + this.set = inputs => { + + /** @type {number} */ + let i; + + while(sessions[i = Math.random() * (1 << 28) | 0]); + + return (sessions[i] = new SessionModel(i, inputs)).i; + }; + + /** + * @param {!(number|Array.)} ids + * @param {!(string|Array.)} permissions + * @returns {boolean} + * @access public + */ + this.check_permissions = (ids, permissions) => Common.get_array(ids).some(id => ( + sessions[id] && sessions[id].check_permissions(permissions) + )); + + /** + * @param {!number} id + * @returns {boolean} + * @access public + */ + this.close = id => { + if(sessions[id]){ + delete sessions[id]; + return true; + }; + return false; + }; + + constructor(); + }; + + return SessionsManager; +})(); \ No newline at end of file diff --git a/Public/ecma/Managers/SettingsManager.ecma.js b/Public/ecma/Managers/SettingsManager.ecma.js new file mode 100644 index 0000000..4090041 --- /dev/null +++ b/Public/ecma/Managers/SettingsManager.ecma.js @@ -0,0 +1,189 @@ +"use strict"; + +import {Common} from "../Utils/Common.ecma.js"; +import {Check} from "../Utils/Checks.ecma.js"; + +/** + * @typedef {import("../Application/AnP.ecma.js").AnP} AnP + */ + +/** + * @class SettingsManager + * @constructor + * @param {!AnP} anp + * @param {?(Object.|Array)} [inputs = null] + * @returns {void} + * @access private + * @static + */ +export const SettingsManager = (function(){ + + /** + * @callback simple_callback + * @returns {void} + */ + + /** + * @callback continue_callback + * @param {!boolean} ok + * @return {boolean} + */ + + /** + * @constructs SettingsManager + * @param {!AnP} anp + * @param {?(Object.|Array)} [inputs = null] + * @returns {void} + * @access private + * @static + */ + const SettingsManager = function(anp, inputs = null){ + + /** @type {!AnP} */ + const self = this, + /** @type {Object.} */ + settings = {}, + /** @type {Object.} */ + secrets = {}; + /** @type {boolean} */ + let started = false; + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.update = (callback = null) => { + Common.execute_array(["default_settings_files", "settings_files", "default_settings", "settings"], (key, next) => { + self.add(self.get(key), true, next); + }, () => { + Common.execute_array(["default_secrets_files", "secrets_files", "default_secrets", "secrets"], (key, next) => { + self.add_secrets(self.get(key), true, next); + }, callback, true); + }, true); + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.reset = (callback = null) => { + + [settings, secrets].forEach(Common.clear_dictionary); + + self.update(callback); + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.start = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(started){ + end(false); + return false; + }; + started = true; + + self.update(() => end(true)); + + return true; + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.close = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(!started){ + end(false); + return false; + }; + started = false; + + end(true); + + return true; + }; + + /** + * @param {!(string|Array.)} keys + * @param {?(Object.|Array)} [subinputs = null] + * @param {?any} [_default = null] + * @returns {any|null} + * @access public + */ + this.get = (keys, subinputs = null, _default = null) => Common.get_value(keys, [ + subinputs, inputs, secrets, settings, SettingsManager.DEFAULT_SETTINGS + ], _default); + + /** + * @param {?any} inputs + * @param {!boolean} [overwrite = false] + * @param {?simple_callback} [callback = null] + * @return {void} + * @access public + */ + this.add = (inputs, overwrite = false, callback = null) => { + anp.files.load_json(inputs, data => { + for(let subinputs of data) + Object.entries(subinputs).filter(([key, _]) => ( + !Check.is_mark_key(key) && + (overwrite || settings[key] === undefined) + )).forEach(([key, value]) => { + settings[key] = value; + }); + Common.execute(callback); + }, true); + }; + + /** + * @param {?any} inputs + * @param {!boolean} [overwrite = false] + * @param {?simple_callback} [callback = null] + * @return {void} + * @access public + */ + this.add_secrets = (inputs, overwrite = false, callback = null) => { + anp.files.load_json(inputs, data => { + for(let subinputs of data) + Object.entries(subinputs).filter(([key, _]) => ( + !Check.is_mark_key(key) && + (overwrite || secrets[key] === undefined)) + ).forEach(([key, value]) => { + secrets[key] = value; + }); + Common.execute(callback); + }, true); + }; + + constructor(); + + }; + + /** @type {Object.} */ + SettingsManager.DEFAULT_SETTINGS = { + autostart : true, + default_settings_files : "/json/AnP.settings.json" + }; + + return SettingsManager; +})(); \ No newline at end of file diff --git a/Public/ecma/Managers/ThreadsManager.ecma.js b/Public/ecma/Managers/ThreadsManager.ecma.js new file mode 100644 index 0000000..e8f90b2 --- /dev/null +++ b/Public/ecma/Managers/ThreadsManager.ecma.js @@ -0,0 +1,258 @@ +"use strict"; + +import {ThreadModel} from "../Models/ThreadModel.ecma.js"; +import {Common} from "../Utils/Common.ecma.js"; +import {Check} from "../Utils/Checks.ecma.js"; + +/** + * @typedef {import("../Application/AnP.ecma.js").AnP} AnP + */ + +/** + * @class ThreadsManager + * @constructor + * @param {!AnP} anp + * @returns {void} + * @access private + * @static + */ +export const ThreadsManager = (function(){ + + /** + * @callback simple_callback + * @returns {void} + */ + + /** + * @callback continue_callback + * @param {!boolean} ok + * @return {boolean} + */ + + /** + * @constructs ThreadsManager + * @param {!AnP} anp + * @returns {void} + * @access private + * @static + */ + const ThreadsManager = function(anp){ + + /** @type {!AnP} */ + const self = this, + /** @type {Object.>} */ + threads = {}; + /** @type {boolean} */ + let started = false, + /** @type {number} */ + thread_i = 0, + /** @type {number} */ + interval = null, + /** @type {string} */ + mode = "interval", + /** @type {number} */ + frames_per_second = 60, + /** @type {number} */ + timer = 1000 / frames_per_second; + + /** + * @returns {void} + * @access private + */ + const constructor = () => { + + self.start(); + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.update = (callback = null) => { + + mode = anp.settings.get("threads_mode", null, mode); + + Common.execute(callback); + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.reset = (callback = null) => { + + Common.clear_dictionary(threads); + mode = "interval"; + + self.update(callback); + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.start = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(started){ + end(false); + return false; + }; + started = true; + + self.update(() => { + executor(); + end(true); + }); + + return true; + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.close = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(!started){ + end(false); + return false; + }; + started = false; + + end(true); + + return true; + }; + + /** + * @returns {void} + * @access private + */ + const execute = () => { + + /** @type {number} */ + const time = Date.now(); + + [...Object.entries(threads)].forEach(([i, thread]) => { + if(!thread.stopped && ( + !thread.frames_per_second || time - thread.last >= thread.timer + )){ + thread.callback(thread); + if(thread.bucle) + thread.last = time; + else + delete threads[i]; + }; + }); + + }; + + /** + * @returns {void} + * @access private + */ + const executor = () => { + + if(!started) + return; + + switch(mode){ + case "interval": + interval = setInterval(execute, timer); + break; + case "timeout": + setTimeout(() => { + execute(); + executor(); + }, timer); + break; + case "animation": + + /** @type {number} */ + const time = Date.now(); + + requestAnimationFrame(() => { + execute(); + setTimeout(executor, timer - (Date.now() - time)); + }); + + break; + case "only_animation": + requestAnimationFrame(() => { + execute(); + executor(); + }); + break; + }; + + }; + + /** + * @param {?any} inputs + * @param {!boolean} [overwrite = false] + * @param {?simple_callback} [callback = null] + * @return {void} + * @access public + */ + this.add = (callback, inputs = null) => { + if(!Check.is_function(callback)) + return null; + + threads[++ thread_i] = new ThreadModel(callback, thread_i, inputs); + + return thread_i; + }; + + /** + * @param {!number} i + * @return {void} + * @access public + */ + this.play = i => { + threads[i] && threads[i].stopped && (threads[i].stopped = false); + }; + + /** + * @param {!number} i + * @return {void} + * @access public + */ + this.stop = i => { + threads[i] && !threads[i].stopped && (threads[i].stopped = true); + }; + + /** + * @param {!number} i + * @return {boolean} + * @access public + */ + this.close = i => { + if(threads[i]){ + delete threads[i]; + return true; + }; + return false; + }; + + constructor(); + + }; + + /** @type {Object.} */ + ThreadsManager.DEFAULT_SETTINGS = {}; + + return ThreadsManager; +})(); \ No newline at end of file diff --git a/Public/ecma/Managers/UniqueKeysManager.ecma.js b/Public/ecma/Managers/UniqueKeysManager.ecma.js new file mode 100644 index 0000000..16bd864 --- /dev/null +++ b/Public/ecma/Managers/UniqueKeysManager.ecma.js @@ -0,0 +1,221 @@ +"use strict"; + +import {Common} from "../Utils/Common.ecma.js"; +import {Check} from "../Utils/Checks.ecma.js"; +import {RE} from "../Utils/Patterns.ecma.js"; +import {UniqueKeyModel} from "../Models/UniqueKeyModel.ecma.js"; + +/** + * @typedef {import("../Application/AnP.ecma.js").AnP} AnP + */ + +/** + * @class UniqueKeysManager + * @constructor + * @param {!AnP} anp + * @return {void} + * @access public + * @static + */ +export const UniqueKeysManager = (function(){ + + /** + * @callback simple_callback + * @returns {void} + */ + + /** + * @callback continue_callback + * @param {!boolean} ok + * @return {boolean} + */ + + /** + * @constructs UniqueKeysManager + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ + const UniqueKeysManager = function(anp){ + + /** @type {UniqueKeysManager} */ + const self = this, + /** @type {Object.} */ + keys = {}, + /** @type {Array.} */ + alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".split(""); + /** @type {boolean} */ + let started = false, + /** @type {number} */ + length = 13, + /** @type {number} */ + keys_i = 0, + /** @type {number|null} */ + thread = null; + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.update = (callback = null) => { + + /** @type {string|Array.} */ + const new_alphabet = anp.settings.get("unique_keys_alphabet", null, alphabet); + + alphabet.splice(0, keys.length, ...Common.unique( + Check.is_string(new_alphabet) ? new_alphabet.split("") : + Check.is_array(new_alphabet) ? new_alphabet : + alphabet)); + length = anp.settings.get("unique_keys_length", null, length); + + Common.execute(callback); + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.reset = (callback = null) => { + + keys.splice(0, keys.length); + alphabet.splice(0, keys.length, ..."123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".split("")); + length = 13; + + self.update(callback); + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.start = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(started){ + end(false); + return false; + }; + started = true; + + self.update(() => { + thread = anp.threads.add(thread_method); + end(true); + }); + + return true; + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.close = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(!started){ + end(false); + return false; + }; + started = false; + + end(true); + + return true; + }; + + /** + * @returns {void} + * @access private + */ + const thread_method = () => { + [...Object.entries(keys)].forEach(([i, model]) => { + if(model.is_html_item){ + if(model.loaded){ + if(!document.querySelector("#" + model.key + ",." + model.key + ",[name=" + model.key + "]")) + delete keys[i]; + }else if(document.querySelector("#" + model.key + ",." + model.key + ",[name=" + model.key + "]")) + model.loaded = true; + }; + }); + }; + + /** + * @param {!string} key + * @returns {boolean} + * @access public + */ + this.exists = key => Object.values(keys).some(k => k.key === key); + + /** + * @param {!boolean} [is_html_item = false] + * @return {string} + * @access public + */ + this.create = (is_html_item = false) => { + + /** @type {string} */ + let key; + /** @type {number} */ + const l = alphabet.length, + /** @type {number} */ + shift = Math.ceil(Math.log2(alphabet.length)); + + do{ + key = ""; + do{ + + /** @type {number} */ + let random = (Math.random() * (1 << 28)) | 0; + + while(random && (key += alphabet[random % l]).length < length) + random >>= shift; + + }while(key.length < length); + }while( + !RE.KEY.test(key) || + document.querySelector("#" + key + ",." + key + ",[name=" + key + "]") || + self.exists(key) + ); + keys[++ keys_i] = new UniqueKeyModel(key, is_html_item, keys_i); + + return key; + }; + + /** + * @param {!string} key + * @returns {boolean} + * @access public + */ + this.remove = key => { + return [...Object.entries(keys)].some(([i, model]) => { + if(model.key == key){ + delete keys[i]; + return true; + }; + return false; + }); + }; + + constructor(); + + }; + + return UniqueKeysManager; +})(); \ No newline at end of file diff --git a/Public/ecma/Managers/ViewsManager.ecma.js b/Public/ecma/Managers/ViewsManager.ecma.js new file mode 100644 index 0000000..6f89f50 --- /dev/null +++ b/Public/ecma/Managers/ViewsManager.ecma.js @@ -0,0 +1,138 @@ +"use strict"; + +import {Common} from "../Utils/Common.ecma.js"; + +/** + * @typedef {import("../AnP.ecma.js").AnP} AnP + */ + +/** + * @class ViewsManager + * @constructor + * @param {!AnP} anp + * @return {void} + * @access public + * @static + */ +export const ViewsManager = (function(){ + + /** + * @callback continue_callback + * @param {!boolean} ok + * @return {boolean} + */ + + /** + * @constructs ViewsManager + * @param {!AnP} anp + * @return {void} + * @access private + * @static + */ + const ViewsManager = function(anp){ + + /** @type {ViewsManager} */ + const self = this, + /** @type {Object.>} */ + views = {}; + /** @type {boolean} */ + let started = false; + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.update = (callback = null) => { + Common.execute_array(["default_views_files", "views_files", "default_views", "views"], (key, next) => { + self.add(self.get(key), true, next); + }, callback, true); + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.reset = (callback = null) => { + + Common.clear_dictionary(views); + + self.update(callback); + + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.start = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(started){ + end(false); + return false; + }; + started = true; + + self.update(() => end(true)); + + return true; + }; + + /** + * @param {?continue_callback} callback + * @returns {boolean} + * @access public + */ + this.close = (callback = null) => { + + /** @type {continue_callback} */ + const end = ok => Common.execute(callback, ok); + + if(!started){ + end(false); + return false; + }; + started = false; + + end(true); + + return true; + }; + + /** + * @param {?(Object.|Array.)} inputs + * @param {!boolean} [overwrite = false] + * @param {?continue_callback} [callback = null] + * @return {void} + * @access public + */ + this.add = (inputs, overwrite = false, callback = null) => { + anp.files.load_json(inputs, data => { + data.forEach(set => { + Object.entries(set).forEach(([key, value]) => { + if(overwrite || !views[key]) + views[key] = value; + }); + }); + Common.execute(callback, true); + }, true); + }; + + this.get = (key, inputs = null) => {}; + + constructor(); + }; + + return ViewsManager; +})(); \ No newline at end of file diff --git a/Public/ecma/Models/RouteModel.ecma.js b/Public/ecma/Models/RouteModel.ecma.js new file mode 100644 index 0000000..886b72f --- /dev/null +++ b/Public/ecma/Models/RouteModel.ecma.js @@ -0,0 +1,59 @@ +"use strict"; + +import {Check} from "../Utils/Checks.ecma.js"; +import {Common} from "../Utils/Common.ecma.js"; + +/** + * @class RouteModel + * @constructor + * @param {!(string|RegExp)} route + * @param {!string} view + * @returns {void} + * @access public + * @static + */ +export const RouteModel = (function(){ + + /** + * @constructs RouteModel + * @param {!(string|RegExp)} route + * @param {!string} view + * @returns {void} + * @access private + * @static + */ + const RouteModel = function(route, view){ + + /** @type {RouteModel} */ + const self = this; + + /** @type {RegExp|null} */ + this.route = null; + /** @type {Array.} */ + this.variables = []; + /** @type {string} */ + this.view = view; + + /** + * @returns {void} + * @access private + */ + const constructor = () => { + if(Check.is_string(route)) + route = new RegExp("^" + Common.to_regular_expression(route.replace(RE.STRING_VARIABLES, (_, key) => { + self.variables.push(key); + return "#######"; + })).replace(/#{7}/g, "([^\\/]+)") + "\\/?$", "i"); + else if(Check.is_regular_expression(route)) + (this.route = route).source.replace(/\([^\(\)]+\)/g, all => { + self.variables.push("" + self.variables.length); + return all; + }); + }; + + constructor(); + + }; + + return RouteModel; +})(); \ No newline at end of file diff --git a/Public/ecma/Models/SessionModel.ecma.js b/Public/ecma/Models/SessionModel.ecma.js new file mode 100644 index 0000000..dca5e25 --- /dev/null +++ b/Public/ecma/Models/SessionModel.ecma.js @@ -0,0 +1,70 @@ +"use strict"; + +import {Common} from "../Utils/Common.ecma.js"; + +/** + * @class SessionModel + * @constructor + * @param {!(Object.|Array.)} inputs + * @return {void} + * @access private + * @static + */ +export const SessionModel = (function(){ + + /** + * @constructs SessionModel + * @param {!number} i + * @param {!(Object.|Array.)} inputs + * @return {void} + * @access private + * @static + */ + const SessionModel = function(i, inputs){ + + /** @type {SessionModel} */ + const self = this; + /** @type {number|null} */ + let id = null, + /** @type {Array.} */ + permissions = [], + /** @type {number} */ + last_check = 0; + + /** @type {string|null} */ + this.nick = null; + /** @type {number} */ + this.type = SessionModel.LOCAL; + /** @type {number} */ + this.i = i; + + /** + * @returns {void} + * @access private + */ + const constructor = () => { + id = Common.get_value("id", inputs, null); + permissions = Common.get_value("permissions", inputs, []); + self.nick = Common.get_value("nick", inputs, null); + self.type = Common.get_value("type", inputs, self.type); + last_check = Date.now(); + }; + + /** + * @param {!(string|Array.)} permissions + * @returns {boolean} + * @access public + */ + this.check_permissions = permissions => permissions.some(self.permissions.includes); + + constructor(); + + }; + + /** @type {number} */ + SessionModel.LOCAL = 1 << 0; + /** @type {number} */ + SessionModel.REMOTE = 1 << 1; + + return SessionModel; +})(); \ No newline at end of file diff --git a/Public/ecma/Models/ThreadModel.ecma.js b/Public/ecma/Models/ThreadModel.ecma.js new file mode 100644 index 0000000..49dd910 --- /dev/null +++ b/Public/ecma/Models/ThreadModel.ecma.js @@ -0,0 +1,53 @@ +"use strict"; + +import {Common} from "../Utils/Common.ecma.js"; + +/** + * @class ThreadModel + * @constructor + * @param {!thread_callback} callback + * @param {!(Object.|Array.)} inputs + * @return {void} + * @access public + * @static + */ +export const ThreadModel = (function(){ + + /** + * @callback thread_callback + * @param {!ThreadModel} thread + * @return {void} + */ + + /** + * @constructs ThreadModel + * @param {!thread_callback} callback + * @param {!number} i + * @param {?(Object.|Array.)} [inputs = null] + * @return {void} + * @access private + * @static + */ + const ThreadModel = function(callback, i, inputs = null){ + /** @type {number} */ + this.i = i; + /** @type {thread_callback} */ + this.callback = callback; + /** @type {boolean} */ + this.autoplay = Common.get_value("autoplay", inputs, true); + /** @type {boolean} */ + this.play_immediately = Common.get_value("play_immediately", inputs, false); + /** @type {number} */ + this.last = this.play_immediately ? 0 : Date.now(); + /** @type {boolean} */ + this.stopped = Common.get_value("stopped", inputs, false); + /** @type {number} */ + this.frames_per_second = Common.get_value(["frames_per_second", "fps"], inputs, 0); + /** @type {number} */ + this.timer = this.frames_per_second > 0 ? 1000 / this.frames_per_second : 0; + /** @type {boolean} */ + this.bucle = Common.get_value("bucle", inputs, false); + }; + + return ThreadModel; +})(); \ No newline at end of file diff --git a/Public/ecma/Models/UniqueKeyModel.ecma.js b/Public/ecma/Models/UniqueKeyModel.ecma.js new file mode 100644 index 0000000..a7bb84e --- /dev/null +++ b/Public/ecma/Models/UniqueKeyModel.ecma.js @@ -0,0 +1,45 @@ +"use strict"; + +import {Common} from "../Utils/Common.ecma.js"; + +/** + * @class ThreadModel + * @constructor + * @param {!thread_callback} callback + * @param {!(Object.|Array.)} inputs + * @return {void} + * @access public + * @static + */ +export const UniqueKeyModel = (function(){ + + /** + * @callback thread_callback + * @param {!UniqueKeyModel} thread + * @return {void} + */ + + /** + * @constructs UniqueKeyModel + * @param {!string} key + * @param {!boolean} is_html_item + * @param {!number} i + * @return {void} + * @access private + * @static + */ + const UniqueKeyModel = function(key, is_html_item, i){ + /** @type {number} */ + this.i = i; + /** @type {string} */ + this.key = key; + /** @type {boolean} */ + this.is_html_item = is_html_item; + /** @type {boolean} */ + this.loaded = false; + /** @type {number} */ + this.date = Date.now(); + }; + + return UniqueKeyModel; +})(); \ No newline at end of file diff --git a/Public/ecma/Utils/Checks.ecma.js b/Public/ecma/Utils/Checks.ecma.js new file mode 100644 index 0000000..3d34666 --- /dev/null +++ b/Public/ecma/Utils/Checks.ecma.js @@ -0,0 +1,147 @@ +"use strict"; + +import {RE} from "./Patterns.ecma.js"; +import {Common} from "./Common.ecma.js"; + +/** + * @class Check + * @constructor + * @returns {void} + * @access private + * @static + */ +export const Check = (function(){ + + /** + * @constructs Check + * @returns {void} + * @access private + * @static + */ + const Check = function(){}; + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_string = item => typeof item == "string"; + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_key = item => typeof item == "string" && RE.KEY.test(item); + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_object = item => item && typeof item == "object"; + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_dictionary = item => item && item.constructor == Object; + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_array = item => item instanceof Array; + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_function = item => typeof item == "function"; + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_bool = item => typeof item == "boolean"; + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_json_item = item => Check.is_dictionary(item) || Check.is_array(item); + + /** + * @param {?any} item + * @param {!boolean} [full_check = null] + * @returns {boolean} + * @access public + * @static + */ + Check.is_json = (item, full_check = true) => ( + item && Check.is_string(item) && + ["[]", "{}"].includes((item = item.trim())[0] + item[item.length - 1]) && + (!full_check || JSON.parse(item, () => null) !== null) + ); + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_html_item = item => item && (item.tagName || item.nodeName); + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_regular_expression = item => item instanceof RegExp; + + /** + * @param {!string} key + * @param {!(string|Array.)} [marks = "AnP"] + * @returns {boolean} + * @access public + * @static + */ + Check.is_mark_key = (key, marks = "AnP") => ( + Check.is_key(key) && + Common.get_keys(marks).some(mark => key.startsWith(mark + "_")) && + ["end", "start"].some(close => key.endsWith("_" + close)) + ); + + /** + * @returns {boolean} + * @access public + * @static + */ + Check.is_mobile = () => ((a) => ( + /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || + /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)) + ))(navigator.userAgent || navigator.vendor || window.opera); + + /** + * @returns {boolean} + * @access public + * @static + */ + Check.is_dark_mode = () => window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; + + return Check; +})(); \ No newline at end of file diff --git a/Public/ecma/Utils/Common.ecma.js b/Public/ecma/Utils/Common.ecma.js new file mode 100644 index 0000000..9ef38a0 --- /dev/null +++ b/Public/ecma/Utils/Common.ecma.js @@ -0,0 +1,471 @@ +"use strict"; + +import {Check} from "./Checks.ecma.js"; +import {RE} from "./Patterns.ecma.js"; + +/** + * @class Common + * @constructor + * @returns {void} + * @access private + * @static + */ +export const Common = (function(){ + + /** + * @callback execute_callback + * @param {...(any|null)} parameters + * @returns {any|null} + */ + + /** + * @callback simple_callback + * @returns {void} + */ + + /** + * @callback each_item_callback + * @param {?any} item + * @param {!simple_callback} next + * @return {void} + */ + + /** + * @callback preload_callback + * @param {?HTMLElement} item + * @param {!boolean} asynchronous + * @param {!boolean} ok + * @return {void} + */ + + /** + * @constructs Common + * @returns {void} + * @access private + * @static + */ + const Common = function(){}; + + /** @type {Object.>} */ + Common.REGULAR_EXPRESSION = { + TO : { + "\n" : "n", + "\r" : "r", + "\t" : "t" + }, + FROM : { + n : "\n", + r : "\r", + t : "\t" + } + }; + + /** + * @param {...(any|null)} items + * @returns {Array.} + * @access public + * @static + */ + Common.get_keys = (...items) => items.reduce((keys, item) => { + + if(Check.is_key(item)) + keys.includes(item) || keys.push(item); + else if(Check.is_array(item)) + keys.push(...Common.get_keys(...item).filter(key => !keys.includes(key))); + + return keys; + }, []); + + /** + * @param {...(any|null)} items + * @returns {Array.} + * @access public + * @static + */ + Common.get_texts = (...items) => items.reduce((texts, item) => { + + if(Check.is_string(item)) + texts.includes(item) || texts.push(item); + else if(Check.is_array(item)) + texts.push(...Common.get_texts(...item)); + + return texts; + }, []); + + /** + * @param {...(any|null)} items + * @returns {Array.>} + * @access public + * @static + */ + Common.get_dictionaries = (...items) => items.reduce((dictionaries, item) => { + + if(Check.is_dictionary(item)) + dictionaries.push(item); + else if(Check.is_array(item)) + dictionaries.push(...Common.get_dictionaries(...item)); + + return dictionaries; + }, []); + + /** + * @param {any|null} items + * @param {!boolean} [overwrite = false] + * @param {!Array.} [except = []] + * @returns {Object.} + * @access public + * @static + */ + Common.get_dictionary = (items, overwrite = false, except = []) => { + if(Check.is_dictionary(items)) + return Object.entries(items).filter(([key, _]) => !except.includes(key)).reduce((dictionary, [key, value]) => { + dictionary[key] = value; + return dictionary; + }, {}); + if(Check.is_array(items)) + return items.reduce((dictionary, item) => { + + if(Check.is_dictionary(item)) + Object.keys(item).filter(key => ( + overwrite || dictionary[key] === undefined + ) && !except.includes(key)).forEach(key => { + dictionary[key] = item[key]; + }); + else if(Check.is_array(item)) + Object.entries(Common.get_dictionary(item, overwrite, except)).filter(([key, _]) => ( + overwrite || dictionary[key] === undefined + ) && !except.includes(key)).forEach(([key, value]) => { + dictionary[key] = value; + }); + + return dictionary; + }, {}); + return {}; + }; + + /** + * @param {?any} items + * @returns {Array.} + * @access public + * @static + */ + Common.get_array = items => Check.is_array(items) ? items : [items]; + + /** + * @param {!(string|Array.)} keys + * @param {!(Object.|Array)} inputs + * @param {?any} [_default = null] + * @returns {any|null} + * @access public + * @static + */ + Common.get_value = (keys, inputs, _default = null) => { + if((keys = Common.get_keys(keys)).length) + for(let subinputs of Common.get_dictionaries(inputs)) + for(let key of keys) + if(subinputs[key] !== undefined) + return subinputs[key]; + return _default; + }; + + /** + * @param {!string} string + * @param {!(Object.|Array)} inputs + * @param {?any} [_default = null] + * @returns {string} + * @access public + * @static + */ + Common.string_variables = (string, inputs, _default = null) => { + + inputs = Common.get_dictionary(inputs); + + return ("" + string).replace(RE.STRING_VARIABLES, (all, key) => ( + inputs[key] !== undefined ? inputs[key] : + _default !== null ? _default : + all)); + }; + + /** + * @param {!execute_callback} callback + * @param {...(any|null)} parameters + * @returns {any|null} + * @access public + * @static + */ + Common.execute = (callback, ...parameters) => Check.is_function(callback) ? callback(...parameters) : null; + + /** + * @param {!Array.} array + * @param {!each_item_callback} each_callback + * @param {?simple_callback} end_callback + * @param {!number} [i = null] + * @returns {void} + * @access private + * @static + */ + const execute_array_ordered = (array, each_callback, end_callback, i = 0) => { + if(i == array.length) + Common.execute(end_callback); + else + Common.execute(each_callback, array[i], () => { + execute_array_ordered(array, each_callback, end_callback, i + 1); + }); + }; + + /** + * @param {!Array.} array + * @param {!each_item_callback} each_callback + * @param {?simple_callback} end_callback + * @returns {void} + * @access private + * @static + */ + const execute_array_unordered = (array, each_callback, end_callback) => { + + /** @type {number} */ + const l = array.length; + /** @type {number} */ + let i = 0; + + if(array.length){ + for(let item of array) + Common.execute(each_callback, item, () => { + ++ i == l && Common.execute(end_callback); + }); + }else + Common.execute(end_callback); + + }; + + /** + * @param {!Array.} array + * @param {!each_item_callback} each_callback + * @param {?simple_callback} end_callback + * @param {!boolean} [ordered = false] + * @returns {void} + * @access public + * @static + */ + Common.execute_array = (array, each_callback, end_callback = null, ordered = false) => { + if(ordered) + execute_array_ordered(array, each_callback, end_callback); + else + execute_array_unordered(array, each_callback, end_callback); + }; + + /** + * @param {!Object.} dictionary + * @returns {void} + * @access public + * @static + */ + Common.clear_dictionary = dictionary => { + [...Object.keys(dictionary)].forEach(key => { + delete dictionary[key]; + }); + }; + + /** + * @param {!string} string + * @returns {string} + * @access public + * @static + */ + Common.to_kebab = string => string.replace(RE.TO_KEBAB, (_, capital, rest, special) => ( + capital ? "-" + (capital + rest).toLowerCase() : + special ? "-" : + "")).toLowerCase(); + + /** + * @param {!(string|HTMLElement)} selector + * @param {!preload_callback} callback + * @param {!number} [timeout = 2000] + * @param {!number} [fps = 10] + * @returns {void} + * @access public + * @static + */ + Common.preload = (selector, callback, timeout = 2000, fps = 10) => { + if(!Check.is_function(callback)) + return; + if(Check.is_html_item(selector)) + return callback(selector, false, true); + if(!Check.is_string(selector)) + return callback(null, false, false); + + /** @type {HTMLElement|null} */ + let item; + + try{ + if(item = document.querySelector(selector)) + try{ + return callback(item, false, true); + }catch(exception){ + console.error(exception); + }; + }catch(exception){ + return callback(null, false, false); + }; + + /** @type {number} */ + const date = Date.now(), + /** @type {number} */ + interval = setInterval(() => { + if(item = document.querySelector(selector)){ + clearInterval(interval); + return callback(item, true, true); + }; + if(Date.now() - date > timeout){ + clearInterval(interval); + return callback(null, true, false); + }; + }, 1000 / fps); + + }; + + /** + * @param {...(HTMLElement|string|Array.)} inputs + * @returns {Array.} + * @access public + * @static + */ + Common.HTML = (...inputs) => { + + /** @type {DocumentFragment} */ + const fragment = new DocumentFragment(), + /** @type {HTMLElement|null} */ + master = ( + Check.is_html_item(inputs[0]) ? inputs[0] : + Check.is_string(inputs[0]) ? document.querySelector(inputs[0]) : + null); + + (master ? inputs.slice(1) : inputs).forEach(subinputs => { + if(Check.is_html_item(subinputs)) + fragment.appendChild(subinputs); + else if(Check.is_string(subinputs)) + fragment.appendChild(document.createTextNode(subinputs)); + else if(Check.is_array(subinputs)){ + + /** @type {[string, Object.|null, any|null]} */ + const [tag, attributes, children] = subinputs.concat([null, null]).slice(0, 3), + /** @type {HTMLElement} */ + item = document.createElement(tag); + + Check.is_dictionary(attributes) && Object.entries(attributes).forEach(([key, value]) => { + if(RE.ON_ATTRIBUTE.test(key) && Check.is_function(value)) + item.addEventListener(key.replace(RE.ON_ATTRIBUTE, "").replace(RE.SPECIAL_HTML_EVENT_CHARACTERS, "").toLowerCase(), event => { + value(item, event); + }); + else if(value !== null) + item.setAttribute(Common.to_kebab(key), value); + }); + + if(Check.is_array(children)) + Common.HTML(...children).forEach(child => item.appendChild(child)); + else if(Check.is_string(children)) + item.innerHTML += children; + + fragment.appendChild(item); + + }; + }); + + master && master.appendChild(fragment); + + return [...fragment.childNodes]; + }; + + /** + * @param {?any} value + * @returns {any|null} + * @access public + * @static + */ + Common.unique = value => ( + Check.is_string(value) ? value.split("").filter((char, i, array) => array.indexOf(char) == i).join("") : + Check.is_array(value) ? value.filter((item, i, array) => array.indexOf(item) == i) : + value); + + /** + * @param {?any} value + * @return {string|null} + * @access public + * @static + */ + Common.json_encode = value => { + try{ + return JSON.stringify(value); + }catch(exception){}; + return null; + }; + + /** + * @param {?any} value + * @returns {Object.|Array.|null} + * @access public + * @static + */ + Common.json_decode = value => { + try{ + return JSON.parse(value); + }catch(exception){}; + return null; + }; + + /** + * @param {?any} value + * @returns {string|null} + * @access public + * @static + */ + Common.base64_encode = value => { + if(Check.is_json_item(value)) + return btoa(JSON.stringify(value)); + try{ + return btoa(value); + }catch(exception){}; + return null; + }; + + /** + * @param {?any} value + * @returns {string|null} + * @access public + * @static + */ + Common.base64_decode = value => { + try{ + return atob(value); + }catch(exception){}; + return null; + }; + + /** + * @param {!(Object.|Array.)} data + * @returns {string} + * @access public + * @static + */ + Common.data_encode = data => Common.base64_encode(Common.json_encode(data)); + + /** + * @param {!string} data + * @returns {(Object.|Array.)} + * @access public + * @static + */ + Common.data_decode = data => Common.json_decode(Common.base64_decode(data)); + + /** + * @param {!string} string + * @returns {string} + * @access public + * @static + */ + Common.to_regular_expression = string => string.replace(RE.TO_REGULAR_EXPRESSION, character => ( + "\\" + (Common.REGULAR_EXPRESSION.FROM[character] || character) + )); + + return Common; +})(); \ No newline at end of file diff --git a/Public/ecma/Utils/HTMLDSL.ecma.js b/Public/ecma/Utils/HTMLDSL.ecma.js new file mode 100644 index 0000000..945754a --- /dev/null +++ b/Public/ecma/Utils/HTMLDSL.ecma.js @@ -0,0 +1,349 @@ +"use strict"; + +/** + * @callback element_callback + * @param {!Object.} [attributes = {}] + * @param {!Array.} [children = []] + * @returns {!Array.} + */ + +/** @type {element_callback} */ +export const Div = (attributes = {}, children = []) => ["div", attributes, children]; +/** @type {element_callback} */ +export const Span = (attributes = {}, children = []) => ["span", attributes, children]; +/** @type {element_callback} */ +export const Footer = (attributes = {}, children = []) => ["footer", attributes, children]; + +/** @type {element_callback} */ +export const Header = (attributes = {}, children = []) => ["header", attributes, children]; +/** @type {element_callback} */ +export const Main = (attributes = {}, children = []) => ["main", attributes, children]; + +/** @type {element_callback} */ +export const H1 = (attributes = {}, children = []) => ["h1", attributes, children]; +/** @type {element_callback} */ +export const H2 = (attributes = {}, children = []) => ["h2", attributes, children]; +/** @type {element_callback} */ +export const H3 = (attributes = {}, children = []) => ["h3", attributes, children]; +/** @type {element_callback} */ +export const H4 = (attributes = {}, children = []) => ["h4", attributes, children]; +/** @type {element_callback} */ +export const H5 = (attributes = {}, children = []) => ["h5", attributes, children]; +/** @type {element_callback} */ +export const H6 = (attributes = {}, children = []) => ["h6", attributes, children]; + +/** @type {element_callback} */ +export const Heading1 = H1; +/** @type {element_callback} */ +export const Heading2 = H2; +/** @type {element_callback} */ +export const Heading3 = H3; +/** @type {element_callback} */ +export const Heading4 = H4; +/** @type {element_callback} */ +export const Heading5 = H5; +/** @type {element_callback} */ +export const Heading6 = H6; + +/** @type {element_callback} */ +export const Heading = (level, attributes = {}, children = []) => { + const tag = "h" + Math.min(Math.max(1, level), 6); + return [tag, attributes, children]; +}; +/** @type {element_callback} */ +export const H = Heading; + +/** @type {element_callback} */ +export const A = (attributes = {}, children = []) => ["a", attributes, children]; +/** @type {element_callback} */ +export const Anchor = A; + +/** @type {element_callback} */ +export const Img = (attributes = {}, children = []) => ["img", attributes, children]; +/** @type {element_callback} */ +export const Image = Img; + +/** @type {element_callback} */ +export const P = (attributes = {}, children = []) => ["p", attributes, children]; +/** @type {element_callback} */ +export const Paragraph = P; + +/** @type {element_callback} */ +export const Section = (attributes = {}, children = []) => ["section", attributes, children]; +/** @type {element_callback} */ +export const Article = (attributes = {}, children = []) => ["article", attributes, children]; + +/** @type {element_callback} */ +export const Aside = (attributes = {}, children = []) => ["aside", attributes, children]; + +/** @type {element_callback} */ +export const Label = (attributes = {}, children = []) => ["label", attributes, children]; + +/** @type {element_callback} */ +export const Form = (attributes = {}, children = []) => ["form", attributes, children]; + +/** @type {element_callback} */ +export const Fieldset = (attributes = {}, children = []) => ["fieldset", attributes, children]; +/** @type {element_callback} */ +export const Legend = (attributes = {}, children = []) => ["legend", attributes, children]; + +/** @type {element_callback} */ +export const Input = (attributes = {}, children = []) => ["input", attributes, children]; +/** @type {element_callback} */ +export const Checkbox = (attributes = {}, children = []) => ["input", Object.assign({type : "checkbox"}, attributes), children]; +/** @type {element_callback} */ +export const Radio = (attributes = {}, children = []) => ["input", Object.assign({type : "radio"}, attributes), children]; +/** @type {element_callback} */ +export const Submit = (attributes = {}, children = []) => ["input", Object.assign({type : "submit"}, attributes), children]; +/** @type {element_callback} */ +export const Reset = (attributes = {}, children = []) => ["input", Object.assign({type : "reset"}, attributes), children]; +/** @type {element_callback} */ +export const Hidden = (attributes = {}, children = []) => ["input", Object.assign({type : "hidden"}, attributes), children]; +/** @type {element_callback} */ +export const Text = (attributes = {}, children = []) => ["input", Object.assign({type : "text"}, attributes), children]; +/** @type {element_callback} */ +export const Date = (attributes = {}, children = []) => ["input", Object.assign({type : "date"}, attributes), children]; +/** @type {element_callback} */ +export const File = (attributes = {}, children = []) => ["input", Object.assign({type : "file"}, attributes), children]; +/** @type {element_callback} */ +export const Password = (attributes = {}, children = []) => ["input", Object.assign({type : "password"}, attributes), children]; +/** @type {element_callback} */ +export const Email = (attributes = {}, children = []) => ["input", Object.assign({type : "email"}, attributes), children]; +/** @type {element_callback} */ +export const Number = (attributes = {}, children = []) => ["input", Object.assign({type : "number"}, attributes), children]; +/** @type {element_callback} */ +export const Integer = (attributes = {}, children = []) => ["input", Object.assign({type : "number", step : 1}, attributes), children]; +/** @type {element_callback} */ +export const Float = Number; +/** @type {element_callback} */ +export const Range = (attributes = {}, children = []) => ["input", Object.assign({type : "range"}, attributes), children]; +/** @type {element_callback} */ +export const Color = (attributes = {}, children = []) => ["input", Object.assign({type : "color"}, attributes), children]; +/** @type {element_callback} */ +export const RadioButton = Radio; + +/** @type {element_callback} */ +export const Button = (attributes = {}, children = []) => ["button", attributes, children]; +/** @type {element_callback} */ +export const Textarea = (attributes = {}, children = []) => ["textarea", attributes, children]; +/** @type {element_callback} */ +export const Select = (attributes = {}, children = []) => ["select", attributes, children]; +/** @type {element_callback} */ +export const Option = (attributes = {}, children = []) => ["option", attributes, children]; + +/** @type {element_callback} */ +export const Optgroup = (attributes = {}, children = []) => ["optgroup", attributes, children]; +/** @type {element_callback} */ +export const OptionGroup = Optgroup; + +/** @type {element_callback} */ +export const Table = (attributes = {}, children = []) => ["table", attributes, children]; + +/** @type {element_callback} */ +export const TBody = (attributes = {}, children = []) => ["tbody", attributes, children]; +/** @type {element_callback} */ +export const THead = (attributes = {}, children = []) => ["thead", attributes, children]; +/** @type {element_callback} */ +export const TFoot = (attributes = {}, children = []) => ["tfoot", attributes, children]; +/** @type {element_callback} */ +export const TR = (attributes = {}, children = []) => ["tr", attributes, children]; +/** @type {element_callback} */ +export const TD = (attributes = {}, children = []) => ["td", attributes, children]; +/** @type {element_callback} */ +export const TH = (attributes = {}, children = []) => ["th", attributes, children]; + +/** @type {element_callback} */ +export const TableBody = TBody; +/** @type {element_callback} */ +export const TableHead = THead; +/** @type {element_callback} */ +export const TableFoot = TFoot; +/** @type {element_callback} */ +export const TableRow = TR; +/** @type {element_callback} */ +export const TableCell = TD; +/** @type {element_callback} */ +export const TableHeaderCell = TH; + +/** @type {element_callback} */ +export const UL = (attributes = {}, children = []) => ["ul", attributes, children]; +/** @type {element_callback} */ +export const OL = (attributes = {}, children = []) => ["ol", attributes, children]; +/** @type {element_callback} */ +export const LI = (attributes = {}, children = []) => ["li", attributes, children]; +/** @type {element_callback} */ +export const DL = (attributes = {}, children = []) => ["dl", attributes, children]; +/** @type {element_callback} */ +export const DT = (attributes = {}, children = []) => ["dt", attributes, children]; +/** @type {element_callback} */ +export const DD = (attributes = {}, children = []) => ["dd", attributes, children]; +/** @type {element_callback} */ +export const Nav = (attributes = {}, children = []) => ["nav", attributes, children]; + +/** @type {element_callback} */ +export const UnorderedList = UL; +/** @type {element_callback} */ +export const OrderedList = OL; +/** @type {element_callback} */ +export const ListItem = LI; +/** @type {element_callback} */ +export const DescriptionList = DL; +/** @type {element_callback} */ +export const DescriptionTerm = DT; +/** @type {element_callback} */ +export const DescriptionDetails = DD; +/** @type {element_callback} */ +export const Navigation = Nav; + +/** @type {element_callback} */ +export const I = (attributes = {}, children = []) => ["i", attributes, children]; +/** @type {element_callback} */ +export const Italic = I; + +/** @type {element_callback} */ +export const B = (attributes = {}, children = []) => ["b", attributes, children]; +/** @type {element_callback} */ +export const Strong = B; +/** @type {element_callback} */ +export const Bold = B; + +/** @type {element_callback} */ +export const U = (attributes = {}, children = []) => ["u", attributes, children]; +/** @type {element_callback} */ +export const Underline = U; + +/** @type {element_callback} */ +export const S = (attributes = {}, children = []) => ["s", attributes, children]; +/** @type {element_callback} */ +export const Strike = S; +/** @type {element_callback} */ +export const StrikeThrough = S; + +/** @type {element_callback} */ +export const Mark = (attributes = {}, children = []) => ["mark", attributes, children]; + +/** @type {element_callback} */ +export const Small = (attributes = {}, children = []) => ["small", attributes, children]; + +/** @type {element_callback} */ +export const Sub = (attributes = {}, children = []) => ["sub", attributes, children]; +/** @type {element_callback} */ +export const Subscript = Sub; + +/** @type {element_callback} */ +export const Sup = (attributes = {}, children = []) => ["sup", attributes, children]; +/** @type {element_callback} */ +export const Superscript = Sup; + +/** @type {element_callback} */ +export const BR = (attributes = {}, children = []) => ["br", attributes, children]; +/** @type {element_callback} */ +export const Break = BR; + +/** @type {element_callback} */ +export const HR = (attributes = {}, children = []) => ["hr", attributes, children]; +/** @type {element_callback} */ +export const HorizontalRule = HR; + +/** @type {element_callback} */ +export const Datalist = (attributes = {}, children = []) => ["datalist", attributes, children]; + +/** @type {element_callback} */ +export const Output = (attributes = {}, children = []) => ["output", attributes, children]; + +/** @type {element_callback} */ +export const Progress = (attributes = {}, children = []) => ["progress", attributes, children]; + +/** @type {element_callback} */ +export const Meter = (attributes = {}, children = []) => ["meter", attributes, children]; + +/** @type {element_callback} */ +export const Details = (attributes = {}, children = []) => ["details", attributes, children]; + +/** @type {element_callback} */ +export const Summary = (attributes = {}, children = []) => ["summary", attributes, children]; + +/** @type {element_callback} */ +export const Dialog = (attributes = {}, children = []) => ["dialog", attributes, children]; + +/** @type {element_callback} */ +export const Menu = (attributes = {}, children = []) => ["menu", attributes, children]; + +/** @type {element_callback} */ +export const Menuitem = (attributes = {}, children = []) => ["menuitem", attributes, children]; + +/** @type {element_callback} */ +export const Menuitemcheckbox = (attributes = {}, children = []) => ["menuitemcheckbox", attributes, children]; + +/** @type {element_callback} */ +export const Menuitemradio = (attributes = {}, children = []) => ["menuitemradio", attributes, children]; + +/** @type {element_callback} */ +export const Slot = (attributes = {}, children = []) => ["slot", attributes, children]; + +/** @type {element_callback} */ +export const Template = (attributes = {}, children = []) => ["template", attributes, children]; + +/** @type {element_callback} */ +export const Canvas = (attributes = {}, children = []) => ["canvas", attributes, children]; + +/** @type {element_callback} */ +export const SVG = (attributes = {}, children = []) => ["svg", attributes, children]; + +/** @type {element_callback} */ +export const MathML = (attributes = {}, children = []) => ["math", attributes, children]; + +/** @type {element_callback} */ +export const Audio = (attributes = {}, children = []) => ["audio", attributes, children]; + +/** @type {element_callback} */ +export const Video = (attributes = {}, children = []) => ["video", attributes, children]; + +/** @type {element_callback} */ +export const Source = (attributes = {}, children = []) => ["source", attributes, children]; + +/** @type {element_callback} */ +export const Track = (attributes = {}, children = []) => ["track", attributes, children]; + +/** @type {element_callback} */ +export const Iframe = (attributes = {}, children = []) => ["iframe", attributes, children]; + +/** @type {element_callback} */ +export const Embed = (attributes = {}, children = []) => ["embed", attributes, children]; + +/** @type {element_callback} */ +export const Object = (attributes = {}, children = []) => ["object", attributes, children]; + +/** @type {element_callback} */ +export const Param = (attributes = {}, children = []) => ["param", attributes, children]; + +/** @type {element_callback} */ +export const Picture = (attributes = {}, children = []) => ["picture", attributes, children]; + +/** @type {element_callback} */ +export const SourceElement = (attributes = {}, children = []) => ["source", attributes, children]; + +/** @type {element_callback} */ +export const Map = (attributes = {}, children = []) => ["map", attributes, children]; + +/** @type {element_callback} */ +export const Area = (attributes = {}, children = []) => ["area", attributes, children]; + +/** @type {element_callback} */ +export const Meta = (attributes = {}, children = []) => ["meta", attributes, children]; + +/** @type {element_callback} */ +export const Link = (attributes = {}, children = []) => ["link", attributes, children]; + +/** @type {element_callback} */ +export const Base = (attributes = {}, children = []) => ["base", attributes, children]; + +/** @type {element_callback} */ +export const Head = (attributes = {}, children = []) => ["head", attributes, children]; + +/** @type {element_callback} */ +export const Body = (attributes = {}, children = []) => ["body", attributes, children]; + +/** @type {element_callback} */ +export const HTML = (attributes = {}, children = []) => ["html", attributes, children]; + diff --git a/Public/ecma/Utils/Patterns.ecma.js b/Public/ecma/Utils/Patterns.ecma.js new file mode 100644 index 0000000..56b3996 --- /dev/null +++ b/Public/ecma/Utils/Patterns.ecma.js @@ -0,0 +1,12 @@ +"use strict"; + +/** @type {Object.} */ +export const RE = { + KEY : /^[a-z_][a-z0-9_]*$/i, + STRING_VARIABLES : /\{([a-z_][a-z0-9_]*)\}/gi, + TO_KEBAB : /[\-_]?([A-Z])([A-Z0-9]*|[a-z0-9]*)|([^a-z0-9]+)/g, + ON_ATTRIBUTE : /^on[\-_]?/i, + SPECIAL_HTML_EVENT_CHARACTERS : /[^a-z0-9]+/gi, + WHITE_SPACES : /(?:\s+|[\r\n]+)+/g, + TO_REGULAR_EXPRESSION : /[\.\-\^\$\\\/\[\]\(\)\{\}\!\?\*\+\n\r\t]/g +}; \ No newline at end of file diff --git a/Public/favicon.ico b/Public/favicon.ico new file mode 100644 index 0000000..cad6265 Binary files /dev/null and b/Public/favicon.ico differ diff --git a/Public/images/AnP-180.png b/Public/images/AnP-180.png new file mode 100755 index 0000000..5f0b5f4 Binary files /dev/null and b/Public/images/AnP-180.png differ diff --git a/Public/images/AnP-192.png b/Public/images/AnP-192.png new file mode 100755 index 0000000..4a3e8b7 Binary files /dev/null and b/Public/images/AnP-192.png differ diff --git a/Public/images/AnP-270.png b/Public/images/AnP-270.png new file mode 100755 index 0000000..9259dec Binary files /dev/null and b/Public/images/AnP-270.png differ diff --git a/Public/images/AnP-32.png b/Public/images/AnP-32.png new file mode 100755 index 0000000..3d44a5e Binary files /dev/null and b/Public/images/AnP-32.png differ diff --git a/Public/images/AnP-512.png b/Public/images/AnP-512.png new file mode 100755 index 0000000..9b0990f Binary files /dev/null and b/Public/images/AnP-512.png differ diff --git a/Public/images/AnP.png b/Public/images/AnP.png new file mode 100755 index 0000000..9b0990f Binary files /dev/null and b/Public/images/AnP.png differ diff --git a/Public/images/default_avatar.png b/Public/images/default_avatar.png new file mode 100755 index 0000000..0fe9617 Binary files /dev/null and b/Public/images/default_avatar.png differ diff --git a/Public/images/flags/english.svg b/Public/images/flags/english.svg new file mode 100644 index 0000000..5eb5a47 --- /dev/null +++ b/Public/images/flags/english.svg @@ -0,0 +1,124 @@ + + + + diff --git a/Public/images/flags/espanol.svg b/Public/images/flags/espanol.svg new file mode 100644 index 0000000..c80e1a7 --- /dev/null +++ b/Public/images/flags/espanol.svg @@ -0,0 +1,117 @@ + + + + diff --git a/Public/images/flags/galego.svg b/Public/images/flags/galego.svg new file mode 100644 index 0000000..53ce3b0 --- /dev/null +++ b/Public/images/flags/galego.svg @@ -0,0 +1,112 @@ + + + + diff --git a/Public/images/flags/nihongo.svg b/Public/images/flags/nihongo.svg new file mode 100644 index 0000000..42739eb --- /dev/null +++ b/Public/images/flags/nihongo.svg @@ -0,0 +1,114 @@ + + + + diff --git a/Public/images/flags/russkiy.svg b/Public/images/flags/russkiy.svg new file mode 100644 index 0000000..5ed18ae --- /dev/null +++ b/Public/images/flags/russkiy.svg @@ -0,0 +1,116 @@ + + + + diff --git a/Public/index.html b/Public/index.html new file mode 100644 index 0000000..782911f --- /dev/null +++ b/Public/index.html @@ -0,0 +1,52 @@ + + + + AnP + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Public/json/AnP.settings.json b/Public/json/AnP.settings.json new file mode 100644 index 0000000..0ec5acd --- /dev/null +++ b/Public/json/AnP.settings.json @@ -0,0 +1,28 @@ +{ + "autostart" : true, + "application_name" : "AnP", + "application_link" : "https://anp.k3y.pw/", + "application_git" : "https://git.k3y.pw/KyMAN/AnP", + "application_logo" : "/images/AnP.png", + "default_settings_files" : "/json/AnP.settings.json", + "default_secrets_files" : "/json/AnP.secrets.json", + "default_i18n_files" : [ + "/json/i18n/AnP.i18n.english.json", + "/json/i18n/AnP.i18n.espanol.json", + "/json/i18n/AnP.i18n.galego.json", + "/json/i18n/AnP.i18n.nihongo.json", + "/json/i18n/AnP.i18n.russkiy.json" + ], + "cells" : 40, + "position" : "body", + "build_base_gui" : true, + "cc_by_nc_sa_4_link" : "https://creativecommons.org/licenses/by-nc-sa/4.0/", + "cc_by_nc_sa_4_icon" : "https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png", + "i18n_selector" : [ + ["english", "English", "/images/flags/english.svg"], + ["espanol", "Español", "/images/flags/espanol.svg"], + ["galego", "Galego", "/images/flags/galego.svg"], + ["nihongo", "日本語", "/images/flags/nihongo.svg"], + ["russkiy", "Русский", "/images/flags/russkiy.svg"] + ] +} \ No newline at end of file diff --git a/Public/json/i18n/AnP.i18n.english.json b/Public/json/i18n/AnP.i18n.english.json new file mode 100644 index 0000000..5c0ac7d --- /dev/null +++ b/Public/json/i18n/AnP.i18n.english.json @@ -0,0 +1,19 @@ +{ + "english" : { + "home" : "Home", + "git" : "Git", + "user" : "User", + "ip" : "IP", + "login" : "Login", + "logout" : "Logout", + "register" : "Register", + "copyright" : "© Copyright {years} {authors}", + "cc_by_nc_sa_4" : "CC-BY-NC-SA-4.0: Creative Commons Attribution, Non-Commercial and Share Alike, version 4.0.", + "zoom" : "Zoom", + "reset_zoom" : "Reset Zoom", + "gui_mode" : "GUI Mode", + "aichat" : "AIChat", + "message" : "Message", + "send" : "Send" + } +} \ No newline at end of file diff --git a/Public/json/i18n/AnP.i18n.espanol.json b/Public/json/i18n/AnP.i18n.espanol.json new file mode 100644 index 0000000..ea672c2 --- /dev/null +++ b/Public/json/i18n/AnP.i18n.espanol.json @@ -0,0 +1,19 @@ +{ + "espanol" : { + "home" : "Principal", + "git" : "Git", + "user" : "Usuario", + "ip" : "IP", + "login" : "Acceder", + "logout" : "Salir", + "register" : "Registrarse", + "copyright" : "© Copyright {years} {authors}", + "cc_by_nc_sa_4" : "CC-BY-NC-SA-4.0: Creative Commons de Atribución, No Comercial y Permitido el Compartir, versión 4.0.", + "zoom" : "Zoom", + "reset_zoom" : "Reiniciar Zoom", + "gui_mode" : "Modo del GUI", + "aichat" : "AIChat", + "message" : "Mensaje", + "send" : "Enviar" + } +} \ No newline at end of file diff --git a/Public/json/i18n/AnP.i18n.galego.json b/Public/json/i18n/AnP.i18n.galego.json new file mode 100644 index 0000000..39f43be --- /dev/null +++ b/Public/json/i18n/AnP.i18n.galego.json @@ -0,0 +1,3 @@ +{ + "galego" : {} +} \ No newline at end of file diff --git a/Public/json/i18n/AnP.i18n.nihongo.json b/Public/json/i18n/AnP.i18n.nihongo.json new file mode 100644 index 0000000..eff18c6 --- /dev/null +++ b/Public/json/i18n/AnP.i18n.nihongo.json @@ -0,0 +1,3 @@ +{ + "nihongo" : {} +} \ No newline at end of file diff --git a/Public/json/i18n/AnP.i18n.russkiy.json b/Public/json/i18n/AnP.i18n.russkiy.json new file mode 100644 index 0000000..b765480 --- /dev/null +++ b/Public/json/i18n/AnP.i18n.russkiy.json @@ -0,0 +1,3 @@ +{ + "russkiy" : {} +} \ No newline at end of file diff --git a/Public/json/views/AnP.views.sessions.json b/Public/json/views/AnP.views.sessions.json new file mode 100644 index 0000000..75069c4 --- /dev/null +++ b/Public/json/views/AnP.views.sessions.json @@ -0,0 +1,25 @@ +{ + "login" : { + "type" : "form", + "submit" : "login@sessions", + "structure" : [ + ["username", "text"], + ["password", "password"] + ] + }, + "unloggin" : { + "type" : "form", + "submit" : "logout@sessions", + "structure" : [] + }, + "register" : { + "type" : "form", + "submit" : "register@sessions", + "structure" : [ + ["username", "text"], + ["password", "password"], + ["confirm_password", "password"], + ["email", "email"] + ] + } +} \ No newline at end of file diff --git a/Public/scss/AnP.base.scss b/Public/scss/AnP.base.scss new file mode 100644 index 0000000..814be71 --- /dev/null +++ b/Public/scss/AnP.base.scss @@ -0,0 +1,264 @@ +@mixin main_color_web($mode){ + background-color : map-deep-get($color, $mode, "back"); + color : map-deep-get($color, $mode, "fore"); + a[href],[data-role=link],button,[type=submit],[type=button],[type=reset],[role=button]{ + color : map-deep-get($color, $mode, "primary"); + &:hover{color : map-deep-get($color, $mode, "secondary");} + } + button,[type=submit],[type=button],[type=reset],[role=button]{ + border-color : map-deep-get($color, $mode, "primary"); + box-shadow : 0em 0em .2em inset map-deep-get($color, $mode, "primary"); + &:hover{ + border-color : map-deep-get($color, $mode, "secondary"); + box-shadow : 0em 0em .2em inset map-deep-get($color, $mode, "secondary"); + } + } +} + +.anp{ + + position : relative; + top : 0em; + left : 0em; + width : 100%; + height : 100%; + overflow : hidden; + &,input,textarea,select,button{font-family : $font-normal;} + + button,input,textarea,select{font-size : 1em;} + + a[href]{text-decoration : none;} + a[href],[data-role=link],button,[type=submit],[type=button],[type=reset],[role=button]{ + cursor : pointer; + transition-duration : $transition-out; + transition-property : color; + &:hover{transition-duration : $transition-in;} + } + button,[type=submit],[type=button],[type=reset],[role=button]{ + cursor : pointer; + border-width : .1em; + border-style : solid; + border-radius : $border-radius; + transition-property : color, border-color, box-shadow; + } + .buttons{ + text-align : center; + button{border-radius : 0em;} + &>:first-child{ + border-top-left-radius : $border-radius; + border-bottom-left-radius : $border-radius; + } + &>:last-child{ + border-top-right-radius : $border-radius; + border-bottom-right-radius : $border-radius; + } + } + + header,main,footer{ + position : absolute; + left : 0em; + width : 100%; + } + header{ + display : flex; + align-items : center; + top : 0em; + height : $header-height; + z-index : 20; + } + main{ + top : $header-height; + bottom : $footer-height; + z-index : 10; + } + footer{ + display : flex; + align-items : center; + bottom : 0em; + height : $footer-height; + z-index : 30; + } + + &[data-forced-gui-mode=default][data-gui-mode=default]{ + @include main_color_web(light); + } + @each $key in (dark, light){ + &[data-forced-gui-mode=#{$key}],&[data-forced-gui-mode=default][data-gui-mode=#{$key}]{ + @include main_color_web($key); + } + } + + .input{ + display : inline-block; + position : relative; + width : 100%; + min-width : 0%; + &>textarea{ + width : 100%; + height : 5em; + min-width : 0%; + min-height : 0%; + resize : none; + } + } + + h1{ + flex-grow : 0; + font-size : 1em; + margin : 0em; + white-space : nowrap; + a>*,.image>*{vertical-align : middle;} + img{ + width : auto; + height : .8 * $header-height; + margin-top : .1 * $header-height; + margin-left : 1em + .1 * $header-height; + margin-right : .1 * $header-height; + &+span{display : none;} + } + .text{ + font-size : .8 * $header-height; + font-weight : 900; + } + } + + .top-menu{ + flex-grow : 1; + &>ul{ + margin : 0em; + padding : 0em; + text-align : center; + list-style-type : none; + li{ + display : inline-block; + margin : 0em 1em; + } + } + } + + .sessions-mini{ + flex-grow : 0; + display : relative; + width : 3 * $header-height; + height : 100%; + .image{ + position : absolute; + top : 0em; + right : 0em; + width : $header-height; + height : $header-height; + cursor : pointer; + background-color : $color-grey; + overflow : hidden; + border-radius : 0% 0% 0% 50%; + transition-duration : $transition-out; + transition-property : border-radius; + &:hover{ + border-radius : 0% 0% 0% 10%; + transition-duration : $transition-in; + } + } + img{ + width : auto; + height : 100%; + &+span{display : none;} + } + .info{ + position : absolute; + top : .2em; + right : $header-height + .5em; + margin : 0em; + padding : 0em; + text-align : right; + list-style-type : none; + li{font-size : .85em;} + [data-icon]+[data-i18n]{display : none;} + } + nav{ + position : absolute; + bottom : .5em; + right : $header-height + .5em; + text-align : right; + ul{ + margin : 0em; + padding : 0em; + text-align : center; + list-style-type : none; + li{ + display : inline-block; + margin : 0em .2em; + } + } + [data-icon]{ + &::before{margin : 0em;} + &+[data-i18n]{display : none;} + } + } + } + + .gui-controls{ + flex-grow : 0; + white-space : nowrap; + [data-icon]{ + &::before{margin : 0em;} + &+[data-i18n]{display : none;} + } + } + + .licenses{ + display : flex; + align-items : center; + flex-grow : 1; + &>*{ + margin : 0em .3em; + text-align : center; + font-size : .7em; + font-weight : 900; + } + &>[data-i18n=cc_by_nc_sa_4]{ + display : flex; + align-items : center; + span{flex-grow : 1;} + img{ + flex-grow : 0; + width : auto; + height : $footer-height; + margin : 0em .3em; + } + } + } + + .i18n-selector{ + flex-grow : 0; + width : 10em; + white-space : nowrap; + ul{ + position : absolute; + bottom : 0em; + right : 0em; + margin : 0em; + padding : 0em .3em; + text-align : right; + list-style-type : none; + &:hover li{ + margin-top : 0em; + opacity : 1; + transition-duration : $transition-in; + } + } + li{ + position : relative; + margin-top : -1em - .28em; + transition-duration : $transition-out; + transition-property : margin-top, opacity; + &>*{vertical-align : middle;} + } + [data-selected=false]{opacity : 0;} + img{ + width : auto; + height : 1em; + margin-right : .3em; + } + } + +} \ No newline at end of file diff --git a/Public/scss/AnP.common.scss b/Public/scss/AnP.common.scss new file mode 100644 index 0000000..2af7d1b --- /dev/null +++ b/Public/scss/AnP.common.scss @@ -0,0 +1,19 @@ +// @use "sass:map"; +// @use "sass:list"; +// @use "sass:meta"; + +@function unicode($code){ + @return unquote("\"") + unquote(str-insert($code, "\\", 1)) + unquote("\""); +} + +@function map-deep-get($scope, $keys...){ + + $i : 1; + + @while (type-of($scope) == map) and ($i <= length($keys)){ + $scope : map-get($scope, nth($keys, $i)); + $i : $i + 1; + } + + @return $scope; +} \ No newline at end of file diff --git a/Public/scss/AnP.css b/Public/scss/AnP.css new file mode 100644 index 0000000..f2259c9 --- /dev/null +++ b/Public/scss/AnP.css @@ -0,0 +1,1057 @@ +@font-face { + font-family: "FA6FB"; + font-style: normal; + font-weight: 400; + font-display: block; + src: url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/webfonts/fa-brands-400.woff2") format("woff2"), url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/webfonts/fa-brands-400.ttf") format("truetype"); } +@font-face { + font-family: "FA6FR"; + font-style: normal; + font-weight: 400; + font-display: block; + src: url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/webfonts/fa-regular-400.woff2") format("woff2"), url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/webfonts/fa-regular-400.ttf") format("truetype"); } +@font-face { + font-family: "FA6FS"; + font-style: normal; + font-weight: 900; + font-display: block; + src: url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/webfonts/fa-solid-900.woff2") format("woff2"), url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/webfonts/fa-solid-900.ttf") format("truetype"); } +/* cyrillic-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 100; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEz0dL_nz.woff2") format("woff2"); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } +/* cyrillic */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 100; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEzQdL_nz.woff2") format("woff2"); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } +/* greek-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 100; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEzwdL_nz.woff2") format("woff2"); + unicode-range: U+1F00-1FFF; } +/* greek */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 100; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEzMdL_nz.woff2") format("woff2"); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; } +/* vietnamese */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 100; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEz8dL_nz.woff2") format("woff2"); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; } +/* latin-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 100; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEz4dL_nz.woff2") format("woff2"); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } +/* latin */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 100; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEzAdLw.woff2") format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } +/* cyrillic-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 300; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TjASc3CsTKlA.woff2") format("woff2"); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } +/* cyrillic */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 300; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TjASc-CsTKlA.woff2") format("woff2"); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } +/* greek-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 300; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TjASc2CsTKlA.woff2") format("woff2"); + unicode-range: U+1F00-1FFF; } +/* greek */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 300; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TjASc5CsTKlA.woff2") format("woff2"); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; } +/* vietnamese */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 300; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TjASc1CsTKlA.woff2") format("woff2"); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; } +/* latin-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 300; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TjASc0CsTKlA.woff2") format("woff2"); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } +/* latin */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 300; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TjASc6CsQ.woff2") format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } +/* cyrillic-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1Mu51xFIzIFKw.woff2") format("woff2"); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } +/* cyrillic */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1Mu51xMIzIFKw.woff2") format("woff2"); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } +/* greek-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1Mu51xEIzIFKw.woff2") format("woff2"); + unicode-range: U+1F00-1FFF; } +/* greek */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1Mu51xLIzIFKw.woff2") format("woff2"); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; } +/* vietnamese */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1Mu51xHIzIFKw.woff2") format("woff2"); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; } +/* latin-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1Mu51xGIzIFKw.woff2") format("woff2"); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } +/* latin */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1Mu51xIIzI.woff2") format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } +/* cyrillic-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51S7ACc3CsTKlA.woff2") format("woff2"); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } +/* cyrillic */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51S7ACc-CsTKlA.woff2") format("woff2"); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } +/* greek-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51S7ACc2CsTKlA.woff2") format("woff2"); + unicode-range: U+1F00-1FFF; } +/* greek */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51S7ACc5CsTKlA.woff2") format("woff2"); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; } +/* vietnamese */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51S7ACc1CsTKlA.woff2") format("woff2"); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; } +/* latin-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51S7ACc0CsTKlA.woff2") format("woff2"); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } +/* latin */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51S7ACc6CsQ.woff2") format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } +/* cyrillic-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzBic3CsTKlA.woff2") format("woff2"); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } +/* cyrillic */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzBic-CsTKlA.woff2") format("woff2"); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } +/* greek-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzBic2CsTKlA.woff2") format("woff2"); + unicode-range: U+1F00-1FFF; } +/* greek */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzBic5CsTKlA.woff2") format("woff2"); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; } +/* vietnamese */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzBic1CsTKlA.woff2") format("woff2"); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; } +/* latin-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzBic0CsTKlA.woff2") format("woff2"); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } +/* latin */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzBic6CsQ.woff2") format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } +/* cyrillic-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 900; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TLBCc3CsTKlA.woff2") format("woff2"); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } +/* cyrillic */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 900; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TLBCc-CsTKlA.woff2") format("woff2"); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } +/* greek-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 900; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TLBCc2CsTKlA.woff2") format("woff2"); + unicode-range: U+1F00-1FFF; } +/* greek */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 900; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TLBCc5CsTKlA.woff2") format("woff2"); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; } +/* vietnamese */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 900; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TLBCc1CsTKlA.woff2") format("woff2"); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; } +/* latin-ext */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 900; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TLBCc0CsTKlA.woff2") format("woff2"); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } +/* latin */ +@font-face { + font-family: "Roboto"; + font-style: italic; + font-weight: 900; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TLBCc6CsQ.woff2") format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } +/* cyrillic-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 100; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1MmgVxFIzIFKw.woff2") format("woff2"); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } +/* cyrillic */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 100; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1MmgVxMIzIFKw.woff2") format("woff2"); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } +/* greek-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 100; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1MmgVxEIzIFKw.woff2") format("woff2"); + unicode-range: U+1F00-1FFF; } +/* greek */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 100; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1MmgVxLIzIFKw.woff2") format("woff2"); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; } +/* vietnamese */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 100; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1MmgVxHIzIFKw.woff2") format("woff2"); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; } +/* latin-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 100; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1MmgVxGIzIFKw.woff2") format("woff2"); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } +/* latin */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 100; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1MmgVxIIzI.woff2") format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } +/* cyrillic-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmSU5fCRc4EsA.woff2") format("woff2"); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } +/* cyrillic */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmSU5fABc4EsA.woff2") format("woff2"); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } +/* greek-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmSU5fCBc4EsA.woff2") format("woff2"); + unicode-range: U+1F00-1FFF; } +/* greek */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmSU5fBxc4EsA.woff2") format("woff2"); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; } +/* vietnamese */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmSU5fCxc4EsA.woff2") format("woff2"); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; } +/* latin-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmSU5fChc4EsA.woff2") format("woff2"); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } +/* latin */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmSU5fBBc4.woff2") format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } +/* cyrillic-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu72xKOzY.woff2") format("woff2"); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } +/* cyrillic */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu5mxKOzY.woff2") format("woff2"); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } +/* greek-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu7mxKOzY.woff2") format("woff2"); + unicode-range: U+1F00-1FFF; } +/* greek */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4WxKOzY.woff2") format("woff2"); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; } +/* vietnamese */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu7WxKOzY.woff2") format("woff2"); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; } +/* latin-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu7GxKOzY.woff2") format("woff2"); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } +/* latin */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4mxK.woff2") format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } +/* cyrillic-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fCRc4EsA.woff2") format("woff2"); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } +/* cyrillic */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fABc4EsA.woff2") format("woff2"); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } +/* greek-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fCBc4EsA.woff2") format("woff2"); + unicode-range: U+1F00-1FFF; } +/* greek */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fBxc4EsA.woff2") format("woff2"); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; } +/* vietnamese */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fCxc4EsA.woff2") format("woff2"); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; } +/* latin-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fChc4EsA.woff2") format("woff2"); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } +/* latin */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fBBc4.woff2") format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } +/* cyrillic-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlfCRc4EsA.woff2") format("woff2"); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } +/* cyrillic */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlfABc4EsA.woff2") format("woff2"); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } +/* greek-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlfCBc4EsA.woff2") format("woff2"); + unicode-range: U+1F00-1FFF; } +/* greek */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlfBxc4EsA.woff2") format("woff2"); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; } +/* vietnamese */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlfCxc4EsA.woff2") format("woff2"); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; } +/* latin-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlfChc4EsA.woff2") format("woff2"); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } +/* latin */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlfBBc4.woff2") format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } +/* cyrillic-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 900; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmYUtfCRc4EsA.woff2") format("woff2"); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } +/* cyrillic */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 900; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmYUtfABc4EsA.woff2") format("woff2"); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } +/* greek-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 900; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmYUtfCBc4EsA.woff2") format("woff2"); + unicode-range: U+1F00-1FFF; } +/* greek */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 900; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmYUtfBxc4EsA.woff2") format("woff2"); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; } +/* vietnamese */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 900; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmYUtfCxc4EsA.woff2") format("woff2"); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; } +/* latin-ext */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 900; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmYUtfChc4EsA.woff2") format("woff2"); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } +/* latin */ +@font-face { + font-family: "Roboto"; + font-style: normal; + font-weight: 900; + font-display: swap; + src: url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmYUtfBBc4.woff2") format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } +/* cyrillic-ext */ +@font-face { + font-family: "Roboto Mono"; + font-style: italic; + font-weight: 100 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/robotomono/v23/L0x7DF4xlVMF-BfR8bXMIjhOm3CWWoKC.woff2") format("woff2"); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } +/* cyrillic */ +@font-face { + font-family: "Roboto Mono"; + font-style: italic; + font-weight: 100 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/robotomono/v23/L0x7DF4xlVMF-BfR8bXMIjhOm3mWWoKC.woff2") format("woff2"); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } +/* greek */ +@font-face { + font-family: "Roboto Mono"; + font-style: italic; + font-weight: 100 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/robotomono/v23/L0x7DF4xlVMF-BfR8bXMIjhOm36WWoKC.woff2") format("woff2"); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; } +/* vietnamese */ +@font-face { + font-family: "Roboto Mono"; + font-style: italic; + font-weight: 100 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/robotomono/v23/L0x7DF4xlVMF-BfR8bXMIjhOm3KWWoKC.woff2") format("woff2"); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; } +/* latin-ext */ +@font-face { + font-family: "Roboto Mono"; + font-style: italic; + font-weight: 100 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/robotomono/v23/L0x7DF4xlVMF-BfR8bXMIjhOm3OWWoKC.woff2") format("woff2"); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } +/* latin */ +@font-face { + font-family: "Roboto Mono"; + font-style: italic; + font-weight: 100 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/robotomono/v23/L0x7DF4xlVMF-BfR8bXMIjhOm32WWg.woff2") format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } +/* cyrillic-ext */ +@font-face { + font-family: "Roboto Mono"; + font-style: normal; + font-weight: 100 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/robotomono/v23/L0x5DF4xlVMF-BfR8bXMIjhGq3-OXg.woff2") format("woff2"); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } +/* cyrillic */ +@font-face { + font-family: "Roboto Mono"; + font-style: normal; + font-weight: 100 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/robotomono/v23/L0x5DF4xlVMF-BfR8bXMIjhPq3-OXg.woff2") format("woff2"); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } +/* greek */ +@font-face { + font-family: "Roboto Mono"; + font-style: normal; + font-weight: 100 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/robotomono/v23/L0x5DF4xlVMF-BfR8bXMIjhIq3-OXg.woff2") format("woff2"); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; } +/* vietnamese */ +@font-face { + font-family: "Roboto Mono"; + font-style: normal; + font-weight: 100 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/robotomono/v23/L0x5DF4xlVMF-BfR8bXMIjhEq3-OXg.woff2") format("woff2"); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; } +/* latin-ext */ +@font-face { + font-family: "Roboto Mono"; + font-style: normal; + font-weight: 100 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/robotomono/v23/L0x5DF4xlVMF-BfR8bXMIjhFq3-OXg.woff2") format("woff2"); + unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } +/* latin */ +@font-face { + font-family: "Roboto Mono"; + font-style: normal; + font-weight: 100 700; + font-display: swap; + src: url("https://fonts.gstatic.com/s/robotomono/v23/L0x5DF4xlVMF-BfR8bXMIjhLq38.woff2") format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } +.anp { + position: relative; + top: 0em; + left: 0em; + width: 100%; + height: 100%; + overflow: hidden; } + .anp, .anp input, .anp textarea, .anp select, .anp button { + font-family: "Roboto"; } + .anp button, .anp input, .anp textarea, .anp select { + font-size: 1em; } + .anp a[href] { + text-decoration: none; } + .anp a[href], .anp [data-role=link], .anp button, .anp [type=submit], .anp [type=button], .anp [type=reset], .anp [role=button] { + cursor: pointer; + transition-duration: 1s; + transition-property: color; } + .anp a[href]:hover, .anp [data-role=link]:hover, .anp button:hover, .anp [type=submit]:hover, .anp [type=button]:hover, .anp [type=reset]:hover, .anp [role=button]:hover { + transition-duration: 0.35s; } + .anp button, .anp [type=submit], .anp [type=button], .anp [type=reset], .anp [role=button] { + cursor: pointer; + border-width: .1em; + border-style: solid; + border-radius: 0.3em; + transition-property: color, border-color, box-shadow; } + .anp .buttons { + text-align: center; } + .anp .buttons button { + border-radius: 0em; } + .anp .buttons > :first-child { + border-top-left-radius: 0.3em; + border-bottom-left-radius: 0.3em; } + .anp .buttons > :last-child { + border-top-right-radius: 0.3em; + border-bottom-right-radius: 0.3em; } + .anp header, .anp main, .anp footer { + position: absolute; + left: 0em; + width: 100%; } + .anp header { + display: flex; + align-items: center; + top: 0em; + height: 4em; + z-index: 20; } + .anp main { + top: 4em; + bottom: 2em; + z-index: 10; } + .anp footer { + display: flex; + align-items: center; + bottom: 0em; + height: 2em; + z-index: 30; } + .anp[data-forced-gui-mode=default][data-gui-mode=default] { + background-color: #EFEFEF; + color: #222; } + .anp[data-forced-gui-mode=default][data-gui-mode=default] a[href], .anp[data-forced-gui-mode=default][data-gui-mode=default] [data-role=link], .anp[data-forced-gui-mode=default][data-gui-mode=default] button, .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=submit], .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=button], .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=reset], .anp[data-forced-gui-mode=default][data-gui-mode=default] [role=button] { + color: #2262b0; } + .anp[data-forced-gui-mode=default][data-gui-mode=default] a[href]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [data-role=link]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] button:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=submit]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=reset]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [role=button]:hover { + color: #b06222; } + .anp[data-forced-gui-mode=default][data-gui-mode=default] button, .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=submit], .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=button], .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=reset], .anp[data-forced-gui-mode=default][data-gui-mode=default] [role=button] { + border-color: #2262b0; + box-shadow: 0em 0em 0.2em inset #2262b0; } + .anp[data-forced-gui-mode=default][data-gui-mode=default] button:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=submit]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=reset]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [role=button]:hover { + border-color: #b06222; + box-shadow: 0em 0em 0.2em inset #b06222; } + .anp[data-forced-gui-mode=dark], .anp[data-forced-gui-mode=default][data-gui-mode=dark] { + background-color: #222; + color: #EFEFEF; } + .anp[data-forced-gui-mode=dark] a[href], .anp[data-forced-gui-mode=dark] [data-role=link], .anp[data-forced-gui-mode=dark] button, .anp[data-forced-gui-mode=dark] [type=submit], .anp[data-forced-gui-mode=dark] [type=button], .anp[data-forced-gui-mode=dark] [type=reset], .anp[data-forced-gui-mode=dark] [role=button], .anp[data-forced-gui-mode=default][data-gui-mode=dark] a[href], .anp[data-forced-gui-mode=default][data-gui-mode=dark] [data-role=link], .anp[data-forced-gui-mode=default][data-gui-mode=dark] button, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=submit], .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=button], .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=reset], .anp[data-forced-gui-mode=default][data-gui-mode=dark] [role=button] { + color: #4b8bd9; } + .anp[data-forced-gui-mode=dark] a[href]:hover, .anp[data-forced-gui-mode=dark] [data-role=link]:hover, .anp[data-forced-gui-mode=dark] button:hover, .anp[data-forced-gui-mode=dark] [type=submit]:hover, .anp[data-forced-gui-mode=dark] [type=button]:hover, .anp[data-forced-gui-mode=dark] [type=reset]:hover, .anp[data-forced-gui-mode=dark] [role=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] a[href]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [data-role=link]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] button:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=submit]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=reset]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [role=button]:hover { + color: #d98b4b; } + .anp[data-forced-gui-mode=dark] button, .anp[data-forced-gui-mode=dark] [type=submit], .anp[data-forced-gui-mode=dark] [type=button], .anp[data-forced-gui-mode=dark] [type=reset], .anp[data-forced-gui-mode=dark] [role=button], .anp[data-forced-gui-mode=default][data-gui-mode=dark] button, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=submit], .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=button], .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=reset], .anp[data-forced-gui-mode=default][data-gui-mode=dark] [role=button] { + border-color: #4b8bd9; + box-shadow: 0em 0em 0.2em inset #4b8bd9; } + .anp[data-forced-gui-mode=dark] button:hover, .anp[data-forced-gui-mode=dark] [type=submit]:hover, .anp[data-forced-gui-mode=dark] [type=button]:hover, .anp[data-forced-gui-mode=dark] [type=reset]:hover, .anp[data-forced-gui-mode=dark] [role=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] button:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=submit]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=reset]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [role=button]:hover { + border-color: #d98b4b; + box-shadow: 0em 0em 0.2em inset #d98b4b; } + .anp[data-forced-gui-mode=light], .anp[data-forced-gui-mode=default][data-gui-mode=light] { + background-color: #EFEFEF; + color: #222; } + .anp[data-forced-gui-mode=light] a[href], .anp[data-forced-gui-mode=light] [data-role=link], .anp[data-forced-gui-mode=light] button, .anp[data-forced-gui-mode=light] [type=submit], .anp[data-forced-gui-mode=light] [type=button], .anp[data-forced-gui-mode=light] [type=reset], .anp[data-forced-gui-mode=light] [role=button], .anp[data-forced-gui-mode=default][data-gui-mode=light] a[href], .anp[data-forced-gui-mode=default][data-gui-mode=light] [data-role=link], .anp[data-forced-gui-mode=default][data-gui-mode=light] button, .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=submit], .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=button], .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=reset], .anp[data-forced-gui-mode=default][data-gui-mode=light] [role=button] { + color: #2262b0; } + .anp[data-forced-gui-mode=light] a[href]:hover, .anp[data-forced-gui-mode=light] [data-role=link]:hover, .anp[data-forced-gui-mode=light] button:hover, .anp[data-forced-gui-mode=light] [type=submit]:hover, .anp[data-forced-gui-mode=light] [type=button]:hover, .anp[data-forced-gui-mode=light] [type=reset]:hover, .anp[data-forced-gui-mode=light] [role=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] a[href]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [data-role=link]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] button:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=submit]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=reset]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [role=button]:hover { + color: #b06222; } + .anp[data-forced-gui-mode=light] button, .anp[data-forced-gui-mode=light] [type=submit], .anp[data-forced-gui-mode=light] [type=button], .anp[data-forced-gui-mode=light] [type=reset], .anp[data-forced-gui-mode=light] [role=button], .anp[data-forced-gui-mode=default][data-gui-mode=light] button, .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=submit], .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=button], .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=reset], .anp[data-forced-gui-mode=default][data-gui-mode=light] [role=button] { + border-color: #2262b0; + box-shadow: 0em 0em 0.2em inset #2262b0; } + .anp[data-forced-gui-mode=light] button:hover, .anp[data-forced-gui-mode=light] [type=submit]:hover, .anp[data-forced-gui-mode=light] [type=button]:hover, .anp[data-forced-gui-mode=light] [type=reset]:hover, .anp[data-forced-gui-mode=light] [role=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] button:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=submit]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=reset]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [role=button]:hover { + border-color: #b06222; + box-shadow: 0em 0em 0.2em inset #b06222; } + .anp .input { + display: inline-block; + position: relative; + width: 100%; + min-width: 0%; } + .anp .input > textarea { + width: 100%; + height: 5em; + min-width: 0%; + min-height: 0%; + resize: none; } + .anp h1 { + flex-grow: 0; + font-size: 1em; + margin: 0em; + white-space: nowrap; } + .anp h1 a > *, .anp h1 .image > * { + vertical-align: middle; } + .anp h1 img { + width: auto; + height: 3.2em; + margin-top: 0.4em; + margin-left: 1.4em; + margin-right: 0.4em; } + .anp h1 img + span { + display: none; } + .anp h1 .text { + font-size: 3.2em; + font-weight: 900; } + .anp .top-menu { + flex-grow: 1; } + .anp .top-menu > ul { + margin: 0em; + padding: 0em; + text-align: center; + list-style-type: none; } + .anp .top-menu > ul li { + display: inline-block; + margin: 0em 1em; } + .anp .sessions-mini { + flex-grow: 0; + display: relative; + width: 12em; + height: 100%; } + .anp .sessions-mini .image { + position: absolute; + top: 0em; + right: 0em; + width: 4em; + height: 4em; + cursor: pointer; + background-color: #898989; + overflow: hidden; + border-radius: 0% 0% 0% 50%; + transition-duration: 1s; + transition-property: border-radius; } + .anp .sessions-mini .image:hover { + border-radius: 0% 0% 0% 10%; + transition-duration: 0.35s; } + .anp .sessions-mini img { + width: auto; + height: 100%; } + .anp .sessions-mini img + span { + display: none; } + .anp .sessions-mini .info { + position: absolute; + top: .2em; + right: 4.5em; + margin: 0em; + padding: 0em; + text-align: right; + list-style-type: none; } + .anp .sessions-mini .info li { + font-size: .85em; } + .anp .sessions-mini .info [data-icon] + [data-i18n] { + display: none; } + .anp .sessions-mini nav { + position: absolute; + bottom: .5em; + right: 4.5em; + text-align: right; } + .anp .sessions-mini nav ul { + margin: 0em; + padding: 0em; + text-align: center; + list-style-type: none; } + .anp .sessions-mini nav ul li { + display: inline-block; + margin: 0em .2em; } + .anp .sessions-mini nav [data-icon]::before { + margin: 0em; } + .anp .sessions-mini nav [data-icon] + [data-i18n] { + display: none; } + .anp .gui-controls { + flex-grow: 0; + white-space: nowrap; } + .anp .gui-controls [data-icon]::before { + margin: 0em; } + .anp .gui-controls [data-icon] + [data-i18n] { + display: none; } + .anp .licenses { + display: flex; + align-items: center; + flex-grow: 1; } + .anp .licenses > * { + margin: 0em .3em; + text-align: center; + font-size: .7em; + font-weight: 900; } + .anp .licenses > [data-i18n=cc_by_nc_sa_4] { + display: flex; + align-items: center; } + .anp .licenses > [data-i18n=cc_by_nc_sa_4] span { + flex-grow: 1; } + .anp .licenses > [data-i18n=cc_by_nc_sa_4] img { + flex-grow: 0; + width: auto; + height: 2em; + margin: 0em .3em; } + .anp .i18n-selector { + flex-grow: 0; + width: 10em; + white-space: nowrap; } + .anp .i18n-selector ul { + position: absolute; + bottom: 0em; + right: 0em; + margin: 0em; + padding: 0em .3em; + text-align: right; + list-style-type: none; } + .anp .i18n-selector ul:hover li { + margin-top: 0em; + opacity: 1; + transition-duration: 0.35s; } + .anp .i18n-selector li { + position: relative; + margin-top: -1.28em; + transition-duration: 1s; + transition-property: margin-top, opacity; } + .anp .i18n-selector li > * { + vertical-align: middle; } + .anp .i18n-selector [data-selected=false] { + opacity: 0; } + .anp .i18n-selector img { + width: auto; + height: 1em; + margin-right: .3em; } + +.anp [data-icon]::before { + margin-right: .3em; + font-family: "FA6FS"; } +.anp [data-icon=home]::before { + content: "\f015"; } +.anp [data-icon=git]::before { + content: "\f841"; + font-family: "FA6FB"; } +.anp [data-icon=user]::before { + content: "\f007"; } +.anp [data-icon=ip]::before { + content: "IP"; + font-weight: 900; + font-family: "Roboto"; } +.anp [data-icon=login]::before { + content: "\f090"; } +.anp [data-icon=register]::before { + content: "\f234"; } +.anp [data-icon=logout]::before { + content: "\f08b"; } +.anp [data-icon=zoom]::before { + content: "\f002"; } +.anp [data-icon=reset_zoom]::before { + content: "\f689"; } +.anp [data-icon=gui_mode]::before { + content: "\f043"; } + +/*# sourceMappingURL=AnP.css.map */ diff --git a/Public/scss/AnP.css.map b/Public/scss/AnP.css.map new file mode 100644 index 0000000..176f30f --- /dev/null +++ b/Public/scss/AnP.css.map @@ -0,0 +1,7 @@ +{ +"version": 3, +"mappings": "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", +"sources": ["AnP.fonts.scss","AnP.base.scss","AnP.settings.scss","AnP.common.scss","AnP.icons.scss"], +"names": [], +"file": "AnP.css" +} diff --git a/Public/scss/AnP.fonts.scss b/Public/scss/AnP.fonts.scss new file mode 100644 index 0000000..4c644cf --- /dev/null +++ b/Public/scss/AnP.fonts.scss @@ -0,0 +1,893 @@ +@font-face { + font-family : "FA6FB"; + font-style : normal; + font-weight : 400; + font-display : block; + src : + url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/webfonts/fa-brands-400.woff2") format("woff2"), + url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/webfonts/fa-brands-400.ttf") format("truetype"); +} +@font-face { + font-family : "FA6FR"; + font-style : normal; + font-weight : 400; + font-display : block; + src : + url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/webfonts/fa-regular-400.woff2") format("woff2"), + url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/webfonts/fa-regular-400.ttf") format("truetype"); +} +@font-face { + font-family : "FA6FS"; + font-style : normal; + font-weight : 900; + font-display : block; + src : + url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/webfonts/fa-solid-900.woff2") format("woff2"), + url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/webfonts/fa-solid-900.ttf") format("truetype"); +} + +/* cyrillic-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 100; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEz0dL_nz.woff2") format("woff2"); + unicode-range : U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 100; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEzQdL_nz.woff2") format("woff2"); + unicode-range : U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 100; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEzwdL_nz.woff2") format("woff2"); + unicode-range : U+1F00-1FFF; +} +/* greek */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 100; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEzMdL_nz.woff2") format("woff2"); + unicode-range : U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 100; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEz8dL_nz.woff2") format("woff2"); + unicode-range : U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 100; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEz4dL_nz.woff2") format("woff2"); + unicode-range : U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 100; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOiCnqEu92Fr1Mu51QrEzAdLw.woff2") format("woff2"); + unicode-range : U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 300; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TjASc3CsTKlA.woff2") format("woff2"); + unicode-range : U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 300; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TjASc-CsTKlA.woff2") format("woff2"); + unicode-range : U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 300; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TjASc2CsTKlA.woff2") format("woff2"); + unicode-range : U+1F00-1FFF; +} +/* greek */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 300; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TjASc5CsTKlA.woff2") format("woff2"); + unicode-range : U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 300; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TjASc1CsTKlA.woff2") format("woff2"); + unicode-range : U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 300; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TjASc0CsTKlA.woff2") format("woff2"); + unicode-range : U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 300; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TjASc6CsQ.woff2") format("woff2"); + unicode-range : U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 400; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1Mu51xFIzIFKw.woff2") format("woff2"); + unicode-range : U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 400; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1Mu51xMIzIFKw.woff2") format("woff2"); + unicode-range : U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 400; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1Mu51xEIzIFKw.woff2") format("woff2"); + unicode-range : U+1F00-1FFF; +} +/* greek */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 400; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1Mu51xLIzIFKw.woff2") format("woff2"); + unicode-range : U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 400; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1Mu51xHIzIFKw.woff2") format("woff2"); + unicode-range : U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 400; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1Mu51xGIzIFKw.woff2") format("woff2"); + unicode-range : U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 400; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1Mu51xIIzI.woff2") format("woff2"); + unicode-range : U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 500; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51S7ACc3CsTKlA.woff2") format("woff2"); + unicode-range : U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 500; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51S7ACc-CsTKlA.woff2") format("woff2"); + unicode-range : U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 500; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51S7ACc2CsTKlA.woff2") format("woff2"); + unicode-range : U+1F00-1FFF; +} +/* greek */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 500; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51S7ACc5CsTKlA.woff2") format("woff2"); + unicode-range : U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 500; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51S7ACc1CsTKlA.woff2") format("woff2"); + unicode-range : U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 500; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51S7ACc0CsTKlA.woff2") format("woff2"); + unicode-range : U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 500; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51S7ACc6CsQ.woff2") format("woff2"); + unicode-range : U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzBic3CsTKlA.woff2") format("woff2"); + unicode-range : U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzBic-CsTKlA.woff2") format("woff2"); + unicode-range : U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzBic2CsTKlA.woff2") format("woff2"); + unicode-range : U+1F00-1FFF; +} +/* greek */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzBic5CsTKlA.woff2") format("woff2"); + unicode-range : U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzBic1CsTKlA.woff2") format("woff2"); + unicode-range : U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzBic0CsTKlA.woff2") format("woff2"); + unicode-range : U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzBic6CsQ.woff2") format("woff2"); + unicode-range : U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 900; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TLBCc3CsTKlA.woff2") format("woff2"); + unicode-range : U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 900; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TLBCc-CsTKlA.woff2") format("woff2"); + unicode-range : U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 900; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TLBCc2CsTKlA.woff2") format("woff2"); + unicode-range : U+1F00-1FFF; +} +/* greek */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 900; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TLBCc5CsTKlA.woff2") format("woff2"); + unicode-range : U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 900; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TLBCc1CsTKlA.woff2") format("woff2"); + unicode-range : U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 900; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TLBCc0CsTKlA.woff2") format("woff2"); + unicode-range : U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face{ + font-family : "Roboto"; + font-style : italic; + font-weight : 900; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TLBCc6CsQ.woff2") format("woff2"); + unicode-range : U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 100; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1MmgVxFIzIFKw.woff2") format("woff2"); + unicode-range : U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 100; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1MmgVxMIzIFKw.woff2") format("woff2"); + unicode-range : U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 100; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1MmgVxEIzIFKw.woff2") format("woff2"); + unicode-range : U+1F00-1FFF; +} +/* greek */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 100; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1MmgVxLIzIFKw.woff2") format("woff2"); + unicode-range : U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 100; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1MmgVxHIzIFKw.woff2") format("woff2"); + unicode-range : U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 100; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1MmgVxGIzIFKw.woff2") format("woff2"); + unicode-range : U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 100; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1MmgVxIIzI.woff2") format("woff2"); + unicode-range : U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 300; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmSU5fCRc4EsA.woff2") format("woff2"); + unicode-range : U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 300; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmSU5fABc4EsA.woff2") format("woff2"); + unicode-range : U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 300; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmSU5fCBc4EsA.woff2") format("woff2"); + unicode-range : U+1F00-1FFF; +} +/* greek */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 300; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmSU5fBxc4EsA.woff2") format("woff2"); + unicode-range : U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 300; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmSU5fCxc4EsA.woff2") format("woff2"); + unicode-range : U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 300; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmSU5fChc4EsA.woff2") format("woff2"); + unicode-range : U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 300; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmSU5fBBc4.woff2") format("woff2"); + unicode-range : U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 400; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu72xKOzY.woff2") format("woff2"); + unicode-range : U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 400; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu5mxKOzY.woff2") format("woff2"); + unicode-range : U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 400; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu7mxKOzY.woff2") format("woff2"); + unicode-range : U+1F00-1FFF; +} +/* greek */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 400; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4WxKOzY.woff2") format("woff2"); + unicode-range : U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 400; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu7WxKOzY.woff2") format("woff2"); + unicode-range : U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 400; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu7GxKOzY.woff2") format("woff2"); + unicode-range : U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 400; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4mxK.woff2") format("woff2"); + unicode-range : U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 500; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fCRc4EsA.woff2") format("woff2"); + unicode-range : U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 500; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fABc4EsA.woff2") format("woff2"); + unicode-range : U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 500; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fCBc4EsA.woff2") format("woff2"); + unicode-range : U+1F00-1FFF; +} +/* greek */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 500; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fBxc4EsA.woff2") format("woff2"); + unicode-range : U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 500; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fCxc4EsA.woff2") format("woff2"); + unicode-range : U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 500; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fChc4EsA.woff2") format("woff2"); + unicode-range : U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 500; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fBBc4.woff2") format("woff2"); + unicode-range : U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlfCRc4EsA.woff2") format("woff2"); + unicode-range : U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlfABc4EsA.woff2") format("woff2"); + unicode-range : U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlfCBc4EsA.woff2") format("woff2"); + unicode-range : U+1F00-1FFF; +} +/* greek */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlfBxc4EsA.woff2") format("woff2"); + unicode-range : U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlfCxc4EsA.woff2") format("woff2"); + unicode-range : U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlfChc4EsA.woff2") format("woff2"); + unicode-range : U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlfBBc4.woff2") format("woff2"); + unicode-range : U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 900; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmYUtfCRc4EsA.woff2") format("woff2"); + unicode-range : U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 900; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmYUtfABc4EsA.woff2") format("woff2"); + unicode-range : U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 900; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmYUtfCBc4EsA.woff2") format("woff2"); + unicode-range : U+1F00-1FFF; +} +/* greek */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 900; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmYUtfBxc4EsA.woff2") format("woff2"); + unicode-range : U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 900; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmYUtfCxc4EsA.woff2") format("woff2"); + unicode-range : U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 900; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmYUtfChc4EsA.woff2") format("woff2"); + unicode-range : U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face{ + font-family : "Roboto"; + font-style : normal; + font-weight : 900; + font-display : swap; + src : url("https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmYUtfBBc4.woff2") format("woff2"); + unicode-range : U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* cyrillic-ext */ +@font-face{ + font-family : "Roboto Mono"; + font-style : italic; + font-weight : 100 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/robotomono/v23/L0x7DF4xlVMF-BfR8bXMIjhOm3CWWoKC.woff2") format("woff2"); + unicode-range : U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face{ + font-family : "Roboto Mono"; + font-style : italic; + font-weight : 100 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/robotomono/v23/L0x7DF4xlVMF-BfR8bXMIjhOm3mWWoKC.woff2") format("woff2"); + unicode-range : U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek */ +@font-face{ + font-family : "Roboto Mono"; + font-style : italic; + font-weight : 100 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/robotomono/v23/L0x7DF4xlVMF-BfR8bXMIjhOm36WWoKC.woff2") format("woff2"); + unicode-range : U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face{ + font-family : "Roboto Mono"; + font-style : italic; + font-weight : 100 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/robotomono/v23/L0x7DF4xlVMF-BfR8bXMIjhOm3KWWoKC.woff2") format("woff2"); + unicode-range : U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face{ + font-family : "Roboto Mono"; + font-style : italic; + font-weight : 100 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/robotomono/v23/L0x7DF4xlVMF-BfR8bXMIjhOm3OWWoKC.woff2") format("woff2"); + unicode-range : U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face{ + font-family : "Roboto Mono"; + font-style : italic; + font-weight : 100 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/robotomono/v23/L0x7DF4xlVMF-BfR8bXMIjhOm32WWg.woff2") format("woff2"); + unicode-range : U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face{ + font-family : "Roboto Mono"; + font-style : normal; + font-weight : 100 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/robotomono/v23/L0x5DF4xlVMF-BfR8bXMIjhGq3-OXg.woff2") format("woff2"); + unicode-range : U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face{ + font-family : "Roboto Mono"; + font-style : normal; + font-weight : 100 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/robotomono/v23/L0x5DF4xlVMF-BfR8bXMIjhPq3-OXg.woff2") format("woff2"); + unicode-range : U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek */ +@font-face{ + font-family : "Roboto Mono"; + font-style : normal; + font-weight : 100 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/robotomono/v23/L0x5DF4xlVMF-BfR8bXMIjhIq3-OXg.woff2") format("woff2"); + unicode-range : U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face{ + font-family : "Roboto Mono"; + font-style : normal; + font-weight : 100 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/robotomono/v23/L0x5DF4xlVMF-BfR8bXMIjhEq3-OXg.woff2") format("woff2"); + unicode-range : U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face{ + font-family : "Roboto Mono"; + font-style : normal; + font-weight : 100 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/robotomono/v23/L0x5DF4xlVMF-BfR8bXMIjhFq3-OXg.woff2") format("woff2"); + unicode-range : U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face{ + font-family : "Roboto Mono"; + font-style : normal; + font-weight : 100 700; + font-display : swap; + src : url("https://fonts.gstatic.com/s/robotomono/v23/L0x5DF4xlVMF-BfR8bXMIjhLq38.woff2") format("woff2"); + unicode-range : U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} \ No newline at end of file diff --git a/Public/scss/AnP.icons.scss b/Public/scss/AnP.icons.scss new file mode 100644 index 0000000..28b34cb --- /dev/null +++ b/Public/scss/AnP.icons.scss @@ -0,0 +1,16 @@ +.anp{ + [data-icon]::before{ + margin-right : .3em; + font-family : $font-icon; + } + [data-icon=home]::before{content : unicode("f015");} + [data-icon=git]::before{content : unicode("f841"); font-family : "FA6FB";} + [data-icon=user]::before{content : unicode("f007");} + [data-icon=ip]::before{content : "IP"; font-weight : 900; font-family : $font-normal;} + [data-icon=login]::before{content : unicode("f090");} + [data-icon=register]::before{content : unicode("f234");} + [data-icon=logout]::before{content : unicode("f08b");} + [data-icon=zoom]::before{content : unicode("f002");} + [data-icon=reset_zoom]::before{content : unicode("f689");} + [data-icon=gui_mode]::before{content : unicode("f043");} +} \ No newline at end of file diff --git a/Public/scss/AnP.scss b/Public/scss/AnP.scss new file mode 100644 index 0000000..7353f1d --- /dev/null +++ b/Public/scss/AnP.scss @@ -0,0 +1 @@ +@import "AnP.fonts.scss", "AnP.settings.scss", "AnP.common.scss", "AnP.base.scss", "AnP.icons.scss"; \ No newline at end of file diff --git a/Public/scss/AnP.settings.scss b/Public/scss/AnP.settings.scss new file mode 100644 index 0000000..2874dd7 --- /dev/null +++ b/Public/scss/AnP.settings.scss @@ -0,0 +1,47 @@ +// Colors +$color-fore : #222; +$color-back : #EFEFEF; +$color-primary : #2272D4; +$color-secondary : #D47222; +$color-full-fore : #000; +$color-full-back : #FFF; +$color-grey : mix($color-fore, $color-back, 50%); +$color : ( + light : ( + fore : $color-fore, + back : $color-back, + primary : mix($color-primary, $color-fore, 80%), + secondary : mix($color-secondary, $color-fore, 80%), + full : $color-full-back, + input-back : mix($color-back, $color-full-back, 80%), + transparent : rgba(255, 255, 255, 0) + ), + dark : ( + fore : $color-back, + back : $color-fore, + primary : mix($color-primary, $color-back, 80%), + secondary : mix($color-secondary, $color-back, 80%), + full : $color-full-fore, + input-back : mix($color-back, $color-full-fore, 80%), + transparent : rgba(0, 0, 0, 0) + ) +); + +// Sizes +$header-height : 4em; +$footer-height : 2em; +$border-radius : .3em; +$margin : .5em; + +// Fonts +// $font-normal : Arial, Helvetica, Sans; +// $font-mono : Consolas, "Courier New", Courier, monospace; +// $font-icon : Arial, Helvetica, Sans; +$font-normal : "Roboto"; +$font-mono : "Roboto Mono"; +$font-icon : "FA6FS"; + +// Transitions +$transition-in : .35s; +$transition-out : 1s; +$transition : .5s; \ No newline at end of file diff --git a/Python/Abstracts/ControllerAbstract.py b/Python/Abstracts/ControllerAbstract.py new file mode 100644 index 0000000..286993f --- /dev/null +++ b/Python/Abstracts/ControllerAbstract.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Self, Any, Optional, Sequence +from Interfaces.Application.AnPInterface import AnPInterface +from Abstracts.ModelAbstract import ModelAbstract + +class ControllerAbstract(ModelAbstract): + + def __init__(self:Self, + anp:AnPInterface, + inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None + ) -> None: + self.anp:AnPInterface = anp \ No newline at end of file diff --git a/Python/Abstracts/DispatchAbstract.py b/Python/Abstracts/DispatchAbstract.py new file mode 100644 index 0000000..c3c31b4 --- /dev/null +++ b/Python/Abstracts/DispatchAbstract.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Self, Any, Optional, Sequence +from Interfaces.Application.AnPInterface import AnPInterface +from Abstracts.ModelAbstract import ModelAbstract + +class DispatchAbstract(ModelAbstract): + + def __init__(self:Self, + anp:AnPInterface, + inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None + ) -> None: + self.anp:AnPInterface = anp \ No newline at end of file diff --git a/Python/Abstracts/ModelAbstract.py b/Python/Abstracts/ModelAbstract.py new file mode 100644 index 0000000..73ba56f --- /dev/null +++ b/Python/Abstracts/ModelAbstract.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +class ModelAbstract:pass \ No newline at end of file diff --git a/Python/Abstracts/RouteAbstract.py b/Python/Abstracts/RouteAbstract.py new file mode 100644 index 0000000..b944b42 --- /dev/null +++ b/Python/Abstracts/RouteAbstract.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +class RouteAbstract:pass \ No newline at end of file diff --git a/Python/Application/AnP.py b/Python/Application/AnP.py new file mode 100644 index 0000000..beeee7b --- /dev/null +++ b/Python/Application/AnP.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Self, Any, Optional, Sequence +import datetime +from re import Match as REMatch +from traceback import extract_tb as extract_traceback, format_stack as trace_format_stack +from Managers.I18NManager import I18NManager +from Managers.SettingsManager import SettingsManager +from Managers.PrintTypesManager import PrintTypesManager +from Managers.TerminalManager import TerminalManager +from Managers.ModelsManager import ModelsManager +from Managers.ControllersManager import ControllersManager +from Managers.DispatchesManager import DispatchesManager +from Managers.IndexesManager import IndexesManager +from Managers.RoutesManager import RoutesManager +from Drivers.HTTPDriver import HTTPDriver +from Utils.Common import Common +from Utils.Patterns import RE + +class AnP: + + def __own_update(self:Self) -> None: + self.__end_print_types = [ + print_type.upper() for print_type in Common.get_keys(self.settings.get("end_print_types", None, self.__end_print_types)) + ] + self.__root_projects_paths = Common.get_texts(self.settings.get("root_projects_paths", None, self.__root_projects_paths)) + self.__print_format = self.settings.get("print_format", None, self.__print_format) + self.__exception_format = self.settings.get("exception_format", None, self.__exception_format) + + def __init__(self:Self, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None: + + self.__working:bool = True + self.settings:SettingsManager = SettingsManager(self, inputs) + self.i18n:I18NManager = I18NManager(self) + self.print_types:PrintTypesManager = PrintTypesManager(self) + self.__end_print_types:list[str] = ["UNKN", "EXCE", "ERRO"] + self.__root_projects_paths:list[str] = [] + self.__print_format:str = "[{type}] {yyyy}{mm}{dd} {hh}{ii}{ss} [{line}]{file}({method}): {message}" + self.__exception_format:str = " '[{line}]{file}({method})'{lines}\n\n{exception_message}" + self.__own_update() + self.terminal:TerminalManager = TerminalManager(self) + self.models:ModelsManager = ModelsManager(self) + self.controllers:ControllersManager = ControllersManager(self) + self.dispatches:DispatchesManager = DispatchesManager(self) + self.indexes:IndexesManager = IndexesManager(self) + self.routes:RoutesManager = RoutesManager(self) + self.http_server:HTTPDriver = HTTPDriver(self) + + def update(self:Self) -> None: + self.settings.update() + self.i18n.update() + self.print_types.update() + self.__own_update() + self.terminal.update() + self.models.update() + self.controllers.update() + self.dispatches.update() + self.indexes.update() + self.routes.update() + self.http_server.update() + + def reset(self:Self) -> None: + self.settings.reset() + self.i18n.reset() + self.print_types.reset() + self.__own_update() + self.terminal.reset() + self.models.reset() + self.controllers.reset() + self.dispatches.reset() + self.indexes.reset() + self.routes.reset() + self.http_server.reset() + + def close(self:Self) -> None: + self.__working = False + self.http_server.close() + + def working(self:Self) -> bool: + return self.__working + + def print(self:Self, + _type:str, + message:str|Sequence[str], + inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None, + i:int = 0 + ) -> None: + + date:datetime.datetime = datetime.datetime.now() + own:dict[str, Any] = { + "raw_type" : _type, + "type": self.print_types.get(_type), + "message": self.i18n.get(message, inputs), + **Common.get_dictionary(inputs), + **Common.get_action_data(i + 1) + } + + for key in ("year", "month", "day", "hour", "minute", "second"): + + k:str = "i" if key == "minute" else key[0] + + own[k] = own[key] = getattr(date, key) + own[k + k] = ("00" + str(own[key]))[-2:] + + own["yyyy"] = ("0000" + str(own["year"]))[-4:] + + for root_path in self.__root_projects_paths: + if own["file"].startswith(root_path): + own["file"] = own["file"][len(root_path):] + break + + if any(own["type"].startswith(end_type) for end_type in self.__end_print_types) and "end" in own: + own["message"] += own["end"] + + print(Common.string_variables(self.__print_format, own)) + + def exception(self:Self, + exception:Exception, + message:str|Sequence[str], + inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None, + i:int = 0 + ) -> None: + + lines:list[str] = extract_traceback(exception.__traceback__).format() + matches:REMatch = RE.EXCEPTION.match(lines[-1]) + data:dict[str, Any|None] = { + **Common.get_dictionary(inputs), + "lines" : "", + "exception_message" : str(exception), + "method" : matches.group(3), + "line" : matches.group(2), + "file" : matches.group(1) + } + block:str + j:int + + for root_path in self.__root_projects_paths: + if data["file"] and data["file"].startswith(root_path): + data["file"] = data["file"][len(root_path):] + + for j, block in enumerate(trace_format_stack()[:-2] + lines): + if block: + data["lines"] += "\n " + str(j) + " - " + RE.NEW_LINE.split(block.strip())[0] + + data["end"] = Common.string_variables(self.__exception_format, data) + + message and self.print("exception", message, data, i + 2) \ No newline at end of file diff --git a/Python/Application/Event.py b/Python/Application/Event.py new file mode 100644 index 0000000..195be72 --- /dev/null +++ b/Python/Application/Event.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Self, Callable, Any, Optional + +class Event: + + def __init__(self:Self) -> None: + self.__events:dict[int, Callable[[Optional[Any]], Any|None]] = {} + + def execute(self:Self, *inputs:Any|None) -> None: + + results:dict[int, Any|None] = {} + + for i, event in self.__events.items(): + results[i] = event(*inputs) + + return results + + def add(self:Self, event:Callable[[Optional[Any]], Any|None]) -> int: + + i:int = 0 + l:int = len(self.__events) + + while i < l: + if i not in self.__events: + break + i += 1 + + self.__events[i] = event + + return i + + def remove(self:Self, i:int) -> None: + if i in self.__events: + del self.__events[i] \ No newline at end of file diff --git a/Python/Controllers/AIController.py b/Python/Controllers/AIController.py new file mode 100644 index 0000000..8b70f90 --- /dev/null +++ b/Python/Controllers/AIController.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Self +from Abstracts.ModelAbstract import ModelAbstract +from Interfaces.Application.AnPInterface import AnPInterface +from Models.RequestModel import RequestModel + +class AIController(ModelAbstract): + + def __init__(self:Self, anp:AnPInterface) -> None: + self.anp: AnPInterface = anp + + def new_message(self:Self, request:RequestModel) -> None: + pass \ No newline at end of file diff --git a/Python/Drivers/HTTPDriver.py b/Python/Drivers/HTTPDriver.py new file mode 100644 index 0000000..141d245 --- /dev/null +++ b/Python/Drivers/HTTPDriver.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Optional, Self, Sequence +from Interfaces.Application.AnPInterface import AnPInterface +from Models.RequestModel import RequestModel +from Utils.Common import Common +from threading import Thread +from http.server import BaseHTTPRequestHandler, HTTPServer + +class HTTPDriver: + + class HTTPRequestHandler(BaseHTTPRequestHandler): + + def __process(self:Self, method:str) -> None: + + anp:AnPInterface = self.server.anp + request:RequestModel = RequestModel() + + request.method = method + request.path = self.path + request.headers = dict(self.headers) + request.client_host = self.client_address[0] + request.client_port = self.client_address[1] + + anp.routes.go(method, self.path, request) + + self.send_response(request.response_code) + self.send_header("Content-Type", request.response_mime) + self.send_header("Content-Length", str(len(request.response))) + self.end_headers() + + self.wfile.write( + request.response.encode() if isinstance(request.response, str) else + request.response) + + def do_GET(self:Self) -> None: + self.__process("get") + + def do_POST(self:Self) -> None: + self.__process("post") + + def do_PUT(self:Self) -> None: + self.__process("put") + + def do_DELETE(self:Self) -> None: + self.__process("delete") + + def do_PATCH(self:Self) -> None: + self.__process("patch") + + def do_HEAD(self:Self) -> None: + self.__process("head") + + def do_OPTIONS(self:Self) -> None: + self.__process("options") + + def do_CONNECT(self:Self) -> None: + self.__process("connect") + + def do_TRACE(self:Self) -> None: + self.__process("trace") + + def do_COPY(self:Self) -> None: + self.__process("copy") + + def do_MOVE(self:Self) -> None: + self.__process("move") + + def do_PROPFIND(self:Self) -> None: + self.__process("propfind") + + def do_PROPPATCH(self:Self) -> None: + self.__process("proppatch") + + def do_LOCK(self:Self) -> None: + self.__process("lock") + + def do_UNLOCK(self:Self) -> None: + self.__process("unlock") + + def do_REPORT(self:Self) -> None: + self.__process("report") + + def do_MKCOL(self:Self) -> None: + self.__process("mkcol") + + def __init__(self:Self, + anp:AnPInterface, + inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None + ) -> None: + + self.anp:AnPInterface = anp + self.__inputs:dict[str, Any|None] = Common.get_dictionary(inputs) + self.__port:int = 8000 + self.__host:str = "" + self.__server:HTTPServer|None = None + self.__thread:Thread|None = None + + self.update() + + def start(self:Self) -> None: + if self.__server is None: + self.__thread = Thread(target = self.__run_service) + self.__thread.start() + + def close(self:Self) -> None: + if self.__server is not None: + self.__server.shutdown() + self.__server = None + + def update(self:Self) -> None: + + self.close() + + self.__port = self.anp.settings.get(("http_server_port", "http_port", "port"), self.__inputs, self.__port) + self.__host = self.anp.settings.get(("http_server_host", "http_host", "host"), self.__inputs, self.__host) + + self.start() + + def reset(self:Self) -> None: + + self.__port = 8000 + self.__host = "" + + self.update() + + def __run_service(self:Self) -> None: + self.__server = HTTPServer((self.__host, self.__port), self.HTTPRequestHandler) + self.__server.anp = self.anp + self.__server.serve_forever() \ No newline at end of file diff --git a/Python/Drivers/OllamaDriver.py b/Python/Drivers/OllamaDriver.py new file mode 100644 index 0000000..08cba74 --- /dev/null +++ b/Python/Drivers/OllamaDriver.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Optional, Self, Sequence +from Interfaces.Application.AnPInterface import AnPInterface + + +class OllamaDriver: + + def __init__(self:Self, + anp:AnPInterface, + inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None + ) -> None: + self.anp:AnPInterface = anp \ No newline at end of file diff --git a/Python/Drivers/WebSocketServerDriver.py b/Python/Drivers/WebSocketServerDriver.py new file mode 100644 index 0000000..bf9c8ea --- /dev/null +++ b/Python/Drivers/WebSocketServerDriver.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Self, Sequence, Optional +from websockets.sync.server import serve as server_serve +from websockets import ServerConnection as WebSocketServer, ClientConnection as WebSocketClient +from Application.Event import Event +from Interfaces.Application.AnPInterface import AnPInterface + +class WebSocketServerDriver: + + def __init__(self:Self, anp:AnPInterface, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None: + + self.anp:AnPInterface = anp + self.on_new_client:Event = Event() + self.on_message:Event = Event() + self.on_close:Event = Event() + self.on_error:Event = Event() + self.__server:WebSocketServer + self.__clients:dict[str, WebSocketClient] = {} + self.__host:str = anp.settings.get(("web_socket_server_host", "host"), inputs, "") + self.__port:int = anp.settings.get(("web_socket_server_port", "port"), inputs, 8765) + + with server_serve(self.__handler, self.__host, self.__port) as self.__server: + self.__server.serve_forever() + + def close(self:Self) -> None: + + id:str + + for id in tuple(self.__clients.keys()): + self.close_client(id) + + self.__server.close() + + def close_client(self:Self, id:str, show_exception:bool = True) -> None: + if id in self.__clients: + try: + self.__clients[id].close() + except Exception as exception: + show_exception and self.anp.exception(exception, "web_socket_server_client_close_exception", { + "client": id, + "port": self.__port, + "host": self.__host + }) + del self.__clients[id] + + def __handler(self:Self, client:WebSocketClient) -> None: + + id:str = str(id(client)) + self.__clients[id] = client + self.on_new_client.execute(client, id) + + self.anp.print("info", "web_socket_server_client_connected", { + "client": id, + "port": self.__port, + "host": self.__host, + "client_host" : client.remote_address[0], + "client_port" : client.remote_address[1] + }) + + try: + while self.anp.working(): + message:str = client.recv() + if message is None: + break + self.on_message.execute(client, message) + except Exception as exception: + self.anp.exception(exception, "web_socket_server_client_exception", { + "client": id, + "port": self.__port, + "host": self.__host + }) + self.on_error.execute(client, exception) + finally: + self.close_client(id, False) + self.on_close.execute(client) + self.anp.print("info", "web_socket_server_client_disconnected", { + "client": id, + "port": self.__port, + "host": self.__host + }) \ No newline at end of file diff --git a/Python/Interfaces/Application/AnPInterface.py b/Python/Interfaces/Application/AnPInterface.py new file mode 100644 index 0000000..09bd8ff --- /dev/null +++ b/Python/Interfaces/Application/AnPInterface.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Optional, Sequence, Self +from abc import ABC, abstractmethod +from Interfaces.Managers.SettingsManagerInterface import SettingsManagerInterface +from Interfaces.Managers.I18NManagerInterface import I18NManagerInterface +from Interfaces.Managers.PrintTypesManagerInterface import PrintTypesManagerInterface +from Interfaces.Managers.TerminalManagerInterface import TerminalManagerInterface +from Interfaces.Managers.ModelsManagerInterface import ModelsManagerInterface +from Interfaces.Managers.ControllersManagerInterface import ControllersManagerInterface +from Interfaces.Managers.DispatchesManagerInterface import DispatchesManagerInterface +from Interfaces.Managers.IndexesManagerInterface import IndexesManagerInterface +from Interfaces.Managers.RoutesManagerInterface import RoutesManagerInterface + +class AnPInterface(ABC): + + def __init__(self:Self, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None: + self.settings:SettingsManagerInterface = None + self.i18n:I18NManagerInterface = None + self.print_types:PrintTypesManagerInterface = None + self.terminal:TerminalManagerInterface = None + self.models:ModelsManagerInterface = None + self.controllers:ControllersManagerInterface = None + self.dispatches:DispatchesManagerInterface = None + self.indexes:IndexesManagerInterface = None + self.routes:RoutesManagerInterface = None + + @abstractmethod + def update(self:Self) -> None:pass + + @abstractmethod + def reset(self:Self) -> None:pass + + @abstractmethod + def close(self:Self) -> None:pass + + @abstractmethod + def working(self:Self) -> bool:pass + + @abstractmethod + def print(self:Self, + _type:str, + message:str|Sequence[str], + inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None, + i:int = 0 + ) -> None:pass + + @abstractmethod + def exception(self:Self, + exception:Exception, + message:str|Sequence[str], + inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None, + i:int = 0 + ) -> None:pass \ No newline at end of file diff --git a/Python/Interfaces/Managers/ControllersManagerInterface.py b/Python/Interfaces/Managers/ControllersManagerInterface.py new file mode 100644 index 0000000..7e3dc81 --- /dev/null +++ b/Python/Interfaces/Managers/ControllersManagerInterface.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Self +from abc import ABC, abstractmethod +from Models.RequestModel import RequestModel + +class ControllersManagerInterface(ABC): + + @abstractmethod + def update(self:Self) -> None:pass + + @abstractmethod + def reset(self:Self) -> None:pass + + @abstractmethod + def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:pass + + @abstractmethod + def execute(self:Self, key:str, method:str, request:RequestModel) -> bool:pass \ No newline at end of file diff --git a/Python/Interfaces/Managers/DispatchesManagerInterface.py b/Python/Interfaces/Managers/DispatchesManagerInterface.py new file mode 100644 index 0000000..d6338df --- /dev/null +++ b/Python/Interfaces/Managers/DispatchesManagerInterface.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Self +from abc import ABC, abstractmethod + +class DispatchesManagerInterface(ABC): + + @abstractmethod + def update(self:Self) -> None:pass + + @abstractmethod + def reset(self:Self) -> None:pass + + @abstractmethod + def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:pass + + @abstractmethod + def execute(self:Self, key:str, method:str, *arguments:list[Any|None]) -> bool:pass \ No newline at end of file diff --git a/Python/Interfaces/Managers/I18NManagerInterface.py b/Python/Interfaces/Managers/I18NManagerInterface.py new file mode 100644 index 0000000..671686a --- /dev/null +++ b/Python/Interfaces/Managers/I18NManagerInterface.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Optional, Self, Sequence +from abc import ABC, abstractmethod + +class I18NManagerInterface(ABC): + + @abstractmethod + def update(self:Self) -> None:pass + + @abstractmethod + def reset(self:Self) -> None:pass + + @abstractmethod + def get(self:Self, + keys:str|Sequence[str], + inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None, + custom_language:Optional[Any] = None + ) -> Any|None:pass + + @abstractmethod + def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:pass \ No newline at end of file diff --git a/Python/Interfaces/Managers/IndexesManagerInterface.py b/Python/Interfaces/Managers/IndexesManagerInterface.py new file mode 100644 index 0000000..b0db3e0 --- /dev/null +++ b/Python/Interfaces/Managers/IndexesManagerInterface.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Self, Any +from abc import ABC, abstractmethod + +class IndexesManagerInterface(ABC): + + @abstractmethod + def update(self:Self) -> None:pass + + @abstractmethod + def reset(self:Self) -> None:pass + + @abstractmethod + def add(self:Self, inputs:Any|None) -> None:pass + + @abstractmethod + def get(self:Self) -> list[str]:pass \ No newline at end of file diff --git a/Python/Interfaces/Managers/ModelsManagerInterface.py b/Python/Interfaces/Managers/ModelsManagerInterface.py new file mode 100644 index 0000000..6f5c82d --- /dev/null +++ b/Python/Interfaces/Managers/ModelsManagerInterface.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Self, Any, Sequence, TypeVar +from abc import ABC, abstractmethod + +T = TypeVar("T") + +class ModelsManagerInterface(ABC): + + @abstractmethod + def update(self:Self) -> None:pass + + @abstractmethod + def reset(self:Self) -> None:pass + + @abstractmethod + def get(self:Self, Type:type[T], keys:str|Sequence[str]) -> T|None:pass + + @abstractmethod + def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:pass \ No newline at end of file diff --git a/Python/Interfaces/Managers/PrintTypesManagerInterface.py b/Python/Interfaces/Managers/PrintTypesManagerInterface.py new file mode 100644 index 0000000..e376177 --- /dev/null +++ b/Python/Interfaces/Managers/PrintTypesManagerInterface.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Self, Sequence +from abc import ABC, abstractmethod + +class PrintTypesManagerInterface(ABC): + + @abstractmethod + def update(self:Self) -> None:pass + + @abstractmethod + def reset(self:Self) -> None:pass + + @abstractmethod + def get(self:Self, keys:str|Sequence[str]) -> str:pass + + @abstractmethod + def add(self:Self, inputs:Any|None) -> None:pass \ No newline at end of file diff --git a/Python/Interfaces/Managers/RoutesManagerInterface.py b/Python/Interfaces/Managers/RoutesManagerInterface.py new file mode 100644 index 0000000..80b182f --- /dev/null +++ b/Python/Interfaces/Managers/RoutesManagerInterface.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Self, Any +from abc import ABC, abstractmethod +from Models.RequestModel import RequestModel + +class RoutesManagerInterface(ABC): + + @abstractmethod + def update(self:Self) -> None:pass + + @abstractmethod + def reset(self:Self) -> None:pass + + @abstractmethod + def go(self:Self, method:str, path:str, request:RequestModel) -> None:pass + + @abstractmethod + def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:pass + \ No newline at end of file diff --git a/Python/Interfaces/Managers/SettingsManagerInterface.py b/Python/Interfaces/Managers/SettingsManagerInterface.py new file mode 100644 index 0000000..0da3691 --- /dev/null +++ b/Python/Interfaces/Managers/SettingsManagerInterface.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Optional, Self, Sequence +from abc import ABC, abstractmethod + +class SettingsManagerInterface(ABC): + + @abstractmethod + def update(self:Self) -> None:pass + + @abstractmethod + def reset(self:Self) -> None:pass + + @abstractmethod + def get(self:Self, + keys:str|Sequence[str], + inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None, + default:Optional[Any] = None + ) -> Any|None:pass + + @abstractmethod + def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:pass + + @abstractmethod + def add_secret(self:Self, inputs:Any|None, overwrite:bool = False) -> None:pass \ No newline at end of file diff --git a/Python/Interfaces/Managers/TerminalManagerInterface.py b/Python/Interfaces/Managers/TerminalManagerInterface.py new file mode 100644 index 0000000..ec1d711 --- /dev/null +++ b/Python/Interfaces/Managers/TerminalManagerInterface.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Self, Any +from abc import ABC, abstractmethod + +class TerminalManagerInterface(ABC): + + @abstractmethod + def update(self:Self) -> None:pass + + @abstractmethod + def reset(self:Self) -> None:pass + + @abstractmethod + def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:pass \ No newline at end of file diff --git a/Python/Managers/ControllersManager.py b/Python/Managers/ControllersManager.py new file mode 100644 index 0000000..f07cd34 --- /dev/null +++ b/Python/Managers/ControllersManager.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Self, Sequence +from Interfaces.Application.AnPInterface import AnPInterface +from Abstracts.ControllerAbstract import ControllerAbstract +from Models.RequestModel import RequestModel +from Utils.Common import Common +from Utils.Checks import Check + +class ControllersManager: + + def __init__(self:Self, anp:AnPInterface) -> None: + + self.anp:AnPInterface = anp + self.__controllers:dict[str, ControllerAbstract] = {} + + self.update() + + def update(self:Self) -> None: + + key:str + + for key in ("default_controllers_files", "controllers_files", "default_controllers", "controllers"): + self.add(self.anp.settings.get(key), True) + + def reset(self:Self) -> None: + + self.__controllers = {} + + self.update() + + def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None: + + subinputs:dict[str, Any|None] + + for subinputs in Common.load_json(inputs, True): + for key, controller in subinputs.items(): + if Common.is_mark_key(key) and controller is None: + continue + + ControllerClass:type[ControllerAbstract]|None + + if Check.is_string(controller): + ControllerClass = self.anp.models.get(ControllerAbstract, controller) + elif issubclass(controller, ControllerAbstract): + ControllerClass = controller + elif Check.is_dictionary(controller) and "type" in controller and Check.is_string(controller["type"]): + ControllerClass = self.anp.models.get(ControllerAbstract, controller["type"]) + else: + continue + + if ControllerClass and ( + overwrite or key not in self.__controllers + ): + self.__controllers[key] = ControllerClass( + self.anp, controller if Check.is_dictionary(controller) else + None) + + def execute(self:Self, key:str, method:str, request:RequestModel) -> bool: + if key in self.__controllers and hasattr(self.__controllers[key], method): + getattr(self.__controllers[key], method)(request) + return True + return False \ No newline at end of file diff --git a/Python/Managers/DispatchesManager.py b/Python/Managers/DispatchesManager.py new file mode 100644 index 0000000..065311d --- /dev/null +++ b/Python/Managers/DispatchesManager.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Self +from Interfaces.Application.AnPInterface import AnPInterface +from Abstracts.DispatchAbstract import DispatchAbstract +from Utils.Common import Common +from Utils.Checks import Check + +class DispatchesManager: + + def __init__(self:Self, anp:AnPInterface) -> None: + + self.anp:AnPInterface = anp + self.__dispatches:dict[str, DispatchAbstract] = {} + + self.update() + + def update(self:Self) -> None: + + key:str + + for key in ("default_dispatches_files", "dispatches_files", "default_dispatches", "dispatches"): + self.add(self.anp.settings.get(key), True) + + def reset(self:Self) -> None: + + self.__dispatches = {} + + self.update() + + def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None: + + subinputs:dict[str, Any|None] + + for subinputs in Common.load_json(inputs, True): + for key, dispatch in subinputs.items(): + if Common.is_mark_key(key) and dispatch is None: + continue + + DispatchClass:type[DispatchAbstract]|None + + if Check.is_string(dispatch): + DispatchClass = self.anp.models.get(DispatchAbstract, dispatch) + elif issubclass(dispatch, DispatchAbstract): + DispatchClass = dispatch + elif Check.is_dictionary(dispatch) and "type" in dispatch and Check.is_string(dispatch["type"]): + DispatchClass = self.anp.models.get(DispatchAbstract, dispatch["type"]) + else: + continue + + if DispatchClass and ( + overwrite or key not in self.__dispatches + ): + self.__dispatches[key] = DispatchClass( + self.anp, dispatch if Check.is_dictionary(dispatch) else + None) + + def execute(self:Self, key:str, method:str, *arguments:list[Any|None]) -> bool: + if key in self.__dispatches and hasattr(self.__dispatches[key], method): + getattr(self.__dispatches[key], method)(*arguments) + return True + return False \ No newline at end of file diff --git a/Python/Managers/I18NManager.py b/Python/Managers/I18NManager.py new file mode 100644 index 0000000..53d1a2a --- /dev/null +++ b/Python/Managers/I18NManager.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Optional, Self, Sequence +from Interfaces.Application.AnPInterface import AnPInterface +from Utils.Checks import Check +from Utils.Common import Common + +class I18NManager: + + def __init__(self:Self, anp:AnPInterface) -> None: + + self.anp:AnPInterface = anp + self.__sentences:dict[str, dict[str, str|list[str]]] = { + "english" : {} + } + self.__default_language:str = list(self.__sentences.keys())[0] + self.__language:str = self.__default_language + + self.update() + + def update(self:Self) -> None: + + key:str + + for key in ("default_i18n_files", "i18n_files", "default_i18n", "i18n"): + self.add(self.anp.settings.get(key), True) + + self.__default_language = self.anp.settings.get("language", None, self.__default_language) + self.__language = self.anp.settings.get("language", None, self.__language) + + def reset(self:Self) -> None: + + self.__sentences = { + "english" : {} + } + self.__default_language = list(self.__sentences.keys())[0] + self.__language = self.__default_language + + self.update() + + def __get_sentence(self:Self, texts:str|Sequence[str], custom_language:Optional[str] = None) -> str|list[str]|None: + + keys:list[str] = Common.get_keys(texts) + + if len(keys) != 0: + + language:str + done:list[str] = [] + + for language in (custom_language, self.__language, self.__default_language) + tuple(self.__sentences.keys()): + if language not in done and language in self.__sentences: + + key:str + + done.append(language) + + for key in keys: + if key in self.__sentences[language]: + return self.__sentences[language][key] + return ( + (texts[0] if len(texts) > 0 else None) if Check.is_array(texts) else + texts if Check.is_string(texts) else + None) + + def get(self:Self, + keys:str|Sequence[str], + inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None, + custom_language:Optional[Any] = None + ) -> Any|None: + + text:str|list[str]|None = self.__get_sentence(keys, custom_language) + + return Common.string_variables(( + text if Check.is_string(text) else + "".join(text) if Check.is_array(text) else + ""), inputs) + + def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None: + + subinputs:dict[str, Any|None] + + for subinputs in Common.load_json(inputs, True): + + language:str + sentences:dict[str, str|list[str]] + + for language, sentences in subinputs.items(): + + key:str + sentence:str|list[str] + + if language not in self.__sentences: + self.__sentences[language] = {} + for key, sentence in sentences.items(): + if Common.is_mark_key(key) and sentence is None: + continue + if overwrite or key not in self.__sentences[language]: + self.__sentences[language][key] = sentence \ No newline at end of file diff --git a/Python/Managers/IndexesManager.py b/Python/Managers/IndexesManager.py new file mode 100644 index 0000000..b51955b --- /dev/null +++ b/Python/Managers/IndexesManager.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Self, Any +from Interfaces.Application.AnPInterface import AnPInterface +from Utils.Checks import Check + +class IndexesManager: + + def __init__(self:Self, anp:AnPInterface) -> None: + + self.anp:AnPInterface = anp + self.__indexes:list[str] = [] + + self.update() + + def update(self:Self) -> None: + + key:str + + for key in ("default_indexes", "indexes"): + self.add(self.anp.settings.get(key)) + + def reset(self:Self) -> None: + + self.__indexes = [] + + self.update() + + def add(self:Self, inputs:Any|None) -> None: + if Check.is_array(inputs): + + item:Any|None + + for item in inputs: + self.add(item) + + elif ( + Check.is_string(inputs) and + (inputs := inputs.strip()) and + inputs not in self.__indexes + ): + self.__indexes.append(inputs) + + def get(self:Self) -> list[str]: + return [*self.__indexes] \ No newline at end of file diff --git a/Python/Managers/ModelsManager.py b/Python/Managers/ModelsManager.py new file mode 100644 index 0000000..28fa7a0 --- /dev/null +++ b/Python/Managers/ModelsManager.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Self, Any, Sequence, TypeVar +from Interfaces.Application.AnPInterface import AnPInterface +from Abstracts.ModelAbstract import ModelAbstract +from Utils.Common import Common + +T = TypeVar("T", bound = ModelAbstract) + +class ModelsManager: + + def __init__(self:Self, anp:AnPInterface) -> None: + + self.anp:AnPInterface = anp + self.__models:dict[str, ModelAbstract] = {} + + self.update() + + def update(self:Self) -> None: + + key:str + + for key in ("default_models_files", "models_files", "default_models", "models"): + self.add(self.anp.settings.get(key), True) + + def reset(self:Self) -> None: + + self.__models = {} + + self.update() + + def get(self:Self, Type:type[T], keys:str|Sequence[str]) -> T|None: + + key:str + + for key in Common.get_keys(keys): + if key in self.__models and isinstance(self.__models[key], Type): + return self.__models[key] + return None + + def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None: + + subinputs:dict[str, ModelAbstract] + + for subinputs in Common.load_json(inputs, True): + for key, model in subinputs.items(): + if Common.is_mark_key(key) and model is None: + continue + if isinstance(model, ModelAbstract) and ( + overwrite or key not in self.__models + ): + self.__models[key] = model \ No newline at end of file diff --git a/Python/Managers/PrintTypesManager.py b/Python/Managers/PrintTypesManager.py new file mode 100644 index 0000000..587a1d6 --- /dev/null +++ b/Python/Managers/PrintTypesManager.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Self, Sequence +from Interfaces.Application.AnPInterface import AnPInterface +from Utils.Common import Common +from Utils.Checks import Check + +class PrintTypesManager: + + def __init__(self:Self, anp:AnPInterface) -> None: + + self.anp:AnPInterface = anp + self.__print_types:list[list[str]] = [ + ["unkn", "unknown"] + ] + + self.update() + + def update(self:Self) -> None: + + key:str + + for key in ("default_print_types_files", "print_types_files", "default_print_types", "print_types"): + self.add(self.anp.settings.get(key)) + + def reset(self:Self) -> None: + + self.__print_types = [ + ["unkn", "unknown"] + ] + + self.update() + + def get(self:Self, keys:str|Sequence[str]) -> str: + + key:str + + for key in Common.get_keys(keys): + + block:list[str] + + key = key.lower() + + for block in self.__print_types: + if key in block: + return block[0].upper() + return self.__print_types[0][0].upper() + + def add(self:Self, inputs:Any|None) -> None: + if Check.is_array(inputs): + for item in inputs: + if all(Check.is_key(subitem) for subitem in item): + + main:str = item[0].lower() + i:int = 0 + l:int = len(self.__print_types) + subitem:str + + while i < l: + if main == self.__print_types[i][0]: + break + i += 1 + + if i == l: + self.__print_types.append([main]) + + for subitem in item[1:]: + subitem = subitem.lower() + if subitem not in self.__print_types[i]: + self.__print_types[i].append(subitem) + + else: + + subinputs:Any|None + + for subinputs in item: + self.add(Common.load_json(subinputs)) diff --git a/Python/Managers/RoutesManager.py b/Python/Managers/RoutesManager.py new file mode 100644 index 0000000..e7cc02c --- /dev/null +++ b/Python/Managers/RoutesManager.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import re +from typing import Self, Any +from Interfaces.Application.AnPInterface import AnPInterface +from Models.RouteModel import RouteModel +from Models.RequestModel import RequestModel +from Utils.Common import Common +from Utils.Checks import Check + +class RoutesManager: + + def __init__(self:Self, anp:AnPInterface) -> None: + + self.anp:AnPInterface = anp + self.__routes:list[RouteModel] = [] + + self.update() + + def update(self:Self) -> None: + + key:str + + for key in ("default_routes_files", "routes_files", "default_routes", "routes"): + self.add(self.anp.settings.get(key), True) + + def reset(self:Self) -> None: + + self.__routes = [] + + self.update() + + def go(self:Self, method:str, path:str, request:RequestModel) -> None: + + route:RouteModel + + for route in self.__routes: + if route.match(method, path, request): + if not request.response: + if route.callback: + route.callback(request) + elif route.path: + + index:str + + for index in [""] + self.anp.indexes.get(): + + path_indexed:str|None = Common.get_absolute_path(route.path + "/" + path + ("/" + index if index else "")) + + if path_indexed is not None and Common.is_file(path_indexed): + request.set_response(Common.load_file(path_indexed, "rb")) + request.response_mime = Common.get_mime_from_path(path_indexed) + return + request.set_response({ + "ok" : False, + "code" : 404, + "message" : "not_found" + }) + elif route.controller and route.controller_method: + if not self.anp.controllers.execute(route.controller, route.controller_method, request): + request.set_response({ + "ok" : False, + "code" : 505, + "message" : "not_implemented" + }) + else: + request.set_response({ + "ok" : True, + "code" : 500, + "message" : "internal_server_error" + }) + return + + request.set_response({ + "ok" : False, + "code" : 404, + "message" : "not_found" + }) + + def __add_new_route(self:Self, new_route:RouteModel, overwrite:bool = False) -> bool: + if new_route.error: + return False + + i:int + route:RouteModel + + for i, route in enumerate(self.__routes): + if route.path == new_route.path and route.method == new_route.method: + if overwrite: + self.__routes[i] = new_route + return True + + self.__routes.append(new_route) + + return True + + def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None: + + subinputs:Any|None + + for subinputs in Common.load_json(inputs, False): + if isinstance(subinputs, RouteModel): + self.__add_new_route(subinputs, overwrite) + elif ( + Check.is_string(subinputs) or Check.is_array(subinputs) or Check.is_dictionary(subinputs) + ) and not self.__add_new_route(RouteModel(subinputs), overwrite): + if Check.is_string(subinputs): + self.add(subinputs, overwrite) + elif Check.is_array(subinputs): + + fragment:Any|None + + for fragment in subinputs: + if Check.is_string(fragment) and not self.__add_new_route(RouteModel(fragment), overwrite): + continue + self.add(fragment, overwrite) + \ No newline at end of file diff --git a/Python/Managers/SettingsManager.py b/Python/Managers/SettingsManager.py new file mode 100644 index 0000000..0c259e0 --- /dev/null +++ b/Python/Managers/SettingsManager.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Optional, Self, Sequence +from Interfaces.Application.AnPInterface import AnPInterface +from Utils.Common import Common + +class SettingsManager: + + DEFAULT_SETTINGS:dict[str, Any|None] = { + "default_settings_files" : "/JSON/AnP.settings.json", + } + + def __init__(self:Self, + anp:AnPInterface, + inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None + ) -> None: + + self.anp:AnPInterface = anp + self.__inputs:dict[str, Any|None] = Common.get_dictionary(inputs) + self.__settings:dict[str, Any|None] = {} + self.__secrets:dict[str, Any|None] = {} + + self.update() + + def update(self:Self) -> None: + + key:str + + for key in ("default_settings_files", "settings_files", "default_settings", "settings"): + self.add(self.get(key), True) + for key in ("default_secrets_files", "secrets_files", "default_secrets", "secrets"): + self.add_secret(self.get(key), True) + + def reset(self:Self) -> None: + + self.__settings = {} + self.__secrets = {} + + self.update() + + def get(self:Self, + keys:str|Sequence[str], + inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None, + default:Optional[Any] = None + ) -> Any|None: + return Common.get_value(keys, ( + inputs, self.__inputs, self.__secrets, self.__settings, self.DEFAULT_SETTINGS + ), default) + + def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None: + + subinputs:dict[str, Any|None] + + for subinputs in Common.load_json(inputs, True): + + key:str + value:Any|None + + for key, value in subinputs.items(): + if Common.is_mark_key(key) and value is None: + continue + if overwrite or key not in self.__settings: + self.__settings[key] = value + + def add_secret(self:Self, inputs:Any|None, overwrite:bool = False) -> None: + + subinputs:dict[str, Any|None] + + for subinputs in Common.load_json(inputs, True): + + key:str + value:Any|None + + for key, value in subinputs.items(): + if Common.is_mark_key(key) and value is None: + continue + if overwrite or key not in self.__secrets: + self.__secrets[key] = value \ No newline at end of file diff --git a/Python/Managers/TerminalManager.py b/Python/Managers/TerminalManager.py new file mode 100644 index 0000000..5c3626f --- /dev/null +++ b/Python/Managers/TerminalManager.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Self, Callable, Any, Optional +from threading import Thread +from Interfaces.Application.AnPInterface import AnPInterface +from Utils.Checks import Check +from Utils.Common import Common +from Models.CommandModel import CommandModel + +class TerminalManager: + + def __init__(self:Self, anp:AnPInterface) -> None: + + self.anp:AnPInterface = anp + self.__commands:list[CommandModel] = [] + self.__thread:Thread = Thread(target = self.__handler) + + self.update() + + self.__thread.start() + + def update(self:Self) -> None: + + key:str + + for keys, callback in ( + (["close", "exit", "quit", "bye"], self.__close_command), + (["update", "upgrade"], self.__update_command), + (["reset"], self.__reset_command), + (["help", "h", "?"], self.__help_command) + ): + if not any(name in command_model.names for command_model in self.__commands for name in keys): + self.__commands.append(CommandModel(keys, callback)) + + for key in ("default_commands_files", "commands_files", "default_commands", "commands"): + self.add(self.anp.settings.get(key), True) + + def reset(self:Self) -> None: + + self.__commands = [] + + self.update() + + def __handler(self:Self) -> None: + while self.anp.working(): + try: + + order:str = input() + command:str = order.split(" ")[0].lower() + parameters:dict[str, Any|None] = {} + arguments:list[Any|None] = [] + done:bool = False + + for command_model in self.__commands: + if command in command_model.names: + command_model.callback(parameters, arguments) + done = True + break + + if not done: + self.anp.print("warning", "terminal_manager_unknown_command", { + "command": command + }) + + except Exception as error: + self.anp.exception(error, "terminal_manager_exception") + + def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None: + if Check.is_array(inputs): + if len(inputs) == 2 and ( + Check.is_key(inputs[0]) or + (Check.is_array(inputs[0]) and all(Check.is_key(name) for name in inputs[0])) + ) and Check.is_function(inputs[1]): + + i:int = 0 + l:int = len(self.__commands) + keys:list[str] = Common.get_keys(inputs[0]) + + while i < l: + if any(name in self.__commands[i].names for name in keys): + break + i += 1 + + if i == l: + self.__commands.append(CommandModel(keys, inputs[1])) + else: + self.__commands[i].update(keys, inputs[1], overwrite) + + def __close_command(self:Self, parameters:dict[str, Any|None], arguments:Optional[list[Any|None]]) -> None: + self.anp.close() + + def __update_command(self:Self, parameters:dict[str, Any|None], arguments:Optional[list[Any|None]]) -> None: + self.anp.update() + + def __reset_command(self:Self, parameters:dict[str, Any|None], arguments:Optional[list[Any|None]]) -> None: + self.anp.reset() + + def __help_command(self:Self, parameters:dict[str, Any|None], arguments:Optional[list[Any|None]]) -> None: + pass \ No newline at end of file diff --git a/Python/Models/CommandModel.py b/Python/Models/CommandModel.py new file mode 100644 index 0000000..9fa5e77 --- /dev/null +++ b/Python/Models/CommandModel.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Callable, Optional, Self, Sequence +from Utils.Common import Common +from Utils.Checks import Check + +class CommandModel: + + def __init__(self:Self, + names:str|Sequence[str], + callback:Callable[[dict[str, Any|None], Optional[list[Any|None]]], None] + ) -> None: + self.names:list[str] = Common.get_keys(names) + self.callback:Callable[[dict[str, Any|None], Optional[list[Any|None]]], None] = callback + + def update(self:Self, + names:str|Sequence[str], + callback:Optional[Callable[[dict[str, Any|None], Optional[list[Any|None]]], None]] = None, + overwrite:bool = False + ) -> None: + self.names += [name for name in Common.get_keys(names) if name not in self.names] + if Check.is_function(callback) or overwrite: + self.callback = callback \ No newline at end of file diff --git a/Python/Models/RequestModel.py b/Python/Models/RequestModel.py new file mode 100644 index 0000000..b479082 --- /dev/null +++ b/Python/Models/RequestModel.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Self, Callable, Sequence, Optional +from json import dumps as json_encode +from Abstracts.RouteAbstract import RouteAbstract +from Utils.Common import Common + +class RequestModel: + + def __init__(self:Self) -> None: + self.post_variables:dict[str, Any|None] = {} + self.get_variables:dict[str, Any|None] = {} + self.url_variables:dict[str, Any|None] = {} + self.variables:dict[str, Any|None] = {} + self.request_headers:dict[str, Any|None] = {} + self.method:str|None = None + self.route:RouteAbstract|None = None + self.response:str|bytes|None = None + self.response_mime:str|None = None + self.response_code:int = 0 + self.response_headers:dict[str, Any|None] = {} + self.callback:Callable[[RequestModel, str|bytes|None], None]|None = None + + def get(self:Self, key:str|Sequence[str], default:Optional[Any] = None) -> Any|None: + return Common.get_value(key, ( + self.url_variables, self.get_variables, self.post_variables, self.variables + ), default) + + def set_variables(self:Self, inputs:dict[str, Any|None], on:Optional[str] = None) -> None: + ( + self.url_variables if on == "url" else + self.get_variables if on == "get" else + self.post_variables if on == "post" else + self.variables).update(Common.get_dictionary(Common.load_json(inputs))) + + def set_response(self:Self, data:Any|None) -> None: + + if isinstance(data, dict): + self.response_code = Common.get_value("code", data, 200) + + if data is None or isinstance(data, (str, bytes)): + if not self.response_code: + self.response_code = 200 + self.response = data + elif isinstance(data, (dict, list, tuple, set)): + self.response_mime = "application/json" + self.response = json_encode(data) + elif isinstance(data, bool): + self.response = "true" if data else "false" + else: + self.response = str(data) + self.callback and self.callback(self, self.response) + + def set_request_headers(self:Self, inputs:Any|None) -> None: + self.request_headers.update(Common.get_dictionary(inputs)) + + def set_response_headers(self:Self, inputs:Any|None) -> None: + self.response_headers.update(Common.get_dictionary(inputs)) \ No newline at end of file diff --git a/Python/Models/RouteModel.py b/Python/Models/RouteModel.py new file mode 100644 index 0000000..a3737a9 --- /dev/null +++ b/Python/Models/RouteModel.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Self, Any, Sequence, Callable +from re import Match as REMatch, Pattern as REPattern, compile as re_compile +from Abstracts.RouteAbstract import RouteAbstract +from Utils.Common import Common +from Utils.Checks import Check +from Utils.Patterns import RE +from Models.RequestModel import RequestModel + +class RouteModel(RouteAbstract): + + def __init__(self:Self, inputs:str|dict[str, Any|None]|Sequence[Any|None]) -> None: + + request:str|REPattern + self.method:str + self.request:REPattern + self.action:str|None = None + self.controller:str|None = None + self.path:str|None = None + self.callback:Callable[[RequestModel], None]|None = None + self.permissions:list[str] = [] + self.variables:list[str] = [] + self.error:int = 0 + + if Check.is_string(inputs): + + matches:REMatch = RE.ROUTE.match(inputs.strip()) + + if matches is not None: + + permissions:str|None + method:str|None + + method, request, self.action, self.controller, self.path, permissions = matches.groups() + + self.method = "get" if method is None else method.lower() + if permissions is not None and (permissions := permissions.strip()) != "": + self.permissions.extend(permissions.split(",")) + + elif Check.is_dictionary(inputs): + + preaction:str|Callable[[RequestModel], None]|None = Common.get_value("action", inputs) + + self.method = Common.get_value("method", inputs, "get").lower() + request = Common.get_value("request", inputs, "/") + self.controller = Common.get_value("controller", inputs) + self.path = Common.get_value("path", inputs) + self.permissions.extend(Common.get_value("permissions", inputs, [])) + + if Check.is_function(preaction): + self.callback = preaction + elif Check.is_key(preaction): + self.action = preaction + + elif Check.is_array(inputs): + + l:int = len(inputs) + preaction:str|Callable[[RequestModel], None]|None + i:int = 3 + + if l < 3: + self.error = 1 << 1 + return + + self.method, request, preaction = inputs[:3] + while l > i: + if Check.is_key(inputs[i]): + self.controller = inputs[i] + elif Check.is_array(inputs[i]): + self.permissions.extend(inputs[i]) + i += 1 + + if Check.is_function(preaction): + self.callback = preaction + elif Check.is_key(preaction): + self.action = preaction + + else: + self.error = 1 << 0 + + if not self.error and not self.path and not self.callback and ( + not self.action or not self.controller + ): + self.error = 1 << 2 + + if not self.error: + if Check.is_string(request): + + def callback(matches:REMatch) -> str: + + self.variables.append(matches.group(1)) + + return r'([^\/]+)' + + self.request = re_compile(r'^' + RE.ROUTE_KEY.sub(callback, Common.to_regular_expression( + request[:-1] if request[-1] == "/" else request + )) + (r'\/?' if self.path is None else r'(\/.*)?') + r'$') + + elif Check.is_regular_expression(request): + request = request.pattern + else: + self.error = 1 << 3 + + def match(self:Self, method:str, path:str, request:RequestModel) -> bool: + + if self.method == method.lower(): + + matches:REMatch = self.request.match(path) + + if matches is not None: + + i:int + variable:str + + for i, variable in enumerate(self.variables): + request.variables[variable] = matches.group(i + 1) + + if self.error: + request.set_response({ + "ok" : False, + "code" : 501, + "message" : "invalid_route_configuration", + "route_error" : self.error + }) + + return True + return False \ No newline at end of file diff --git a/Python/Utils/Checks.py b/Python/Utils/Checks.py new file mode 100644 index 0000000..0f80265 --- /dev/null +++ b/Python/Utils/Checks.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Self, Sequence +from re import Pattern as REPattern +from Utils.Patterns import RE + +class Check: + + @staticmethod + def is_string(item:Any|None) -> bool: + return isinstance(item, str) + + @classmethod + def is_key(cls:type[Self], item:Any|None) -> bool: + return isinstance(item, str) and RE.KEY.match(item) is not None + + @staticmethod + def is_array(item:Any|None) -> bool: + return isinstance(item, (list, tuple)) + + @staticmethod + def is_dictionary(item:Any|None) -> bool: + return isinstance(item, dict) + + @staticmethod + def is_function(item:Any|None) -> bool: + return callable(item) + + @staticmethod + def is_regular_expression(item:Any|None) -> bool: + return isinstance(item, REPattern) \ No newline at end of file diff --git a/Python/Utils/Common.py b/Python/Utils/Common.py new file mode 100644 index 0000000..e8e59b2 --- /dev/null +++ b/Python/Utils/Common.py @@ -0,0 +1,274 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any, Optional, Sequence, Self +from re import Match as REMatch +from os.path import abspath as absolute_path, dirname as directory_name, exists as path_exists, isfile as is_file +from json import loads as json_decode +from io import FileIO +from mimetypes import guess_type as get_mime_by_extension +from inspect import FrameInfo, stack as get_stack +from Utils.Checks import Check +from Utils.Patterns import RE + +ROOT_PATH:str = absolute_path(directory_name(__file__)) +SLASH:str = "/" if "/" in ROOT_PATH else "\\" + +class Common: + + ROOT_PATH:str = ROOT_PATH + SLASH:str = SLASH + ROOTS_PATH:list[str] = [""] + [ROOT_PATH + (SLASH + "..") * i for i in range(4)] + SPECIAL_REGULAR_EXPRESSION_CHARACTERS:dict[str, str] = { + "\r" : "r", + "\n" : "n", + "\t" : "t" + } + + @classmethod + def get_keys(cls:type[Self], *items:list[Any|None]) -> list[str]: + + keys:list[str] = [] + item:Any|None + + for item in items: + if Check.is_key(item): + item not in keys and keys.append(item) + elif Check.is_array(item): + + key:str + + for key in cls.get_keys(*item): + key not in keys and keys.append(key) + + return keys + + @classmethod + def get_texts(cls:type[Self], *items:list[Any|None]) -> list[str]: + + texts:list[str] = [] + item:Any|None + + for item in items: + if Check.is_string(item): + texts.append(item) + elif Check.is_array(item): + + text:str + + for text in cls.get_texts(*item): + texts.append(text) + + return texts + + @classmethod + def get_dictionaries(cls:type[Self], *items:list[Any|None]) -> list[dict[str, Any|None]]: + + dictionaries:list[dict[str, Any|None]] = [] + item:Any|None + + for item in items: + if Check.is_dictionary(item): + dictionaries.append(item) + elif Check.is_array(item): + + dictionary:dict[str, Any|None] + + for dictionary in cls.get_dictionaries(*item): + dictionaries.append(dictionary) + + return dictionaries + + @classmethod + def get_dictionary(cls:type[Self], inputs:Any|None, overwrite:bool = False) -> dict[str, Any|None]: + + dictionary:dict[str, Any|None] = {} + + if Check.is_dictionary(inputs): + + key:str + value:Any|None + + for key, value in inputs.items(): + if overwrite or key not in dictionary: + dictionary[key] = value + + elif Check.is_array(inputs): + + subinputs:dict[str, Any|None] + + for subinputs in inputs: + + key:str + value:Any|None + + for key, value in cls.get_dictionaries(subinputs).items(): + if overwrite or key not in dictionary: + dictionary[key] = value + + return dictionary + + @classmethod + def get_value(cls:type[Self], + keys:str|Sequence[str], + inputs:dict[str, Any|None]|Sequence[Any|None], + default:Optional[Any|None] = None + ) -> Any|None: + if len(keys := cls.get_keys(keys)): + + subinputs:dict[str, Any|None] + + for subinputs in cls.get_dictionaries(inputs): + + key:str + + for key in keys: + if key in subinputs: + return subinputs[key] + return default + + @classmethod + def string_variables(cls:type[Self], + string:str, + inputs:dict[str, Any|None]|Sequence[Any|None], + default:Optional[str] = None + ) -> str: + + inputs = cls.get_dictionary(inputs) + + def replace(matches:REMatch) -> str: + + key:str = matches.group(1) + + return str( + inputs[key] if key in inputs else + default if default is not None else + matches.group(0)) + + return RE.STRING_VARIABLES.sub(replace, str(string)) + + @classmethod + def fix_path(cls:type[Self], path:str) -> str: + return RE.SLASHES.sub(cls.SLASH, path) + + @classmethod + def get_absolute_path(cls:type[Self], path:str) -> str|None: + + root:str + + for root in cls.ROOTS_PATH: + + absolute_path:str = cls.fix_path((root + cls.SLASH if root else "") + path) + + if absolute_path[0] == "\\": + absolute_path = "\\" + absolute_path + + if path_exists(absolute_path): + return absolute_path + return None + + @classmethod + def load_file(cls:type[Self], path:str, mode:str = "r") -> str|bytes|None: + try: + + file:FileIO + + if mode == "r": + for format in ( + "utf8", "cp1252", "ascii", "cp850", "latin1", "iso8859_1", + "utf16", "utf16le", "utf16be", "utf8sig", "iso8859_15" + ): + try: + with open(cls.get_absolute_path(path), mode, encoding = format) as file: + return file.read() + except Exception as exception: + pass + elif mode == "rb": + with open(cls.get_absolute_path(path), mode) as file: + return file.read() + except Exception as exception: + pass + return None + + @classmethod + def load_json(cls:type[Self], + data:str|dict[str, Any|None]|Sequence[Any|None], + only_dictionaries:bool = True + ) -> list[dict[str, Any|None]|Sequence[Any|None]]: + + json:list[dict[str, Any|None]|Sequence[Any|None]] = [] + + if isinstance(data, dict): + json.append(data) + elif isinstance(data, str): + + subdata:dict[str, Any|None]|Sequence[Any|None]|None + + try: + if subdata := json_decode(data): + json.extend(cls.load_json(subdata, only_dictionaries)) + return + except Exception as exception: + pass + + try: + json.extend(cls.load_json(json_decode(cls.load_file(data, "r")), only_dictionaries)) + except Exception as exception: + pass + + elif isinstance(data, (list, tuple)): + if only_dictionaries: + + item:Any|None + + for item in data: + json.extend(cls.load_json(item, only_dictionaries)) + else: + json.append(data) + + return json + + @staticmethod + def get_action_data(i:int = 0) -> dict[str, str|int]: + + stack:FrameInfo = get_stack()[i] + + return { + "file" : stack.filename, + "method" : stack.function, + "line" : stack.lineno + } + + @classmethod + def to_regular_expression(cls:type[Self], string:str) -> str: + + def callback(matches:REMatch) -> str: + + character:str = matches.group(0) + + return "\\" + ( + cls.SPECIAL_REGULAR_EXPRESSION_CHARACTERS[character] if character in cls.SPECIAL_REGULAR_EXPRESSION_CHARACTERS else + character) + + return RE.TO_REGULAR_EXPRESSION.sub(callback, string) + + @staticmethod + def get_mime_from_path(path:str) -> str|None: + return get_mime_by_extension(path)[0] + + @classmethod + def is_mark_key(cls:type[Self], key:str, marks:str|Sequence[str] = "AnP") -> bool: + + mark:str + + for mark in cls.get_keys(marks): + if key.startswith(mark + "_") and ( + key.endswith("_start") or + key.endswith("_end") + ): + return True + return False + + @staticmethod + def is_file(path:str) -> bool: + return is_file(path) \ No newline at end of file diff --git a/Python/Utils/Patterns.py b/Python/Utils/Patterns.py new file mode 100644 index 0000000..4de1181 --- /dev/null +++ b/Python/Utils/Patterns.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from re import compile as re_compile, Pattern as REPattern, IGNORECASE as RE_IGNORECASE + +class RE: + + KEY:REPattern = re_compile(r"^[a-z_][a-z0-9_]*$", RE_IGNORECASE) + STRING_VARIABLES:REPattern = re_compile(r"\{([a-z_][a-z0-9_]*)\}", RE_IGNORECASE) + SLASHES:REPattern = re_compile(r"[\\\/]+") + NEW_LINES:REPattern = re_compile(r"\r\n|\r|\n") + ROUTE:REPattern = re_compile(r"^(?:([a-z]+)\:)?([^\s]+)\s+(?:([^\s\@]+)\@([^\s]+)|([^\s]+))(?:\s+(.+))?$", RE_IGNORECASE) + TO_REGULAR_EXPRESSION:REPattern = re_compile(r'[\(\)\{\}\/\\\.\-\+\*\^\$\?\|\!\<\>\r\n\t]') + ROUTE_KEY:REPattern = re_compile(r'\\\{([a-z_][a-z0-9_]*)\\\}', RE_IGNORECASE) + EXCEPTION:REPattern = re_compile(r'^\s*File "([^"]+)", line ([0-9]+), in ([^\n]+)(.*|[\r\n]*)*$') + NEW_LINE:REPattern = re_compile(r'\r\n|[\r\n]') \ No newline at end of file diff --git a/Python/run.py b/Python/run.py new file mode 100644 index 0000000..c604fe1 --- /dev/null +++ b/Python/run.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Any +from Application.AnP import AnP +from Controllers.AIController import AIController + +inputs:dict[str, dict[str, Any|None]] = { + "default_models" : { + "AIController" : AIController + } +} + +try: + + from secrets import secrets as custom_secrets + + for key, value in dict(custom_secrets).items(): + if key not in inputs or isinstance(inputs[key], dict): + inputs[key] = value + elif isinstance(value, dict): + for subkey, subvalue in value.items(): + inputs[key][subkey] = subvalue + +except ImportError: + pass + +anp:AnP = AnP(inputs) \ No newline at end of file diff --git a/Tools/run.server.python.sh b/Tools/run.server.python.sh new file mode 100755 index 0000000..f4738bd --- /dev/null +++ b/Tools/run.server.python.sh @@ -0,0 +1,3 @@ +#!/bin/bash +directory=`dirname $(readlink -f "$0")` +python3 "$directory/../Python/run.py" diff --git a/Tools/sass.sh b/Tools/sass.sh new file mode 100755 index 0000000..bac3be8 --- /dev/null +++ b/Tools/sass.sh @@ -0,0 +1,3 @@ +#!/bin/bash +directory=`dirname $(readlink -f "$0")` +sass $directory/../Public/scss/AnP.scss ../Public/scss/AnP.css; diff --git a/version b/version new file mode 100644 index 0000000..8a9ecc2 --- /dev/null +++ b/version @@ -0,0 +1 @@ +0.0.1 \ No newline at end of file