193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair/* 293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * Copyright 2007 the original author or authors. 393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * 493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * Licensed under the Apache License, Version 2.0 (the "License"); 593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * you may not use this file except in compliance with the License. 693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * You may obtain a copy of the License at 793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * 893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * http://www.apache.org/licenses/LICENSE-2.0 993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * 1093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * Unless required by applicable law or agreed to in writing, software 1193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * distributed under the License is distributed on an "AS IS" BASIS, 1293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * See the License for the specific language governing permissions and 1493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * limitations under the License. 1593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair */ 1693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismairpackage org.mockftpserver.core.command; 1793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair 18dfa40a06dff44f29d8d5e1d3186055ad325fc7b9chrismairimport org.slf4j.Logger; 19dfa40a06dff44f29d8d5e1d3186055ad325fc7b9chrismairimport org.slf4j.LoggerFactory; 2093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismairimport org.easymock.MockControl; 2193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismairimport org.mockftpserver.core.session.Session; 2293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismairimport org.mockftpserver.core.util.AssertFailedException; 2340658190151b7ded3489ff89c301b470155c95f4chrismairimport org.mockftpserver.test.AbstractTestCase; 2493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair 25848932d9e7c6953b3c345c9aa6b0b6c3cfe20d79chrismairimport java.util.ListResourceBundle; 26848932d9e7c6953b3c345c9aa6b0b6c3cfe20d79chrismairimport java.util.ResourceBundle; 27848932d9e7c6953b3c345c9aa6b0b6c3cfe20d79chrismair 2893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair/** 29848932d9e7c6953b3c345c9aa6b0b6c3cfe20d79chrismair * Tests for the AbstractTrackingCommandHandler class. The class name is prefixed with an 30848932d9e7c6953b3c345c9aa6b0b6c3cfe20d79chrismair * underscore so that it is not filtered out by Maven's Surefire test plugin. 310da0f84ad9831bea470896e79b5ec207c83f258echrismair * 3293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * @author Chris Mair 330da0f84ad9831bea470896e79b5ec207c83f258echrismair * @version $Revision$ - $Date$ 3493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair */ 3540658190151b7ded3489ff89c301b470155c95f4chrismairpublic final class _AbstractTrackingCommandHandlerTest extends AbstractTestCase { 3693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair 37dfa40a06dff44f29d8d5e1d3186055ad325fc7b9chrismair private static final Logger LOG = LoggerFactory.getLogger(_AbstractTrackingCommandHandlerTest.class); 3893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair private static final String COMMAND_NAME = "abc"; 3993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair private static final Object ARG = "123"; 400da0f84ad9831bea470896e79b5ec207c83f258echrismair private static final Object[] ARGS = {ARG}; 4193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair private static final Command COMMAND = new Command(COMMAND_NAME, EMPTY); 4293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair private static final Command COMMAND_WITH_ARGS = new Command(COMMAND_NAME, EMPTY); 4393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair private static final int REPLY_CODE1 = 777; 4493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair private static final int REPLY_CODE2 = 888; 4593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair private static final int REPLY_CODE3 = 999; 4693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair private static final String REPLY_TEXT1 = "reply1 ... abcdef"; 4793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair private static final String REPLY_TEXT2 = "abc {0} def"; 4893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair private static final String REPLY_TEXT2_FORMATTED = "abc 123 def"; 4993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair private static final String OVERRIDE_REPLY_TEXT = "overridden reply ... abcdef"; 5093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair private static final String MESSAGE_KEY = "key.123"; 5193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair private static final String MESSAGE_TEXT = "message.123"; 520da0f84ad9831bea470896e79b5ec207c83f258echrismair 53848932d9e7c6953b3c345c9aa6b0b6c3cfe20d79chrismair private AbstractTrackingCommandHandler commandHandler; 5493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair private Session session; 550da0f84ad9831bea470896e79b5ec207c83f258echrismair 5693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair /** 5793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * Test the handleCommand(Command,Session) method 5893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair */ 5993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair public void testHandleCommand() throws Exception { 6093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair assertEquals("before", 0, commandHandler.numberOfInvocations()); 6193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.handleCommand(COMMAND, session); 6293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair assertEquals("after", 1, commandHandler.numberOfInvocations()); 6393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair assertTrue("locked", commandHandler.getInvocation(0).isLocked()); 6493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 6593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair 6693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair /** 6793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * Test the handleCommand(Command,Session) method, passing in a null Command 6893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair */ 6993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair public void testHandleCommand_NullCommand() throws Exception { 7093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair try { 7193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.handleCommand(null, session); 7293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair fail("Expected AssertFailedException"); 7393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 7493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair catch (AssertFailedException expected) { 7593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair LOG.info("Expected: " + expected); 7693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 7793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 780da0f84ad9831bea470896e79b5ec207c83f258echrismair 7993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair /** 8093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * Test the handleCommand(Command,Session) method, passing in a null Session 8193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair */ 8293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair public void testHandleCommand_NullSession() throws Exception { 8393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair try { 8493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.handleCommand(COMMAND, null); 8593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair fail("Expected AssertFailedException"); 8693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 8793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair catch (AssertFailedException expected) { 8893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair LOG.info("Expected: " + expected); 8993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 9093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 910da0f84ad9831bea470896e79b5ec207c83f258echrismair 9293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair /** 9393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * Test the numberOfInvocations(), addInvocationRecord() and clearInvocationRecord() methods 9493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair */ 9593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair public void testInvocationHistory() throws Exception { 9693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair control(session).expectAndDefaultReturn(session.getClientHost(), DEFAULT_HOST); 9793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair replay(session); 9893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair 9993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair assertEquals("none", 0, commandHandler.numberOfInvocations()); 10093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.handleCommand(COMMAND, session); 10193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair assertEquals("1", 1, commandHandler.numberOfInvocations()); 10293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.handleCommand(COMMAND, session); 10393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair assertEquals("2", 2, commandHandler.numberOfInvocations()); 10493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.clearInvocations(); 10593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair assertEquals("cleared", 0, commandHandler.numberOfInvocations()); 10693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 10793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair 10893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair /** 10993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * Test the getInvocation() method 1100da0f84ad9831bea470896e79b5ec207c83f258echrismair * 1110da0f84ad9831bea470896e79b5ec207c83f258echrismair * @throws Exception 11293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair */ 11393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair public void testGetInvocation() throws Exception { 11493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair control(session).expectAndDefaultReturn(session.getClientHost(), DEFAULT_HOST); 11593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair replay(session); 11693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair 11793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.handleCommand(COMMAND, session); 11893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.handleCommand(COMMAND_WITH_ARGS, session); 11993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair assertSame("1", COMMAND, commandHandler.getInvocation(0).getCommand()); 12093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair assertSame("2", COMMAND_WITH_ARGS, commandHandler.getInvocation(1).getCommand()); 12193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 12293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair 12393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair /** 12493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * Test the getInvocation() method, passing in an invalid index 12593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair */ 12693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair public void testGetInvocation_IndexOutOfBounds() throws Exception { 12793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.handleCommand(COMMAND, session); 12893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair try { 12993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.getInvocation(2); 13093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair fail("Expected IndexOutOfBoundsException"); 13193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 13293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair catch (IndexOutOfBoundsException expected) { 13393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair LOG.info("Expected: " + expected); 13493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 13593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 13693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair 13793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair /** 13893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * Test the sendReply() method, when no message arguments are specified 13993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair */ 14093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair public void testSendReply() { 14193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair session.sendReply(REPLY_CODE1, REPLY_TEXT1); 14293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair session.sendReply(REPLY_CODE1, MESSAGE_TEXT); 14393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair session.sendReply(REPLY_CODE1, OVERRIDE_REPLY_TEXT); 14493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair session.sendReply(REPLY_CODE3, null); 14593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair replay(session); 1460da0f84ad9831bea470896e79b5ec207c83f258echrismair 14793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.sendReply(session, REPLY_CODE1, null, null, null); 14893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.sendReply(session, REPLY_CODE1, MESSAGE_KEY, null, null); 14993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.sendReply(session, REPLY_CODE1, MESSAGE_KEY, OVERRIDE_REPLY_TEXT, null); 15093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.sendReply(session, REPLY_CODE3, null, null, null); 1510da0f84ad9831bea470896e79b5ec207c83f258echrismair 15293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair verify(session); 15393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 1540da0f84ad9831bea470896e79b5ec207c83f258echrismair 15593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair /** 1560da0f84ad9831bea470896e79b5ec207c83f258echrismair * Test the sendReply() method, passing in message arguments 15793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair */ 15893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair public void testSendReply_WithMessageArguments() { 15993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair session.sendReply(REPLY_CODE1, REPLY_TEXT2_FORMATTED); 16093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair replay(session); 1610da0f84ad9831bea470896e79b5ec207c83f258echrismair 16293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.sendReply(session, REPLY_CODE1, null, REPLY_TEXT2, ARGS); 1630da0f84ad9831bea470896e79b5ec207c83f258echrismair 16493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair verify(session); 16593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 1660da0f84ad9831bea470896e79b5ec207c83f258echrismair 16793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair /** 1680da0f84ad9831bea470896e79b5ec207c83f258echrismair * Test the sendReply() method, passing in a null Session 16993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair */ 17093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair public void testSendReply_NullSession() { 17193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair try { 17293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.sendReply(null, REPLY_CODE1, REPLY_TEXT1, null, null); 17393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair fail("Expected AssertFailedException"); 17493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 17593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair catch (AssertFailedException expected) { 17693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair LOG.info("Expected: " + expected); 17793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 17893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 17993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair 18093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair /** 1810da0f84ad9831bea470896e79b5ec207c83f258echrismair * Test the sendReply() method, passing in an invalid replyCode 18293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair */ 18393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair public void testSendReply_InvalidReplyCode() { 18493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair try { 18593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.sendReply(session, 0, REPLY_TEXT1, null, null); 18693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair fail("Expected AssertFailedException"); 18793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 18893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair catch (AssertFailedException expected) { 18993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair LOG.info("Expected: " + expected); 19093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 19193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 19293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair 19393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair //------------------------------------------------------------------------- 19493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair // Test setup 19593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair //------------------------------------------------------------------------- 1960da0f84ad9831bea470896e79b5ec207c83f258echrismair 19793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair /** 19893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * Perform initialization before each test 1990da0f84ad9831bea470896e79b5ec207c83f258echrismair * 20040658190151b7ded3489ff89c301b470155c95f4chrismair * @see org.mockftpserver.test.AbstractTestCase#setUp() 20193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair */ 20293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair protected void setUp() throws Exception { 20393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair super.setUp(); 20493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair session = (Session) createMock(Session.class); 20593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair control(session).setDefaultMatcher(MockControl.ARRAY_MATCHER); 206848932d9e7c6953b3c345c9aa6b0b6c3cfe20d79chrismair commandHandler = new AbstractTrackingCommandHandler() { 20793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair public void handleCommand(Command command, Session session, InvocationRecord invocationRecord) throws Exception { 2080da0f84ad9831bea470896e79b5ec207c83f258echrismair } 20993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair }; 2100da0f84ad9831bea470896e79b5ec207c83f258echrismair ResourceBundle replyTextBundle = new ListResourceBundle() { 21193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair protected Object[][] getContents() { 2120da0f84ad9831bea470896e79b5ec207c83f258echrismair return new Object[][]{ 2130da0f84ad9831bea470896e79b5ec207c83f258echrismair {Integer.toString(REPLY_CODE1), REPLY_TEXT1}, 2140da0f84ad9831bea470896e79b5ec207c83f258echrismair {Integer.toString(REPLY_CODE2), REPLY_TEXT2}, 2150da0f84ad9831bea470896e79b5ec207c83f258echrismair {MESSAGE_KEY, MESSAGE_TEXT} 21693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair }; 21793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 21893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair }; 21993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair commandHandler.setReplyTextBundle(replyTextBundle); 22093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair } 2210da0f84ad9831bea470896e79b5ec207c83f258echrismair 22293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair} 223