Commit Graph

1169 Commits

Author SHA1 Message Date
Trustin Lee
754392aaa9 Add ByteBuf.order(ByteOrder) method to simplify little endian access
- Removed all methods that requires ByteOrder as a parameter
  from Unpooled (formerly ByteBufs/ChannelBuffers)
  - Instead, a user calls order(ByteOrder) to get a little endian
    version of the user's buffer
  - This gives less overwhelming number of methods in Unpooled.
2012-06-11 20:24:44 +09:00
Trustin Lee
876847fd20 Merge MessageBufs and ByteBufs into Unpooled
- e.g. Unpooled.messageBuffer()
- It will make much more sense once we introduce pooling:
  - i.e. Pooled.buffer()
2012-06-11 17:02:29 +09:00
Trustin Lee
7d36f936c8 Fix failing tests 2012-06-11 11:35:07 +09:00
Trustin Lee
574d84e98e Remove ChannelBufferHolder / Add more handler interfaces for type safety
- ChannelInboundHandler and ChannelOutboundHandler does not have a type
  parameter anymore.  
- User should implement ChannelInboundMessageHandler or
  ChannelOutboundMessageHandler.
2012-06-10 12:22:32 +09:00
Trustin Lee
a849d11877 ChannelBuffers -> ByteBufs / Add MessageBuf & ChannelBuf
- Add MessageBuf which replaces java.util.Queue
- Add ChannelBuf which is common type of ByteBuf and ChannelBuf
- ChannelBuffers was renamed to ByteBufs
- Add MessageBufs
- All these changes are going to replace ChannelBufferHolder.
2012-06-10 11:31:39 +09:00
Trustin Lee
5164d91255 Rename ChannelBuffer to ByteBuf as discussed before
- ChannelBuffer gives a perception that it's a buffer of a
  channel, but channel's buffer is now a byte buffer or a message
  buffer.  Therefore letting it be as is is going to be confusing.
2012-06-10 11:08:43 +09:00
Trustin Lee
e376888d48 Replace 'Stream' with 'Byte'
- In computing, 'stream' means both byte stream and message stream,
  which is confusing.
- Also, we were already mixing stream and byte in some places and
  it's better use the terms consistently.
  (e.g. inboundByteBuffer & inbound stream)
