Mercurial > pub > ImplabNet
annotate Implab/Components/PollingComponent.cs @ 210:5dc21f6a3222 v2
Code review for RunnableComponent
Added StaApartment class based on System.Windows.Forms.Application message loop
author | cin |
---|---|
date | Mon, 20 Mar 2017 17:44:18 +0300 |
parents | 7d07503621fe |
children |
rev | line source |
---|---|
203
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
1 using System; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
2 using System.Threading; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
3 using Implab.Diagnostics; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
4 |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
5 namespace Implab.Components { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
6 public class PollingComponent : RunnableComponent { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
7 readonly Timer m_timer; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
8 readonly Func<Func<ICancellationToken, IPromise>, IPromise> m_dispatcher; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
9 readonly TimeSpan m_interval; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
10 |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
11 readonly object m_lock = new object(); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
12 |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
13 ActionTask m_pending; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
14 |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
15 protected PollingComponent(TimeSpan interval, Func<Func<ICancellationToken, IPromise>, IPromise> dispatcher, bool initialized) : base(initialized) { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
16 m_timer = new Timer(OnInternalTick); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
17 |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
18 m_interval = interval; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
19 m_dispatcher = dispatcher; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
20 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
21 |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
22 protected override IPromise OnStart() { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
23 m_timer.Change(TimeSpan.Zero, m_interval); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
24 |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
25 return base.OnStart(); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
26 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
27 |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
28 void OnInternalTick(object state) { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
29 if (StartTick()) { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
30 try { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
31 if (m_dispatcher != null) { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
32 var result = m_dispatcher(OnTick); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
33 m_pending.CancellationRequested(result.Cancel); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
34 AwaitTick(result); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
35 } else { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
36 AwaitTick(OnTick(m_pending)); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
37 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
38 } catch (Exception error) { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
39 HandleTickError(error); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
40 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
41 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
42 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
43 |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
44 /// <summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
45 /// Checks wheather there is no running handler in the component and marks that the handler is starting. |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
46 /// </summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
47 /// <returns>boolean value, true - the new tick handler may be invoked, false - a tick handler is already running or a component isn't running.</returns> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
48 /// <remarks> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
49 /// If the component is stopping no new handlers can be run. Every successful call to this method must be completed with either AwaitTick or HandleTickError handlers. |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
50 /// </remarks> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
51 protected virtual bool StartTick() { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
52 lock (m_lock) { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
53 if (State != ExecutionState.Running || m_pending != null) |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
54 return false; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
55 // actually the component may be in a not running state here (stopping, disposed or what ever), |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
56 // but OnStop method also locks on the same object and will handle operation in m_pending |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
57 m_pending = new ActionTask( |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
58 () => { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
59 // only one operation is running, it's safe to assing m_pending from it |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
60 m_pending = null; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
61 }, |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
62 ex => { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
63 try { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
64 OnTickError(ex); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
65 // Analysis disable once EmptyGeneralCatchClause |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
66 } catch { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
67 } finally { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
68 m_pending = null; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
69 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
70 // suppress error |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
71 }, |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
72 ex => { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
73 try { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
74 OnTickCancel(ex); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
75 // Analysis disable once EmptyGeneralCatchClause |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
76 } catch { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
77 } finally { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
78 m_pending = null; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
79 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
80 // supress cancellation |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
81 }, |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
82 false |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
83 ); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
84 return true; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
85 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
86 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
87 |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
88 /// <summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
89 /// Awaits the tick. |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
90 /// </summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
91 /// <param name="tick">Tick.</param> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
92 /// <remarks> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
93 /// This method is called only after StartTick method and m_pending will hold the promise which should be fulfilled. |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
94 /// </remarks> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
95 void AwaitTick(IPromise tick) { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
96 if (tick == null) { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
97 m_pending.Resolve(); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
98 } else { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
99 tick.On( |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
100 m_pending.Resolve, |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
101 m_pending.Reject, |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
102 m_pending.CancelOperation |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
103 ); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
104 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
105 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
106 |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
107 /// <summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
108 /// Handles the tick error. |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
109 /// </summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
110 /// <remarks> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
111 /// This method is called only after StartTick method and m_pending will hold the promise which should be fulfilled. |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
112 /// </remarks> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
113 void HandleTickError(Exception error) { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
114 m_pending.Reject(error); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
115 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
116 |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
117 protected virtual void OnTickError(Exception error) { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
118 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
119 |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
120 protected virtual void OnTickCancel(Exception error) { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
121 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
122 |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
123 /// <summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
124 /// Invoked when the timer ticks, use this method to implement your logic |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
125 /// </summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
126 protected virtual IPromise OnTick(ICancellationToken cancellationToken) { |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
127 return Promise.Success; |
203
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
128 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
129 |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
130 protected override IPromise OnStop() { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
131 m_timer.Change(-1, -1); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
132 |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
133 // the component is in the stopping state |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
134 lock (m_lock) { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
135 // after this lock no more pending operations could be created |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
136 var pending = m_pending; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
137 // m_pending could be fulfilled and set to null already |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
138 if (pending != null) { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
139 pending.Cancel(); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
140 return pending.Then(base.OnStop); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
141 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
142 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
143 |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
144 return base.OnStop(); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
145 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
146 |
208
7d07503621fe
RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool)
cin
parents:
205
diff
changeset
|
147 protected override void Dispose(bool disposing) { |
203
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
148 if (disposing) |
208
7d07503621fe
RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool)
cin
parents:
205
diff
changeset
|
149 m_timer.Dispose(); |
203
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
150 |
208
7d07503621fe
RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool)
cin
parents:
205
diff
changeset
|
151 base.Dispose(disposing); |
203
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
152 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
153 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
154 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
diff
changeset
|
155 |