modifiing grammar for instructions in file
This commit is contained in:
@ -1,8 +1,11 @@
|
|||||||
|
use reactionsystems::rsprocess::presets;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// let now = std::time::Instant::now();
|
// let now = std::time::Instant::now();
|
||||||
// println!("{}", now.elapsed().as_micros());
|
// println!("{}", now.elapsed().as_micros());
|
||||||
|
|
||||||
let (g, t) = reactionsystems::rsprocess::presets::digraph("testing/first.system".into()).unwrap();
|
match presets::run("testing/first.system".into()) {
|
||||||
|
Ok(_) => {},
|
||||||
reactionsystems::rsprocess::presets::dot(&g, &t, "testing/first.dot".into()).unwrap();
|
Err(e) => {println!("{e}")}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,8 @@ use crate::rsprocess::structure::{RSset,
|
|||||||
RSsystem,
|
RSsystem,
|
||||||
RSreaction};
|
RSreaction};
|
||||||
use crate::rsprocess::translator::{Translator, IdType};
|
use crate::rsprocess::translator::{Translator, IdType};
|
||||||
|
use crate::rsprocess::presets::Instructions;
|
||||||
|
use crate::rsprocess::presets;
|
||||||
|
|
||||||
grammar(translator: &mut Translator);
|
grammar(translator: &mut Translator);
|
||||||
|
|
||||||
@ -19,6 +21,7 @@ grammar(translator: &mut Translator);
|
|||||||
|
|
||||||
// order
|
// order
|
||||||
match {
|
match {
|
||||||
|
".", ",", ";",
|
||||||
"nill",
|
"nill",
|
||||||
"{", "}",
|
"{", "}",
|
||||||
"[", "]",
|
"[", "]",
|
||||||
@ -27,12 +30,21 @@ match {
|
|||||||
"r:", "i:", "p:",
|
"r:", "i:", "p:",
|
||||||
"-", "^",
|
"-", "^",
|
||||||
"true", "false",
|
"true", "false",
|
||||||
"inW", "inR", "inI", "inP"
|
"inW", "inR", "inI", "inP",
|
||||||
|
"Environment", "Initial Entities", "Context", "Reactions",
|
||||||
|
"Weights", "Sets",
|
||||||
|
"Print", "Save",
|
||||||
|
"Dot", "GraphML", "Serialize",
|
||||||
|
"Stats", "Target", "Run", "Loop", "Frequency", "LimitFrequency",
|
||||||
|
"FastFrequency", "Digraph",
|
||||||
|
"Deserialize"
|
||||||
} else {
|
} else {
|
||||||
r"[0-9]+" => NUMBER
|
r"[0-9]+" => NUMBER
|
||||||
} else {
|
} else {
|
||||||
// r"([[:alpha:]]|\p{Emoji})([[:word:]]|\p{Emoji})*" => WORD
|
// r"([[:alpha:]]|\p{Emoji})([[:word:]]|\p{Emoji})*" => WORD
|
||||||
r"(\p{L}|\p{Emoji})(\p{L}|\p{Emoji}|\p{Dash}|\p{N})*" => WORD
|
r"(\p{L}|\p{Emoji})(\p{L}|\p{Emoji}|\p{Dash}|\p{N})*" => WORD,
|
||||||
|
} else {
|
||||||
|
r#"".*""# => PATH,
|
||||||
} else {
|
} else {
|
||||||
_
|
_
|
||||||
}
|
}
|
||||||
@ -49,6 +61,10 @@ Num: i64 = {
|
|||||||
.map_err(|_| ParseError::User { error: "Number is too big" })
|
.map_err(|_| ParseError::User { error: "Number is too big" })
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Path: String = {
|
||||||
|
PATH => <>.trim_end_matches("\"").trim_start_matches("\"").to_string()
|
||||||
|
};
|
||||||
|
|
||||||
// macro for matching sequence of patterns with C as separator
|
// macro for matching sequence of patterns with C as separator
|
||||||
Separated<T, C>: Vec<T> = {
|
Separated<T, C>: Vec<T> = {
|
||||||
<mut v:(<T> C)+> <e:T?> => match e {
|
<mut v:(<T> C)+> <e:T?> => match e {
|
||||||
@ -181,18 +197,19 @@ Formula_BHML: RSBHML = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// File Parsing
|
// File Parsing
|
||||||
// -----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// system
|
// system
|
||||||
// a system is an environment, a set of entities as initial state, a context and
|
// a system is an environment, a set of entities as initial state, a context and
|
||||||
// a set of reaction rules.
|
// a set of reaction rules.
|
||||||
|
|
||||||
pub System: RSsystem = {
|
pub System: RSsystem = {
|
||||||
"Environment:" <delta: Environment>
|
"Environment" ":" <delta: Environment>
|
||||||
"Initial Entities:" <available_entities: Set>
|
"Initial Entities" ":" <available_entities: Set>
|
||||||
"Context:" <context_process: Context>
|
"Context" ":" <context_process: Context>
|
||||||
"Reactions:" <reaction_rules: Reactions>
|
"Reactions" ":" <reaction_rules: Reactions>
|
||||||
=> RSsystem::from(delta.into(),
|
=> RSsystem::from(delta.into(),
|
||||||
available_entities,
|
available_entities,
|
||||||
context_process,
|
context_process,
|
||||||
@ -204,7 +221,68 @@ pub System: RSsystem = {
|
|||||||
// entities of equal length.
|
// entities of equal length.
|
||||||
|
|
||||||
pub Experiment: (Vec<u32>, Vec<RSset>) = {
|
pub Experiment: (Vec<u32>, Vec<RSset>) = {
|
||||||
"Weights:" <w: Separated_Or<Num, ",">>
|
"Weights" ":" <w: Separated_Or<Num, ",">>
|
||||||
"Sets:" <s: Separated_Or<Set_of_entities, ",">>
|
"Sets" ":" <s: Separated_Or<Set_of_entities, ",">>
|
||||||
=> (w.into_iter().map(|x| x as u32).collect::<Vec<_>>(), s),
|
=> (w.into_iter().map(|x| x as u32).collect::<Vec<_>>(), s),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Instruction Parsing
|
||||||
|
|
||||||
|
Helper_SO: presets::SaveOptions = {
|
||||||
|
"Print" =>
|
||||||
|
presets::SaveOptions {print: true, save: None},
|
||||||
|
"Save" "(" <p: Path> ")" =>
|
||||||
|
presets::SaveOptions {print: false, save: Some(vec![p])}
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveOptions: presets::SaveOptions = {
|
||||||
|
<p: Separated_Or<Helper_SO, ";">> => {
|
||||||
|
if let Some(a) =
|
||||||
|
p.into_iter()
|
||||||
|
.reduce(|mut acc, mut e| {acc.combine(&mut e); acc}) {
|
||||||
|
a
|
||||||
|
} else {
|
||||||
|
presets::SaveOptions::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GraphSaveOptions: presets::GraphSaveOptions = {
|
||||||
|
"Dot" ">" <so: SaveOptions> =>
|
||||||
|
presets::GraphSaveOptions::Dot { so },
|
||||||
|
"GraphML" ">" <so: SaveOptions> =>
|
||||||
|
presets::GraphSaveOptions::GraphML { so },
|
||||||
|
"Serialize" "(" <path: Path> ")" =>
|
||||||
|
presets::GraphSaveOptions::Serialize { path },
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Instruction: presets::Instruction = {
|
||||||
|
"Stats" ">" <so: SaveOptions> =>
|
||||||
|
presets::Instruction::Stats { so },
|
||||||
|
"Target" ">" <so: SaveOptions> =>
|
||||||
|
presets::Instruction::Target { so },
|
||||||
|
"Run" ">" <so: SaveOptions> =>
|
||||||
|
presets::Instruction::Run { so },
|
||||||
|
"Loop" "(" <symbol: Literal> ")" ">" <so: SaveOptions> =>
|
||||||
|
presets::Instruction::Loop { symbol, so },
|
||||||
|
"Frequency" "(" <p: Path> ")" ">" <so: SaveOptions> =>
|
||||||
|
presets::Instruction::Frequency { experiment: p, so },
|
||||||
|
"LimitFrequency" "(" <p: Path> ")" ">" <so: SaveOptions> =>
|
||||||
|
presets::Instruction::LimitFrequency { experiment: p, so },
|
||||||
|
"FastFrequency" "(" <p: Path> ")" ">" <so: SaveOptions> =>
|
||||||
|
presets::Instruction::FastFrequency { experiment: p, so },
|
||||||
|
"Digraph" ">" <gso: Separated_Or<GraphSaveOptions, "|">> =>
|
||||||
|
presets::Instruction::Digraph { gso },
|
||||||
|
}
|
||||||
|
|
||||||
|
pub Run: presets::Instructions = {
|
||||||
|
<sys: System> <instr: Separated_Or<Instruction, ",">> =>
|
||||||
|
Instructions { system: presets::System::RSsystem { sys },
|
||||||
|
instructions: instr },
|
||||||
|
"Deserialize" "(" <path: Path> ")" <instr: Separated_Or<Instruction, ",">> =>
|
||||||
|
Instructions { system: presets::System::Deserialize { path },
|
||||||
|
instructions: instr },
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
//! Module that holds useful presets for interacting with other modules.
|
//! Module that holds useful presets for interacting with other modules.
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::fmt::Display;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
@ -18,6 +19,75 @@ use super::structure::{RSset, RSsystem};
|
|||||||
use super::translator::Translator;
|
use super::translator::Translator;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Structures
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SaveOptions {
|
||||||
|
pub print: bool,
|
||||||
|
pub save: Option<Vec<String>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SaveOptions {
|
||||||
|
pub fn combine(&mut self, other: &mut Self) {
|
||||||
|
self.print = self.print || other.print;
|
||||||
|
match (self.save.is_some(), other.save.is_some()) {
|
||||||
|
(false, false) |
|
||||||
|
(true, false) => {}
|
||||||
|
(false, true) => {
|
||||||
|
self.save = other.save.to_owned();
|
||||||
|
},
|
||||||
|
(true, true) => {
|
||||||
|
self.save
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.append(other.save.as_mut().unwrap());}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn new() -> Self {
|
||||||
|
SaveOptions { print: false, save: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SaveOptions {
|
||||||
|
fn default() -> Self {
|
||||||
|
SaveOptions::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum GraphSaveOptions {
|
||||||
|
Dot { so: SaveOptions },
|
||||||
|
GraphML { so: SaveOptions },
|
||||||
|
Serialize { path: String }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Instruction {
|
||||||
|
Stats { so: SaveOptions },
|
||||||
|
Target { so: SaveOptions },
|
||||||
|
Run { so: SaveOptions },
|
||||||
|
Loop { symbol: String, so: SaveOptions },
|
||||||
|
Frequency { experiment: String, so: SaveOptions },
|
||||||
|
LimitFrequency { experiment: String, so: SaveOptions },
|
||||||
|
FastFrequency { experiment: String, so: SaveOptions },
|
||||||
|
Digraph { gso: Vec<GraphSaveOptions> },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum System {
|
||||||
|
Deserialize { path: String },
|
||||||
|
RSsystem { sys: RSsystem }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Instructions {
|
||||||
|
pub system: System,
|
||||||
|
pub instructions: Vec<Instruction>
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Helper Functions
|
// Helper Functions
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@ -55,6 +125,77 @@ where
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reformat_error<T, S>(
|
||||||
|
e: ParseError<usize, T, &'static str>
|
||||||
|
) -> Result<S, String>
|
||||||
|
where
|
||||||
|
T: Display
|
||||||
|
{
|
||||||
|
match e {
|
||||||
|
ParseError::ExtraToken { token: (l, t, r) } => {
|
||||||
|
Err(format!(
|
||||||
|
"Unexpected token \"{t}\" \
|
||||||
|
between positions {l} and {r}."
|
||||||
|
))
|
||||||
|
},
|
||||||
|
ParseError::UnrecognizedEof { location: _, expected: _ } => {
|
||||||
|
Err("End of file encountered while parsing.".into())
|
||||||
|
},
|
||||||
|
ParseError::InvalidToken { location } => {
|
||||||
|
Err(format!("Invalid token at position {location}."))
|
||||||
|
},
|
||||||
|
ParseError::UnrecognizedToken { token: (l, t, r), expected }
|
||||||
|
=> {
|
||||||
|
Err(format!(
|
||||||
|
"Unrecognized token \"{t}\" \
|
||||||
|
between positions {l} and {r}. Expected: {expected:?}"
|
||||||
|
))
|
||||||
|
},
|
||||||
|
ParseError::User { error } => {
|
||||||
|
Err(error.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parser_system(
|
||||||
|
translator: &mut Translator,
|
||||||
|
contents: String
|
||||||
|
) -> Result<RSsystem, String>
|
||||||
|
{
|
||||||
|
match grammar::SystemParser::new()
|
||||||
|
.parse(translator, &contents)
|
||||||
|
{
|
||||||
|
Ok(sys) => Ok(sys),
|
||||||
|
Err(e) => reformat_error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parser_experiment(
|
||||||
|
translator: &mut Translator,
|
||||||
|
contents: String
|
||||||
|
) -> Result<(Vec<u32>, Vec<RSset>), String>
|
||||||
|
{
|
||||||
|
match grammar::ExperimentParser::new()
|
||||||
|
.parse(translator, &contents)
|
||||||
|
{
|
||||||
|
Ok(sys) => Ok(sys),
|
||||||
|
Err(e) => reformat_error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parser_instructions(
|
||||||
|
translator: &mut Translator,
|
||||||
|
contents: String
|
||||||
|
) -> Result<Instructions, String>
|
||||||
|
{
|
||||||
|
match grammar::RunParser::new()
|
||||||
|
.parse(translator, &contents)
|
||||||
|
{
|
||||||
|
Ok(sys) => Ok(sys),
|
||||||
|
Err(e) => reformat_error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn save_file(
|
fn save_file(
|
||||||
contents: String,
|
contents: String,
|
||||||
path_string: String,
|
path_string: String,
|
||||||
@ -81,85 +222,9 @@ fn save_file(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parser_system(
|
|
||||||
translator: &mut Translator,
|
|
||||||
contents: String
|
|
||||||
) -> Result<RSsystem, String>
|
|
||||||
{
|
|
||||||
match grammar::SystemParser::new()
|
|
||||||
.parse(translator, &contents)
|
|
||||||
{
|
|
||||||
Ok(sys) => Ok(sys),
|
|
||||||
Err(e) => {
|
|
||||||
match e {
|
|
||||||
ParseError::ExtraToken { token: (l, t, r) } => {
|
|
||||||
Err(format!(
|
|
||||||
"Unexpected token \"{t}\" \
|
|
||||||
between positions {l} and {r}."
|
|
||||||
))
|
|
||||||
},
|
|
||||||
ParseError::UnrecognizedEof { location: _, expected: _ } => {
|
|
||||||
Err("End of file encountered while parsing.".into())
|
|
||||||
},
|
|
||||||
ParseError::InvalidToken { location } => {
|
|
||||||
Err(format!("Invalid token at position {location}."))
|
|
||||||
},
|
|
||||||
ParseError::UnrecognizedToken { token: (l, t, r), expected: _ }
|
|
||||||
=> {
|
|
||||||
Err(format!(
|
|
||||||
"Unexpected token \"{t}\" \
|
|
||||||
between positions {l} and {r}."
|
|
||||||
))
|
|
||||||
},
|
|
||||||
ParseError::User { error } => {
|
|
||||||
Err(error.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parser_experiment(
|
|
||||||
translator: &mut Translator,
|
|
||||||
contents: String
|
|
||||||
) -> Result<(Vec<u32>, Vec<RSset>), String>
|
|
||||||
{
|
|
||||||
match grammar::ExperimentParser::new()
|
|
||||||
.parse(translator, &contents)
|
|
||||||
{
|
|
||||||
Ok(sys) => Ok(sys),
|
|
||||||
Err(e) => {
|
|
||||||
match e {
|
|
||||||
ParseError::ExtraToken { token: (l, t, r) } => {
|
|
||||||
Err(format!(
|
|
||||||
"Unexpected token \"{t}\" \
|
|
||||||
between positions {l} and {r}."
|
|
||||||
))
|
|
||||||
},
|
|
||||||
ParseError::UnrecognizedEof { location: _, expected: _ } => {
|
|
||||||
Err("End of file encountered while parsing.".into())
|
|
||||||
},
|
|
||||||
ParseError::InvalidToken { location } => {
|
|
||||||
Err(format!("Invalid token at position {location}."))
|
|
||||||
},
|
|
||||||
ParseError::UnrecognizedToken { token: (l, t, r), expected: _ }
|
|
||||||
=> {
|
|
||||||
Err(format!(
|
|
||||||
"Unexpected token \"{t}\" \
|
|
||||||
between positions {l} and {r}."
|
|
||||||
))
|
|
||||||
},
|
|
||||||
ParseError::User { error } => {
|
|
||||||
Err(error.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Methods
|
// main_do
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Prints statistics of the system.
|
/// Prints statistics of the system.
|
||||||
@ -195,10 +260,11 @@ pub fn target(path_string: String) -> Result<(), String> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Finds the list of traversed states in a (deterministic) terminating
|
/// Finds the list of traversed states in a (deterministic) terminating
|
||||||
/// reaction.
|
/// reaction.
|
||||||
/// equivalent to main_do(run,Es)
|
/// equivalent to main_do(run,Es)
|
||||||
pub fn run(path_string: String) -> Result<(), String> {
|
pub fn traversed(path_string: String) -> Result<(), String> {
|
||||||
let mut translator = Translator::new();
|
let mut translator = Translator::new();
|
||||||
|
|
||||||
let system = read_file(&mut translator, path_string, parser_system)?;
|
let system = read_file(&mut translator, path_string, parser_system)?;
|
||||||
@ -217,7 +283,7 @@ pub fn run(path_string: String) -> Result<(), String> {
|
|||||||
|
|
||||||
|
|
||||||
/// Finds the looping list of states in a reaction system with a perpetual
|
/// Finds the looping list of states in a reaction system with a perpetual
|
||||||
/// context IMPORTANT: for loops, we assume Delta defines the process constant
|
/// context. IMPORTANT: for loops, we assume Delta defines the process constant
|
||||||
/// x = Q.x and the context process is x .
|
/// x = Q.x and the context process is x .
|
||||||
/// equivalent to main_do(loop,Es)
|
/// equivalent to main_do(loop,Es)
|
||||||
pub fn hoop(path_string: String) -> Result<(), String> {
|
pub fn hoop(path_string: String) -> Result<(), String> {
|
||||||
@ -347,9 +413,9 @@ pub fn digraph(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Output Functions
|
// Output Functions
|
||||||
// ----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Writes the specified graph to a file in .dot format.
|
/// Writes the specified graph to a file in .dot format.
|
||||||
pub fn dot(
|
pub fn dot(
|
||||||
@ -486,3 +552,18 @@ pub fn deserialize(
|
|||||||
Err(_) => Err("Error during deserialization.".into())
|
Err(_) => Err("Error during deserialization.".into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Interpreting Instructions
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
pub fn run(path: String) -> Result<(), String> {
|
||||||
|
let mut translator = Translator::new();
|
||||||
|
|
||||||
|
let instructions = read_file(&mut translator, path, parser_instructions)?;
|
||||||
|
|
||||||
|
println!("{:?}", instructions);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@ -1,4 +1,9 @@
|
|||||||
Environment: [x = {a}.y, y =({a}.x + {b}.y)]
|
Environment: [x = {a}.y, y =({a}.x + {b}.y) ]
|
||||||
Initial Entities: {a, b}
|
Initial Entities: {a, b}
|
||||||
Context: [({a,b}.{a}.{a,c}.x + {a,b}.{a}.{a}.nill)]
|
Context: [({a,b}.{a}.{a,c}.x + {a,b}.{a}.{a}.nill)]
|
||||||
Reactions: ([{a,b}, {c}, {b}])
|
Reactions: ([{a,b}, {c}, {b}])
|
||||||
|
|
||||||
|
Run > Print; Save("testing/asd"),
|
||||||
|
LimitFrequency("testing/first.experiment") > Print,
|
||||||
|
Digraph > Dot > Save("testing/asddd")
|
||||||
|
| Serialize("testing/asdd")
|
||||||
|
|||||||
Reference in New Issue
Block a user