*** empty log message ***
This commit is contained in:
parent
f4d6969b11
commit
def19717ce
11 changed files with 251 additions and 57 deletions
|
|
@ -132,6 +132,20 @@ extern "C" {
|
|||
catch (CanteraError) { return -1; }
|
||||
}
|
||||
|
||||
double DLL_EXPORT domain_upperBound(int i, int n) {
|
||||
try {
|
||||
return _domain(i)->upperBound(n);
|
||||
}
|
||||
catch (CanteraError) { return -1.0; }
|
||||
}
|
||||
|
||||
double DLL_EXPORT domain_lowerBound(int i, int n) {
|
||||
try {
|
||||
return _domain(i)->lowerBound(n);
|
||||
}
|
||||
catch (CanteraError) { return -1.0; }
|
||||
}
|
||||
|
||||
int DLL_EXPORT domain_setTolerances(int i, int nr, double* rtol,
|
||||
int na, double* atol, int itime) {
|
||||
try {
|
||||
|
|
@ -141,6 +155,20 @@ extern "C" {
|
|||
catch (CanteraError) { return -1; }
|
||||
}
|
||||
|
||||
double DLL_EXPORT domain_rtol(int i, int n) {
|
||||
try {
|
||||
return _domain(i)->rtol(n);
|
||||
}
|
||||
catch (CanteraError) { return -1.0; }
|
||||
}
|
||||
|
||||
double DLL_EXPORT domain_atol(int i, int n) {
|
||||
try {
|
||||
return _domain(i)->atol(n);
|
||||
}
|
||||
catch (CanteraError) { return -1.0; }
|
||||
}
|
||||
|
||||
int DLL_EXPORT domain_setupGrid(int i, int npts, double* grid) {
|
||||
try {
|
||||
_domain(i)->setupGrid(npts, grid);
|
||||
|
|
@ -298,7 +326,7 @@ extern "C" {
|
|||
}
|
||||
|
||||
int DLL_EXPORT stflow_setFixedTempProfile(int i, int n, double* pos,
|
||||
double* temp) {
|
||||
int m, double* temp) {
|
||||
try {
|
||||
int j;
|
||||
vector_fp vpos(n), vtemp(n);
|
||||
|
|
@ -379,7 +407,7 @@ extern "C" {
|
|||
}
|
||||
|
||||
int DLL_EXPORT sim1D_setProfile(int i, int dom, int comp,
|
||||
int np, double* pos, double* v) {
|
||||
int np, double* pos, int nv, double* v) {
|
||||
try {
|
||||
vector_fp vv, pv;
|
||||
for (int n = 0; n < np; n++) {
|
||||
|
|
|
|||
|
|
@ -11,15 +11,19 @@ extern "C" {
|
|||
int DLL_IMPORT domain_index(int i);
|
||||
int DLL_IMPORT domain_nComponents(int i);
|
||||
int DLL_IMPORT domain_nPoints(int i);
|
||||
int DLL_IMPORT domain_componentName(int i, int n, int sz, char* buf);
|
||||
int DLL_IMPORT domain_componentName(int i, int n, int sz, char* nameout);
|
||||
int DLL_IMPORT domain_componentIndex(int i, char* name);
|
||||
int DLL_IMPORT domain_setBounds(int i, int nl, double* lower,
|
||||
int nu, double* upper);
|
||||
double DLL_EXPORT domain_lowerBound(int i, int n);
|
||||
double DLL_EXPORT domain_upperBound(int i, int n);
|
||||
int DLL_IMPORT domain_setTolerances(int i, int nr, double* rtol,
|
||||
int na, double* atol, int itime);
|
||||
double DLL_IMPORT domain_rtol(int i, int n);
|
||||
double DLL_IMPORT domain_atol(int i, int n);
|
||||
int DLL_IMPORT domain_setupGrid(int i, int npts, double* grid);
|
||||
int DLL_IMPORT domain_setID(int, char* id);
|
||||
int DLL_IMPORT domain_setDesc(int, char* desc);
|
||||
int DLL_IMPORT domain_setID(int i, char* id);
|
||||
int DLL_IMPORT domain_setDesc(int i, char* desc);
|
||||
double DLL_IMPORT domain_grid(int i, int n);
|
||||
|
||||
int DLL_IMPORT bdry_setMdot(int i, double mdot);
|
||||
|
|
@ -41,7 +45,7 @@ extern "C" {
|
|||
int DLL_IMPORT stflow_new(int iph, int ikin, int itr);
|
||||
int DLL_IMPORT stflow_setPressure(int i, double p);
|
||||
int DLL_IMPORT stflow_setFixedTempProfile(int i, int n, double* pos,
|
||||
double* temp);
|
||||
int m, double* temp);
|
||||
int DLL_IMPORT stflow_solveSpeciesEqs(int i, int flag);
|
||||
int DLL_IMPORT stflow_solveEnergyEqn(int i, int flag);
|
||||
|
||||
|
|
@ -50,7 +54,7 @@ extern "C" {
|
|||
int DLL_IMPORT sim1D_del(int i);
|
||||
int DLL_IMPORT sim1D_setValue(int i, int dom, int comp, int localPoint, double value);
|
||||
int DLL_IMPORT sim1D_setProfile(int i, int dom, int comp,
|
||||
int np, double* pos, double* v);
|
||||
int np, double* pos, int nv, double* v);
|
||||
int DLL_IMPORT sim1D_setFlatProfile(int i, int dom, int comp, double v);
|
||||
int DLL_IMPORT sim1D_showSolution(int i, char* fname);
|
||||
int DLL_IMPORT sim1D_setTimeStep(int i, double stepsize, int ns, int* nsteps);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
""" Python script to generate a Python extension module from a clib
|
||||
header file. """
|
||||
|
||||
import sys
|
||||
|
||||
_class = ''
|
||||
_newclass = 1
|
||||
|
||||
def getargs(line):
|
||||
"""Get the function name and arguments."""
|
||||
i1 = line.find('(')
|
||||
i2 = line.find(')')
|
||||
if (i1 < 0 or i2 < 0):
|
||||
|
|
@ -10,52 +17,147 @@ def getargs(line):
|
|||
argline = line[i1+1:i2]
|
||||
args = argline.split(',')
|
||||
for n in range(len(args)): args[n] = args[n].split()
|
||||
return nm, args
|
||||
v = []
|
||||
for a in args:
|
||||
if len(a) == 2: v.append(a)
|
||||
return nm, v
|
||||
|
||||
_itype = {'int':'i', 'double':'d', 'char*':'s', 'double*':'O', 'int*':'O'}
|
||||
|
||||
def writepyfunc(name, args):
|
||||
|
||||
def isoutput(name):
|
||||
if len(name) >= 3 and name[-3:] == 'out':
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def writepyfunc(rtype, name, args):
|
||||
"""Write the Python extension module function."""
|
||||
|
||||
print """
|
||||
static PyObject *
|
||||
py_"""+name+"""(PyObject *self, PyObject *args)
|
||||
{
|
||||
int _iok;"""
|
||||
for a in args:
|
||||
if len(a) == 2:
|
||||
print ' ',a[0],a[1]+';'
|
||||
print ' if (!PyArg_ParseTuple(args,',
|
||||
s = '"'
|
||||
for a in args:
|
||||
if len(a) == 2:
|
||||
s += _itype[a[0]]
|
||||
s += ':'+name+'",'
|
||||
for a in args:
|
||||
if len(a) == 2:
|
||||
s += ' &'+a[1]+','
|
||||
s = s[:-1]+'))'
|
||||
print s,
|
||||
print """
|
||||
"""+rtype+""" _val;"""
|
||||
|
||||
global _class, _newclass
|
||||
cls, func = name.split('_')
|
||||
if cls != _class:
|
||||
_class = cls
|
||||
_newclass = 1
|
||||
else:
|
||||
_newclass = 0
|
||||
|
||||
na = len(args)
|
||||
ain = []
|
||||
output = []
|
||||
if na > 0:
|
||||
vtype = []
|
||||
for a in args:
|
||||
# if the argument is an array, then the previous argument
|
||||
# must have been the array size. The Python argument list
|
||||
# will not include the size
|
||||
if a[0] == 'double*' or a[0] == 'int*':
|
||||
if not isoutput(a[1]):
|
||||
vtype[-1] = 'PyObject*'
|
||||
ain[-1] = a
|
||||
else:
|
||||
output.append(a)
|
||||
elif a[0] == 'char*' and isoutput(a[1]):
|
||||
output.append(a)
|
||||
ain.pop()
|
||||
else:
|
||||
vtype.append(a[0])
|
||||
ain.append(a)
|
||||
for n in range(len(ain)):
|
||||
print ' ',vtype[n],ain[n][1]+';'
|
||||
print ' if (!PyArg_ParseTuple(args,',
|
||||
s = '"'
|
||||
for a in ain:
|
||||
s += _itype[a[0]]
|
||||
s += ':'+name+'",'
|
||||
for a in ain:
|
||||
s += ' &'+a[1]+','
|
||||
s = s[:-1]+'))'
|
||||
print s,
|
||||
print """
|
||||
return NULL;
|
||||
"""
|
||||
s = ' _iok = '+name+'('
|
||||
v = []
|
||||
for a in output:
|
||||
if a[0] == 'char*':
|
||||
print ' int '+a[1]+'_sz = 80;'
|
||||
print ' char* '+a[1]+' = new char['+a[1]+'_sz];'
|
||||
print
|
||||
|
||||
for a in args:
|
||||
if len(a) == 2:
|
||||
s += a[1]+','
|
||||
s = s[:-1]+')'
|
||||
if a[0] == 'double*' or a[0] == 'int*':
|
||||
v[-1] = a[1]+'_len'
|
||||
v.append(a[1]+'_data')
|
||||
array = a[1]+'_array'
|
||||
print
|
||||
print ' PyArrayObject* '+array+' = (PyArrayObject*)'+a[1]+';'
|
||||
print ' '+a[0]+' '+a[1]+'_data = ('+a[0]+')'+array+'->data;'
|
||||
print ' int '+a[1]+'_len = '+array+'->dimensions[0];'
|
||||
print
|
||||
elif a[0] == 'char*' and isoutput(a[1]):
|
||||
v[-1] = a[1]+'_sz'
|
||||
v.append(a[1])
|
||||
else:
|
||||
v.append(a[1])
|
||||
|
||||
s = ' _val = '+name+'('
|
||||
for a in v:
|
||||
s += a+','
|
||||
if s[-1] == ',': s = s[:-1]
|
||||
s += ');'
|
||||
print s,
|
||||
print """
|
||||
if (_iok == -1) return reportCanteraError();
|
||||
return Py_BuildValue("i",_iok);
|
||||
if (output):
|
||||
print '\n PyObject* _ret = Py_BuildValue("'+_itype[output[0][0]]+'",'+output[0][1]+');'
|
||||
print ' delete '+output[0][1]+';'
|
||||
print ' if (int(_val) == -1) return reportCanteraError();'
|
||||
print """ return _ret;\n
|
||||
}
|
||||
"""
|
||||
"""
|
||||
else:
|
||||
print """
|
||||
if (int(_val) == -1) return reportCanteraError();
|
||||
"""+'return Py_BuildValue("'+_itype[rtype]+'",_val);'+"""
|
||||
}
|
||||
"""
|
||||
return ain
|
||||
|
||||
|
||||
def writepyclass(f, name, args):
|
||||
global _newclass
|
||||
if _newclass == 1:
|
||||
f.write("class "+_class.capitalize()+":\n")
|
||||
f.write(" def __init__(self):\n")
|
||||
f.write(" pass\n");
|
||||
_newclass = 0
|
||||
cls, nm = name.split('_')
|
||||
f.write(' def '+nm+'(self')
|
||||
for a in args[1:]:
|
||||
f.write(', '+a[1])
|
||||
f.write('):\n')
|
||||
f.write(' return _cantera.'+name+'(self._index')
|
||||
for a in args[1:]:
|
||||
f.write(', '+a[1])
|
||||
f.write(')\n')
|
||||
|
||||
fname = sys.argv[1]
|
||||
base, ext = fname.split('.')
|
||||
mfile = 'py'+base+'_methods.h'
|
||||
pfile = base+'.py'
|
||||
|
||||
_rtypes = ['int', 'double']
|
||||
|
||||
f = open(fname,'r')
|
||||
fm = open(mfile,'w')
|
||||
fp = open(pfile,'w')
|
||||
|
||||
lines = f.readlines()
|
||||
f.close()
|
||||
|
||||
infunc = 0
|
||||
funcline = ''
|
||||
|
|
@ -71,8 +173,13 @@ for line in lines:
|
|||
if last[-1] == ';':
|
||||
infunc = 0
|
||||
name, args = getargs(funcline)
|
||||
writepyfunc(name, args)
|
||||
toks = funcline.split()
|
||||
a = writepyfunc(toks[0], name, args)
|
||||
writepyclass(fp, name, a)
|
||||
fm.write(' {"'+name+'", py_'+name+', METH_VARARGS},\n')
|
||||
funcline = ''
|
||||
|
||||
fm.close()
|
||||
fp.close()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -48,16 +48,11 @@ class Kinetics:
|
|||
"""
|
||||
np = len(phases)
|
||||
self._np = np
|
||||
#self._ph = {}
|
||||
self._sp = []
|
||||
#for p in phases:
|
||||
# self._ph[p.thermophase()] = p
|
||||
self._phnum = {}
|
||||
|
||||
self._end = [0]
|
||||
p0 = phases[0].thermophase()
|
||||
#self._ph[phases[0]] = phases
|
||||
#self._end.append(phases[0].nSpecies())
|
||||
p1 = -1
|
||||
p2 = -1
|
||||
p3 = -1
|
||||
|
|
@ -82,9 +77,6 @@ class Kinetics:
|
|||
self._end.append(self._end[-1]+p.nSpecies())
|
||||
for k in range(p.nSpecies()):
|
||||
self._sp.append(p.speciesName(k))
|
||||
|
||||
#self.phases = phases
|
||||
|
||||
|
||||
|
||||
def __del__(self):
|
||||
|
|
@ -98,6 +90,9 @@ class Kinetics:
|
|||
def kin_index(self):
|
||||
return self.ckin
|
||||
|
||||
def kinetics_hndl(self):
|
||||
return self.ckin
|
||||
|
||||
def kineticsType(self):
|
||||
"""Kinetics manager type."""
|
||||
return _cantera.kin_type(self.ckin)
|
||||
|
|
|
|||
|
|
@ -58,6 +58,9 @@ class ThermoPhase(Phase):
|
|||
reference the kernel object."""
|
||||
return self._phase_id
|
||||
|
||||
def thermo_hndl(self):
|
||||
return self._phase_id
|
||||
|
||||
def refPressure(self):
|
||||
"""Reference pressure [Pa].
|
||||
All standard-state thermodynamic properties are for this pressure.
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ class Transport:
|
|||
loglevel --- controls amount of diagnostic output
|
||||
"""
|
||||
|
||||
#self._phase = phase
|
||||
if model == "" or model == "Default":
|
||||
try:
|
||||
self.model = xml_phase.child('transport')['model']
|
||||
|
|
@ -42,14 +41,6 @@ class Transport:
|
|||
except:
|
||||
pass
|
||||
|
||||
## def setTransportModel(self, model):
|
||||
## if self._models.has_key(model):
|
||||
## self.__tr_id = self._models[model]
|
||||
## else:
|
||||
## self.__tr_id = _cantera.Transport(model,
|
||||
## self._phase._phase_id, 0)
|
||||
## self.model = model
|
||||
|
||||
def desc(self):
|
||||
if self.model == 'Multi':
|
||||
return 'Multicomponent'
|
||||
|
|
@ -60,6 +51,9 @@ class Transport:
|
|||
|
||||
def transport_id(self):
|
||||
return self.__tr_id
|
||||
|
||||
def transport_hndl(self):
|
||||
return self.__tr_id
|
||||
|
||||
def viscosity(self):
|
||||
return _cantera.tran_viscosity(self.__tr_id)
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@ else:
|
|||
# f.write('date = '+`time.time()`)
|
||||
# f.close()
|
||||
|
||||
try:
|
||||
#try:
|
||||
setup(name="Cantera",
|
||||
version="1.4",
|
||||
version="1.5",
|
||||
description="The Cantera Python Interface",
|
||||
long_description="""
|
||||
""",
|
||||
|
|
@ -33,7 +33,8 @@ try:
|
|||
author_email="dgoodwin@caltech.edu",
|
||||
url="http://www.cantera.org",
|
||||
package_dir = {'MixMaster':'../../apps/MixMaster'},
|
||||
packages = ["","Cantera","MixMaster","MixMaster.Units"],
|
||||
packages = ["","Cantera","Cantera.OneD",
|
||||
"MixMaster","MixMaster.Units"],
|
||||
ext_modules=[
|
||||
Extension("Cantera._cantera",
|
||||
["src/pycantera.cpp", "src/writelog.cpp"],
|
||||
|
|
@ -42,6 +43,7 @@ try:
|
|||
library_dirs = ["@buildlib@"], libraries = libs)
|
||||
],
|
||||
)
|
||||
except:
|
||||
print 'setup.py failed'
|
||||
#except:
|
||||
# print '***************************************'
|
||||
# print ' Error: setup.py failed'
|
||||
|
||||
|
|
|
|||
|
|
@ -125,6 +125,64 @@ static PyMethodDef ct_methods[] = {
|
|||
{"onedim_timestep", py_onedim_timestep, METH_VARARGS},
|
||||
{"onedim_save", py_onedim_save, METH_VARARGS},
|
||||
|
||||
{"domain_clear", py_domain_clear, METH_VARARGS},
|
||||
{"domain_del", py_domain_del, METH_VARARGS},
|
||||
{"domain_type", py_domain_type, METH_VARARGS},
|
||||
{"domain_index", py_domain_index, METH_VARARGS},
|
||||
{"domain_nComponents", py_domain_nComponents, METH_VARARGS},
|
||||
{"domain_nPoints", py_domain_nPoints, METH_VARARGS},
|
||||
{"domain_componentName", py_domain_componentName, METH_VARARGS},
|
||||
{"domain_componentIndex", py_domain_componentIndex, METH_VARARGS},
|
||||
{"domain_setBounds", py_domain_setBounds, METH_VARARGS},
|
||||
{"domain_lowerBound", py_domain_lowerBound, METH_VARARGS},
|
||||
{"domain_upperBound", py_domain_upperBound, METH_VARARGS},
|
||||
{"domain_setTolerances", py_domain_setTolerances, METH_VARARGS},
|
||||
{"domain_rtol", py_domain_rtol, METH_VARARGS},
|
||||
{"domain_atol", py_domain_atol, METH_VARARGS},
|
||||
{"domain_setupGrid", py_domain_setupGrid, METH_VARARGS},
|
||||
{"domain_setID", py_domain_setID, METH_VARARGS},
|
||||
{"domain_setDesc", py_domain_setDesc, METH_VARARGS},
|
||||
{"domain_grid", py_domain_grid, METH_VARARGS},
|
||||
{"bdry_setMdot", py_bdry_setMdot, METH_VARARGS},
|
||||
{"bdry_setTemperature", py_bdry_setTemperature, METH_VARARGS},
|
||||
{"bdry_setMoleFractions", py_bdry_setMoleFractions, METH_VARARGS},
|
||||
{"bdry_temperature", py_bdry_temperature, METH_VARARGS},
|
||||
{"bdry_massFraction", py_bdry_massFraction, METH_VARARGS},
|
||||
{"bdry_mdot", py_bdry_mdot, METH_VARARGS},
|
||||
{"reactingsurf_setkineticsmgr", py_reactingsurf_setkineticsmgr, METH_VARARGS},
|
||||
{"reactingsurf_enableCoverageEqs", py_reactingsurf_enableCoverageEqs, METH_VARARGS},
|
||||
{"inlet_new", py_inlet_new, METH_VARARGS},
|
||||
{"outlet_new", py_outlet_new, METH_VARARGS},
|
||||
{"symm_new", py_symm_new, METH_VARARGS},
|
||||
{"surf_new", py_surf_new, METH_VARARGS},
|
||||
{"reactingsurf_new", py_reactingsurf_new, METH_VARARGS},
|
||||
{"stflow_new", py_stflow_new, METH_VARARGS},
|
||||
{"stflow_setPressure", py_stflow_setPressure, METH_VARARGS},
|
||||
{"stflow_setFixedTempProfile", py_stflow_setFixedTempProfile, METH_VARARGS},
|
||||
{"stflow_solveSpeciesEqs", py_stflow_solveSpeciesEqs, METH_VARARGS},
|
||||
{"stflow_solveEnergyEqn", py_stflow_solveEnergyEqn, METH_VARARGS},
|
||||
{"sim1D_clear", py_sim1D_clear, METH_VARARGS},
|
||||
{"sim1D_new", py_sim1D_new, METH_VARARGS},
|
||||
{"sim1D_del", py_sim1D_del, METH_VARARGS},
|
||||
{"sim1D_setValue", py_sim1D_setValue, METH_VARARGS},
|
||||
{"sim1D_setProfile", py_sim1D_setProfile, METH_VARARGS},
|
||||
{"sim1D_setFlatProfile", py_sim1D_setFlatProfile, METH_VARARGS},
|
||||
{"sim1D_showSolution", py_sim1D_showSolution, METH_VARARGS},
|
||||
{"sim1D_setTimeStep", py_sim1D_setTimeStep, METH_VARARGS},
|
||||
{"sim1D_solve", py_sim1D_solve, METH_VARARGS},
|
||||
{"sim1D_refine", py_sim1D_refine, METH_VARARGS},
|
||||
{"sim1D_setRefineCriteria", py_sim1D_setRefineCriteria, METH_VARARGS},
|
||||
{"sim1D_save", py_sim1D_save, METH_VARARGS},
|
||||
{"sim1D_restore", py_sim1D_restore, METH_VARARGS},
|
||||
{"sim1D_writeStats", py_sim1D_writeStats, METH_VARARGS},
|
||||
{"sim1D_domainIndex", py_sim1D_domainIndex, METH_VARARGS},
|
||||
{"sim1D_value", py_sim1D_value, METH_VARARGS},
|
||||
{"sim1D_workValue", py_sim1D_workValue, METH_VARARGS},
|
||||
{"sim1D_eval", py_sim1D_eval, METH_VARARGS},
|
||||
{"sim1D_setMaxJacAge", py_sim1D_setMaxJacAge, METH_VARARGS},
|
||||
{"sim1D_timeStepFactor", py_sim1D_timeStepFactor, METH_VARARGS},
|
||||
{"sim1D_setTimeStepLimits", py_sim1D_setTimeStepLimits, METH_VARARGS},
|
||||
|
||||
{"surf_setsitedensity", py_surf_setsitedensity, METH_VARARGS},
|
||||
{"surf_sitedensity", py_surf_sitedensity, METH_VARARGS},
|
||||
{"surf_setcoverages", py_surf_setcoverages, METH_VARARGS},
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "ctrpath.h"
|
||||
#include "ctreactor.h"
|
||||
#include "ctfunc.h"
|
||||
#include "ctonedim.h"
|
||||
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
|
@ -45,6 +46,7 @@ static PyObject *ErrorObject;
|
|||
#include "ctrpath_methods.cpp"
|
||||
#include "ctreactor_methods.cpp"
|
||||
#include "ctfunc_methods.cpp"
|
||||
#include "ctonedim_methods.cpp"
|
||||
|
||||
#include "methods.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ namespace Cantera {
|
|||
if (m_cvode_mem) CVodeFree(m_cvode_mem);
|
||||
if (m_y) N_VFree(nv(m_y));
|
||||
if (m_abstol) N_VFree(nv(m_abstol));
|
||||
delete[] m_iopt;
|
||||
}
|
||||
|
||||
double& CVodeInt::solution(int k){ return N_VIth(nv(m_y),k); }
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace Cantera {
|
|||
// resize the internal solution vector and the wprk array,
|
||||
// and perform domain-specific initialization of the
|
||||
// solution vector.
|
||||
//writelog("size = "+int2str(size())+"\n");
|
||||
|
||||
m_x.resize(size(), 0.0);
|
||||
m_xnew.resize(size(), 0.0);
|
||||
for (int n = 0; n < m_nd; n++) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue