diff --git a/lib/Ratchet/Application/WebSocket/App.php b/lib/Ratchet/Application/WebSocket/App.php
index 2a75987..b398d8d 100644
--- a/lib/Ratchet/Application/WebSocket/App.php
+++ b/lib/Ratchet/Application/WebSocket/App.php
@@ -101,14 +101,35 @@ class App implements ApplicationInterface, ConfiguratorInterface {
             return $comp;
         }
 
-        // buffer!
-
-        $msg = $from->WebSocket->version->unframe($msg);
-        if (is_array($msg)) { // temporary
-            $msg = $msg['payload'];
+        if (!isset($from->WebSocket->message)) {
+            $from->WebSocket->message = $from->WebSocket->version->newMessage();
         }
 
-        return $this->prepareCommand($this->_app->onRecv($from, $msg));
+        // There is a frame fragment attatched to the connection, add to it
+        if (!isset($from->WebSocket->frame)) {
+            $from->WebSocket->frame = $from->WebSocket->version->newFrame();
+        }
+
+        $from->WebSocket->frame->addBuffer($msg);
+        if ($from->WebSocket->frame->isCoalesced()) {
+            if ($from->WebSocket->frame->getOpcode() > 2) {
+                throw new \UnexpectedValueException('Control frame support coming soon!');
+            }
+            // Check frame
+            // If is control frame, do your thing
+            // Else, add to message
+            // Control frames (ping, pong, close) can be sent in between a fragmented message
+
+            $from->WebSocket->message->addFrame($from->WebSocket->frame);
+            unset($from->WebSocket->frame);
+        }
+
+        if ($from->WebSocket->message->isCoalesced()) {
+            $cmds = $this->prepareCommand($this->_app->onRecv($from, (string)$from->WebSocket->message));
+            unset($from->WebSocket->message);
+
+            return $cmds;
+        }
     }
 
     public function onClose(Connection $conn) {
@@ -153,7 +174,7 @@ class App implements ApplicationInterface, ConfiguratorInterface {
      * @todo Can/will add more versions later, but perhaps a chain of responsibility, ask each version if they want to handle the request
      */
     protected function getVersion($message) {
-        if (false === strstr($message, "\r\n\r\n")) { // This _could_ fail with Hixie
+        if (false === strstr($message, "\r\n\r\n")) { // This CAN fail with Hixie, depending on the TCP buffer in between
             throw new \UnderflowException;
         }
 
diff --git a/lib/Ratchet/Application/WebSocket/FrameInterface.php b/lib/Ratchet/Application/WebSocket/Version/FrameInterface.php
similarity index 56%
rename from lib/Ratchet/Application/WebSocket/FrameInterface.php
rename to lib/Ratchet/Application/WebSocket/Version/FrameInterface.php
index 5b500e5..3056094 100644
--- a/lib/Ratchet/Application/WebSocket/FrameInterface.php
+++ b/lib/Ratchet/Application/WebSocket/Version/FrameInterface.php
@@ -1,7 +1,18 @@
 <?php
-namespace Ratchet\Protocol\WebSocket;
+namespace Ratchet\Application\WebSocket\Version;
 
 interface FrameInterface {
+    /**
+     * @alias getPayload
+     */
+    function __toString();
+
+    /**
+     * Dunno if I'll use this
+     * Thinking could be used if a control frame?
+     */
+//    function __invoke();
+
     /**
      * @return bool
      */
@@ -9,18 +20,19 @@ interface FrameInterface {
 
     /**
      * @param string
+     * @todo Theoretically, there won't be a buffer overflow (end of frame + start of new frame) - but test later, return a string with overflow here
      */
     function addBuffer($buf);
 
     /**
      * @return bool
      */
-    function isFragment();
+//    function isFragment();
 
     /**
      * @return bool
      */
-    function isFinial();
+    function isFinal();
 
     /**
      * @return bool
@@ -40,7 +52,7 @@ interface FrameInterface {
     /**
      * @return int
      */
-    function getReceivedPayloadLength();
+//    function getReceivedPayloadLength();
 
     /**
      * 32-big string
diff --git a/lib/Ratchet/Application/WebSocket/Version/Hixie76.php b/lib/Ratchet/Application/WebSocket/Version/Hixie76.php
index 8ff0da9..e83e9b4 100644
--- a/lib/Ratchet/Application/WebSocket/Version/Hixie76.php
+++ b/lib/Ratchet/Application/WebSocket/Version/Hixie76.php
@@ -2,6 +2,13 @@
 namespace Ratchet\Application\WebSocket\Version;
 
 /**
+ * FOR THE LOVE OF BEER, PLEASE PLEASE PLEASE DON'T allow the use of this in your application!
+ * Hixie76 is bad for 2 (there's more) reasons:
+ *  1) The handshake is done in HTTP, which includes a key for signing in the body...
+ *     BUT there is no Length defined in the header (as per HTTP spec) so the TCP buffer can't tell when the message is done!
+ *  2) By nature it's insecure.  Google did a test study where they were able to do a
+ *     man-in-the-middle attack on 10%-15% of the people who saw their add who had a browser (currently only Safari) supporting the Hixie76 protocol.
+ *     This was exploited by taking advantage of proxy servers in front of the user who ignored some HTTP headers in the handshake
  * The Hixie76 is currently implemented by Safari
  * Handshake from Andrea Giammarchi (http://webreflection.blogspot.com/2010/06/websocket-handshake-76-simplified.html)
  * @link http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
@@ -34,6 +41,14 @@ class Hixie76 implements VersionInterface {
         ;
     }
 
+    public function newMessage() {
+        return new Hixie76\Message;
+    }
+
+    public function newFrame() {
+        return new Hixie76\Frame;
+    }
+
     public function unframe($message) {
         return substr($message, 1, strlen($message) - 2);
     }
diff --git a/lib/Ratchet/Application/WebSocket/Version/Hixie76/Frame.php b/lib/Ratchet/Application/WebSocket/Version/Hixie76/Frame.php
new file mode 100644
index 0000000..4fcdec8
--- /dev/null
+++ b/lib/Ratchet/Application/WebSocket/Version/Hixie76/Frame.php
@@ -0,0 +1,58 @@
+<?php
+namespace Ratchet\Application\WebSocket\Version\Hixie76;
+use Ratchet\Application\WebSocket\Version\FrameInterface;
+
+/**
+ * This does not entirely follow the protocol to spec, but (mostly) works
+ * Hixie76 probably should not even be supported
+ */
+class Frame implements FrameInterface {
+    /**
+     * @type string
+     */
+    protected $_data = '';
+
+    public function __toString() {
+        return $this->getPayload();
+    }
+
+    public function isCoalesced() {
+        return (boolean)($this->_data[0] == chr(0) && substr($this->_data, -1) == chr(255));
+    }
+
+    public function addBuffer($buf) {
+        $this->_data .= (string)$buf;
+    }
+
+    public function isFinal() {
+        return true;
+    }
+
+    public function isMasked() {
+        return false;
+    }
+
+    public function getOpcode() {
+        return 1;
+    }
+
+    public function getPayloadLength() {
+        if (!$this->isCoalesced()) {
+            throw new \UnderflowException('Not enough of the message has been buffered to determine the length of the payload');
+        }
+
+        return strlen($this->_data) - 2;
+    }
+
+    public function getMaskingKey() {
+        return '';
+    }
+
+    public function getPayload() {
+        if (!$this->isCoalesced()) {
+            return new \UnderflowException('Not enough data buffered to read payload');
+        }
+
+        return substr($this->_data, 1, strlen($this->_data) - 2);
+    }
+}
\ No newline at end of file
diff --git a/lib/Ratchet/Application/WebSocket/Version/Hixie76/Message.php b/lib/Ratchet/Application/WebSocket/Version/Hixie76/Message.php
new file mode 100644
index 0000000..6366c22
--- /dev/null
+++ b/lib/Ratchet/Application/WebSocket/Version/Hixie76/Message.php
@@ -0,0 +1,48 @@
+<?php
+namespace Ratchet\Application\WebSocket\Version\Hixie76;
+use Ratchet\Application\WebSocket\Version\MessageInterface;
+use Ratchet\Application\WebSocket\Version\FrameInterface;
+
+class Message implements MessageInterface {
+    /**
+     * @var Ratchet\Application\WebSocket\Version\FrameInterface
+     */
+    protected $_frame = null;
+
+    public function __toString() {
+        return $this->getPayload();
+    }
+
+    public function isCoalesced() {
+        if (!($this->_frame instanceof FrameInterface)) {
+            return false;
+        }
+
+        return $this->_frame->isCoalesced();
+    }
+
+    public function addFrame(FrameInterface $fragment) {
+        if (null !== $this->_frame) {
+            throw new \OverflowException('Hixie76 does not support multiple framing of messages');
+        }
+
+        $this->_frame = $fragment;
+    }
+
+    public function getOpcode() {
+        // Hixie76 only supported text messages
+        return 1;
+    }
+
+    public function getPayloadLength() {
+        throw new \DomainException('Please sir, may I have some code? (' . __FUNCTION__ . ')');
+    }
+
+    public function getPayload() {
+        if (!$this->isCoalesced()) {
+            throw new \UnderflowException('Message has not been fully buffered yet');
+        }
+
+        return $this->_frame->getPayload();
+    }
+}
\ No newline at end of file
diff --git a/lib/Ratchet/Application/WebSocket/Version/HyBi10.php b/lib/Ratchet/Application/WebSocket/Version/HyBi10.php
index 6077879..e4bba6d 100644
--- a/lib/Ratchet/Application/WebSocket/Version/HyBi10.php
+++ b/lib/Ratchet/Application/WebSocket/Version/HyBi10.php
@@ -5,12 +5,14 @@ use Ratchet\Application\WebSocket\Util\HTTP;
 /**
  * The HyBi-10 version, identified in the headers as version 8, is currently implemented by the latest Chrome and Firefix version
  * @link http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10
+ * @todo Naming...I'm not fond of this naming convention...
  */
 class HyBi10 implements VersionInterface {
     const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
 
     /**
      * @return array
+     * I kept this as an array and combined in App for future considerations...easier to add a subprotol as a key value than edit a string
      */
     public function handshake($message) {
         $headers = HTTP::getHeaders($message);
@@ -25,6 +27,20 @@ class HyBi10 implements VersionInterface {
         );
    }
 
+    /**
+     * @return HyBi10\Message
+     */
+    public function newMessage() {
+        return new HyBi10\Message;
+    }
+
+    /**
+     * @return HyBi10\Frame
+     */
+    public function newFrame() {
+        return new HyBi10\Frame;
+    }
+
     /**
      * Unframe a message received from the client
      * Thanks to @lemmingzshadow for the code on decoding a HyBi-10 frame
diff --git a/lib/Ratchet/Application/WebSocket/Version/HyBi10/Frame.php b/lib/Ratchet/Application/WebSocket/Version/HyBi10/Frame.php
new file mode 100644
index 0000000..5223a96
--- /dev/null
+++ b/lib/Ratchet/Application/WebSocket/Version/HyBi10/Frame.php
@@ -0,0 +1,203 @@
+<?php
+namespace Ratchet\Application\WebSocket\Version\HyBi10;
+use Ratchet\Application\WebSocket\Version\FrameInterface;
+
+class Frame implements FrameInterface {
+    /**
+     * The contents of the frame
+     * @var string
+     */
+    protected $_data = '';
+
+    /**
+     * Number of bytes received from the frame
+     * @var int
+     */
+    public $_bytes_rec = 0;
+
+    /**
+     * Number of bytes in the payload (as per framing protocol)
+     * @var int
+     */
+    protected $_pay_len_def = -1;
+
+    /**
+     * Bit 9-15
+     * @var int
+     */
+    protected $_pay_check = -1;
+
+    public function __toString() {
+        return (string)$this->getPayload();
+    }
+
+    public function isCoalesced() {
+        try {
+            $payload_length = $this->getPayloadLength();
+            $payload_start  = $this->getPayloadStartingByte();
+        } catch (\UnderflowException $e) {
+            return false;
+        }
+
+        return $payload_length + $payload_start === $this->_bytes_rec;        
+    }
+
+    public function addBuffer($buf) {
+        $buf = (string)$buf;
+
+        $this->_data      .= $buf;
+        $this->_bytes_rec += strlen($buf);
+    }
+
+    public function isFinal() {
+        if ($this->_bytes_rec < 1) {
+            throw new \UnderflowException('Not enough bytes received to determine if this is the final frame in message');
+        }
+
+        $fbb = sprintf('%08b', ord($this->_data[0]));
+        return (boolean)(int)$fbb[0];
+    }
+
+    public function isMasked() {
+        if ($this->_bytes_rec < 2) {
+            throw new \UnderflowException("Not enough bytes received ({$this->_bytes_rec}) to determine if mask is set");
+        }
+
+        return (boolean)bindec(substr(sprintf('%08b', ord($this->_data[1])), 0, 1));
+    }
+
+    public function getOpcode() {
+        if ($this->_bytes_rec < 1) {
+            throw new \UnderflowException('Not enough bytes received to determine opcode');
+        }
+
+        return bindec(substr(sprintf('%08b', ord($this->_data[0])), 4, 4));
+    }
+
+    /**
+     * Gets the decimal value of bits 9 (10th) through 15 inclusive
+     * @return int
+     * @throws UnderflowException If the buffer doesn't have enough data to determine this
+     */
+    protected function getFirstPayloadVal() {
+        if ($this->_bytes_rec < 2) {
+            throw new \UnderflowException('Not enough bytes received');
+        }
+
+        return ord($this->_data[1]) & 127;
+    }
+
+    /**
+     * @return int (7|23|71) Number of bits defined for the payload length in the fame
+     * @throws UnderflowException
+     */
+    protected function getNumPayloadBits() {
+        if ($this->_bytes_rec < 2) {
+            throw new \UnderflowException('Not enough bytes received');
+        }
+
+        // By default 7 bits are used to describe the payload length
+        // These are bits 9 (10th) through 15 inclusive
+        $bits = 7;
+
+        // Get the value of those bits
+        $check = $this->getFirstPayloadVal();
+
+        // If the value is 126 the 7 bits plus the next 16 are used to describe the payload length
+        if ($check >= 126) {
+            $bits += 16;
+        }
+
+        // If the value of the initial payload length are is 127 an additional 48 bits are used to describe length 
+        // Note: The documentation specifies the length is to be 63 bits, but I think that's a type and is 64 (16+48)
+        if ($check === 127) {
+            $bits += 48;
+        }
+
+        if (!in_array($bits, array(7, 23, 71))) {
+            throw new \UnexpectedValueException("Malformed frame, invalid payload length provided");
+        }
+
+        return $bits;
+    }
+
+    /**
+     * This just returns the number of bytes used in the frame to describe the payload length (as opposed to # of bits)
+     * @see getNumPayloadBits
+     */
+    protected function getNumPayloadBytes() {
+        return (1 + $this->getNumPayloadBits()) / 8;
+    }
+
+    public function getPayloadLength() {
+        if ($this->_pay_len_def !== -1) {
+            return $this->_pay_len_def;
+        }
+
+        $length_check = $this->getFirstPayloadVal();
+
+        if ($length_check <= 125) {
+            $this->_pay_len_def = $length_check;
+            return $this->getPayloadLength();
+        }
+
+        $byte_length = $this->getNumPayloadBytes();
+        if ($this->_bytes_rec < 1 + $byte_length) {
+            throw new \UnderflowException('Not enough data buffered to determine payload length');
+        }
+
+        $strings = array();
+        for ($i = 2; $i < $byte_length + 1; $i++) {
+            $strings[] = ord($this->_data[$i]);
+        }
+
+        $this->_pay_len_def = bindec(vsprintf(str_repeat('%08b', $byte_length - 1), $strings));
+        return $this->getPayloadLength();
+    }
+
+    public function getMaskingKey() {
+        if (!$this->isMasked()) {
+            return '';
+        }
+
+        $length = 4;
+        $start  = 1 + $this->getNumPayloadBytes();
+
+        if ($this->_bytes_rec < $start + $length) {
+            throw new \UnderflowException('Not enough data buffered to calculate the masking key');
+        }
+
+        return substr($this->_data, $start, $length);
+    }
+
+    public function getPayloadStartingByte() {
+        return 1 + $this->getNumPayloadBytes() + strlen($this->getMaskingKey());
+    }
+
+    public function getPayload() {
+        if (!$this->isCoalesced()) {
+            throw new \UnderflowException('Can not return partial message');
+        }
+
+        $payload = '';
+        $length  = $this->getPayloadLength();
+
+        if ($this->isMasked()) {
+            $mask  = $this->getMaskingKey();
+            $start = $this->getPayloadStartingByte();
+
+            for ($i = 0; $i < $length; $i++) {
+                $payload .= $this->_data[$i + $start] ^ $mask[$i % 4];
+            }
+        } else {
+            $payload = substr($this->_data, $start, $this->getPayloadLength());
+        }
+
+        if (strlen($payload) !== $length) {
+            // Is this possible?  isCoalesced() math _should_ ensure if there is mal-formed data, it would return false
+            throw new \UnexpectedValueException('Payload length does not match expected length');
+        }
+
+        return $payload;
+    }
+}
\ No newline at end of file
diff --git a/lib/Ratchet/Application/WebSocket/Version/HyBi10/Message.php b/lib/Ratchet/Application/WebSocket/Version/HyBi10/Message.php
new file mode 100644
index 0000000..ccca59f
--- /dev/null
+++ b/lib/Ratchet/Application/WebSocket/Version/HyBi10/Message.php
@@ -0,0 +1,63 @@
+<?php
+namespace Ratchet\Application\WebSocket\Version\HyBi10;
+use Ratchet\Application\WebSocket\Version\MessageInterface;
+use Ratchet\Application\WebSocket\Version\FrameInterface;
+
+class Message implements MessageInterface {
+    /**
+     * @var SplDoublyLinkedList
+     */
+    protected $_frames;
+
+    public function __construct() {
+        $this->_frames = new \SplDoublyLinkedList;
+    }
+
+    public function __toString() {
+        return $this->getPayload();
+    }
+
+    public function isCoalesced() {
+        if (count($this->_frames) == 0) {
+            return false;
+        }
+
+        $last = $this->_frames->top();
+
+        return ($last->isCoalesced() && $last->isFinal());
+    }
+
+    /**
+     * @todo Should I allow addFrame if the frame is not coalesced yet?  I believe I'm assuming this class will only receive fully formed frame messages
+     * @todo Also, I should perhaps check the type...control frames (ping/pong/close) are not to be considered part of a message
+     */
+    public function addFrame(FrameInterface $fragment) {
+        $this->_frames->push($fragment);
+    }
+
+    public function getOpcode() {
+        if (count($this->_frames) == 0) {
+            throw new \UnderflowException('No frames have been added to this message');
+        }
+
+        return $this->_frames->bottom()->getOpcode();
+    }
+
+    public function getPayloadLength() {
+        throw new \DomainException('Please sir, may I have some code? (' . __FUNCTION__ . ')');
+    }
+
+    public function getPayload() {
+        if (!$this->isCoalesced()) {
+            throw new \UnderflowMessage('Message has not been put back together yet');
+        }
+
+        $buffer = '';
+
+        foreach ($this->_frames as $frame) {
+            $buffer .= (string)$frame;
+        }
+
+        return $buffer;
+    }
+}
\ No newline at end of file
diff --git a/lib/Ratchet/Application/WebSocket/MessageInterface.php b/lib/Ratchet/Application/WebSocket/Version/MessageInterface.php
similarity index 74%
rename from lib/Ratchet/Application/WebSocket/MessageInterface.php
rename to lib/Ratchet/Application/WebSocket/Version/MessageInterface.php
index 9053fb2..57cba5d 100644
--- a/lib/Ratchet/Application/WebSocket/MessageInterface.php
+++ b/lib/Ratchet/Application/WebSocket/Version/MessageInterface.php
@@ -1,10 +1,15 @@
 <?php
-namespace Ratchet\Protocol\WebSocket;
+namespace Ratchet\Application\WebSocket\Version;
 
 /**
  * @todo Consider making parent interface/composite for Message/Frame with (isCoalesced, getOpcdoe, getPayloadLength, getPayload)
  */
 interface MessageInterface {
+    /**
+     * @alias getPayload
+     */
+    function __toString();
+
     /**
      * @return bool
      */
@@ -13,7 +18,7 @@ interface MessageInterface {
     /**
      * @param FragmentInterface
      */
-    function addFragment(FragmentInterface $fragment);
+    function addFrame(FrameInterface $fragment);
 
     /**
      * @return int
diff --git a/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php b/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php
index d671b22..4d4df15 100644
--- a/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php
+++ b/lib/Ratchet/Application/WebSocket/Version/VersionInterface.php
@@ -13,11 +13,22 @@ interface VersionInterface {
      */
     function handshake($message);
 
+    /**
+     * @return MessageInterface
+     */
+    function newMessage();
+
+    /**
+     * @return FrameInterface
+     */
+    function newFrame();
+
     /**
      * Get a framed message as per the protocol and return the decoded message
      * @param string
      * @return string
      * @todo Return a frame object with message, type, masked?
+     * @deprecated
      */
     function unframe($message);
 
diff --git a/tests/Ratchet/Tests/Application/WebSocket/Version/HyBi10/FrameTest.php b/tests/Ratchet/Tests/Application/WebSocket/Version/HyBi10/FrameTest.php
new file mode 100644
index 0000000..0dbd13b
--- /dev/null
+++ b/tests/Ratchet/Tests/Application/WebSocket/Version/HyBi10/FrameTest.php
@@ -0,0 +1,256 @@
+<?php
+namespace Ratchet\Tests\Application\WebSocket\Version\HyBi10;
+use Ratchet\Application\WebSocket\Version\HyBi10\Frame;
+
+/**
+ * @covers Ratchet\Application\WebSocket\Version\HyBi10\Frame
+ * @todo getMaskingKey, getPayloadStartingByte don't have tests yet
+ * @todo Could use some clean up in general, I had to rush to fix a bug for a deadline, sorry.
+ */
+class FrameTest extends \PHPUnit_Framework_TestCase {
+    protected $_firstByteFinText    = '10000001';
+    protected $_secondByteMaskedSPL = '11111101';
+
+    protected $_frame;
+
+    protected $_packer;
+
+    public function setUp() {
+        $this->_frame = new Frame;
+    }
+
+    protected static function convert($in) {
+        return pack('C', bindec($in));
+    }
+
+    /**
+     * This is a data provider
+     * @param string The UTF8 message
+     * @param string The WebSocket framed message, then base64_encoded
+     */
+    public static function UnframeMessageProvider() {
+        return array(
+            array('Hello World!',                'gYydAIfa1WXrtvIg0LXvbOP7')
+          , array('!@#$%^&*()-=_+[]{}\|/.,<>`~', 'gZv+h96r38f9j9vZ+IHWrvOWoayF9oX6gtfRqfKXwOeg')
+          , array('ಠ_ಠ',                         'gYfnSpu5B/g75gf4Ow==')
+          , array("The quick brown fox jumps over the lazy dog.  All work and no play makes Chris a dull boy.  I'm trying to get past 128 characters for a unit test here...", 'gf4Amahb14P8M7Kj2S6+4MN7tfHHLLmjzjSvo8IuuvPbe7j1zSn398A+9+/JIa6jzDSwrYh7lu/Ee6Ds2jD34sY/9+3He6fvySL37skwsvCIGL/xwSj34og/ou/Ee7Xs0XX3o+F8uqPcKa7qxjz398d7sObce6fi2y/3sppj9+DAOqXiyy+y8dt7sezae7aj3TW+94gvsvDce7/m2j75rYY=')
+        );
+    }
+
+    /**
+     * A data provider for testing the first byte of a WebSocket frame
+     * @param bool Given, is the byte indicate this is the final frame
+     * @param int Given, what is the expected opcode
+     * @param string of 0|1 Each character represents a bit in the byte
+     */
+    public static function firstByteProvider() {
+        return array(
+            array(false, 8,  '00001000')
+          , array(true,  10, '10001010')
+          , array(false, 15, '00001111')
+          , array(true,   1, '10000001')
+          , array(true,  15, '11111111')
+        );
+    }
+
+    public function testUnderflowExceptionFromAllTheMethodsMimickingBuffering() {
+        return $this->markTestIncomplete();
+
+        $this->expectException('\UnderflowException');
+    }
+
+    /**
+     * @dataProvider firstByteProvider
+     */
+    public function testFinCodeFromBits($fin, $opcode, $bin) {
+        $this->_frame->addBuffer(static::convert($bin));
+        $this->assertEquals($fin, $this->_frame->isFinal());
+    }
+
+    /**
+     * @dataProvider UnframeMessageProvider
+     */
+    public function testFinCodeFromFullMessage($msg, $encoded) {
+        $this->_frame->addBuffer(base64_decode($encoded));
+        $this->assertTrue($this->_frame->isFinal());
+    }
+
+    /**
+     * @dataProvider firstByteProvider
+     */
+    public function testOpcodeFromBits($fin, $opcode, $bin) {
+        $this->_frame->addBuffer(static::convert($bin));
+        $this->assertEquals($opcode, $this->_frame->getOpcode());
+    }
+
+    /**
+     * @dataProvider UnframeMessageProvider
+     */
+    public function testOpcodeFromFullMessage($msg, $encoded) {
+        $this->_frame->addBuffer(base64_decode($encoded));
+        $this->assertEquals(1, $this->_frame->getOpcode());
+    }
+
+    public static function payloadLengthDescriptionProvider() {
+        return array(
+            array(7,  '01110101')
+          , array(7,  '01111101')
+          , array(23, '01111110')
+          , array(71, '01111111')
+          , array(7,  '00000000') // Should this throw an exception?  Can a payload be empty?
+          , array(7,  '00000001')
+        );
+    }
+
+    /**
+     * @dataProvider payloadLengthDescriptionProvider
+     */
+    public function testFirstPayloadDesignationValue($bits, $bin) {
+        $this->_frame->addBuffer(static::convert($this->_firstByteFinText));
+        $this->_frame->addBuffer(static::convert($bin));
+
+        $ref = new \ReflectionClass($this->_frame);
+        $cb  = $ref->getMethod('getFirstPayloadVal');
+        $cb->setAccessible(true);
+
+        $this->assertEquals(bindec($bin), $cb->invoke($this->_frame));
+    }
+
+    /**
+     * @dataProvider payloadLengthDescriptionProvider
+     */
+    public function testDetermineHowManyBitsAreUsedToDescribePayload($expected_bits, $bin) {
+        $this->_frame->addBuffer(static::convert($this->_firstByteFinText));
+        $this->_frame->addBuffer(static::convert($bin));
+
+        $ref = new \ReflectionClass($this->_frame);
+        $cb  = $ref->getMethod('getNumPayloadBits');
+        $cb->setAccessible(true);
+
+        $this->assertEquals($expected_bits, $cb->invoke($this->_frame));
+    }
+
+    public function secondByteProvider() {
+        return array(
+            array(true,   1, '10000001')
+          , array(false,  1, '00000001')
+          , array(true, 125, $this->_secondByteMaskedSPL)
+        );
+    }
+
+    /**
+     * @dataProvider secondByteProvider
+     */
+    public function testIsMaskedReturnsExpectedValue($masked, $payload_length, $bin) {
+        $this->_frame->addBuffer(static::convert($this->_firstByteFinText));
+        $this->_frame->addBuffer(static::convert($bin));
+
+        $this->assertEquals($masked, $this->_frame->isMasked());
+    }
+
+    /**
+     * @dataProvider UnframeMessageProvider
+     */
+    public function testIsMaskedFromFullMessage($msg, $encoded) {
+        $this->_frame->addBuffer(base64_decode($encoded));
+        $this->assertTrue($this->_frame->isMasked());
+    }
+
+    /**
+     * @dataProvider secondByteProvider
+     */
+    public function testGetPayloadLengthWhenOnlyFirstFrameIsUsed($masked, $payload_length, $bin) {
+        $this->_frame->addBuffer(static::convert($this->_firstByteFinText));
+        $this->_frame->addBuffer(static::convert($bin));
+
+        $this->assertEquals($payload_length, $this->_frame->getPayloadLength());
+    }
+
+    /**
+     * @dataProvider UnframeMessageProvider
+     * @todo Not yet testing when second additional payload length descriptor
+     */
+    public function testGetPayloadLengthFromFullMessage($msg, $encoded) {
+        $this->_frame->addBuffer(base64_decode($encoded));
+        $this->assertEquals(strlen($msg), $this->_frame->getPayloadLength());
+    }
+
+    protected function generateMask() {
+    }
+
+    protected function getPacker() {
+        return function($str) {
+            $packed = '';
+            for ($i = 0, $len = strlen($str); $i < $len; $i++) {
+                $packed .= pack('C', ord($str[$i]));
+//                $packed .= pack("c", ord(substr($str, $i, 1)));
+            }
+
+            return $packed;
+        };
+    }
+
+    public function maskingKeyProvider() {
+        $packer = $this->getPacker();
+        $mask_generator = function() use ($packer) {
+            $characters = 'abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 !@#$%^&*() -=_+`~[]{}\|/,.<>';
+            $mask = '';
+
+            for ($i = 0; $i < 32; $i++) {
+                $mask .= $characters[mt_rand(0, strlen($characters) -1)];
+            }
+
+            return array($mask, $packer($mask));
+        };
+
+        return array(
+            $mask_generator()
+          , $mask_generator()
+          , $mask_generator()
+        );
+    }
+
+    /**
+     * @dataProvider maskingKeyProvider
+     * @todo I I wrote the dataProvider incorrectly, skpping for now
+     */
+    public function testGetMaskingKey($mask, $bin) {
+        return $this->markTestIncomplete("I'm not packing the data properly in the provider, I think");
+
+        $this->_frame->addBuffer(static::convert($this->_firstByteFinText));
+        $this->_frame->addBuffer(static::convert($this->_secondByteMaskedSPL));
+        $this->_frame->addBuffer($bin);
+
+        $this->assertEquals($mask, $this->_frame->getMaskingKey());
+    }
+
+    /**
+     * @dataProvider UnframeMessageProvider
+     * @todo Move this test to bottom as it requires all methods of the class
+     */
+    public function testUnframeFullMessage($unframed, $base_framed) {
+        $this->_frame->addBuffer(base64_decode($base_framed));
+        $this->assertEquals($unframed, $this->_frame->getPayload());
+    }
+
+    public static function messageFragmentProvider() {
+        return array(
+            array(false, '', '', '', '', '')
+        );
+    }
+
+    /**
+     * @dataProvider messageFragmentProvider
+     */
+    public function testCheckPiecingTogetherMessage($coalesced, $first_bin, $secnd_bin, $mask, $payload1, $payload2) {
+        return $this->markTestIncomplete('Ran out of time, had to attend to something else, come finish me!');
+
+        $this->_frame->addBuffer(static::convert($first_bin));
+        $this->_frame->addBuffer(static::convert($second_bin));
+        // mask?
+//        $this->_frame->addBuffer(
+//        $this->_frame->addBuffer(
+
+        $this->assertEquals($coalesced, $this->_frame->isCoalesced());
+    }
+}
\ No newline at end of file