aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDiva Canto2009-08-14 14:04:15 -0700
committerDiva Canto2009-08-14 14:04:15 -0700
commitcd444c1e82dcf7929cc34e00a66bc16998c3d90c (patch)
tree24a2495ea19c5a2e258582fc3db8407dfc1c86be
parentReturning UUID.Zero is scene and user profile service are null in GetSession.... (diff)
parent* Re-enable TestLoadIarV0_1ExistingUsers() (diff)
downloadopensim-SC-cd444c1e82dcf7929cc34e00a66bc16998c3d90c.zip
opensim-SC-cd444c1e82dcf7929cc34e00a66bc16998c3d90c.tar.gz
opensim-SC-cd444c1e82dcf7929cc34e00a66bc16998c3d90c.tar.bz2
opensim-SC-cd444c1e82dcf7929cc34e00a66bc16998c3d90c.tar.xz
Merge branch 'master' of ssh://diva@opensimulator.org/var/git/opensim
-rw-r--r--OpenSim/Data/Tests/BasicUserTest.cs12
-rw-r--r--OpenSim/Data/Tests/PropertyCompareConstraint.cs298
-rw-r--r--OpenSim/Data/Tests/ScrambleForTesting.cs102
-rw-r--r--OpenSim/Framework/Tests/ThreadTrackerTests.cs192
-rw-r--r--OpenSim/Framework/ThreadTracker.cs36
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs55
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs25
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs6
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs6
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs15
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs9
-rw-r--r--OpenSim/Services/Interfaces/IAssetService.cs46
-rw-r--r--OpenSim/Tests/Common/Mock/TestAssetService.cs14
-rw-r--r--README.txt2
14 files changed, 730 insertions, 88 deletions
diff --git a/OpenSim/Data/Tests/BasicUserTest.cs b/OpenSim/Data/Tests/BasicUserTest.cs
index d3e6f41..4e4ddc8 100644
--- a/OpenSim/Data/Tests/BasicUserTest.cs
+++ b/OpenSim/Data/Tests/BasicUserTest.cs
@@ -204,8 +204,16 @@ namespace OpenSim.Data.Tests
204 UUID webloginkey = UUID.Random(); 204 UUID webloginkey = UUID.Random();
205 uint homeregx = (uint) random.Next(); 205 uint homeregx = (uint) random.Next();
206 uint homeregy = (uint) random.Next(); 206 uint homeregy = (uint) random.Next();
207 Vector3 homeloc = new Vector3((float)Math.Round(random.NextDouble(),5),(float)Math.Round(random.NextDouble(),5),(float)Math.Round(random.NextDouble(),5)); 207 Vector3 homeloc
208 Vector3 homelookat = new Vector3((float)Math.Round(random.NextDouble(),5),(float)Math.Round(random.NextDouble(),5),(float)Math.Round(random.NextDouble(),5)); 208 = new Vector3(
209 (float)Math.Round(random.NextDouble(), 5),
210 (float)Math.Round(random.NextDouble(), 5),
211 (float)Math.Round(random.NextDouble(), 5));
212 Vector3 homelookat
213 = new Vector3(
214 (float)Math.Round(random.NextDouble(), 5),
215 (float)Math.Round(random.NextDouble(), 5),
216 (float)Math.Round(random.NextDouble(), 5));
209 int created = random.Next(); 217 int created = random.Next();
210 int lastlogin = random.Next(); 218 int lastlogin = random.Next();
211 string userinvuri = RandomName(); 219 string userinvuri = RandomName();
diff --git a/OpenSim/Data/Tests/PropertyCompareConstraint.cs b/OpenSim/Data/Tests/PropertyCompareConstraint.cs
new file mode 100644
index 0000000..678501e
--- /dev/null
+++ b/OpenSim/Data/Tests/PropertyCompareConstraint.cs
@@ -0,0 +1,298 @@
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.Drawing;
5using System.Linq;
6using System.Linq.Expressions;
7using System.Reflection;
8using NUnit.Framework;
9using NUnit.Framework.Constraints;
10using NUnit.Framework.SyntaxHelpers;
11using OpenMetaverse;
12using OpenSim.Framework;
13
14namespace OpenSim.Data.Tests
15{
16 public static class Constraints
17 {
18 //This is here because C# has a gap in the language, you can't infer type from a constructor
19 public static PropertyCompareConstraint<T> PropertyCompareConstraint<T>(T expected)
20 {
21 return new PropertyCompareConstraint<T>(expected);
22 }
23 }
24
25 public class PropertyCompareConstraint<T> : NUnit.Framework.Constraints.Constraint
26 {
27 private readonly object _expected;
28 //the reason everywhere uses propertyNames.Reverse().ToArray() is because the stack is backwards of the order we want to display the properties in.
29 private string failingPropertyName = string.Empty;
30 private object failingExpected;
31 private object failingActual;
32
33 public PropertyCompareConstraint(T expected)
34 {
35 _expected = expected;
36 }
37
38 public override bool Matches(object actual)
39 {
40 return ObjectCompare(_expected, actual, new Stack<string>());
41 }
42
43 private bool ObjectCompare(object expected, object actual, Stack<string> propertyNames)
44 {
45 if (actual.GetType() != expected.GetType())
46 {
47 propertyNames.Push("GetType()");
48 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
49 propertyNames.Pop();
50 failingActual = actual.GetType();
51 failingExpected = expected.GetType();
52 return false;
53 }
54
55 if(actual.GetType() == typeof(Color))
56 {
57 Color actualColor = (Color) actual;
58 Color expectedColor = (Color) expected;
59 if (actualColor.R != expectedColor.R)
60 {
61 propertyNames.Push("R");
62 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
63 propertyNames.Pop();
64 failingActual = actualColor.R;
65 failingExpected = expectedColor.R;
66 return false;
67 }
68 if (actualColor.G != expectedColor.G)
69 {
70 propertyNames.Push("G");
71 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
72 propertyNames.Pop();
73 failingActual = actualColor.G;
74 failingExpected = expectedColor.G;
75 return false;
76 }
77 if (actualColor.B != expectedColor.B)
78 {
79 propertyNames.Push("B");
80 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
81 propertyNames.Pop();
82 failingActual = actualColor.B;
83 failingExpected = expectedColor.B;
84 return false;
85 }
86 if (actualColor.A != expectedColor.A)
87 {
88 propertyNames.Push("A");
89 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
90 propertyNames.Pop();
91 failingActual = actualColor.A;
92 failingExpected = expectedColor.A;
93 return false;
94 }
95 return true;
96 }
97
98 //Skip static properties. I had a nasty problem comparing colors because of all of the public static colors.
99 PropertyInfo[] properties = expected.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
100 foreach (var property in properties)
101 {
102 if (ignores.Contains(property.Name))
103 continue;
104
105 object actualValue = property.GetValue(actual, null);
106 object expectedValue = property.GetValue(expected, null);
107
108 //If they are both null, they are equal
109 if (actualValue == null && expectedValue == null)
110 continue;
111
112 //If only one is null, then they aren't
113 if (actualValue == null || expectedValue == null)
114 {
115 propertyNames.Push(property.Name);
116 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
117 propertyNames.Pop();
118 failingActual = actualValue;
119 failingExpected = expectedValue;
120 return false;
121 }
122
123 IComparable comp = actualValue as IComparable;
124 if (comp != null)
125 {
126 if (comp.CompareTo(expectedValue) != 0)
127 {
128 propertyNames.Push(property.Name);
129 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
130 propertyNames.Pop();
131 failingActual = actualValue;
132 failingExpected = expectedValue;
133 return false;
134 }
135 continue;
136 }
137
138 IEnumerable arr = actualValue as IEnumerable;
139 if (arr != null)
140 {
141 List<object> actualList = arr.Cast<object>().ToList();
142 List<object> expectedList = ((IEnumerable)expectedValue).Cast<object>().ToList();
143 if (actualList.Count != expectedList.Count)
144 {
145 propertyNames.Push(property.Name);
146 propertyNames.Push("Count");
147 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
148 failingActual = actualList.Count;
149 failingExpected = expectedList.Count;
150 propertyNames.Pop();
151 propertyNames.Pop();
152 }
153 //Todo: A value-wise comparison of all of the values.
154 //Everything seems okay...
155 continue;
156 }
157
158 propertyNames.Push(property.Name);
159 if (!ObjectCompare(expectedValue, actualValue, propertyNames))
160 return false;
161 propertyNames.Pop();
162 }
163
164 return true;
165 }
166
167 public override void WriteDescriptionTo(MessageWriter writer)
168 {
169 writer.WriteExpectedValue(failingExpected);
170 }
171
172 public override void WriteActualValueTo(MessageWriter writer)
173 {
174 writer.WriteActualValue(failingActual);
175 writer.WriteLine();
176 writer.Write(" On Property: " + failingPropertyName);
177 }
178
179 //These notes assume the lambda: (x=>x.Parent.Value)
180 //ignores should really contain like a fully dotted version of the property name, but I'm starting with small steps
181 readonly List<string> ignores = new List<string>();
182 public PropertyCompareConstraint<T> IgnoreProperty(Expression<Func<T, object>> func)
183 {
184 Expression express = func.Body;
185 PullApartExpression(express);
186
187 return this;
188 }
189
190 private void PullApartExpression(Expression express)
191 {
192 //This deals with any casts... like implicit casts to object. Not all UnaryExpression are casts, but this is a first attempt.
193 if (express is UnaryExpression)
194 PullApartExpression(((UnaryExpression)express).Operand);
195 if (express is MemberExpression)
196 {
197 //If the inside of the lambda is the access to x, we've hit the end of the chain.
198 // We should track by the fully scoped parameter name, but this is the first rev of doing this.
199 if (((MemberExpression)express).Expression is ParameterExpression)
200 {
201 ignores.Add(((MemberExpression)express).Member.Name);
202 }
203 else
204 {
205 //Otherwise there could be more parameters inside...
206 PullApartExpression(((MemberExpression)express).Expression);
207 }
208 }
209 }
210 }
211
212 [TestFixture]
213 public class PropertyCompareConstraintTest
214 {
215 public class HasInt
216 {
217 public int TheValue { get; set; }
218 }
219
220 [Test]
221 public void IntShouldMatch()
222 {
223 HasInt actual = new HasInt { TheValue = 5 };
224 HasInt expected = new HasInt { TheValue = 5 };
225 var constraint = Constraints.PropertyCompareConstraint(expected);
226
227 Assert.That(constraint.Matches(actual), Is.True);
228 }
229
230 [Test]
231 public void IntShouldNotMatch()
232 {
233 HasInt actual = new HasInt { TheValue = 5 };
234 HasInt expected = new HasInt { TheValue = 4 };
235 var constraint = Constraints.PropertyCompareConstraint(expected);
236
237 Assert.That(constraint.Matches(actual), Is.False);
238 }
239
240
241 [Test]
242 public void IntShouldIgnore()
243 {
244 HasInt actual = new HasInt { TheValue = 5 };
245 HasInt expected = new HasInt { TheValue = 4 };
246 var constraint = Constraints.PropertyCompareConstraint(expected).IgnoreProperty(x=>x.TheValue);
247
248 Assert.That(constraint.Matches(actual), Is.True);
249 }
250
251 [Test]
252 public void AssetShouldMatch()
253 {
254 UUID uuid1 = UUID.Random();
255 AssetBase actual = new AssetBase(uuid1, "asset one");
256 AssetBase expected = new AssetBase(uuid1, "asset one");
257
258 var constraint = Constraints.PropertyCompareConstraint(expected);
259
260 Assert.That(constraint.Matches(actual), Is.True);
261 }
262
263 [Test]
264 public void AssetShouldNotMatch()
265 {
266 UUID uuid1 = UUID.Random();
267 AssetBase actual = new AssetBase(uuid1, "asset one");
268 AssetBase expected = new AssetBase(UUID.Random(), "asset one");
269
270 var constraint = Constraints.PropertyCompareConstraint(expected);
271
272 Assert.That(constraint.Matches(actual), Is.False);
273 }
274
275 [Test]
276 public void AssetShouldNotMatch2()
277 {
278 UUID uuid1 = UUID.Random();
279 AssetBase actual = new AssetBase(uuid1, "asset one");
280 AssetBase expected = new AssetBase(uuid1, "asset two");
281
282 var constraint = Constraints.PropertyCompareConstraint(expected);
283
284 Assert.That(constraint.Matches(actual), Is.False);
285 }
286
287 [Test]
288 public void TestColors()
289 {
290 Color actual = Color.Red;
291 Color expected = Color.FromArgb(actual.A, actual.R, actual.G, actual.B);
292
293 var constraint = Constraints.PropertyCompareConstraint(expected);
294
295 Assert.That(constraint.Matches(actual), Is.True);
296 }
297 }
298} \ No newline at end of file
diff --git a/OpenSim/Data/Tests/ScrambleForTesting.cs b/OpenSim/Data/Tests/ScrambleForTesting.cs
new file mode 100644
index 0000000..c6e467f
--- /dev/null
+++ b/OpenSim/Data/Tests/ScrambleForTesting.cs
@@ -0,0 +1,102 @@
1using System;
2using System.Collections;
3using System.Reflection;
4using System.Text;
5using NUnit.Framework;
6using OpenMetaverse;
7using OpenSim.Framework;
8
9namespace OpenSim.Data.Tests
10{
11 public static class ScrambleForTesting
12 {
13 private static readonly Random random = new Random();
14 public static void Scramble(object obj)
15 {
16 PropertyInfo[] properties = obj.GetType().GetProperties();
17 foreach (var property in properties)
18 {
19 //Skip indexers of classes. We will assume that everything that has an indexer
20 // is also IEnumberable. May not always be true, but should be true normally.
21 if(property.GetIndexParameters().Length > 0)
22 continue;
23
24 RandomizeProperty(obj, property, null);
25 }
26 //Now if it implments IEnumberable, it's probably some kind of list, so we should randomize
27 // everything inside of it.
28 IEnumerable enumerable = obj as IEnumerable;
29 if(enumerable != null)
30 {
31 foreach (object value in enumerable)
32 {
33 Scramble(value);
34 }
35 }
36 }
37
38 private static void RandomizeProperty(object obj, PropertyInfo property, object[] index)
39 {
40 Type t = property.PropertyType;
41 if (!property.CanWrite)
42 return;
43 object value = property.GetValue(obj, index);
44 if (value == null)
45 return;
46
47 if (t == typeof (string))
48 property.SetValue(obj, RandomName(), index);
49 else if (t == typeof (UUID))
50 property.SetValue(obj, UUID.Random(), index);
51 else if (t == typeof (sbyte))
52 property.SetValue(obj, (sbyte)random.Next(sbyte.MinValue, sbyte.MaxValue), index);
53 else if (t == typeof (short))
54 property.SetValue(obj, (short)random.Next(short.MinValue, short.MaxValue), index);
55 else if (t == typeof (int))
56 property.SetValue(obj, random.Next(), index);
57 else if (t == typeof (long))
58 property.SetValue(obj, random.Next() * int.MaxValue, index);
59 else if (t == typeof (byte))
60 property.SetValue(obj, (byte)random.Next(byte.MinValue, byte.MaxValue), index);
61 else if (t == typeof (ushort))
62 property.SetValue(obj, (ushort)random.Next(ushort.MinValue, ushort.MaxValue), index);
63 else if (t == typeof (uint))
64 property.SetValue(obj, Convert.ToUInt32(random.Next()), index);
65 else if (t == typeof (ulong))
66 property.SetValue(obj, Convert.ToUInt64(random.Next()) * Convert.ToUInt64(UInt32.MaxValue), index);
67 else if (t == typeof (bool))
68 property.SetValue(obj, true, index);
69 else if (t == typeof (byte[]))
70 {
71 byte[] bytes = new byte[30];
72 random.NextBytes(bytes);
73 property.SetValue(obj, bytes, index);
74 }
75 else
76 Scramble(value);
77 }
78
79 private static string RandomName()
80 {
81 StringBuilder name = new StringBuilder();
82 int size = random.Next(5, 12);
83 for (int i = 0; i < size; i++)
84 {
85 char ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
86 name.Append(ch);
87 }
88 return name.ToString();
89 }
90 }
91
92 [TestFixture]
93 public class ScrableForTestingTest
94 {
95 [Test]
96 public void TestScramble()
97 {
98 AssetBase actual = new AssetBase(UUID.Random(), "asset one");
99 ScrambleForTesting.Scramble(actual);
100 }
101 }
102} \ No newline at end of file
diff --git a/OpenSim/Framework/Tests/ThreadTrackerTests.cs b/OpenSim/Framework/Tests/ThreadTrackerTests.cs
new file mode 100644
index 0000000..37c75ef
--- /dev/null
+++ b/OpenSim/Framework/Tests/ThreadTrackerTests.cs
@@ -0,0 +1,192 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using NUnit.Framework;
30using System.Threading;
31using System.Collections.Generic;
32
33namespace OpenSim.Framework.Tests
34{
35 [TestFixture]
36 public class ThreadTrackerTests
37 {
38 private bool running = true;
39 private bool running2 = true;
40
41 [Test]
42 public void DefaultThreadTrackerTest()
43 {
44 List<Thread> lThread = ThreadTracker.GetThreads();
45
46 /*
47 foreach (Thread t in lThread)
48 {
49 System.Console.WriteLine(t.Name);
50 }
51 */
52
53 Assert.That(lThread.Count == 1);
54 Assert.That(lThread[0].Name == "ThreadTrackerThread");
55 }
56
57 /// <summary>
58 /// Validate that adding a thread to the thread tracker works
59 /// Validate that removing a thread from the thread tracker also works.
60 /// </summary>
61 [Test]
62 public void AddThreadToThreadTrackerTestAndRemoveTest()
63 {
64 Thread t = new Thread(run);
65 t.Name = "TestThread";
66 t.Priority = ThreadPriority.BelowNormal;
67 t.IsBackground = true;
68 t.SetApartmentState(ApartmentState.MTA);
69 t.Start();
70 ThreadTracker.Add(t);
71
72 List<Thread> lThread = ThreadTracker.GetThreads();
73
74 Assert.That(lThread.Count == 2);
75
76 foreach (Thread tr in lThread)
77 {
78 Assert.That((tr.Name == "ThreadTrackerThread" || tr.Name == "TestThread"));
79 }
80 running = false;
81 ThreadTracker.Remove(t);
82
83 lThread = ThreadTracker.GetThreads();
84
85 Assert.That(lThread.Count == 1);
86
87 foreach (Thread tr in lThread)
88 {
89 Assert.That((tr.Name == "ThreadTrackerThread"));
90 }
91
92
93 }
94
95 /// <summary>
96 /// Test a dead thread removal by aborting it and setting it's last seen active date to 50 seconds
97 /// </summary>
98 [Test]
99 public void DeadThreadTest()
100 {
101 Thread t = new Thread(run2);
102 t.Name = "TestThread";
103 t.Priority = ThreadPriority.BelowNormal;
104 t.IsBackground = true;
105 t.SetApartmentState(ApartmentState.MTA);
106 t.Start();
107 ThreadTracker.Add(t);
108 t.Abort();
109 Thread.Sleep(5000);
110 ThreadTracker.m_Threads[1].LastSeenActive = DateTime.Now.Ticks - (50*10000000);
111 ThreadTracker.CleanUp();
112 List<Thread> lThread = ThreadTracker.GetThreads();
113
114 Assert.That(lThread.Count == 1);
115
116 foreach (Thread tr in lThread)
117 {
118 Assert.That((tr.Name == "ThreadTrackerThread"));
119 }
120 }
121
122 [Test]
123 public void UnstartedThreadTest()
124 {
125 Thread t = new Thread(run2);
126 t.Name = "TestThread";
127 t.Priority = ThreadPriority.BelowNormal;
128 t.IsBackground = true;
129 t.SetApartmentState(ApartmentState.MTA);
130 ThreadTracker.Add(t);
131 ThreadTracker.m_Threads[1].LastSeenActive = DateTime.Now.Ticks - (50 * 10000000);
132 ThreadTracker.CleanUp();
133 List<Thread> lThread = ThreadTracker.GetThreads();
134
135 Assert.That(lThread.Count == 1);
136
137 foreach (Thread tr in lThread)
138 {
139 Assert.That((tr.Name == "ThreadTrackerThread"));
140 }
141 }
142
143 [Test]
144 public void NullThreadTest()
145 {
146 Thread t = null;
147 ThreadTracker.Add(t);
148
149 List<Thread> lThread = ThreadTracker.GetThreads();
150
151 Assert.That(lThread.Count == 1);
152
153 foreach (Thread tr in lThread)
154 {
155 Assert.That((tr.Name == "ThreadTrackerThread"));
156 }
157 }
158
159
160 /// <summary>
161 /// Worker thread 0
162 /// </summary>
163 /// <param name="o"></param>
164 public void run( object o)
165 {
166 while (running)
167 {
168 Thread.Sleep(5000);
169 }
170 }
171
172 /// <summary>
173 /// Worker thread 1
174 /// </summary>
175 /// <param name="o"></param>
176 public void run2(object o)
177 {
178 try
179 {
180 while (running2)
181 {
182 Thread.Sleep(5000);
183 }
184
185 }
186 catch (ThreadAbortException)
187 {
188 }
189 }
190
191 }
192}
diff --git a/OpenSim/Framework/ThreadTracker.cs b/OpenSim/Framework/ThreadTracker.cs
index d8bd2c0..fa6f0b8 100644
--- a/OpenSim/Framework/ThreadTracker.cs
+++ b/OpenSim/Framework/ThreadTracker.cs
@@ -77,12 +77,15 @@ namespace OpenSim.Framework
77 public static void Add(Thread thread) 77 public static void Add(Thread thread)
78 { 78 {
79#if DEBUG 79#if DEBUG
80 lock (m_Threads) 80 if (thread != null)
81 { 81 {
82 ThreadTrackerItem tti = new ThreadTrackerItem(); 82 lock (m_Threads)
83 tti.Thread = thread; 83 {
84 tti.LastSeenActive = DateTime.Now.Ticks; 84 ThreadTrackerItem tti = new ThreadTrackerItem();
85 m_Threads.Add(tti); 85 tti.Thread = thread;
86 tti.LastSeenActive = DateTime.Now.Ticks;
87 m_Threads.Add(tti);
88 }
86 } 89 }
87#endif 90#endif
88 } 91 }
@@ -107,16 +110,25 @@ namespace OpenSim.Framework
107 { 110 {
108 foreach (ThreadTrackerItem tti in new ArrayList(m_Threads)) 111 foreach (ThreadTrackerItem tti in new ArrayList(m_Threads))
109 { 112 {
110 if (tti.Thread.IsAlive) 113 try
111 { 114 {
112 // Its active 115
113 tti.LastSeenActive = DateTime.Now.Ticks; 116
117 if (tti.Thread.IsAlive)
118 {
119 // Its active
120 tti.LastSeenActive = DateTime.Now.Ticks;
121 }
122 else
123 {
124 // Its not active -- if its expired then remove it
125 if (tti.LastSeenActive + ThreadTimeout < DateTime.Now.Ticks)
126 m_Threads.Remove(tti);
127 }
114 } 128 }
115 else 129 catch (NullReferenceException)
116 { 130 {
117 // Its not active -- if its expired then remove it 131 m_Threads.Remove(tti);
118 if (tti.LastSeenActive + ThreadTimeout < DateTime.Now.Ticks)
119 m_Threads.Remove(tti);
120 } 132 }
121 } 133 }
122 } 134 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
index 28b4d64..470a386 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
@@ -74,7 +74,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
74 /// <summary> 74 /// <summary>
75 /// Test saving a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet). 75 /// Test saving a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet).
76 /// </summary> 76 /// </summary>
77 //[Test] 77 [Test]
78 public void TestSaveIarV0_1() 78 public void TestSaveIarV0_1()
79 { 79 {
80 TestHelper.InMethod(); 80 TestHelper.InMethod();
@@ -82,7 +82,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
82 82
83 InventoryArchiverModule archiverModule = new InventoryArchiverModule(); 83 InventoryArchiverModule archiverModule = new InventoryArchiverModule();
84 84
85 Scene scene = SceneSetupHelpers.SetupScene(""); 85 Scene scene = SceneSetupHelpers.SetupScene("Inventory");
86 SceneSetupHelpers.SetupSceneModules(scene, archiverModule); 86 SceneSetupHelpers.SetupSceneModules(scene, archiverModule);
87 CommunicationsManager cm = scene.CommsManager; 87 CommunicationsManager cm = scene.CommsManager;
88 88
@@ -222,7 +222,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
222 /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where 222 /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where
223 /// an account exists with the creator name. 223 /// an account exists with the creator name.
224 /// </summary> 224 /// </summary>
225 //[Test] 225 [Test]
226 public void TestLoadIarV0_1ExistingUsers() 226 public void TestLoadIarV0_1ExistingUsers()
227 { 227 {
228 TestHelper.InMethod(); 228 TestHelper.InMethod();
@@ -262,7 +262,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
262 InventoryArchiverModule archiverModule = new InventoryArchiverModule(); 262 InventoryArchiverModule archiverModule = new InventoryArchiverModule();
263 263
264 // Annoyingly, we have to set up a scene even though inventory loading has nothing to do with a scene 264 // Annoyingly, we have to set up a scene even though inventory loading has nothing to do with a scene
265 Scene scene = SceneSetupHelpers.SetupScene(); 265 Scene scene = SceneSetupHelpers.SetupScene("inventory");
266 IUserAdminService userAdminService = scene.CommsManager.UserAdminService; 266 IUserAdminService userAdminService = scene.CommsManager.UserAdminService;
267 267
268 SceneSetupHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); 268 SceneSetupHelpers.SetupSceneModules(scene, serialiserModule, archiverModule);
@@ -276,16 +276,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
276 276
277 CachedUserInfo userInfo 277 CachedUserInfo userInfo
278 = scene.CommsManager.UserProfileCacheService.GetUserDetails(userFirstName, userLastName); 278 = scene.CommsManager.UserProfileCacheService.GetUserDetails(userFirstName, userLastName);
279 //userInfo.FetchInventory(); 279
280 /*
281 for (int i = 0 ; i < 50 ; i++)
282 {
283 if (userInfo.HasReceivedInventory == true)
284 break;
285 Thread.Sleep(200);
286 }
287 Assert.That(userInfo.HasReceivedInventory, Is.True, "FetchInventory timed out (10 seconds)");
288 */
289 InventoryItemBase foundItem = userInfo.RootFolder.FindItemByPath(itemName); 280 InventoryItemBase foundItem = userInfo.RootFolder.FindItemByPath(itemName);
290 Assert.That(foundItem, Is.Not.Null, "Didn't find loaded item"); 281 Assert.That(foundItem, Is.Not.Null, "Didn't find loaded item");
291 Assert.That( 282 Assert.That(
@@ -395,17 +386,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
395 userInfo = UserProfileTestUtils.CreateUserWithInventory(commsManager, InventoryReceived); 386 userInfo = UserProfileTestUtils.CreateUserWithInventory(commsManager, InventoryReceived);
396 Monitor.Wait(this, 60000); 387 Monitor.Wait(this, 60000);
397 } 388 }
398
399 //userInfo.FetchInventory();
400 /*
401 for (int i = 0 ; i < 50 ; i++)
402 {
403 if (userInfo.HasReceivedInventory == true)
404 break;
405 Thread.Sleep(200);
406 }
407 Assert.That(userInfo.HasReceivedInventory, Is.True, "FetchInventory timed out (10 seconds)");
408 */
409 389
410 Console.WriteLine("userInfo.RootFolder 1: {0}", userInfo.RootFolder); 390 Console.WriteLine("userInfo.RootFolder 1: {0}", userInfo.RootFolder);
411 391
@@ -429,22 +409,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
429 409
430 Console.WriteLine("userInfo.RootFolder 2: {0}", userInfo.RootFolder); 410 Console.WriteLine("userInfo.RootFolder 2: {0}", userInfo.RootFolder);
431 411
432 try 412 new InventoryArchiveReadRequest(userInfo, null, (Stream)null, null, null)
433 { 413 .ReplicateArchivePathToUserInventory(
434 new InventoryArchiveReadRequest(userInfo, null, (Stream)null, null, null) 414 itemArchivePath, false, userInfo.RootFolder, foldersCreated, nodesLoaded);
435 .ReplicateArchivePathToUserInventory(itemArchivePath, false, userInfo.RootFolder, foldersCreated, nodesLoaded); 415
436 416 Console.WriteLine("userInfo.RootFolder 3: {0}", userInfo.RootFolder);
437 Console.WriteLine("userInfo.RootFolder 3: {0}", userInfo.RootFolder); 417 InventoryFolderImpl folder1 = userInfo.RootFolder.FindFolderByPath("a");
438 InventoryFolderImpl folder1 = userInfo.RootFolder.FindFolderByPath("a"); 418 Assert.That(folder1, Is.Not.Null, "Could not find folder a");
439 Assert.That(folder1, Is.Not.Null, "Could not find folder a"); 419 InventoryFolderImpl folder2 = folder1.FindFolderByPath("b");
440 InventoryFolderImpl folder2 = folder1.FindFolderByPath("b"); 420 Assert.That(folder2, Is.Not.Null, "Could not find folder b");
441 Assert.That(folder2, Is.Not.Null, "Could not find folder b");
442 }
443 catch (NullReferenceException e)
444 {
445 // Non fatal for now until we resolve the race condition
446 Console.WriteLine("Test failed with {0}", e);
447 }
448 } 421 }
449 } 422 }
450} 423}
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs
index 1836447..88452d2 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs
@@ -113,6 +113,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
113 agent.InventoryFolder = UUID.Zero; 113 agent.InventoryFolder = UUID.Zero;
114 agent.startpos = Vector3.Zero; 114 agent.startpos = Vector3.Zero;
115 agent.CapsPath = GetRandomCapsObjectPath(); 115 agent.CapsPath = GetRandomCapsObjectPath();
116 agent.ChildrenCapSeeds = new Dictionary<ulong, string>();
116 117
117 string reason; 118 string reason;
118 scene.NewUserConnection(agent, out reason); 119 scene.NewUserConnection(agent, out reason);
@@ -147,7 +148,13 @@ namespace OpenSim.Region.Framework.Scenes.Tests
147 TestHelper.InMethod(); 148 TestHelper.InMethod();
148 149
149 string reason; 150 string reason;
151
152 if (acd1 == null)
153 fixNullPresence();
154
150 scene.NewUserConnection(acd1, out reason); 155 scene.NewUserConnection(acd1, out reason);
156 if (testclient == null)
157 testclient = new TestClient(acd1, scene);
151 scene.AddNewClient(testclient); 158 scene.AddNewClient(testclient);
152 159
153 ScenePresence presence = scene.GetScenePresence(agent1); 160 ScenePresence presence = scene.GetScenePresence(agent1);
@@ -162,6 +169,24 @@ namespace OpenSim.Region.Framework.Scenes.Tests
162 169
163 Assert.That(neighbours.Count, Is.EqualTo(2)); 170 Assert.That(neighbours.Count, Is.EqualTo(2));
164 } 171 }
172 public void fixNullPresence()
173 {
174 string firstName = "testfirstname";
175
176 AgentCircuitData agent = new AgentCircuitData();
177 agent.AgentID = agent1;
178 agent.firstname = firstName;
179 agent.lastname = "testlastname";
180 agent.SessionID = UUID.Zero;
181 agent.SecureSessionID = UUID.Zero;
182 agent.circuitcode = 123;
183 agent.BaseFolder = UUID.Zero;
184 agent.InventoryFolder = UUID.Zero;
185 agent.startpos = Vector3.Zero;
186 agent.CapsPath = GetRandomCapsObjectPath();
187
188 acd1 = agent;
189 }
165 190
166 [Test] 191 [Test]
167 public void T013_TestRemoveNeighbourRegion() 192 public void T013_TestRemoveNeighbourRegion()
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index ff85b96..691732a 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -125,9 +125,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
125 125
126 if (lease.CurrentState == LeaseState.Initial) 126 if (lease.CurrentState == LeaseState.Initial)
127 { 127 {
128 lease.InitialLeaseTime = TimeSpan.FromMinutes(1.0); 128 lease.InitialLeaseTime = TimeSpan.FromMinutes(0);
129 lease.RenewOnCallTime = TimeSpan.FromSeconds(10.0); 129// lease.RenewOnCallTime = TimeSpan.FromSeconds(10.0);
130 lease.SponsorshipTimeout = TimeSpan.FromMinutes(1.0); 130// lease.SponsorshipTimeout = TimeSpan.FromMinutes(1.0);
131 } 131 }
132 return lease; 132 return lease;
133 } 133 }
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index 6539bda..6e3a3ab 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -166,9 +166,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
166 166
167 if (lease.CurrentState == LeaseState.Initial) 167 if (lease.CurrentState == LeaseState.Initial)
168 { 168 {
169 lease.InitialLeaseTime = TimeSpan.FromMinutes(1.0); 169 lease.InitialLeaseTime = TimeSpan.FromMinutes(0);
170 lease.RenewOnCallTime = TimeSpan.FromSeconds(10.0); 170// lease.RenewOnCallTime = TimeSpan.FromSeconds(10.0);
171 lease.SponsorshipTimeout = TimeSpan.FromMinutes(1.0); 171// lease.SponsorshipTimeout = TimeSpan.FromMinutes(1.0);
172 } 172 }
173 return lease; 173 return lease;
174 } 174 }
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs
index d119a77..838cafb 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs
@@ -42,16 +42,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
42 public partial class ScriptBaseClass : MarshalByRefObject, IScript 42 public partial class ScriptBaseClass : MarshalByRefObject, IScript
43 { 43 {
44 private Dictionary<string, MethodInfo> inits = new Dictionary<string, MethodInfo>(); 44 private Dictionary<string, MethodInfo> inits = new Dictionary<string, MethodInfo>();
45 private ScriptSponsor m_sponser; 45// private ScriptSponsor m_sponser;
46 46
47 public override Object InitializeLifetimeService() 47 public override Object InitializeLifetimeService()
48 { 48 {
49 ILease lease = (ILease)base.InitializeLifetimeService(); 49 ILease lease = (ILease)base.InitializeLifetimeService();
50 if (lease.CurrentState == LeaseState.Initial) 50 if (lease.CurrentState == LeaseState.Initial)
51 { 51 {
52 lease.InitialLeaseTime = TimeSpan.FromMinutes(1.0); 52 // Infinite
53 lease.RenewOnCallTime = TimeSpan.FromSeconds(10.0); 53 lease.InitialLeaseTime = TimeSpan.FromMinutes(0);
54 lease.SponsorshipTimeout = TimeSpan.FromMinutes(1.0); 54// lease.RenewOnCallTime = TimeSpan.FromSeconds(10.0);
55// lease.SponsorshipTimeout = TimeSpan.FromMinutes(1.0);
55 } 56 }
56 return lease; 57 return lease;
57 } 58 }
@@ -79,7 +80,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
79 } 80 }
80 } 81 }
81 82
82 m_sponser = new ScriptSponsor(); 83// m_sponser = new ScriptSponsor();
83 } 84 }
84 85
85 private Executor m_Executor = null; 86 private Executor m_Executor = null;
@@ -112,7 +113,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
112 return; 113 return;
113 114
114 ILease lease = (ILease)RemotingServices.GetLifetimeService(data as MarshalByRefObject); 115 ILease lease = (ILease)RemotingServices.GetLifetimeService(data as MarshalByRefObject);
115 lease.Register(m_sponser); 116// lease.Register(m_sponser);
116 117
117 MethodInfo mi = inits[api]; 118 MethodInfo mi = inits[api];
118 119
@@ -126,7 +127,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
126 127
127 public void Close() 128 public void Close()
128 { 129 {
129 m_sponser.Close(); 130// m_sponser.Close();
130 } 131 }
131 132
132 public Dictionary<string, object> GetVars() 133 public Dictionary<string, object> GetVars()
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 4211ced..225126d 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -53,7 +53,7 @@ using OpenSim.Region.ScriptEngine.Interfaces;
53 53
54namespace OpenSim.Region.ScriptEngine.Shared.Instance 54namespace OpenSim.Region.ScriptEngine.Shared.Instance
55{ 55{
56 public class ScriptInstance : MarshalByRefObject, IScriptInstance, ISponsor 56 public class ScriptInstance : MarshalByRefObject, IScriptInstance
57 { 57 {
58 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 58 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
59 59
@@ -261,7 +261,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
261 "SecondLife.Script"); 261 "SecondLife.Script");
262 262
263 ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); 263 ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
264 lease.Register(this); 264// lease.Register(this);
265 } 265 }
266 catch (Exception) 266 catch (Exception)
267 { 267 {
@@ -1006,10 +1006,5 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
1006 { 1006 {
1007 return true; 1007 return true;
1008 } 1008 }
1009
1010 public TimeSpan Renewal(ILease lease)
1011 {
1012 return lease.InitialLeaseTime;
1013 }
1014 } 1009 }
1015} 1010}
diff --git a/OpenSim/Services/Interfaces/IAssetService.cs b/OpenSim/Services/Interfaces/IAssetService.cs
index ec8a71b..6dfe78d 100644
--- a/OpenSim/Services/Interfaces/IAssetService.cs
+++ b/OpenSim/Services/Interfaces/IAssetService.cs
@@ -34,25 +34,53 @@ namespace OpenSim.Services.Interfaces
34 34
35 public interface IAssetService 35 public interface IAssetService
36 { 36 {
37 // Three different ways to retrieve an asset 37 /// <summary>
38 // 38 /// Get an asset synchronously.
39 /// </summary>
40 /// <param name="id"></param>
41 /// <returns></returns>
39 AssetBase Get(string id); 42 AssetBase Get(string id);
43
44 /// <summary>
45 /// Get an asset's metadata
46 /// </summary>
47 /// <param name="id"></param>
48 /// <returns></returns>
40 AssetMetadata GetMetadata(string id); 49 AssetMetadata GetMetadata(string id);
50
41 byte[] GetData(string id); 51 byte[] GetData(string id);
42 52
53 /// <summary>
54 /// Get an asset asynchronously
55 /// </summary>
56 /// <param name="id">The asset id</param>
57 /// <param name="sender">Represents the requester. Passed back via the handler</param>
58 /// <param name="handler">The handler to call back once the asset has been retrieved</param>
59 /// <returns>True if the id was parseable, false otherwise</returns>
43 bool Get(string id, Object sender, AssetRetrieved handler); 60 bool Get(string id, Object sender, AssetRetrieved handler);
44 61
45 // Creates a new asset 62 /// <summary>
46 // Returns a random ID if none is passed into it 63 /// Creates a new asset
47 // 64 /// </summary>
65 /// Returns a random ID if none is passed into it
66 /// <param name="asset"></param>
67 /// <returns></returns>
48 string Store(AssetBase asset); 68 string Store(AssetBase asset);
49 69
50 // Attachments and bare scripts need this!! 70 /// <summary>
51 // 71 /// Update an asset's content
72 /// </summary>
73 /// Attachments and bare scripts need this!!
74 /// <param name="id"> </param>
75 /// <param name="data"></param>
76 /// <returns></returns>
52 bool UpdateContent(string id, byte[] data); 77 bool UpdateContent(string id, byte[] data);
53 78
54 // Kill an asset 79 /// <summary>
55 // 80 /// Delete an asset
81 /// </summary>
82 /// <param name="id"></param>
83 /// <returns></returns>
56 bool Delete(string id); 84 bool Delete(string id);
57 } 85 }
58} 86}
diff --git a/OpenSim/Tests/Common/Mock/TestAssetService.cs b/OpenSim/Tests/Common/Mock/TestAssetService.cs
index 5f1184b..81f123a 100644
--- a/OpenSim/Tests/Common/Mock/TestAssetService.cs
+++ b/OpenSim/Tests/Common/Mock/TestAssetService.cs
@@ -45,7 +45,13 @@ namespace OpenSim.Tests.Common.Mock
45 45
46 public AssetBase Get(string id) 46 public AssetBase Get(string id)
47 { 47 {
48 return Assets[ id ]; 48 AssetBase asset;
49 if (Assets.ContainsKey(id))
50 asset = Assets[id];
51 else
52 asset = null;
53
54 return asset;
49 } 55 }
50 56
51 public AssetMetadata GetMetadata(string id) 57 public AssetMetadata GetMetadata(string id)
@@ -59,8 +65,10 @@ namespace OpenSim.Tests.Common.Mock
59 } 65 }
60 66
61 public bool Get(string id, object sender, AssetRetrieved handler) 67 public bool Get(string id, object sender, AssetRetrieved handler)
62 { 68 {
63 throw new NotImplementedException(); 69 handler(id, sender, Get(id));
70
71 return true;
64 } 72 }
65 73
66 public string Store(AssetBase asset) 74 public string Store(AssetBase asset)
diff --git a/README.txt b/README.txt
index e796bb2..5c34201 100644
--- a/README.txt
+++ b/README.txt
@@ -25,7 +25,7 @@ See configuring OpenSim
25== Installation on Linux == 25== Installation on Linux ==
26 26
27Prereqs: 27Prereqs:
28 * Mono >= 2.4 (>= 2.4.2 is better) 28 * Mono >= 2.0.1 (>= 2.4.2 is better)
29 * Nant >= 0.86beta 29 * Nant >= 0.86beta
30 * sqlite3 or mysql 5.x (you'll need a back end database) 30 * sqlite3 or mysql 5.x (you'll need a back end database)
31 31