File Source: ProcessMode.java
/*
P/P * Method: com.dmdirc.parser.irc.ProcessMode__static_init
*/
1 /*
2 * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 package com.dmdirc.parser.irc;
24
25 import com.dmdirc.parser.irc.callbacks.CallbackObject;
26 import java.util.Calendar;
27
28 /**
29 * Process a Mode line.
30 */
31 public class ProcessMode extends IRCProcessor {
32 /**
33 * Process a Mode Line.
34 *
35 * @param sParam Type of line to process ("MODE", "324")
36 * @param token IRCTokenised line to process
37 */
38 @Override
39 public void process(String sParam, String[] token) {
40 String[] sModestr;
41 String sChannelName;
/*
P/P * Method: void process(String, String[])
*
* Preconditions:
* sParam != null
* token != null
* (soft) this.myParser.nNextKeyUser in {-4_611_686_018_427_387_904..263-1}
* (soft) init'ed(this.myParser.stringConverter)
* (soft) this.myParser != null
* (soft) this.myParser.cMyself != null
* (soft) init'ed(this.myParser.cMyself.bIsFake)
* (soft) init'ed(this.myParser.cMyself.sNickname)
* (soft) this.myParser.hChanPrefix != null
* (soft) this.myParser.hChannelList != null
* ...
*
* Presumptions:
* this.myParser.stringConverter.lowercase != null
*
* Postconditions:
* this.myParser.nNextKeyCMBool == old this.myParser.nNextKeyCMBool
* this.myParser.nNextKeyUser <= 264-2
* init'ed(this.myParser.stringConverter)
* new IRCStringConverter(getIRCStringConverter#1) num objects == undefined
* new IRCStringConverter(getIRCStringConverter#1) num objects == 0, if init'ed
* new IRCStringConverter(getIRCStringConverter#1).limit == new IRCStringConverter(getIRCStringConverter#1) num objects
* new char[](IRCStringConverter#1) num objects == new IRCStringConverter(getIRCStringConverter#1) num objects
* new char[](IRCStringConverter#1).length == new IRCStringConverter(getIRCStringConverter#1) num objects
* new char[](IRCStringConverter#1)[...] == new IRCStringConverter(getIRCStringConverter#1) num objects
* new char[](IRCStringConverter#2) num objects == new IRCStringConverter(getIRCStringConverter#1) num objects
* ...
*
* Test Vectors:
* java.lang.String:equals(...)@42: {0}, {1}
* java.lang.String:equals(...)@46: {0}, {1}
*/
42 if (sParam.equals("324")) {
43 sChannelName = token[3];
44 sModestr = new String[token.length-4];
45 System.arraycopy(token, 4, sModestr, 0, token.length-4);
46 } else if (sParam.equals("221")) {
47 processUserMode(sParam, token, new String[]{token[token.length-1]}, true);
48 return;
49 } else {
50 sChannelName = token[2];
51 sModestr = new String[token.length-3];
52 System.arraycopy(token, 3, sModestr, 0, token.length-3);
53 }
54
55 if (!isValidChannelName(sChannelName)) { processUserMode(sParam, token, sModestr, false); }
56 else { processChanMode(sParam, token, sModestr, sChannelName); }
57 }
58
59 /**
60 * Method to trim spaces from strings
61 *
62 * @param str String to trim
63 * @return String without spaces on the ends
64 */
/*
P/P * Method: String trim(String)
*
* Preconditions:
* str != null
*
* Postconditions:
* return_value != null
*/
65 private String trim(String str) { return str.trim(); }
66
67 /**
68 * Process Chan modes.
69 *
70 * @param sParam String representation of parameter to parse
71 * @param token IRCTokenised Array of the incomming line
72 * @param sModestr The modes and params
73 * @param sChannelName Channel these modes are for
74 */
75 public void processChanMode(String sParam, String token[], String sModestr[], String sChannelName) {
/*
P/P * Method: void processChanMode(String, String[], String[], String)
*
* Preconditions:
* sChannelName != null
* sParam != null
* this.myParser.hChannelList != null
* (soft) this.myParser.nNextKeyCMBool in {-4_611_686_018_427_387_904..263-1}
* (soft) init'ed(this.myParser.stringConverter)
* (soft) sModestr != null
* (soft) sModestr.length in {1..232-1}
* (soft) sModestr[0] != null
* (soft) sModestr[...] != null
* (soft) this.myParser != null
* ...
*
* Presumptions:
* getClient(...).sHost@108 != null
* iChannel.hChannelUserList != null
* iChannel.hListModes != null
* iChannel.hParamModes != null
* iChannel.myParser != null
* ...
*
* Postconditions:
* this.myParser.nNextKeyCMBool <= 264-2
* init'ed(this.myParser.stringConverter)
* new IRCStringConverter(getIRCStringConverter#1) num objects == 0
* init'ed(new IRCStringConverter(getIRCStringConverter#1) num objects)
* new IRCStringConverter(getIRCStringConverter#1) num objects <= 1
* new char[](IRCStringConverter#1) num objects == new IRCStringConverter(getIRCStringConverter#1) num objects
* new char[](IRCStringConverter#2) num objects == new IRCStringConverter(getIRCStringConverter#1) num objects
* init'ed(new IRCStringConverter(getIRCStringConverter#1).limit)
* new IRCStringConverter(getIRCStringConverter#1).limit == 4
* init'ed(new IRCStringConverter(getIRCStringConverter#1).lowercase)
* ...
*
* Test Vectors:
* sModestr.length: {2..232-1}, {1}
* java.lang.Byte:byteValue(...)@124: {1}, {-128..-1, 4..255}
* java.lang.Character:equals(...)@120: {0}, {1}
* java.lang.Character:equals(...)@121: {0}, {1}
* java.lang.String:equals(...)@106: {1}, {0}
* java.lang.String:equals(...)@209: {0}, {1}
* java.lang.String:equals(...)@93: {1}, {0}
* java.lang.String:isEmpty(...)@111: {0}, {1}
* java.lang.String:length(...)@115: {232-2}, {0}
* java.lang.String:length(...)@115 - sModestr.length: {-232+2..-1}, {232-3}
* ...
*/
76 StringBuilder sFullModeStr = new StringBuilder();
77 String sNonUserModeStr = "";
78 String sNonUserModeStrParams = "";
79 String sModeParam;
80 String sTemp;
81 int nParam = 1;
82 long nTemp = 0, nValue = 0, nCurrent = 0;
83 boolean bPositive = true, bBooleanMode = true;
84 char cPositive = '+';
85 ChannelInfo iChannel;
86 ChannelClientInfo iChannelClientInfo;
87 ClientInfo iClient;
88 ChannelClientInfo setterCCI;
89
90 CallbackObject cbSingle = null;
91 CallbackObject cbNonUser = null;
92
93 if (!sParam.equals("324")) {
94 cbSingle = getCallbackManager().getCallbackType("OnChannelSingleModeChanged");
95 cbNonUser = getCallbackManager().getCallbackType("OnChannelNonUserModeChanged");
96 }
97
98 iChannel = getChannelInfo(sChannelName);
99 if (iChannel == null) {
100 // callErrorInfo(new ParserError(ParserError.ERROR_WARNING, "Got modes for channel ("+sChannelName+") that I am not on.", myParser.getLastLine()));
101 // iChannel = new ChannelInfo(myParser, sChannelName);
102 // myParser.addChannel(iChannel);
103 return;
104 }
105 // Get the current channel modes
106 if (!sParam.equals("324")) { nCurrent = iChannel.getMode(); }
107
108 setterCCI = iChannel.getUser(token[0]);
109 if (IRCParser.ALWAYS_UPDATECLIENT && setterCCI != null) {
110 // Facilitate dmdirc formatter
111 if (setterCCI.getClient().getHost().isEmpty()) {setterCCI.getClient().setUserBits(token[0],false); }
112 }
113
114 // Loop through the mode string, and add/remove modes/params where they are needed
115 for (int i = 0; i < sModestr[0].length(); ++i) {
116 Character cMode = sModestr[0].charAt(i);
117 if (cMode.equals(":".charAt(0))) { continue; }
118
119 sNonUserModeStr = sNonUserModeStr+cMode;
120 if (cMode.equals("+".charAt(0))) { cPositive = '+'; bPositive = true; }
121 else if (cMode.equals("-".charAt(0))) { cPositive = '-'; bPositive = false; }
122 else {
123 if (myParser.hChanModesBool.containsKey(cMode)) { nValue = myParser.hChanModesBool.get(cMode); bBooleanMode = true; }
124 else if (myParser.hChanModesOther.containsKey(cMode)) { nValue = myParser.hChanModesOther.get(cMode); bBooleanMode = false; }
125 else if (myParser.hPrefixModes.containsKey(cMode)) {
126 // (de) OP/Voice someone
127 if (sModestr.length <= nParam) {
128 myParser.callErrorInfo(new ParserError(ParserError.ERROR_FATAL + ParserError.ERROR_USER, "Broken Modes. Parameter required but not given.", myParser.getLastLine()));
129 }
130 sModeParam = sModestr[nParam++];
131 nValue = myParser.hPrefixModes.get(cMode);
132 callDebugInfo(IRCParser.DEBUG_INFO, "User Mode: %c / %d [%s] {Positive: %b}",cMode, nValue, sModeParam, bPositive);
133 iChannelClientInfo = iChannel.getUser(sModeParam);
134 if (iChannelClientInfo == null) {
135 // Client not known?
136 // callErrorInfo(new ParserError(ParserError.ERROR_WARNING, "Got mode for client not known on channel - Added", myParser.getLastLine()));
137 iClient = getClientInfo(sModeParam);
138 if (iClient == null) {
139 // callErrorInfo(new ParserError(ParserError.ERROR_WARNING, "Got mode for client not known at all - Added", myParser.getLastLine()));
140 iClient = new ClientInfo(myParser, sModeParam);
141 myParser.addClient(iClient);
142 }
143 iChannelClientInfo = iChannel.addClient(iClient);
144 }
145 callDebugInfo(IRCParser.DEBUG_INFO, "\tOld Mode Value: %d",iChannelClientInfo.getChanMode());
146 if (bPositive) { iChannelClientInfo.setChanMode(iChannelClientInfo.getChanMode() | nValue); sTemp = "+"; }
147 else { iChannelClientInfo.setChanMode(iChannelClientInfo.getChanMode() ^ (iChannelClientInfo.getChanMode() & nValue)); sTemp = "-"; }
148 sTemp = sTemp+cMode;
149 callChannelUserModeChanged(iChannel, iChannelClientInfo, setterCCI, token[0], sTemp);
150 continue;
151 } else {
152 // unknown mode - add as boolean
153 // callErrorInfo(new ParserError(ParserError.ERROR_WARNING, "Got unknown mode "+cMode+" - Added as boolean mode", myParser.getLastLine()));
154 myParser.hChanModesBool.put(cMode,myParser.nNextKeyCMBool);
155 nValue = myParser.nNextKeyCMBool;
156 bBooleanMode = true;
157 myParser.nNextKeyCMBool = myParser.nNextKeyCMBool*2;
158 }
159
160 if (bBooleanMode) {
161 callDebugInfo(IRCParser.DEBUG_INFO, "Boolean Mode: %c [%d] {Positive: %b}",cMode, nValue, bPositive);
162
163 if (bPositive) { nCurrent = nCurrent | nValue; }
164 else { nCurrent = nCurrent ^ (nCurrent & nValue); }
165 } else {
166
167 if ((bPositive || nValue == IRCParser.MODE_LIST || ((nValue & IRCParser.MODE_UNSET) == IRCParser.MODE_UNSET)) && (sModestr.length <= nParam)) {
168 myParser.callErrorInfo(new ParserError(ParserError.ERROR_FATAL + ParserError.ERROR_USER, "Broken Modes. Parameter required but not given.", myParser.getLastLine()));
169 }
170
171 if (nValue == IRCParser.MODE_LIST) {
172 // List Mode
173 sModeParam = sModestr[nParam++];
174 sNonUserModeStrParams = sNonUserModeStrParams+" "+sModeParam;
175 nTemp = (Calendar.getInstance().getTimeInMillis() / 1000);
176 iChannel.setListModeParam(cMode, new ChannelListModeItem(sModeParam, token[0], nTemp ), bPositive);
177 callDebugInfo(IRCParser.DEBUG_INFO, "List Mode: %c [%s] {Positive: %b}",cMode, sModeParam, bPositive);
178 if (cbSingle != null) { cbSingle.call(iChannel, setterCCI, token[0], cPositive+cMode+" "+sModeParam ); }
179 } else {
180 // Mode with a parameter
181 if (bPositive) {
182 // +Mode - always needs a parameter to set
183 sModeParam = sModestr[nParam++];
184 sNonUserModeStrParams = sNonUserModeStrParams+" "+sModeParam;
185 callDebugInfo(IRCParser.DEBUG_INFO, "Set Mode: %c [%s] {Positive: %b}",cMode, sModeParam, bPositive);
186 iChannel.setModeParam(cMode,sModeParam);
187 if (cbSingle != null) { cbSingle.call(iChannel, setterCCI, token[0], cPositive+cMode+" "+sModeParam ); }
188 } else {
189 // -Mode - parameter isn't always needed, we need to check
190 if ((nValue & IRCParser.MODE_UNSET) == IRCParser.MODE_UNSET) {
191 sModeParam = sModestr[nParam++];
192 sNonUserModeStrParams = sNonUserModeStrParams+" "+sModeParam;
193 } else {
194 sModeParam = "";
195 }
196 callDebugInfo(IRCParser.DEBUG_INFO, "Unset Mode: %c [%s] {Positive: %b}",cMode, sModeParam, bPositive);
197 iChannel.setModeParam(cMode,"");
198 if (cbSingle != null) { cbSingle.call(iChannel, setterCCI, token[0], trim(cPositive+cMode+" "+sModeParam) ); }
199 }
200 }
201 }
202 }
203 }
204
205 // Call Callbacks
206 for (int i = 0; i < sModestr.length; ++i) { sFullModeStr.append(sModestr[i]).append(" "); }
207
208 iChannel.setMode(nCurrent);
209 if (sParam.equals("324")) { callChannelModeChanged(iChannel, null, "", sFullModeStr.toString().trim()); }
210 else { callChannelModeChanged(iChannel, setterCCI, token[0], sFullModeStr.toString().trim()); }
211 if (cbNonUser != null) { cbNonUser.call(iChannel, setterCCI, token[0], trim(sNonUserModeStr+sNonUserModeStrParams)); }
212 }
213
214 /**
215 * Process user modes.
216 *
217 * @param sParam String representation of parameter to parse
218 * @param token IRCTokenised Array of the incomming line
219 * @param clearOldModes Clear old modes before applying these modes (used by 221)
220 */
221 private void processUserMode(String sParam, String token[], String sModestr[], boolean clearOldModes) {
/*
P/P * Method: void processUserMode(String, String[], String[], bool)
*
* Preconditions:
* init'ed(this.myParser.stringConverter)
* this.myParser.hClientList != null
* token != null
* token.length >= 3
* token[2] != null
* (soft) this.myParser.nNextKeyUser in {-4_611_686_018_427_387_904..263-1}
* (soft) sModestr != null
* (soft) sModestr.length >= 1
* (soft) sModestr[0] != null
* (soft) sParam != null
* ...
*
* Presumptions:
* java.lang.Character:valueOf(...)@237 != null
* java.util.Map:get(...)@242 != null
*
* Postconditions:
* this.myParser.nNextKeyUser <= 264-2
* this.myParser.stringConverter == One-of{old this.myParser.stringConverter, &new IRCStringConverter(getIRCStringConverter#1)}
* this.myParser.stringConverter != null
* new IRCStringConverter(getIRCStringConverter#1) num objects <= 1
* new char[](IRCStringConverter#1) num objects == new IRCStringConverter(getIRCStringConverter#1) num objects
* new char[](IRCStringConverter#2) num objects == new IRCStringConverter(getIRCStringConverter#1) num objects
* new IRCStringConverter(getIRCStringConverter#1).limit == 4
* new IRCStringConverter(getIRCStringConverter#1).lowercase == &new char[](IRCStringConverter#1)
* new IRCStringConverter(getIRCStringConverter#1).uppercase == &new char[](IRCStringConverter#2)
* new char[](IRCStringConverter#1).length == 127
* ...
*
* Test Vectors:
* clearOldModes: {0}, {1}
* java.lang.Character:equals(...)@238: {0}, {1}
* java.lang.Character:equals(...)@239: {0}, {1}
* java.lang.String:equals(...)@258: {0}, {1}
* java.util.Map:containsKey(...)@242: {0}, {1}
*/
222 long nCurrent = 0, nValue = 0;
223 boolean bPositive = true;
224
225 ClientInfo iClient;
226
227 iClient = getClientInfo(token[2]);
228 if (iClient == null) { return; }
229
230 if (clearOldModes) {
231 nCurrent = 0;
232 } else {
233 nCurrent = iClient.getUserMode();
234 }
235
236 for (int i = 0; i < sModestr[0].length(); ++i) {
237 Character cMode = sModestr[0].charAt(i);
238 if (cMode.equals("+".charAt(0))) { bPositive = true; }
239 else if (cMode.equals("-".charAt(0))) { bPositive = false; }
240 else if (cMode.equals(":".charAt(0))) { continue; }
241 else {
242 if (myParser.hUserModes.containsKey(cMode)) { nValue = myParser.hUserModes.get(cMode); }
243 else {
244 // Unknown mode
245 callErrorInfo(new ParserError(ParserError.ERROR_WARNING, "Got unknown user mode "+cMode+" - Added", myParser.getLastLine()));
246 myParser.hUserModes.put(cMode,myParser.nNextKeyUser);
247 nValue = myParser.nNextKeyUser;
248 myParser.nNextKeyUser = myParser.nNextKeyUser*2;
249 }
250 // Usermodes are always boolean
251 callDebugInfo(IRCParser.DEBUG_INFO, "User Mode: %c [%d] {Positive: %b}",cMode, nValue, bPositive);
252 if (bPositive) { nCurrent = nCurrent | nValue; }
253 else { nCurrent = nCurrent ^ (nCurrent & nValue); }
254 }
255 }
256
257 iClient.setUserMode(nCurrent);
258 if (sParam.equals("221")) {
259 callUserModeDiscovered(iClient, sModestr[0]);
260 } else {
261 callUserModeChanged(iClient, token[0], sModestr[0]);
262 }
263 }
264
265 /**
266 * Callback to all objects implementing the ChannelModeChanged Callback.
267 *
268 * @see IChannelModeChanged
269 * @param cChannel Channel where modes were changed
270 * @param cChannelClient Client chaning the modes (null if server)
271 * @param sHost Host doing the mode changing (User host or server name)
272 * @param sModes Exact String parsed
273 * @return true if a method was called, false otherwise
274 */
275 protected boolean callChannelModeChanged(ChannelInfo cChannel, ChannelClientInfo cChannelClient, String sHost, String sModes) {
/*
P/P * Method: bool callChannelModeChanged(ChannelInfo, ChannelClientInfo, String, String)
*
* Preconditions:
* this.myParser != null
* this.myParser.myCallbackManager != null
* this.myParser.myCallbackManager.callbackHash != null
*
* Presumptions:
* getCallbackManager(...)@276 init'ed
*
* Postconditions:
* init'ed(return_value)
*/
276 return getCallbackManager().getCallbackType("OnChannelModeChanged").call(cChannel, cChannelClient, sHost, sModes);
277 }
278
279 /**
280 * Callback to all objects implementing the ChannelUserModeChanged Callback.
281 *
282 * @see IChannelUserModeChanged
283 * @param cChannel Channel where modes were changed
284 * @param cChangedClient Client being changed
285 * @param cSetByClient Client chaning the modes (null if server)
286 * @param sMode String representing mode change (ie +o)
287 * @param sHost Host doing the mode changing (User host or server name)
288 * @return true if a method was called, false otherwise
289 */
290 protected boolean callChannelUserModeChanged(ChannelInfo cChannel, ChannelClientInfo cChangedClient, ChannelClientInfo cSetByClient, String sHost, String sMode) {
/*
P/P * Method: bool callChannelUserModeChanged(ChannelInfo, ChannelClientInfo, ChannelClientInfo, String, String)
*
* Preconditions:
* this.myParser != null
* this.myParser.myCallbackManager != null
* this.myParser.myCallbackManager.callbackHash != null
*
* Presumptions:
* getCallbackManager(...)@291 init'ed
*
* Postconditions:
* init'ed(return_value)
*/
291 return getCallbackManager().getCallbackType("OnChannelUserModeChanged").call(cChannel, cChangedClient, cSetByClient, sHost, sMode);
292 }
293
294 /**
295 * Callback to all objects implementing the UserModeChanged Callback.
296 *
297 * @see IUserModeChanged
298 * @param cClient Client that had the mode changed (almost always us)
299 * @param sSetby Host that set the mode (us or servername)
300 * @param sModes The modes set.
301 * @return true if a method was called, false otherwise
302 */
303 protected boolean callUserModeChanged(ClientInfo cClient, String sSetby, String sModes) {
/*
P/P * Method: bool callUserModeChanged(ClientInfo, String, String)
*
* Preconditions:
* this.myParser != null
* this.myParser.myCallbackManager != null
* this.myParser.myCallbackManager.callbackHash != null
*
* Presumptions:
* getCallbackManager(...)@304 init'ed
*
* Postconditions:
* init'ed(return_value)
*/
304 return getCallbackManager().getCallbackType("OnUserModeChanged").call(cClient, sSetby, sModes);
305 }
306
307 /**
308 * Callback to all objects implementing the UserModeDiscovered Callback.
309 *
310 * @see IUserModeDiscovered
311 * @param cClient Client that had the mode changed (almost always us)
312 * @param sModes The modes set.
313 * @return true if a method was called, false otherwise
314 */
315 protected boolean callUserModeDiscovered(ClientInfo cClient, String sModes) {
/*
P/P * Method: bool callUserModeDiscovered(ClientInfo, String)
*
* Preconditions:
* this.myParser != null
* this.myParser.myCallbackManager != null
* this.myParser.myCallbackManager.callbackHash != null
*
* Presumptions:
* getCallbackManager(...)@316 init'ed
*
* Postconditions:
* init'ed(return_value)
*/
316 return getCallbackManager().getCallbackType("OnUserModeDiscovered").call(cClient, sModes);
317 }
318
319 /**
320 * What does this IRCProcessor handle.
321 *
322 * @return String[] with the names of the tokens we handle.
323 */
324 @Override
325 public String[] handles() {
/*
P/P * Method: String[] handles()
*
* Postconditions:
* return_value == &new String[](handles#1)
* new String[](handles#1) num objects == 1
* return_value.length == 3
* return_value[0] == &"MODE"
* return_value[1] == &"324"
* return_value[2] == &"221"
*/
326 return new String[]{"MODE", "324", "221"};
327 }
328
329 /**
330 * Create a new instance of the IRCProcessor Object.
331 *
332 * @param parser IRCParser That owns this IRCProcessor
333 * @param manager ProcessingManager that is in charge of this IRCProcessor
334 */
/*
P/P * Method: void com.dmdirc.parser.irc.ProcessMode(IRCParser, ProcessingManager)
*
* Postconditions:
* this.myManager == manager
* init'ed(this.myManager)
* this.myParser == parser
* init'ed(this.myParser)
*/
335 protected ProcessMode (IRCParser parser, ProcessingManager manager) { super(parser, manager); }
336
337 }
SofCheck Inspector Build Version : 2.17854
| ProcessMode.java |
2009-Jun-25 01:54:24 |
| ProcessMode.class |
2009-Sep-02 17:04:16 |