[Pkg-javascript-commits] [node-utf8] 01/06: Imported Upstream version 2.0.0
Sebastiaan Couwenberg
sebastic at moszumanska.debian.org
Fri Apr 3 14:12:35 UTC 2015
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository node-utf8.
commit 172cf1295aae986c92556c2cfc9c3bb5344638be
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Mon Mar 30 00:16:21 2015 +0200
Imported Upstream version 2.0.0
---
.gitattributes | 2 +
.gitignore | 20 +
.travis.yml | 19 +
Gruntfile.js | 72 +++
LICENSE-GPL.txt | 278 +++++++++++
LICENSE-MIT.txt | 20 +
README.md | 119 +++++
bower.json | 14 +
component.json | 16 +
coverage/index.html | 333 +++++++++++++
coverage/prettify.css | 1 +
coverage/prettify.js | 1 +
coverage/utf8.js/index.html | 333 +++++++++++++
coverage/utf8.js/utf8.js.html | 1028 +++++++++++++++++++++++++++++++++++++++++
package.json | 49 ++
tests/generate-test-data.py | 47 ++
tests/index.html | 35 ++
tests/tests.js | 242 ++++++++++
utf8.js | 239 ++++++++++
19 files changed, 2868 insertions(+)
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..0a91f75
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Automatically normalize line endings for all text-based files
+* text=auto
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c4b384e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,20 @@
+# Generated test data file (> 100 MB)
+tests/data.json
+
+# JSON version of coverage report
+coverage/coverage.json
+
+# Installed npm modules
+node_modules
+
+# Folder view configuration files
+.DS_Store
+Desktop.ini
+
+# Thumbnail cache files
+._*
+Thumbs.db
+
+# Files that might appear on external disks
+.Spotlight-V100
+.Trashes
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..58fe013
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,19 @@
+language: node_js
+node_js:
+ - "0.10"
+ - "0.8"
+before_script:
+ - "npm install -g grunt-cli"
+ # Narwhal uses a hardcoded path to openjdk v6, so use that version
+ - "sudo apt-get update -qq"
+ - "sudo apt-get install -qq openjdk-6-jre"
+ - "PACKAGE=rhino1_7R3; wget http://ftp.mozilla.org/pub/mozilla.org/js/$PACKAGE.zip && sudo unzip $PACKAGE -d /opt/ && rm $PACKAGE.zip"
+ - "PACKAGE=rhino1_7R3; echo -e '#!/bin/sh\\njava -jar /opt/'$PACKAGE'/js.jar $@' | sudo tee /usr/local/bin/rhino && sudo chmod +x /usr/local/bin/rhino"
+ - "PACKAGE=ringojs-0.9; wget http://ringojs.org/downloads/$PACKAGE.zip && sudo unzip $PACKAGE -d /opt/ && rm $PACKAGE.zip"
+ - "PACKAGE=ringojs-0.9; sudo ln -s /opt/$PACKAGE/bin/ringo /usr/local/bin/ringo && sudo chmod +x /usr/local/bin/ringo"
+ - "PACKAGE=v0.3.2; wget https://github.com/280north/narwhal/archive/$PACKAGE.zip && sudo unzip $PACKAGE -d /opt/ && rm $PACKAGE.zip"
+ - "PACKAGE=narwhal-0.3.2; sudo ln -s /opt/$PACKAGE/bin/narwhal /usr/local/bin/narwhal && sudo chmod +x /usr/local/bin/narwhal"
+ # If the enviroment stores rt.jar in a different directory, find it and symlink the directory
+ - "PREFIX=/usr/lib/jvm; if [ ! -d $PREFIX/java-6-openjdk ]; then for d in $PREFIX/java-6-openjdk-*; do if [ -e $d/jre/lib/rt.jar ]; then sudo ln -s $d $PREFIX/java-6-openjdk; break; fi; done; fi"
+script:
+ "grunt ci"
diff --git a/Gruntfile.js b/Gruntfile.js
new file mode 100644
index 0000000..6d5a6d1
--- /dev/null
+++ b/Gruntfile.js
@@ -0,0 +1,72 @@
+module.exports = function(grunt) {
+
+ grunt.initConfig({
+ 'shell': {
+ 'options': {
+ 'stdout': true,
+ 'stderr': true,
+ 'failOnError': true
+ },
+ 'generate-test-data': { // Only when needed
+ 'command': 'if [ ! -f data.json ]; then echo python generate-test-data.py; fi',
+ 'options': {
+ 'execOptions': {
+ 'cwd': 'tests'
+ }
+ }
+ },
+ 'cover': {
+ 'command': 'istanbul cover --report "html" --verbose --dir "coverage" "tests/tests.js"; istanbul report --root "coverage" --format "html"'
+ },
+ 'test-narwhal': {
+ 'command': 'echo "Testing in Narwhal..."; export NARWHAL_OPTIMIZATION=-1; narwhal "tests/tests.js"'
+ },
+ 'test-phantomjs': {
+ 'command': 'echo "Testing in PhantomJS..."; phantomjs "tests/tests.js"'
+ },
+ // Rhino 1.7R4 has a bug that makes it impossible to test in.
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=775566
+ // To test, use Rhino 1.7R3, or wait (heh) for the 1.7R5 release.
+ 'test-rhino': {
+ 'command': 'echo "Testing in Rhino..."; rhino -opt -1 "tests.js"',
+ 'options': {
+ 'execOptions': {
+ 'cwd': 'tests'
+ }
+ }
+ },
+ 'test-ringo': {
+ 'command': 'echo "Testing in Ringo..."; ringo -o -1 "tests/tests.js"'
+ },
+ 'test-node': {
+ 'command': 'echo "Testing in Node..."; node "tests/tests.js" --extended'
+ },
+ 'test-browser': {
+ 'command': 'echo "Testing in a browser..."; open "tests/index.html"'
+ }
+ }
+ });
+
+ grunt.loadNpmTasks('grunt-shell');
+
+ grunt.registerTask('cover', 'shell:cover');
+ grunt.registerTask('ci', [
+ 'shell:generate-test-data',
+ 'shell:test-narwhal',
+ 'shell:test-phantomjs',
+ 'shell:test-rhino',
+ 'shell:test-ringo',
+ 'shell:test-node',
+ ]);
+ grunt.registerTask('test', [
+ 'shell:generate-test-data',
+ 'ci',
+ 'shell:test-browser'
+ ]);
+
+ grunt.registerTask('default', [
+ 'shell:test-node',
+ 'cover'
+ ]);
+
+};
diff --git a/LICENSE-GPL.txt b/LICENSE-GPL.txt
new file mode 100644
index 0000000..11dddd0
--- /dev/null
+++ b/LICENSE-GPL.txt
@@ -0,0 +1,278 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
diff --git a/LICENSE-MIT.txt b/LICENSE-MIT.txt
new file mode 100644
index 0000000..97067e5
--- /dev/null
+++ b/LICENSE-MIT.txt
@@ -0,0 +1,20 @@
+Copyright Mathias Bynens <http://mathiasbynens.be/>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2362b66
--- /dev/null
+++ b/README.md
@@ -0,0 +1,119 @@
+# utf8.js [![Build status](https://travis-ci.org/mathiasbynens/utf8.js.png?branch=master)](https://travis-ci.org/mathiasbynens/utf8.js) [![Dependency status](https://gemnasium.com/mathiasbynens/utf8.js.png)](https://gemnasium.com/mathiasbynens/utf8.js)
+
+_utf8.js_ is a well-tested UTF-8 encoder/decoder written in JavaScript. Unlike many other JavaScript solutions, it is designed to be a _proper_ UTF-8 encoder/decoder: it can encode/decode any given Unicode code point, including astral symbols and unpaired surrogates.
+
+Feel free to fork if you see possible improvements!
+
+## Installation
+
+Via [npm](http://npmjs.org/):
+
+```bash
+npm install utf8
+```
+
+Via [Bower](http://bower.io/):
+
+```bash
+bower install utf8
+```
+
+Via [Component](https://github.com/component/component):
+
+```bash
+component install mathiasbynens/utf8.js
+```
+
+In a browser:
+
+```html
+<script src="utf8.js"></script>
+```
+
+In [Narwhal](http://narwhaljs.org/), [Node.js](http://nodejs.org/), and [RingoJS ≥ v0.8.0](http://ringojs.org/):
+
+```js
+var utf8 = require('utf8');
+```
+
+In [Rhino](http://www.mozilla.org/rhino/):
+
+```js
+load('utf8.js');
+```
+
+Using an AMD loader like [RequireJS](http://requirejs.org/):
+
+```js
+require(
+ {
+ 'paths': {
+ 'utf8': 'path/to/utf8'
+ }
+ },
+ ['utf8'],
+ function(utf8) {
+ console.log(utf8);
+ }
+);
+```
+
+## API
+
+### `utf8.encode(string)`
+
+Encodes any given JavaScript string (`string`) as UTF-8, and returns the UTF-8-encoded version of the string.
+
+```js
+// U+00A9 COPYRIGHT SIGN; see http://codepoints.net/U+00A9
+utf8.encode('\xA9');
+// → '\xC2\xA9'
+// U+10001 LINEAR B SYLLABLE B038 E; see http://codepoints.net/U+10001
+utf8.encode('\uD800\uDC01');
+// → '\xF0\x90\x80\x81'
+```
+
+### `utf8.decode(byteString)`
+
+Encodes any given UTF-8-encoded string (`byteString`) as UTF-8, and returns the UTF-8-decoded version of the string. It throws an error when malformed UTF-8 is detected.
+
+```js
+utf8.decode('\xC2\xA9');
+// → '\xA9'
+
+utf8.decode('\xF0\x90\x80\x81');
+// → '\uD800\uDC01'
+// → U+10001 LINEAR B SYLLABLE B038 E
+```
+
+### `utf8.version`
+
+A string representing the semantic version number.
+
+## Support
+
+utf8.js has been tested in at least Chrome 27-29, Firefox 3-22, Safari 4-6, Opera 10-12, IE 6-10, Node.js v0.10.0, Narwhal 0.3.2, RingoJS 0.8-0.9, PhantomJS 1.9.0, and Rhino 1.7RC4.
+
+## Unit tests & code coverage
+
+After cloning this repository, run `npm install` to install the dependencies needed for development and testing. You may want to install Istanbul _globally_ using `npm install istanbul -g`.
+
+Once that’s done, you can run the unit tests in Node using `npm test` or `node tests/tests.js`. To run the tests in Rhino, Ringo, Narwhal, PhantomJS, and web browsers as well, use `grunt test`.
+
+To generate [the code coverage report](http://rawgithub.com/mathiasbynens/utf8.js/master/coverage/utf8.js/utf8.js.html), use `grunt cover`.
+
+## FAQ
+
+### Why is the first release named v2.0.0? Haven’t you heard of [semantic versioning](http://semver.org/)?
+
+Long before utf8.js was created, the `utf8` module on npm was registered and used by another (slightly buggy) library. @ryanmcgrath was kind enough to give me access to the `utf8` package on npm when I told him about utf8.js. Since there has already been a v1.0.0 release of the old library, and to avoid breaking backwards compatibility with projects that rely on the `utf8` npm package, I decided the tag the first release of utf8.js as v2.0.0 and take it from there.
+
+## Author
+
+| [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](http://twitter.com/mathias "Follow @mathias on Twitter") |
+|---|
+| [Mathias Bynens](http://mathiasbynens.be/) |
+
+## License
+
+utf8.js is dual licensed under the [MIT](http://mths.be/mit) and [GPL](http://mths.be/gpl) licenses.
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..fe8fa72
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,14 @@
+{
+ "name": "utf8",
+ "version": "2.0.0",
+ "main": "utf8.js",
+ "ignore": [
+ "coverage",
+ "tests",
+ ".*",
+ "component.json",
+ "Gruntfile.js",
+ "node_modules",
+ "package.json"
+ ]
+}
diff --git a/component.json b/component.json
new file mode 100644
index 0000000..5165d4f
--- /dev/null
+++ b/component.json
@@ -0,0 +1,16 @@
+{
+ "name": "utf8",
+ "version": "2.0.0",
+ "description": "A well-tested UTF-8 encoder/decoder written in JavaScript.",
+ "repo": "mathiasbynens/utf8.js",
+ "license": "MIT/GPL",
+ "scripts": [
+ "utf8.js"
+ ],
+ "keywords": [
+ "charset",
+ "encoding",
+ "unicode",
+ "utf8"
+ ]
+}
diff --git a/coverage/index.html b/coverage/index.html
new file mode 100644
index 0000000..68f3574
--- /dev/null
+++ b/coverage/index.html
@@ -0,0 +1,333 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <title>Code coverage report for All files</title>
+ <meta charset="utf-8">
+
+ <link rel="stylesheet" href="prettify.css">
+
+ <style>
+ body, html {
+ margin:0; padding: 0;
+ }
+ body {
+ font-family: Helvetica Neue, Helvetica,Arial;
+ font-size: 10pt;
+ }
+ div.header, div.footer {
+ background: #eee;
+ padding: 1em;
+ }
+ div.header {
+ z-index: 100;
+ position: fixed;
+ top: 0;
+ border-bottom: 1px solid #666;
+ width: 100%;
+ }
+ div.footer {
+ border-top: 1px solid #666;
+ }
+ div.body {
+ margin-top: 10em;
+ }
+ div.meta {
+ font-size: 90%;
+ text-align: center;
+ }
+ h1, h2, h3 {
+ font-weight: normal;
+ }
+ h1 {
+ font-size: 12pt;
+ }
+ h2 {
+ font-size: 10pt;
+ }
+ pre {
+ font-family: Consolas, Menlo, Monaco, monospace;
+ margin: 0;
+ padding: 0;
+ line-height: 14px;
+ font-size: 14px;
+ -moz-tab-size: 2;
+ -o-tab-size: 2;
+ tab-size: 2;
+ }
+
+ div.path { font-size: 110%; }
+ div.path a:link, div.path a:visited { color: #000; }
+ table.coverage { border-collapse: collapse; margin:0; padding: 0 }
+
+ table.coverage td {
+ margin: 0;
+ padding: 0;
+ color: #111;
+ vertical-align: top;
+ }
+ table.coverage td.line-count {
+ width: 50px;
+ text-align: right;
+ padding-right: 5px;
+ }
+ table.coverage td.line-coverage {
+ color: #777 !important;
+ text-align: right;
+ border-left: 1px solid #666;
+ border-right: 1px solid #666;
+ }
+
+ table.coverage td.text {
+ }
+
+ table.coverage td span.cline-any {
+ display: inline-block;
+ padding: 0 5px;
+ width: 40px;
+ }
+ table.coverage td span.cline-neutral {
+ background: #eee;
+ }
+ table.coverage td span.cline-yes {
+ background: #b5d592;
+ color: #999;
+ }
+ table.coverage td span.cline-no {
+ background: #fc8c84;
+ }
+
+ .cstat-yes { color: #111; }
+ .cstat-no { background: #fc8c84; color: #111; }
+ .fstat-no { background: #ffc520; color: #111 !important; }
+ .cbranch-no { background: yellow !important; color: #111; }
+ .missing-if-branch {
+ display: inline-block;
+ margin-right: 10px;
+ position: relative;
+ padding: 0 4px;
+ background: black;
+ color: yellow;
+ xtext-decoration: line-through;
+ }
+ .missing-if-branch .typ {
+ color: inherit !important;
+ }
+
+ .entity, .metric { font-weight: bold; }
+ .metric { display: inline-block; border: 1px solid #333; padding: 0.3em; background: white; }
+ .metric small { font-size: 80%; font-weight: normal; color: #666; }
+
+ div.coverage-summary table { border-collapse: collapse; margin: 3em; font-size: 110%; }
+ div.coverage-summary td, div.coverage-summary table th { margin: 0; padding: 0.25em 1em; border-top: 1px solid #666; border-bottom: 1px solid #666; }
+ div.coverage-summary th { text-align: left; border: 1px solid #666; background: #eee; font-weight: normal; }
+ div.coverage-summary th.file { border-right: none !important; }
+ div.coverage-summary th.pic { border-left: none !important; text-align: right; }
+ div.coverage-summary th.pct { border-right: none !important; }
+ div.coverage-summary th.abs { border-left: none !important; text-align: right; }
+ div.coverage-summary td.pct { text-align: right; border-left: 1px solid #666; }
+ div.coverage-summary td.abs { text-align: right; font-size: 90%; color: #444; border-right: 1px solid #666; }
+ div.coverage-summary td.file { text-align: right; border-left: 1px solid #666; white-space: nowrap; }
+ div.coverage-summary td.pic { min-width: 120px !important; }
+ div.coverage-summary a:link { text-decoration: none; color: #000; }
+ div.coverage-summary a:visited { text-decoration: none; color: #333; }
+ div.coverage-summary a:hover { text-decoration: underline; }
+ div.coverage-summary tfoot td { border-top: 1px solid #666; }
+
+ div.coverage-summary .yui3-datatable-sort-indicator, div.coverage-summary .dummy-sort-indicator {
+ height: 10px;
+ width: 7px;
+ display: inline-block;
+ margin-left: 0.5em;
+ }
+ div.coverage-summary .yui3-datatable-sort-indicator {
+ background: url("http://yui.yahooapis.com/3.6.0/build/datatable-sort/assets/skins/sam/sort-arrow-sprite.png") no-repeat scroll 0 0 transparent;
+ }
+ div.coverage-summary .yui3-datatable-sorted .yui3-datatable-sort-indicator {
+ background-position: 0 -20px;
+ }
+ div.coverage-summary .yui3-datatable-sorted-desc .yui3-datatable-sort-indicator {
+ background-position: 0 -10px;
+ }
+
+ .high { background: #b5d592 !important; }
+ .medium { background: #ffe87c !important; }
+ .low { background: #fc8c84 !important; }
+
+ span.cover-fill, span.cover-empty {
+ display:inline-block;
+ border:1px solid #444;
+ background: white;
+ height: 12px;
+ }
+ span.cover-fill {
+ background: #ccc;
+ border-right: 1px solid #444;
+ }
+ span.cover-empty {
+ background: white;
+ border-left: none;
+ }
+ span.cover-full {
+ border-right: none !important;
+ }
+ pre.prettyprint {
+ border: none !important;
+ padding: 0 !important;
+ margin: 0 !important;
+ }
+ .com { color: #999 !important; }
+ </style>
+</head>
+<body>
+<div class="header high">
+ <h1>Code coverage report for <span class="entity">All files</span></h1>
+ <h2>
+
+ Statements: <span class="metric">92.31% <small>(120 / 130)</small></span>
+
+
+ Branches: <span class="metric">78.79% <small>(52 / 66)</small></span>
+
+
+ Functions: <span class="metric">90% <small>(9 / 10)</small></span>
+
+
+ Lines: <span class="metric">92.31% <small>(120 / 130)</small></span>
+
+ </h2>
+ <div class="path"></div>
+</div>
+<div class="body">
+<div class="coverage-summary">
+<table>
+<thead>
+<tr>
+ <th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
+ <th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
+ <th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
+ <th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
+ <th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
+ <th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
+ <th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
+ <th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
+ <th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
+ <th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
+</tr>
+</thead>
+<tbody><tr>
+ <td class="file high" data-value="utf8.js/"><a href="utf8.js/index.html">utf8.js/</a></td>
+ <td data-value="92.31" class="pic high"><span class="cover-fill" style="width: 92px;"></span><span class="cover-empty" style="width:8px;"></span></td>
+ <td data-value="92.31" class="pct high">92.31%</td>
+ <td data-value="130" class="abs high">(120 / 130)</td>
+ <td data-value="78.79" class="pct medium">78.79%</td>
+ <td data-value="66" class="abs medium">(52 / 66)</td>
+ <td data-value="90" class="pct high">90%</td>
+ <td data-value="10" class="abs high">(9 / 10)</td>
+ <td data-value="92.31" class="pct high">92.31%</td>
+ <td data-value="130" class="abs high">(120 / 130)</td>
+ </tr>
+
+</tbody>
+</table>
+</div>
+</div>
+<div class="footer">
+ <div class="meta">Generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Thu Jun 20 2013 14:00:05 GMT+0200 (CEST)</div>
+</div>
+
+<script src="prettify.js"></script>
+
+<script src="http://yui.yahooapis.com/3.6.0/build/yui/yui-min.js"></script>
+<script>
+
+ YUI().use('datatable', function (Y) {
+
+ var formatters = {
+ pct: function (o) {
+ o.className += o.record.get('classes')[o.column.key];
+ try {
+ return o.value.toFixed(2) + '%';
+ } catch (ex) { return o.value + '%'; }
+ },
+ html: function (o) {
+ o.className += o.record.get('classes')[o.column.key];
+ return o.record.get(o.column.key + '_html');
+ }
+ },
+ defaultFormatter = function (o) {
+ o.className += o.record.get('classes')[o.column.key];
+ return o.value;
+ };
+
+ function getColumns(theadNode) {
+ var colNodes = theadNode.all('tr th'),
+ cols = [],
+ col;
+ colNodes.each(function (colNode) {
+ col = {
+ key: colNode.getAttribute('data-col'),
+ label: colNode.get('innerHTML') || ' ',
+ sortable: !colNode.getAttribute('data-nosort'),
+ className: colNode.getAttribute('class'),
+ type: colNode.getAttribute('data-type'),
+ allowHTML: colNode.getAttribute('data-html') === 'true' || colNode.getAttribute('data-fmt') === 'html'
+ };
+ col.formatter = formatters[colNode.getAttribute('data-fmt')] || defaultFormatter;
+ cols.push(col);
+ });
+ return cols;
+ }
+
+ function getRowData(trNode, cols) {
+ var tdNodes = trNode.all('td'),
+ i,
+ row = { classes: {} },
+ node,
+ name;
+ for (i = 0; i < cols.length; i += 1) {
+ name = cols[i].key;
+ node = tdNodes.item(i);
+ row[name] = node.getAttribute('data-value') || node.get('innerHTML');
+ row[name + '_html'] = node.get('innerHTML');
+ row.classes[name] = node.getAttribute('class');
+ //Y.log('Name: ' + name + '; Value: ' + row[name]);
+ if (cols[i].type === 'number') { row[name] = row[name] * 1; }
+ }
+ //Y.log(row);
+ return row;
+ }
+
+ function getData(tbodyNode, cols) {
+ var data = [];
+ tbodyNode.all('tr').each(function (trNode) {
+ data.push(getRowData(trNode, cols));
+ });
+ return data;
+ }
+
+ function replaceTable(node) {
+ if (!node) { return; }
+ var cols = getColumns(node.one('thead')),
+ data = getData(node.one('tbody'), cols),
+ table,
+ parent = node.get('parentNode');
+
+ table = new Y.DataTable({
+ columns: cols,
+ data: data,
+ sortBy: 'file'
+ });
+ parent.set('innerHTML', '');
+ table.render(parent);
+ }
+
+ Y.on('domready', function () {
+ replaceTable(Y.one('div.coverage-summary table'));
+ if (typeof prettyPrint === 'function') {
+ prettyPrint();
+ }
+ });
+ });
+</script>
+</body>
+</html>
diff --git a/coverage/prettify.css b/coverage/prettify.css
new file mode 100644
index 0000000..b317a7c
--- /dev/null
+++ b/coverage/prettify.css
@@ -0,0 +1 @@
+.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding [...]
diff --git a/coverage/prettify.js b/coverage/prettify.js
new file mode 100644
index 0000000..ef51e03
--- /dev/null
+++ b/coverage/prettify.js
@@ -0,0 +1 @@
+window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,expl [...]
diff --git a/coverage/utf8.js/index.html b/coverage/utf8.js/index.html
new file mode 100644
index 0000000..926b3f6
--- /dev/null
+++ b/coverage/utf8.js/index.html
@@ -0,0 +1,333 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <title>Code coverage report for utf8.js/</title>
+ <meta charset="utf-8">
+
+ <link rel="stylesheet" href="../prettify.css">
+
+ <style>
+ body, html {
+ margin:0; padding: 0;
+ }
+ body {
+ font-family: Helvetica Neue, Helvetica,Arial;
+ font-size: 10pt;
+ }
+ div.header, div.footer {
+ background: #eee;
+ padding: 1em;
+ }
+ div.header {
+ z-index: 100;
+ position: fixed;
+ top: 0;
+ border-bottom: 1px solid #666;
+ width: 100%;
+ }
+ div.footer {
+ border-top: 1px solid #666;
+ }
+ div.body {
+ margin-top: 10em;
+ }
+ div.meta {
+ font-size: 90%;
+ text-align: center;
+ }
+ h1, h2, h3 {
+ font-weight: normal;
+ }
+ h1 {
+ font-size: 12pt;
+ }
+ h2 {
+ font-size: 10pt;
+ }
+ pre {
+ font-family: Consolas, Menlo, Monaco, monospace;
+ margin: 0;
+ padding: 0;
+ line-height: 14px;
+ font-size: 14px;
+ -moz-tab-size: 2;
+ -o-tab-size: 2;
+ tab-size: 2;
+ }
+
+ div.path { font-size: 110%; }
+ div.path a:link, div.path a:visited { color: #000; }
+ table.coverage { border-collapse: collapse; margin:0; padding: 0 }
+
+ table.coverage td {
+ margin: 0;
+ padding: 0;
+ color: #111;
+ vertical-align: top;
+ }
+ table.coverage td.line-count {
+ width: 50px;
+ text-align: right;
+ padding-right: 5px;
+ }
+ table.coverage td.line-coverage {
+ color: #777 !important;
+ text-align: right;
+ border-left: 1px solid #666;
+ border-right: 1px solid #666;
+ }
+
+ table.coverage td.text {
+ }
+
+ table.coverage td span.cline-any {
+ display: inline-block;
+ padding: 0 5px;
+ width: 40px;
+ }
+ table.coverage td span.cline-neutral {
+ background: #eee;
+ }
+ table.coverage td span.cline-yes {
+ background: #b5d592;
+ color: #999;
+ }
+ table.coverage td span.cline-no {
+ background: #fc8c84;
+ }
+
+ .cstat-yes { color: #111; }
+ .cstat-no { background: #fc8c84; color: #111; }
+ .fstat-no { background: #ffc520; color: #111 !important; }
+ .cbranch-no { background: yellow !important; color: #111; }
+ .missing-if-branch {
+ display: inline-block;
+ margin-right: 10px;
+ position: relative;
+ padding: 0 4px;
+ background: black;
+ color: yellow;
+ xtext-decoration: line-through;
+ }
+ .missing-if-branch .typ {
+ color: inherit !important;
+ }
+
+ .entity, .metric { font-weight: bold; }
+ .metric { display: inline-block; border: 1px solid #333; padding: 0.3em; background: white; }
+ .metric small { font-size: 80%; font-weight: normal; color: #666; }
+
+ div.coverage-summary table { border-collapse: collapse; margin: 3em; font-size: 110%; }
+ div.coverage-summary td, div.coverage-summary table th { margin: 0; padding: 0.25em 1em; border-top: 1px solid #666; border-bottom: 1px solid #666; }
+ div.coverage-summary th { text-align: left; border: 1px solid #666; background: #eee; font-weight: normal; }
+ div.coverage-summary th.file { border-right: none !important; }
+ div.coverage-summary th.pic { border-left: none !important; text-align: right; }
+ div.coverage-summary th.pct { border-right: none !important; }
+ div.coverage-summary th.abs { border-left: none !important; text-align: right; }
+ div.coverage-summary td.pct { text-align: right; border-left: 1px solid #666; }
+ div.coverage-summary td.abs { text-align: right; font-size: 90%; color: #444; border-right: 1px solid #666; }
+ div.coverage-summary td.file { text-align: right; border-left: 1px solid #666; white-space: nowrap; }
+ div.coverage-summary td.pic { min-width: 120px !important; }
+ div.coverage-summary a:link { text-decoration: none; color: #000; }
+ div.coverage-summary a:visited { text-decoration: none; color: #333; }
+ div.coverage-summary a:hover { text-decoration: underline; }
+ div.coverage-summary tfoot td { border-top: 1px solid #666; }
+
+ div.coverage-summary .yui3-datatable-sort-indicator, div.coverage-summary .dummy-sort-indicator {
+ height: 10px;
+ width: 7px;
+ display: inline-block;
+ margin-left: 0.5em;
+ }
+ div.coverage-summary .yui3-datatable-sort-indicator {
+ background: url("http://yui.yahooapis.com/3.6.0/build/datatable-sort/assets/skins/sam/sort-arrow-sprite.png") no-repeat scroll 0 0 transparent;
+ }
+ div.coverage-summary .yui3-datatable-sorted .yui3-datatable-sort-indicator {
+ background-position: 0 -20px;
+ }
+ div.coverage-summary .yui3-datatable-sorted-desc .yui3-datatable-sort-indicator {
+ background-position: 0 -10px;
+ }
+
+ .high { background: #b5d592 !important; }
+ .medium { background: #ffe87c !important; }
+ .low { background: #fc8c84 !important; }
+
+ span.cover-fill, span.cover-empty {
+ display:inline-block;
+ border:1px solid #444;
+ background: white;
+ height: 12px;
+ }
+ span.cover-fill {
+ background: #ccc;
+ border-right: 1px solid #444;
+ }
+ span.cover-empty {
+ background: white;
+ border-left: none;
+ }
+ span.cover-full {
+ border-right: none !important;
+ }
+ pre.prettyprint {
+ border: none !important;
+ padding: 0 !important;
+ margin: 0 !important;
+ }
+ .com { color: #999 !important; }
+ </style>
+</head>
+<body>
+<div class="header high">
+ <h1>Code coverage report for <span class="entity">utf8.js/</span></h1>
+ <h2>
+
+ Statements: <span class="metric">92.31% <small>(120 / 130)</small></span>
+
+
+ Branches: <span class="metric">78.79% <small>(52 / 66)</small></span>
+
+
+ Functions: <span class="metric">90% <small>(9 / 10)</small></span>
+
+
+ Lines: <span class="metric">92.31% <small>(120 / 130)</small></span>
+
+ </h2>
+ <div class="path"><a href="../index.html">All files</a> » utf8.js/</div>
+</div>
+<div class="body">
+<div class="coverage-summary">
+<table>
+<thead>
+<tr>
+ <th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
+ <th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
+ <th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
+ <th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
+ <th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
+ <th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
+ <th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
+ <th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
+ <th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
+ <th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
+</tr>
+</thead>
+<tbody><tr>
+ <td class="file high" data-value="utf8.js"><a href="utf8.js.html">utf8.js</a></td>
+ <td data-value="92.31" class="pic high"><span class="cover-fill" style="width: 92px;"></span><span class="cover-empty" style="width:8px;"></span></td>
+ <td data-value="92.31" class="pct high">92.31%</td>
+ <td data-value="130" class="abs high">(120 / 130)</td>
+ <td data-value="78.79" class="pct medium">78.79%</td>
+ <td data-value="66" class="abs medium">(52 / 66)</td>
+ <td data-value="90" class="pct high">90%</td>
+ <td data-value="10" class="abs high">(9 / 10)</td>
+ <td data-value="92.31" class="pct high">92.31%</td>
+ <td data-value="130" class="abs high">(120 / 130)</td>
+ </tr>
+
+</tbody>
+</table>
+</div>
+</div>
+<div class="footer">
+ <div class="meta">Generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Thu Jun 20 2013 14:00:05 GMT+0200 (CEST)</div>
+</div>
+
+<script src="../prettify.js"></script>
+
+<script src="http://yui.yahooapis.com/3.6.0/build/yui/yui-min.js"></script>
+<script>
+
+ YUI().use('datatable', function (Y) {
+
+ var formatters = {
+ pct: function (o) {
+ o.className += o.record.get('classes')[o.column.key];
+ try {
+ return o.value.toFixed(2) + '%';
+ } catch (ex) { return o.value + '%'; }
+ },
+ html: function (o) {
+ o.className += o.record.get('classes')[o.column.key];
+ return o.record.get(o.column.key + '_html');
+ }
+ },
+ defaultFormatter = function (o) {
+ o.className += o.record.get('classes')[o.column.key];
+ return o.value;
+ };
+
+ function getColumns(theadNode) {
+ var colNodes = theadNode.all('tr th'),
+ cols = [],
+ col;
+ colNodes.each(function (colNode) {
+ col = {
+ key: colNode.getAttribute('data-col'),
+ label: colNode.get('innerHTML') || ' ',
+ sortable: !colNode.getAttribute('data-nosort'),
+ className: colNode.getAttribute('class'),
+ type: colNode.getAttribute('data-type'),
+ allowHTML: colNode.getAttribute('data-html') === 'true' || colNode.getAttribute('data-fmt') === 'html'
+ };
+ col.formatter = formatters[colNode.getAttribute('data-fmt')] || defaultFormatter;
+ cols.push(col);
+ });
+ return cols;
+ }
+
+ function getRowData(trNode, cols) {
+ var tdNodes = trNode.all('td'),
+ i,
+ row = { classes: {} },
+ node,
+ name;
+ for (i = 0; i < cols.length; i += 1) {
+ name = cols[i].key;
+ node = tdNodes.item(i);
+ row[name] = node.getAttribute('data-value') || node.get('innerHTML');
+ row[name + '_html'] = node.get('innerHTML');
+ row.classes[name] = node.getAttribute('class');
+ //Y.log('Name: ' + name + '; Value: ' + row[name]);
+ if (cols[i].type === 'number') { row[name] = row[name] * 1; }
+ }
+ //Y.log(row);
+ return row;
+ }
+
+ function getData(tbodyNode, cols) {
+ var data = [];
+ tbodyNode.all('tr').each(function (trNode) {
+ data.push(getRowData(trNode, cols));
+ });
+ return data;
+ }
+
+ function replaceTable(node) {
+ if (!node) { return; }
+ var cols = getColumns(node.one('thead')),
+ data = getData(node.one('tbody'), cols),
+ table,
+ parent = node.get('parentNode');
+
+ table = new Y.DataTable({
+ columns: cols,
+ data: data,
+ sortBy: 'file'
+ });
+ parent.set('innerHTML', '');
+ table.render(parent);
+ }
+
+ Y.on('domready', function () {
+ replaceTable(Y.one('div.coverage-summary table'));
+ if (typeof prettyPrint === 'function') {
+ prettyPrint();
+ }
+ });
+ });
+</script>
+</body>
+</html>
diff --git a/coverage/utf8.js/utf8.js.html b/coverage/utf8.js/utf8.js.html
new file mode 100644
index 0000000..8923045
--- /dev/null
+++ b/coverage/utf8.js/utf8.js.html
@@ -0,0 +1,1028 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <title>Code coverage report for utf8.js/utf8.js</title>
+ <meta charset="utf-8">
+
+ <link rel="stylesheet" href="../prettify.css">
+
+ <style>
+ body, html {
+ margin:0; padding: 0;
+ }
+ body {
+ font-family: Helvetica Neue, Helvetica,Arial;
+ font-size: 10pt;
+ }
+ div.header, div.footer {
+ background: #eee;
+ padding: 1em;
+ }
+ div.header {
+ z-index: 100;
+ position: fixed;
+ top: 0;
+ border-bottom: 1px solid #666;
+ width: 100%;
+ }
+ div.footer {
+ border-top: 1px solid #666;
+ }
+ div.body {
+ margin-top: 10em;
+ }
+ div.meta {
+ font-size: 90%;
+ text-align: center;
+ }
+ h1, h2, h3 {
+ font-weight: normal;
+ }
+ h1 {
+ font-size: 12pt;
+ }
+ h2 {
+ font-size: 10pt;
+ }
+ pre {
+ font-family: Consolas, Menlo, Monaco, monospace;
+ margin: 0;
+ padding: 0;
+ line-height: 14px;
+ font-size: 14px;
+ -moz-tab-size: 2;
+ -o-tab-size: 2;
+ tab-size: 2;
+ }
+
+ div.path { font-size: 110%; }
+ div.path a:link, div.path a:visited { color: #000; }
+ table.coverage { border-collapse: collapse; margin:0; padding: 0 }
+
+ table.coverage td {
+ margin: 0;
+ padding: 0;
+ color: #111;
+ vertical-align: top;
+ }
+ table.coverage td.line-count {
+ width: 50px;
+ text-align: right;
+ padding-right: 5px;
+ }
+ table.coverage td.line-coverage {
+ color: #777 !important;
+ text-align: right;
+ border-left: 1px solid #666;
+ border-right: 1px solid #666;
+ }
+
+ table.coverage td.text {
+ }
+
+ table.coverage td span.cline-any {
+ display: inline-block;
+ padding: 0 5px;
+ width: 40px;
+ }
+ table.coverage td span.cline-neutral {
+ background: #eee;
+ }
+ table.coverage td span.cline-yes {
+ background: #b5d592;
+ color: #999;
+ }
+ table.coverage td span.cline-no {
+ background: #fc8c84;
+ }
+
+ .cstat-yes { color: #111; }
+ .cstat-no { background: #fc8c84; color: #111; }
+ .fstat-no { background: #ffc520; color: #111 !important; }
+ .cbranch-no { background: yellow !important; color: #111; }
+ .missing-if-branch {
+ display: inline-block;
+ margin-right: 10px;
+ position: relative;
+ padding: 0 4px;
+ background: black;
+ color: yellow;
+ xtext-decoration: line-through;
+ }
+ .missing-if-branch .typ {
+ color: inherit !important;
+ }
+
+ .entity, .metric { font-weight: bold; }
+ .metric { display: inline-block; border: 1px solid #333; padding: 0.3em; background: white; }
+ .metric small { font-size: 80%; font-weight: normal; color: #666; }
+
+ div.coverage-summary table { border-collapse: collapse; margin: 3em; font-size: 110%; }
+ div.coverage-summary td, div.coverage-summary table th { margin: 0; padding: 0.25em 1em; border-top: 1px solid #666; border-bottom: 1px solid #666; }
+ div.coverage-summary th { text-align: left; border: 1px solid #666; background: #eee; font-weight: normal; }
+ div.coverage-summary th.file { border-right: none !important; }
+ div.coverage-summary th.pic { border-left: none !important; text-align: right; }
+ div.coverage-summary th.pct { border-right: none !important; }
+ div.coverage-summary th.abs { border-left: none !important; text-align: right; }
+ div.coverage-summary td.pct { text-align: right; border-left: 1px solid #666; }
+ div.coverage-summary td.abs { text-align: right; font-size: 90%; color: #444; border-right: 1px solid #666; }
+ div.coverage-summary td.file { text-align: right; border-left: 1px solid #666; white-space: nowrap; }
+ div.coverage-summary td.pic { min-width: 120px !important; }
+ div.coverage-summary a:link { text-decoration: none; color: #000; }
+ div.coverage-summary a:visited { text-decoration: none; color: #333; }
+ div.coverage-summary a:hover { text-decoration: underline; }
+ div.coverage-summary tfoot td { border-top: 1px solid #666; }
+
+ div.coverage-summary .yui3-datatable-sort-indicator, div.coverage-summary .dummy-sort-indicator {
+ height: 10px;
+ width: 7px;
+ display: inline-block;
+ margin-left: 0.5em;
+ }
+ div.coverage-summary .yui3-datatable-sort-indicator {
+ background: url("http://yui.yahooapis.com/3.6.0/build/datatable-sort/assets/skins/sam/sort-arrow-sprite.png") no-repeat scroll 0 0 transparent;
+ }
+ div.coverage-summary .yui3-datatable-sorted .yui3-datatable-sort-indicator {
+ background-position: 0 -20px;
+ }
+ div.coverage-summary .yui3-datatable-sorted-desc .yui3-datatable-sort-indicator {
+ background-position: 0 -10px;
+ }
+
+ .high { background: #b5d592 !important; }
+ .medium { background: #ffe87c !important; }
+ .low { background: #fc8c84 !important; }
+
+ span.cover-fill, span.cover-empty {
+ display:inline-block;
+ border:1px solid #444;
+ background: white;
+ height: 12px;
+ }
+ span.cover-fill {
+ background: #ccc;
+ border-right: 1px solid #444;
+ }
+ span.cover-empty {
+ background: white;
+ border-left: none;
+ }
+ span.cover-full {
+ border-right: none !important;
+ }
+ pre.prettyprint {
+ border: none !important;
+ padding: 0 !important;
+ margin: 0 !important;
+ }
+ .com { color: #999 !important; }
+ </style>
+</head>
+<body>
+<div class="header high">
+ <h1>Code coverage report for <span class="entity">utf8.js/utf8.js</span></h1>
+ <h2>
+
+ Statements: <span class="metric">92.31% <small>(120 / 130)</small></span>
+
+
+ Branches: <span class="metric">78.79% <small>(52 / 66)</small></span>
+
+
+ Functions: <span class="metric">90% <small>(9 / 10)</small></span>
+
+
+ Lines: <span class="metric">92.31% <small>(120 / 130)</small></span>
+
+ </h2>
+ <div class="path"><a href="../index.html">All files</a> » <a href="index.html">utf8.js/</a> » utf8.js</div>
+</div>
+<div class="body">
+<pre><table class="coverage">
+<tr><td class="line-count">1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242</td><td class="line-coverage"><span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-yes">52</span>
+<span class="cline-any cline-yes">52</span>
+<span class="cline-any cline-yes">52</span>
+<span class="cline-any cline-yes">52</span>
+<span class="cline-any cline-yes">52</span>
+<span class="cline-any cline-yes">52</span>
+<span class="cline-any cline-yes">128</span>
+<span class="cline-any cline-yes">128</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">8</span>
+<span class="cline-any cline-yes">8</span>
+<span class="cline-any cline-yes">5</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">3</span>
+<span class="cline-any cline-yes">3</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">120</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">52</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-yes">24</span>
+<span class="cline-any cline-yes">24</span>
+<span class="cline-any cline-yes">24</span>
+<span class="cline-any cline-yes">24</span>
+<span class="cline-any cline-yes">24</span>
+<span class="cline-any cline-yes">32</span>
+<span class="cline-any cline-yes">32</span>
+<span class="cline-any cline-yes">5</span>
+<span class="cline-any cline-yes">5</span>
+<span class="cline-any cline-yes">5</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">32</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">24</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-yes">29</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-yes">32</span>
+<span class="cline-any cline-yes">5</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">27</span>
+<span class="cline-any cline-yes">27</span>
+<span class="cline-any cline-yes">3</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">24</span>
+<span class="cline-any cline-yes">19</span>
+<span class="cline-any cline-yes">19</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">5</span>
+<span class="cline-any cline-yes">5</span>
+<span class="cline-any cline-yes">5</span>
+<span class="cline-any cline-yes">5</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">27</span>
+<span class="cline-any cline-yes">27</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-yes">24</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">24</span>
+<span class="cline-any cline-yes">24</span>
+<span class="cline-any cline-yes">24</span>
+<span class="cline-any cline-yes">24</span>
+<span class="cline-any cline-yes">24</span>
+<span class="cline-any cline-yes">32</span>
+<span class="cline-any cline-yes">32</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">24</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-yes">60</span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">59</span>
+<span class="cline-any cline-yes">59</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">59</span>
+<span class="cline-any cline-yes">57</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">2</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-yes">60</span>
+<span class="cline-any cline-yes">60</span>
+<span class="cline-any cline-yes">60</span>
+<span class="cline-any cline-yes">60</span>
+<span class="cline-any cline-yes">60</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">60</span>
+<span class="cline-any cline-no"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">60</span>
+<span class="cline-any cline-yes">24</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">36</span>
+<span class="cline-any cline-yes">36</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">36</span>
+<span class="cline-any cline-yes">5</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">31</span>
+<span class="cline-any cline-yes">4</span>
+<span class="cline-any cline-yes">3</span>
+<span class="cline-any cline-yes">3</span>
+<span class="cline-any cline-yes">3</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-no"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">27</span>
+<span class="cline-any cline-yes">20</span>
+<span class="cline-any cline-yes">19</span>
+<span class="cline-any cline-yes">19</span>
+<span class="cline-any cline-yes">19</span>
+<span class="cline-any cline-yes">19</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-no"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">7</span>
+<span class="cline-any cline-yes">6</span>
+<span class="cline-any cline-yes">6</span>
+<span class="cline-any cline-yes">5</span>
+<span class="cline-any cline-yes">5</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">5</span>
+<span class="cline-any cline-yes">5</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-yes">28</span>
+<span class="cline-any cline-yes">28</span>
+<span class="cline-any cline-yes">28</span>
+<span class="cline-any cline-yes">28</span>
+<span class="cline-any cline-yes">28</span>
+<span class="cline-any cline-yes">28</span>
+<span class="cline-any cline-yes">32</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">24</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-no"> </span>
+<span class="cline-any cline-no"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-yes">1</span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-no"> </span>
+<span class="cline-any cline-no"> </span>
+<span class="cline-any cline-no"> </span>
+<span class="cline-any cline-no"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-no"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span>
+<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">/*! http://mths.be/utf8js v2.0.0 by @mathias */
+;(function(root) {
+
+ // Detect free variables `exports`
+ var freeExports = typeof exports == 'object' && exports;
+
+ // Detect free variable `module`
+ var freeModule = typeof module == 'object' && module &&
+ module.exports == freeExports && module;
+
+ // Detect free variable `global`, from Node.js or Browserified code,
+ // and use it as `root`
+ var freeGlobal = typeof global == 'object' && global;
+ <span class="missing-if-branch" title="else path not taken"" >E</span>if (freeGlobal.global === freeGlobal || <span class="branch-1 cbranch-no" title="branch not covered" >freeGlobal.window === freeGlobal)</span> {
+ root = freeGlobal;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ var stringFromCharCode = String.fromCharCode;
+
+ // Taken from http://mths.be/punycode
+ function ucs2decode(string) {
+ var output = [];
+ var counter = 0;
+ var length = string.length;
+ var value;
+ var extra;
+ while (counter < length) {
+ value = string.charCodeAt(counter++);
+ if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
+ // high surrogate, and there is a next character
+ extra = string.charCodeAt(counter++);
+ if ((extra & 0xFC00) == 0xDC00) { // low surrogate
+ output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+ } else {
+ // unmatched surrogate; only append this code unit, in case the next
+ // code unit is the high surrogate of a surrogate pair
+ output.push(value);
+ counter--;
+ }
+ } else {
+ output.push(value);
+ }
+ }
+ return output;
+ }
+
+ // Taken from http://mths.be/punycode
+ function ucs2encode(array) {
+ var length = array.length;
+ var index = -1;
+ var value;
+ var output = '';
+ while (++index < length) {
+ value = array[index];
+ if (value > 0xFFFF) {
+ value -= 0x10000;
+ output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
+ value = 0xDC00 | value & 0x3FF;
+ }
+ output += stringFromCharCode(value);
+ }
+ return output;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ // https://github.com/php/php-src/blob/master/ext/mbstring/oniguruma/enc/utf8.c
+ function createByte(codePoint, shift) {
+ return stringFromCharCode(((codePoint >> shift) & 0x3F) | 0x80);
+ }
+
+ function encodeCodePoint(codePoint) {
+ if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence
+ return stringFromCharCode(codePoint);
+ }
+ var symbol = '';
+ if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence
+ symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0);
+ }
+ else if ((codePoint & 0xFFFF0000) == 0) { // 3-byte sequence
+ symbol = stringFromCharCode(((codePoint >> 12) & 0x0F) | 0xE0);
+ symbol += createByte(codePoint, 6);
+ }
+ else <span class="missing-if-branch" title="else path not taken"" >E</span>if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence
+ symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0);
+ symbol += createByte(codePoint, 12);
+ symbol += createByte(codePoint, 6);
+ }
+ symbol += stringFromCharCode((codePoint & 0x3F) | 0x80);
+ return symbol;
+ }
+
+ function utf8encode(string) {
+ var codePoints = ucs2decode(string);
+
+ // console.log(JSON.stringify(codePoints.map(function(x) {
+ // return 'U+' + x.toString(16).toUpperCase();
+ // })));
+
+ var length = codePoints.length;
+ var index = -1;
+ var codePoint;
+ var byteString = '';
+ while (++index < length) {
+ codePoint = codePoints[index];
+ byteString += encodeCodePoint(codePoint);
+ }
+ return byteString;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ // https://github.com/php/php-src/blob/master/ext/json/utf8_decode.c
+ function readContinuationByte() {
+ if (byteIndex >= byteCount) {
+ throw Error('Invalid byte index');
+ }
+
+ var continuationByte = byteArray[byteIndex] & 0xFF;
+ byteIndex++;
+
+ if ((continuationByte & 0xC0) == 0x80) {
+ return continuationByte & 0x3F;
+ }
+
+ // If we end up here, it’s not a continuation byte
+ throw Error('Invalid continuation byte');
+ }
+
+ function decodeSymbol() {
+ var byte1;
+ var byte2;
+ var byte3;
+ var byte4;
+ var codePoint;
+
+ <span class="missing-if-branch" title="if path not taken"" >I</span>if (byteIndex > byteCount) {
+<span class="cstat-no" title="statement not covered" > throw Error('Invalid byte index');</span>
+ }
+
+ if (byteIndex == byteCount) {
+ return false;
+ }
+
+ // Read first byte
+ byte1 = byteArray[byteIndex] & 0xFF;
+ byteIndex++;
+
+ // 1-byte sequence (no continuation bytes)
+ if ((byte1 & 0x80) == 0) {
+ return byte1;
+ }
+
+ // 2-byte sequence
+ if ((byte1 & 0xE0) == 0xC0) {
+ var byte2 = readContinuationByte();
+ codePoint = ((byte1 & 0x1F) << 6) | byte2;
+ <span class="missing-if-branch" title="else path not taken"" >E</span>if (codePoint >= 0x80) {
+ return codePoint;
+ } else {
+<span class="cstat-no" title="statement not covered" > throw Error('Invalid continuation byte');</span>
+ }
+ }
+
+ // 3-byte sequence (may include unpaired surrogates)
+ if ((byte1 & 0xF0) == 0xE0) {
+ byte2 = readContinuationByte();
+ byte3 = readContinuationByte();
+ codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3;
+ <span class="missing-if-branch" title="else path not taken"" >E</span>if (codePoint >= 0x0800) {
+ return codePoint;
+ } else {
+<span class="cstat-no" title="statement not covered" > throw Error('Invalid continuation byte');</span>
+ }
+ }
+
+ // 4-byte sequence
+ if ((byte1 & 0xF8) == 0xF0) {
+ byte2 = readContinuationByte();
+ byte3 = readContinuationByte();
+ byte4 = readContinuationByte();
+ codePoint = ((byte1 & 0x0F) << 0x12) | (byte2 << 0x0C) |
+ (byte3 << 0x06) | byte4;
+ <span class="missing-if-branch" title="else path not taken"" >E</span>if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) {
+ return codePoint;
+ }
+ }
+
+ throw Error('Invalid UTF-8 detected');
+ }
+
+ var byteArray;
+ var byteCount;
+ var byteIndex;
+ function utf8decode(byteString) {
+ byteArray = ucs2decode(byteString);
+ byteCount = byteArray.length;
+ byteIndex = 0;
+ var codePoints = [];
+ var tmp;
+ while ((tmp = decodeSymbol()) !== false) {
+ codePoints.push(tmp);
+ }
+ return ucs2encode(codePoints);
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ var utf8 = {
+ 'version': '2.0.0',
+ 'encode': utf8encode,
+ 'decode': utf8decode
+ };
+
+ // Some AMD build optimizers, like r.js, check for specific condition patterns
+ // like the following:
+ <span class="missing-if-branch" title="if path not taken"" >I</span>if (
+ typeof define == 'function' &&
+<span class="branch-1 cbranch-no" title="branch not covered" > typeof define.amd == 'object' </span>&&
+<span class="branch-2 cbranch-no" title="branch not covered" > define.amd</span>
+ ) {
+<span class="cstat-no" title="statement not covered" > define(<span class="fstat-no" title="function not covered" >function() {</span></span>
+<span class="cstat-no" title="statement not covered" > return utf8;</span>
+ });
+ } else <span class="missing-if-branch" title="else path not taken"" >E</span>if (freeExports && !freeExports.nodeType) {
+ <span class="missing-if-branch" title="else path not taken"" >E</span>if (freeModule) { // in Node.js or RingoJS v0.8.0+
+ freeModule.exports = utf8;
+ } else { // in Narwhal or RingoJS v0.7.0-
+<span class="cstat-no" title="statement not covered" > var object = {};</span>
+<span class="cstat-no" title="statement not covered" > var hasOwnProperty = object.hasOwnProperty;</span>
+<span class="cstat-no" title="statement not covered" > for (var key in utf8) {</span>
+<span class="cstat-no" title="statement not covered" > hasOwnProperty.call(utf8, key) && (freeExports[key] = utf8[key]);</span>
+ }
+ }
+ } else { // in Rhino or a web browser
+<span class="cstat-no" title="statement not covered" > root.utf8 = utf8;</span>
+ }
+
+}(this));
+ </pre></td></tr>
+</table></pre>
+
+</div>
+<div class="footer">
+ <div class="meta">Generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Thu Jun 20 2013 14:00:05 GMT+0200 (CEST)</div>
+</div>
+
+<script src="../prettify.js"></script>
+
+<script src="http://yui.yahooapis.com/3.6.0/build/yui/yui-min.js"></script>
+<script>
+
+ YUI().use('datatable', function (Y) {
+
+ var formatters = {
+ pct: function (o) {
+ o.className += o.record.get('classes')[o.column.key];
+ try {
+ return o.value.toFixed(2) + '%';
+ } catch (ex) { return o.value + '%'; }
+ },
+ html: function (o) {
+ o.className += o.record.get('classes')[o.column.key];
+ return o.record.get(o.column.key + '_html');
+ }
+ },
+ defaultFormatter = function (o) {
+ o.className += o.record.get('classes')[o.column.key];
+ return o.value;
+ };
+
+ function getColumns(theadNode) {
+ var colNodes = theadNode.all('tr th'),
+ cols = [],
+ col;
+ colNodes.each(function (colNode) {
+ col = {
+ key: colNode.getAttribute('data-col'),
+ label: colNode.get('innerHTML') || ' ',
+ sortable: !colNode.getAttribute('data-nosort'),
+ className: colNode.getAttribute('class'),
+ type: colNode.getAttribute('data-type'),
+ allowHTML: colNode.getAttribute('data-html') === 'true' || colNode.getAttribute('data-fmt') === 'html'
+ };
+ col.formatter = formatters[colNode.getAttribute('data-fmt')] || defaultFormatter;
+ cols.push(col);
+ });
+ return cols;
+ }
+
+ function getRowData(trNode, cols) {
+ var tdNodes = trNode.all('td'),
+ i,
+ row = { classes: {} },
+ node,
+ name;
+ for (i = 0; i < cols.length; i += 1) {
+ name = cols[i].key;
+ node = tdNodes.item(i);
+ row[name] = node.getAttribute('data-value') || node.get('innerHTML');
+ row[name + '_html'] = node.get('innerHTML');
+ row.classes[name] = node.getAttribute('class');
+ //Y.log('Name: ' + name + '; Value: ' + row[name]);
+ if (cols[i].type === 'number') { row[name] = row[name] * 1; }
+ }
+ //Y.log(row);
+ return row;
+ }
+
+ function getData(tbodyNode, cols) {
+ var data = [];
+ tbodyNode.all('tr').each(function (trNode) {
+ data.push(getRowData(trNode, cols));
+ });
+ return data;
+ }
+
+ function replaceTable(node) {
+ if (!node) { return; }
+ var cols = getColumns(node.one('thead')),
+ data = getData(node.one('tbody'), cols),
+ table,
+ parent = node.get('parentNode');
+
+ table = new Y.DataTable({
+ columns: cols,
+ data: data,
+ sortBy: 'file'
+ });
+ parent.set('innerHTML', '');
+ table.render(parent);
+ }
+
+ Y.on('domready', function () {
+ replaceTable(Y.one('div.coverage-summary table'));
+ if (typeof prettyPrint === 'function') {
+ prettyPrint();
+ }
+ });
+ });
+</script>
+</body>
+</html>
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..308e66e
--- /dev/null
+++ b/package.json
@@ -0,0 +1,49 @@
+{
+ "name": "utf8",
+ "version": "2.0.0",
+ "description": "A well-tested UTF-8 encoder/decoder written in JavaScript.",
+ "homepage": "http://mths.be/utf8js",
+ "main": "utf8.js",
+ "keywords": [
+ "charset",
+ "encoding",
+ "unicode",
+ "utf8"
+ ],
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "http://mths.be/mit"
+ },
+ {
+ "type": "GPL",
+ "url": "http://mths.be/gpl"
+ }
+ ],
+ "author": {
+ "name": "Mathias Bynens",
+ "url": "http://mathiasbynens.be/"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/mathiasbynens/utf8.js.git"
+ },
+ "bugs": {
+ "url": "https://github.com/mathiasbynens/utf8.js/issues"
+ },
+ "directories": {
+ "test": "tests"
+ },
+ "scripts": {
+ "test": "node tests/tests.js"
+ },
+ "dependencies": {},
+ "devDependencies": {
+ "grunt": "~0.4.1",
+ "grunt-shell": "~0.2.2",
+ "istanbul": "~0.1.36",
+ "qunit-clib": "~1.3.0",
+ "qunitjs": "~1.11.0",
+ "requirejs": "~2.1.6"
+ }
+}
diff --git a/tests/generate-test-data.py b/tests/generate-test-data.py
new file mode 100755
index 0000000..096b012
--- /dev/null
+++ b/tests/generate-test-data.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+import re
+import json
+
+# http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+# http://stackoverflow.com/a/13436167/96656
+def unisymbol(codePoint):
+ if codePoint >= 0x0000 and codePoint <= 0xFFFF:
+ return unichr(codePoint)
+ elif codePoint >= 0x010000 and codePoint <= 0x10FFFF:
+ highSurrogate = int((codePoint - 0x10000) / 0x400) + 0xD800
+ lowSurrogate = int((codePoint - 0x10000) % 0x400) + 0xDC00
+ return unichr(highSurrogate) + unichr(lowSurrogate)
+ else:
+ return 'Error'
+
+def hexify(codePoint):
+ return 'U+' + hex(codePoint)[2:].upper().zfill(6)
+
+def writeFile(filename, contents):
+ print filename
+ with open(filename, 'w') as f:
+ f.write(contents.strip() + '\n')
+
+data = []
+for codePoint in range(0x000000, 0x10FFFF + 1):
+ symbol = unisymbol(codePoint)
+ # http://stackoverflow.com/a/17199950/96656
+ bytes = symbol.encode('utf8').decode('latin1')
+ data.append({
+ 'codePoint': codePoint,
+ 'decoded': symbol,
+ 'encoded': bytes
+ });
+
+jsonData = json.dumps(data, sort_keys=False, indent=2, separators=(',', ': '))
+# Use tabs instead of double spaces for indentation
+jsonData = jsonData.replace(' ', '\t')
+# Escape hexadecimal digits in escape sequences
+jsonData = re.sub(
+ r'\\u([a-fA-F0-9]{4})',
+ lambda match: r'\u{}'.format(match.group(1).upper()),
+ jsonData
+)
+
+writeFile('data.json', jsonData)
diff --git a/tests/index.html b/tests/index.html
new file mode 100644
index 0000000..13cc04d
--- /dev/null
+++ b/tests/index.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>utf8.js test suite</title>
+ <link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css">
+ </head>
+ <body>
+ <div id="qunit"></div>
+ <script src="../node_modules/qunitjs/qunit/qunit.js"></script>
+ <script src="../utf8.js"></script>
+ <script>
+ // populate `QUnit.urlParams`
+ QUnit.urlParams.norequire = /[?&]norequire=true(?:&|$)/.test(location.search);
+
+ // load tests.js if not using require.js
+ document.write(QUnit.urlParams.norequire
+ ? '<script src="tests.js"><\/script>'
+ : '<script src="../node_modules/requirejs/require.js"><\/script>'
+ );
+ </script>
+ <script>
+ window.require && require({
+ 'baseUrl': '../node_modules/requirejs/',
+ 'urlArgs': 't=' + (+new Date),
+ 'paths': {
+ 'utf8': '../../utf8'
+ }
+ },
+ ['utf8'], function(utf8) {
+ require(['tests.js']);
+ });
+ </script>
+ </body>
+</html>
diff --git a/tests/tests.js b/tests/tests.js
new file mode 100644
index 0000000..cb01e10
--- /dev/null
+++ b/tests/tests.js
@@ -0,0 +1,242 @@
+;(function(root) {
+ 'use strict';
+
+ /** Use a single `load` function */
+ var load = typeof require == 'function' ? require : root.load;
+
+ /** The unit testing framework */
+ var QUnit = (function() {
+ var noop = Function.prototype;
+ return root.QUnit || (
+ root.addEventListener || (root.addEventListener = noop),
+ root.setTimeout || (root.setTimeout = noop),
+ root.QUnit = load('../node_modules/qunitjs/qunit/qunit.js') || root.QUnit,
+ (load('../node_modules/qunit-clib/qunit-clib.js') || { 'runInContext': noop }).runInContext(root),
+ addEventListener === noop && delete root.addEventListener,
+ root.QUnit
+ );
+ }());
+
+ /** The `utf8` object to test */
+ var utf8 = root.utf8 || (root.utf8 = (
+ utf8 = load('../utf8.js') || root.utf8,
+ utf8 = utf8.utf8 || utf8
+ ));
+
+ /*--------------------------------------------------------------------------*/
+
+ function forEach(array, fn) {
+ var index = -1;
+ var length = array.length;
+ while (++index < length) {
+ fn(array[index]);
+ }
+ }
+
+ // Quick and dirty test to see if we’re in Node & need extended tests
+ var runExtendedTests = (function() {
+ try {
+ return process.argv[0] == 'node' && process.argv[2] == '--extended';
+ } catch(error) { }
+ }());
+
+ var data = [
+ // 1-byte
+ {
+ 'codePoint': 0x0000,
+ 'decoded': '\0',
+ 'encoded': '\0'
+ },
+ {
+ 'codePoint': 0x005C,
+ 'decoded': '\x5C',
+ 'encoded': '\x5C'
+ },
+ {
+ 'codePoint': 0x007F,
+ 'decoded': '\x7F',
+ 'encoded': '\x7F'
+ },
+
+ // 2-byte
+ {
+ 'codePoint': 0x0080,
+ 'decoded': '\x80',
+ 'encoded': '\xC2\x80'
+ },
+ {
+ 'codePoint': 0x05CA,
+ 'decoded': '\u05CA',
+ 'encoded': '\xD7\x8A'
+ },
+ {
+ 'codePoint': 0x07FF,
+ 'decoded': '\u07FF',
+ 'encoded': '\xDF\xBF',
+ },
+
+ // 3-byte
+ {
+ 'codePoint': 0x0800,
+ 'decoded': '\u0800',
+ 'encoded': '\xE0\xA0\x80',
+ },
+ {
+ 'codePoint': 0x2C3C,
+ 'decoded': '\u2C3C',
+ 'encoded': '\xE2\xB0\xBC'
+ },
+ {
+ 'codePoint': 0xFFFF,
+ 'decoded': '\uFFFF',
+ 'encoded': '\xEF\xBF\xBF'
+ },
+ // unmatched surrogate halves
+ // high surrogates: 0xD800 to 0xDBFF
+ {
+ 'codePoint': 0xD800,
+ 'decoded': '\uD800',
+ 'encoded': '\xED\xA0\x80'
+ },
+ {
+ 'description': 'High surrogate followed by another high surrogate',
+ 'decoded': '\uD800\uD800',
+ 'encoded': '\xED\xA0\x80\xED\xA0\x80'
+ },
+ {
+ 'description': 'High surrogate followed by a symbol that is not a surrogate',
+ 'decoded': '\uD800A',
+ 'encoded': '\xED\xA0\x80A'
+ },
+ {
+ 'description': 'Unmatched high surrogate, followed by a surrogate pair, followed by an unmatched high surrogate',
+ 'decoded': '\uD800\uD834\uDF06\uD800',
+ 'encoded': '\xED\xA0\x80\xF0\x9D\x8C\x86\xED\xA0\x80'
+ },
+ {
+ 'codePoint': 0xD9AF,
+ 'decoded': '\uD9AF',
+ 'encoded': '\xED\xA6\xAF'
+ },
+ {
+ 'codePoint': 0xDBFF,
+ 'decoded': '\uDBFF',
+ 'encoded': '\xED\xAF\xBF'
+ },
+ // low surrogates: 0xDC00 to 0xDFFF
+ {
+ 'codePoint': 0xDC00,
+ 'decoded': '\uDC00',
+ 'encoded': '\xED\xB0\x80'
+ },
+ {
+ 'description': 'Low surrogate followed by another low surrogate',
+ 'decoded': '\uDC00\uDC00',
+ 'encoded': '\xED\xB0\x80\xED\xB0\x80'
+ },
+ {
+ 'description': 'Low surrogate followed by a symbol that is not a surrogate',
+ 'decoded': '\uDC00A',
+ 'encoded': '\xED\xB0\x80A'
+ },
+ {
+ 'description': 'Unmatched low surrogate, followed by a surrogate pair, followed by an unmatched low surrogate',
+ 'decoded': '\uDC00\uD834\uDF06\uDC00',
+ 'encoded': '\xED\xB0\x80\xF0\x9D\x8C\x86\xED\xB0\x80'
+ },
+ {
+ 'codePoint': 0xDEEE,
+ 'decoded': '\uDEEE',
+ 'encoded': '\xED\xBB\xAE'
+ },
+ {
+ 'codePoint': 0xDFFF,
+ 'decoded': '\uDFFF',
+ 'encoded': '\xED\xBF\xBF'
+ },
+
+ // 4-byte
+ {
+ 'codePoint': 0x010000,
+ 'decoded': '\uD800\uDC00',
+ 'encoded': '\xF0\x90\x80\x80'
+ },
+ {
+ 'codePoint': 0x01D306,
+ 'decoded': '\uD834\uDF06',
+ 'encoded': '\xF0\x9D\x8C\x86'
+ },
+ {
+ 'codePoint': 0x10FFF,
+ 'decoded': '\uDBFF\uDFFF',
+ 'encoded': '\xF4\x8F\xBF\xBF'
+ }
+ ];
+
+ if (runExtendedTests) {
+ data = data.concat(require('./data.json'));
+ }
+
+ // `throws` is a reserved word in ES3; alias it to avoid errors
+ var raises = QUnit.assert['throws'];
+
+ // explicitly call `QUnit.module()` instead of `module()`
+ // in case we are in a CLI environment
+ QUnit.module('utf8.js');
+
+ test('encode/decode', function() {
+ forEach(data, function(object) {
+ var description = object.description || 'U+' + object.codePoint.toString(16).toUpperCase();
+ ;
+ equal(
+ object.encoded,
+ utf8.encode(object.decoded),
+ 'Encoding: ' + description
+ );
+ equal(
+ object.decoded,
+ utf8.decode(object.encoded),
+ 'Decoding: ' + description
+ );
+ });
+
+ // Error handling
+ raises(
+ function() {
+ utf8.decode('\uFFFF');
+ },
+ Error,
+ 'Error: invalid UTF-8 detected'
+ );
+ raises(
+ function() {
+ utf8.decode('\xE9\x00\x00');
+ },
+ Error,
+ 'Error: invalid continuation byte (4-byte sequence expected)'
+ );
+ raises(
+ function() {
+ utf8.decode('\xC2\uFFFF');
+ },
+ Error,
+ 'Error: invalid continuation byte'
+ );
+ raises(
+ function() {
+ utf8.decode('\xF0\x9D');
+ },
+ Error,
+ 'Error: invalid byte index'
+ );
+ });
+
+ /*--------------------------------------------------------------------------*/
+
+ // configure QUnit and call `QUnit.start()` for
+ // Narwhal, Node.js, PhantomJS, Rhino, and RingoJS
+ if (!root.document || root.phantom) {
+ QUnit.config.noglobals = true;
+ QUnit.start();
+ }
+}(typeof global == 'object' && global || this));
diff --git a/utf8.js b/utf8.js
new file mode 100644
index 0000000..8f99bb1
--- /dev/null
+++ b/utf8.js
@@ -0,0 +1,239 @@
+/*! http://mths.be/utf8js v2.0.0 by @mathias */
+;(function(root) {
+
+ // Detect free variables `exports`
+ var freeExports = typeof exports == 'object' && exports;
+
+ // Detect free variable `module`
+ var freeModule = typeof module == 'object' && module &&
+ module.exports == freeExports && module;
+
+ // Detect free variable `global`, from Node.js or Browserified code,
+ // and use it as `root`
+ var freeGlobal = typeof global == 'object' && global;
+ if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
+ root = freeGlobal;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ var stringFromCharCode = String.fromCharCode;
+
+ // Taken from http://mths.be/punycode
+ function ucs2decode(string) {
+ var output = [];
+ var counter = 0;
+ var length = string.length;
+ var value;
+ var extra;
+ while (counter < length) {
+ value = string.charCodeAt(counter++);
+ if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
+ // high surrogate, and there is a next character
+ extra = string.charCodeAt(counter++);
+ if ((extra & 0xFC00) == 0xDC00) { // low surrogate
+ output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+ } else {
+ // unmatched surrogate; only append this code unit, in case the next
+ // code unit is the high surrogate of a surrogate pair
+ output.push(value);
+ counter--;
+ }
+ } else {
+ output.push(value);
+ }
+ }
+ return output;
+ }
+
+ // Taken from http://mths.be/punycode
+ function ucs2encode(array) {
+ var length = array.length;
+ var index = -1;
+ var value;
+ var output = '';
+ while (++index < length) {
+ value = array[index];
+ if (value > 0xFFFF) {
+ value -= 0x10000;
+ output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
+ value = 0xDC00 | value & 0x3FF;
+ }
+ output += stringFromCharCode(value);
+ }
+ return output;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ function createByte(codePoint, shift) {
+ return stringFromCharCode(((codePoint >> shift) & 0x3F) | 0x80);
+ }
+
+ function encodeCodePoint(codePoint) {
+ if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence
+ return stringFromCharCode(codePoint);
+ }
+ var symbol = '';
+ if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence
+ symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0);
+ }
+ else if ((codePoint & 0xFFFF0000) == 0) { // 3-byte sequence
+ symbol = stringFromCharCode(((codePoint >> 12) & 0x0F) | 0xE0);
+ symbol += createByte(codePoint, 6);
+ }
+ else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence
+ symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0);
+ symbol += createByte(codePoint, 12);
+ symbol += createByte(codePoint, 6);
+ }
+ symbol += stringFromCharCode((codePoint & 0x3F) | 0x80);
+ return symbol;
+ }
+
+ function utf8encode(string) {
+ var codePoints = ucs2decode(string);
+
+ // console.log(JSON.stringify(codePoints.map(function(x) {
+ // return 'U+' + x.toString(16).toUpperCase();
+ // })));
+
+ var length = codePoints.length;
+ var index = -1;
+ var codePoint;
+ var byteString = '';
+ while (++index < length) {
+ codePoint = codePoints[index];
+ byteString += encodeCodePoint(codePoint);
+ }
+ return byteString;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ function readContinuationByte() {
+ if (byteIndex >= byteCount) {
+ throw Error('Invalid byte index');
+ }
+
+ var continuationByte = byteArray[byteIndex] & 0xFF;
+ byteIndex++;
+
+ if ((continuationByte & 0xC0) == 0x80) {
+ return continuationByte & 0x3F;
+ }
+
+ // If we end up here, it’s not a continuation byte
+ throw Error('Invalid continuation byte');
+ }
+
+ function decodeSymbol() {
+ var byte1;
+ var byte2;
+ var byte3;
+ var byte4;
+ var codePoint;
+
+ if (byteIndex > byteCount) {
+ throw Error('Invalid byte index');
+ }
+
+ if (byteIndex == byteCount) {
+ return false;
+ }
+
+ // Read first byte
+ byte1 = byteArray[byteIndex] & 0xFF;
+ byteIndex++;
+
+ // 1-byte sequence (no continuation bytes)
+ if ((byte1 & 0x80) == 0) {
+ return byte1;
+ }
+
+ // 2-byte sequence
+ if ((byte1 & 0xE0) == 0xC0) {
+ var byte2 = readContinuationByte();
+ codePoint = ((byte1 & 0x1F) << 6) | byte2;
+ if (codePoint >= 0x80) {
+ return codePoint;
+ } else {
+ throw Error('Invalid continuation byte');
+ }
+ }
+
+ // 3-byte sequence (may include unpaired surrogates)
+ if ((byte1 & 0xF0) == 0xE0) {
+ byte2 = readContinuationByte();
+ byte3 = readContinuationByte();
+ codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3;
+ if (codePoint >= 0x0800) {
+ return codePoint;
+ } else {
+ throw Error('Invalid continuation byte');
+ }
+ }
+
+ // 4-byte sequence
+ if ((byte1 & 0xF8) == 0xF0) {
+ byte2 = readContinuationByte();
+ byte3 = readContinuationByte();
+ byte4 = readContinuationByte();
+ codePoint = ((byte1 & 0x0F) << 0x12) | (byte2 << 0x0C) |
+ (byte3 << 0x06) | byte4;
+ if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) {
+ return codePoint;
+ }
+ }
+
+ throw Error('Invalid UTF-8 detected');
+ }
+
+ var byteArray;
+ var byteCount;
+ var byteIndex;
+ function utf8decode(byteString) {
+ byteArray = ucs2decode(byteString);
+ byteCount = byteArray.length;
+ byteIndex = 0;
+ var codePoints = [];
+ var tmp;
+ while ((tmp = decodeSymbol()) !== false) {
+ codePoints.push(tmp);
+ }
+ return ucs2encode(codePoints);
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ var utf8 = {
+ 'version': '2.0.0',
+ 'encode': utf8encode,
+ 'decode': utf8decode
+ };
+
+ // Some AMD build optimizers, like r.js, check for specific condition patterns
+ // like the following:
+ if (
+ typeof define == 'function' &&
+ typeof define.amd == 'object' &&
+ define.amd
+ ) {
+ define(function() {
+ return utf8;
+ });
+ } else if (freeExports && !freeExports.nodeType) {
+ if (freeModule) { // in Node.js or RingoJS v0.8.0+
+ freeModule.exports = utf8;
+ } else { // in Narwhal or RingoJS v0.7.0-
+ var object = {};
+ var hasOwnProperty = object.hasOwnProperty;
+ for (var key in utf8) {
+ hasOwnProperty.call(utf8, key) && (freeExports[key] = utf8[key]);
+ }
+ }
+ } else { // in Rhino or a web browser
+ root.utf8 = utf8;
+ }
+
+}(this));
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-utf8.git
More information about the Pkg-javascript-commits
mailing list