//-------------------------------------------------------------------------------------
		#region << Methods >>
		/// <summary>
		/// Возвращает true, если объект заглушен, false - если зарегистрирован
		/// </summary>
		/// <param name="obj"></param>
		/// <param name="cox"></param>
		/// <param name="typeid"></param>
		/// <param name="objid"></param>
		/// <returns></returns>
		private static bool StubGOLObject(GlobalObject obj, SerContext cox, ushort typeid, uint objid)
		{
			if(cox.asEmptyTypes.Contains(obj.GetType()) || cox.asEmptyObjects.Contains(obj))
			{
				#region
				SerObjectInfo si = new SerObjectInfo();
				si.typeID = (ushort)InfraTypes.PulsarEmptyStub;
				si.objID = objid;
				si.fields = new List<SerFieldInfo>(1);

				SerFieldInfo fsi = new SerFieldInfo();
				fsi.typeID = typeid;
				si.fields.Add(fsi);

				if(obj is GlobalObject)
				{
					fsi = new SerFieldInfo();
					fsi.typeID = (ushort)PrimitiveTypes.OID;
					fsi.name = "oid";
					fsi.value = ToBytes(((GlobalObject)obj).OID);
					si.fields.Add(fsi);
				}

				si.Save(cox.stream);
				#endregion 
				return true;
			}

			bool noStub = cox.noStubObjects.Contains(obj);
			if(noStub == false && cox.noStubTypes.Count > 0)
			{
			 Type t = obj.GetType();
				while(t != null)
				 if((noStub = cox.noStubTypes.Contains(t)) == true)
					 break;
					else
					 t = t.BaseType;
			}


			if(typeid == 0)
				typeid = cox.types.GetTypeID(obj.GetType());
			if(objid == 0)
				objid = cox.objs.GetObjID(typeid, obj);

			if(noStub)
			{
				cox.stream.WriteUInt16((ushort)InfraTypes.GOLObjectRegistrator);
				if(Pulsar.Server.ServerParamsBase.IsServer == false && GOL.Contains(obj) == false)
				 GOL.Add(obj);
			}
			else
				cox.stream.WriteUInt16((ushort)InfraTypes.GOLObjectStub);

			cox.stream.WriteUInt16(typeid);
			cox.stream.WriteUInt32(objid);
			cox.stream.WriteBytes(ToBytes(obj.OID));
			if(noStub)
			{
			 if(((IReadWriteLockObject)obj).IsLocked == false)
			  ((IReadWriteLockObject)obj).BeginRead();
				cox.stack.Push(obj);
			}
			return !noStub;
		}
		//-------------------------------------------------------------------------------------
		/// <summary>
		/// Сериализует объект в поток.
		/// </summary>
		/// <param name="stream">Поток сериализации/</param>
		/// <param name="obj">Сериализуемый объект.</param>
		/// <param name="pars">Параметры сериализации.</param>
		public static void Serialize(Stream stream, object obj, PulsarSerializationParams pars)
		{
			try
			{
				if(obj == null)
					return;
				if(stream == null)
					throw new ArgumentNullException("stream");
				if(stream.CanWrite == false)
					throw new Exception("Указанный поток сериализации не позволяет запись!");
				
				SerContext cox = new SerContext(stream, pars);

				Type objType = obj.GetType();
				if(IsPrimitive(objType) || objType == typeof(string) || objType == typeof(RefString) || obj is Array || 
								obj is Type || obj is ISelfSerialization)
					obj = new PulsarPrimitiveHolder(obj);
				else if(cox.mode != PulsarSerializationMode.Backup && obj is GlobalObject)
				{
					if(StubGOLObject((GlobalObject)obj, cox, 0, 0))	// cox.noStubObjects.Contains(obj) == false &&
					{
						stream.WriteUInt16(ushort.MaxValue);
						return;
					}
				}
				if(cox.stack.Contains(obj) == false)
					cox.stack.Push(obj);


				ushort objTypeID = 0;
				uint objID = 0;
				SerObjectInfo si = null;
				while(cox.stack.Count > 0)
				{
					obj = cox.stack.Pop();
					objType = obj.GetType();
					objTypeID = cox.types.GetTypeID(objType);
					objID = cox.objs.GetObjID(objTypeID, obj);

					if(si == null)
					{
						si = new SerObjectInfo() { fields = new List<SerFieldInfo>() };
						si.fields.Add(new SerFieldInfo() { name = "$root$" });
						if(obj is GlobalObject)
						{
							SerFieldInfo fsi = new SerFieldInfo();
							fsi.typeID = (ushort)PrimitiveTypes.OID;
							fsi.name = "oid";
							fsi.value = ToBytes(((GlobalObject)obj).OID);
							si.fields.Add(fsi);
						}
					}
					else
						si = new SerObjectInfo();

					if(cox.asEmptyTypes.Contains(objType) || cox.asEmptyObjects.Contains(obj))
					{
						#region
						si.typeID = (ushort)InfraTypes.PulsarEmptyStub;
						si.objID = objID;
						if(si.fields == null)
						 si.fields = new List<SerFieldInfo>(1);

						SerFieldInfo fsi = new SerFieldInfo();
						fsi.typeID = objTypeID;
						si.fields.Add(fsi);

						if(obj is GlobalObject)
						{
							fsi = new SerFieldInfo();
							fsi.typeID = (ushort)PrimitiveTypes.OID;
							fsi.name = "oid";
							fsi.value = ToBytes(((GlobalObject)obj).OID);
							si.fields.Add(fsi);
						}

						si.Save(stream);
						#endregion
						continue;
					}

					si.typeID = objTypeID;
					si.objID = objID;
					CallOnSerializing(obj, cox);

					if(obj is ISerializable)
					{
						#region
						SerializationInfo serInfo = new SerializationInfo(objType, nativeConverter);
						((ISerializable)obj).GetObjectData(serInfo, new StreamingContext());

						FieldWrap m_members = null;
						FieldWrap m_data = null;

						TypeSerializationWrap tw = TypeSerializationWrap.GetTypeSerializationWrap(typeof(SerializationInfo));
						foreach(FieldWrap fw in tw.Fields)
							if(fw.Name == "m_members")
								m_members = fw;
							else if(fw.Name == "m_data")
								m_data = fw;

						if(si.fields == null)
							si.fields = new List<SerFieldInfo>(2);
						SerFieldInfo fsi = new SerFieldInfo();
						fsi.typeID = (ushort)InfraTypes.StringArr;
						fsi.name = "m_members";
						fsi.value = PackArray((Array)m_members.Get(serInfo), cox);
						si.fields.Add(fsi);

						fsi = new SerFieldInfo();
						fsi.typeID = (ushort)InfraTypes.ObjectArr;
						fsi.name = "m_data";
						fsi.value = PackArray((Array)m_data.Get(serInfo), cox);
						si.fields.Add(fsi);

						si.Save(stream);
						CallOnSerialized(obj, cox);
						#endregion
						continue;
					}

					string pref = "";
					while(objType != typeof(object))
					{
						//foreach(FieldInfo fi in objType.GetFields(fieldsDiscovery))
						foreach(FieldWrap fw in TypeSerializationWrap.GetTypeSerializationWrap(objType).Fields)
						{
							if(fw.NoSerMode != null)
								if(fw.NoSerMode.Value == PulsarSerializationMode.Default || 
												cox.mode == PulsarSerializationMode.Default || 
											(fw.NoSerMode & cox.mode) > 0)
												continue;

							object val = fw.Get(obj);

							if(val == null || val is Delegate)
								continue;
							Type valType = val is Type ? typeof(Type) : val.GetType();
							if(valType.IsValueType && valType == fw.Type && val.Equals(Activator.CreateInstance(valType)))
								continue;

							if(fw.ByDemandModes != null)
								if(fw.ByDemandModes.Value == PulsarSerializationMode.Default || 
												cox.mode == PulsarSerializationMode.Default ||
												(fw.ByDemandModes & cox.mode) == 0)
							{
								if(cox.opts.HasFlag(PulsarSerializationOptions.IgnoreAllByDemandSerialization) == false &&
											cox.byDemandTypes.Contains(valType) == false)
									continue;
							}

							SerFieldInfo fsi = new SerFieldInfo();
							fsi.typeID = cox.types.GetTypeID(valType);
							fsi.name = pref + fw.Name;

							// При добавлении, посмотреть PackArray
							if(fsi.typeID <= 25 || valType.IsEnum || fsi.typeID == (uint)InfraTypes.RefString)
								fsi.value = ToBytes(val);
							else if(val is ISelfSerialization)
							{
								CallOnSerializing(val, cox);
								fsi.value = ((ISelfSerialization)val).GetSerializedData();
								CallOnSerialized(val, cox);
							}
							else if(val is Type)
								fsi.value = ToBytes(cox.types.GetTypeID((Type)val));
							else if(val is Array)
								fsi.value = PackArray((Array)val, cox);
							else
							{
								uint id;
								if(cox.objs.AddAsNew(fsi.typeID, val, out id))
									if(val is GlobalObject && pars != null && pars.Options.HasFlag(PulsarSerializationOptions.DeepSerialization) == false)
										StubGOLObject((GlobalObject)val, cox, fsi.typeID, id);
									else
										cox.stack.Push(val);
								fsi.value = ToBytes(id);
							}
							if(si.fields == null)
								si.fields = new List<SerFieldInfo>();
							si.fields.Add(fsi);
						}
						objType = objType.BaseType;
						if(objType == null || objType == typeof(object))
							break;
						pref += '.';
					}
					si.Save(stream);
					CallOnSerialized(obj, cox);
				}
				stream.WriteUInt16(ushort.MaxValue);
			}
			catch
			{
				throw;
			}
		}
		/// <summary>
		/// Метод десериализации объекта.
		/// </summary>
		/// <param name="stream">Поток десериализации.</param>
		/// <param name="root">Объект, в который будет производится десериализация.</param>
		/// <returns></returns>
		public static object Deserialize(Stream stream, object root, bool isLoad = false)
		{
			try
			{
				if(stream == null)
					throw new ArgumentNullException("stream");
				if(stream.CanRead == false)
					throw new Exception("Указанный поток десериализации не позволяет чтение!");

				DeserContext cox = new DeserContext(stream);

				ushort typeID;
				while((typeID = stream.ReadUInt16()) < ushort.MaxValue)
				{
					if(typeID == 0)
					{
						SerTypeInfo sti = new SerTypeInfo();
						sti.Load(stream);
						cox.types.Process(sti);
						continue;
					}
					if(typeID == (ushort)InfraTypes.GOLObjectRegistrator)
					{		
						#region
						ushort xx = stream.ReadUInt16();
						Type stt = cox.types[xx];
						uint stid = stream.ReadUInt32();
						OID stoid = (OID)FromBytes(typeof(OID), stream.ReadBytes(16));
						GlobalObject go = GOL.Get(stoid);
						if(go != null)
						{
							if(GOL.IsInitMode == false && isLoad == false && Pulsar.Server.ServerParamsBase.IsServer)
								throw new Exception("Попытка перезаписать объект на сервере!");
							if(go.Equals(root) == false)
								cox.objs.Add(stid, new DeserObj(go));
						}
						else
						{
							if(root != null && root is GlobalObject && ((GlobalObject)root).OID == stoid)
							{
								go = (GlobalObject)root;
								root = null;
							}
							else
							{
								object obj = FormatterServices.GetUninitializedObject(stt);
								if(obj is GlobalObject == false)
									throw new SerializationException(String.Format("Тип [{0}] не наследует GlobalObject!", stt.FullName));
								go = (GlobalObject)obj;
								go.OID = stoid;
							}
							cox.objs.Add(stid, new DeserObj(go));
							////GOL.AddUninitialized(go, 0, null);
							GOL.Add(go);
						}
						if(isLoad == false)
							go.BeginWrite();

						#endregion
						continue;
					}
					if(typeID == (ushort)InfraTypes.GOLObjectStub)
					{
						#region
						Type stt = cox.types[stream.ReadUInt16()];
						uint stid = stream.ReadUInt32();
						OID stoid = (OID)FromBytes(typeof(OID), stream.ReadBytes(16));

						GlobalObject go = GOL.Locate(stt,stoid);
						if(go != null)
						{
							cox.objs.Add(stid, new DeserObj(go));
							if(go.IsInitialized)
							 cox.objs[stid].WaitsCount = 0;
							else
							{
								if(cox.lateLoad.Contains(stid) == false)
									cox.lateLoad.Add(stid);
							}
							////if(GOL.IsUninitialized(stoid) == false)
							//// cox.objs[stid].WaitsCount = 0;
							////else
							////{
							//// GOL.AddUninitialized(go, stid, cox);
							//// if(cox.lateLoad.Contains(stid) == false)
							////  cox.lateLoad.Add(stid);
							////}
						}
						else /*if(GOL.LateInitMode == GOLLateInitModes.AllowAll ||
														(GOL.LateInitMode == GOLLateInitModes.AllowEssences && 
															stt.IsDefined(typeof(PulsarEssenceAttribute), true)))*/
						{
							object obj = FormatterServices.GetUninitializedObject(stt);
							if(obj is GlobalObject == false)
								throw new SerializationException(String.Format("Тип [{0}] не наследует IGOLObject!", stt.FullName));

							go = (GlobalObject)obj;
							go.OID = stoid;
							cox.objs.Add(stid, new DeserObj(go));
							////GOL.AddUninitialized(go, stid, cox);
							GOL.Add(go);
							cox.lateLoad.Add(stid);
						}
						//else
						// throw new SerializationException(String.Format("Заглушка объекта {{{0}}} типа [{1}] не раскрыта!",
						//  stoid, stt.FullName));
						#endregion
						continue;
					}

					SerObjectInfo si = new SerObjectInfo();
					si.typeID = typeID;
					si.Load(stream);

					Type t = cox.types[si.typeID];
					DeserObj siObjID = null;

					if(typeID == (ushort)InfraTypes.PulsarPrimitiveHolder)
					{
						SerFieldInfo fsi = si.index["Primitive"];
						t = cox.types[fsi.typeID];
						Object val = null;
						if(typeof(ISelfSerialization).IsAssignableFrom(t))
						{
							val = root == null ? FormatterServices.GetUninitializedObject(t) : root;
							var tw = TypeSerializationWrap.GetTypeSerializationWrap(t);
							tw.OnDeserializing(val);
							((ISelfSerialization)val).Deserialize(fsi.value);
							tw.OnDeserialized(val);
						}
						else
							val = FromBytes(t, fsi.value);
						return val;
					}



					if(root == null) // && cox.objs.Count == 0)				 && t != typeof(PulsarPrimitiveHolder)
						cox.objs.TryGetValue(si.objID, out siObjID);
					else
					{
						if(t.IsAssignableFrom(root.GetType()) == false || si.index == null || si.index.ContainsKey("$root$") == false)
							throw new Exception("Данные сериализации не соответствуют объекту root!");
						cox.objs.Add(si.objID, siObjID = new DeserObj(root));
						if(si.index.ContainsKey("oid"))
							((GlobalObject)root).OID = (OID)FromBytes(typeof(OID),si.index["oid"].value);
						root = null;
					}

					if(t == typeof(PulsarEmptyStub))
					{
						#region
						t = cox.types[si.index[""].typeID];
						if(siObjID == null)
							cox.objs.Add(si.objID, siObjID = new DeserObj(t));
						siObjID.IsEmpty = true;
						ConstructorInfo ci = t.GetConstructor(fieldsDiscovery, null, Type.EmptyTypes, null);
						if(ci != null)
							ci.Invoke(siObjID.Obj, null);
						if(si.index.ContainsKey("oid") && siObjID.Obj is GlobalObject)  //  
							if(siObjID.Obj is GlobalObject)
								((GlobalObject)siObjID.Obj).OID =  new OID(si.index["oid"].value);
							else
							{
								InterfaceMapping im = t.GetInterfaceMap(typeof(IOIDObject));
								if(im.TargetMethods.Length == 0)
									throw new SerializationException(String.Format("Тип [{0}] не содержит свойство OID!", t.FullName));
								if(t != im.TargetMethods[0].DeclaringType)
									t = im.TargetMethods[0].DeclaringType;
								PropertyInfo pi = t.GetProperty("OID", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
								if(pi == null)
									throw new SerializationException(String.Format("Тип [{0}] не содержит свойство OID!", t.FullName));
								MethodInfo mi = pi.GetSetMethod(true);
								if(mi == null)
									throw new SerializationException(String.Format("Тип [{0}] не реализует set метод для свойства OID!",
																																																																				siObjID.Obj.GetType().FullName));
								mi.Invoke(siObjID.Obj, new object[] { new OID(si.index["oid"].value) });
							}
						#endregion
						siObjID.WaitsCount = 0;
					}

					if(siObjID == null)
						//if(typeof(GlobalObject).IsAssignableFrom(t))
						// if(pars
						// throw new Exception("Попытка создать объект Пульсара вне GOL!");
						//else
							cox.objs.Add(si.objID, siObjID = new DeserObj(t));
					if(siObjID.WaitsCount != 0)
						CallOnDeserializing(siObjID.Obj);

					if(siObjID.WaitsCount != 0 &&  siObjID.Obj is ISerializable)
					{
						if(siObjID.WaitsCount == -1)
							siObjID.WaitsCount = 0;
						#region
						siObjID.Tag = new object[2];
						SerFieldInfo fsi = si.index["m_members"];
						object val = null;
						UnPackArray(ref val, fsi.value, typeof(string), si.objID, cox);
						((object[])siObjID.Tag)[0] = val;

						val = null;
						fsi = si.index["m_data"];
						UnPackArray(ref val, fsi.value, typeof(object), si.objID, cox);
						((object[])siObjID.Tag)[1] = val;

						if(siObjID.WaitsCount != 0)
							continue;
						#endregion
					}

					if(siObjID.WaitsCount == 0)
					{
						OnFullDeser(cox, si.objID, true);
						continue;
					}

					string pref = "";
					if(siObjID.WaitsCount == -1)
						siObjID.WaitsCount = 0;
					while(t != typeof(object))
					{
						foreach(FieldWrap fw in TypeSerializationWrap.GetTypeSerializationWrap(t).Fields)
						{
							if(si.index == null || si.index.ContainsKey(pref + fw.Name) == false)
								continue;

							SerFieldInfo fsi = si.index[pref + fw.Name];
							Type valType = cox.types[fsi.typeID];
							object val = null; 

							if(fsi.typeID <= 25 || valType.IsEnum  || fsi.typeID == (uint)InfraTypes.RefString)
									//) && fsi.typeID != 18  && fsi.typeID != 19 )
								val = FromBytes(valType, fsi.value);
							else if(typeof(ISelfSerialization).IsAssignableFrom(valType))
							{
								val = FormatterServices.GetUninitializedObject(valType);
								TypeSerializationWrap tw = TypeSerializationWrap.GetTypeSerializationWrap(valType);
								tw.OnDeserializing(val);
								((ISelfSerialization)val).Deserialize(fsi.value);
								tw.OnDeserialized(val);
							}
							else if(valType == typeof(Type))
								val = cox.types[BitConverter.ToUInt16(fsi.value, 0)];
							else if(valType.IsArray)
								UnPackArray(ref val, fsi.value, valType.GetElementType(), si.objID, cox);
							else
							{
								uint id = BitConverter.ToUInt32(fsi.value, 0);

								DeserObj dObj = null;

								if(cox.objs.TryGetValue(id, out dObj)) //  cox.objs.ContainsKey(id)
								{
									if(dObj.WaitsCount == 0)
										val = dObj.Obj;
									else
									{
										siObjID.WaitsCount++;

										List<LateDeserInfo> lll;
										if(cox.lateSet.TryGetValue(id, out lll) == false)
											cox.lateSet.Add(id, lll = new List<LateDeserInfo>());
										lll.Add(new LateDeserInfo(si.objID, fw));
										continue;
									}
								}
								else
								{
									// Противоречит "глубокой" сериализации
									//if(typeof(GlobalObject).IsAssignableFrom(valType))
									// throw new Exception("Попытка создать GlobalObject вне GOL!");
									cox.objs.Add(id, new DeserObj(valType));
									siObjID.WaitsCount++;
									
									List<LateDeserInfo> lll;
									if(cox.lateSet.TryGetValue(id, out lll) == false)
										cox.lateSet.Add(id, lll = new List<LateDeserInfo>());
									lll.Add(new LateDeserInfo(si.objID, fw));
									continue;
								}
							}
							fw.Set(siObjID.Obj, val);
						}
						t = t.BaseType;
						if(t == null || t == typeof(object))
							break;
						pref += '.';
					}

					if(siObjID.WaitsCount == 0)
						OnFullDeser(cox, si.objID, true);
				}
				if(cox.lateSet.Count > 0) //!! && GOL.LateInitMode != GOLLateInitModes.AllowAll)
				{
					#region
					////List<GlobalObject> toLoad = new List<GlobalObject>(cox.lateLoad.Count);
					////foreach(uint i in cox.lateLoad)
					//// if(cox.objs[i].Obj is GlobalObject)
					////  toLoad.Add((GlobalObject)cox.objs[i].Obj);
					//// else
					////  throw new Exception("Найдено неразрешимое кольцевое замыкание объектов!");
					////if(toLoad.Count == 0)
					//// throw new Exception("Найдено неразрешимое кольцевое замыкание объектов!");
					////GOL.LoadGlobalObjects(toLoad);

					if(cox.lateLoad.Count > 0)
						GOL.LoadGlobalObjects(cox.lateLoad.ForEach((i)=> (GlobalObject)	cox.objs[i].Obj));

					foreach(uint i in cox.lateLoad)
					{
					 GlobalObject go = (GlobalObject)	cox.objs[i].Obj;
						if(go.IsInitialized)
							OnFullDeser(cox,i,false);
						else
						 throw new PulsarException("Не удалось загрузить глобальный объект [{0}] типа {1}!", go.OID, go.GetType());
					}		 
					if(cox.lateSet.Count != 0)
						throw new Exception("Найдено неразрешимое кольцевое замыкание объектов!");
					#endregion
				}
				if(cox.objs.Count == 0)
					return null;
				//if(cox.objs[1].Obj is PulsarPrimitiveHolder)
				// return ((PulsarPrimitiveHolder)cox.objs[1].Obj).Primitive;
				return cox.objs[1].Obj;
			}
			catch
			{
				//--- Debbuger Break --- //
				if(System.Diagnostics.Debugger.IsAttached)
					System.Diagnostics.Debugger.Break();
				//--- Debbuger Break --- //
				throw;
			}
		}