Interfacing with IBM WebSphere MQ (formally IBM MQSeries) from .NET





5.00/5 (15 votes)
May 4, 2006
20 min read

327405
This article is targeting architects and developers who are looking for a way to integrate .NET applications / Servers with IBM WebSphere MQ (IBM MQSeries).
1. Who should read this article?
This article is targeting architects and developers who are looking for a way to integrate .NET applications / Servers with IBM WebSphere MQ (IBM MQSeries).
2. What to read?
This article is designed to provide a basic understanding of messaging from IBM perspective through the explanation of some basic functionalities of WebSphere MQ. The document is divided into three main parts:
a. Introduction to messaging: this is covered in sections 3 - 4.5. You can skip this part if you have a past experience with MSMQ.
b. Interacting with WebSphere MQ: this is covered in sections 4.6 - 8, and will provide you with sufficient knowledge that will allow you to interact with WebSphere MQ (IBM MQSeries).
c. Appendixes: this is covered in section 9, and to be used as a reference for part two.
3. Introduction:
Message queuing has been used in data processing for many years. It is most commonly used today in electronic mail. Without queuing, sending an electronic message over long distances requires every node on the route to be available for forwarding messages, and aware of the fact that you are trying to send them a message. In a queuing system, messages are stored at intermediate nodes until the system is ready to forward them or process them.
Even so, many complex business transactions are processed today without queuing. If this is the case; then why do we need queuing? Think about a system consisting of multiple nodes, where those nodes need to communicate with each other. If one node of the system suffers a problem, many nodes could become unusable.
In a message queuing environment, each program from the set that makes up the system is designed to perform a well-defined, self-contained function in response to a specific request. To communicate with another program, a program must put a message on a predefined queue. The other program retrieves the message from the queue, and processes the message. So message queuing is a style of program-to-program communication.
Queuing is the mechanism by which messages are held until an application is ready to process them. Queuing allows you to:
- Communicate between programs (which may each be running in different environments) without having to write the communication code.
- Select the order in which a program processes messages.
- Balance loads on a system by arranging for more than one program to service a queue when the number of messages exceeds a threshold.
- Increase the availability of your applications by arranging for an alternative system to service the queues if your primary system is unavailable.
4. Messaging
4.1. What is a message?
In message queuing, a message is simply a collection of data sent by one program and intended for another program. WebSphere MQ primarily defines four types of message:
- Datagram: A simple message for which no reply is expected
- Request: A message for which a reply is expected
- Reply: A reply to a request message
- Report: A message that describes an event such as the occurrence of an error.
In this article will be talking about type 2 and 3 of messages. Type 1 and 4 are out of scope.
4.2. Message descriptor
A message consists of control information and application data. The control information is defined in a message descriptor structure (MQMD) and contains things like:
- The type of the message
- An identifier for the message
- The priority for delivery of the message
The structure and content of the application data is determined by the participating programs, not by WebSphere MQ.
4.3. What is a message queue?
A message queue, referred to as a queue, is a named destination to which messages can be sent. Messages accumulate on queues until they are retrieved by programs that service those queues. Queues reside in, and are managed by, a queue manager. A queue can either be a volatile buffer area in the memory of a computer, or a data set on a permanent storage device, such as a disk. The physical management of queues is the responsibility of the queue manager and is not made apparent to the participating application programs.
Programs access queues only through queue manager. They can open a queue, put messages, get messages, and they can close the queue. They can also set, and inquire about, the attributes of queues.
4.4. What is a queue manager?
A queue manager is a system program that provides queuing services to applications. It exposes an API that would allow programs to put, and get messages from queues. A queue manager provides additional functions that would provide administrators with the ability to create new queues, alter the properties of existing ones, and control the operation of the queue manager.
For the queuing services to be available on a system; there must be a queue manager running On OS/400, z/OS, OS/2, Windows systems, UNIX, or some other supported operating system. You can have more than one queue manager running on a single system (for example, to separate the testing environment from the production one). To an application, each queue manager is identified by a connection handle (Hconn).
Many different applications can make use of the queue manager’s services at the same time and these applications can be entirely unrelated. For a program to use the services of a queue manager, it must establish a connection to that queue manager. For applications to be able to send messages to applications that are connected to other queue managers, queue managers must be able to communicate among themselves. WebSphere achieved this by implementing a store-and-forward protocol to ensure the safe delivery of messages between such applications.
4.5. Messages
There are four types of message defined by WebSphere MQ:
· Datagram
· Request
· Reply
· Report
Applications can use the first three types of messages to pass information between themselves. The fourth type, report, is for applications and queue managers to report information about events such as the occurrence of an error.
4.1.1. Datagrams
You should use a datagram when you do not require a reply from the application that receives the message. An example of an application that could use datagrams is one that displays flight information on the airport screens periodically.
4.1.2. Request messages
You should use a request message when you expect a reply from the application that receives the message. An example of an application that could use request messages is one that displays the balance of an account. The request message could contain the number of the account, and the reply message would contain the account balance. If you want to link your reply message with your request message, there are two options:
- You can give the application that handles the request message the responsibility of ensuring that it puts information into the reply message that relates to the request message.
- You can use the report field in the message descriptor of your request message to specify the content of the MsgId and CorrelId fields of the reply message:
- You can request that either the MsgId or the CorrelId of the original message is to be copied into the CorrelId field of the reply message (the default action is to copy MsgId).
- You can request that either a new MsgId is generated for the reply message, or that the MsgId of the original message is to be copied into the MsgId field of the reply message (the default action is to generate a new message identifier).
4.1.3. Reply messages
You should use a reply message when you reply to another message. When you create a reply message, you should respect any options that were set in the message descriptor of the message to which you are replying. Report options specify the content of the message identifier (MsgId) and correlation identifier (CorrelId) fields. These fields allow the application that receives the reply to correlate the reply with its original request.
4.1.4. Report messages
Report messages inform applications about events such as the occurrence of an error when processing a message. They can be generated by:
- A queue manager,
- A message channel agent (for example, if they cannot deliver the message), or
- An application (for example, if it cannot use the data in the message).
Note that report messages can be generated at any time, and they may arrive on a queue when your application is not expecting them.
4.1.5. Correlating replies
In WebSphere MQ applications, when a program receives a message that asks it to do some work, the program usually sends one or more reply messages to the requester. To help the requester to associate these replies with its original request, an application can set a correlation identifier field in the descriptor of each message. Programs should copy the message identifier of the request message into the correlation identifier field of their reply messages.
4.6. Channels
A channel is a communication link used by queue managers. There are two categories of channel in WebSphere MQ, and we can describe them as control channels and data channels:
Message channels, which are unidirectional, and transfer messages from one queue manager to another.
Message Queue Interface (MQI) channels, which are bidirectional, and transfer control calls from a WebSphere MQ client to a queue manager, and responses from a queue manager to a WebSphere MQ client. We will not spend more time on this part since it is out of the scope of this article.
5. WebSphere MQ Object Model:
The WebSphere MQ Object Model consists of the following:
- Classes representing MQ concepts such as queue managers, queues, and messages.
- Methods on each class corresponding to MQI calls.
- Properties on each class corresponding to attributes of MQ objects.
And provides the following set of classes:
Class Name |
Description |
|
An object of the |
|
An object of the |
|
An object of the |
|
An object of the |
|
An object of the |
6. WebSphere MQ client:
A WebSphere MQ client is part of the WebSphere MQ product that can be installed on a separate machine from the base product and server and acts as a proxy between that machine and the server. You can run a WebSphere MQ application on a WebSphere MQ client and it can interact with one or more WebSphere MQ servers and connect to their queue managers by means of a communications protocol.
The MQI is available to applications running on the client platform; the queues and other WebSphere MQ objects are held on a queue manager that you have installed on a server machine. An application that you want to run in the WebSphere MQ client environment must first be linked with the relevant client library. When the application issues an MQI call, the WebSphere MQ client directs the request to a queue manager, where it is processed and from where a reply is sent back to the WebSphere MQ client.
6.1. How the client connects to the server
An application running in the WebSphere MQ client environment runs in synchronous mode because there must be an active connection between the client and the server machines. The connection is made by an application issuing an MQCONN or MQCONNX calls. Clients and servers communicate through MQI channels. When the call succeeds, the MQI channel remains connected until the application issues a MQDISC call. This is the case for every queue manager that an application needs to connect to.
6.2. Why use WebSphere MQ clients?
Using WebSphere MQ clients is an efficient way of implementing WebSphere MQ messaging and queuing.
You can have an application that uses the MQI running on one machine and the queue manager running on a different machine. The benefits of doing this are:
- There is no need for a full WebSphere MQ implementation on the client machine; for example, it could be a DOS, Windows 3.1, Windows 95, Windows 98, Windows XP, Windows 2k, or Windows 2k3 system.
- Hardware requirements on the client system are reduced.
- System administration requirements are reduced.
- A WebSphere MQ application running on a client can connect to multiple queue managers on different systems.
7. We saw the players, so let’s start the game:
Before you become able to send and receive messages to and from MQSeries; you need to install a set of applications and do some simple configurations. You need to install:
- .NET Framework (v1.1.4322 or later).
- WebSphere MQ client V 5.2 or above.
- WebSphere MQ classes for Microsoft .NET.
After installing the software you need to go and configure the MQ client. There are multiple ways of performing the configurations; the easiest and most straight forward one is by adding a system wide environment variable called MQSERVER
and assigning to it the channel name, protocol used, server address and port in the following format:
MQSERVER=ChannelName/Protocol/server_address(port)
For example:
MQSERVER=GI_HUB_SVCON/TCP/172.21.106.14(1414).
To perform this on windows-XP right-click on my computer and select properties, then click over the Advanced tab.
Then click on the Environment Variables button.
Under system variables, click on the New button; a screen will popup asking you to provide the variable name and its value.
Then click over the OK button. Remember to restart the machine or the system will not be able to catch the variable you’ve just added.
Below you will find a ready-to-use class with comments showing you how to drop and receive messages from WebSphere MQ. All what you have to do is to add a reference to IBM.WMQ namespace which exists in amqmdnet.dll, if you install MQ client on the default directory; you will find amqmdnet.dll under C:\Program Files\MQSeries Client\bin.
One of the annoying things about the .NET implementation is that whenever the system raise an exception and you examined the “CompCode” (stands for completion code), and “Reason” properties of the MQException object, they will always provide you with a number that you have to lookup to know exactly what went wrong.
CompCode can have one of three values:
0 : Successful completion.
1 : Warning (partial completion).
2 : Call failed
When the value of CompCode is not equal to 0 you need to go and examine the Reason property which will give you another number that you can lookup in Appendix B for a basic explanation of the code, for more details you can refer to IBM WebSphere Messages Document.
8. The Code:
This code can be used whenever a need arise to interface with WebSphere MQ from a .NET client code. Those clients include but not limited to BizTalk 2004, CMS 2002, SPS 2003, or any custom .NET application. It has been tested with Windows-XP and Windows 2003 and in both cases it was working without problems.
/////////////////////////////////////////////////////////////////////
// Author :
// E-mail :
// Date : May - 2004
// Description : This class acts as a simple interface between any
// .net application and IBM MQseries (WebSphere MQ)
//
/////////////////////////////////////////////////////////////////////
using System;
using IBM.WMQ;
using System.IO ;
using System.Text ;
namespace SHB.CB2B
{
public enum MessagingType
{
ASync,
Sync
}
public class MQAdapter
{
// The name of the queue manager.
private string QueManager;
// The name of the queue where you will be dropping your messages.
private string InQueName;
// The name of the queue where you will be getting your messages.
private string OutQueName;
// The time you want a thread to wait on
// an empty queue until a relevant message shows up.
private int WaitInterval;
private MQQueueManager qMgr;
private MQQueue InputQueue;
private MQQueue OutputQueue;
private MQMessage MqsMsg;
private MQMessage retrievedMessage;
private MQGetMessageOptions gmo;
private String msgText;
private UTF8Encoding utf8Enc;
public MQAdapter(MessagingType Type)
{
if (Type == MessagingType.ASync)
{
try
{
QMgr = new MQQueueManager(QueManager);
}
catch (MQException ex)
{
// Add your MQSeries exception handling here
}
}
}
public string SendRequestToMQ(string RequestStream)
{
try
{
qMgr =new MQQueueManager(QueManager);
int InOpenOptions = MQC.MQOO_OUTPUT |
MQC.MQOO_FAIL_IF_QUIESCING ;
int OutOpenOptions = MQC.MQOO_INPUT_AS_Q_DEF |
MQC.MQOO_FAIL_IF_QUIESCING ;
InputQueue = qMgr.AccessQueue(InQueName, InOpenOptions);
OutputQueue = qMgr.AccessQueue(OutQueName, OutOpenOptions);
MqsMsg =new MQMessage();
// Since .NET strings stores characters encoded
// in a UTF-16 format, while a major portion
// of the applications using IBM MQSeries are legacy
// application, you might need to encode strings
// in a UTF-8, or ASCII format in order for
// the applications on the other side to be able
// to understand your messages
utf8Enc = new UTF8Encoding();
MqsMsg.WriteBytes(Encoding.UTF8.GetBytes(RequestStream));
MQPutMessageOptions pmo =new MQPutMessageOptions();
InputQueue.Put(MqsMsg,pmo);
}
catch (MQException ex)
{
// Add your MQSeries exception handling here
}
catch (Exception e)
{
// Add your exception handling here
// to handle exceptions of types other than MQException
}
try
{
retrievedMessage =new MQMessage();
retrievedMessage.CorrelationId =MqsMsg.MessageId;
//Setting the get message options..
gmo =new MQGetMessageOptions();
// In order to activate "Wait on an empty queue";
// you have to mask MQGetMessageOptions with MQGMO_WAIT
// for more details on other available options kindly refer to Appendix A
gmo.Options = MQC.MQGMO_FAIL_IF_QUIESCING | MQC.MQGMO_WAIT ;
gmo.WaitInterval = WaitInterval ;// wait time
// to match using CorrelationID
// or MQMO_MATCH_MSG_ID to match using MessageID
gmo.MatchOptions = MQC.MQMO_MATCH_CORREL_ID ;
OutputQueue.Get(retrievedMessage, gmo);
//writing Message result
msgText =retrievedMessage.ReadString(retrievedMessage.MessageLength) ;
}
catch (MQException ex)
{
// Add your MQSeries exception handling here
}
catch (Exception e)
{
// Add your exception handling here to
// handle exceptions of types other than MQException
}
try
{
//Close the queue
OutputQueue.Close();
InputQueue.Close() ;
//Disconnect from the queue manager
qMgr.Disconnect();
}
catch (MQException ex)
{
// Add your MQSeries exception handling here
}
catch (Exception e)
{
// Add your exception handling here
// to handle exceptions of types other than MQException
}
return msgText;
}
// --------- See the comments one the code above --------//
public Byte[] SendMessage(string Message)
{
int InOpenOptions ;
MQQueue InputQueue = null ;
MQMessage MqsMsg ;
UTF8Encoding utf8Enc ;
MQPutMessageOptions Pmo ;
InOpenOptions = MQC.MQOO_OUTPUT | MQC.MQOO_FAIL_IF_QUIESCING ;
try
{
InputQueue = qMgr.AccessQueue(InQueName, InOpenOptions);
MqsMsg =new MQMessage();
utf8Enc = new UTF8Encoding();
MqsMsg.WriteBytes(utf8Enc.GetBytes(Message));
Pmo =new MQPutMessageOptions();
InputQueue.Put(MqsMsg,Pmo);
}
catch (MQException ex)
{
// Add your MQSeries exception handling here
}
catch (System.Exception e)
{
// Add your exception handling here
// to handle exceptions of types other than MQException
}
finally
{
InputQueue.Close() ;
}
return MqsMsg.MessageId ;
}
public string GetMessage(Byte[] MessageId)
{
int OutOpenOptions ;
MQQueue OutputQueue = null ;
MQMessage RetrievedMessage ;
MQGetMessageOptions Gmo ;
OutOpenOptions = MQC.MQOO_INPUT_AS_Q_DEF |
MQC.MQOO_FAIL_IF_QUIESCING ;
RetrievedMessage =new MQMessage();
Gmo =new MQGetMessageOptions();
Gmo.Options = MQC.MQGMO_FAIL_IF_QUIESCING |
MQC.MQGMO_WAIT ;
Gmo.WaitInterval = WaitInterval ;
Gmo.MatchOptions = MQC.MQMO_MATCH_CORREL_ID ;
try
{
OutputQueue = qMgr.AccessQueue(OutQueName, OutOpenOptions);
RetrievedMessage.CorrelationId = MessageId ;
OutputQueue.Get(RetrievedMessage,Gmo);
}
catch (MQException e)
{
// Add your MQSerie exception handling here
}
catch (System.Exception e)
{
// Add your exception handling here
// to handle exceptions of types other than MQException
}
finally
{
OutputQueue.Close() ;
}
return RetrievedMessage.ReadString(RetrievedMessage.MessageLength) ;
}
~ MQAdapter()
{
try
{
qMgr.Close() ;
}
catch
{
}
}
}
9. References:
1. WebSphere MQ Application Programming Guide
2. WebSphere MQ Application Programming Reference
3. WebSphere MQ Clients
4. WebSphere MQ Message
5. WebSphere MQ Using the Component Object Model Interface
10. Appendixes:
9.1. Appendix A - Queue Accessing Options:
Queue Access Options |
Explanation |
MQOO_INPUT_AS_Q_DEF |
Open to get messages using queue-defined default. |
MQOO_INPUT_SHARED |
Open to get messages with shared access. |
MQOO_INPUT_EXCLUSIVE |
Open to get messages with exclusive access. |
MQOO_BROWSE |
Open to browse message. |
MQOO_OUTPUT |
Open to put messages. |
MQOO_INQUIRE |
Open for inquiry, required if you wish to query properties. |
MQOO_SET |
Open to set attributes, required if you wish to set properties. |
MQOO_BIND_ON_OPEN |
Bind handle to destination when queue is opened. |
MQOO_BIND_NOT_FIXED |
Do not bind to a specific destination. |
MQOO_BIND_AS_Q_DEF |
Use default binding for queue. |
MQOO_SAVE_ALL_CONTEXT |
Save context when message retrieved. |
MQOO_PASS_IDENTITY_CONTEXT |
Allow identity context to be passed. |
MQOO_PASS_ALL_CONTEXT |
Allow all contexts to be passed. |
MQOO_SET_IDENTITY_CONTEXT |
Allows identity context to be set. |
MQOO_SET_ALL_CONTEXT |
Allows all contexts to be set. |
MQOO_ALTERNATE_USER_AUTHORITY |
Validate with the specified user identifier. |
MQOO_FAIL_IF_QUIESCING |
Fail if the queue manager is quiescing. |
9.2. Appendix B – Error & Reason Codes
Reason Code |
Error Code |
|
0 |
|
900 |
|
999 |
|
2001 |
|
2002 |
|
2003 |
|
2004 |
|
2005 |
|
2006 |
|
2007 |
|
2008 |
|
2009 |
|
2010 |
|
2011 |
|
2012 |
|
2013 |
|
2014 |
|
2016 |
|
2017 |
|
2018 |
|
2019 |
|
2020 |
|
2021 |
|
2022 |
|
2023 |
|
2024 |
|
2025 |
|
2026 |
|
2027 |
|
2029 |
|
2030 |
|
2031 |
|
2033 |
|
2034 |
|
2035 |
|
2036 |
|
2037 |
|
2038 |
|
2039 |
|
2040 |
|
2041 |
|
2042 |
|
2043 |
|
2044 |
|
2045 |
|
2046 |
|
2047 |
|
2048 |
|
2049 |
|
2050 |
|
2051 |
|
2052 |
|
2053 |
|
2055 |
|
2056 |
|
2057 |
|
2058 |
|
2059 |
|
2061 |
|
2062 |
|
2063 |
|
2065 |
|
2066 |
|
2067 |
|
2068 |
|
2069 |
|
2070 |
|
2071 |
|
2072 |
|
2075 |
|
2076 |
|
2077 |
|
2078 |
|
2079 |
|
2080 |
|
2082 |
|
2085 |
|
2086 |
|
2087 |
|
2090 |
|
2091 |
|
2092 |
|
2093 |
|
2094 |
|
2095 |
|
2096 |
|
2097 |
|
2098 |
|
2099 |
|
2100 |
|
2101 |
|
2102 |
|
2103 |
|
2104 |
|
2105 |
|
2106 |
|
2109 |
|
2110 |
|
2111 |
|
2112 |
|
2113 |
|
2114 |
|
2115 |
|
2116 |
|
2117 |
|
2118 |
|
2119 |
|
2120 |
|
2120 |
|
2121 |
|
2122 |
|
2123 |
|
2124 |
|
2125 |
|
2126 |
|
2127 |
|
2128 |
|
2129 |
|
2130 |
|
2131 |
|
2132 |
|
2133 |
|
2134 |
|
2135 |
|
2136 |
|
2137 |
|
2138 |
|
2139 |
|
2140 |
|
2141 |
|
2142 |
|
2143 |
|
2144 |
|
2145 |
|
2146 |
|
2148 |
|
2149 |
|
2150 |
|
2152 |
|
2153 |
|
2154 |
|
2155 |
|
2156 |
|
2157 |
|
2158 |
|
2159 |
|
2160 |
|
2161 |
|
2162 |
|
2163 |
|
2173 |
|
2182 |
|
2183 |
|
2184 |
|
2185 |
|
2186 |
|
2187 |
|
2188 |
|
2189 |
|
2190 |
|
2191 |
|
2192 |
|
2192 |
|
2193 |
|
2194 |
|
2195 |
|
2196 |
|
2197 |
|
2198 |
|
2199 |
|
2201 |
|
2202 |
|
2203 |
|
2204 |
|
2206 |
|
2207 |
|
2208 |
|
2209 |
|
2216 |
|
2217 |
|
2218 |
|
2219 |
|
2220 |
|
2222 |
|
2223 |
|
2224 |
|
2225 |
|
2226 |
|
2227 |
|
2232 |
|
2233 |
|
2234 |
|
2235 |
|
2236 |
|
2237 |
|
2238 |
|
2239 |
|
2241 |
|
2242 |
|
2243 |
|
2244 |
|
2245 |
|
2246 |
|
2247 |
|
2248 |
|
2249 |
|
2250 |
|
2251 |
|
2252 |
|
2253 |
|
2255 |
|
2256 |
|
2257 |
|
2258 |
|
2259 |
|
2260 |
|
2261 |
|
2262 |
|
2263 |
|
2264 |
|
2265 |
|
2266 |
|
2267 |
|
2268 |
|
2269 |
|
2270 |
|
2271 |
|
2272 |
|
2273 |
|
2274 |
|
2277 |
|
2278 |
|
2279 |
|
2280 |
|
2281 |
|
2282 |
|
2283 |
|
2284 |
|
2285 |
|
2286 |
|
2287 |
|
2288 |
|
2289 |
|
2290 |
|
2291 |
|
2292 |
|
2293 |
|
2294 |
|
2295 |
|
2296 |
|
2297 |
|
2298 |
|
2299 |
|
2300 |
|
2301 |
|
2302 |
|
2303 |
|
2304 |
|
2305 |
|
2306 |
|
2307 |
|
2308 |
|
2309 |
|
2310 |
|
2311 |
|
2312 |
|
2313 |
|
2314 |
|
2315 |
|
2316 |
|
2317 |
|
2318 |
|
2319 |
|
2320 |
|
2321 |
|
2322 |
|
2323 |
|
2324 |
|
2325 |
|
2326 |
|
2327 |
|
2328 |
|
2329 |
|
2330 |
|
2331 |
|
2332 |
|
2333 |
|
2334 |
|
2335 |
|
2336 |
|
2337 |
|
2338 |
|
2339 |
|
2340 |
|
2341 |
|
2342 |
|
2343 |
|
2344 |
|
2345 |
|
2346 |
|
2347 |
|
2348 |
|
2349 |
|
2350 |
|
2351 |
|
2352 |
|
2353 |
|
2354 |
|
2355 |
|
2356 |
|
2357 |
|
2358 |
|
2359 |
|
2360 |
|
2361 |
|
2111 |
|
2112 |
|
2113 |
|
2114 |
|
2115 |
|
2116 |
|
2117 |
|
2118 |
|
2119 |
|
2120 |
|
2120 |
|
2121 |
|
2122 |
|
2123 |
|
2124 |
|
2125 |
|
2126 |
|
2127 |
|
2128 |
|
2129 |
|
2130 |
|
2131 |
|
2132 |
|
2133 |
|
2134 |
|
2135 |
|
2136 |
|
2137 |
|
2138 |
|
2139 |
|
2140 |
|
2141 |
|
2142 |
|
2143 |
|
2144 |
|
2145 |
|
2146 |
|
2148 |
|
2149 |
|
2150 |
|
2152 |
|
2153 |
|
2154 |
|
2155 |
|
2156 |
|
2157 |
|
2158 |
|
2159 |
|
2160 |
|
2161 |
|
2162 |
|
2163 |
|
2173 |
|
2182 |
|
2183 |
|
2184 |
|
2185 |
|
2186 |
|
2187 |
|
2188 |
|
2189 |
|
2190 |
|
2191 |
|
2192 |
|
2192 |
|
2193 |
|
2194 |
|
2195 |
|
2196 |
|
2197 |
|
2198 |
|
2199 |
|
2201 |
|
2202 |
|
2203 |
|
2204 |
|
2206 |
|
2207 |
|
2208 |
|
2209 |
|
2216 |
|
2217 |
|
2218 |
|
2219 |
|
2220 |
|
2222 |
|
2223 |
|
2224 |
|
2225 |
|
2226 |
|
2227 |
|
2232 |
|
2233 |
|
2234 |
|
2235 |
|
2236 |
|
2237 |
|
2238 |
|
2239 |
|
2241 |
|
2242 |
|
2243 |
|
2244 |
|
2245 |
|
2246 |
|
2247 |
|
2248 |
|
2249 |
|
2250 |
|
2251 |
|
2252 |
|
2253 |
|
2255 |
|
2256 |
|
2257 |
|
2258 |
|
2259 |
|
2260 |
|
2261 |
|
2262 |
|
2263 |
|
2264 |
|
2265 |
|
2266 |
|
2267 |
|
2268 |
|
2269 |
|
2270 |
|
2271 |
|
2272 |
|
2273 |
|
2274 |
|
2277 |
|
2278 |
|
2279 |
|
2280 |
|
2281 |
|
2282 |
|
2283 |
|
2284 |
|
2285 |
|
2286 |
|
2287 |
|
2288 |
|
2289 |
|
2290 |
|
2291 |
|
2292 |
|
2293 |
|
2294 |
|
2295 |
|
2296 |
|
2297 |
|
2298 |
|
2299 |
|
2300 |
|
2301 |
|
2302 |
|
2303 |
|
2304 |
|
2305 |
|
2306 |
|
2307 |
|
2308 |
|
2309 |
|
2310 |
|
2311 |
|
2312 |
|
2313 |
|
2314 |
|
2315 |
|
2316 |
|
2317 |
|
2318 |
|
2319 |
|
2320 |
|
2321 |
|
2322 |
|
2323 |
|
2324 |
|
2325 |
|
2326 |
|
2327 |
|
2328 |
|
2329 |
|
2330 |
|
2331 |
|
2332 |
|
2333 |
|
2334 |
|
2335 |
|
2336 |
|
2337 |
|
2338 |
|
2339 |
|
2340 |
|
2341 |
|
2342 |
|
2343 |
|
2344 |
|
2345 |
|
2346 |
|
2347 |
|
2348 |
|
2349 |
|
2350 |
|
2351 |
|
2352 |
|
2353 |
|
2354 |
|
2355 |
|
2356 |
|
2357 |
|
2358 |
|
2359 |
|
2360 |
|
2361 |