void AttributeParser::parseNumeric(MPlug plug, MFnNumericData::Type type)
	{
		MStatus status;

		MObject attrObj = plug.attribute(&status);
		if (!status) return;

		MFnAttribute attr(attrObj, &status);
		if (!status) return;

		MString name = attr.name(&status);
		if (!status) return;

		switch (type)
		{
		case MFnNumericData::kInvalid:			//!< Invalid data.
			break;
		case MFnNumericData::kBoolean:			//!< Boolean.
		{
			bool value;
			status = plug.getValue(value);
			if (!status) return;
			onBoolean(plug, name, value);
		}
		break;
		case MFnNumericData::kByte:				//!< One byte.
		{
			char value;
			status = plug.getValue(value);
			if (!status) return;
			onByte(plug, name, value);
		}
		break;
		case MFnNumericData::kChar:				//!< One character.
		{
			char value;
			status = plug.getValue(value);
			if (!status) return;
			onChar(plug, name, value);
		}
		break;
		case MFnNumericData::kShort:				//!< One short.
		{
			short value;
			status = plug.getValue(value);
			if (!status) return;
			onShort(plug, name, value);
		}
		break;
		case MFnNumericData::k2Short:			//!< Two shorts.
		{
			MObject object;
			status = plug.getValue(object);
			if (!status) return;
			MFnNumericData fnNumericData(object, &status);
			if (!status) return;
			short value[2];
			status = fnNumericData.getData(value[0], value[1]);
			if (!status) return;
			onShort2(plug, name, value);
		}
		break;
		case MFnNumericData::k3Short:			//!< Three shorts.
		{
			MObject object;
			status = plug.getValue(object);
			if (!status) return;
			MFnNumericData fnNumericData(object, &status);
			if (!status) return;
			short value[3];
			status = fnNumericData.getData(value[0], value[1], value[2]);
			if (!status) return;
			onShort3(plug, name, value);
		}
		break;
		case MFnNumericData::kInt:				//!< One long. Same as int since "long" is not platform-consistent.
		{
			int value;
			status = plug.getValue(value);
			if (!status) return;
			onInteger(plug, name, value);
		}
		break;
		case MFnNumericData::k2Int:				//!< Two longs. Same as 2 ints since "long" is not platform-consistent.
		{
			MObject object;
			status = plug.getValue(object);
			if (!status) return;
			MFnNumericData fnNumericData(object, &status);
			if (!status) return;
			int value[2];
			status = fnNumericData.getData(value[0], value[1]);
			if (!status) return;
			onInteger2(plug, name, value);
		}
		break;
		case MFnNumericData::k3Int:				//!< Three longs. Same as 3 ints since "long" is not platform-consistent.
		{
			MObject object;
			status = plug.getValue(object);
			if (!status) return;
			MFnNumericData fnNumericData(object, &status);
			if (!status) return;
			int value[3];
			status = fnNumericData.getData(value[0], value[1], value[2]);
			if (!status) return;
			onInteger3(plug, name, value);
		}
		break;
		case MFnNumericData::kFloat:				//!< One float.
		{
            MFn::Type apiType = attrObj.apiType();
            switch (apiType)
            {
            case MFn::kFloatAngleAttribute:
            {
                MAngle angle = plug.asMAngle(MDGContext::fsNormal, &status);
                if (!status) return;
                onAngle(plug, name, angle);
            }
            break;
            case MFn::kFloatLinearAttribute:
            {
                MDistance distance = plug.asMDistance(MDGContext::fsNormal, &status);
                if (!status) return;
                onDistance(plug, name, distance);
            }
            break;
            default:
            {
                float value = plug.asFloat(MDGContext::fsNormal, &status);
                if (!status) return;
                onFloat(plug, name, value);
            }
            break;
            }
		}
		break;
		case MFnNumericData::k2Float:			//!< Two floats.
		{
            const unsigned int numChildren = 2;

			MPlug childPlugs[numChildren];
            for (unsigned int i = 0; i < numChildren; ++i) {
                childPlugs[i] = plug.child(i, &status);
                if (!status) return;
            }

            MObject childAttr[numChildren];
            for (unsigned int i = 0; i < numChildren; ++i) {
                childAttr[i] = childPlugs[i].attribute(&status);
                if (!status) return;
            }

            MFn::Type apiType = childAttr[0].apiType();
            switch (apiType)
            {
            case MFn::kFloatAngleAttribute:
            {
                MAngle angles[numChildren];
                for (unsigned int i = 0; i < numChildren; ++i) {
                    angles[i] = childPlugs[i].asMAngle(MDGContext::fsNormal, &status);
                    if (!status) return;
                }
                onAngle2(plug, name, angles);
            }
            break;
            case MFn::kFloatLinearAttribute:
            {
                MDistance distances[numChildren];
                for (unsigned int i = 0; i < numChildren; ++i) {
                    distances[i] = childPlugs[i].asMDistance(MDGContext::fsNormal, &status);
                    if (!status) return;
                }
                onDistance2(plug, name, distances);
            }
            break;
            default:
            {
                float values[numChildren];
                for (unsigned int i = 0; i < numChildren; ++i) {
                    values[i] = childPlugs[i].asFloat(MDGContext::fsNormal, &status);
                    if (!status) return;
                }
                onFloat2(plug, name, values);
            }
            break;
            }
		}
		break;
		case MFnNumericData::k3Float:			//!< Three floats.
		{
            const unsigned int numChildren = 3;

			MPlug childPlugs[numChildren];
            for (unsigned int i = 0; i < numChildren; ++i) {
                childPlugs[i] = plug.child(i, &status);
                if (!status) return;
            }

            MObject childAttr[numChildren];
            for (unsigned int i = 0; i < numChildren; ++i) {
                childAttr[i] = childPlugs[i].attribute(&status);
                if (!status) return;
            }

            MFn::Type apiType = childAttr[0].apiType();
            switch (apiType)
            {
            case MFn::kFloatAngleAttribute:
            {
                MAngle angles[numChildren];
                for (unsigned int i = 0; i < numChildren; ++i) {
                    angles[i] = childPlugs[i].asMAngle(MDGContext::fsNormal, &status);
                    if (!status) return;
                }
                onAngle3(plug, name, angles);
            }
            break;
            case MFn::kFloatLinearAttribute:
            {
                MDistance distances[numChildren];
                for (unsigned int i = 0; i < numChildren; ++i) {
                    distances[i] = childPlugs[i].asMDistance(MDGContext::fsNormal, &status);
                    if (!status) return;
                }
                onDistance3(plug, name, distances);
            }
            break;
            default:
            {
                float values[numChildren];
                for (unsigned int i = 0; i < numChildren; ++i) {
                    values[i] = childPlugs[i].asFloat(MDGContext::fsNormal, &status);
                    if (!status) return;
                }
                onFloat3(plug, name, values);
            }
            break;
            }
		}
		break;
		case MFnNumericData::kDouble:			//!< One double.
		{
            MFn::Type apiType = attrObj.apiType();
            switch (apiType)
            {
            case MFn::kDoubleAngleAttribute:
            {
                MAngle angle = plug.asMAngle(MDGContext::fsNormal, &status);
                if (!status) return;
                onAngle(plug, name, angle);
            }
            break;
            case MFn::kDoubleLinearAttribute:
            {
                MDistance distance = plug.asMDistance(MDGContext::fsNormal, &status);
                if (!status) return;
                onDistance(plug, name, distance);
            }
            break;
            default:
            {
                double value = plug.asDouble(MDGContext::fsNormal, &status);
                if (!status) return;
                onDouble(plug, name, value);
            }
            break;
            }
		}
		break;
		case MFnNumericData::k2Double:			//!< Two doubles.
		{
			const unsigned int numChildren = 2;

			MPlug childPlugs[numChildren];
            for (unsigned int i = 0; i < numChildren; ++i) {
                childPlugs[i] = plug.child(i, &status);
                if (!status) return;
            }

            MObject childAttr[numChildren];
            for (unsigned int i = 0; i < numChildren; ++i) {
                childAttr[i] = childPlugs[i].attribute(&status);
                if (!status) return;
            }

            MFn::Type apiType = childAttr[0].apiType();
            switch (apiType)
            {
            case MFn::kDoubleAngleAttribute:
            {
                MAngle angles[numChildren];
                for (unsigned int i = 0; i < numChildren; ++i) {
                    angles[i] = childPlugs[i].asMAngle(MDGContext::fsNormal, &status);
                    if (!status) return;
                }
                onAngle2(plug, name, angles);
            }
            break;
            case MFn::kDoubleLinearAttribute:
            {
                MDistance distances[numChildren];
                for (unsigned int i = 0; i < numChildren; ++i) {
                    distances[i] = childPlugs[i].asMDistance(MDGContext::fsNormal, &status);
                    if (!status) return;
                }
                onDistance2(plug, name, distances);
            }
            break;
            default:
            {
                double values[numChildren];
                for (unsigned int i = 0; i < numChildren; ++i) {
                    values[i] = childPlugs[i].asDouble(MDGContext::fsNormal, &status);
                    if (!status) return;
                }
                onDouble2(plug, name, values);
            }
            break;
            }
		}
		break;
		case MFnNumericData::k3Double:			//!< Three doubles.
		{
			const unsigned int numChildren = 3;

			MPlug childPlugs[numChildren];
            for (unsigned int i = 0; i < numChildren; ++i) {
                childPlugs[i] = plug.child(i, &status);
                if (!status) return;
            }

            MObject childAttr[numChildren];
            for (unsigned int i = 0; i < numChildren; ++i) {
                childAttr[i] = childPlugs[i].attribute(&status);
                if (!status) return;
            }

            MFn::Type apiType = childAttr[0].apiType();
            switch (apiType)
            {
            case MFn::kDoubleAngleAttribute:
            {
                MAngle angles[numChildren];
                for (unsigned int i = 0; i < numChildren; ++i) {
                    angles[i] = childPlugs[i].asMAngle(MDGContext::fsNormal, &status);
                    if (!status) return;
                }
                onAngle3(plug, name, angles);
            }
            break;
            case MFn::kDoubleLinearAttribute:
            {
                MDistance distances[numChildren];
                for (unsigned int i = 0; i < numChildren; ++i) {
                    distances[i] = childPlugs[i].asMDistance(MDGContext::fsNormal, &status);
                    if (!status) return;
                }
                onDistance3(plug, name, distances);
            }
            break;
            default:
            {
                double values[numChildren];
                for (unsigned int i = 0; i < numChildren; ++i) {
                    values[i] = childPlugs[i].asDouble(MDGContext::fsNormal, &status);
                    if (!status) return;
                }
                onDouble3(plug, name, values);
            }
            break;
            }
		}
		break;
		case MFnNumericData::k4Double:			//!< Four doubles.
		{
			const unsigned int numChildren = 4;

			MPlug childPlugs[numChildren];
            for (unsigned int i = 0; i < numChildren; ++i) {
                childPlugs[i] = plug.child(i, &status);
                if (!status) return;
            }

            MObject childAttr[numChildren];
            for (unsigned int i = 0; i < numChildren; ++i) {
                childAttr[i] = childPlugs[i].attribute(&status);
                if (!status) return;
            }

            MFn::Type apiType = childAttr[0].apiType();
            switch (apiType)
            {
            case MFn::kDoubleAngleAttribute:
            {
                MAngle angles[numChildren];
                for (unsigned int i = 0; i < numChildren; ++i) {
                    angles[i] = childPlugs[i].asMAngle(MDGContext::fsNormal, &status);
                    if (!status) return;
                }
                onAngle4(plug, name, angles);
            }
            break;
            case MFn::kDoubleLinearAttribute:
            {
                MDistance distances[numChildren];
                for (unsigned int i = 0; i < numChildren; ++i) {
                    distances[i] = childPlugs[i].asMDistance(MDGContext::fsNormal, &status);
                    if (!status) return;
                }
                onDistance4(plug, name, distances);
            }
            break;
            default:
            {
                double values[numChildren];
                for (unsigned int i = 0; i < numChildren; ++i) {
                    values[i] = childPlugs[i].asDouble(MDGContext::fsNormal, &status);
                    if (!status) return;
                }
                onDouble4(plug, name, values);
            }
            break;
            }
		}
		break;
		case MFnNumericData::kAddr:				//!< An address.
			// TODO
			break;
		default:
			break;
		}
	}
	MStatus AttributeParser::parseNumeric(MPlug plug, MFnNumericData::Type type)
	{
		MStatus status;

		MObject attrObj = plug.attribute(&status);
		if (!status) return status;

		MFnAttribute attr(attrObj, &status);
		if (!status) return status;

		MString name = attr.name(&status);
		if (!status) return status;

		switch (type)
		{
		case MFnNumericData::kInvalid:			//!< Invalid data.
			break;
		case MFnNumericData::kBoolean:			//!< Boolean.
		{
			bool value;
			MStatus status = plug.getValue(value);
			if (!status) return status;
			return onBoolean(plug, name, value);
		}
		break;
		case MFnNumericData::kByte:				//!< One byte.
		{
			char value;
			MStatus status = plug.getValue(value);
			if (!status) return status;
			return onByte(plug, name, value);
		}
		break;
		case MFnNumericData::kChar:				//!< One character.
		{
			char value;
			MStatus status = plug.getValue(value);
			if (!status) return status;
			return onChar(plug, name, value);
		}
		break;
		case MFnNumericData::kShort:				//!< One short.
		{
			short value;
			MStatus status = plug.getValue(value);
			if (!status) return status;
			return onShort(plug, name, value);
		}
		break;
		case MFnNumericData::k2Short:			//!< Two shorts.
		{
			MStatus status;
			short value[2];
			MPlug plug0 = plug.child(0, &status);
			if (!status) return status;
			MPlug plug1 = plug.child(1, &status);
			if (!status) return status;
			status = plug0.getValue(value[0]);
			if (!status) return status;
			status = plug1.getValue(value[1]);
			if (!status) return status;
			return onShort2(plug, name, value);
		}
		break;
		case MFnNumericData::k3Short:			//!< Three shorts.
		{
			MStatus status;
			short value[3];
			MPlug plug0 = plug.child(0, &status);
			if (!status) return status;
			MPlug plug1 = plug.child(1, &status);
			if (!status) return status;
			MPlug plug2 = plug.child(2, &status);
			if (!status) return status;
			status = plug0.getValue(value[0]);
			if (!status) return status;
			status = plug1.getValue(value[1]);
			if (!status) return status;
			status = plug2.getValue(value[2]);
			if (!status) return status;
			return onShort3(plug, name, value);
		}
		break;
		case MFnNumericData::kLong:				//!< One long. Same as int since "long" is not platform-consistent.
		{
			int value;
			MStatus status = plug.getValue(value);
			if (!status) return status;
			return onLong(plug, name, value);
		}
		break;
		//case MFnNumericData::Type::kInt:		//!< One int.
		//	break;
		case MFnNumericData::k2Long:				//!< Two longs. Same as 2 ints since "long" is not platform-consistent.
		{
			MStatus status;
			int value[2];
			MPlug plug0 = plug.child(0, &status);
			if (!status) return status;
			MPlug plug1 = plug.child(1, &status);
			if (!status) return status;
			status = plug0.getValue(value[0]);
			if (!status) return status;
			status = plug1.getValue(value[1]);
			if (!status) return status;
			return onLong2(plug, name, value);
		}
		break;
		//case MFnNumericData::Type::k2Int:		//!< Two ints.
		//	break;
		case MFnNumericData::k3Long:				//!< Three longs. Same as 3 ints since "long" is not platform-consistent.
		{
			MStatus status;
			int value[3];
			MPlug plug0 = plug.child(0, &status);
			if (!status) return status;
			MPlug plug1 = plug.child(1, &status);
			if (!status) return status;
			MPlug plug2 = plug.child(2, &status);
			if (!status) return status;
			status = plug0.getValue(value[0]);
			if (!status) return status;
			status = plug1.getValue(value[1]);
			if (!status) return status;
			status = plug2.getValue(value[2]);
			if (!status) return status;
			return onLong3(plug, name, value);
		}
		break;
		//case MFnNumericData::Type::k3Int:		//!< Three ints.
		//	break;
		case MFnNumericData::kFloat:				//!< One float.
		{
			float value;
			MStatus status = plug.getValue(value);
			if (!status) return status;
			return onFloat(plug, name, value);
		}
		break;
		case MFnNumericData::k2Float:			//!< Two floats.
		{
			MStatus status;
			float value[2];
			MPlug plug0 = plug.child(0, &status);
			if (!status) return status;
			MPlug plug1 = plug.child(1, &status);
			if (!status) return status;
			status = plug0.getValue(value[0]);
			if (!status) return status;
			status = plug1.getValue(value[1]);
			if (!status) return status;
			return onFloat2(plug, name, value);
		}
		break;
		case MFnNumericData::k3Float:			//!< Three floats.
		{
			MStatus status;
			float value[3];
			MPlug plug0 = plug.child(0, &status);
			if (!status) return status;
			MPlug plug1 = plug.child(1, &status);
			if (!status) return status;
			MPlug plug2 = plug.child(2, &status);
			if (!status) return status;
			status = plug0.getValue(value[0]);
			if (!status) return status;
			status = plug1.getValue(value[1]);
			if (!status) return status;
			status = plug2.getValue(value[2]);
			if (!status) return status;
			return onFloat3(plug, name, value);
		}
		break;
		case MFnNumericData::kDouble:			//!< One double.
		{
			double value;
			MStatus status = plug.getValue(value);
			if (!status) return status;
			return onDouble(plug, name, value);
		}
		break;
		case MFnNumericData::k2Double:			//!< Two doubles.
		{
			MStatus status;
			double value[2];
			MPlug plug0 = plug.child(0, &status);
			if (!status) return status;
			MPlug plug1 = plug.child(1, &status);
			if (!status) return status;
			status = plug0.getValue(value[0]);
			if (!status) return status;
			status = plug1.getValue(value[1]);
			if (!status) return status;
			return onDouble2(plug, name, value);
		}
		break;
		case MFnNumericData::k3Double:			//!< Three doubles.
		{
			MStatus status;
			double value[3];
			MPlug plug0 = plug.child(0, &status);
			if (!status) return status;
			MPlug plug1 = plug.child(1, &status);
			if (!status) return status;
			MPlug plug2 = plug.child(2, &status);
			if (!status) return status;
			status = plug0.getValue(value[0]);
			if (!status) return status;
			status = plug1.getValue(value[1]);
			if (!status) return status;
			status = plug2.getValue(value[2]);
			if (!status) return status;
			return onDouble3(plug, name, value);
		}
		break;
		case MFnNumericData::k4Double:			//!< Four doubles.
		{
			MStatus status;
			double value[4];
			MPlug plug0 = plug.child(0, &status);
			if (!status) return status;
			MPlug plug1 = plug.child(1, &status);
			if (!status) return status;
			MPlug plug2 = plug.child(2, &status);
			if (!status) return status;
			MPlug plug3 = plug.child(3, &status);
			if (!status) return status;
			status = plug0.getValue(value[0]);
			if (!status) return status;
			status = plug1.getValue(value[1]);
			if (!status) return status;
			status = plug2.getValue(value[2]);
			if (!status) return status;
			status = plug3.getValue(value[3]);
			if (!status) return status;
			return onDouble4(plug, name, value);
		}
		break;
		case MFnNumericData::kAddr:				//!< An address.
			// TODO
			break;
		default:
			break;
		}
		return MS::kSuccess;
	}