From 45cf7633fec697fcfcf9ed8985a2a7e1ebfa01a8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 9 Sep 2010 06:29:44 +0000 Subject: [PATCH] remove class methods for defining properties eg: bpy.types.Scene.BoolProperty() --- release/scripts/io/netrender/ui.py | 47 ++++++++++--------- release/scripts/modules/bpy_types.py | 4 +- .../ui/properties_data_armature_rigify.py | 39 ++++----------- source/blender/python/intern/bpy_props.c | 44 ++++++++--------- source/blender/python/intern/bpy_props.h | 26 ---------- source/blender/python/intern/bpy_rna.c | 15 ------ 6 files changed, 57 insertions(+), 118 deletions(-) diff --git a/release/scripts/io/netrender/ui.py b/release/scripts/io/netrender/ui.py index c2d943f63f8..7a784af01ea 100644 --- a/release/scripts/io/netrender/ui.py +++ b/release/scripts/io/netrender/ui.py @@ -339,42 +339,43 @@ class NetRenderJob(bpy.types.IDPropertyGroup): pass def addProperties(): - bpy.types.Scene.PointerProperty(attr="network_render", type=NetRenderSettings, name="Network Render", description="Network Render Settings") + from bpy.props import PointerProperty, StringProperty, BoolProperty, EnumProperty, IntProperty, CollectionProperty + bpy.types.Scene.network_render = PointerProperty(type=NetRenderSettings, name="Network Render", description="Network Render Settings") - NetRenderSettings.StringProperty( attr="server_address", + NetRenderSettings.server_address = StringProperty( name="Server address", description="IP or name of the master render server", maxlen = 128, default = "[default]") - NetRenderSettings.IntProperty( attr="server_port", + NetRenderSettings.server_port = IntProperty( name="Server port", description="port of the master render server", default = 8000, min=1, max=65535) - NetRenderSettings.BoolProperty( attr="use_master_broadcast", + NetRenderSettings.use_master_broadcast = BoolProperty( name="Broadcast", description="broadcast master server address on local network", default = True) - NetRenderSettings.BoolProperty( attr="use_slave_clear", + NetRenderSettings.use_slave_clear = BoolProperty( name="Clear on exit", description="delete downloaded files on exit", default = True) - NetRenderSettings.BoolProperty( attr="use_slave_thumb", + NetRenderSettings.use_slave_thumb = BoolProperty( name="Generate thumbnails", description="Generate thumbnails on slaves instead of master", default = False) - NetRenderSettings.BoolProperty( attr="use_slave_output_log", + NetRenderSettings.use_slave_output_log = BoolProperty( name="Output render log on console", description="Output render text log to console as well as sending it to the master", default = True) - NetRenderSettings.BoolProperty( attr="use_master_clear", + NetRenderSettings.use_master_clear = BoolProperty( name="Clear on exit", description="delete saved files on exit", default = False) @@ -389,67 +390,67 @@ def addProperties(): elif not default_path.endswith(os.sep): default_path += os.sep - NetRenderSettings.StringProperty( attr="path", + NetRenderSettings.path = StringProperty( name="Path", description="Path for temporary files", maxlen = 128, default = default_path, subtype='FILE_PATH') - NetRenderSettings.StringProperty( attr="job_name", + NetRenderSettings.job_name = StringProperty( name="Job name", description="Name of the job", maxlen = 128, default = "[default]") - NetRenderSettings.StringProperty( attr="job_category", + NetRenderSettings.job_category = StringProperty( name="Job category", description="Category of the job", maxlen = 128, default = "") - NetRenderSettings.IntProperty( attr="chunks", + NetRenderSettings.chunks = IntProperty( name="Chunks", description="Number of frame to dispatch to each slave in one chunk", default = 5, min=1, max=65535) - NetRenderSettings.IntProperty( attr="priority", + NetRenderSettings.priority = IntProperty( name="Priority", description="Priority of the job", default = 1, min=1, max=10) - NetRenderSettings.StringProperty( attr="job_id", + NetRenderSettings.job_id = StringProperty( name="Network job id", description="id of the last sent render job", maxlen = 64, default = "") - NetRenderSettings.IntProperty( attr="active_slave_index", + NetRenderSettings.active_slave_index = IntProperty( name="Index of the active slave", description="", default = -1, min= -1, max=65535) - NetRenderSettings.IntProperty( attr="active_blacklisted_slave_index", + NetRenderSettings.active_blacklisted_slave_index = IntProperty( name="Index of the active slave", description="", default = -1, min= -1, max=65535) - NetRenderSettings.IntProperty( attr="active_job_index", + NetRenderSettings.active_job_index = IntProperty( name="Index of the active job", description="", default = -1, min= -1, max=65535) - NetRenderSettings.EnumProperty(attr="mode", + NetRenderSettings.mode = EnumProperty( items=( ("RENDER_CLIENT", "Client", "Act as render client"), ("RENDER_MASTER", "Master", "Act as render master"), @@ -459,17 +460,17 @@ def addProperties(): description="Mode of operation of this instance", default="RENDER_CLIENT") - NetRenderSettings.CollectionProperty(attr="slaves", type=NetRenderSlave, name="Slaves", description="") - NetRenderSettings.CollectionProperty(attr="slaves_blacklist", type=NetRenderSlave, name="Slaves Blacklist", description="") - NetRenderSettings.CollectionProperty(attr="jobs", type=NetRenderJob, name="Job List", description="") + NetRenderSettings.slaves = CollectionProperty(type=NetRenderSlave, name="Slaves", description="") + NetRenderSettings.slaves_blacklist = CollectionProperty(type=NetRenderSlave, name="Slaves Blacklist", description="") + NetRenderSettings.jobs = CollectionProperty(type=NetRenderJob, name="Job List", description="") - NetRenderSlave.StringProperty( attr="name", + NetRenderSlave.name = StringProperty( name="Name of the slave", description="", maxlen = 64, default = "") - NetRenderJob.StringProperty( attr="name", + NetRenderJob.name = StringProperty( name="Name of the job", description="", maxlen = 128, diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 9219f7edcb0..b349fa0a76e 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -27,8 +27,8 @@ class RNA_IDProp_Meta(type): # bpy.types.Scene.myprop = bpy.props.BoolProperty() def __setattr__(cls, attr, value): if type(value) == tuple and len(value) == 2: - print(cls, attr, value) - if attr in cls.bl_rna.properties: + prop = cls.bl_rna.properties.get(attr) + if prop and prop.is_runtime: _bpy.props.RemoveProperty(cls, attr=attr) func, kw = value kw["attr"] = attr diff --git a/release/scripts/ui/properties_data_armature_rigify.py b/release/scripts/ui/properties_data_armature_rigify.py index afcf0b336ed..92b9074892b 100644 --- a/release/scripts/ui/properties_data_armature_rigify.py +++ b/release/scripts/ui/properties_data_armature_rigify.py @@ -18,14 +18,17 @@ # import bpy - - -class PoseTemplateSettings(bpy.types.IDPropertyGroup): - pass +from bpy.props import * class PoseTemplate(bpy.types.IDPropertyGroup): - pass + name = StringProperty(attr="name", name="Name of the slave", description="", maxlen=64, default="") + active_template_index = IntProperty(name="Index of the active slave", description="", default=-1, min=-1, max=65535) + use_generate_deform_rig = BoolProperty(name="Create Deform Rig", description="Create a copy of the metarig, constrainted by the generated rig", default=False) + + +class PoseTemplateSettings(bpy.types.IDPropertyGroup): + templates = CollectionProperty(type=PoseTemplate, name="Templates", description="") def metarig_templates(): @@ -104,10 +107,6 @@ class DATA_PT_template(bpy.types.Panel): sub.operator("pose.metarig_reload", icon="FILE_REFRESH", text="") -# operators -from bpy.props import StringProperty - - class Reload(bpy.types.Operator): '''Re-Scan the metarig package directory for scripts''' @@ -314,27 +313,7 @@ import space_info # ensure the menu is loaded first def register(): - PoseTemplate.StringProperty(attr="name", - name="Name of the slave", - description="", - maxlen=64, - default="") - - PoseTemplateSettings.CollectionProperty(attr="templates", type=PoseTemplate, name="Templates", description="") - PoseTemplateSettings.IntProperty(attr="active_template_index", - name="Index of the active slave", - description="", - default=-1, - min=-1, - max=65535) - - PoseTemplateSettings.BoolProperty(attr="use_generate_deform_rig", - name="Create Deform Rig", - description="Create a copy of the metarig, constrainted by the generated rig", - default=False) - - bpy.types.Scene.PointerProperty(attr="pose_templates", type=PoseTemplateSettings, name="Pose Templates", description="Pose Template Settings") - + bpy.types.Scene.pose_templates = PointerProperty(type=PoseTemplateSettings, name="Pose Templates", description="Pose Template Settings") space_info.INFO_MT_armature_add.append(menu_func) diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index 3d8eb04093f..8f75ae3e76e 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -143,7 +143,7 @@ static int bpy_struct_id_used(StructRNA *srna, char *identifier) /* Function that sets RNA, NOTE - self is NULL when called from python, but being abused from C so we can pass the srna allong * This isnt incorrect since its a python object - but be careful */ -char BPy_BoolProperty_doc[] = +static char BPy_BoolProperty_doc[] = ".. function:: BoolProperty(name=\"\", description=\"\", default=False, options={'ANIMATABLE'}, subtype='NONE')\n" "\n" " Returns a new boolean property definition.\n" @@ -153,7 +153,7 @@ char BPy_BoolProperty_doc[] = " :arg subtype: Enumerator in ['UNSIGNED', 'PERCENTAGE', 'FACTOR', 'ANGLE', 'TIME', 'DISTANCE', 'NONE'].\n" " :type subtype: string"; -PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) +static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -200,7 +200,7 @@ PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) Py_RETURN_NONE; } -char BPy_BoolVectorProperty_doc[] = +static char BPy_BoolVectorProperty_doc[] = ".. function:: BoolVectorProperty(name=\"\", description=\"\", default=(False, False, False), options={'ANIMATABLE'}, subtype='NONE', size=3)\n" "\n" " Returns a new vector boolean property definition.\n" @@ -209,7 +209,7 @@ char BPy_BoolVectorProperty_doc[] = " :type options: set\n" " :arg subtype: Enumerator in ['COLOR', 'TRANSLATION', 'DIRECTION', 'VELOCITY', 'ACCELERATION', 'MATRIX', 'EULER', 'QUATERNION', 'AXISANGLE', 'XYZ', 'COLOR_GAMMA', 'LAYER', 'NONE'].\n" " :type subtype: string"; -PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw) +static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -267,7 +267,7 @@ PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw) Py_RETURN_NONE; } -char BPy_IntProperty_doc[] = +static char BPy_IntProperty_doc[] = ".. function:: IntProperty(name=\"\", description=\"\", default=0, min=-sys.maxint, max=sys.maxint, soft_min=-sys.maxint, soft_max=sys.maxint, step=1, options={'ANIMATABLE'}, subtype='NONE')\n" "\n" " Returns a new int property definition.\n" @@ -276,7 +276,7 @@ char BPy_IntProperty_doc[] = " :type options: set\n" " :arg subtype: Enumerator in ['UNSIGNED', 'PERCENTAGE', 'FACTOR', 'ANGLE', 'TIME', 'DISTANCE', 'NONE'].\n" " :type subtype: string"; -PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) +static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -323,7 +323,7 @@ PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) Py_RETURN_NONE; } -char BPy_IntVectorProperty_doc[] = +static char BPy_IntVectorProperty_doc[] = ".. function:: IntVectorProperty(name=\"\", description=\"\", default=(0, 0, 0), min=-sys.maxint, max=sys.maxint, soft_min=-sys.maxint, soft_max=sys.maxint, options={'ANIMATABLE'}, subtype='NONE', size=3)\n" "\n" " Returns a new vector int property definition.\n" @@ -332,7 +332,7 @@ char BPy_IntVectorProperty_doc[] = " :type options: set\n" " :arg subtype: Enumerator in ['COLOR', 'TRANSLATION', 'DIRECTION', 'VELOCITY', 'ACCELERATION', 'MATRIX', 'EULER', 'QUATERNION', 'AXISANGLE', 'XYZ', 'COLOR_GAMMA', 'LAYER', 'NONE'].\n" " :type subtype: string"; -PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject *kw) +static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -391,7 +391,7 @@ PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject *kw) } -char BPy_FloatProperty_doc[] = +static char BPy_FloatProperty_doc[] = ".. function:: FloatProperty(name=\"\", description=\"\", default=0.0, min=sys.float_info.min, max=sys.float_info.max, soft_min=sys.float_info.min, soft_max=sys.float_info.max, step=3, precision=2, options={'ANIMATABLE'}, subtype='NONE', unit='NONE')\n" "\n" " Returns a new float property definition.\n" @@ -402,7 +402,7 @@ char BPy_FloatProperty_doc[] = " :type subtype: string\n" " :arg unit: Enumerator in ['NONE', 'LENGTH', 'AREA', 'VOLUME', 'ROTATION', 'TIME', 'VELOCITY', 'ACCELERATION'].\n" " :type unit: string\n"; -PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) +static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -457,7 +457,7 @@ PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) Py_RETURN_NONE; } -char BPy_FloatVectorProperty_doc[] = +static char BPy_FloatVectorProperty_doc[] = ".. function:: FloatVectorProperty(name=\"\", description=\"\", default=(0.0, 0.0, 0.0), min=sys.float_info.min, max=sys.float_info.max, soft_min=sys.float_info.min, soft_max=sys.float_info.max, step=3, precision=2, options={'ANIMATABLE'}, subtype='NONE', size=3)\n" "\n" " Returns a new vector float property definition.\n" @@ -466,7 +466,7 @@ char BPy_FloatVectorProperty_doc[] = " :type options: set\n" " :arg subtype: Enumerator in ['COLOR', 'TRANSLATION', 'DIRECTION', 'VELOCITY', 'ACCELERATION', 'MATRIX', 'EULER', 'QUATERNION', 'AXISANGLE', 'XYZ', 'COLOR_GAMMA', 'LAYER', 'NONE'].\n" " :type subtype: string"; -PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw) +static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -524,7 +524,7 @@ PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw) Py_RETURN_NONE; } -char BPy_StringProperty_doc[] = +static char BPy_StringProperty_doc[] = ".. function:: StringProperty(name=\"\", description=\"\", default=\"\", maxlen=0, options={'ANIMATABLE'}, subtype='NONE')\n" "\n" " Returns a new string property definition.\n" @@ -533,7 +533,7 @@ char BPy_StringProperty_doc[] = " :type options: set\n" " :arg subtype: Enumerator in ['FILE_PATH', 'DIR_PATH', 'FILENAME', 'NONE'].\n" " :type subtype: string"; -PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw) +static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -625,7 +625,7 @@ static EnumPropertyItem *enum_items_from_py(PyObject *value, const char *def, in return items; } -char BPy_EnumProperty_doc[] = +static char BPy_EnumProperty_doc[] = ".. function:: EnumProperty(items, name=\"\", description=\"\", default=\"\", options={'ANIMATABLE'})\n" "\n" " Returns a new enumerator property definition.\n" @@ -634,7 +634,7 @@ char BPy_EnumProperty_doc[] = " :type options: set\n" " :arg items: The items that make up this enumerator.\n" " :type items: sequence of string triplets"; -PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw) +static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -698,7 +698,7 @@ static StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix return srna; } -char BPy_PointerProperty_doc[] = +static char BPy_PointerProperty_doc[] = ".. function:: PointerProperty(items, type=\"\", description=\"\", default=\"\", options={'ANIMATABLE'})\n" "\n" " Returns a new pointer property definition.\n" @@ -707,7 +707,7 @@ char BPy_PointerProperty_doc[] = " :type options: set\n" " :arg type: Dynamic type from :mod:`bpy.types`.\n" " :type type: class"; -PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) +static PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -747,7 +747,7 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) Py_RETURN_NONE; } -char BPy_CollectionProperty_doc[] = +static char BPy_CollectionProperty_doc[] = ".. function:: CollectionProperty(items, type=\"\", description=\"\", default=\"\", options={'ANIMATABLE'})\n" "\n" " Returns a new collection property definition.\n" @@ -756,7 +756,7 @@ char BPy_CollectionProperty_doc[] = " :type options: set\n" " :arg type: Dynamic type from :mod:`bpy.types`.\n" " :type type: class"; -PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) +static PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -796,14 +796,14 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) Py_RETURN_NONE; } -char BPy_RemoveProperty_doc[] = +static char BPy_RemoveProperty_doc[] = ".. function:: RemoveProperty(attr)\n" "\n" " Removes a dynamically defined property.\n" "\n" " :arg attr: Property name.\n" " :type attr: string"; -PyObject *BPy_RemoveProperty(PyObject *self, PyObject *args, PyObject *kw) +static PyObject *BPy_RemoveProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; diff --git a/source/blender/python/intern/bpy_props.h b/source/blender/python/intern/bpy_props.h index d90b12c0f91..fc295ccdf5d 100644 --- a/source/blender/python/intern/bpy_props.h +++ b/source/blender/python/intern/bpy_props.h @@ -29,32 +29,6 @@ PyObject *BPY_rna_props( void ); -/* functions for setting up new props - experemental */ -PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw); -PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw); -PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw); -PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject *kw); -PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw); -PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw); -PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw); -PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw); -PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw); -PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw); - -PyObject *BPy_RemoveProperty(PyObject *self, PyObject *args, PyObject *kw); - -extern char BPy_BoolProperty_doc[]; -extern char BPy_BoolVectorProperty_doc[]; -extern char BPy_IntProperty_doc[]; -extern char BPy_IntVectorProperty_doc[]; -extern char BPy_FloatProperty_doc[]; -extern char BPy_FloatVectorProperty_doc[]; -extern char BPy_StringProperty_doc[]; -extern char BPy_EnumProperty_doc[]; -extern char BPy_PointerProperty_doc[]; -extern char BPy_CollectionProperty_doc[];\ -extern char BPy_RemoveProperty_doc[]; - #define PYRNA_STACK_ARRAY 32 #endif diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index f5e8e0e7b4e..48ed0619bb1 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -3271,21 +3271,6 @@ static struct PyMethodDef pyrna_struct_methods[] = { /* experemental */ {"callback_add", (PyCFunction)pyrna_callback_add, METH_VARARGS, NULL}, {"callback_remove", (PyCFunction)pyrna_callback_remove, METH_VARARGS, NULL}, - - /* class methods, only valid for subclasses */ - {"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS|METH_CLASS, BPy_BoolProperty_doc}, - {"BoolVectorProperty", (PyCFunction)BPy_BoolVectorProperty, METH_VARARGS|METH_KEYWORDS|METH_CLASS, BPy_BoolVectorProperty_doc}, - {"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS|METH_CLASS, BPy_IntProperty_doc}, - {"IntVectorProperty", (PyCFunction)BPy_IntVectorProperty, METH_VARARGS|METH_KEYWORDS|METH_CLASS, BPy_IntVectorProperty_doc}, - {"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS|METH_CLASS, BPy_FloatProperty_doc}, - {"FloatVectorProperty", (PyCFunction)BPy_FloatVectorProperty, METH_VARARGS|METH_KEYWORDS|METH_CLASS, BPy_FloatVectorProperty_doc}, - {"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS|METH_CLASS, BPy_StringProperty_doc}, - {"EnumProperty", (PyCFunction)BPy_EnumProperty, METH_VARARGS|METH_KEYWORDS|METH_CLASS, BPy_EnumProperty_doc}, - {"PointerProperty", (PyCFunction)BPy_PointerProperty, METH_VARARGS|METH_KEYWORDS|METH_CLASS, BPy_PointerProperty_doc}, - {"CollectionProperty", (PyCFunction)BPy_CollectionProperty, METH_VARARGS|METH_KEYWORDS|METH_CLASS, BPy_CollectionProperty_doc}, - - {"RemoveProperty", (PyCFunction)BPy_RemoveProperty, METH_VARARGS|METH_KEYWORDS|METH_CLASS, BPy_RemoveProperty_doc}, - {NULL, NULL, 0, NULL} };