2012-06-09 21:05:59 +09:00
Trustin Lee
468a3228a4 Fit every line into 120 columns 2012-06-08 19:28:12 +09:00
Trustin Lee
748de5ea83 Fix a compilation error 2012-06-08 10:02:44 +09:00
Trustin Lee
92cbe6f980 Support long Expires dates and commas in cookie values (#96)
- Contribution by @valodzka
2012-06-08 09:25:39 +09:00
Trustin Lee
4a23c2a6eb Fix checkstyle errors 2012-06-07 22:01:59 +09:00
Trustin Lee
10f7a31908 Fixed SpdySessionHandlerTest / Fixed NPE in EmbeddedChannel
- Some tests like SpdySessionHandlerTest accesses outbound buffer
  even before the outbound buffer is initialized by
  AbstractEmbeddedChannel's subclasses, leading to NPE at <init>.
  To fix this problem, subclasses now pass the outbound buffer as
  a constructor parameter to AbstractEmbeddedChannel.
2012-06-07 21:33:31 +09:00
Trustin Lee
994038975a Port HttpContentEncoder/Decoder to use EmbeddedStreamChannel / Cleanup
- Removed unused constructor parameter in AbstractChannel
- Re-enabled GZIP encoding in HTTP snoop example
2012-06-07 21:06:56 +09:00
Trustin Lee
8701e24b9a Add back Channel(Inbound|Outbound)(Message|Stream)HandlerAdapter
- they are useful when creating an anonymous class
- Also added back CombinedChannelHandler with extra constraints
2012-06-07 17:49:45 +09:00
Trustin Lee
ea0c9cfe79 Post-overhaul fixes / Split LoggingHandler into three
- LoggingHandler now only logs state and operations
- StreamLoggingHandler and MessageLoggingHandler log the buffer content
- Added ChannelOperationHandlerAdapter
  - Used by WriteTimeoutHandler
2012-06-07 16:56:21 +09:00
Trustin Lee
5e93d206ff Overhaul - Split ChannelHandler & Merge ChannelHandlerContext
- Extracted some handler methods from ChannelInboundHandler into
  ChannelStateHandler
- Extracted some handler methods from ChannelOutboundHandler into
  ChannelOperationHandler
- Moved exceptionCaught and userEventTriggered are now in
  ChannelHandler
  
- Channel(Inbound|Outbound)HandlerContext is merged into
  ChannelHandlerContext
- ChannelHandlerContext adds direct access methods for inboud and
  outbound buffers
  - The use of ChannelBufferHolder is minimal now.
    - Before: inbound().byteBuffer()
    - After: inboundByteBuffer()
    - Simpler and better performance
    
- Bypass buffer types were removed because it just does not work at all
  with the thread model.
  - All handlers that uses a bypass buffer are broken.  Will fix soon.

- CombinedHandlerAdapter does not make sense anymore either because
  there are four handler interfaces to consider and often the two
  handlers will implement the same handler interface such as
  ChannelStateHandler.  Thinking of better ways to provide this feature
2012-06-07 14:52:33 +09:00
Trustin Lee
3def2e6598 Fix more checkstyle errors 2012-06-07 09:19:14 +09:00
Frédéric Brégier
c2e3d305b4 Merge pull request #381 from fredericBregier/master
Improve HTTP message streaming in decoder same as #380
2012-06-05 10:05:34 -07:00
Frédéric Brégier
06e754eb81 Improve HTTP message streaming in decoder, in Master same as #380 submitted fix 2012-06-05 19:56:01 +03:00
Trustin Lee
1eced1e9e3 Update license headers 2012-06-04 13:31:44 -07:00
Trustin Lee
361cb417e0 Move SPDY echo tests to testsuite to use AbstractSocketTest
- Moved MIN_VERSION and MAX_VERSION to SpdyConstants to allow public
  access
- Removed the tests that are not necessary anymore.
2012-06-03 04:47:05 -07:00
Trustin Lee
f991a8c7d4 Fix a bug where DefaultChannelPipeline.write() doesn't find the buffer
- Also fixed failures in SpdySessionHandlerTest
2012-06-03 04:10:32 -07:00
Trustin Lee
3e0cbf0caa Fix HttpClientCodecTest.testFailsOnMissingResponse()
- AbstractCodecEmbedder does not throw an exception immediately anymore.
  It stores the caught exceptions in the product queue and throws them
  on pool() or peek().
2012-06-03 03:32:30 -07:00
Trustin Lee
3b2c25e8ed Rename (Server)Bootstrap.(child)initializer to (child)handler
- The handler you specify with initializer() is actually simply added
  to the pipeline and that's all.  It's ChannelInitializer which does
  additional work.  For example, a user can specify just a single
  handler with initializer() and it will still work.  This is especially
  common for Bootstrap, so I renamed initializer to handler, which makes
  more sense.
2012-06-03 01:00:16 -07:00
Trustin Lee
cc4c98d7ba Fix #378 again
- @jroper's fix did not work, so I just fixed it again.
2012-06-02 23:05:20 -07:00
James Roper
e8a74c8ad0 Fixing #378, when path or domain are null in both this and that, equals and compareTo return false even when the cookies are equal. 2012-06-03 01:04:23 +03:00
Trustin Lee
45f19d02ff Remove the codecs and handlers that can't make it on time for 4.0.0.A1
- Removed ones are: IP filer and HTTP multipart codec
  - Needs closer code review and polishing
  - Sorry. I'll add them back in the next alpha releases
  - SSL handler and ChunkedWriteHandler also need more work, but
    I really want to make them part of the first alpha because they
    are used pretty often by users.
2012-06-02 01:38:10 -07:00
Trustin Lee
cc4f705029 Replace ChannelBuffer.toByteBuffer() with hasNioBuffer() and nioBuffer()
... just like we do with byte arrays.  toByteBuffer() and
toByteBuffers() had an indeterministic behavior and thus it could not
tell when the returned NIO buffer is shared or not.  nioBuffer() always
returns a view buffer of the Netty buffer.  The only case where
hasNioBuffer() returns false and nioBuffer() fails is the
CompositeChannelBuffer, which is not very commonly used and *slow*.
2012-06-02 01:30:55 -07:00
Trustin Lee
141a05c831 Strict thread model / Allow assign an executor to a handler
- Add EventExecutor and make EventLoop extend it
- Add SingleThreadEventExecutor and MultithreadEventExecutor
- Add EventExecutor's default implementation
- Fixed an API design problem where there is no way to get non-bypass
  buffer of desired type
2012-06-01 17:51:19 -07:00
Trustin Lee
77274ae743 Automated code clean-up 2012-05-31 12:03:01 -07:00
Trustin Lee
734d452be2 Apply missing changes in the branch '3' 2012-05-31 11:50:08 -07:00
Trustin Lee
0cd766df30 Move HTTP multipart classes to its own package / Clean-up
- Move CaseIgnoringComparable to netty-common
- Add HttpConstants
2012-05-31 11:32:42 -07:00
Trustin Lee
197f31c90e Test all supported SPDY session management 2012-05-31 02:06:53 -07:00
Trustin Lee
a494f201fc Call setHandshakeComplete() before the handler replacement (#332)
- Contributed by @normanmaurer
2012-05-31 02:02:02 -07:00
Trustin Lee
7ac89ace4f Finished forward-porting SPDY codec 2012-05-31 01:53:58 -07:00
Trustin Lee
131eef2c51 Forward-porting SPDY codec 2012-05-31 00:37:27 -07:00
Trustin Lee
d7a198a60f Zap marshalling and spdy codec to forwardport again 2012-05-30 23:14:18 -07:00
Trustin Lee
743596aaea Fix a bug where first websocket frame is discarded (#332) 2012-05-30 19:18:08 -07:00
Trustin Lee
a5a76131e6 Fix checkstyle errors 2012-05-30 19:09:23 -07:00
vibul
4fc089829d Fixed bug where subprotocol not sent by client
Conflicts:

	codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker.java
	codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker08.java
	codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker13.java
	codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java
2012-05-30 19:07:44 -07:00
Frédéric Brégier
a73e6ea581 typo fix ! Sorry 2012-05-30 17:39:03 -07:00
Frédéric Brégier
a91e72403c Very small fix (readUnsigned while in optimized version it was signed but should be unsigned) 2012-05-30 17:37:41 -07:00
Trustin Lee
d6cedb008b Reduce the cost of throwing a SeekAheadNoBackArrayException 2012-05-30 17:37:12 -07:00
Frédéric Brégier
f799c9f215 Add Exception to the exception class name 2012-05-30 17:31:40 -07:00
Frédéric Brégier
b8ab8828c0 Add Exception to name of the Exception ;-) 2012-05-30 17:31:21 -07:00
Frédéric Brégier
ac39f39f36 Update codec-http/src/main/java/io/netty/handler/codec/http/HttpPostRequestDecoder.java 2012-05-30 17:31:03 -07:00
Frédéric Brégier
5d2bf43b59 Optimize Buffer access while decoding by going through backend array when possible (divide by almost 2 the time spent in decoding) 2012-05-30 17:30:47 -07:00
Frédéric Brégier
759d0633a4 Add the SeekAheadOptimize class to enable faster seek of bytes values in HttpPostRequestDecoder 2012-05-30 17:30:36 -07:00
Trustin Lee
e8bc276ddd Fix in addContent when switching from MemoryAttribute if it is done when
last buffer added, in order to not close immediately the underlying
file before adding the last buffer.

- Contribution by @fredericBregier
2012-05-30 17:28:51 -07:00
Trustin Lee
dba9a6d408 Close channel when needed / Call force() only when necessary
- Contribution by @fredericBregier
2012-05-30 17:26:41 -07:00
Trustin Lee
92f010d688 Use int instead of long for maxFramePayloadLength 2012-05-30 17:21:51 -07:00
Trustin Lee
67ee22e23a Add max frame length for web socket to limit chance of DOS attack (#283)
- Contributed by @veebs
2012-05-30 17:13:00 -07:00
Trustin Lee
ec43aa121f Case-insensitive matching for Upgrade and Connection header (#278) 2012-05-30 16:43:04 -07:00
Trustin Lee
42abb6df3a QueueFactory cleanup
- Really attempt to create a queue to determine LTQ can be initialized
  in runtime, and cache the result
- Remove unnecessary Class<T> parameter in createQueue()
- Remove unused createQueue(Collection)
2012-05-30 16:19:22 -07:00
Trustin Lee
c7004ed142 Use Sec-WebSocket-Origin instead of Origin (#264)
- Contributed by @normanmaurer
2012-05-30 16:04:34 -07:00
Trustin Lee
367895f660 Add port to Origin if the port is non default (80/443). (#262) 2012-05-30 16:00:40 -07:00
Trustin Lee
7e94632d41 Add port to 'Origin' if the port is non default (80/443) (#262)
- Contributed by @normanmaurer
2012-05-30 15:57:39 -07:00
Trustin Lee
5e896cf0b3 Add a note that explain the behavior of CookieEncoder (#94)
- Contributed by @normanmaurer
2012-05-30 15:53:20 -07:00
Trustin Lee
8eda2280b3 Add test for HttpClientCodec missing response handling (#256, #259)
- Contributed by @normanmaurer
2012-05-30 15:48:57 -07:00
Trustin Lee
922cec1f9b Add an option to tell a user if there was a missing response (#256)
- Contributed by @normanmaurer
2012-05-30 15:37:01 -07:00
Trustin Lee
a9948d681e Throw NoSuchBufferException instead of returning null
- Exception in this case makes a user less confusing
- To reduce the overhead of filling the stack trace,
  NoSuchBufferException has a public pre-constructed instance.
  - This is necessary because codec framework sometimes need to support
    both type of outbound buffers.
- Fixed a bug where SpdyFrameEncoder did not handle ping messages
- Reduced memory copy in codec embedder (EmbeddedChannel)
2012-05-29 17:25:09 -07:00
Trustin Lee
8237afff64 Ported most examples
- Renamed ChannelBootstrap to Bootstrap
- Renamed ServerChannelBootstrap to ServerBootstrap
- Moved bootstrap classes to io.netty.bootstrap as before
- Moved unfoldAndAdd() to a separate utility class
- Fixed a bug in unfoldAndAdd() where it did not handle ChannelBuffer
  correctly
2012-05-29 16:41:26 -07:00
Trustin Lee
b10cf29393 Add isDecodable/isEncodable() to codecs to support stacked codecs 2012-05-29 13:34:01 -07:00
Trustin Lee
026715e818 Refactor the pipeline API to support stacked codecs
- Previous API did not support the pipeline which contains multiple
  MessageToStreamEncoders because there was no way to find the closest
  outbound byte buffer.  Now you always get the correct buffer even if
  the handler that provides the buffer is placed distantly.
  For example:
  
    Channel -> MsgAEncoder -> MsgBEncoder -> MsgCEncoder
  
  Msg(A|B|C)Encoder will all have access to the channel's outbound
  byte buffer.  Previously, it was simply impossible.

- Improved ChannelBufferHolder.toString()
2012-05-29 12:09:29 -07:00
Trustin Lee
a1bdf671f1 Simplified EventLoop implementation names
- Also
  - Fixed a test failure
  - Fixed compiler warnings related with ChannelInitializer type
    parameters
2012-05-25 15:51:22 -07:00
Trustin Lee
f60f918763 Fixed all SPDY echo tests / Handle closed old I/O channels correctly 2012-05-25 14:24:25 -07:00
Trustin Lee
debaa6a72a Fix resource management 2012-05-23 11:45:30 -07:00
Trustin Lee
c883b61503 Ported codec-http to the new API
- Added ChannelBufferHolders.catchAllBuffer()
- Relaxed UnsupportedMessageTypeException constructor signature
- EmbeddedChannel now uses the catchAllBuffer
- ChanelInboundMessageHandlerAdapter.messageReceive() throws Exception
- Added ChannelInboundStreamHandlerAdapter
2012-05-23 11:42:10 -07:00
Trustin Lee
af37ec4f23 Ported the HTTP snoop example to the new API
- Replaced pipeline factories with initializers
- Ported essential parts related with HTTP to the new API
- Replaced ChannelHandlerAdapter.combine() with CombinedChannelHandler
- Fixed a bug where ReplayingDecoder does not notify the next handler
- Fixed a bug where ReplayingDecoder calls wrong callDecode() method
- Added a destination buffer as an argument to AbstractChannel.doRead()
  for easier implementation
- Fixed a bug where NioSocketChannel did not try to increase the inbound
  buffer size (moved the logic to AbstractChannel)
2012-05-20 14:19:11 +09:00
Trustin Lee
251a18160c Move VoidEnum to util 2012-05-18 14:34:42 +09:00
Trustin Lee
1bf0dfe64a Retrofit ReplayingDecoder with the new API
- Moved up to 'codec' from 'codec.replay'
- Test passes with Redis client codec
2012-05-17 12:37:37 +09:00
Trustin Lee
92a688e5b2 Retrofit the codec framework with the new API (in progress)
- Replaced FrameDecoder and OneToOne(Encoder|Decoder) with:
  - (Stream|Message)To(String|Message)(Encoder|Decoder)
- Moved the classes in 'codec.frame' up to 'codec'
- Fixed some bugs found while running unit tests
2012-05-16 23:02:06 +09:00
Trustin Lee
368156f5d0 Another round of the new API design
- Channel now creates a ChannelPipeline by itself

  I find no reason to allow a user to use one's own pipeline
  implementation since I saw nobody does except for the cases where a
  user wants to add a user attribute to a channel, which is now covered
  by AttributeMap.

- Removed ChannelEvent and its subtypes because they are replaced by
  direct method invocation.
- Replaced ChannelSink with Channel.unsafe()
- Various getter renaming (e.g. Channel.getId() -> Channel.id())
- Added ChannelHandlerInvoker interface
- Implemented AbstractChannel and AbstractServerChannel
- Some other changes I don't remember
2012-05-01 17:19:41 +09:00
vibul
91dc8efd4b Issue #250. Implement web socket close frame status code and reason text. 2012-04-10 08:15:24 +02:00
Trustin Lee
fd0b0a4e2b Code cleanup 2012-03-30 12:48:28 +09:00
Norman Maurer
60d9364604 First round of remove the boss-thread. See #240 2012-03-28 20:19:39 +02:00
Norman Maurer
0082a15899 Fix javadocs warnings 2012-03-26 19:50:39 +03:00
Norman Maurer
2766133a4d Fix javadocs warnings 2012-03-26 19:50:01 +03:00
Norman Maurer
32ff810b64 Correctly handle Hixie 76 websocket handshake response. See #222 2012-03-21 19:00:32 +01:00
norman
e8ddc3cf00 remove unnecessary check. See #222 2012-03-20 15:44:59 +01:00
norman
8d9f78c84d Correctly handle responses with return code of 1xx. See #222 2012-03-20 15:40:34 +01:00
Norman Maurer
cb931bfb92 Correctly handle HTTP Patch. See #227 2012-03-11 11:54:54 +01:00
Trustin Lee
279d859c7e Issue #220 - Treat content as non-empty on 101 Web Socket upgrade response 2012-03-09 11:07:26 +09:00
norman
92a907c4d7 Merge branch 'master' of github.com:netty/netty 2012-03-08 08:09:17 +01:00
norman
09b41b28ea Correctly handle earlier versions of websockets. See #222 2012-03-08 08:08:36 +01:00
Norman Maurer
30ef214677 Make sure ...Decompressor.end() is called even on Exception. See #224 2012-03-07 21:14:48 +01:00
Trustin Lee
70e0eba894 Replace SpdyHeaderBlockJZlibDecompressor with java.util.zip.Inflater-based one
It should be fine because the Inflater-based one uses only JDK 1.5 API
2012-03-07 20:09:05 +09:00
Trustin Lee
2109fdedb6 Fix cherry-pick where git was not very smart 2012-03-07 20:07:12 +09:00
Jeff Pinner
304eee1db4 SPDY: use java.util.zip for header block decompressor 2012-03-07 20:05:25 +09:00
Trustin Lee
cf02ad2a1e Add DetectionUtil which replaces UnsafeDetectUtil / Improve SpdyHeaderBlockJZlibDecompressor 2012-03-07 19:54:44 +09:00
Trustin Lee
efe27dbce5 Rename SPDY header block (de)compressor classes 2012-03-02 10:43:04 -08:00
norman
5291560283 Remove left-over of refactoring. See #211 2012-03-02 08:03:20 +01:00
norman
8eec693883 Remove twitter license headers. See #202 2012-03-02 07:46:56 +01:00
norman
985fc448dc Remove unused imports 2012-03-02 07:38:05 +01:00
norman
469cb8b80b Remove Twitter license. See #202 2012-03-02 07:37:43 +01:00
Trustin Lee
b22ebbe430 Make #211 work with Java 5
* Use java.util.zip.Deflater only when running under Java 7
2012-03-01 15:52:57 -08:00
Jeff Pinner
5aae8279b9 SPDY: use jdk 1.7 java.util.zip instead of jzlib 2012-03-01 15:41:08 -08:00
Trustin Lee
4c67a24860 Fix #202 - Remove Twitter license
Twitter signed CCLA today.
2012-03-01 14:02:30 -08:00
Dennis Boldt
b3cc305578 Organized imports. 2012-02-21 03:06:26 +01:00
Jestan Nirojan
7dbb8d2b8f fixed checkstyle build failures 2012-02-19 12:38:39 +05:30
Jestan Nirojan
20d7379c53 merge upstream master 2012-02-19 12:37:50 +05:30
norman
c46b083c1f Correctly decode URI in QueryStringDecoder. See #189 2012-02-15 08:30:22 +01:00
Jestan Nirojan
a298398630 added test timeout for SPDY echo test 2012-02-11 23:04:25 +05:30
Norman Maurer
9b563c8a28 SPDY Protocol HTTP Layer. See #184 2012-02-11 12:52:56 +01:00
Trustin Lee
dd27cd510a Use getHeader() instead of getHeaders() 2012-02-07 18:13:13 +09:00
Trustin Lee
3b31daf8a3 Fix missing copyright headers 2012-02-07 17:26:55 +09:00
Norman Maurer
bad9e83121 Merge pull request #177 from cgbystrom/websocketx-chunkaggregator-fix
Don't require HttpChunkAggregator to be present in pipeline for WS. See #177
2012-02-04 08:37:29 -08:00
Norman Maurer
58e6bec3b1 Merge SPDY support from 3.2 branch. See #176 2012-02-04 17:31:53 +01:00
Carl Byström
f7a4a646f8 Don't require HttpChunkAggregator to be present in pipeline for Web Sockets. 2012-02-04 16:59:04 +01:00
Norman Maurer
6689063eef HttpMessageEncoder should add Header "Transfer-Encoding: chunked"
if HttpMessage.isChunked(). See #171
2012-02-02 15:24:30 +01:00
Trustin Lee
1f6e96ed15 Forward-port the pull request #172 to fix #164 2012-02-02 16:10:28 +09:00
Trustin Lee
cd69bd4e2c Backport the pull request #174 to fix #163 2012-02-02 15:52:06 +09:00
Trustin Lee
c1aa8b4c7b Clean up the new WebSocket package 2012-01-19 13:12:45 +09:00
Trustin Lee
b9b2366361 Fix checkstyle violations / Renaming RXTX -> Rxtx 2012-01-15 01:08:00 +09:00
Trustin Lee
303c1b5f79 Overall cleanup / Add lost old jzlib headers 2012-01-13 17:41:18 +09:00
Trustin Lee
ebfc4513e0 Apply checkstyle to the build
Please note that the build will fail at the moment due to various checkstyle
violations which should be fixed soon
2012-01-11 20:16:14 +09:00
Norman Maurer
999343e8cf Fix possible JavaDoc error in QueryStringEncoder. Type mismatch. See
#139
2012-01-08 21:54:31 +01:00
Trustin Lee
521bf83d0f Issue #141: hashdos security vulnerability in QueryStringDecoder and possibly other components
* Limited maximum number of parameters to 1024 by default and made the
limitation configurable
* QueryStringDecoder is now able to handle an HTTP POST content
2011-12-30 17:58:51 +09:00
Trustin Lee
8663716d38 Issue #60: Make the project multi-module
Split the project into the following modules:
* common
* buffer
* codec
* codec-http
* transport
* transport-*
* handler
* example
* testsuite (integration tests that involve 2+ modules)
* all (does nothing yet, but will make it generate netty.jar)

This commit also fixes the compilation errors with transport-sctp on
non-Linux systems.  It will at least compile without complaints.
2011-12-28 19:44:04 +09:00