*Added support for prim counting on parcels
**No restrictions yet in place, or total prim countafrisby
parent
5a909a2054
commit
423d03eaef
|
@ -47,6 +47,8 @@ namespace OpenSim.Framework.Types
|
|||
public int claimPrice = 0; //Unemplemented
|
||||
public LLUUID groupID = new LLUUID(); //Unemplemented
|
||||
public int groupPrims = 0; //Unemplemented
|
||||
public int otherPrims = 0; //Unemplemented
|
||||
public int ownerPrims = 0; //Unemplemented
|
||||
public int salePrice = 0; //Unemeplemented. Parcels price.
|
||||
public Parcel.ParcelStatus parcelStatus = Parcel.ParcelStatus.Leased;
|
||||
public uint parcelFlags = (uint)Parcel.ParcelFlags.AllowFly | (uint)Parcel.ParcelFlags.AllowLandmark | (uint)Parcel.ParcelFlags.AllowAllObjectEntry | (uint)Parcel.ParcelFlags.AllowDeedToGroup | (uint)Parcel.ParcelFlags.AllowTerraform | (uint)Parcel.ParcelFlags.CreateObjects | (uint)Parcel.ParcelFlags.AllowOtherScripts;
|
||||
|
@ -84,6 +86,8 @@ namespace OpenSim.Framework.Types
|
|||
parcelData.globalID = this.globalID;
|
||||
parcelData.groupID = this.groupID;
|
||||
parcelData.groupPrims = this.groupPrims;
|
||||
parcelData.otherPrims = this.otherPrims;
|
||||
parcelData.ownerPrims = this.ownerPrims;
|
||||
parcelData.isGroupOwned = this.isGroupOwned;
|
||||
parcelData.localID = this.localID;
|
||||
parcelData.landingType = this.landingType;
|
||||
|
|
|
@ -75,6 +75,11 @@ namespace OpenSim.Region.Environment
|
|||
private int lastParcelLocalID = START_PARCEL_LOCAL_ID - 1;
|
||||
private int[,] parcelIDList = new int[64, 64];
|
||||
|
||||
/// <summary>
|
||||
/// Set to true when a prim is moved, created, added. Performs a prim count update
|
||||
/// </summary>
|
||||
public bool parcelPrimCountTainted = false;
|
||||
|
||||
private Scene m_world;
|
||||
private RegionInfo m_regInfo;
|
||||
|
||||
|
@ -190,6 +195,13 @@ namespace OpenSim.Region.Environment
|
|||
/// <param name="x">Value between 0 - 256 on the x axis of the point</param>
|
||||
/// <param name="y">Value between 0 - 256 on the y axis of the point</param>
|
||||
/// <returns>Parcel at the point supplied</returns>
|
||||
public Parcel getParcel(float x_float, float y_float)
|
||||
{
|
||||
int x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float)));
|
||||
int y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float)));
|
||||
|
||||
return getParcel(x, y);
|
||||
}
|
||||
public Parcel getParcel(int x, int y)
|
||||
{
|
||||
if (x > 256 || y > 256 || x < 0 || y < 0)
|
||||
|
@ -200,7 +212,6 @@ namespace OpenSim.Region.Environment
|
|||
{
|
||||
return parcelList[parcelIDList[x / 4, y / 4]];
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
@ -262,9 +273,11 @@ namespace OpenSim.Region.Environment
|
|||
parcelList[startParcelIndex].setParcelBitmap(Parcel.modifyParcelBitmapSquare(startParcel.getParcelBitmap(), start_x, start_y, end_x, end_y, false));
|
||||
parcelList[startParcelIndex].forceUpdateParcelInfo();
|
||||
|
||||
|
||||
this.setPrimsTainted();
|
||||
|
||||
//Now add the new parcel
|
||||
Parcel result = addParcel(newParcel);
|
||||
|
||||
result.sendParcelUpdateToAvatarsOverMe();
|
||||
|
||||
|
||||
|
@ -326,6 +339,8 @@ namespace OpenSim.Region.Environment
|
|||
}
|
||||
|
||||
|
||||
this.setPrimsTainted();
|
||||
|
||||
masterParcel.sendParcelUpdateToAvatarsOverMe();
|
||||
|
||||
return true;
|
||||
|
@ -493,13 +508,46 @@ namespace OpenSim.Region.Environment
|
|||
Avatar clientAvatar = m_world.RequestAvatar(remote_client.AgentId);
|
||||
if (clientAvatar != null)
|
||||
{
|
||||
Parcel over = getParcel(Convert.ToInt32(clientAvatar.Pos.X), Convert.ToInt32(clientAvatar.Pos.Y));
|
||||
Parcel over = getParcel(clientAvatar.Pos.X,clientAvatar.Pos.Y);
|
||||
if (over != null)
|
||||
{
|
||||
over.sendParcelProperties(0, false, 0, remote_client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void resetAllParcelPrimCounts()
|
||||
{
|
||||
foreach (Parcel p in parcelList.Values)
|
||||
{
|
||||
p.resetParcelPrimCounts();
|
||||
}
|
||||
}
|
||||
|
||||
public void addPrimToParcelCounts(SceneObject obj)
|
||||
{
|
||||
LLVector3 position = obj.rootPrimitive.Pos;
|
||||
int pos_x = Convert.ToInt32(Math.Round(position.X));
|
||||
int pos_y = Convert.ToInt32(Math.Round(position.Y));
|
||||
Parcel parcelUnderPrim = getParcel(pos_x, pos_y);
|
||||
if (parcelUnderPrim != null)
|
||||
{
|
||||
parcelUnderPrim.addPrimToCount(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public void removePrimFromParcelCounts(SceneObject obj)
|
||||
{
|
||||
foreach (Parcel p in parcelList.Values)
|
||||
{
|
||||
p.removePrimFromCount(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPrimsTainted()
|
||||
{
|
||||
this.parcelPrimCountTainted = true;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
|
@ -513,6 +561,8 @@ namespace OpenSim.Region.Environment
|
|||
{
|
||||
#region Member Variables
|
||||
public ParcelData parcelData = new ParcelData();
|
||||
public List<SceneObject> primsOverMe = new List<SceneObject>();
|
||||
|
||||
public Scene m_world;
|
||||
|
||||
private bool[,] parcelBitmap = new bool[64, 64];
|
||||
|
@ -602,9 +652,9 @@ namespace OpenSim.Region.Environment
|
|||
updatePacket.ParcelData.Name = Helpers.StringToField(parcelData.parcelName);
|
||||
updatePacket.ParcelData.OtherCleanTime = 0; //unemplemented
|
||||
updatePacket.ParcelData.OtherCount = 0; //unemplemented
|
||||
updatePacket.ParcelData.OtherPrims = 0; //unemplented
|
||||
updatePacket.ParcelData.OtherPrims = parcelData.groupPrims;
|
||||
updatePacket.ParcelData.OwnerID = parcelData.ownerID;
|
||||
updatePacket.ParcelData.OwnerPrims = 0; //unemplemented
|
||||
updatePacket.ParcelData.OwnerPrims = parcelData.ownerPrims;
|
||||
updatePacket.ParcelData.ParcelFlags = parcelData.parcelFlags;
|
||||
updatePacket.ParcelData.ParcelPrimBonus = m_world.RegionInfo.estateSettings.objectBonusFactor;
|
||||
updatePacket.ParcelData.PassHours = parcelData.passHours;
|
||||
|
@ -616,7 +666,7 @@ namespace OpenSim.Region.Environment
|
|||
updatePacket.ParcelData.RegionPushOverride = (((uint)m_world.RegionInfo.estateSettings.regionFlags & (uint)Simulator.RegionFlags.RestrictPushObject) > 0);
|
||||
updatePacket.ParcelData.RentPrice = 0;
|
||||
updatePacket.ParcelData.RequestResult = request_result;
|
||||
updatePacket.ParcelData.SalePrice = parcelData.salePrice; //unemplemented
|
||||
updatePacket.ParcelData.SalePrice = parcelData.salePrice;
|
||||
updatePacket.ParcelData.SelectedPrims = 0; //unemeplemented
|
||||
updatePacket.ParcelData.SelfCount = 0;//unemplemented
|
||||
updatePacket.ParcelData.SequenceID = sequence_id;
|
||||
|
@ -625,7 +675,7 @@ namespace OpenSim.Region.Environment
|
|||
updatePacket.ParcelData.SnapSelection = snap_selection;
|
||||
updatePacket.ParcelData.SnapshotID = parcelData.snapshotID;
|
||||
updatePacket.ParcelData.Status = (byte)parcelData.parcelStatus;
|
||||
updatePacket.ParcelData.TotalPrims = 0; //unemplemented
|
||||
updatePacket.ParcelData.TotalPrims = parcelData.ownerPrims + parcelData.groupPrims + parcelData.otherPrims;
|
||||
updatePacket.ParcelData.UserLocation = parcelData.userLocation;
|
||||
updatePacket.ParcelData.UserLookAt = parcelData.userLookAt;
|
||||
remote_client.OutPacket((Packet)updatePacket);
|
||||
|
@ -900,6 +950,59 @@ namespace OpenSim.Region.Environment
|
|||
}
|
||||
#endregion
|
||||
|
||||
public void resetParcelPrimCounts()
|
||||
{
|
||||
parcelData.groupPrims = 0;
|
||||
parcelData.ownerPrims = 0;
|
||||
parcelData.groupPrims = 0;
|
||||
primsOverMe.Clear();
|
||||
}
|
||||
|
||||
public void addPrimToCount(SceneObject obj)
|
||||
{
|
||||
LLUUID prim_owner = obj.rootPrimitive.OwnerID;
|
||||
int prim_count = obj.primCount;
|
||||
|
||||
if(prim_owner == parcelData.ownerID)
|
||||
{
|
||||
parcelData.ownerPrims += prim_count;
|
||||
}
|
||||
else if (prim_owner == parcelData.groupID)
|
||||
{
|
||||
parcelData.groupPrims += prim_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
parcelData.otherPrims += prim_count;
|
||||
}
|
||||
primsOverMe.Add(obj);
|
||||
|
||||
}
|
||||
|
||||
public void removePrimFromCount(SceneObject obj)
|
||||
{
|
||||
if (primsOverMe.Contains(obj))
|
||||
{
|
||||
LLUUID prim_owner = obj.rootPrimitive.OwnerID;
|
||||
int prim_count = obj.primCount;
|
||||
|
||||
if (prim_owner == parcelData.ownerID)
|
||||
{
|
||||
parcelData.ownerPrims -= prim_count;
|
||||
}
|
||||
else if (prim_owner == parcelData.groupID)
|
||||
{
|
||||
parcelData.groupPrims -= prim_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
parcelData.otherPrims -= prim_count;
|
||||
}
|
||||
|
||||
primsOverMe.Remove(obj);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
|
|
@ -45,6 +45,8 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
public bool m_isRootPrim;
|
||||
public EntityBase m_Parent;
|
||||
|
||||
private ParcelManager m_parcelManager;
|
||||
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// If rootprim, will return world position
|
||||
|
@ -130,10 +132,12 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
/// <param name="isRoot"></param>
|
||||
/// <param name="parent"></param>
|
||||
/// <param name="rootObject"></param>
|
||||
public Primitive(ulong regionHandle, Scene world, LLUUID ownerID, uint localID, bool isRoot, EntityBase parent, SceneObject rootObject, PrimitiveBaseShape shape, LLVector3 pos)
|
||||
public Primitive(ulong regionHandle, Scene world, ParcelManager parcelManager, LLUUID ownerID, uint localID, bool isRoot, EntityBase parent, SceneObject rootObject, PrimitiveBaseShape shape, LLVector3 pos)
|
||||
{
|
||||
|
||||
m_regionHandle = regionHandle;
|
||||
m_world = world;
|
||||
m_parcelManager = parcelManager;
|
||||
inventoryItems = new Dictionary<LLUUID, InventoryItem>();
|
||||
this.m_Parent = parent;
|
||||
this.m_isRootPrim = isRoot;
|
||||
|
@ -141,6 +145,9 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
|
||||
this.CreateFromShape(ownerID, localID, pos, shape);
|
||||
this.Rotation = Axiom.Math.Quaternion.Identity;
|
||||
|
||||
|
||||
m_parcelManager.setPrimsTainted();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -149,11 +156,19 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
/// <remarks>Empty constructor for duplication</remarks>
|
||||
public Primitive()
|
||||
{
|
||||
|
||||
m_parcelManager.setPrimsTainted();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Destructors
|
||||
|
||||
~Primitive()
|
||||
{
|
||||
m_parcelManager.setPrimsTainted();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Duplication
|
||||
|
||||
public Primitive Copy(EntityBase parent, SceneObject rootParent)
|
||||
|
@ -260,6 +275,8 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
|
||||
this.m_world.DeleteEntity(linkObject.rootUUID);
|
||||
linkObject.DeleteAllChildren();
|
||||
|
||||
m_parcelManager.setPrimsTainted();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -335,6 +352,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
prim.m_pos += offset;
|
||||
prim.updateFlag = 2;
|
||||
}
|
||||
m_parcelManager.setPrimsTainted();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -385,6 +403,8 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
|
||||
this.Pos = newPos;
|
||||
this.updateFlag = 2;
|
||||
|
||||
m_parcelManager.setPrimsTainted();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -419,6 +439,8 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
this.m_pos = newPos;
|
||||
this.updateFlag = 2;
|
||||
}
|
||||
|
||||
m_parcelManager.setPrimsTainted();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -59,6 +59,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
private uint _primCount = 702000;
|
||||
private System.Threading.Mutex _primAllocateMutex = new Mutex(false);
|
||||
private int storageCount;
|
||||
private int parcelPrimCheckCount;
|
||||
private Mutex updateLock;
|
||||
|
||||
protected AuthenticateSessionsBase authenticateHandler;
|
||||
|
@ -144,6 +145,8 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
Terrain = new TerrainEngine();
|
||||
|
||||
ScenePresence.LoadAnims();
|
||||
|
||||
this.performParcelPrimCountUpdate();
|
||||
this.httpListener = httpServer;
|
||||
}
|
||||
#endregion
|
||||
|
@ -211,6 +214,18 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
this.Backup();
|
||||
storageCount = 0;
|
||||
}
|
||||
|
||||
this.parcelPrimCheckCount++;
|
||||
if (this.parcelPrimCheckCount > 50) //check every 5 seconds for tainted prims
|
||||
{
|
||||
if (m_parcelManager.parcelPrimCountTainted)
|
||||
{
|
||||
//Perform parcel update of prim count
|
||||
performParcelPrimCountUpdate();
|
||||
this.parcelPrimCheckCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -441,7 +456,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
{
|
||||
try
|
||||
{
|
||||
SceneObject sceneOb = new SceneObject(m_regionHandle, this, ownerID, this.PrimIDAllocate(), pos, shape);
|
||||
SceneObject sceneOb = new SceneObject(m_regionHandle, this, this.m_eventManager,this.m_parcelManager, ownerID, this.PrimIDAllocate(), pos, shape);
|
||||
this.Entities.Add(sceneOb.rootUUID, sceneOb);
|
||||
|
||||
// Trigger event for listeners
|
||||
|
@ -809,6 +824,12 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
return this.commsManager.InterRegion.ExpectAvatarCrossing(regionhandle, agentID, position);
|
||||
}
|
||||
|
||||
public void performParcelPrimCountUpdate()
|
||||
{
|
||||
m_parcelManager.resetAllParcelPrimCounts();
|
||||
m_eventManager.TriggerParcelPrimCountUpdate();
|
||||
m_parcelManager.parcelPrimCountTainted = false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,9 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
public delegate void OnRemovePresenceDelegate(LLUUID uuid);
|
||||
public event OnRemovePresenceDelegate OnRemovePresence;
|
||||
|
||||
public delegate void OnParcelPrimCountUpdateDelegate();
|
||||
public event OnParcelPrimCountUpdateDelegate OnParcelPrimCountUpdate;
|
||||
|
||||
public void TriggerOnFrame()
|
||||
{
|
||||
if (OnFrame != null)
|
||||
|
@ -48,5 +51,13 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
OnBackup(dstore);
|
||||
}
|
||||
}
|
||||
|
||||
public void TriggerParcelPrimCountUpdate()
|
||||
{
|
||||
if (OnParcelPrimCountUpdate != null)
|
||||
{
|
||||
OnParcelPrimCountUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,9 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
private PhysicsScene m_PhysScene;
|
||||
private PhysicsActor m_PhysActor;
|
||||
|
||||
private EventManager m_eventManager;
|
||||
private ParcelManager m_parcelManager;
|
||||
|
||||
public LLUUID rootUUID
|
||||
{
|
||||
get
|
||||
|
@ -65,27 +68,29 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public SceneObject(ulong regionHandle, Scene world, LLUUID ownerID, uint localID, LLVector3 pos, PrimitiveBaseShape shape)
|
||||
public int primCount
|
||||
{
|
||||
m_regionHandle = regionHandle;
|
||||
m_world = world;
|
||||
this.Pos = pos;
|
||||
this.CreateRootFromShape(ownerID, localID, shape, pos);
|
||||
|
||||
// Setup a backup event listener
|
||||
world.EventManager.OnBackup += new EventManager.OnBackupDelegate(ProcessBackup);
|
||||
get
|
||||
{
|
||||
return this.ChildPrimitives.Count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes backup
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="datastore"></param>
|
||||
void ProcessBackup(OpenSim.Region.Interfaces.IRegionDataStore datastore)
|
||||
public SceneObject(ulong regionHandle, Scene world, EventManager eventManager, ParcelManager parcelManager, LLUUID ownerID, uint localID, LLVector3 pos, PrimitiveBaseShape shape)
|
||||
{
|
||||
datastore.StoreObject(this);
|
||||
m_regionHandle = regionHandle;
|
||||
m_world = world;
|
||||
m_eventManager = eventManager;
|
||||
m_parcelManager = parcelManager;
|
||||
|
||||
this.Pos = pos;
|
||||
this.CreateRootFromShape(ownerID, localID, shape, pos);
|
||||
|
||||
registerEvents();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -97,6 +102,37 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
|
||||
}
|
||||
|
||||
public void registerEvents()
|
||||
{
|
||||
m_eventManager.OnBackup += new EventManager.OnBackupDelegate(ProcessBackup);
|
||||
m_eventManager.OnParcelPrimCountUpdate += new EventManager.OnParcelPrimCountUpdateDelegate(ProcessParcelPrimCountUpdate);
|
||||
}
|
||||
public void unregisterEvents()
|
||||
{
|
||||
m_eventManager.OnBackup -= new EventManager.OnBackupDelegate(ProcessBackup);
|
||||
m_eventManager.OnParcelPrimCountUpdate -= new EventManager.OnParcelPrimCountUpdateDelegate(ProcessParcelPrimCountUpdate);
|
||||
}
|
||||
/// <summary>
|
||||
/// Processes backup
|
||||
/// </summary>
|
||||
/// <param name="datastore"></param>
|
||||
public void ProcessBackup(OpenSim.Region.Interfaces.IRegionDataStore datastore)
|
||||
{
|
||||
datastore.StoreObject(this);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sends my primitive info to the parcel manager for it to keep tally of all of the prims!
|
||||
/// </summary>
|
||||
private void ProcessParcelPrimCountUpdate()
|
||||
{
|
||||
m_parcelManager.addPrimToParcelCounts(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
@ -105,7 +141,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
/// <param name="localID"></param>
|
||||
public void CreateRootFromShape(LLUUID agentID, uint localID, PrimitiveBaseShape shape, LLVector3 pos)
|
||||
{
|
||||
this.rootPrimitive = new Primitive(this.m_regionHandle, this.m_world, agentID, localID, true, this, this, shape, pos);
|
||||
this.rootPrimitive = new Primitive(this.m_regionHandle, this.m_world,this.m_parcelManager, agentID, localID, true, this, this, shape, pos);
|
||||
this.children.Add(rootPrimitive);
|
||||
this.ChildPrimitives.Add(this.rootUUID, this.rootPrimitive);
|
||||
}
|
||||
|
@ -120,7 +156,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Copies a prim or group of prims (SceneObject) -- TODO: cleanup code
|
||||
/// </summary>
|
||||
/// <returns>A complete copy of the object</returns>
|
||||
public new SceneObject Copy()
|
||||
|
@ -136,6 +172,8 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
dupe.Rotation = this.Rotation;
|
||||
LLUUID rootu= dupe.rootUUID;
|
||||
uint rooti = dupe.rootLocalID;
|
||||
|
||||
dupe.registerEvents();
|
||||
return dupe;
|
||||
}
|
||||
|
||||
|
@ -147,6 +185,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
this.children.Clear();
|
||||
this.ChildPrimitives.Clear();
|
||||
this.rootPrimitive = null;
|
||||
unregisterEvents();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -256,5 +295,6 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
|
||||
client.OutPacket(proper);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue