#wip(py,sql,cs,js): Starting project.

This commit is contained in:
KyMAN 2026-03-29 20:37:07 +02:00
parent 42126e52f2
commit 58548a6576
61 changed files with 4293 additions and 1 deletions

12
.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
/Data
/Public/data
__pycache__
.sass-cache
*.[Ss]ecret.*
*.[Ss]ecrets.*
*.deleted.*
/CSharp/bin
/CSharp/obj
/SQLServer/data
/SQLServer/scripts
/SQLServer/temporary

29
AnPv2.sln.old Normal file
View File

@ -0,0 +1,29 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CSharp", "CSharp", "{B41BF331-FCCB-2ADF-CDB6-767964B34647}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnP", "CSharp\AnP.csproj", "{720E15E3-2F0D-4B91-98F1-400300826A0A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{720E15E3-2F0D-4B91-98F1-400300826A0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{720E15E3-2F0D-4B91-98F1-400300826A0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{720E15E3-2F0D-4B91-98F1-400300826A0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{720E15E3-2F0D-4B91-98F1-400300826A0A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{720E15E3-2F0D-4B91-98F1-400300826A0A} = {B41BF331-FCCB-2ADF-CDB6-767964B34647}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {47442BB3-05F5-4AAF-A859-D456A81FC0A2}
EndGlobalSection
EndGlobal

23
CSharp/AnP.csproj Executable file
View File

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0;net462</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
<RootNamespace>AnP</RootNamespace>
<AssemblyName>AnP</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
</ItemGroup>
</Project>

3
CSharp/AnP.slnx Executable file
View File

@ -0,0 +1,3 @@
<Solution>
<Project Path="AnP.csproj" />
</Solution>

9
CSharp/Application/AnP.cs Executable file
View File

@ -0,0 +1,9 @@
using AnP.Interfaces.Application;
namespace AnP.Application{
class AnP:AnPInterface{
public AnP(object? inputs = null){}
}
}

View File

@ -0,0 +1,5 @@
namespace AnP.Interfaces.Application{
public interface AnPInterface{
}
}

View File

@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Linq;
namespace AnP.Interface.Managers{
public interface I18NManagerInterface{
public string get(List<string> strings, object? inputs = null, List<string>? languages = null, int custom_options = 0);
public void add(object? items, int custom_options = 0);
}
}

View File

@ -0,0 +1,58 @@
using System.Collections.Generic;
using AnP.Types;
using AnP.Utils;
using AnP.Interfaces.Application;
namespace AnP.Managers{
public class I18NManager{
private static readonly Dictionary<string, Dictionary<string, I18NSentenceType>> DEFAULT_SENTENCES = new Dictionary<string, Dictionary<string, I18NSentenceType>>{
{"english", new Dictionary<string, I18NSentenceType>{
{"greeting", new I18NSentenceType.Text("Hello, World!")}
}}
};
private static readonly Options GET_OPTIONS = new Options();
public AnPInterface anp;
private Dictionary<string, Dictionary<string, I18NSentenceType>> sentences;
private string language;
private string default_language;
public I18NManager(AnPInterface anp){
this.anp = anp;
sentences = new Dictionary<string, Dictionary<string, I18NSentenceType>>(DEFAULT_SENTENCES);
language = default_language = "english";
}
public string get(object strings, object? inputs = null, object? languages = null, int custom_options = 0){
List<string> keys = Common.get_keys(strings);
Options options = new Options(custom_options, GET_OPTIONS);
if(keys.Count != 0){
List<string> languages_used = new List<string>();
foreach(string language in Common.get_keys(languages).Concat<string>(
new List<string>{this.language, default_language}
).Concat<string>(sentences.Keys))
if(!languages_used.Contains(language)){
languages_used.Add(language);
if(sentences.ContainsKey(language))
foreach(string key in keys)
if(sentences[language].ContainsKey(key))
return sentences[language][key] switch{
I18NSentenceType.Text text => text.value,
I18NSentenceType.List list => string.Join("", list.value),
_ => ""
};
}
};
return Common.get_strings(strings).FirstOrDefault() ?? "";
}
public void add(object? items, int custom_options = 0){}
}
}

View File

@ -0,0 +1,31 @@
using System.Collections.Generic;
using AnP.Utils;
using AnP.Interfaces.Application;
namespace AnP.Managers{
public class SettingsManager{
public static readonly Dictionary<string, object?> DEFAULT_SETTINGS = new Dictionary<string, object?>{};
public static readonly Options GET_OPTIONS = new Options(Options.ALLOW_NULLS);
public static readonly Options ADD_OPTIONS = new Options(Options.NO_OVERWRITE);
public AnPInterface anp;
public Dictionary<string, object?> settings = new Dictionary<string, object?>(){};
public Dictionary<string, object?> secrets = new Dictionary<string, object?>(){};
public Dictionary<string, object?> inputs;
public SettingsManager(AnPInterface anp, object? inputs = null){
this.anp = anp;
this.inputs = Common.get_dictionary<object?>(inputs);
}
public T? get<T>(object keys, object? inputs, T? _default = default(T?), int custom_options = 0){
return Common.get<T>(keys, new object?[]{
inputs, this.inputs, secrets, settings, DEFAULT_SETTINGS
}, _default, new Options(custom_options, GET_OPTIONS).get());
}
public void add(object? items, int custom_options = 0){}
}
}

9
CSharp/Program.cs Executable file
View File

@ -0,0 +1,9 @@
using System;
namespace AnP{
class Program{
static void Main(string[] args){
Console.WriteLine("Hello World!");
}
}
}

14
CSharp/Types/ColorType.cs Normal file
View File

@ -0,0 +1,14 @@
using AnP.Utils;
namespace AnP.Types{
public abstract record ColorType{
private ColorType(){}
public sealed record String(string value):ColorType;
public sealed record List(IEnumerable<string> value):ColorType;
public sealed record Integer(int value):ColorType;
public sealed record Instance(Color value):ColorType;
}
}

View File

@ -0,0 +1,10 @@
namespace AnP.Types{
public abstract record I18NSentenceType{
private I18NSentenceType(){}
public sealed record Text(string value):I18NSentenceType;
public sealed record List(IEnumerable<string> value):I18NSentenceType;
}
}

41
CSharp/Utils/Check.cs Executable file
View File

@ -0,0 +1,41 @@
using System.Collections;
using System.Collections.Generic;
namespace AnP.Utils{
public class Check{
public static bool is_string(object? item){
return item is string;
}
public static bool is_key(object? item){
return item is string && RE.KEY.IsMatch((string)item);
}
public static bool is_dictionary<T>(object? item){
return item is IDictionary<string, T>;
}
public static bool is_dictionary(object? item){
return item is IDictionary;
}
public static bool is_array<T>(object? item){
return item is IEnumerable<T>;
}
public static bool is_array(object? item){
return item is IEnumerable;
}
public static bool is_integer(object? item){
return item is int;
}
public static bool is_float(object? item){
return item is float || item is double || item is decimal;
}
}
}

140
CSharp/Utils/Color.cs Executable file
View File

@ -0,0 +1,140 @@
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
namespace AnP.Utils{
public class Color{
public int red = 0x00;
public int green = 0x00;
public int blue = 0x00;
public int alpha = 0xFF;
public Color(string code){
if(code.StartsWith("#")){
code = code.Substring(1);
if(code.Length == 3 || code.Length == 4)
code = string.Concat(code.Select(c => $"{c}{c}"));
code = code.PadLeft(8, 'F');
alpha = Convert.ToInt32(code.Substring(0, 2), 16);
red = Convert.ToInt32(code.Substring(2, 2), 16);
green = Convert.ToInt32(code.Substring(4, 2), 16);
blue = Convert.ToInt32(code.Substring(6, 2), 16);
}else if(code.StartsWith("rgb")){
string[] items = code.Substring(code.IndexOf("(") + 1, code.LastIndexOf(")") - code.IndexOf("(") - 1).Split(",");
red = items.Length > 0 ? Convert.ToInt32(items[0]) : 0;
green = items.Length > 1 ? Convert.ToInt32(items[1]) : 0;
blue = items.Length > 2 ? Convert.ToInt32(items[2]) : 0;
alpha = items.Length > 3 ? (
items[3].Contains(".") ? (int)(Convert.ToSingle(items[3]) * 0xFF) :
Convert.ToInt32(items[3])) : 0xFF;
}
}
public Color(int color){
alpha = 0xFF - ((color >> 24) & 0xFF);
red = (color >> 16) & 0xFF;
green = (color >> 8) & 0xFF;
blue = color & 0xFF;
}
public Color(IEnumerable inputs, string type = "rgba"){
object[] array = ((IEnumerable)inputs).Cast<object>().ToArray();
if(type == "rgb" || type == "rgba" || true){
red = array.Length > 0 ? (int)array[0] : 0;
green = array.Length > 1 ? (int)array[1] : 0;
blue = array.Length > 2 ? (int)array[2] : 0;
alpha = array.Length > 3 ? (
Check.is_integer(array[3]) ? (int)array[3] :
Check.is_float(array[3]) ? (int)((float)array[3] * 0xFF) :
0xFF) : 0xFF;
}
}
public Color(Color color){
red = color.red;
green = color.green;
blue = color.blue;
alpha = color.alpha;
}
public string to_rgba(){
return $"rgba({red}, {green}, {blue}, {(float)alpha / 0xFF:0.##})";
}
public string to_rgb(){
return $"rgb({red}, {green}, {blue})";
}
public string to_hex(bool with_alpha = false){
return $"#{(with_alpha ? $"{alpha:X2}" : "")}{red:X2}{green:X2}{blue:X2}";
}
public static Color mix(params object[] colors){
if(colors.Length == 0)
return new Color(0);
Color _base;
int l = colors.Length;
if(Check.is_string(colors[0]))
_base = new Color((string)colors[0]);
else if(Check.is_integer(colors[0]))
_base = new Color((int)colors[0]);
else if(Check.is_array(colors[0]))
_base = new Color((IEnumerable)colors[0]);
else if(colors[0] is Color)
_base = new Color((Color)colors[0]);
else
return new Color(0);
if(l != 1){
for(int i = 1; i < l; i ++){
Color subcolor;
if(Check.is_string(colors[i]))
subcolor = new Color((string)colors[i]);
else if(Check.is_integer(colors[i]))
subcolor = new Color((int)colors[i]);
else if(Check.is_array(colors[i]))
subcolor = new Color((IEnumerable)colors[i]);
else if(colors[i] is Color)
subcolor = new Color((Color)colors[i]);
else
continue;
_base.red += subcolor.red;
_base.green += subcolor.green;
_base.blue += subcolor.blue;
_base.alpha += subcolor.alpha;
}
_base.red /= l;
_base.green /= l;
_base.blue /= l;
_base.alpha /= l;
};
return _base;
}
}
}

99
CSharp/Utils/Common.cs Executable file
View File

@ -0,0 +1,99 @@
using System.Collections.Generic;
namespace AnP.Utils{
public class Common{
public static readonly Options GET_DICTIONARY_OPTIONS = new Options(Options.NO_OVERWRITE);
public static readonly Options GET_OPTIONS = new Options(Options.ALLOW_NULLS);
public static List<string> get_strings(object? items){
List<string> strings = new List<string>();
if(items != null){
if(Check.is_string(items))
strings.Add((string)items);
else if(Check.is_array<object>(items))
foreach(object item in (IEnumerable<object>)items)
if(Check.is_string(item))
strings.Add((string)item);
}
return strings;
}
public static List<string> get_keys(object? items){
List<string> keys = new List<string>();
if(items != null){
if(Check.is_key(items))
keys.Add((string)items);
else if(Check.is_array<object>(items))
foreach(object item in (IEnumerable<object>)items)
if(Check.is_key(item)){
string key = (string)item;
if(!keys.Contains(key))
keys.Add(key);
};
}
return keys;
}
public static List<IDictionary<string, T>> get_dictionaries<T>(object? items){
List<IDictionary<string, T>> dictionaries = new List<IDictionary<string, T>>();
if(items != null){
if(Check.is_dictionary<T>(items))
dictionaries.Add((Dictionary<string, T>)items);
else if(Check.is_array<object>(items))
foreach(object item in (IEnumerable<object>)items)
if(Check.is_dictionary<T>(item))
dictionaries.Add((IDictionary<string, T>)item);
}
return dictionaries;
}
public static Dictionary<string, T> get_dictionary<T>(object? items, int custom_options = 0){
Dictionary<string, T> dictionary = new Dictionary<string, T>();
Options options = new Options(custom_options, GET_DICTIONARY_OPTIONS);
if(items != null){
if(Check.is_dictionary<T>(items))
dictionary = (Dictionary<string, T>)items;
else if(Check.is_array<object>(items))
foreach(object item in (IEnumerable<object>)items)
if(Check.is_dictionary<T>(item))
foreach(KeyValuePair<string, T> pair in (IDictionary<string, T>)item)
if(options.overwrite == true || !dictionary.ContainsKey(pair.Key))
dictionary[pair.Key] = pair.Value;
}
return dictionary;
}
public static T? get<T>(object keys, object inputs, T? _default = default(T?), int custom_options = 0){
Options options = new Options(custom_options, GET_OPTIONS);
List<string> keys_list = get_keys(keys);
if(keys_list.Count != 0)
foreach(IDictionary<string, T> subinputs in get_dictionaries<T>(inputs))
foreach(string key in keys_list)
if(subinputs.ContainsKey(key) && (
options.allow_null == true ||
subinputs[key] != null
))
return subinputs[key];
return _default;
}
}
}

57
CSharp/Utils/Options.cs Executable file
View File

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
namespace AnP.Utils{
public class Options{
public const int OVERWRITING = 0;
public static readonly int OVERWRITE = 1 * (int)Math.Pow(3, OVERWRITING);
public static readonly int NO_OVERWRITE = 2 * (int)Math.Pow(3, OVERWRITING);
public const int NULLISH = 1;
public static readonly int ALLOW_NULLS = 1 * (int)Math.Pow(3, NULLISH);
public static readonly int NO_NULLS = 2 * (int)Math.Pow(3, NULLISH);
public static readonly Options DEFAULT = new Options(NO_OVERWRITE + ALLOW_NULLS);
public static bool? get(int value, int option){
int ternary = value / (int)Math.Pow(3, option) % 3;
return (
ternary == 1 ? true :
ternary == 2 ? false :
null);
}
public bool? overwrite = null;
public bool? allow_null = null;
public Options(int value = 0, Options? _default = null){
if(_default == null)
_default = DEFAULT;
overwrite = get(value, OVERWRITING) ?? _default?.overwrite;
allow_null = get(value, NULLISH) ?? _default?.allow_null;
}
public int get(){
int code = 0;
foreach(KeyValuePair<int, bool?> pair in new Dictionary<int, bool?>{
{OVERWRITING, overwrite},
{NULLISH, allow_null}
})
code += (
pair.Value == true ? 1 :
pair.Value == false ? 2 :
0) * (int)Math.Pow(3, pair.Key);
return code;
}
}
}

7
CSharp/Utils/Patterns.cs Executable file
View File

@ -0,0 +1,7 @@
using System.Text.RegularExpressions;
namespace AnP.Utils{
public class RE{
public static readonly Regex KEY = new Regex(@"^[a-z_][a-z0-9_]*$", RegexOptions.IgnoreCase);
}
}

5
DotNET/Dockerfile Normal file
View File

@ -0,0 +1,5 @@
from mcr.microsoft.com/dotnet/sdk:10.0
env dotnet_cli_telemetry_output=1
run apt update && apt install -y procps build-essential cmake g++ gdb git
run rm -rf /var/lib/apt/lists/*
workdir /workspace

4
DotNET/docker.rebuild.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
directory=`dirname $(readlink -f "$0")`
[ "$(docker images -q anp:dotnet 2>/dev/null)" ] && docker image remove anp:dotnet --force
docker build -f $directory/Dockerfile -t anp:dotnet $directory --no-cache

7
DotNET/scripts/entrypoint.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
trap "exit 0" INT TERM
while true; do
sleep 1 & wait $!
done

69
JSON/AnP.settings.json Normal file
View File

@ -0,0 +1,69 @@
{
"anp_start" : null,
"anp_show_building_message" : true,
"anp_show_built_message" : true,
"anp_show_starting_message" : true,
"anp_show_already_started_message" : true,
"anp_show_started_message" : true,
"anp_show_updating_message" : true,
"anp_show_updated_message" : true,
"anp_show_closing_message" : true,
"anp_show_already_closed_message" : true,
"anp_show_closed_message" : true,
"print_format" : "[{type}] {yyyy}{mm}{dd} {hh}:{ii}:{ss} [{line}]{file_relative}({method}): {message}",
"exception_format" : " '{file}({method})[{line}]'{lines}\n\n{message}",
"trace_line_format" : " [{i}] {trace_line}",
"autostart" : true,
"anp_end" : null,
"anp_print_types_manager_start" : null,
"default_print_types" : [
["#888", ["unkn", "unknown"]],
["#00F", ["info", "information", "default"]],
["#FF0", ["warn", "warning", "caution"]],
["#F00", ["erro", "err", "no", "x", "n", "error", "panic", "danger", "critical"]],
["#0F0", [" ok ", "ok", "yes", "y", "success", "done", "complete"]],
["#888", ["test", "debug", "trace", "debugging"]],
["#F00", ["exce", "except", "exception"]]
],
"anp_print_types_manager_show_building_message" : true,
"anp_print_types_manager_show_built_message" : true,
"anp_print_types_manager_show_starting_message" : true,
"anp_print_types_manager_show_already_started_message" : true,
"anp_print_types_manager_show_started_message" : true,
"anp_print_types_manager_show_updating_message" : true,
"anp_print_types_manager_show_updated_message" : true,
"anp_print_types_manager_show_closing_message" : true,
"anp_print_types_manager_show_already_closed_message" : true,
"anp_print_types_manager_show_closed_message" : true,
"anp_print_types_manager_end" : null,
"anp_settings_manager_start" : null,
"default_settings_files" : "JSON/AnP.settings.json",
"default_secrets_files" : "JSON/AnP.secrets.json",
"default_value" : null,
"allow_nulls" : true,
"default_text" : "",
"anp_settings_manager_show_building_message" : true,
"anp_settings_manager_show_built_message" : true,
"anp_settings_manager_show_starting_message" : true,
"anp_settings_manager_show_already_started_message" : true,
"anp_settings_manager_show_started_message" : true,
"anp_settings_manager_show_updating_message" : true,
"anp_settings_manager_show_updated_message" : true,
"anp_settings_manager_show_closing_message" : true,
"anp_settings_manager_show_already_closed_message" : true,
"anp_settings_manager_show_closed_message" : true,
"anp_settings_manager_add_show_ok" : false,
"anp_settings_manager_add_show_errors" : true,
"anp_settings_manager_add_check_errors" : true,
"anp_settings_manager_add_secrets_show_ok" : false,
"anp_settings_manager_add_secrets_show_errors" : true,
"anp_settings_manager_add_secrets_check_errors" : true,
"anp_settings_manager_get_show_ok" : false,
"anp_settings_manager_get_show_errors" : true,
"anp_settings_manager_get_check_errors" : true,
"anp_settings_manager_end" : null
}

View File

@ -0,0 +1,44 @@
{
"espanol" : {
"anp_start" : null,
"anp_building" : "La aplicación AnP se está construyendo...",
"anp_built" : "La aplicación AnP se ha construido.",
"anp_starting" : "La aplicación AnP se está iniciando...",
"anp_already_started" : "La aplicación AnP ya se ha iniciado.",
"anp_started" : "La aplicación AnP se ha iniciado.",
"anp_updating" : "La aplicación AnP se está actualizando...",
"anp_updated" : "La aplicación AnP se ha actualizado.",
"anp_closing" : "La aplicación AnP se está cerrando...",
"anp_already_closed" : "La aplicación AnP ya se ha cerrado.",
"anp_closed" : "La aplicación AnP se ha cerrado.",
"anp_end" : null,
"anp_print_types_manager_start" : null,
"anp_print_types_manager_building" : "El Administrador de Tipos de Impresión se está construyendo...",
"anp_print_types_manager_built" : "El Administrador de Tipos de Impresión se ha construido.",
"anp_print_types_manager_starting" : "El Administrador de Tipos de Impresión se está iniciando...",
"anp_print_types_manager_already_started" : "El Administrador de Tipos de Impresión ya se ha iniciado.",
"anp_print_types_manager_started" : "El Administrador de Tipos de Impresión se ha iniciado.",
"anp_print_types_manager_updating" : "El Administrador de Tipos de Impresión se está actualizando...",
"anp_print_types_manager_updated" : "El Administrador de Tipos de Impresión se ha actualizado.",
"anp_print_types_manager_closing" : "El Administrador de Tipos de Impresión se está cerrando...",
"anp_print_types_manager_already_closed" : "El Administrador de Tipos de Impresión ya se ha cerrado.",
"anp_print_types_manager_closed" : "El Administrador de Tipos de Impresión se ha cerrado.",
"anp_print_types_manager_end" : null,
"anp_settings_manager_start" : null,
"anp_settings_manager_building" : "El Administrador de Configuraciones se está construyendo...",
"anp_settings_manager_built" : "El Administrador de Configuraciones se ha construido.",
"anp_settings_manager_starting" : "El Administrador de Configuraciones se está iniciando...",
"anp_settings_manager_already_started" : "El Administrador de Configuraciones ya se ha iniciado.",
"anp_settings_manager_started" : "El Administrador de Configuraciones se ha iniciado.",
"anp_settings_manager_updating" : "El Administrador de Configuraciones se está actualizando...",
"anp_settings_manager_updated" : "El Administrador de Configuraciones se ha actualizado.",
"anp_settings_manager_closing" : "El Administrador de Configuraciones se está cerrando...",
"anp_settings_manager_already_closed" : "El Administrador de Configuraciones ya se ha cerrado.",
"anp_settings_manager_closed" : "El Administrador de Configuraciones se ha cerrado.",
"anp_settings_manager_end" : null
}
}

View File

@ -0,0 +1,190 @@
"use strict";
/**
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
*/
import {Utils} from "../Utils/Utils.ecma";
import {Check} from "../Utils/Check.ecma";
/**
* @abstract
* @class BaseAbstract
* @constructor
* @param {!any} base
* @param {!AnP} anp
* @param {!string} key
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @param {!Object.<string, any|null>} [print_options = {}]
* @returns {void}
* @access public
* @static
*/
export const BaseAbstract = (function(){
/**
* @callable base_abstract_callback_end
* @param {!boolean} ok
* @returns {boolean}
*/
/**
* @callable base_abstract_get_value
* @param {!(string|Array.<string>)} keys
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @param {?any} [default_value = null]
* @returns {any|null}
*/
/**
* @constructs BaseAbstract
* @param {!any} base
* @param {!AnP} anp
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @param {!string} key
* @param {!Object.<string, any|null>} [print_options = {}]
* @returns {void}
* @access private
* @static
*/
const BaseAbstract = function(base, anp, key, inputs = null, print_options = {}){
/** @type {BaseAbstract} */
const self = this;
/**
* @returns {boolean}
* @access public
*/
this._build = () => true;
/**
* @param {!string} type
* @param {!(string|Array.<string>)} message
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @param {!number} [i = 0]
* @returns {void}
* @access public
*/
this.print = (type, message, inputs = null, i = 0) => {
self.allow_print.message === false ||
anp.print(type, key + "_" + message, [print_options, inputs], i + 1);
};
/**
* @returns {void}
* @private
*/
const constructor = () => {
/** @type {base_abstract_get_value} */
const get_value = anp.settings ? anp.settings.get : Utils.get_value;
/** @type {Object.<string, boolean>} */
this.allow_print = [
"building", "built",
"starting", "started", "already_started",
"closing", "closed", "already_closed"
].reduce((item, action) => {
item[key] = get_value(key + "_print_" + action + "_message", inputs, true);
return item;
}, {});
self.print("info", "building");
this.key = key;
/** @type {boolean} */
this.started = false;
/** @type {boolean} */
this.closed = true;
self.extends(base);
self._build();
self.print("ok", "built");
};
/**
* @param {!any} item
* @returns {void}
* @access public
*/
this.extends = item => {
Utils.extends(self, item);
};
/**
* @param {?base_abstract_callback_end} [callback = null]
* @returns {boolean}
* @access public
*/
this._start = (callback = null) => Check.is_function(callback) ? callback(true) : true;
/**
* @param {?base_abstract_callback_end} [callback = null]
* @returns {boolean}
* @access public
*/
this.start = (callback = null) => {
/** @type {base_abstract_callback_end} */
const end = ok => Check.is_function(callback) ? callback(ok) : ok;
self.print("info", "starting");
if(self.started){
self.print("warn", "already_started");
return end(false);
};
self.started = true;
return self._start(ok => {
self.closed = false;
self.print("ok", "started");
return end(ok);
});
};
/**
* @param {?base_abstract_callback_end} [callback = null]
* @returns {boolean}
* @access public
*/
this._close = (callback = null) => Check.is_function(callback) ? callback(true) : true;
/**
* @param {?base_abstract_callback_end} [callback = null]
* @returns {boolean}
* @access public
*/
this.close = (callback = null) => {
/** @type {base_abstract_callback_end} */
const end = ok => Check.is_function(callback) ? callback(ok) : ok;
self.print("info", "closing");
if(self.closed){
self.print("warn", "already_closed");
return end(false);
};
self.closed = true;
return self._close(ok => {
self.started = false;
self.print("ok", "closed");
return end(ok);
});
};
constructor();
};
return BaseAbstract;
})();

View File

@ -0,0 +1,67 @@
"use strict";
import {I18NManager} from "../Managers/I18NManager.ecma.js";
import {SettingsManager} from "../Managers/SettingsManager.ecma.js";
import {Components} from "./Components.ecma.js";
import {FilesDriver} from "../Drivers/FilesDriver.ecma.js";
/**
* @class AnP
* @constructor
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @returns {void}
* @access public
* @static
*/
export const AnP = (function(){
/**
* @constructs AnP
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @returns {void}
* @access private
* @static
*/
const AnP = function(inputs = null){
/** @type {AnP} */
const self = this;
/** @type {boolean} */
let started = false,
/** @type {boolean} */
closed = false;
/** @type {SettingsManager}*/
this.settings = new SettingsManager(self, inputs);
/** @type {I18NManager}*/
this.i18n = new I18NManager(self);
/** @type {Components} */
this.comp = this.components = new Components(self);
/** @type {FilesDriver} */
this.files = new FilesDriver(self);
/**
* @returns {void}
* @access private
*/
const constructor = () => {};
this.start = (callback = null) => {};
/**
* @param {!any} module
* @returns {void}
* @access public
*/
this.extends = module => {
for(const key in self)
module[key] === undefined &&
(module[key] = self[key]);
};
constructor();
};
return AnP;
})();

View File

@ -0,0 +1,412 @@
"use strict";
import {Check} from "../Utils/Check.ecma.js";
/**
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
*/
/**
* @class Components
* @constructor
* @param {!AnP} anp
* @returns {void}
* @access public
* @static
*/
export const Components = (function(){
/**
* @callback components_event_callback
* @param {!HTMLElement} item
* @param {!Event} event
* @returns {boolean|void}
*/
/**
* @constructs Components
* @param {!AnP} anp
* @returns {void}
* @access private
* @static
*/
const Components = function(anp){
/** @type {Components} */
const self = this;
/**
* @returns {void}
* @access private
*/
const constructor = () => {};
/**
* @param {!(string|Array.<string>)} i18n
* @param {!string} [tag = "span"]
* @param {?string} [_default = null]
* @returns {[string, Object.<string, string>, string]}
* @access public
*/
this.i18n = (i18n, tag = "span", _default = null) => [tag, {data_i18n : i18n}, anp.i18n.get(i18n, null, _default)];
/**
* @param {!string} name
* @param {!string} [tag = "span"]
* @returns {[string, Object.<string, string>]}
* @access public
*/
this.icon = (name, tag = "span") => [tag, {data_icon : name}];
/**
* @param {!string} name
* @param {?components_event_callback} [on_click = null]
* @param {!string} [type = "button"]
* @param {?string} [default_text = null]
* @returns {[string, Object.<string, (string|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
* @access public
*/
this.button = (name, on_click = null, type = "button", default_text) => ["button", {
type : type,
data_i18n : name,
data_i18n_without : true,
title : anp.i18n.get(name, null, default_text),
...(on_click ? {on_click : on_click} : {})
}, [
self.icon(name),
self.i18n(name, "span", default_text)
]];
/**
* @param {!string} type
* @param {!string} name
* @param {!boolean} checked
* @param {?components_event_callback} on_change
* @param {?string} default_text
* @param {!boolean} [role_button = false]
* @returns {[string, Object.<string, (string|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
* @access private
*/
const select_item = (type, name, checked, on_change, default_text, role_button = false) => {
/** @type {string} */
const id = name.slice(-2) == "[]" ? anp.identifiers.get() : name;
return ["label", {
for : id,
class : type + "-input",
data_i18n : name,
data_i18n_without : true,
title : anp.i18n.get(name, null, default_text),
...(role_button ? {role : "button"} : {})
}, [
["input", {
type : type,
id : id,
name : name,
...(on_change ? {on_change : on_change} : {}),
...(checked ? {checked : "checked"} : {})
}],
self.icon(type, "span"),
self.i18n(name, "span", default_text)
]];
};
/**
* @param {!string} name
* @param {!boolean} [checked = false]
* @param {?components_event_callback} [on_change = null]
* @param {?string} [default_text = null]
* @param {!boolean} [role_button = false]
* @returns {[string, Object.<string, (string|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
*/
this.checkbox = (name, checked = false, on_change = null, default_text, role_button = false) => (
select_item("checkbox", name, checked, on_change, default_text, role_button)
);
/**
* @param {!string} name
* @param {!boolean} [checked = false]
* @param {?components_event_callback} [on_change = null]
* @param {?string} [default_text = null]
* @returns {[string, Object.<string, (string|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
*/
this.radio = (name, checked = false, on_change = null, default_text) => (
select_item("radio", name, checked, on_change, default_text)
);
/**
* @param {!string} name
* @param {?number} [value = null]
* @param {?number} [minimum = null]
* @param {?number} [maximum = null]
* @param {?number} [step = null]
* @param {?components_event_callback} [on_change = null]
* @param {?string} [default_text = null]
* @returns {[string, Object.<string, (string|number|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
* @access public
*/
this.number = (name, value = null, minimum = null, maximum = null, step = null, on_change = null, default_text) => {
/** @type {string} */
const text = anp.i18n.get(name, null, default_text);
return ["label", {
for : name,
class : "number-input",
data_i18n : name,
data_i18n_without : true,
title : text,
}, [
["input", {
type : "number",
id : name,
name : name,
...(value !== null ? {value : value} : {}),
...(minimum !== null ? {min : minimum} : {}),
...(maximum !== null ? {max : maximum} : {}),
...(step !== null ? {step : step} : {}),
...(on_change ? {on_change : on_change} : {}),
data_i18n : name,
data_i18n_without : true,
placeholder : text + "..."
}],
["span", {class : "minimum"}, minimum || "-∞"],
["span", {class : "maximum"}, maximum || "∞"]
]];
};
/**
* @param {!string} type
* @param {!string} name
* @param {?string} [value = null]
* @param {?number} [maximum_length = null]
* @param {?string} [pattern = null]
* @param {?components_event_callback} [on_change = null]
* @param {?string} [default_text = null]
* @returns {[string, Object.<string, (string|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
* @access private
*/
const text = (type, name, value = null, maximum_length = null, pattern = null, on_change = null, default_text = null) => {
/** @type {string} */
const text = anp.i18n.get(name, null, default_text);
return ["label", {
for : name,
class : "input-" + type
}, [
["input", {
type : type,
id : name,
name : name,
...(value !== null ? {value : value} : {}),
...(pattern !== null ? {pattern : pattern} : {}),
...(on_change ? {on_input : on_change} : {}),
data_i18n : name,
data_i18n_without : true,
placeholder : text + "..."
}],
["span", {class : "length"}, 0],
...(maximum_length ? [["span", {class : "maximum-length"}, maximum_length || "∞"]] : [])
]];
};
/**
* @param {!string} name
* @param {?string} [value = null]
* @param {?number} [maximum_length = null]
* @param {?string} [pattern = null]
* @param {?components_event_callback} [on_change = null]
* @param {?string} [default_text = null]
* @returns {[string, Object.<string, (string|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
* @access public
*/
this.text = (name, value = null, maximum_length = null, pattern = null, on_change = null, default_text = null) => (
text("text", name, value, maximum_length, pattern, on_change, default_text)
);
/**
* @param {!string} name
* @param {?string} [value = null]
* @param {?number} [maximum_length = null]
* @param {?string} [pattern = null]
* @param {?components_event_callback} [on_change = null]
* @param {?string} [default_text = null]
* @returns {[string, Object.<string, (string|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
* @access public
*/
this.password = (name, value = null, maximum_length = null, pattern = null, on_change = null, default_text = null) => (
text("password", name, value, maximum_length, pattern, on_change, default_text)
);
/**
* @param {...[string, components_event_callback|null, string, string|null]} buttons
* @returns {[string, Object.<string, string>, Array.<(string|[string, Object.<string, string>, string])>]}
* @access public
*/
this.buttons = (...buttons) => ["div", {class : "buttons"}, buttons.map(button => self.button(...button))];
/**
* @param {!string} name
* @param {...any} items
* @returns {[string, Object.<string, string>, Array.<(string|[string, Object.<string, string>, string])>]}
*/
this.group = (name, ...items) => ["div", {
class : "group",
data_i18n : name,
data_i18n_without : true,
title : anp.i18n.get(name)
}, items];
/**
* @param {!string} name
* @param {!Array.<any|null>} structure
* @param {?components_event_callback} on_submit
* @param {...(components_event_callback|null)} [extra_actions]
* @returns {[string, Object.<string, (string|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
* @access public
*/
this.form = (name, structure, on_submit, ...extra_actions) => ["form", {
class : "form",
data_name : name,
method : "get",
action : "#",
...(on_submit ? {on_submit : on_submit} : {})
}, [
["fieldset", {}, [
self.i18n(name, "legend"),
self.i18n(name + "_text", "p"),
["div", {class : "structure"}, structure.map(([type, name, ...item], i) => {
return ["div", {
data_i : i,
data_type : type,
data_i18n : name,
data_i18n_without : true,
title : anp.i18n.get(name, null, item[1] || name)
}, [
["label", {for : name}, [
self.i18n(name),
self.i18n(name + "_description")
]],
["span", {class : "input"}, self[type] ? [self[type](name, ...item)] : item],
["ul", {class : "errors"}]
]];
})],
["ul", {class : "form-errors"}],
self.buttons(
["clean", null, "clean"],
...extra_actions,
on_submit ? ["submit", null, "submit"] : null
)
]]
]];
/**
* @param {!HTMLElement} form
* @returns {HTMLFormElement|null}
* @access public
*/
this.get_form = form => {
if(form)
while(form.tagName.toLowerCase() != "form" && (form = form.parentNode));
return form;
};
/**
* @param {!HTMLElement} form
* @returns {Object.<string, (string|number|boolean|Array.<(string|number|boolean)>)>}
* @access public
*/
this.get_form_data = form => (
[...self.get_form(form).querySelectorAll("[name]")].reduce((data, item) => {
/** @type {string} */
let name_value = item.getAttribute("name");
/** @type {string} */
const name = name_value.replace(/\[\]$/i, ""),
/** @type {boolean} */
is_array = name_value != name;
is_array && !(name in data) && (data[name] = []);
switch(item.getAttribute("type")){
case "radio":
data[name] == [] && (data[name] = false);
item.checked && (data[name] = Number(item.value));
break;
case "checkbox":
if(is_array)
data[name].push(item.checked);
else
data[name] = item.checked;
break;
case "number":
if(is_array)
data[name].push(Number(item.value));
else
data[name] = Number(item.value);
break;
default:
if(is_array)
data[name].push(item.value);
else
data[name] = item.value;
break;
};
return data;
}, {})
);
/**
* @param {!(string|Array.<string>)} sources
* @param {?(string|Array.<string>)} [i18n = null]
* @param {?string} [default_text = null]
* @returns {[string, Object.<string, (string|number|function)>, (string|[string, Object.<string, string>, string])>]}
* @access public
*/
this.image = (sources, i18n = null, default_text = null) => {
/** @type {number} */
let i = 0;
Check.is_array(sources) || (sources = [sources]);
return ["span", {
class : "image",
data_status : "loading",
...(
i18n ? {data_i18n : i18n, title : anp.i18n.get(i18n, null, default_text)} :
default_text ? {title : default_text} :
{}),
}, [
["img", {
src : sources[i],
...(
i18n ? {data_i18n : i18n, alt : anp.i18n.get(i18n, null, default_text)} :
default_text ? {alt : default_text} :
{}),
on_error : (image, event) => {
if(i >= sources.length)
image.parentNode.setAttribute("data-status", "error");
else
image.parentNode.setAttribute("src", sources[++ i]);
},
on_load : (image, event) => {
image.parentNode.setAttribute("data-status", "loaded");
image.parentNode.querySelector("span").style.backgroundImage = "url('" + sources[i] + "')";
}
}],
["span"]
]];
};
constructor();
};
return Components;
})();

View File

@ -0,0 +1,155 @@
"use strict";
/**
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
*/
/**
* @class FilesDriver
* @constructor
* @param {!AnP} anp
* @returns {void}
* @access public
* @static
*/
export const FilesDriver = (function(){
/**
* @callback files_driver_start_callback
* @param {!boolean} ok
* @returns {boolean}
*/
/**
* @constructs FilesDriver
* @param {!AnP} anp
* @returns {void}
* @access private
* @static
*/
const FilesDriver = function(anp){
/** @type {FilesDriver} */
const self = this;
/** @type {boolean} */
let started = false,
/** @type {boolean} */
closed = false,
/** @type {string} */
default_http_method = "GET",
/** @type {boolean} */
default_http_asynchronous = true,
/** @type {number} */
default_timeout = 2000;
/**
* @returns {void}
* @access private
*/
const constructor = () => {
self.update();
};
/**
* @param {?files_driver_start_callback} [callback = null]
* @returns {boolean}
* @access public
*/
this.update = (callback = null) => {
default_http_method = anp.settings.get([
"http_method", "default_http_method"
], null, default_http_method);
default_http_asynchronous = anp.settings.get([
"http_asynchronous", "default_http_asynchronous"
], null, default_http_asynchronous);
default_timeout = anp.settings.get([
"timeout", "default_timeout"
], null, default_timeout);
Utils.execute(callback);
return true;
};
/**
* @param {?files_driver_start_callback} [callback = null]
* @returns {boolean}
* @access public
*/
this.start = (callback = null) => {
if(started){
return false;
};
started = true;
self.update(callback);
return true;
};
this.load = (path, callback = null, inputs = null) => {
/** @type {boolean} */
let ended = false,
/** @type {number} */
error = 0;
/** @type {XMLHttpRequest} */
const ajax = new XMLHttpRequest(),
/** @type {number} */
timeout = Utils.get_value([
"timeout", "ajax_timeout", "default_timeout"
], inputs, default_timeout),
/** @type {number} */
date = Date.now(),
end = code => {
code && (error |= 1 << code);
!ended && (ended = true) &&
Utils.execute(
callback,
ajax.responseText,
ajax.status,
ajax.readyState,
error,
error === 0
);
};
ajax.open(
Utils.get_value([
"method", "http_method", "default_http_method"
], inputs, default_http_method),
path,
Utils.get_value([
"asynchronous", "http_asynchronous", "default_http_asynchronous"
], inputs, default_http_asynchronous)
);
ajax.timeout = timeout;
ajax.onreadystatechange = function(){
if(ended)
return;
if(ajax.readyState === 4)
end((
ajax.status >= 200 && ajax.status < 300
) || [301, 302, 304].includes(ajax.status) ? 0 : 1);
else if(Date.now() - date >= timeout)
end(2);
};
ajax.send(null);
ajax.onerror = () => {end(3);}
ajax.onabort = () => {end(4);}
ajax.ontimeout = () => {end(5);}
return ajax;
};
constructor();
};
return FilesDriver;
})();

View File

@ -0,0 +1,139 @@
"use strict";
import {Check} from "../Utils/Check.ecma.js";
import {Utils} from "../Utils/Utils.ecma.js";
/**
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
*/
/**
* @class I18NManager
* @constructor
* @param {!AnP} anp
* @returns {void}
* @access public
* @static
*/
export const I18NManager = (function(){
/**
* @callback i18n_manager_default_callback
* @returns {void}
*/
/**
* @constructs I18NManager
* @param {!AnP} anp
* @returns {void}
* @access private
* @static
*/
const I18NManager = function(anp){
/** @type {I18NManager} */
const self = this,
/** @type {Object.<string, Object.<string, string|Array.<string>>} */
sentences = {};
/** @type {string} */
let language_selected = "espanol",
/** @type {string} */
default_language = "espanol";
/**
* @returns {void}
* @access private
*/
const constructor = () => {
language_selected = anp.settings.get(["language_selected", "default_language"], null, language_selected);
default_language = anp.settings.get(["default_language", "language_selected"], null, default_language);
};
/**
* @param {?i18n_manager_default_callback} [callback = null]
* @returns {void}
* @access public
*/
this.start = (callback = null) => {
Utils.execute_array([
"default_i18n_files", "i18n_files"
], (key, next_callback) => {
self.add(anp.settings.get(key), next_callback, true);
}, callback);
};
/**
* @param {!(string|Array.<string>)} texts
* @param {?(Object.<string, any|null>|Array.<any|null>)} [variables = null]
* @param {?any} [_default = null]
* @returns {string|null}
* @access public
*/
this.get = (texts, variables = null, _default = null) => {
/** @type {string|Array.<string>|null} */
let text = null;
/** @type {Array.<string>} */
const used = [],
/** @type {Array.<string>} */
languages = [language_selected, default_language].concat(Object.keys(sentences)),
/** @type {Array.<string>} */
keys = Utils.get_keys(texts);
if(keys.length)
for(const language of languages){
if(!used.includes(language) && sentences[language])
for(const key of keys){
if(sentences[language][key] !== undefined){
text = sentences[language][key];
break;
};
};
if(text !== undefined)
break;
used.push(language);
};
text === null && (text = (
_default !== null ? _default :
texts !== null ? (
Check.is_string(texts) ? texts :
Check.is_array(texts) && texts.length ? texts[0] :
null) :
null))
return Utils.string_variables((
Check.is_array(text) ? text.join("") :
text), variables, _default);
};
/**
* @param {!(Object.<string, Object.<string, string|Array.<string>|null>>|Array.<any|null>|string)} inputs
* @param {?i18n_manager_default_callback} [callback = null]
* @param {!boolean} [overwrite = false]
* @returns {void}
* @access public
*/
this.add = (inputs, callback = null, overwrite = false) => {
anp.load_json(inputs, (item, next_callback) => {
for(const language in item){
sentences[language] || (sentences[language] = {});
for(const key in item[language])
(overwrite || Check.is_null_or_undefined(sentences[language][key])) &&
(sentences[language][key] = item[language][key]);
};
next_callback();
}, callback, true);
};
constructor();
};
/** @type {Object.<string, any|null>} */
I18NManager.DEFAULT_SETTINGS = {};
return I18NManager;
})();

View File

@ -0,0 +1,89 @@
"use strict";
import {Utils} from "../Utils/Utils.ecma.js";
/**
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
*/
/**
* @class IdentifiersManager
* @constructor
* @param {!AnP} anp
* @returns {void}
* @access public
* @static
*/
export const IdentifiersManager = (function(){
/**
* @constructs IdentifiersManager
* @param {!AnP} anp
* @returns {void}
* @access private
* @static
*/
const IdentifiersManager = function(anp){
/** @type {IdentifiersManager} */
const self = this,
/** @type {Array.<string>} */
identifiers = [];
/** @type {Array.<string>|string} */
let alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
/** @type {number} */
length = 11;
/**
* @returns {void}
* @access private
*/
const constructor = () => {
alphabet = anp.settings.get(["identifiers_alphabet", "default_identifiers_alphabet"], null, alphabet);
length = anp.settings.get(["identifiers_length", "default_identifiers_length"], null, length);
};
/**
* @param {!(string|Array.<string>)} keys
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @param {?any} [_default = null]
* @returns {any|null}
* @access public
*/
this.get = () => {
/** @type {string} */
let identifier;
do{
identifier = "";
while((identifier += Utils.get_random(alphabet)).length < length);
}while(
identifiers.includes(identifier) ||
/^[^a-z]/i.test(identifier) ||
document.querySelector("." + identifier + ",#" + identifier + ",[name=" + identifier + "]")
);
identifiers.push(identifier);
return identifier;
};
/**
* @param {!string} identifier
* @returns {void}
*/
this.remove = identifier => {
identifier in identifiers && identifiers.splice(identifiers.indexOf(identifier), 1);
};
constructor();
};
/** @type {Object.<string, any|null>} */
IdentifiersManager.DEFAULT_SETTINGS = {};
return IdentifiersManager;
})();

View File

@ -0,0 +1,135 @@
"use strict";
import {Utils} from "../Utils/Utils.ecma.js";
/**
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
*/
/**
* @class SettingsManager
* @constructor
* @param {!AnP} anp
* @param {?(Object.<string, any|null>|Array.<any|null>)} customs
* @returns {void}
* @access public
* @static
*/
export const SettingsManager = (function(){
/**
* @callback settings_manager_default_callback
* @returns {void}
*/
/**
* @constructs SettingsManager
* @param {!AnP} anp
* @param {?(Object.<string, any|null>|Array.<any|null>)} customs
* @returns {void}
* @access private
* @static
*/
const SettingsManager = function(anp, customs = null){
/** @type {SettingsManager} */
const self = this,
/** @type {Object.<string, any|null>} */
settings = {},
/** @type {Object.<string, any|null>} */
secrets = {};
/**
* @returns {void}
* @access private
*/
const constructor = () => {
customs = Utils.get_dictionary(customs);
};
/**
* @param {?settings_manager_default_callback} [callback = null]
* @returns {void}
* @access public
*/
this.start = (callback = null) => {
Utils.execute_array([
"default_settings_files", "settings_files"
], (key, next_callback) => {
self.add(self.get(key), next_callback, true);
}, () => {
Utils.execute_array([
"default_secrets_files", "secrets_files"
], (key, next_callback) => {
self.add_secrets(self.get(key), next_callback, true);
}, callback);
});
};
/**
* @param {!(string|Array.<string>)} keys
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @param {?any} [_default = null]
* @returns {any|null}
* @access public
*/
this.get = (keys, inputs = null, _default = null) => (
Utils.get_value(keys, [inputs, customs, secrets, settings, SettingsManager.DEFAULT_SETTINGS], _default)
);
/**
* @param {!(Object.<string, Object.<string, string|Array.<string>|null>>|Array.<any|null>|string)} inputs
* @param {?i18n_manager_default_callback} callback
* @param {!boolean} overwrite
* @returns {void}
* @access public
*/
this.add = (inputs, callback = null, overwrite = false) => {
anp.load_json(inputs, (item, next_callback) => {
for(key in item)
(overwrite || Check.is_null_or_undefined(settings[key])) &&
(settings[key] = item[key]);
next_callback();
}, callback, true);
};
/**
* @param {!(Object.<string, any|null>|Array.<any|null>|string)} inputs
* @param {?settings_manager_default_callback} [callback = null]
* @param {!boolean} [overwrite = false]
* @returns {void}
* @access public
*/
this.add_secrets = (inputs, callback = null, overwrite = false) => {
anp.load_json(inputs, (item, next_callback) => {
for(const key in item)
(overwrite || Check.is_null_or_undefined(secrets[key])) &&
(secrets[key] = item[key]);
next_callback();
}, callback, true);
};
constructor();
};
/** @type {Object.<string, any|null>} */
SettingsManager.DEFAULT_SETTINGS = {
/** @type {Array.<string>|string|Object.<string, any|null>} */
default_settings_files : ["/json/AnP.settings.json"],
/** @type {Array.<string>|string|Object.<string, any|null>} */
default_secrets_files : ["/json/AnP.secrets.json"],
/** @type {Array.<string>|string|Object.<string, any|null>} */
default_i18n_files : [
"/json/i18n/AnP.i18n.espanol.json",
"/json/i18n/AnP.i18n.galego.json",
"/json/i18n/AnP.i18n.english.json"
],
/** @type {Array.<string>|string|Object.<string, any|null>} */
default_database_files : ["/json/database.json"],
};
return SettingsManager;
})();

View File

@ -0,0 +1,102 @@
"use strict";
import {RE} from "./Patterns.ecma.js";
/**
* @class Check
* @constructor
* @returns {void}
* @access public
* @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 => item && Check.is_string(item) && RE.KEY.test(item);
/**
* @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_dictionary = item => item && item.constructor == Object;
/**
* @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_html_item = item => item && (item.tagName || item.nodeName);
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Check.is_number = item => typeof item == "number";
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Check.is_integer = item => Check.is_number(item) && item == item >> 0;
/**
* @returns {boolean}
* @access public
* @static
*/
Check.is_dark_mode = () => !!window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Check.is_null_or_undefined = item => item === null || item === undefined;
return Check;
})();

View File

@ -0,0 +1,113 @@
"use strict";
/**
* @class Options
* @constructor
* @returns {void}
* @access public
* @static
*/
export const Options = (function(){
/**
* @constructs Options
* @returns {void}
* @access private
* @static
*/
const Options = function(options, _default = null){
/** @type {Options} */
const self = this;
/** @type {boolean|null} */
this.overwrite = null;
/** @type {boolean|null} */
this.allow_nulls = null;
/**
* @returns {void}
* @access private
*/
const constructor = () => {
_default || (_default = Options.DEFAULT);
[
["overwrite", Options.OVERWRITE],
["allow_nulls", Options.NULLISH]
].forEach(([key, option]) => {
/** @type {boolean|null} */
const value = Options.get_value(options, option);
self[key] = value !== null ? value : _default[key];
});
};
/**
* @returns {number}
* @access public
*/
this.get = () => {
/** @type {number} */
let code = 0;
[
[Options.OVERWRITING, self.overwrite],
[Options.NULLISH, self.allow_nulls],
].forEach(([option, value]) => {
code += (
value ? 1 :
value === false ? 2 :
0) * 3 ** option;
});
return code;
};
constructor();
};
/** @type {number} */
Options.OVERWRITING = 0;
/** @type {number} */
Options.OVERWRITE = 1 + 3 * Options.OVERWRITING;
/** @type {number} */
Options.NO_OVERWRITE = 2 + 3 * Options.OVERWRITING;
/** @type {number} */
Options.NULLISH = 1;
/** @type {number} */
Options.ALLOW_NULLS = 1 + 3 * Options.NULLISH;
/** @type {number} */
Options.NOT_NULLS = 2 + 3 * Options.NULLISH;
/** @type {Options} */
Options.DEFAULT = new Options(Options.NO_OVERWRITE | Options.ALLOW_NULLS);
/**
* @param {!number} value
* @param {!number} option
* @returns {boolean|null}
* @access public
* @static
*/
Options.get_value = (value, option) => {
/** @type {number} */
const ternary = (value / 3 ** option >> 0) % 3;
return (
ternary === 1 ? true :
ternary === 2 ? false :
null
);
}
return Options;
})();

View File

@ -0,0 +1,24 @@
"use strict";
/**
* @class RE
* @constructor
* @returns {void}
* @access public
* @static
*/
export const RE = (function(){
/**
* @constructs RE
* @returns {void}
* @access private
* @static
*/
const RE = function(){};
/** @type {RegExp} */
RE.KEY = /^[a-z_][a-z0-9_]*$/i;
return RE;
})();

View File

@ -0,0 +1,404 @@
"use strict";
import {Check} from "./Check.ecma.js";
import {Options} from "./Options.ecma.js";
/**
* @class Utils
* @constructor
* @returns {void}
* @access public
* @static
*/
export const Utils = (function(){
/**
* @callback utils_execute_callback
* @param {...(any|null)} inputs
* @returns {any|null}
*/
/**
* @callback utils_default_callback
* @returns {void}
*/
/**
* @callback utils_execute_array_each_callback
* @param {?any} item
* @param {!utils_default_callback} callback
* @returns {void}
*/
/**
* @constructs Utils
* @returns {void}
* @access private
* @static
*/
const Utils = function(){};
/** @type {Options} */
Utils.GET_DICTIONARY_OPTIONS = new Options(Options.NO_OVERWRITE);
/** @type {Options} */
Utils.GET_VALUE_OPTIONS = new Options(Options.ALLOW_NULLS);
/** @type {string} */
Utils.BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
/** @type {string} */
Utils.RANDOM_ALPHABET = "bHMnuamw/RUBk+xNvCXghsPdlSFG12rLoT0O3VZ=5QeWyI8pADqjcEfJ9Kt64i7Yz";
/**
* @param {...(any|null)} items
* @returns {Array<string>}
* @access public
* @static
*/
Utils.get_keys = (...items) => items.reduce((keys, item) => {
if(Check.is_key(item))
item in keys || keys.push(item);
else if(Check.is_array(item))
Utils.get_keys(...item).forEach(key => key in keys || keys.push(key));
return keys;
}, []);
/**
* @param {...(any|null)} items
* @returns {Array.<Object.<string, any|null>>}
* @access public
* @static
*/
Utils.get_dictionaries = (...items) => items.reduce((dictionaries, item) => {
if(Check.is_dictionary(item))
dictionaries.push(item);
else if(Check.is_array(item))
dictionaries.push(...Utils.get_dictionaries(...item));
return dictionaries;
}, []);
/**
* @param {?any} items
* @param {!number} [custom_options = 0]
* @returns {Object.<string, any|null>}
* @access public
* @static
*/
Utils.get_dictionary = (items, custom_options = 0) => {
/** @type {Object.<string, any|null>} */
const dictionary = {},
/** @type {Options} */
options = new Options(custom_options, Utils.GET_DICTIONARY_OPTIONS);
if(Check.is_dictionary(items)){
for(const [key, value] of Object.entries(items))
dictionary[key] = value;
}else if(Check.is_array(items))
items.forEach(item => {
for(const [key, value] of Object.entries(Utils.get_dictionary(item, options)))
if(options.overwrite || !(key in dictionary))
dictionary[key] = value;
});
return dictionary;
}
/**
* @param {!(string|Array.<string>)} keys
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
* @param {?any} [_default = null]
* @param {!number} [custom_options = 0]
* @returns {any|null}
* @access public
* @static
*/
Utils.get_value = (keys, inputs, _default = null, custom_options = 0) => {
/** @type {number} */
const l = (keys = Utils.get_keys(keys)).length,
/** @type {Options} */
options = new Options(custom_options, Utils.GET_VALUE_OPTIONS);
if(l){
/** @type {number} */
const m = (inputs = Utils.get_dictionaries(inputs)).length;
for(let i = 0; i < l; i++)
for(let j = 0; j < m; j++)
if(keys[i] in inputs[j] && (options.allow_nulls || inputs[j][keys[i]] !== null))
return inputs[j][keys[i]];
};
return _default;
};
/**
* @param {!string} string
* @param {!(Object.<string, any|null>|Array.<any|null>)} variables
* @param {?any} _default
* @returns {string}
* @access public
* @static
*/
Utils.string_variables = (string, variables, _default = null) => {
variables = Utils.get_dictionary(variables || {});
return ("" + string).replace(/\{([a-z_][a-z0-9_]*)\}/gi, (all, key) => (
key in variables ? variables[key] :
_default === null ? all :
_default));
};
/**
* @param {!string} string
* @returns {string}
* @access public
* @static
*/
Utils.to_kebab_case = string => ("" + string).replace(/([A-Z]+)|[^a-z0-9]+/g, (_, upper) => (
upper ? "-" + upper.toLowerCase() :
"-"));
/**
* @param {!string} string
* @returns {string}
* @access public
* @static
*/
Utils.to_snake_case = string => ("" + string).replace(/([A-Z]+)|[^a-z0-9]+/g, (_, upper) => (
upper ? "_" + upper.toLowerCase() :
"_"));
/**
* @param {!HTMLElement} item
* @param {...Object.<string, any|null>} attributes
* @returns {void}
* @access public
* @static
*/
Utils.attributes = (item, attributes) => {
for(const [key, value] of Object.entries(attributes)){
if(/^on[_\-]?/i.test(key) && Check.is_function(value))
item.addEventListener(key.toLowerCase().replace(/^on[_\-]?/, ""), event => {
Utils.execute(value, item, event);
});
else
item.setAttribute(Utils.to_kebab_case(key), value);
};
};
/**
* @param {!HTMLElement} item
* @param {...(string|HTMLElement|[string, Object.<string, any|null>|null, string|Array.<string>|null]|null)} structure
* @returns {Array.<HTMLElement>}
* @access public
* @static
*/
Utils.html = (item, ...structure) => {
/** @type {Array.<HTMLElement>} */
const items = [];
item || (item = document.createDocumentFragment());
for(const node of structure)
if(Check.is_string(node))
item.innerHTML += node;
else if(Check.is_html_item(node))
items.push(item.appendChild(node));
else if(Check.is_array(node)){
/** @type {[string, Object.<string, any|null>|null, Array.<any|null>|null]} */
const [tag, attributes, children] = node.concat(null, null).slice(0, 3),
/** @type {HTMLElement} */
element = document.createElement(tag);
attributes && Utils.attributes(element, attributes);
if(children && children.length){
if(Check.is_string(children))
element.innerHTML += children;
else
Utils.html(element, ...children);
};
items.push(item.appendChild(element));
};
return items;
};
/**
* @param {?any} item
* @returns {any|null}
* @access public
* @static
*/
Utils.unique = item => (
Check.is_array(item) ? item.filter((item, i, array) => array.indexOf(item) == i) :
Check.is_string(item) ? item.split("").filter((char, i, array) => array.indexOf(char) == i).join("") :
item);
/**
* @param {?(number|Array.<any|null>|string)} [from = null]
* @param {?number} [to = null]
* @returns {any|null}
* @access public
* @static
*/
Utils.get_random = (from = null, to = null) => (
Check.is_array(from) || Check.is_string(from) ? from.length ? from[Math.random() * from.length >> 0] : null :
Check.is_integer(from) ? (
to === null ? Math.random() * from >> 0 :
Check.is_integer(to) ? from + (Math.random() * (to - from + 1) >> 0) :
Check.is_number(to) ? from + Math.random() * (to - from) :
null) :
Check.is_number(from) ? (
to === null ? Math.random() * from :
Check.is_number(to) ? from + Math.random() * (to - from) :
null) :
from === null ? Math.random() :
null);
/**
* @param {?any} data
* @returns {string}
* @access public
* @static
*/
Utils.encode_data = data => btoa(encodeURIComponent(JSON.stringify(data)).replace(/%([0-9A-F]{2})/g, (_, p1) => String.fromCharCode("0x" + p1)));
/**
* @param {!string} code
* @param {!boolean} [is_json = true]
* @returns {any|null}
* @access public
* @static
*/
Utils.decode_data = (code, is_json = true) => {
/** @type {string} */
const data = decodeURIComponent(atob(code).split("").map(c => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2)).join(""));
if(is_json)
try{
return JSON.parse(data) || data;
}catch(exception){};
return data;
};
/**
* @param {!utils_execute_callback} callback
* @param {...(any|null)} inputs
* @returns {any|null}
* @access public
* @static
*/
Utils.execute = (callback, ...inputs) => (
Check.is_function(callback) ? callback(...inputs) :
null);
/**
* @param {!Array.<any|null>} array
* @param {!utils_execute_array_each_callback} each_callback
* @param {?utils_default_callback} [end_callback = null]
* @param {!number} [i = 0]
* @returns {void}
* @access public
* @static
*/
Utils.execute_array = (array, each_callback, end_callback = null, i = 0) => {
if(i < array.length)
Utils.execute(each_callback, array[i], () => {
Utils.execute_array(array, each_callback, end_callback, i + 1);
});
else
Utils.execute(end_callback);
};
/**
* @param {?any} item
* @returns {Array.<any|null>}
* @access public
* @static
*/
Utils.get_array = item => Check.is_array(item) ? item : [item];
/**
* @param {!string} string
* @returns {string}
* @access public
* @static
*/
Utils.randomize_string = string => string.split("").sort(() => Utils.get_random() - 0.5).join("");
/**
* @param {?any} data
* @returns {string}
* @access public
* @static
*/
Utils.encrypt_data = data => Utils.encode_data(data).split("").map(character => Utils.RANDOM_ALPHABET[Utils.BASE64_ALPHABET.indexOf(character)]).join("");
/**
* @param {string} data
* @returns {any|null}
* @access public
* @static
*/
Utils.decrypt_data = data => {
/** @type {string} */
const results = Utils.decode_data(data.split("").map(character => Utils.BASE64_ALPHABET[Utils.RANDOM_ALPHABET.indexOf(character)]).join(""), false);
try{
return JSON.parse(results) || results;
}catch(exception){};
return results;
};
/**
* @param {!Array.<any|null>} array
* @returns {void}
* @access public
* @static
*/
Utils.randomize_array = array => {
/** @type {number} */
const l = array.length - 1;
array.forEach((item, i) => {
/** @type {number} */
const j = Utils.get_random(l);
i != j && ([array[i], array[j]] = [array[j], array[i]]);
});
};
/**
* @param {!any} base
* @param {...any} items
* @returns {void}
* @access public
* @static
*/
Utils.extends = (base, ...items) => {
items.forEach(item => {
Object.entries(item).forEach(([key, value]) => {
base[key] = value;
});
});
};
return Utils;
})();

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,3 @@
{
"espanol" : {}
}

View File

@ -0,0 +1,44 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Callable, Optional
from Interfaces.Application.AnPInterface import AnPInterface
class BaseAbstract:
def _build(self:Self) -> None:
pass
def __init__(self:Self, anp:AnPInterface, key:str) -> None:
self.anp:AnPInterface = anp
self.key:str = key
self._built:bool = False
self._started:bool = False
self._stopped:bool = False
self._build()
self._built = True
def _start(self:Self, callback:Optional[Callable[[bool], bool]] = None) -> bool:
pass
def start(self:Self, callback:Optional[Callable[[bool], bool]] = None) -> bool:
if self._started:
return False if callback is None else callback(False)
self._started = True
self._stopped = False
return True if callback is None else callback(True)
def _close(self:Self, callback:Optional[Callable[[bool], bool]] = None) -> bool:
pass
def close(self:Self, callback:Optional[Callable[[bool], bool]] = None) -> bool:
if self._stopped:
return False if callback is None else callback(False)
self._started = False
self._close(callback)
self._stopped = True
return True if callback is None else callback(True)

33
Python/Application/AnP.py Normal file
View File

@ -0,0 +1,33 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any, Optional, Sequence
from Managers.SettingsManager import SettingsManager
from Managers.I18NManager import I18NManager
from Managers.PrintTypesManager import PrintTypesManager
class AnP:
def __init__(self:Self,
inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None
) -> None:
self.i18n:I18NManager = I18NManager(self)
self.print_types:PrintTypesManager = PrintTypesManager(self)
self.settings:SettingsManager = SettingsManager(self, inputs)
def print(self:Self,
_type:str,
data:Any|None,
inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None,
i:int = 0
) -> None:
own:dict[str, Any|None] = {}
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

View File

@ -0,0 +1,31 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any, Optional, Sequence
from abc import ABC, abstractmethod
from Interfaces.Managers.SettingsManagerInterface import SettingsManagerInterface
from Interfaces.Managers.I18NManagerInterface import I18NManagerInterface
from Interfaces.Managers.PrintTypesManagerInterface import PrintTypesManagerInterface
class AnPInterface(ABC):
def __init__(self:Self, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
self.print_types:PrintTypesManagerInterface = None
self.i18n:I18NManagerInterface = None
self.settings:SettingsManagerInterface = None
@abstractmethod
def print(self:Self,
_type:str,
data:Any|None,
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

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Any, Self, Sequence, Optional
from abc import ABC, abstractmethod
class I18NManagerInterface(ABC):
@abstractmethod
def get(self:Self,
strings:str|Sequence[str],
inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None,
languages:Optional[str|Sequence[str]] = None,
custom_options:int = 0
) -> Any|None:pass
@abstractmethod
def add(self:Self, inputs:Any|None, custom_options:int = 0) -> None:pass

View File

@ -0,0 +1,13 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Any, Self
from abc import ABC, abstractmethod
class PrintTypesManagerInterface(ABC):
@abstractmethod
def get(self:Self, _type:str) -> str:pass
@abstractmethod
def add(self:Self, inputs:Any|None, custom_options:int = 0) -> None:pass

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Any, Self, Sequence, Optional
from abc import ABC, abstractmethod
class SettingsManagerInterface(ABC):
@abstractmethod
def get(self:Self,
keys:str|Sequence[str],
inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None,
default:Any|None = None,
custom_options:int = 0
) -> Any|None:pass
@abstractmethod
def add(self:Self, inputs:Any|None, custom_options:int = 0) -> None:pass

View File

@ -0,0 +1,72 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Any, Self, Sequence, Optional
from Interfaces.Application.AnPInterface import AnPInterface
from Utils.Utils import Utils
from Utils.Options import Options
class I18NManager:
DEFAULT_SENTENCES:dict[str, Any|None] = {
"english" : {}
}
GET_OPTIONS:Options = Options(Options.ALLOW_NULLS)
ADD_OPTIONS:Options = Options(Options.NO_OVERWRITE)
def __init__(self:Self, anp:AnPInterface) -> None:
self.anp:AnPInterface = anp
self.__sentences:dict[str, Any|None] = self.DEFAULT_SENTENCES
self.__language:str = "english"
self.__default_language:str = "english"
def __get_sentence(self:Self,
strings:str|Sequence[str],
languages:list[str],
options:Options
) -> str|list[str]|None:
keys:list[str] = Utils.get_keys(strings)
if len(keys):
languages_used:list[str] = []
language:str
for language in languages + [
self.__language, self.__default_language
] + list(self.__sentences.keys()):
if language in languages_used:
continue
key:str
languages_used.append(language)
for key in keys:
if key in self.__sentences[language] and (
options.allow_null or
self.__sentences[language][key] is not None
):
return self.__sentences[language][key]
return Utils.get_strings(strings)[0]
def get(self:Self,
strings:str|Sequence[str],
inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None,
languages:Optional[str|Sequence[str]] = None,
custom_options:int = 0
) -> Any|None:
options:Options = Options(custom_options, self.GET_OPTIONS)
text:str|list[str]|None = self.__get_sentence(strings, Utils.get_array(languages), options)
return Utils.string_variables((
text if isinstance(text, str) else
"".join(text) if isinstance(text, (list, tuple)) else
str(text)), inputs)
def add(self:Self, inputs:Any|None, custom_options:int = 0) -> None:
pass

View File

@ -0,0 +1,26 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Any, Self
from Interfaces.Application.AnPInterface import AnPInterface
from Models.PrintTypeModel import PrintTypeModel
class PrintTypesManager:
def __init__(self:Self, anp:AnPInterface) -> None:
self.anp:AnPInterface = anp
self.__print_types:list[PrintTypeModel] = [
PrintTypeModel(["unkn", "unknown"], "#888")
]
def get(self:Self, _type:str) -> str:
subset:list[str]
for subset in self.__print_types:
if _type in subset:
return subset[0]
return self.__print_types[0][0]
def add(self:Self, inputs:Any|None, custom_options:int = 0) -> None:
pass

View File

@ -0,0 +1,36 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Any, Self, Sequence, Optional
from Interfaces.Application.AnPInterface import AnPInterface
from Utils.Utils import Utils
from Utils.Options import Options
class SettingsManager:
DEFAUTL_SETTINGS:dict[str, Any|None] = {}
GET_OPTIONS:Options = Options(Options.ALLOW_NULLS)
ADD_OPTIONS:Options = Options(Options.NO_OVERWRITE)
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] = Utils.get_dictionary(inputs, Options.OVERWRITE)
self.__secrets:dict[str, Any|None] = {}
def get(self:Self,
keys:str|Sequence[str],
inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None,
default:Any|None = None,
custom_options:int = 0
) -> Any|None:
return Utils.get_value(keys, (
inputs, self.__inputs, self.__secrets, self.DEFAUTL_SETTINGS
), default, Options(custom_options, self.GET_OPTIONS).get())
def add(self:Self, inputs:Any|None, custom_options:int = 0) -> None:
pass

View File

@ -0,0 +1,30 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Optional, Self, Sequence
from Utils.Color import Color
from Utils.Utils import Utils
class PrintTypeModel:
def __init__(self:Self,
names:str|Sequence[str],
fore:str|int|Sequence[int]|Color,
back:Optional[str|int|Sequence[int]|Color] = None
) -> None:
self.names:list[str] = []
self.name:str
self.fore:Color = Color(fore)
self.back:Color|None = None if back is None else Color(back)
self.add_names(names)
self.name = self.names[0].upper()
def add_names(self:Self, names:str|Sequence[str]) -> None:
name:str
for name in Utils.get_keys(names, self.names):
if name not in self.names:
self.names.append(name)

27
Python/Utils/Check.py Normal file
View File

@ -0,0 +1,27 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Any, Self
from Utils.Patterns import RE
class Check:
@staticmethod
def is_string(value:Any|None) -> bool:
return isinstance(value, str)
@classmethod
def is_key(cls:type[Self], value:Any|None) -> bool:
return cls.is_string(value) and RE.KEY.match(value) is not None
@staticmethod
def is_array(value:Any|None) -> bool:
return isinstance(value, (list, tuple))
@staticmethod
def is_dictionary(value:Any|None) -> bool:
return isinstance(value, dict)
@staticmethod
def is_integer(value:Any|None) -> bool:
return isinstance(value, int)

75
Python/Utils/Color.py Normal file
View File

@ -0,0 +1,75 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Sequence
from Utils.Check import Check
class Color:
def __init__(self:Self, inputs:str|int|Sequence[int]|Self, _type:str = "rgba") -> None:
self.red:int = 0x00
self.green:int = 0x00
self.blue:int = 0x00
self.alpha:int = 0xFF
if Check.is_string(inputs):
if inputs.startswith("#"):
inputs = inputs[1:]
if len(inputs) in (3, 4):
inputs = "".join([character * 2 for character in inputs])
if len(inputs) in (7, 9):
inputs = ("FF" + inputs[1:])[-8:]
self.alpha, self.red, self.green, self.blue = [int(inputs[i:i + 2], 16) for i in (0, 2, 4, 6)]
elif inputs.startswith("rgb"):
self.red, self.green, self.blue, self.alpha = ([(
int(item) if i < 3 else
int(float(item) * 0xFF)) for item, i in enumerate(inputs[inputs.find("(") + 1:inputs.find(")")].split(","))] + [0xFF])[:4]
elif Check.is_integer(inputs):
self.alpha = 0xFF - ((inputs >> 24) & 0xFF)
self.red = (inputs >> 16) & 0xFF
self.green = (inputs >> 8) & 0xFF
self.blue = inputs & 0xFF
elif Check.is_array(inputs):
if _type in ("rgb", "rgba") or True:
self.red, self.green, self.blue, self.alpha = (inputs + [0xFF] * 4)[:4]
elif isinstance(inputs, Color):
self.red = inputs.red
self.green = inputs.green
self.blue = inputs.blue
self.alpha = inputs.alpha
def to_rgba(self:Self) -> str:
return f"rgba({self.red}, {self.green}, {self.blue}, {self.alpha / 0xFF:.2f})"
def to_rgb(self:Self) -> str:
return f"rgb({self.red}, {self.green}, {self.blue})"
def to_hex(self:Self, with_alpha:bool = False) -> str:
return "#" + (f"{self.alpha:02X}" if with_alpha else "") + f"{self.red:02X}{self.green:02X}{self.blue:02X}"
@staticmethod
def mix(*colors:str|int|Sequence[int]|Self) -> Self:
if len(colors) == 0:
return Color(0)
base:Color = Color(colors[0])
color:str|int|Sequence[int]|Color
l:int = len(colors)
if l != 1:
for color in colors[1:]:
subcolor:Color = Color(color)
base.red += subcolor.red
base.green += subcolor.green
base.blue += subcolor.blue
base.alpha += subcolor.alpha
base.red //= l
base.green //= l
base.blue //= l
base.alpha //= l
return base

60
Python/Utils/Options.py Normal file
View File

@ -0,0 +1,60 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Optional
class Options:
OVERWRITING:int = 0
OVERWRITE:int = 1 * 3 ** OVERWRITING
NO_OVERWRITE:int = 2 * 3 ** OVERWRITING
NULLISH:int = 1
ALLOW_NULLS:int = 1 * 3 ** NULLISH
NOT_NULLS:int = 2 * 3 ** NULLISH
DEFAULT:Self = Self(NO_OVERWRITE + ALLOW_NULLS)
@classmethod
def get_value(cls:type[Self], value:int, option:int) -> bool|None:
ternary:int = value // 3 ** option % 3
return (
True if ternary == 1 else
False if ternary == 2 else
None)
def __init__(self:Self, options:int = 0, default:Optional[Self] = None) -> None:
self.overwrite:bool|None
self.allow_null:bool|None
if default is None:
default = self.DEFAULT
for key, option in (
("overwrite", self.OVERWRITE),
("allow_null", self.NULLISH)
):
value:bool|None = self.get_value(options, option)
setattr(self, key, getattr(default, key) if value is None and default is not None else value)
def get(self:Self) -> int:
code:int = 0
option:int
value:bool|None
for option, value in (
(self.OVERWRITING, self.overwrite),
(self.NULLISH, self.allow_null)
):
code += (
1 if value is True else
2 if value is False else
0) * 3 ** option
return code

8
Python/Utils/Patterns.py Normal file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from re import compile as re_compile, Pattern as REPattern, I as RE_IGNORE_CASE
class RE:
KEY:REPattern = re_compile(r'^[a-z_][a-z0-9_]*$', RE_IGNORE_CASE)
STRING_VARIABLES:REPattern = re_compile(r'\{([a-z_][a-z0-9_]*)\}', RE_IGNORE_CASE)

140
Python/Utils/Utils.py Normal file
View File

@ -0,0 +1,140 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Any, Self, Sequence, Optional
from re import Match as REMatch
from Utils.Check import Check
from Utils.Options import Options
from Utils.Patterns import RE
class Utils:
GET_DICTIONARY_OPTIONS:Options = Options(Options.NO_OVERWRITE)
GET_VALUE_OPTIONS:Options = Options(Options.ALLOW_NULLS)
@classmethod
def get_keys(cls:type[Self], *items:Any|None) -> list[str]:
keys:list[str] = []
item:Any|None
for item in items:
if Check.is_key(item):
item in keys or keys.append(item)
elif Check.is_array(item):
key:str
for key in cls.get_keys(*item):
key in keys or keys.append(key)
return keys
@classmethod
def get_dictionaries(cls:type[Self], *items: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):
item in dictionaries or dictionaries.append(item)
elif Check.is_array(item):
dictionary:dict
for dictionary in cls.get_dictionaries(*item):
dictionary in dictionaries or dictionaries.append(dictionary)
return dictionaries
@classmethod
def get_dictionary(cls:type[Self], items:Any|None, custom_options:int = 0) -> dict[str, Any|None]:
dictionary:dict[str, Any|None] = {}
options:Options = Options(custom_options, cls.GET_DICTIONARY_OPTIONS)
if Check.is_dictionary(items):
dictionary = items
elif Check.is_array(items):
item:Any|None
for item in items:
key:str
value:Any|None
for key, value in cls.get_dictionary(item, options).items():
if options.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,
custom_options:int = 0
) -> Any|None:
options:Options = Options(custom_options, cls.GET_VALUE_OPTIONS)
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 and (
options.allow_null or
subinputs[key] is not None
):
return subinputs[key]
return default
@staticmethod
def get_array(value:Any|None) -> list[Any]:
return (
value if isinstance(value, list) else
list(value) if isinstance(value, (set, tuple)) else
[value])
@staticmethod
def get_strings(value:Any|None) -> list[str]:
strings:list[str] = []
item:Any|None
for item in Utils.get_array(value):
if Check.is_string(item):
item in strings or strings.append(item)
elif Check.is_array(item):
strings.extend(Utils.get_strings(item))
return strings
@classmethod
def string_variables(cls:type[Self],
string:str,
variables:dict[str, Any|None],
default:Optional[str] = None
) -> str:
variables = Utils.get_dictionary(variables)
def callback(matches:REMatch) -> str:
key:str = matches.group(1)
return (
str(variables[key]) if key in variables else
default if default is not None else
matches.group(0))
return RE.STRING_VARIABLES.sub(callback, string)

View File

@ -1,3 +1,39 @@
# AnPv2 # AnPv2
AnP Framework, version 2. AnP Framework, version 2.
## .NET
- Docker Hub del SDK: https://hub.docker.com/r/microsoft/dotnet-sdk
- Git del SDK: https://github.com/dotnet/sdk
Para crear los SLN de la Solución:
```sh
#!/bin/bash
docker exec -it anp-dotnet bash
cd CSharp
dotnet new sln -n AnP
dotnet sln add AnP.csproj
cd ..
exit
sudo chown -R root:$USER CSharp/AnP.slnx
```
Instalación del SDK para desarrollo VSCode.
```sh
#!/bin/bash
wget https://packages.microsoft.com/config/ubuntu/24.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb
sudo apt update
sudo apt install -y dotnet-sdk-10.0
```
Luego, instalar el Pluggin Nuget de Visual Studio Code `C/C++ DevTools`.

View File

@ -0,0 +1,690 @@
if (select top 1 0 from sys.databases where name = 'AnP') is null create database AnP collate Latin1_General_CI_AS
go
use AnP
if object_id(N'dbo.common_tables_delete', N'P') is not null drop procedure dbo.common_tables_delete
go
create procedure dbo.common_tables_delete as begin
set nocount on
if object_id(N'dbo.fk_sessions_user', N'F') is not null
alter table dbo.[Sessions] drop constraint fk_sessions_user
-- Level 3.
if object_id(N'dbo.Logs', N'U') is not null drop table dbo.Logs
if object_id(N'dbo.Exceptions', N'U') is not null drop table dbo.Exceptions
if object_id(N'dbo.Terminals', N'U') is not null drop table dbo.Terminals
if object_id(N'dbo.SessionsIps', N'U') is not null drop table dbo.SessionsIps
-- Level 2.
if object_id(N'dbo.[Sessions]', N'U') is not null drop table dbo.[Sessions]
-- Level 1.
if object_id(N'dbo.[Procedures]', N'U') is not null drop table dbo.[Procedures]
if object_id(N'dbo.Users', N'U') is not null drop table dbo.Users
-- Level 0.
if object_id(N'dbo.Ips', N'U') is not null drop table dbo.Ips
if object_id(N'dbo.[Databases]', N'U') is not null drop table dbo.[Databases]
if object_id(N'dbo.Hashes', N'U') is not null drop table dbo.Hashes
if object_id(N'dbo.[Messages]', N'U') is not null drop table dbo.[Messages]
if object_id(N'dbo.Errors', N'U') is not null drop table dbo.Errors
-- Level historical.
if object_id(N'dbo.UsersData', N'U') is not null drop table dbo.UsersData
end
go
if object_id(N'dbo.common_tables_create', N'P') is not null drop procedure dbo.common_tables_create
go
create procedure dbo.common_tables_create as begin
set nocount on
-- Level historical.
if object_id(N'dbo.UsersData', N'U') is null create table dbo.UsersData(
id integer not null identity(1, 1),
entity integer not null,
[procedure] integer not null,
[session] integer not null,
[hash] integer,
nick varchar(32) collate database_default,
[password] binary(64),
accessible bit,
date_in datetime not null,
date_out datetime,
constraint pk_users_data primary key clustered (id)
)
-- Level 0.
if object_id(N'dbo.[Databases]', N'U') is null create table dbo.[Databases](
id integer not null identity(1, 1),
[name] varchar(64) collate database_default not null,
date_in datetime not null constraint df_databases_date_in default getdate(),
date_out datetime,
constraint pk_databases primary key clustered (id),
constraint uk_databases_name unique nonclustered ([name] asc) with (fillfactor = 90),
constraint ck_databases_name check (
[name] != '' and
[name] like '[a-z_]%' and
[name] not like '%[^a-z0-9_]%'
)
)
if object_id(N'dbo.[Messages]', N'U') is null create table dbo.[Messages](
id integer not null identity(1, 1),
[message] varchar(max) collate database_default not null,
date_in datetime not null constraint df_messages_date_in default getdate(),
date_out datetime,
constraint pk_messages primary key clustered (id)
)
if object_id(N'dbo.Hashes', N'U') is null create table dbo.Hashes(
id integer not null identity(1, 1),
[name] varchar(16) collate database_default not null,
date_in datetime not null constraint df_hashes_date_in default getdate(),
date_out datetime,
constraint pk_hashes primary key clustered (id),
constraint uk_hashes_name unique nonclustered ([name] asc) with (fillfactor = 90),
constraint ck_hashes_name check ([name] != '')
)
if object_id(N'dbo.Errors', N'U') is null create table dbo.Errors(
id integer not null identity(1, 1),
[error] varchar(512) collate database_default not null,
date_in datetime not null constraint df_errors_date_in default getdate(),
date_out datetime,
constraint pk_errors primary key clustered (id),
constraint uk_errors_error unique nonclustered ([error] asc) with (fillfactor = 90)
)
create table dbo.Ips(
id integer not null identity(1, 1),
[ip] varchar(45) collate database_default not null, -- 3x4+3=15 for IPv4; 8x4+7=39 for IPv6; 30+15 for Hibrid.
date_in datetime not null constraint df_ips_date_in default getdate(),
date_out datetime,
constraint pk_ips primary key clustered (id),
constraint uk_ips_ip unique nonclustered ([ip] asc) with (fillfactor = 90),
constraint ck_ips_ip check (len([ip]) > 1 and [ip] not like '%[^0-9a-f:.]%'),
index ix_ips_ip nonclustered ([ip] asc) with (fillfactor = 90)
)
-- Level 1.
if object_id(N'dbo.[Procedures]', N'U') is null begin
create table dbo.[Procedures](
id integer not null identity(1, 1),
[database] integer not null,
[name] varchar(64) collate database_default not null,
date_in datetime not null constraint df_procedures_date_in default getdate(),
date_out datetime,
constraint pk_procedures primary key clustered (id),
constraint fk_procedures_database foreign key([database]) references dbo.[Databases](id),
constraint uk_procedures_name unique([database], [name]),
constraint ck_procedures_database check ([database] > 0),
constraint ck_procedures_name check (
[name] != '' and
[name] like '[a-z_]%' and
[name] not like '%[^a-z0-9_]%'
)
)
create nonclustered index ix_procedures_name on dbo.[Procedures]([name] asc) include ([database]) with (fillfactor = 90)
end
if object_id(N'dbo.Users', N'U') is null create table dbo.Users(
id integer not null identity(1, 1),
[hash] integer not null constraint df_users_hash default 1,
nick varchar(32) collate database_default not null,
[password] binary(64),
accessible bit not null constraint df_users_accessible default 1,
date_in datetime not null constraint df_users_date_in default getdate(),
date_out datetime,
constraint pk_users_id primary key clustered (id),
constraint fk_users_hash foreign key([hash]) references dbo.Hashes(id),
constraint uk_users_nick unique nonclustered (nick asc) with (fillfactor = 90),
constraint ck_users_hash check ([hash] > 0),
constraint ck_users_nick check (nick != ''),
index ix_users_hash nonclustered ([hash] asc) with (fillfactor = 90),
index ix_users_nick nonclustered (nick asc) with (fillfactor = 90)
)
-- level 2.
if object_id(N'dbo.[Sessions]', N'U') is null create table dbo.[Sessions](
id integer not null identity(1, 1),
[user] integer not null,
date_last datetime not null constraint df_sessions_date_last default getdate(),
date_in datetime not null constraint df_sessions_date_in default getdate(),
date_out datetime,
constraint pk_sessions primary key clustered (id),
constraint fk_sessions_user foreign key([user]) references dbo.Users(id),
constraint ck_sessions_user check ([user] > 0),
index ix_sessions_user nonclustered ([user] asc) with (fillfactor = 90)
)
-- Level 3.
if object_id(N'dbo.Logs', N'U') is null begin
create table dbo.Logs(
id integer not null identity(1, 1),
[procedure] integer not null,
[session] integer not null,
[message] integer not null,
error integer,
parameters text,
date_in datetime not null constraint df_logs_date_in default getdate(),
date_out datetime,
constraint pk_logs primary key clustered (id),
constraint fk_logs_procedure foreign key([procedure]) references dbo.[Procedures](id),
constraint fk_logs_session foreign key([session]) references dbo.[Sessions](id),
constraint fk_logs_message foreign key([message]) references dbo.[Messages](id),
constraint fk_logs_error foreign key(error) references dbo.Errors(id),
constraint ck_logs_procedure check ([procedure] > 0),
constraint ck_logs_session check ([session] > 0),
constraint ck_logs_message check ([message] > 0),
constraint ck_logs_error check (error is null or error > 0)
)
create nonclustered index ix_logs_procedure on dbo.Logs ([procedure] asc) include ([session], [message], error) with (fillfactor = 90)
create nonclustered index ix_logs_session on dbo.Logs ([session] asc) include ([procedure], [message], error) with (fillfactor = 90)
create nonclustered index ix_logs_error on dbo.Logs (error asc) include ([procedure], [session], [message]) with (fillfactor = 90)
create nonclustered index ix_logs_message on dbo.Logs ([message] asc) include ([procedure], [session], error) with (fillfactor = 90)
end
if object_id(N'dbo.Exceptions', N'U') is null begin
create table dbo.Exceptions(
id integer not null identity(1, 1),
[procedure] integer not null,
[session] integer not null,
[message] integer not null,
exception integer not null,
parameters text,
[status] varchar(16) collate database_default,
code integer,
date_in datetime not null constraint df_exceptions_date_in default getdate(),
date_out datetime,
constraint pk_exceptions primary key clustered (id),
constraint fk_exceptions_procedure foreign key([procedure]) references dbo.[Procedures](id),
constraint fk_exceptions_session foreign key([session]) references dbo.[Sessions](id),
constraint fk_exceptions_message foreign key([message]) references dbo.[Messages](id),
constraint fk_exceptions_exception foreign key([exception]) references dbo.[Messages](id),
constraint ck_exceptions_procedure check ([procedure] > 0),
constraint ck_exceptions_session check ([session] > 0),
constraint ck_exceptions_message check ([message] > 0),
constraint ck_exceptions_exception check ([exception] > 0)
)
create nonclustered index ix_exceptions_procedure on dbo.Exceptions ([procedure] asc) include ([session], [message], exception) with (fillfactor = 90)
create nonclustered index ix_exceptions_session on dbo.Exceptions ([session] asc) include ([procedure], [message], exception) with (fillfactor = 90)
create nonclustered index ix_exceptions_exception on dbo.Exceptions (exception asc) include ([procedure], [session], [message]) with (fillfactor = 90)
create nonclustered index ix_exceptions_message on dbo.Exceptions ([message] asc) include ([procedure], [session], exception) with (fillfactor = 90)
end
if object_id(N'dbo.Terminals', N'U') is null begin
create table dbo.Terminals(
id integer not null identity(1, 1),
[procedure] integer not null,
[session] integer not null,
[message] varchar(max) collate database_default,
date_in datetime not null constraint df_terminals_date_in default getdate(),
date_out datetime,
constraint pk_terminals_id primary key clustered (id),
constraint fk_terminals_procedure foreign key([procedure]) references dbo.[Procedures](id),
constraint fk_terminals_session foreign key([session]) references dbo.[Sessions](id),
constraint ck_terminals_procedure check ([procedure] > 0),
constraint ck_terminals_session check ([session] > 0)
)
create nonclustered index ix_terminals_procedure on dbo.Terminals ([procedure] asc) include ([session]) with (fillfactor = 90)
create nonclustered index ix_terminals_session on dbo.Terminals ([session] asc) include ([procedure]) with (fillfactor = 90)
end
if object_id(N'dbo.SessionsIps', N'U') is null begin
create table dbo.SessionsIps(
id integer not null identity(1, 1),
[session] integer not null,
[ip] integer not null,
date_in datetime not null constraint df_sessions_ips_date_in default getdate(),
date_out datetime,
constraint pk_sessions_ips_id primary key clustered (id),
constraint fk_sessions_ips_session foreign key([session]) references dbo.[Sessions](id),
constraint fk_sessions_ips_ip foreign key([ip]) references dbo.Ips(id),
constraint ck_sessions_ips_session check ([session] > 0),
constraint ck_sessions_ips_ip check ([ip] > 0)
)
create nonclustered index ix_sessions_ips_session on dbo.SessionsIps ([session] asc) include ([ip]) with (fillfactor = 90)
create nonclustered index ix_sessions_ips_ip on dbo.SessionsIps ([ip] asc) include ([session]) with (fillfactor = 90)
end
end
go
if object_id(N'dbo.common_tables_update', N'P') is not null drop procedure dbo.common_tables_update
go
create procedure dbo.common_tables_update as begin
set nocount on
end
go
execute dbo.common_tables_delete
go
execute dbo.common_tables_create
go
execute dbo.common_tables_update
go
if object_id(N'dbo.sql_set', N'P') is not null drop procedure dbo.sql_set
go
create procedure dbo.sql_set
@database varchar(64),
@procedure varchar(64),
@session integer
as begin
declare @data binary(128) = (
cast(substring(isnull(@database, ''), 1, 62) as binary(62)) +
cast(substring(isnull(@procedure, ''), 1, 62) as binary(62)) +
cast(isnull(@session, 0) as binary(4))
)
set nocount on
set context_info @data
end
go
if object_id(N'dbo.sql_get', N'P') is not null drop procedure dbo.sql_get
go
create procedure dbo.sql_get
@database varchar(64) output,
@procedure varchar(64) output,
@session integer output
as begin
declare @context binary(128) = context_info()
declare @null char(1) = char(0)
set nocount on
set @database = rtrim(replace(cast(substring(@context, 1, 62) as varchar(64)), @null, ''))
set @procedure = rtrim(replace(cast(substring(@context, 63, 62) as varchar(64)), @null, ''))
set @session = cast(substring(@context, 125, 4) as int)
end
go
if object_id(N'dbo.procedure_get', N'P') is not null drop procedure dbo.procedure_get
go
create procedure dbo.procedure_get
@database varchar(64),
@procedure varchar(64),
@id integer output
as begin
declare @database_id integer = (select top 1 id from dbo.[Databases] where
date_out is null and
[name] = @database
)
set nocount on
if @database_id is null begin
insert into dbo.[Databases]([name]) values(@database)
set @database_id = scope_identity()
end
set @id = (select top 1 id from dbo.[Procedures] where
date_out is null and
[database] = @database_id and
[name] = @procedure
)
if @id is null begin
insert into dbo.[Procedures]([database], [name]) values(@database_id, @procedure)
set @id = scope_identity()
end
end
go
if object_id(N'dbo.users_trigger_update', N'TR') is not null drop trigger dbo.users_trigger_update
go
create trigger dbo.users_trigger_update on dbo.Users after insert, update as begin
declare @session integer
declare @database varchar(64)
declare @procedure varchar(64)
declare @procedure_id integer
declare @id integer
declare @hash integer
declare @nick varchar(32)
declare @password binary(64)
declare @accessible bit
declare @date_in datetime
declare @date_out datetime
declare users_cursor cursor local for (
select id, [hash], nick, [password], accessible, date_in, date_out from inserted
)
set nocount on
execute dbo.sql_get @database output, @procedure output, @session output
execute dbo.procedure_get @database, @procedure, @procedure_id output
open users_cursor
while 1 = 1 begin
fetch next from users_cursor into @id, @hash, @nick, @password, @accessible, @date_in, @date_out
if @@fetch_status != 0
break
insert into dbo.UsersData(entity, [procedure], [session], [hash], nick, [password], accessible, date_in, date_out) values
(@id, @procedure_id, @session, @hash, @nick, @password, @accessible, @date_in, @date_out)
end
close users_cursor
deallocate users_cursor
end
go
if object_id(N'dbo.hash_create_name', N'FN') is not null drop function dbo.hash_create_name
go
create function dbo.hash_create_name(
@method varchar(16)
) returns varchar(16) as begin
return (case
when @method = 'md5' then 'md5'
when @method = 'sha1' then 'sha1'
when @method in (
'sha2_256', 'sha2-256', 'sha-256', 'sha256', 'sha_256'
) then 'sha2_256'
when @method in (
'sha2_512', 'sha2-512', 'sha-512', 'sha512', 'sha_512'
) then 'sha2_512'
else null end)
end
go
if object_id(N'dbo.hash_create', N'FN') is not null drop function dbo.hash_create
go
create function dbo.hash_create(
@method varchar(16),
@input varchar(max)
) returns binary(64) as begin
set @method = dbo.hash_create_name(@method)
return (case
when @method in (
'md5', 'sha1', 'sha2_256', 'sha2_512'
) then hashbytes(upper(@method), @input)
else cast(@input as binary(64)) end)
end
go
if object_id(N'dbo.message_get', N'P') is not null drop procedure dbo.message_get
go
create procedure dbo.message_get
@message varchar(max),
@id integer output
as begin
set nocount on
set @id = (select top 1 id from dbo.[Messages] where date_out is null and [message] = @message)
if @id is null begin
insert into dbo.[Messages]([message]) values(@message)
set @id = scope_identity()
end
end
go
if object_id(N'dbo.error_get', N'P') is not null drop procedure dbo.error_get
go
create procedure dbo.error_get
@error varchar(512),
@id integer output
as begin
set nocount on
set @id = (select top 1 id from dbo.Errors where date_out is null and [error] = @error)
if @id is null begin
insert into dbo.Errors([error]) values(@error)
set @id = scope_identity()
end
end
go
if object_id(N'dbo.hash_get', N'P') is not null drop procedure dbo.hash_get
go
create procedure dbo.hash_get
@name varchar(16),
@id integer output
as begin
set nocount on
set @id = (select top 1 id from dbo.Hashes where date_out is null and [name] = @name)
if @id is null begin
insert into dbo.Hashes([name]) values(@name)
set @id = scope_identity()
end
end
go
if object_id(N'dbo.logs_set', N'P') is not null drop procedure dbo.logs_set
go
create procedure dbo.logs_set
@session integer,
@database varchar(64),
@procedure varchar(64),
@message varchar(max),
@parameters varchar(max),
@error varchar(512) = '',
@level tinyint = 0
as begin
declare @procedure_id integer
declare @error_id integer
declare @message_id integer
set nocount on
execute dbo.procedure_get @database, @procedure, @procedure_id output
execute dbo.message_get @message, @message_id output
execute dbo.error_get @error, @error_id output
insert into dbo.Logs([procedure], [session], [message], parameters, [error]) values
(@procedure_id, @session, @message_id, @parameters, @error_id)
end
go
if object_id(N'dbo.logs_set', N'P') is not null drop procedure dbo.logs_set
go
create procedure dbo.logs_set
@session integer,
@database varchar(64),
@procedure varchar(64),
@message varchar(max),
@parameters varchar(max)
as begin
declare @exception varchar(max) = error_message()
declare @status varchar(16) = error_state()
declare @code integer = error_number()
declare @exception_id integer
declare @procedure_id integer
declare @message_id integer
set nocount on
execute dbo.message_get @exception, @exception_id output
execute dbo.procedure_get @database, @procedure, @procedure_id output
execute dbo.message_get @message, @message_id output
insert into dbo.Exceptions([procedure], [session], [message], exception, [parameters], [status], code) values
(@procedure_id, @session, @message_id, @exception_id, @parameters, @status, @code)
end
go
if object_id(N'dbo.common_tables_fill', N'P') is not null drop procedure dbo.common_tables_fill
go
create procedure dbo.common_tables_fill as begin
declare @database varchar(64) = 'AnP'
declare @procedure varchar(64) = 'common_tables_fill'
declare @procedure_id integer
declare @local_ip varchar(71) = '::1'
declare @main_user varchar(32) = 'machine'
declare @user varchar(32)
declare @session_id integer = (
select top 1 id from dbo.[Sessions] where date_out is null and [user] = (
select top 1 id from dbo.Users where date_out is null and nick = @main_user
)
)
declare @has_session bit = case when @session_id is null then 0 else 1 end
declare @ip_id integer = (
select top 1 id from dbo.Ips where date_out is null and ip = @local_ip
)
declare @hash_id integer
declare @hash varchar(16)
declare users_cursor cursor local for (
select @main_user as [name] union all
select 'guest'
)
declare hashes_cursor cursor local for (
select 'null' as [name] union all
select 'md5' union all
select 'sha1' union all
select 'sha2_256' union all
select 'sha2_512'
)
set nocount on
if @has_session = 0 begin
if (select top 1 0 from sys.indexes where name = N'ix_sessions_user') is not null
drop index ix_sessions_user on dbo.[Sessions]
if object_id(N'dbo.fk_sessions_user', N'F') is not null
alter table dbo.[Sessions] drop constraint fk_sessions_user
alter table dbo.[Sessions] alter column [user] integer
insert into dbo.[Sessions] default values
set @session_id = scope_identity()
end
execute dbo.sql_set @database, @procedure, @session_id
execute dbo.procedure_get @database, @procedure, @procedure_id output
open hashes_cursor
while 1 = 1 begin
fetch next from hashes_cursor into @hash
if @@fetch_status != 0
break
if (select top 1 0 from dbo.Hashes where date_out is null and [name] = @hash) is null
insert into dbo.Hashes([name]) values(@hash)
end
close hashes_cursor
deallocate hashes_cursor
execute dbo.hash_get 'null', @hash_id output
open users_cursor
while 1 = 1 begin
fetch next from users_cursor into @user
if @@fetch_status != 0
break
if (select top 1 0 from dbo.Users where date_out is null and nick = @user) is null
insert into dbo.Users([hash], nick) values
(@hash_id, @user)
end
close users_cursor
deallocate users_cursor
if @has_session = 0 begin
update dbo.[Sessions] set [user] = (
select top 1 id from dbo.Users where date_out is null and nick = @main_user
) where id = @session_id
alter table dbo.[Sessions] alter column [user] integer not null
alter table dbo.[Sessions] add constraint fk_sessions_user foreign key([user]) references dbo.Users(id)
create nonclustered index ix_sessions_user on dbo.[Sessions]([user] asc) with (fillfactor = 90)
end
if @ip_id is null begin
insert into dbo.Ips([ip]) values(@local_ip)
set @ip_id = scope_identity()
end
if (select top 1 0 from dbo.SessionsIps where
date_out is null and
[session] = @session_id and
[ip] = @ip_id
) is null
insert into dbo.SessionsIps([session], [ip]) values(@session_id, @ip_id)
end
go
execute dbo.common_tables_fill
go
if object_id(N'dbo.where_set', N'FN') is not null drop function dbo.where_set
go
create function dbo.where_set(
@old_where varchar(max),
@new_where varchar(max)
) returns varchar(max) as begin
set @new_where = ltrim(rtrim(isnull(@new_where, '')))
set @old_where = ltrim(rtrim(isnull(@old_where, '')))
return (case
when @new_where = '' then @old_where
when @old_where = '' then @new_where
else '(' + @old_where + ') and (' + @new_where + ')' end)
end
go
if object_id(N'dbo.tables_list', N'P') is not null drop procedure dbo.tables_list
go
create procedure dbo.tables_list
@view varchar(max),
@page integer,
@items_per_page integer,
@where varchar(max),
@order_by varchar(max),
@has_errors bit,
@pages integer output,
@items integer output,
@results integer output
as begin
declare @where_string varchar(max) = (case
when @has_errors = 1 then ' where ' + dbo.where_set('0 = 1', @where)
when ltrim(rtrim(isnull(@where, ''))) = '' then ''
else ' where ' + @where end)
declare @query varchar(max) = N'select top 1 @subitems = count(1) from ' + @view + @where_string
set nocount on
execute sp_executesql @query, N'@subitems integer output', @subitems = @items output
set @pages = ceiling(@items / cast(@items_per_page as float))
set @query = (
N'select * from ' + @view + @where_string +
(case when ltrim(rtrim(isnull(@order_by, ''))) = '' then '' else N' order by ' + @order_by end) +
N' offset ' + cast((((case
when @page < 1 then 1
when @page > @pages then @pages
else @page end) - 1) * @items_per_page) as varchar) + N' rows fetch next ' + cast(@items_per_page as varchar) + N' rows only'
)
execute sp_executesql @query
set @results = @@rowcount
end
go

View File

@ -0,0 +1,345 @@
use AnP
if object_id(N'dbo.groups_tables_delete', N'P') is not null drop procedure dbo.groups_tables_delete
go
create procedure dbo.groups_tables_delete as begin
set nocount on;
-- Level 3.
if object_id(N'dbo.GroupsIps', N'U') is not null drop table dbo.GroupsIps
if object_id(N'dbo.GroupsUsers', N'U') is not null drop table dbo.GroupsUsers
-- Level 1.
if object_id(N'dbo.Groups', N'U') is not null drop table dbo.Groups
-- Level 0.
if object_id(N'dbo.GroupsTypes', N'U') is not null drop table dbo.GroupsTypes
-- Level historical.
if object_id(N'dbo.GroupsIpsData', N'U') is not null drop table dbo.GroupsIpsData
if object_id(N'dbo.GroupsUsersData', N'U') is not null drop table dbo.GroupsUsersData
if object_id(N'dbo.GroupsData', N'U') is not null drop table dbo.GroupsData
if object_id(N'dbo.GroupsTypesData', N'U') is not null drop table dbo.GroupsTypesData
end
go
if object_id(N'dbo.groups_tables_create', N'P') is not null drop procedure dbo.groups_tables_create
go
create procedure dbo.groups_tables_create as begin
set nocount on;
-- Level historical.
if object_id(N'dbo.GroupsTypesData', N'U') is null create table dbo.GroupsTypesData(
id integer not null identity(1,1),
entity integer not null,
[name] varchar(32) not null,
[description] varchar(256),
date_in datetime not null,
date_out datetime,
constraint pk_groups_types primary key clustered(id)
)
if object_id(N'dbo.GroupsData', N'U') is null create table dbo.GroupsData(
id integer not null identity(1,1),
entity integer not null,
[procedure] integer not null,
[session] integer not null,
[type] integer not null,
[name] varchar(32) not null,
[description] varchar(256),
date_in datetime not null,
date_out datetime,
constraint pk_groups_data primary key clustered (id)
)
if object_id(N'dbo.GroupsIpsData', N'U') is null create table dbo.GroupsIpsData(
id integer not null identity(1,1),
entity integer not null,
[procedure] integer not null,
[session] integer not null,
[group] integer not null,
[ip] integer not null,
belongs bit not null,
date_in datetime not null,
constraint pk_groups_ips_data primary key clustered (id)
)
if object_id(N'dbo.GroupsUsersData', N'U') is null create table dbo.GroupsUsersData(
id integer not null identity(1,1),
entity integer not null,
[procedure] integer not null,
[session] integer not null,
[group] integer not null,
[user] integer not null,
belongs bit not null,
date_in datetime not null,
constraint pk_groups_users_data primary key clustered (id)
)
-- Level 0.
if object_id(N'dbo.GroupsTypes', N'U') is null create table dbo.GroupsTypes(
id integer not null identity(1,1),
[name] varchar(32) not null,
[description] varchar(256),
date_in datetime not null constraint df_groups_types_date_in default getdate(),
date_out datetime,
constraint pk_groups_types primary key clustered (id),
constraint uk_groups_types_name unique nonclustered ([name] asc) with (fillfactor = 90),
constraint ck_groups_types_name check ([name] != '')
)
-- Level 1.
if object_id(N'dbo.Groups', N'U') is null begin
create table dbo.Groups(
id integer not null identity(1,1),
[type] integer not null,
[name] varchar(32) not null,
[description] varchar(256),
date_in datetime not null constraint df_groups_date_in default getdate(),
date_out datetime,
constraint pk_groups primary key clustered (id),
constraint fk_groups_type foreign key ([type]) references dbo.GroupsTypes(id),
constraint uk_groups_type_name unique([name], [type]),
constraint ck_groups_type check ([type] > 0),
constraint ck_groups_name check ([name] != '')
)
create nonclustered index ix_groups_type on dbo.Groups([type] asc) include ([name]) with (fillfactor = 90)
create nonclustered index ix_groups_name on dbo.Groups([name] asc) include ([type]) with (fillfactor = 90)
end
-- Level 2.
if object_id(N'dbo.GroupsIps', N'U') is null begin
create table dbo.GroupsIps(
id integer not null identity(1,1),
[group] integer not null,
[ip] integer not null,
belongs bit not null constraint df_groups_ips_belongs default 1,
date_in datetime not null constraint df_groups_ips_date_in default getdate(),
constraint pk_groups_ips primary key clustered (id),
constraint fk_groups_ips_group foreign key ([group]) references dbo.Groups(id),
constraint fk_groups_ips_ip foreign key ([ip]) references dbo.Ips(id),
constraint uk_groups_ips_group_ip unique([group], [ip]),
constraint ck_groups_ips_group check ([group] > 0),
constraint ck_groups_ips_ip check ([ip] > 0)
)
create nonclustered index ix_groups_ips_group on dbo.GroupsIps([group] asc) include ([ip], belongs) with (fillfactor = 90)
create nonclustered index ix_groups_ips_ip on dbo.GroupsIps([ip] asc) include ([group], belongs) with (fillfactor = 90)
end
if object_id(N'dbo.GroupsUsers', N'U') is null begin
create table dbo.GroupsUsers(
id integer not null identity(1,1),
[group] integer not null,
[user] integer not null,
belongs bit not null constraint df_groups_users_belongs default 1,
date_in datetime not null constraint df_groups_users_date_in default getdate(),
constraint pk_groups_users primary key clustered (id),
constraint fk_groups_users_group foreign key ([group]) references dbo.Groups(id),
constraint fk_groups_users_user foreign key ([user]) references dbo.Users(id),
constraint uk_groups_users_group_user unique([group], [user]),
constraint ck_groups_users_group check ([group] > 0),
constraint ck_groups_users_user check ([user] > 0)
)
create nonclustered index ix_groups_users_group on dbo.GroupsUsers([group] asc) include ([user], belongs) with (fillfactor = 90)
create nonclustered index ix_groups_users_user on dbo.GroupsUsers([user] asc) include ([group], belongs) with (fillfactor = 90)
end
end
go
if object_id(N'dbo.groups_tables_update', N'P') is not null drop procedure dbo.groups_tables_update
go
create procedure dbo.groups_tables_update as begin
set nocount on;
end
go
execute dbo.groups_tables_delete
go
execute dbo.groups_tables_create
go
execute dbo.groups_tables_update
go
if object_id(N'dbo.groups_trigger_update', N'TR') is not null drop trigger dbo.groups_trigger_update
go
create trigger dbo.groups_trigger_update on dbo.Groups after insert, update as begin
declare @database varchar(64)
declare @procedure varchar(64)
declare @procedure_id integer
declare @session integer
declare @id integer
declare @name varchar(32)
declare @description varchar(256)
declare @date_in datetime
declare @date_out datetime
declare groups_cursor cursor local for (
select id, [name], [description], date_in, date_out from inserted
)
set nocount on
execute dbo.sql_get @database output, @procedure output, @session output
execute dbo.procedure_get @database, @procedure, @procedure_id output
open groups_cursor
while 1 = 1 begin
fetch next from groups_cursor into @id, @procedure, @session, @name, @description, @date_in, @date_out
if @@fetch_status != 0
break
insert into dbo.GroupsData(entity, [procedure], [session], [name], [description], date_in, date_out) values
(@id, @procedure, @session, @name, @description, @date_in, @date_out)
update dbo.Groups set data_id = scope_identity() where id = @id
end
close groups_cursor
deallocate groups_cursor
end
go
if object_id(N'dbo.groups_ips_trigger_update', N'TR') is not null drop trigger dbo.groups_ips_trigger_update
go
create trigger dbo.groups_ips_trigger_update on dbo.GroupsIps after insert, update as begin
declare @database varchar(64)
declare @procedure varchar(64)
declare @procedure_id integer
declare @session integer
declare @id integer
declare @group integer
declare @ip integer
declare @belongs bit
declare @date_in datetime
declare groups_ips_cursor cursor local for (
select id, [group], [ip], belongs, date_in from inserted
)
set nocount on
execute dbo.sql_get @database output, @procedure output, @session output
execute dbo.procedure_get @database, @procedure, @procedure_id output
open groups_ips_cursor
while 1 = 1 begin
fetch next from groups_ips_cursor into @id, @group, @ip, @belongs, @date_in
if @@fetch_status != 0
break
insert into dbo.GroupsIpsData(entity, [procedure], [session], [group], [ip], belongs, date_in) values
(@id, @procedure_id, @session_id, @group, @ip, @belongs, @date_in)
end
close groups_ips_cursor
deallocate groups_ips_cursor
end
go
if object_id(N'dbo.groups_users_trigger_update', N'TR') is not null drop trigger dbo.groups_users_trigger_update
go
create trigger dbo.groups_users_trigger_update on dbo.GroupsUsers after insert, update as begin
declare @database varchar(64)
declare @procedure varchar(64)
declare @procedure_id integer
declare @session integer
declare @id integer
declare @group integer
declare @user integer
declare @belongs bit
declare @date_in datetime
declare groups_users_cursor cursor local for (
select id, [group], [user], belongs, date_in from inserted
)
set nocount on
execute dbo.sql_get @database output, @procedure output, @session output
execute dbo.procedure_get @database, @procedure, @procedure_id output
open groups_users_cursor
while 1 = 1 begin
fetch next from groups_users_cursor into @id, @procedure, @session, @group, @user, @belongs, @date_in
if @@fetch_status != 0
break
insert into dbo.GroupsUsersData(entity, [procedure], [session], [group], [user], belongs, date_in) values
(@id, @procedure, @session, @group, @user, @belongs, @date_in)
update dbo.GroupsUsers set data_id = scope_identity() where id = @id
end
close groups_users_cursor
deallocate groups_users_cursor
end
go
execute dbo.groups_tables_fill
go
if object_id(N'dbo.IpsView', N'V') is not null drop view dbo.IpsView
go
create view dbo.IpsView as select
ips.id as id,
ips.[ip] as [ip],
ips.date_in as date_in
from dbo.Ips ips
where ips.date_out is null
go
if object_id(N'dbo.UsersView', N'V') is not null drop view dbo.UsersView
go
create view dbo.UsersView as select
users.id as id,
users.nick as nick,
users.date_in as date_in
from dbo.Users users
where users.date_out is null
go
if object_id(N'dbo.GroupsView', N'V') is not null drop view dbo.GroupsView
go
create view dbo.GroupsView as select
groups.id as id,
groups.name as [name],
groups.description as [description],
groups.date_in as date_in
from dbo.Groups groups
where groups.date_out is null
go
if object_id(N'dbo.GroupsIpsView', N'V') is not null drop view dbo.GroupsIpsView
go
create view dbo.GroupsIpsView as select
groups_ips.id as id,
groups.id as group_id,
groups.[name] as [group],
ips.id as ip_id,
ips.[ip] as [ip],
isnull(groups_ips.belongs, 0) as belongs,
groups_ips.date_in as date_in
from dbo.GroupsViews groups
join dbo.IpsViews ips on 1 = 1
left join dbo.GroupsIps groups_ips on
groups_ips.[group] = groups.id
groups_ips.[ip] = ips.id
go
if object_id(N'dbo.GroupsUsersView', N'V') is not null drop view dbo.GroupsUsersView
go
create view dbo.GroupsUsersView as select
groups_users.id as id,
groups.id as group_id,
groups.[name] as [group],
users.id as user_id,
users.nick as [user],
isnull(groups_users.belongs, 0) as belongs,
groups_users.date_in as date_in
from dbo.GroupsViews groups
join dbo.UsersViews users on 1 = 1
left join dbo.GroupsUsers groups_users on
groups_users.[group] = groups.id
groups_users.[user] = users.id
go

4
SQLServer/Dockerfile Normal file
View File

@ -0,0 +1,4 @@
from mcr.microsoft.com/mssql/server:2022-latest
expose 1433/tcp
user root
env ACCEPT_EULA=Y

4
SQLServer/docker.rebuild.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
directory=`dirname $(readlink -f "$0")`
[ "$(docker images -q anp:sql-server 2>/dev/null)" ] && docker image remove anp:sql-server --force
docker build -f $directory/Dockerfile -t anp:sql-server $directory --no-cache

6
Tools/reinstall.dockers.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/bash
directory=`dirname $(readlink -f "$0")`
for file in $(find $directory/.. -type f -name "docker.rebuild.sh"); do
chmod +x $file
$file
done

4
Tools/run.cs.server.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
cd `dirname $(readlink -f "$0")`/..
docker exec -it anp-dotnet dotnet run --project /workspace/CSharp/AnP.csproj -f net10.0
cd Tools

3
Tools/run.server.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
directory=`dirname $(readlink -f "$0")`
python3 "$directory/../Python/server.py"

3
Tools/sass.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
directory=`dirname $(readlink -f "$0")`
sass $directory/../Public/scss/AnP.scss ../Public/scss/AnP.css;

41
docker-compose.yml Normal file
View File

@ -0,0 +1,41 @@
services:
dotnet:
image: anp:dotnet
container_name: anp-dotnet
volumes:
- ./DotNET/scripts:/scripts
- ./CSharp:/workspace/CSharp
- ./VB:/workspace/VB
- ./FSharp:/workspace/FSharp
- ./CPP:/workspace/CPP
- ./JSON:/workspace/JSON
- ./Public:/workspace/Public
ports:
- 28080:80/tcp
entrypoint: /scripts/entrypoint.sh
networks:
anp-network:
ipv4_address: 172.20.11.223
anp-sql-server:
image: anp:sql-server
container_name: anp-sql-server
environment:
- MSSQL_SA_PASSWORD=Abc123..
volumes:
- ./SQLServer/data:/var/opt/mssql
- ./SQLServer/temporary:/temporary
- ./SQLServer/scripts:/scripts
ports:
- 21433:1433/tcp
networks:
anp-network:
ipv4_address: 172.20.11.222
networks:
anp-network:
driver: bridge
ipam:
config:
- subnet: 172.20.11.0/24

1
version Normal file
View File

@ -0,0 +1 @@
0.0.1