From db7b69ad45f8645cfb8b89cef55e19bdf37b268b Mon Sep 17 00:00:00 2001 From: KyMAN <0kyman0@gmail.com> Date: Mon, 25 May 2026 07:26:02 +0200 Subject: [PATCH] #wip: In Dev client and server connection. --- .gitignore | 8 + Artbook/AnP_telegram.png | Bin 0 -> 6693 bytes Artbook/AnPv1.svg | 353 ++++++ Artbook/AnPv1.xcf | Bin 0 -> 107316 bytes Artbook/images.svg | 68 ++ Artbook/images.xcf | Bin 0 -> 26537 bytes JSON/AnP.routes.json | 4 + JSON/AnP.settings.json | 87 ++ JSON/I18N/AnP.i18n.english.json | 3 + JSON/I18N/AnP.i18n.espanol.json | 47 + JSON/I18N/AnP.i18n.galego.json | 3 + JSON/I18N/AnP.i18n.nihongo.json | 3 + JSON/I18N/AnP.i18n.russkiy.json | 3 + Public/ecma/Application/AnP.ecma.js | 191 +++ Public/ecma/Application/Components.ecma.js | 357 ++++++ Public/ecma/Application/Event.ecma.js | 97 ++ .../ecma/Components/AIChatComponent.ecma.js | 88 ++ Public/ecma/Components/BaseComponent.ecma.js | 279 +++++ Public/ecma/Components/DatesComponent.ecma.js | 49 + Public/ecma/Components/FormsComponent.ecma.js | 152 +++ Public/ecma/Components/I18NComponent.ecma.js | 83 ++ .../ecma/Components/LicensesComponent.ecma.js | 81 ++ .../ecma/Components/SelectsComponent.ecma.js | 49 + .../Components/SessionMiniComponent.ecma.js | 79 ++ .../ecma/Components/TablesComponent.ecma.js | 49 + .../ecma/Controllers/AIChatController.ecma.js | 39 + .../Controllers/SessionsController.ecma.js | 45 + Public/ecma/Drivers/FilesDriver.ecma.js | 310 +++++ Public/ecma/Drivers/WebSocketsDriver.ecma.js | 18 + .../ecma/Managers/ControllersManager.ecma.js | 157 +++ Public/ecma/Managers/I18NManager.ecma.js | 224 ++++ Public/ecma/Managers/ModelsManager.ecma.js | 148 +++ .../ecma/Managers/PrintTypesManager.ecma.js | 185 +++ Public/ecma/Managers/RoutesManager.ecma.js | 151 +++ Public/ecma/Managers/SessionsManager.ecma.js | 81 ++ Public/ecma/Managers/SettingsManager.ecma.js | 189 +++ Public/ecma/Managers/ThreadsManager.ecma.js | 258 ++++ .../ecma/Managers/UniqueKeysManager.ecma.js | 221 ++++ Public/ecma/Managers/ViewsManager.ecma.js | 138 +++ Public/ecma/Models/RouteModel.ecma.js | 59 + Public/ecma/Models/SessionModel.ecma.js | 70 ++ Public/ecma/Models/ThreadModel.ecma.js | 53 + Public/ecma/Models/UniqueKeyModel.ecma.js | 45 + Public/ecma/Utils/Checks.ecma.js | 147 +++ Public/ecma/Utils/Common.ecma.js | 471 ++++++++ Public/ecma/Utils/HTMLDSL.ecma.js | 349 ++++++ Public/ecma/Utils/Patterns.ecma.js | 12 + Public/favicon.ico | Bin 0 -> 8566 bytes Public/images/AnP-180.png | Bin 0 -> 18205 bytes Public/images/AnP-192.png | Bin 0 -> 14119 bytes Public/images/AnP-270.png | Bin 0 -> 14876 bytes Public/images/AnP-32.png | Bin 0 -> 2326 bytes Public/images/AnP-512.png | Bin 0 -> 8165 bytes Public/images/AnP.png | Bin 0 -> 8165 bytes Public/images/default_avatar.png | Bin 0 -> 3727 bytes Public/images/flags/english.svg | 124 ++ Public/images/flags/espanol.svg | 117 ++ Public/images/flags/galego.svg | 112 ++ Public/images/flags/nihongo.svg | 114 ++ Public/images/flags/russkiy.svg | 116 ++ Public/index.html | 52 + Public/json/AnP.settings.json | 28 + Public/json/i18n/AnP.i18n.english.json | 19 + Public/json/i18n/AnP.i18n.espanol.json | 19 + Public/json/i18n/AnP.i18n.galego.json | 3 + Public/json/i18n/AnP.i18n.nihongo.json | 3 + Public/json/i18n/AnP.i18n.russkiy.json | 3 + Public/json/views/AnP.views.sessions.json | 25 + Public/scss/AnP.base.scss | 264 ++++ Public/scss/AnP.common.scss | 19 + Public/scss/AnP.css | 1057 +++++++++++++++++ Public/scss/AnP.css.map | 7 + Public/scss/AnP.fonts.scss | 893 ++++++++++++++ Public/scss/AnP.icons.scss | 16 + Public/scss/AnP.scss | 1 + Public/scss/AnP.settings.scss | 47 + Python/Abstracts/ControllerAbstract.py | 14 + Python/Abstracts/DispatchAbstract.py | 14 + Python/Abstracts/ModelAbstract.py | 4 + Python/Abstracts/RouteAbstract.py | 4 + Python/Application/AnP.py | 148 +++ Python/Application/Event.py | 36 + Python/Controllers/AIController.py | 15 + Python/Drivers/HTTPDriver.py | 131 ++ Python/Drivers/OllamaDriver.py | 14 + Python/Drivers/WebSocketServerDriver.py | 82 ++ Python/Interfaces/Application/AnPInterface.py | 55 + .../Managers/ControllersManagerInterface.py | 20 + .../Managers/DispatchesManagerInterface.py | 19 + .../Managers/I18NManagerInterface.py | 23 + .../Managers/IndexesManagerInterface.py | 19 + .../Managers/ModelsManagerInterface.py | 21 + .../Managers/PrintTypesManagerInterface.py | 19 + .../Managers/RoutesManagerInterface.py | 21 + .../Managers/SettingsManagerInterface.py | 26 + .../Managers/TerminalManagerInterface.py | 16 + Python/Managers/ControllersManager.py | 64 + Python/Managers/DispatchesManager.py | 63 + Python/Managers/I18NManager.py | 99 ++ Python/Managers/IndexesManager.py | 46 + Python/Managers/ModelsManager.py | 53 + Python/Managers/PrintTypesManager.py | 78 ++ Python/Managers/RoutesManager.py | 118 ++ Python/Managers/SettingsManager.py | 79 ++ Python/Managers/TerminalManager.py | 100 ++ Python/Models/CommandModel.py | 24 + Python/Models/RequestModel.py | 59 + Python/Models/RouteModel.py | 129 ++ Python/Utils/Checks.py | 32 + Python/Utils/Common.py | 274 +++++ Python/Utils/Patterns.py | 16 + Python/run.py | 28 + Tools/run.server.python.sh | 3 + Tools/sass.sh | 3 + version | 1 + 115 files changed, 10512 insertions(+) create mode 100644 .gitignore create mode 100755 Artbook/AnP_telegram.png create mode 100755 Artbook/AnPv1.svg create mode 100755 Artbook/AnPv1.xcf create mode 100755 Artbook/images.svg create mode 100755 Artbook/images.xcf create mode 100644 JSON/AnP.routes.json create mode 100644 JSON/AnP.settings.json create mode 100644 JSON/I18N/AnP.i18n.english.json create mode 100644 JSON/I18N/AnP.i18n.espanol.json create mode 100644 JSON/I18N/AnP.i18n.galego.json create mode 100644 JSON/I18N/AnP.i18n.nihongo.json create mode 100644 JSON/I18N/AnP.i18n.russkiy.json create mode 100644 Public/ecma/Application/AnP.ecma.js create mode 100644 Public/ecma/Application/Components.ecma.js create mode 100644 Public/ecma/Application/Event.ecma.js create mode 100644 Public/ecma/Components/AIChatComponent.ecma.js create mode 100644 Public/ecma/Components/BaseComponent.ecma.js create mode 100644 Public/ecma/Components/DatesComponent.ecma.js create mode 100644 Public/ecma/Components/FormsComponent.ecma.js create mode 100644 Public/ecma/Components/I18NComponent.ecma.js create mode 100644 Public/ecma/Components/LicensesComponent.ecma.js create mode 100644 Public/ecma/Components/SelectsComponent.ecma.js create mode 100644 Public/ecma/Components/SessionMiniComponent.ecma.js create mode 100644 Public/ecma/Components/TablesComponent.ecma.js create mode 100644 Public/ecma/Controllers/AIChatController.ecma.js create mode 100644 Public/ecma/Controllers/SessionsController.ecma.js create mode 100644 Public/ecma/Drivers/FilesDriver.ecma.js create mode 100644 Public/ecma/Drivers/WebSocketsDriver.ecma.js create mode 100644 Public/ecma/Managers/ControllersManager.ecma.js create mode 100644 Public/ecma/Managers/I18NManager.ecma.js create mode 100644 Public/ecma/Managers/ModelsManager.ecma.js create mode 100644 Public/ecma/Managers/PrintTypesManager.ecma.js create mode 100644 Public/ecma/Managers/RoutesManager.ecma.js create mode 100644 Public/ecma/Managers/SessionsManager.ecma.js create mode 100644 Public/ecma/Managers/SettingsManager.ecma.js create mode 100644 Public/ecma/Managers/ThreadsManager.ecma.js create mode 100644 Public/ecma/Managers/UniqueKeysManager.ecma.js create mode 100644 Public/ecma/Managers/ViewsManager.ecma.js create mode 100644 Public/ecma/Models/RouteModel.ecma.js create mode 100644 Public/ecma/Models/SessionModel.ecma.js create mode 100644 Public/ecma/Models/ThreadModel.ecma.js create mode 100644 Public/ecma/Models/UniqueKeyModel.ecma.js create mode 100644 Public/ecma/Utils/Checks.ecma.js create mode 100644 Public/ecma/Utils/Common.ecma.js create mode 100644 Public/ecma/Utils/HTMLDSL.ecma.js create mode 100644 Public/ecma/Utils/Patterns.ecma.js create mode 100644 Public/favicon.ico create mode 100755 Public/images/AnP-180.png create mode 100755 Public/images/AnP-192.png create mode 100755 Public/images/AnP-270.png create mode 100755 Public/images/AnP-32.png create mode 100755 Public/images/AnP-512.png create mode 100755 Public/images/AnP.png create mode 100755 Public/images/default_avatar.png create mode 100644 Public/images/flags/english.svg create mode 100644 Public/images/flags/espanol.svg create mode 100644 Public/images/flags/galego.svg create mode 100644 Public/images/flags/nihongo.svg create mode 100644 Public/images/flags/russkiy.svg create mode 100644 Public/index.html create mode 100644 Public/json/AnP.settings.json create mode 100644 Public/json/i18n/AnP.i18n.english.json create mode 100644 Public/json/i18n/AnP.i18n.espanol.json create mode 100644 Public/json/i18n/AnP.i18n.galego.json create mode 100644 Public/json/i18n/AnP.i18n.nihongo.json create mode 100644 Public/json/i18n/AnP.i18n.russkiy.json create mode 100644 Public/json/views/AnP.views.sessions.json create mode 100644 Public/scss/AnP.base.scss create mode 100644 Public/scss/AnP.common.scss create mode 100644 Public/scss/AnP.css create mode 100644 Public/scss/AnP.css.map create mode 100644 Public/scss/AnP.fonts.scss create mode 100644 Public/scss/AnP.icons.scss create mode 100644 Public/scss/AnP.scss create mode 100644 Public/scss/AnP.settings.scss create mode 100644 Python/Abstracts/ControllerAbstract.py create mode 100644 Python/Abstracts/DispatchAbstract.py create mode 100644 Python/Abstracts/ModelAbstract.py create mode 100644 Python/Abstracts/RouteAbstract.py create mode 100644 Python/Application/AnP.py create mode 100644 Python/Application/Event.py create mode 100644 Python/Controllers/AIController.py create mode 100644 Python/Drivers/HTTPDriver.py create mode 100644 Python/Drivers/OllamaDriver.py create mode 100644 Python/Drivers/WebSocketServerDriver.py create mode 100644 Python/Interfaces/Application/AnPInterface.py create mode 100644 Python/Interfaces/Managers/ControllersManagerInterface.py create mode 100644 Python/Interfaces/Managers/DispatchesManagerInterface.py create mode 100644 Python/Interfaces/Managers/I18NManagerInterface.py create mode 100644 Python/Interfaces/Managers/IndexesManagerInterface.py create mode 100644 Python/Interfaces/Managers/ModelsManagerInterface.py create mode 100644 Python/Interfaces/Managers/PrintTypesManagerInterface.py create mode 100644 Python/Interfaces/Managers/RoutesManagerInterface.py create mode 100644 Python/Interfaces/Managers/SettingsManagerInterface.py create mode 100644 Python/Interfaces/Managers/TerminalManagerInterface.py create mode 100644 Python/Managers/ControllersManager.py create mode 100644 Python/Managers/DispatchesManager.py create mode 100644 Python/Managers/I18NManager.py create mode 100644 Python/Managers/IndexesManager.py create mode 100644 Python/Managers/ModelsManager.py create mode 100644 Python/Managers/PrintTypesManager.py create mode 100644 Python/Managers/RoutesManager.py create mode 100644 Python/Managers/SettingsManager.py create mode 100644 Python/Managers/TerminalManager.py create mode 100644 Python/Models/CommandModel.py create mode 100644 Python/Models/RequestModel.py create mode 100644 Python/Models/RouteModel.py create mode 100644 Python/Utils/Checks.py create mode 100644 Python/Utils/Common.py create mode 100644 Python/Utils/Patterns.py create mode 100644 Python/run.py create mode 100755 Tools/run.server.python.sh create mode 100755 Tools/sass.sh create mode 100644 version 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 0000000000000000000000000000000000000000..911f643bff862f1cd8f34f7b57b4372407ad00f6 GIT binary patch literal 6693 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 CHJfJu literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..9cea9f5f47c539dea9b8432d73f0c77c988753da GIT binary patch literal 107316 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..a4579926ee266c3a6792b434c3ffe757848bfa1b GIT binary patch literal 26537 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 [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 0000000000000000000000000000000000000000..cad6265702975aee54a9ea81d3ce2151315f9ac6 GIT binary patch literal 8566 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 literal 0 HcmV?d00001 diff --git a/Public/images/AnP-180.png b/Public/images/AnP-180.png new file mode 100755 index 0000000000000000000000000000000000000000..5f0b5f47b8cb5ebc1d43ea2bae6ec73642712ac3 GIT binary patch literal 18205 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 Eg1k)K^#A|> literal 0 HcmV?d00001 diff --git a/Public/images/AnP-192.png b/Public/images/AnP-192.png new file mode 100755 index 0000000000000000000000000000000000000000..4a3e8b70f7616a8615c6db4600cc2dd2956a59b4 GIT binary patch literal 14119 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 literal 0 HcmV?d00001 diff --git a/Public/images/AnP-270.png b/Public/images/AnP-270.png new file mode 100755 index 0000000000000000000000000000000000000000..9259dec845fe2394f7dd77e457682c15385efcab GIT binary patch literal 14876 zcmX9_WmpwmyB->(yK&PXo$}I1cS(1Hgmi;QcXvv6H-aGD2vQ;)l2Q@^f@k?1xcIS$ znLV-AdY-!`N=-!;^BLJQ2!b%><)kzq2oCGtA1X4~;@x;x3OZh}?iU#gK_+sq~9yo;WU}YI&@Y(EqBKO3I7b+qnv$QDR`_G0VT-%-*+p!9&2O~_A=Emp(t3vO!<+OZmBB&7 zKrM`J8VF88ij#>;Q`MTN`JBS!_Wa_SeZ0AQ=JCJ#wBRwQKu&nZeSl^imcQ2GKK(Fg zrkzf(?Y4~;!Y=n`)Z^RU%W3)uq<58t3)x z8tvnn0M(~{H3@?;=e!?Gc)G9fm?IO_Ws$UWBj>7;%xRP#xUm05?x-dyGUy=1QlM8z zgzf(R{CCr<-P*->T>05h&^qz=ClUnskK)y4-#13u)&$}H%=D!#UMywztuh|Q#S{Gp zkKFb?<~W|=3@$^c?>vQ_G@16!?%5E{d7#WjDoVK1`%irB?Kh$-&x2S!TKy3yDBySK z$Bl2jy&68Yznf`!c!2wlz%_B`ONA;J7G!fpSt;o6zuyl%^6=+rH1F!i zbf=efa_9HSyFk%>1h-Sm)1Dch>099$w`m`&5b@VAn!OPW==OzZJCtd2L8}5KB5yJU zwFjrgHtLR>VgzwV@U5LeB`-ud5H}wZyh+f0##1Oo!pxINki_B7nSxj-ZeGyB{lN|r zXO#<$yg~TwLcw?K4Cz5{;9iqRv;_;`g)nKr<+2$NJRkgKpO3!zx9clc8F*9kbpe7AYwyZg11-=@~)?W#5Hu zfo3|Xoss>UH{8Z9q$!c3gs1-%Cn^e*z>OlS(aO=mscUH=(L77Hq*+ll3Zj#rUtE-N zbab3wSy5;r|EivxoJ{ADCsW8Y;d%YGW9>BlFNa=})H6|?PysoqM`{V444(}&Kpb?DRFSCs;Z<$qP>n^6`p^pv&DdzIXF}W|Ni+! zOOHGd6{6E^T8Uhso-Yx`%JCnro#xUc;dl{UhF)tPN$&AGO*Oiy zO#%6`R4>=u@qL7;zT=_P6A%$8AR!?cQ76}1QQ}ihZ&`k}EPcw2{FKmg{rue@m%~}v z=W%@h>8emLGc)5scKxAfb2=sggen;O9`A*p`e+lt{SK=S7P5aWQ%<3J_vgYka@UW> zmtP;As3Ac}gUn7bBQ;gdVkABdk~=&+v`!AU13S~o#G)>dKCL4y?dkFP%+JpYWDBGU za(SNUR+f~|k>N2DI>ox77BeLi8GZD09JO^&ZwwXiy*i+VOXPQ2tswnNUld>jOQ7+< zx%*Nm8P9-~zlSWY4|Xk~)1X5g%nzLv!|S(w^QP$fc!`{_+L^$m!iGxp?;kg|%irt@ zmj|D7-rt`OU^COw4qOZtvPw|u_XhTW%OGHWe?^RF9)PifLF3DF;=l7b#1cQbfzpMk z+}-PBxlo#FghtDAVN#1R_PLm7U8JPZ_{2nMz{8F7E104*#-LzEiOF&&cR>Oq2c}*! zEPgb=2h-)gn5*4qxAE=9rw#_J(z-kUuI5Jx(p$GG^nqL{67E&#kMG9y!=s$Md?C2| zme$rG19E?~O?Vzw!Jd80c2^Cj`da8R^;$NbLgMe!qs6RVAaqV^TVvWvCb4D@O2pXM z*w&}~SdyQ#-018PxJEftcD%g2eLELw3JTBQoZ;=3Gp1U+Vl+bEVM7^J#}79@b8sa3 zKb)49lq8Pq6o!W*uQjSHI*#<+4B}!0!VA=0cW?Or!mRsr|7LuAyl8Pzd-m8ulEQb_ zMS&ns%o6qS>EUe4^CP}YdTnj(DAuaBf~Zg%_Aug-<#Y;CBa zq0wSaRW6ISn)3bpEVuN*g>(m%I0zXQ_gu_aS zE@6Z=a=_H8K-j0Lq{oA?=tekA_D_@y#b>eFCJ5?Cb zM{r~tY7E*{wwZ3*KbDjI+M;A#nVTcDz)t>b;G61@=J_Uuw0PTpR~FPBIbN7gxwZiK^x zG;G18_CA55V>39EAs%&1?^#{3ot+(S^9zYN$hory(aD40X#iU+RF2MGgianF^1og4 zI#Q&C>n5DeP5;g*b?oNmw&mIx8bs(S=>MDZt@Su&kT8|1algUyrZgAa1asAVVfmbw zZ_8?GYP?%{DfX*ENeO8k&wh|hH4K&x!HI)0nfvZ9=UO0dyR@6(o7IL_A`maYJ6cTh z>T*=`?^g4SC`+WI#SiHS;XpfjA6+|Iyr2Y+Nqso-;;t@zBf`TZ+~@Y467YXNkEJjU zT!$sV#mbRPNOFw*MCa&+!6lMdM43AZEN+tsIDeSO^xDJQd*0gGiWVbT%sE{0IRr&f zvs`7NNpx73%V=Vf0rNlcAL=H4hou>|nC2JqOQV0c{ zH=&;!y#JsuqQivhN6DAcO#Jx!61^)fmO&GJ3AMQUm0m>@`~xKNu$(E92_r|`NjU6 zOO8J3)EiSq8F#;V*~tca2e_W*9?`P$azz&HnlCXv0z$)u9CI6SJ;!*@?)woI+EEw6C?`*^EZEECt1 z_sQDE=2(xam#$oS;iwk1mDX%`e_v5cOKbK(0~2?uS@DxxXUJq*w6J%3OY_`|QOo?* zblk$Ks_4sKza0154hDsDoBLloB~JLfRW~$rs1~<%a;kf6U_f5E{yWMx)JQ1ISlDiN zG%0-C<#4XFtyQon@jGf~+(1!V+oEo9}R}#8K zU!=rnS-eP#EkS`h!LI4_>zp=f${HyqI=U;(dF;*BL#uY^N+Ivdm$F6pA0ur);A<{T z%m_<}T#JAvG|*HE8pjN14H7gVRz_c>&wr~45yTOe1%7Xfpg~KpZ0`tPI!?2m%%r9i z@#Repah-O)zkkP46Youf70)`8=pl(On?O}c%44njiOBMN^K-I{Xo9Rm`>-U|^jb-2 zjrN(yw@x=3fqw6(NY`zpZ>l;e9k6((30~PnLgkay&aZRtxtEuCsb-ArQ1=G=sqc7e z;`#s0sO#%%-=BZraXWWhBB*DMGDZB_vIb|#T~PJvob%5#5H`5$$h*7`X0bg!@w)-fio4!>IXc-qU3jgEe>DG1;%jFhC`*KwC+ zidns`sbQ_`>dKa-S`%$A{WxNGjlwBzkXPoJp%`|rP!XnW4i znHv-}iv?THRdyaG9-Ha;X5MG`T(Y#d*W3f!koebfRaLo|kgpuiT2s$^|338oBsddT zr}XL(szmq>UA@-!KmUx9&KW2#kH(;!UEIl`XCTwsL=X6d{GtgWSW;3tBo^Kd`}Nn_X-Vb^OS-_vR2J z>$8?1f%l}w)+2rylA?ByZC_^=L(CxqZp3be_uZ4fu}Li)PYlY}`|V#y!4#r(MVFeDXL!6PSAODpHR= zW5!b$r>Uu_wn*NmQ6Dj88tr&+DOz>>IQ4WS)igBBBgE}`GxaH&S}z*9o<2RC@=Qr* z{pZGT+H-5nrf88Q@TlAemyQCbJJ>AzZ=2^BeMY9aPsf^5ZEkPEpgU3W%huN>CU2u# zKa->|sN_}*B^HO4QnO-3=u;Kf80XhD!twGGMf{PJKDrkTxKEUSwWu#6O3|laW``;; zf2oVMsY6y`KJI3FwN)f{`rOXhz3DP!c`z6Q5w~oS=+`qC^A zi2k9z$$Yc#{Vw230q^(o{jm1)yr^cZ@CH)Bt z!V4&V!u44jUK$@;D=TBrTy(UhFoW?{qeqT-P+Yq2*-5$A8rDTJK5o`#3Hn}DFbC9E zR?6p@pNFP9NV3KQ^0WC)RcG-XfCb@g@e_Nm+}wDM*M#W)yP=2-st~t1{zVR*jg`Xp z9lE6Yg^dYrykGC}vsmqL3E$A2y$zX3T4Nh-KA(3pb3~1yrFo1kA5`x4s;RDSuEMsy zw5%fBv3>m@#-1^uW_I@&IGjL^W+4fCVLy1WOMU$3m6egUcDnZSsLF+zD35um-6}{9 z`HS72d|;p`ojmu+dw|M5k5Sza&tfBX$x&sDyx&v*PzSp2=+qS7Nq92d=bxU{W6YGf zUvUiI;G^{!H`BLRj9^ivh%(k-zGvS?fMmCWgp+AbShxo21Fu=~zrerIyJU@j&LYNY z*pUcOFoxfkKY#pL7x!^P=r?d=gPVu?76YqXt^VUpVS5tK?)%`_)G zTp|AVIbDJ=XC!SrzZ`gMG-cw*hGMqa33-^gTyOAAwfBBs>`?y4y6&@2*;CA&@48(R z^Jh|VDt~Wxv_3+^^G(c-#9jnrzISl!YT@l>2=-;>FH-Qh-AhB_$X{Z`a&0>hqO64c zjL-2%dg$jlx|dI3_&kc!4^ZKPma=}GLe+f^cvPd5z60TynmRv`8&us9-q*n@ssa3X zZDdqC#s!57Oi zb8{MOdmE5x?0{j$^GX(E3=-4jseIofW~wdY`6vO)Evrmsq&UqDtY>M&kw{0!$LhMe zsB!bj7=3u<9qgB;zORkMJdR##K1YbQ(<>dCwZj@d!1&>{5zxNUGD>vBj-!|>?8Ci$ z(K3qQeEvpL<#{x7;O)na%CM%m{VMn1B)w1L;~iOJbX#SpBz)%O<>mPMFq%@*r!Ist z2OgReMXvY8{dF*xSPhd*v3H-Sv3IV0eNL#LFR<5!eW*CN+1c4@`ufokRK9XC!ovv5 zW;zp+RIkYk^+~b-$Xga!sx=s?{-hyKk*o(_QC&UY*uGX~eRCYds!;fh@f}mhW}1S%6Yb?t zYSL2NjdCm($K_iVm;U%X4%@);(o%IFpU(VajW_N484q%dJTMlPi7$SiZrA-v_NxpF zYbGZqcpP4ygb^E8SVx{oXYiwd)-2+C#d++RytW4(Y$UOq8$I(%nsc~vlF!o zIQ^J{f1jv?`WA_B4ej82J4c?+k1Ty`Kb9aqsd>gEyNtr_i=uh+n`^QPO&hoM{^V8MN4$viNNTbT%r_354 zOhJNJnj$XSh`!fHR@qpX8aGS%e;MZe(__KW@{f)i-7*nR53zR5KmB4E`ievY^&9Qp~ z?dZ3(%t!W1(yn(eC$`TY9;s!2WWAzL6}||CVWB&3g%RujsAHM{3*83QWqxVNo?ear zPu|mY{kubv6)SM0RLe>YKe*3D99d;$OtkF=-s#z~qvd8B?9Mf(uaUGoJeu$@LZFZV z?uPIW=rat${hT}w?@gK5n-lt#8F^5W)XW~GK=C%3-SLIbYduGggVY4v2U>EafCwO( zhy)5Ppk6j43m6g|T~Zba{j-rqwU6<%lS`ej32&_VsXM|;+{InQF!uh6&Ua7HIm zCAn(>=QVL4il#m~I_g)BS;U#`Aerj=LsnI~A1r_v8-(5GYZW#`-nxwi^i0sxOk-zr z-hLXRO$>yH5IRQ2&|yd}bomQh(t1Fx3sn`plhUQ+lH%;?%kx@C%exAthsbgjsD!so zkqP1aHWi`2)ioWv$%-p!pXrB_bS)+`xqRys1%s?;!@`s=F4@uEDC@qz^~m?|qP=L(*#7%M>uMsz{lcINiU zo%p&Al&Hj|W5Pk)9d6K_*%T#dico&4P&myxB9d6Ziq;@@qy{aYpW`g`gXIN*{XqE1#M~+0XjxUeBIATLw5| z`CzsoCQ7TY*Nk#%UIO977?`$pN<=i;A+0uWiA%r~i4fnXoGzc=l@ zhkG(S z%S#PtWmO^}^%2gGzg@c1e-`9Lfe$Ubhhe>s9Fx@cMia*hQs_DRxaKsO z^D+S!*WSs=+QY-61^~_)f<#s4wQy_D|9Fr8yMG)iEUxVe4N6f(g}e(lo(o zHJ%zTT>HY@5(-2z)$GO#hhf3-L?J>>2}$-)b)?0?m%`s8Vo!y8+5RY-EjLTnF1?H5 zI1xeOh|8Y>gdV=l1eST+aRz<0EK-U@QlJ^8hJCQ$GV)l^0%a_L%B}=XfN$Lh-^>LS zRcedKalKnF2KNZg8(1KmrhP%7DRJNu5xr~FOlIih=V;={p!Mpyt{2qul3>8$$EPm|D0c2zaweZ+J3-XWpk&PN7DIOF;CE{zk++YTySp;kWryi-#6|#Y|RdS!hA&LkJ zihcL=tKg(u?6Gojj}QuEL6rp83;}6E&BP=j1O@x(C*L8`W+)7Et4cQ<=v^poOop;j z7JIJga)=J1b6>xztEoXW=79Nkmu|f+7KszDg<+bx=psvB60O5i7iKY702amc;>DZ- z&L6lS14J{_?FIz9T;xr1YRqGx=4E}at-PNe=Vv!e`%Q$9%~HkTK&=?RCF8$`l29bt;q&n5~Xo;Y8)3oTM5MN3Od z!=?)og)s8w+ak8mYIBsi%o=GjgLbE|??1~ny+o+6L&I?WIEU4Yjj?(+>Sf6=`Y((6!u@zyMLws#pARnRS<7<@il&UM ze7{p_39`06>0sW_Av2UY(NX?dzNlxDG@gcwgCi%UBc0FJi2=@^xB_n$OU=QN(B}BvdT58wE2AXTgANus04*W* zRYRwkH#~dS(b3N^$oXS6G&Nl=cjZ~AE;w8dU!>zDaX(xjw>&pta*K{!Kt^x;&RcYx^Wxb%xwNLQ&-vnIsXDh!VP>-cx){zq=5e`-u8BxW(E91+ZZsmG# zYGvw^{qE4$^8y0r_902nw{T`IBoZXz4^Cs4!b`iri0n(#F}AaVQn|uG#{_1T^oFUE zmjw(*Zf0!kaJ+T{z5%h1o8}%Ns6Gsd=F7q~5%E}b2yLZGzdk(7%Gx@d4x7J$gnHs9 zdj`v{F__k+U0s4zwY8;8=kKI=gCfswzQ2u`1{iy;%5um>g5uH-16`Jkh(Iz@@+==1 zU3gGsLxbAo!{hGl11&X9ud^AVi!9F~VID?NZ~Q8M=s*A)3;k-7CLblLGFjPX9}83yfHw!g(f$R-a0w`ljoc#Ka$8%a+yngvERcTbcL4iX7wBWjrwpu zs}B)u4cO`z^YcLv@xi|=fC&<5FcLaZA}lTwNxgNB_6a-4B>F>T5N&X=)NWEQxw*p9 z;^N%Nx8_oy*9vtq#Jg&F4;^1C7_>Rex*ALq?ot~PejgEtJaEdtQAn2JXF!+5M}dG% zD#>x`()GXVGaR{?*HlHD;==*VaLL$@O}ox;Eale{G>x-MZBF4CPF^)A1f6fka5NE{ z_^Y?%zXxK)0Du)2z;ZYz**1Cgs(-byxf-5ke8IJYabRd`uxnO2wvCb$4cov27$Xh@x+|jy)&P~kYBAm5Ol&BKNc08}Iuddunjsk z#>*t0v|gmR9qiz`7yvYn2qbeoSM0jqo5nQ=DvkK+66D6m?BM?M-9Pk-M0!1f7{W=4 zs;C)FvDb+jkX!1yG~|ZdTl!Xa_&*Tua1L_(7!+9N8{HSuVmX~%S$T64%vJYosaQ7Q zG&9zO>CDV3ohLq0j40sS{HKpAHKD8NY|t-nVPTWW$c_=}tT2OxrIeJE5XSD$dria3 z3d+huH$T6pMMV{{iDhUqa?_Xti`onm6B7dhI;656cKi1@N+HjR>gK^zZ}YyE^{>@B z9Gd=IL)qBaK@+XpRKO{+X7Y|4`Z7273IqwPC!M~Ot3J21vdX)wX*k187X4By{qLmM{-P3ZmCOeVeOpXT#}BCY(0-R-;7qps*4~sJ_G6-0wD> zJKq|x`}JeWn!oFkR22DKJyk3TZS&UG#QSIKk}ZH7;Z$WmuYDUGzH$G#U+UHVG=m29 zNWoUTx77^1WXe1-TqLH1FJj+CzpupTk+Cm%0@OtbJ-5o~ai9H@Vgu`}Z+RAv4cQa> zKas1o+7#36>Q2lcEhl^O6GwtFG3(~{s|cxHNfP$fS5Fyg4Q zob}|td-7pfC7f+mW{4jjSKx`Vz>BQ-!n$2iQ}dcdw@Mlw1($M;tP%y2Y?owPt!GJ6 zKSGn#V_Hc@Cj9FDxW0PB?gI>a;M%)@+sTICr2{I_|NT^u86Y`SGf@dWP30i{2K84D zD3isLj(2(12qg7ZX(Vt3GZFLiID~?*uC}cU%mQv>8%w3Aecy1Uk+!xrvKvIt6&~QQ zqeB6OT=aQaSy4b7W=tL-@3zMlJ`XaxZGEGx6ubk!7tuT|IKhdpnoP%@qolC{17y^N z9Jau9@i6*c^Yry$BDJJ>*Tf>KPS{SgNASj(YK5nA$?x!4>TqzH#P6LDtJ1DaqESXM zREMHA{h*?yMJVLDi|RK1FiKKh^PunNcJw*Ug9+N*b2npCEI^8wy8*$oUt z8sfU%v{rN7rtLygZzFwUq1X%)6ub6juSAD z{>_CYeLjTa|2IJHC^pHH%YF|_2m1qYP)6ai+?&%ia;d?5?`<>z)9S$DE*eJ0k;#Yh z$S23x9C(=g-GB5$B^2ZJG9&mX}Xbc6AWGGtAf*vN8p^!wuCaE`j(I7x`2 zaane$ulR6W$uLAV`-tm_UN*Kk;%&Pt)N#FNpy#|e6i+(5yZ=s?aNkzkPvu)?#zM8u zQcRsA);lIKAc^DzoY9q5o3Hq1FC9w*V=0?{ahXpW<|U47nsM)&KqVqBbpo;;UZKNx zk58;nKrGYcTXYh1;vg0BG5)vf4$F~3Kn_b}hcgXJ=G3n01p=Y%=)nBK!Ua)v$LuE; zbWeI5Xdi)T&!|AekDnaCE}-j~?oS!Xh~_NMTSw<4SH-@C`rZcqA|E*Y&wLQo2>I*P z+t_}ffer@{3C%oCu&){E*G&L3Y?_RmJWID1W(p&l>dwkXucM1+NhLN8xYm-4NCX~L zrJru?nt`%Mm0@HrT1$O*z+RdTZ+RmkqInn)Pr2vjK%yf5e&pRcuyS%9CjAe^VSUw9 zC!Cig)eH%MOADX(A^h{(Uo|6{AC_IIFZG`HqldHQdEXzFOHv^O303@6h$+^1oU;2` zM#>P2hR<+brSsqCc^yRM4EW!KXF^`r$=+11rakZ&4|O)eIHWtzFt z6!3d1Vyq&}MEv2sbyd|!t2qVqCCVD4BCHmdZIy(}fIr2@$Jec>nMYvyx|6+E(?k{2 zWKhE{77gB_T@xQvY}mp!Y~5~dV)41eM3q9bEU&)zDDc{qUcn0Hyur+PR-4ASjNm?)$5PR<2}@) zpl0X;Co?ON=e3)o%lF|Li~5><>3VHvYa(;@l|%y32UW_#QAuM7n@X4@uy;eCY|V=|2PujF}=PO+O(A!6jeG4d{}RSHDc8oo}Js}|G+)*BZc zdl|edt8yCzi9E9P=RTcU^9Y?WJN4LH26Foa??h+1f2X7nYmPM;#@$?V#TBujy2Ghf zTac3l&|3qJiZDatSPCP2bz=-H30;iK1u}Bte zhEUYGufx5LJp=u{xVW-X9P~=CoQT{#TZn?oJk;!?RfwF5$`7u?9u<@R+H8+QmirL# z(8f4FAtVx|Wh54PJegRM!Zv|>H+dN&>KWJ2OcszTdU;i7#7;aMM?PW^rISmg_Ik4G z4|!p=MR`;m%?B7JvS~=y6If+0{Snsyr>`&Ilj^Q9!V33y{2{OY+4br`J$iqzJ@@N= z*85w$&+7Y!BNVMLaxyZdLqBC@<-BPo+9G`YfSFPYV^#IV>w{SY;53J$pT@mh-xR4N z;Mm1&5hajzC@1Wz(Q6K7AJ03o&&tXQKbG_H`42?uX63cuu3~-h^MuI)>q|a>ESoy$ z6@@kX*S@8BLSC0O@vj=KjC3h3D3&&v9|3fvuV1q7X#K2*chO_~&h0QR7K%>u0F*v_ z#^!`!1%UZKSLI@*AX9c->H|6b!`lfZaGTa10TvdtRK5q)lFgY2KR-JBH`X3=T@&Z* zRzn?=;xGD~hj!$L-&xOyMWod;33Sv!bUW{mu39N@EzHqReF)eUq(xCnx5d<0$O}oq zAW0Z*je=hE;REEhKfQ+*4`$jRt{s$1rwu;S^LW1A2SOnW3!RaJd^5Wig^jWV;7>J6z(xQXaY*Rqp{sX|D7W;i2o7jMV2~9b&HiE{krp?HS^fpn_M~ z$2Q*6R23;rqvrUrS<=B8y?bVe>uxB{$A|u5M?eZcQZh!EAC83HGv}GWmlab;#tt*p z+A4PGKuA@_^{*}e2lpmHZl3R|Je>EOJ0G;T+Ybv+v5c5cI795<&5b%qzrAbjH5E$6Ei3 z7!K-((o*R)6Oy32Bz>V-T?#&Ed?D}~&}@{2o^1liJOH?|cd`)^D>$1j8T!IfI-7wE zh@=(R%{19Bu@5)$*9FO(u4Z;%l2Pl9)g-5Ow#(0

XfdW{PVap<75WNaD*lk4Zt%88i{%Hd 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 literal 0 HcmV?d00001 diff --git a/Public/images/AnP-32.png b/Public/images/AnP-32.png new file mode 100755 index 0000000000000000000000000000000000000000..3d44a5e54616bcd10f92e85839c06a80f992ff38 GIT binary patch literal 2326 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 Jx19pw{||!^T#*0( literal 0 HcmV?d00001 diff --git a/Public/images/AnP.png b/Public/images/AnP.png new file mode 100755 index 0000000000000000000000000000000000000000..9b0990f15df9ed11a36672af84b2fc0fd1e93d61 GIT binary patch literal 8165 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 Jx19pw{||!^T#*0( literal 0 HcmV?d00001 diff --git a/Public/images/default_avatar.png b/Public/images/default_avatar.png new file mode 100755 index 0000000000000000000000000000000000000000..0fe9617617228728c4dad0dc38d2e6281fa15514 GIT binary patch literal 3727 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 J_-u9dKLIOzV)Xz3 literal 0 HcmV?d00001 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