1 |
johnpye |
529 |
/* ASCEND modelling environment |
2 |
|
|
Copyright (C) 1990, 1993, 1994 Thomas Guthrie Epperly, Kirk Abbott. |
3 |
|
|
Copyright (C) 1997 Benjamin Allan |
4 |
|
|
Copyright (C) 2006 Carnegie Mellon University |
5 |
aw0a |
1 |
|
6 |
johnpye |
529 |
This program is free software; you can redistribute it and/or modify |
7 |
|
|
it under the terms of the GNU General Public License as published by |
8 |
|
|
the Free Software Foundation; either version 2, or (at your option) |
9 |
|
|
any later version. |
10 |
johnpye |
62 |
|
11 |
johnpye |
529 |
This program is distributed in the hope that it will be useful, |
12 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
|
|
GNU General Public License for more details. |
15 |
|
|
|
16 |
|
|
You should have received a copy of the GNU General Public License |
17 |
|
|
along with this program; if not, write to the Free Software |
18 |
|
|
Foundation, Inc., 59 Temple Place - Suite 330, |
19 |
|
|
Boston, MA 02111-1307, USA. |
20 |
|
|
*//** |
21 |
|
|
@file |
22 |
|
|
User package management. |
23 |
|
|
|
24 |
|
|
Users of this header should not have to include anything |
25 |
|
|
except instance_enum.h and list.h and whatever headers those |
26 |
|
|
may require. |
27 |
|
|
*//* |
28 |
|
|
by Ben Allan & Kirk Abbott |
29 |
|
|
Created: July 4, 1994 |
30 |
|
|
Version: $Revision: 1.12 $ |
31 |
|
|
Version control file: $RCSfile: packages.h,v $ |
32 |
|
|
Date last modified: $Date: 1998/05/18 16:36:45 $ |
33 |
|
|
Last modified by: $Author: ballan $ |
34 |
|
|
*/ |
35 |
|
|
|
36 |
johnpye |
62 |
#ifndef ASC_PACKAGES_H |
37 |
|
|
#define ASC_PACKAGES_H |
38 |
aw0a |
1 |
|
39 |
johnpye |
1067 |
/** @addtogroup compiler Compiler |
40 |
johnpye |
1066 |
@{ |
41 |
|
|
*/ |
42 |
|
|
|
43 |
johnpye |
62 |
/** |
44 |
jpye |
1616 |
Have included the follow here to simplify instructions for people |
45 |
johnpye |
62 |
writing their own external packages: |
46 |
|
|
*/ |
47 |
johnpye |
399 |
#include <utilities/ascConfig.h> |
48 |
johnpye |
62 |
#include "instance_enum.h" |
49 |
johnpye |
399 |
#include <general/list.h> |
50 |
johnpye |
62 |
#include "extfunc.h" |
51 |
aw0a |
1 |
|
52 |
johnpye |
379 |
#ifndef ASC_CLIENTDATA_DECLARED |
53 |
|
|
# ifdef __STDC__ |
54 |
|
|
typedef void *ascClientData; |
55 |
|
|
# else |
56 |
|
|
typedef int *ascClientData; |
57 |
|
|
# endif |
58 |
|
|
# define ASC_CLIENTDATA_DECLARED |
59 |
aw0a |
1 |
#endif |
60 |
|
|
|
61 |
jpye |
1616 |
/** |
62 |
johnpye |
529 |
these are for external clients to return to us when they have |
63 |
|
|
an error or other procedural message to report about flow of |
64 |
|
|
control. |
65 |
|
|
*/ |
66 |
aw0a |
1 |
#define ASC_OK 0 |
67 |
|
|
#define ASC_ERROR 1 |
68 |
|
|
#define ASC_RETURN 2 |
69 |
|
|
#define ASC_BREAK 3 |
70 |
|
|
#define ASC_CONTINUE 4 |
71 |
|
|
|
72 |
|
|
typedef int (Asc_MethodProc) (ascClientData, CONST char *, |
73 |
|
|
struct Instance *, struct gl_list_t *); |
74 |
|
|
|
75 |
|
|
typedef int (Asc_MethodDelete) (ascClientData, CONST char *, Asc_MethodProc); |
76 |
jds |
54 |
|
77 |
jpye |
1616 |
/** |
78 |
johnpye |
529 |
Clients should use the operators below to access this enum and |
79 |
|
|
associated structure. |
80 |
|
|
*/ |
81 |
aw0a |
1 |
enum argItemEnum { |
82 |
jds |
54 |
argError, /**< should never be seen by client */ |
83 |
|
|
/* the first 3 characters of the comment lines are the |
84 |
aw0a |
1 |
* equivalent of C conversion characters in printf when |
85 |
|
|
* specifying the arguments desired in the parsestring. |
86 |
|
|
*/ |
87 |
ben.allan |
33 |
argOldFileId, /**< OF name of an existing file (char *) */ |
88 |
|
|
argNewFileId, /**< NF name of new file (char *) */ |
89 |
|
|
argUnkFileId, /**< UF name of file, unknown status (char *) */ |
90 |
|
|
argFloat, /**< f maps ASCEND integer/real types to a float value */ |
91 |
|
|
argDouble, /**< g maps ASCEND integer/real types to a double value */ |
92 |
|
|
argLong, /**< ld maps ASCEND integer/boolean to long value. */ |
93 |
|
|
argDoublePtr, /**< pg maps ASCEND reals to a double * */ |
94 |
|
|
argLongPtr, /**< pld maps ASCEND integers to long * */ |
95 |
|
|
argInt, /**< d maps ASCEND integer/boolean to int value. */ |
96 |
|
|
argBoolean, /**< b maps ASCEND boolean or integer to 0,1 value */ |
97 |
|
|
argString, /**< s maps ASCEND symbol types to a C const char * */ |
98 |
|
|
argSetString, /**< ss maps ASCEND set types into a C const char * */ |
99 |
|
|
argNameString, /**< n maps ASCEND Name given into a C const char * */ |
100 |
|
|
argNameList, /**< N expand ASCEND Name given into a C const char * */ |
101 |
|
|
argTypeString, /**< T maps ASCEND type name given into a C const char * */ |
102 |
|
|
argInst, /**< i instance pointer may be any kind */ |
103 |
|
|
argInstReal, /**< R instance pointer must be REAL*INST */ |
104 |
|
|
argInstRealList, /**< LR flattens array of real insts into a gl_list */ |
105 |
|
|
argInstRealArray, /**< AR instance pointer must be an array of reals */ |
106 |
|
|
argDoubleConst, /**< CR pointer to new double value for unassigned const */ |
107 |
|
|
argInstInt, /**< I instance pointer must be INTEGER*INST */ |
108 |
|
|
argInstIntList, /**< LI flattens array of integer insts into a gl_list */ |
109 |
|
|
argInstIntArray, /**< AI instance pointer must be an array of integers */ |
110 |
|
|
argIntConst, /**< CI pointer to new long value for unassigned const */ |
111 |
|
|
argInstBool, /**< B instance must be BOOLEAN_[ATOM/CONSTANT]_INST */ |
112 |
|
|
argInstBoolList, /**< LB flattens array of boolean insts into a gl_list */ |
113 |
|
|
argInstBoolArray, /**< AB instance pointer must be an array of boolean */ |
114 |
|
|
argBoolConst, /**< CB pointer to new 0/1 value for unassigned const */ |
115 |
|
|
argInstSym, /**< S instance must be SYMBOL_[ATOM/CONSTANT]_INST */ |
116 |
|
|
argInstSymList, /**< LS flattens array of symbol insts into a gl_list */ |
117 |
|
|
argInstSymArray, /**< AS instance pointer must be an array of symbols */ |
118 |
|
|
argSymConst, /**< CS pointer to new char * value for unassigned const */ |
119 |
|
|
argInstSet, /**< SS instance must be SET_[ATOM/CONSTANT]_INST */ |
120 |
|
|
argInstSetList, /**< LSS flattens array of set insts into a gl_list */ |
121 |
|
|
argInstSetArray, /**< ASS instance pointer must be an array of sets */ |
122 |
|
|
argISetConst, /**< CSS pointer to gl_list of longs for unassigned set */ |
123 |
|
|
argESetConst, /**< DSS pointer to gl_list of char * for unassigned set */ |
124 |
|
|
argInstRel, /**< r instance must be RELATION_INST */ |
125 |
|
|
argInstRelList, /**< Lr flattens array of relation insts into a gl_list */ |
126 |
|
|
argInstRelArray, /**< Ar instance pointer must be an array of relations */ |
127 |
|
|
argInstLRel, /**< lr instance must be LOGREL_INST */ |
128 |
|
|
argInstLRelList, /**< Llr flattens array of logrelations into a gl_list */ |
129 |
|
|
argInstLRelArray, /**< Alr instance pointer must be an array of logrel */ |
130 |
|
|
argInstModel, /**< M MODEL instance pointer */ |
131 |
|
|
argInstModelList, /**< LM flattens array of MODEL insts into a gl_list */ |
132 |
|
|
argInstModelArray,/**< AM flattens array of MODEL insts into a gl_list */ |
133 |
|
|
argProcName, /**< P maps name of a method/call to a CONST char * */ |
134 |
|
|
argExpr, /**< V maps a reference to an ASCEND Expr into lval */ |
135 |
|
|
argSLit /**< Q a C string literal is expected. */ |
136 |
jds |
54 |
/* probably need to add type Q for double quoted text */ |
137 |
aw0a |
1 |
}; |
138 |
jds |
54 |
|
139 |
aw0a |
1 |
struct argItem { |
140 |
|
|
enum argItemEnum kind; |
141 |
ben.allan |
33 |
int depth; /**< For Array and list arguments, sets the number of |
142 |
aw0a |
1 |
* subscripts expected. If 0, any number is allowed. |
143 |
|
|
* Internal use only. |
144 |
|
|
*/ |
145 |
|
|
union { |
146 |
jds |
54 |
double dval; /**< double value */ |
147 |
|
|
long lival; /**< long int value */ |
148 |
|
|
double dptr; /**< double pointer */ |
149 |
|
|
long liptr; /**< long int pointer */ |
150 |
|
|
int ival; /**< int value */ |
151 |
|
|
int bval; /**< boolean value */ |
152 |
|
|
CONST char *cval; /**< const char * from an ascend set/symbol */ |
153 |
|
|
CONST char *nval; /**< string form of the ascend name given */ |
154 |
|
|
CONST char *fval; /**< file id string */ |
155 |
ben.allan |
33 |
CONST struct gl_list_t *lval; /**< list according to enum */ |
156 |
jds |
54 |
struct Instance *i; /**< instance according to enum */ |
157 |
|
|
} u; /**< union of possible values */ |
158 |
|
|
short args; /**< 0 usually. 1 if item is ... at the end. Internal use. */ |
159 |
|
|
short exact; /**< 0 usually. 1 if type specifier to be match. 2 if exactly */ |
160 |
johnpye |
62 |
symchar *type_name; /**< typeidentifier from the symbol table */ |
161 |
aw0a |
1 |
}; |
162 |
|
|
|
163 |
jds |
54 |
#define Asc_argItemKind(aip) ((aip)->kind) |
164 |
|
|
#define Asc_argItemDepth(aip) ((aip)->depth) |
165 |
|
|
#define Asc_argItemInstance(aip) ((aip)->u.i) |
166 |
|
|
#define Asc_argItemDoublePtr(aip) ((aip)->u.dptr) |
167 |
|
|
#define Asc_argItemLongPtr(aip) ((aip)->u.liptr) |
168 |
|
|
#define Asc_argItemDouble(aip) ((aip)->u.dval) |
169 |
|
|
#define Asc_argItemLongVal(aip) ((aip)->u.lival) |
170 |
|
|
#define Asc_argItemIntVal(aip) ((aip)->u.ival) |
171 |
|
|
#define Asc_argItemBoolVal(aip) ((aip)->u.bval) |
172 |
|
|
#define Asc_argItemStringVal(aip) ((aip)->u.cval) |
173 |
|
|
#define Asc_argItemNameString(aip) ((aip)->u.nval) |
174 |
|
|
#define Asc_argItemTypeName(aip) ((aip)->u.nval) |
175 |
|
|
#define Asc_argItemFileString(aip) ((aip)->u.fval) |
176 |
|
|
#define Asc_argItemListValue(aip) ((aip)->u.lval) |
177 |
johnpye |
62 |
/**< |
178 |
aw0a |
1 |
* All of the data in or referenced directly by an argItem |
179 |
|
|
* should not be changed or destroyed by the user proc. |
180 |
|
|
* The only exception is that the value pointed to by argItemDoublePtr |
181 |
|
|
* or argItemLongPtr items may be changed. |
182 |
|
|
*/ |
183 |
|
|
|
184 |
jpye |
1519 |
/* Asc_AddUserMethod is not used and has been removed from this header. We are |
185 |
|
|
using CreateUserFunctionMethod instead. */ |
186 |
johnpye |
62 |
|
187 |
jpye |
1519 |
/* Asc_DeleteUserMethod was not being used and has been removed from this |
188 |
|
|
header. Not sure what we are using instead, actually. */ |
189 |
johnpye |
62 |
|
190 |
|
|
/** Look up the brief help text for a named external method. */ |
191 |
jds |
54 |
extern CONST char *Asc_UserMethodDescription(char *mname); |
192 |
|
|
/**< |
193 |
johnpye |
62 |
@return description oneliner help string for a named method, or NULL if mname unknown. |
194 |
|
|
@param mname name of the method |
195 |
|
|
*/ |
196 |
aw0a |
1 |
|
197 |
johnpye |
62 |
|
198 |
|
|
/** Loop up detailed help text for a named external method. */ |
199 |
jds |
54 |
extern CONST char *Asc_UserMethodDetails(char *mname); |
200 |
johnpye |
62 |
/**< |
201 |
|
|
@return long descriptive help text for the named method, or NULL if mname unknown. |
202 |
|
|
@param mname name of the method |
203 |
|
|
*/ |
204 |
aw0a |
1 |
|
205 |
johnpye |
62 |
|
206 |
|
|
/** Get a list of all defined user methods in the user packages library. */ |
207 |
aw0a |
1 |
extern struct gl_list_t *Asc_UserMethodsDefined(void); |
208 |
jpye |
1616 |
/**< |
209 |
johnpye |
62 |
@return list of const char* pointers where registered method names are stored. |
210 |
aw0a |
1 |
|
211 |
johnpye |
62 |
The caller should gl_destroy(mlist) when done with looking at it. |
212 |
|
|
*/ |
213 |
|
|
|
214 |
|
|
/** Give usage info for a named user method */ |
215 |
jds |
54 |
extern int Asc_UserMethodArguments(FILE *fp, char *mname); |
216 |
jpye |
1616 |
/**< |
217 |
johnpye |
62 |
@param fp file to which the output should be written |
218 |
|
|
@param mname method name for which details are required |
219 |
aw0a |
1 |
|
220 |
johnpye |
62 |
Writes a synopsis of the arguments required, based on information |
221 |
|
|
derived from the parse-string to fp. |
222 |
|
|
*/ |
223 |
aw0a |
1 |
|
224 |
johnpye |
62 |
/*------------------------------------------------------- |
225 |
|
|
This whole header is junk below here. Temporarily, it is functioning |
226 |
|
|
extern * junk. We need to reimplement some and scrap the rest. |
227 |
|
|
*/ |
228 |
|
|
|
229 |
|
|
/** @file packages.h |
230 |
|
|
Interface to external packages |
231 |
|
|
@see @ref packagespage "Packages" |
232 |
|
|
*/ |
233 |
|
|
|
234 |
|
|
/** @page packagespage |
235 |
|
|
|
236 |
|
|
This file implements an interface to external packages. These external packages may be invoked from the procedural section, say for doing external calculations, querying a database, and writing/ reading values from the instance tree. They may also be used in the declarative section for providing relations to augment those in the declarative section. These may be full models/ solvers capable of solving themselves or smarter models/matrix routines capable of operating in a single step mode. [This overloading has caused a protocol that serves neither very well.] The rest of the discussion here is based on packages in the procedural section, and packages in the declarative section that will solve themselves to completion at each major iteration of the solution scheme in which they are imbedded. |
237 |
|
|
|
238 |
|
|
@section procedural Procedural section |
239 |
|
|
|
240 |
|
|
The packages provided in the procedural section follow the 'foreign pointer' concept; i.e., they will be handed a pointer to a reference instance, and a list of list of arguments. They need to provide only the number of input arguements, and may freely manipulate the instance tree and whatever way they feel. The only *mandatory* function must respect the following function prototype: |
241 |
|
|
|
242 |
|
|
@code |
243 |
johnpye |
908 |
int (*proc) (struct BBoxInterp *interp |
244 |
johnpye |
62 |
,struct Instance *reference |
245 |
|
|
,struct gl_list_t *arglist |
246 |
|
|
); |
247 |
|
|
@endcode |
248 |
|
|
|
249 |
|
|
An optional help string may be provided. We will *make a copy* of this string, if non-null. When invoked this package must do whatever arg checking that is necessary, do its thing, and return a nonzero error result if there are any errors. |
250 |
|
|
|
251 |
|
|
@section declarative Declarative section |
252 |
|
|
|
253 |
|
|
More information is need from the packages in the declarative section that provide relations. In particular a *presolve/init* routine must be provided, which the compiler/solver will invoke to make sure that all is ok. This package when registering itself has to provide: n_input_args -- the number of input args on its arglist. n_output_args -- the number of output args on its arglist. In addition to the presolve/init routine, the following functions for doing function and jacobian evaluations have to be provided. The deriv (jacobian evaluation routine) and higher order derivative routines may be left NULL, and finite difference via repeated function calls will be done. The calling protocal for all functions is as follows: |
254 |
|
|
|
255 |
|
|
@code |
256 |
johnpye |
908 |
int (*init) (struct BBoxInterp *interp, |
257 |
johnpye |
62 |
struct Instance *model_data, |
258 |
|
|
struct gl_list_t *arglist); |
259 |
|
|
|
260 |
johnpye |
908 |
int (*value) (struct BBoxInterp *interp, |
261 |
johnpye |
62 |
int ninputs, int noutputs, |
262 |
|
|
double *inputs, double *outputs, |
263 |
|
|
double *jacobian); |
264 |
|
|
|
265 |
johnpye |
908 |
int (*deriv) (struct BBoxInterp *interp, |
266 |
johnpye |
62 |
int ninputs, int noutputs, |
267 |
|
|
double *inputs, double *outputs, |
268 |
|
|
double *jacobian); |
269 |
|
|
@endcode |
270 |
|
|
|
271 |
|
|
deriv2 and any higher order derivatives that come along will follow same calling protocol as for value and deriv. |
272 |
|
|
|
273 |
|
|
@note The arguement model_data is provided for external packages that need to get additional information from the instance tree so as to do there computations. This information, should ideally be retrieved during exection of the init function and cached away. |
274 |
|
|
|
275 |
|
|
@section interpreter The Interpreter |
276 |
|
|
|
277 |
|
|
The interpreter structure is the means of communication between external packages and the ASCEND instance tree and/or solvers. It is particularly necessary in the case of packages in the declarative section. The state of the bit flags must be monitored and appropriate action taken. In the case of an error, a nonzero result must be returned from all functions, and the reason indicated by writing to the interp->status field. At the moment 1 wild hook is provided for the convenience of users. A user may attach an object to this hook and it will be passed around to each of its function calls. As an example consider the following code fragment. |
278 |
|
|
|
279 |
|
|
@code |
280 |
johnpye |
908 |
int init(struct BBoxInterp *interp |
281 |
johnpye |
62 |
, struct Instance *data |
282 |
|
|
,struct gl_list_t *arglist) |
283 |
|
|
{ |
284 |
|
|
struct my_solve_system *system; |
285 |
|
|
double *my_inputs; |
286 |
johnpye |
908 |
if(interp->firstcall){ |
287 |
johnpye |
62 |
system = my_presolve(data,arglist); |
288 |
|
|
|
289 |
|
|
if (system!=NULL) { |
290 |
|
|
my_inputs = MakeVectorFromList(arglist); |
291 |
|
|
system->inputs = my_inputs; |
292 |
johnpye |
908 |
interp->user_data = (void *)system; |
293 |
johnpye |
62 |
}else{ |
294 |
johnpye |
908 |
interp->status = calc__error; |
295 |
johnpye |
62 |
return 1; |
296 |
|
|
} |
297 |
|
|
}else{ |
298 |
johnpye |
908 |
destroy_sys((my_solve_system *)interp->user_data); |
299 |
|
|
interp->user_data = NULL; |
300 |
johnpye |
62 |
} |
301 |
johnpye |
908 |
interp->status = calc_all_ok; |
302 |
johnpye |
62 |
return 0; |
303 |
|
|
} |
304 |
|
|
@endcode |
305 |
|
|
|
306 |
|
|
The arglist and all references to instances have been intentionally removed from the value (function evaluation) and deriv* routines so as to allow ease of interfacing to existing standalone packages. |
307 |
|
|
*/ |
308 |
|
|
|
309 |
|
|
/** Reset the interpreter to its initial state. */ |
310 |
johnpye |
908 |
extern void Reset_BBoxInterp(struct BBoxInterp *interp); |
311 |
johnpye |
62 |
/* |
312 |
|
|
@deprecated { Needs revising @see packages.h } |
313 |
|
|
*/ |
314 |
aw0a |
1 |
|
315 |
johnpye |
62 |
/** Register all statically-linked user packages */ |
316 |
aw0a |
1 |
extern void AddUserFunctions(void); |
317 |
jpye |
1616 |
/**< |
318 |
johnpye |
62 |
@deprecated { Needs revising @see packages.h } |
319 |
aw0a |
1 |
|
320 |
johnpye |
62 |
If the compiler-time flag STATIC_PACKAGES was set, this function should load any statically linked packages into the user packages library. If the flag was not set, it should do nothing. |
321 |
|
|
*/ |
322 |
|
|
|
323 |
johnpye |
908 |
#ifdef TEST_RELOCATE |
324 |
johnpye |
62 |
/** Calculate an external relation */ |
325 |
jds |
54 |
extern int CallExternalProcs(struct Instance *i); |
326 |
|
|
/**< |
327 |
johnpye |
62 |
@deprecated { Needs revising @see packages.h } |
328 |
aw0a |
1 |
|
329 |
johnpye |
62 |
This function given a handle to a relation instance which represents an external relation, will attempt to invoke it and write the results to stdout. |
330 |
|
|
*/ |
331 |
johnpye |
908 |
#endif |
332 |
johnpye |
62 |
|
333 |
jpye |
1519 |
extern int package_load(CONST char *partialpath, CONST char *initfunc); |
334 |
jpye |
1616 |
/**< |
335 |
|
|
Generalised loading of external libraries. This allows for the possibility of |
336 |
johnpye |
864 |
libraries being either external shared libraries (DLL or SO files) or external scripts |
337 |
|
|
of types registered using importhandler_add(). |
338 |
|
|
|
339 |
|
|
@param name the short name of the library, as well as partial directory path, optionally |
340 |
|
|
@param initfunc name of the registration function, or NULL. |
341 |
johnpye |
62 |
@return 0 if success, 1 if failure. |
342 |
aw0a |
1 |
|
343 |
johnpye |
864 |
@note |
344 |
|
|
This function was previously deprecated but now it is positively encouraged! |
345 |
jds |
54 |
|
346 |
johnpye |
864 |
If the registration function name is not specified, it will be auto-generated by the importhandler's importfn. |
347 |
|
|
|
348 |
|
|
In the case of external DLL/SO files, the registration function must be visible in your DLL/SO and have the funciton prototype: |
349 |
jpye |
1616 |
|
350 |
johnpye |
864 |
@code void Routine_register(void); @endcode |
351 |
johnpye |
62 |
*/ |
352 |
|
|
|
353 |
johnpye |
908 |
extern void Init_BBoxInterp(struct BBoxInterp *interp); |
354 |
johnpye |
542 |
/**< |
355 |
|
|
@deprecated { Needs revising @see packages.h } |
356 |
|
|
|
357 |
|
|
Gets the interpreter back to a 'clean' state. The default settings are guaranteed to be as follows: |
358 |
|
|
@li nodestamp = 0; |
359 |
|
|
@li status = calc_all_ok; |
360 |
|
|
@li first_call = (unsigned)0; |
361 |
|
|
@li last_call = (unsigned)0; |
362 |
|
|
@li check_args = (unsigned)0; |
363 |
|
|
@li recalculate = (unsigned)0; |
364 |
|
|
@li deriv_eval = (unsigned)0; |
365 |
|
|
@li func_eval = (unsigned)0; |
366 |
|
|
*/ |
367 |
|
|
|
368 |
johnpye |
1066 |
/* @} */ |
369 |
|
|
|
370 |
johnpye |
62 |
#endif /* ASC_PACKAGES_H */ |
371 |
|
|
|