Merge branch 'develop' into 'master'

Version 2.2

Pull Request tracking changes leading up to version 2.2

See merge request !1
This commit is contained in:
Timothy Warren 2016-02-10 12:29:39 -05:00
commit 1fb95adfbf
71 changed files with 4744 additions and 4138 deletions

19
.gitignore vendored
View File

@ -1,21 +1,22 @@
.codelite .codelite
.phing_targets
.sonar/
*.phprj *.phprj
*.workspace *.workspace
vendor vendor
app/cache/* **/cache/**
app/logs/* **/logs/**
**/coverage/**
**/docs/**
public/images/* public/images/*
public/js/cache/*
composer.lock composer.lock
*.sqlite *.sqlite
*.db *.db
*.sqlite3 *.sqlite3
docs/* docs/*
coverage/*
tests/test_data/sessions/* tests/test_data/sessions/*
build/coverage/*
build/logs/*
build/pdepend/*
build/phpdox/*
cache.properties cache.properties
tests/test_data/cache/* build/**
!build/*.txt
!build/*.xml
!build/*.php

7
.htaccess Normal file
View File

@ -0,0 +1,7 @@
#Rewrite index.php out of the app urls
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $1 !^(public)
RewriteRule ^(.*)$ index.php/$1 [L]

View File

@ -15,9 +15,12 @@ script:
- phpunit -c build - phpunit -c build
after_script: after_script:
- wget https://scrutinizer-ci.com/ocular.phar - CODECLIMATE_REPO_TOKEN=2cbddcebcb9256b3402867282e119dbe61de0b31039325356af3c7d72ed6d058 vendor/bin/test-reporter
- php ocular.phar code-coverage:upload --format=php-clover build/logs/coverage.clover
matrix: matrix:
allow_failures: allow_failures:
- php: nightly - php: nightly
addons:
code_climate:
repo_token: 2cbddcebcb9256b3402867282e119dbe61de0b31039325356af3c7d72ed6d058

View File

@ -42,9 +42,36 @@ A self-hosted client that allows custom formatting of data from the hummingbird
2. Configure settings in `app/config/config.php` to your liking 2. Configure settings in `app/config/config.php` to your liking
3. Create the following directories if they don't exist, and make sure they are world writable 3. Create the following directories if they don't exist, and make sure they are world writable
* app/cache * app/cache
* public/js/cache
* public/images/manga * public/images/manga
* public/images/anime * public/images/anime
* public/js/cache
### Server Setup
#### nginx
Basic nginx setup
```nginx
server {
location / {
try_files $uri $uri/ /index.php$uri?$args;
}
location ~ ^(.+\.php)($|/) {
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_index index.php;
}
location ^~ /vendor {
deny all;
}
}
```
#### Apache
Make sure to have `mod_rewrite` and `AllowOverride All` enabled in order to take
advantage of the included `.htaccess` file. If you don't wish to use an `.htaccess` file,
include the contents of the `.htaccess` file in your Apache configuration.
#### Anime Collection Additional Installation #### Anime Collection Additional Installation
* Run `php /vendor/bin/phinx migrate -e development` to create the database tables * Run `php /vendor/bin/phinx migrate -e development` to create the database tables

View File

@ -4,56 +4,78 @@
* *
* An API client for Hummingbird to manage anime and manga watch lists * An API client for Hummingbird to manage anime and manga watch lists
* *
* @package HummingbirdAnimeClient * @package HummingbirdAnimeClient
* @author Timothy J. Warren * @author Timothy J. Warren
* @copyright Copyright (c) 2015 - 2016 * @copyright Copyright (c) 2015 - 2016
* @link https://github.com/timw4mail/HummingBirdAnimeClient * @link https://github.com/timw4mail/HummingBirdAnimeClient
* @license MIT * @license MIT
*/ */
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/* $config = */require 'config.php'; /* $config = */require 'config.php';
// Should we use myth to preprocess? return [
$use_myth = FALSE;
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| CSS Folder | CSS Folder
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| The folder where css files exist, in relation to the document root | The folder where css files exist, in relation to the document root
| |
*/ */
$css_root = $config['asset_dir'] . '/css/'; 'css_root' => $config['asset_dir'] . '/css/',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Path from | Path from
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Path fragment to rewrite in css files | Path fragment to rewrite in css files
| |
*/ */
$path_from = ''; 'path_from' => '',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Path to | Path to
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| The path fragment replacement for the css files | The path fragment replacement for the css files
| |
*/ */
$path_to = ''; 'path_to' => '',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| JS Folder | CSS Groups file
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| The folder where javascript files exist, in relation to the document root | The file where the css groups are configured
| |
*/ */
$js_root = $config['asset_dir'] . '/js/'; 'css_groups_file' => realpath(__DIR__ . '/minify_css_groups.php'),
/*
|--------------------------------------------------------------------------
| JS Folder
|--------------------------------------------------------------------------
|
| The folder where javascript files exist, in relation to the document root
|
*/
'js_root' => $config['asset_dir'] . '/js/',
/*
|--------------------------------------------------------------------------
| JS Groups file
|--------------------------------------------------------------------------
|
| The file where the javascript groups are configured
|
*/
'js_groups_file' => realpath(__DIR__ . '/minify_js_groups.php'),
];
// End of minify_config.php

View File

@ -17,45 +17,33 @@
* This is the config array for javascript files to concatenate and minify * This is the config array for javascript files to concatenate and minify
*/ */
return [ return [
/* 'base' => [
For each group create an array like so 'base/classList.js',
'base/AnimeClient.js',
'my_group' => array(
'path/to/js/file1.js',
'path/to/js/file2.js'
),
*/
'table' => [
'lib/jquery.min.js',
'lib/table_sorter/jquery.tablesorter.min.js',
'sort_tables.js'
], ],
'edit' => [ 'event' => [
'lib/jquery.min.js', 'base/events.js',
'show_message.js', ],
'anime_edit.js', 'table' => [
'manga_edit.js' 'base/sort_tables.js',
], ],
'table_edit' => [ 'table_edit' => [
'lib/jquery.min.js',
'lib/table_sorter/jquery.tablesorter.min.js',
'sort_tables.js', 'sort_tables.js',
'show_message.js',
'anime_edit.js', 'anime_edit.js',
'manga_edit.js' 'manga_edit.js',
],
'edit' => [
'anime_edit.js',
'manga_edit.js',
], ],
'anime_collection' => [ 'anime_collection' => [
'lib/jquery.min.js', 'lib/mustache.js',
'lib/jquery.throttle-debounce.js', 'anime_collection.js',
'lib/jsrender.js',
'anime_collection.js'
], ],
'manga_collection' => [ 'manga_collection' => [
'lib/jquery.min.js', 'lib/mustache.js',
'lib/jquery.throttle-debounce.js', 'manga_collection.js',
'lib/jsrender.js', ],
'manga_collection.js'
]
]; ];
// End of js_groups.php // End of js_groups.php

View File

@ -20,9 +20,6 @@ return [
// Specify default paths and views // Specify default paths and views
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
'route_config' => [ 'route_config' => [
// Subfolder prefix for url, if in a subdirectory of the web root
'subfolder_prefix' => '',
// Path to public directory, where images/css/javascript are located, // Path to public directory, where images/css/javascript are located,
// appended to the url // appended to the url
'asset_path' => '/public', 'asset_path' => '/public',
@ -56,6 +53,30 @@ return [
'action' => 'add', 'action' => 'add',
'verb' => 'post' 'verb' => 'post'
], ],
'anime_detail' => [
'path' => '/anime/details/{id}',
'action' => 'details',
'tokens' => [
'id' => '[a-z0-9\-]+'
]
],
// ---------------------------------------------------------------------
// Manga Routes
// ---------------------------------------------------------------------
'manga_search' => [
'path' => '/manga/search',
'action' => 'search',
],
'manga_add_form' => [
'path' => '/manga/add',
'action' => 'add_form',
'verb' => 'get'
],
'manga_add' => [
'path' => '/manga/add',
'action' => 'add',
'verb' => 'post'
],
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Anime Collection Routes // Anime Collection Routes
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
@ -96,9 +117,10 @@ return [
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Default / Shared routes // Default / Shared routes
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
'login' => [ 'login_form' => [
'path' => '/{controller}/login', 'path' => '/{controller}/login',
'action' => 'login', 'action' => 'login',
'verb' => 'get'
], ],
'login_post' => [ 'login_post' => [
'path' => '/{controller}/login', 'path' => '/{controller}/login',
@ -130,7 +152,7 @@ return [
'action' => 'edit', 'action' => 'edit',
'tokens' => [ 'tokens' => [
'id' => '[0-9a-z_]+', 'id' => '[0-9a-z_]+',
'status' => '[a-zA-z\- ]+', 'status' => '([a-zA-Z\- ]|%20)+',
] ]
], ],
'list' => [ 'list' => [

View File

@ -3,6 +3,11 @@
<h2>Add Anime to your List</h2> <h2>Add Anime to your List</h2>
<form action="<?= $action_url ?>" method="post"> <form action="<?= $action_url ?>" method="post">
<section> <section>
<div class="cssload-loader" hidden="hidden">
<div class="cssload-inner cssload-one"></div>
<div class="cssload-inner cssload-two"></div>
<div class="cssload-inner cssload-three"></div>
</div>
<label for="search">Search for anime by name:&nbsp;&nbsp;&nbsp;&nbsp;<input type="search" id="search" /></label> <label for="search">Search for anime by name:&nbsp;&nbsp;&nbsp;&nbsp;<input type="search" id="search" /></label>
<section id="series_list" class="media-wrap"> <section id="series_list" class="media-wrap">
</section> </section>
@ -30,11 +35,5 @@
</table> </table>
</form> </form>
</main> </main>
<template id="show_list"> <script src="<?= $urlGenerator->asset_url('js.php/g/anime_collection') ?>"></script>
<article class="media">
<div class="name"><label><input type="radio" name="id" value="{{:slug}}" />&nbsp;<span>{{:title}}<br />{{:alternate_title}}</span></label></div>
<img src="{{:cover_image}}" alt="{{:title}}" />
</article>
</template>
<script src="<?= $urlGenerator->asset_url('js.php?g=anime_collection') ?>"></script>
<?php endif ?> <?php endif ?>

View File

@ -65,5 +65,5 @@
<?php endif ?> <?php endif ?>
</main> </main>
<?php if ($auth->is_authenticated()): ?> <?php if ($auth->is_authenticated()): ?>
<script src="<?= $urlGenerator->asset_url('js.php?g=edit') ?>"></script> <script src="<?= $urlGenerator->asset_url('js.php/g/edit') ?>"></script>
<?php endif ?> <?php endif ?>

View File

@ -0,0 +1,11 @@
<main>
<h2><a href="<?= $data['url'] ?>"><?= $data['title'] ?></a></h2>
<?php if( ! empty($data['alternate_title'])): ?>
<h3><?= $data['alternate_title'] ?></h3>
<?php endif ?>
<img src="<?= $data['cover_image'] ?>" alt="<?= $data['title'] ?> cover image" />
<p><?= nl2br($data['synopsis']) ?></p>
<pre><?= print_r($data, TRUE) ?></pre>
</main>

View File

@ -85,5 +85,5 @@
</table> </table>
</form> </form>
</main> </main>
<script src="<?= $urlGenerator->asset_url('js.php?g=edit') ?>"></script> <script src="<?= $urlGenerator->asset_url('js.php/g/edit') ?>"></script>
<?php endif ?> <?php endif ?>

View File

@ -11,7 +11,7 @@
<thead> <thead>
<tr> <tr>
<?php if($auth->is_authenticated()): ?> <?php if($auth->is_authenticated()): ?>
<th>&nbsp;</th> <td class="no_border">&nbsp;</td>
<?php endif ?> <?php endif ?>
<th>Title</th> <th>Title</th>
<th>Airing Status</th> <th>Airing Status</th>
@ -33,7 +33,7 @@
<a class="bracketed" href="<?= $urlGenerator->url("/anime/edit/{$item['id']}/{$item['watching_status']}") ?>">Edit</a> <a class="bracketed" href="<?= $urlGenerator->url("/anime/edit/{$item['id']}/{$item['watching_status']}") ?>">Edit</a>
</td> </td>
<?php endif ?> <?php endif ?>
<td class="align_left"> <td class="justify">
<a href="<?= $item['anime']['url'] ?>" target="_blank"> <a href="<?= $item['anime']['url'] ?>" target="_blank">
<?= $item['anime']['title'] ?> <?= $item['anime']['title'] ?>
</a> </a>
@ -42,7 +42,7 @@
<td class="align_left"><?= $item['airing']['status'] ?></td> <td class="align_left"><?= $item['airing']['status'] ?></td>
<td><?= $item['user_rating'] ?> / 10 </td> <td><?= $item['user_rating'] ?> / 10 </td>
<td><?= $item['anime']['type'] ?></td> <td><?= $item['anime']['type'] ?></td>
<td id="<?= $item['anime']['slug'] ?>"> <td class="align_left" id="<?= $item['anime']['slug'] ?>">
Episodes: <br /> Episodes: <br />
<span class="completed_number"><?= $item['episodes']['watched'] ?></span>&nbsp;/&nbsp;<span class="total_number"><?= $item['episodes']['total'] ?></span> <span class="completed_number"><?= $item['episodes']['watched'] ?></span>&nbsp;/&nbsp;<span class="total_number"><?= $item['episodes']['total'] ?></span>
</td> </td>
@ -74,4 +74,4 @@
<?php endif ?> <?php endif ?>
</main> </main>
<?php $group = ($auth->is_authenticated()) ? 'table_edit' : 'table' ?> <?php $group = ($auth->is_authenticated()) ? 'table_edit' : 'table' ?>
<script src="<?= $urlGenerator->asset_url("js.php?g={$group}") ?>"></script> <script src="<?= $urlGenerator->asset_url("js.php/g/{$group}") ?>"></script>

View File

@ -3,6 +3,11 @@
<h2>Add Anime to your Collection</h2> <h2>Add Anime to your Collection</h2>
<form action="<?= $action_url ?>" method="post"> <form action="<?= $action_url ?>" method="post">
<section> <section>
<div class="cssload-loader" hidden="hidden">
<div class="cssload-inner cssload-one"></div>
<div class="cssload-inner cssload-two"></div>
<div class="cssload-inner cssload-three"></div>
</div>
<label for="search">Search for anime by name:&nbsp;&nbsp;&nbsp;&nbsp;<input type="search" id="search" name="search" /></label> <label for="search">Search for anime by name:&nbsp;&nbsp;&nbsp;&nbsp;<input type="search" id="search" name="search" /></label>
<section id="series_list" class="media-wrap"> <section id="series_list" class="media-wrap">
</section> </section>
@ -34,11 +39,5 @@
</table> </table>
</form> </form>
</main> </main>
<template id="show_list"> <script src="<?= $urlGenerator->asset_url('js.php/g/anime_collection') ?>"></script>
<article class="media">
<div class="name"><label><input type="radio" name="id" value="{{:id}}" />&nbsp;<span>{{:title}}<br />{{:alternate_title}}</span></label></div>
<img src="{{:cover_image}}" alt="{{:title}}" />
</article>
</template>
<script src="<?= $urlGenerator->asset_url('js.php?g=anime_collection') ?>"></script>
<?php endif ?> <?php endif ?>

View File

@ -52,5 +52,5 @@
<img src="{{:cover_image}}" alt="{{:title}}" /> <img src="{{:cover_image}}" alt="{{:title}}" />
</article> </article>
</template> </template>
<script src="<?= $urlGenerator->asset_url('js.php?g=anime_collection') ?>"></script> <script src="<?= $urlGenerator->asset_url('js.php/g/anime_collection') ?>"></script>
<?php endif ?> <?php endif ?>

View File

@ -49,4 +49,4 @@
<?php endforeach ?> <?php endforeach ?>
<?php endif ?> <?php endif ?>
</main> </main>
<script src="<?= $urlGenerator->asset_url('js.php?g=table') ?>"></script> <script src="<?= $urlGenerator->asset_url('js.php/g/table') ?>"></script>

View File

@ -1,2 +1,3 @@
<script src="<?= $urlGenerator->asset_url('js.php/g/event') ?>"></script>
</body> </body>
</html> </html>

View File

@ -4,11 +4,10 @@
<head> <head>
<title><?= $title ?></title> <title><?= $title ?></title>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="stylesheet" href="<?= $urlGenerator->asset_url('css.php?g=base') ?>" /> <meta http-equiv="cache-control" content="no-store" />
<script> <meta http-equiv="Content-Security-Policy" content="script-src 'self'" />
var BASE_URL = "<?= $urlGenerator->base_url($url_type) ?>"; <link rel="stylesheet" href="<?= $urlGenerator->asset_url('css.php/g/base') ?>" />
var CONTROLLER = "<?= $url_type ?>"; <script src="<?= $urlGenerator->asset_url('js.php/g/base') ?>"></script>
</script>
</head> </head>
<body class="<?= $escape->attr($url_type) ?> list"> <body class="<?= $escape->attr($url_type) ?> list">
<header> <header>
@ -48,11 +47,8 @@
</ul> </ul>
<?php endif ?> <?php endif ?>
</nav> </nav>
<?php if(isset($message) && is_array($message)):
extract($message);
include 'message.php';
endif ?>
</header> </header>
<?php if(isset($message) && is_array($message)): ?>
<div class="message <?= $escape->attr($message['message_type']) ?>">
<span class="icon"></span>
<?= $escape->html($message['message']) ?>
<span class="close" onclick="this.parentElement.style.display='none'">x</span>
</div>
<?php endif ?>

View File

@ -0,0 +1,39 @@
<?php if ($auth->is_authenticated()): ?>
<main>
<h2>Add Manga to your List</h2>
<form action="<?= $action_url ?>" method="post">
<section>
<div class="cssload-loader" hidden="hidden">
<div class="cssload-inner cssload-one"></div>
<div class="cssload-inner cssload-two"></div>
<div class="cssload-inner cssload-three"></div>
</div>
<label for="search">Search for manga by name:&nbsp;&nbsp;&nbsp;&nbsp;<input type="search" id="search" /></label>
<section id="series_list" class="media-wrap">
</section>
</section>
<br />
<table class="form">
<tbody>
<tr>
<td><label for="status">Reading Status</label></td>
<td>
<select name="status" id="status">
<?php foreach($status_list as $status_key => $status_title): ?>
<option value="<?= $status_key ?>"><?= $status_title ?></option>
<?php endforeach ?>
</select>
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>
<button type="submit">Save</button>
</td>
</tr>
</tbody>
</table>
</form>
</main>
<script src="<?= $urlGenerator->asset_url('js.php/g/manga_collection') ?>"></script>
<?php endif ?>

View File

@ -1,4 +1,7 @@
<main> <main>
<?php if ($auth->is_authenticated()): ?>
<a class="bracketed" href="<?= $urlGenerator->url('manga/add') ?>">Add Item</a>
<?php endif ?>
<?php if (empty($sections)): ?> <?php if (empty($sections)): ?>
<h3>There's nothing here!</h3> <h3>There's nothing here!</h3>
<?php else: ?> <?php else: ?>
@ -53,5 +56,5 @@
<?php endif ?> <?php endif ?>
</main> </main>
<?php if ($auth->is_authenticated()): ?> <?php if ($auth->is_authenticated()): ?>
<script src="<?= $urlGenerator->asset_url('js.php?g=edit') ?>"></script> <script src="<?= $urlGenerator->asset_url('js.php/g/edit') ?>"></script>
<?php endif ?> <?php endif ?>

View File

@ -85,5 +85,4 @@
</table> </table>
</form> </form>
</main> </main>
<script src="<?= $urlGenerator->asset_url('js.php?g=edit') ?>"></script>
<?php endif ?> <?php endif ?>

View File

@ -1,4 +1,7 @@
<main> <main>
<?php if ($auth->is_authenticated()): ?>
<a class="bracketed" href="<?= $urlGenerator->url('manga/add') ?>">Add Item</a>
<?php endif ?>
<?php if (empty($sections)): ?> <?php if (empty($sections)): ?>
<h3>There's nothing here!</h3> <h3>There's nothing here!</h3>
<?php else: ?> <?php else: ?>
@ -42,4 +45,4 @@
<?php endforeach ?> <?php endforeach ?>
<?php endif ?> <?php endif ?>
</main> </main>
<script src="<?= $urlGenerator->asset_url('js.php?g=table') ?>"></script> <script src="<?= $urlGenerator->asset_url('js.php/g/table') ?>"></script>

5
app/views/message.ms Normal file
View File

@ -0,0 +1,5 @@
<div class="message {{message_type}}">
<span class="icon"></span>
{{message}}
<span class="close">x</span>
</div>

View File

@ -1,5 +1,5 @@
<div class="message <?= $escape->attr($message_type) ?>"> <div class="message <?= $escape->attr($message_type) ?>">
<span class="icon"></span> <span class="icon"></span>
<?= $escape->html($message) ?> <?= $escape->html($message) ?>
<span class="close" onclick="this.parentElement.style.display='none'">x</span> <span class="close"></span>
</div> </div>

120
build.xml
View File

@ -13,10 +13,6 @@
depends="prepare,static-analysis,phpunit,phpdox,sonar" depends="prepare,static-analysis,phpunit,phpdox,sonar"
description="Performs static analysis, runs the tests, and generates project documentation" description="Performs static analysis, runs the tests, and generates project documentation"
/> />
<target name="full-build-parallel"
depends="prepare,static-analysis-parallel,phpunit,phpdox"
description="Performs static analysis (executing the tools in parallel), runs the tests, and generates project documentation"
/>
<target name="quick-build" <target name="quick-build"
depends="prepare,lint,phpunit-no-coverage" depends="prepare,lint,phpunit-no-coverage"
description="Performs a lint check and runs the tests (without generating code coverage reports)" description="Performs a lint check and runs the tests (without generating code coverage reports)"
@ -26,18 +22,6 @@
description="Performs static analysis" description="Performs static analysis"
/> />
<!-- Adjust the threadCount attribute's value to the number of CPUs -->
<target name="static-analysis-parallel" description="Performs static analysis (executing the tools in parallel)">
<parallel threadCount="6">
<sequential>
<antcall target="pdepend" />
</sequential>
<antcall target="lint" />
<antcall target="phpcpd-ci" />
<antcall target="phploc-ci" />
</parallel>
</target>
<target name="clean" unless="clean.done" description="Cleanup build artifacts"> <target name="clean" unless="clean.done" description="Cleanup build artifacts">
<delete dir="build/api" /> <delete dir="build/api" />
<delete dir="build/coverage" /> <delete dir="build/coverage" />
@ -57,23 +41,38 @@
</target> </target>
<target name="lint" unless="lint.done" description="Perform syntax check of sourcecode files"> <target name="lint" unless="lint.done" description="Perform syntax check of sourcecode files">
<apply executable="php" taskname="lint"> <parallel threadcount="6">
<arg value="-l" /> <apply executable="php" passthru="true" taskname="lint">
<arg value="-l" />
<fileset dir="src"> <fileset dir=".">
<include name="**/*.php" /> <include name="src/Aviat/AnimeClient/**/*.php" />
</fileset> </fileset>
</apply>
<fileset dir="tests"> <apply executable="php" passthru="true" taskname="lint">
<include name="**/*.php" /> <arg value="-l" />
</fileset> <fileset dir=".">
</apply> <include name="src/Aviat/Ion/**/*.php" />
</fileset>
</apply>
<apply executable="php" passthru="true" taskname="lint">
<arg value="-l" />
<fileset dir=".">
<include name="tests/AnimeClient/**/*.php" />
</fileset>
</apply>
<apply executable="php" passthru="true" taskname="lint">
<arg value="-l" />
<fileset dir=".">
<include name="tests/Ion/**/*.php" />
</fileset>
</apply>
</parallel>
<property name="lint.done" value="true" /> <property name="lint.done" value="true" />
</target> </target>
<target name="phploc" unless="phploc.done" description="Measure project size using PHPLOC and print human readable output. Intended for usage on the command line."> <target name="phploc" unless="phploc.done" description="Measure project size using PHPLOC and print human readable output. Intended for usage on the command line.">
<exec executable="${phploc}" taskname="phploc"> <exec executable="${phploc}" passthru="true" taskname="phploc">
<arg value="--count-tests" /> <arg value="--count-tests" />
<arg path="src" /> <arg path="src" />
<arg path="tests" /> <arg path="tests" />
@ -83,50 +82,61 @@
</target> </target>
<target name="phploc-ci" depends="prepare" unless="phploc.done" description="Measure project size using PHPLOC and log result in CSV and XML format. Intended for usage within a continuous integration environment."> <target name="phploc-ci" depends="prepare" unless="phploc.done" description="Measure project size using PHPLOC and log result in CSV and XML format. Intended for usage within a continuous integration environment.">
<exec executable="${phploc}" taskname="phploc"> <parallel threadcount="2">
<arg value="--count-tests" /> <phploc countTests="true" reportType="csv" reportDirectory="build/logs" reportName="phploc" taskname="csv report">
<arg value="--log-csv" /> <fileset dir=".">
<arg path="build/logs/phploc.csv" /> <include name="src/**/*.php" />
<arg value="--log-xml" /> <include name="tests/**/*.php" />
<arg path="build/logs/phploc.xml" /> </fileset>
<arg path="src" /> </phploc>
<arg path="tests" /> <phploc countTests="true" reportType="xml" reportDirectory="build/logs" reportName="phploc" taskname="xml report">
</exec> <fileset dir=".">
<include name="src/**/*.php" />
<include name="tests/**/*.php" />
</fileset>
</phploc>
</parallel>
<property name="phploc.done" value="true" /> <property name="phploc.done" value="true" />
</target> </target>
<target name="pdepend" depends="prepare" unless="pdepend.done" description="Calculate software metrics using PHP_Depend and log result in XML format. Intended for usage within a continuous integration environment."> <target name="pdepend" depends="prepare" unless="pdepend.done" description="Calculate software metrics using PHP_Depend and log result in XML format. Intended for usage within a continuous integration environment.">
<exec executable="${pdepend}" taskname="pdepend"> <phpdepend>
<arg value="--jdepend-xml=build/logs/jdepend.xml" /> <fileset dir=".">
<arg value="--jdepend-chart=build/pdepend/dependencies.svg" /> <include name="src/**/*.php" />
<arg value="--overview-pyramid=build/pdepend/overview-pyramid.svg" /> </fileset>
<arg path="src" /> <logger type="jdepend-xml" outfile="build/logs/jdepend.xml" />
</exec> <logger type="jdepend-chart" outfile="build/pdepend/dependencies.svg" />
<logger type="overview-pyramid" outfile="build/pdepend/overview-pyramid.svg" />
</phpdepend>
<property name="pdepend.done" value="true" /> <property name="pdepend.done" value="true" />
</target> </target>
<target name="phpcpd" unless="phpcpd.done" description="Find duplicate code using PHPCPD and print human readable output. Intended for usage on the command line before committing."> <target name="phpcpd" unless="phpcpd.done" description="Find duplicate code using PHPCPD and print human readable output. Intended for usage on the command line before committing.">
<exec executable="${phpcpd}" taskname="phpcpd"> <phpcpd>
<arg path="src" /> <formatter type="default" usefile="false" />
</exec> <fileset dir=".">
<include name="src/**/*.php" />
</fileset>
</phpcpd>
<property name="phpcpd.done" value="true" /> <property name="phpcpd.done" value="true" />
</target> </target>
<target name="phpcpd-ci" depends="prepare" unless="phpcpd.done" description="Find duplicate code using PHPCPD and log result in XML format. Intended for usage within a continuous integration environment."> <target name="phpcpd-ci" depends="prepare" unless="phpcpd.done" description="Find duplicate code using PHPCPD and log result in XML format. Intended for usage within a continuous integration environment.">
<exec executable="${phpcpd}" taskname="phpcpd"> <phpcpd>
<arg value="--log-pmd" /> <formatter type="pmd" outfile="build/logs/pmd-cpd.xml" />
<arg path="build/logs/pmd-cpd.xml" /> <fileset dir=".">
<arg path="src" /> <include name="src/**/*.php" />
</exec> </fileset>
</phpcpd>
<property name="phpcpd.done" value="true" /> <property name="phpcpd.done" value="true" />
</target> </target>
<target name="phpunit" unless="phpunit.done" depends="prepare" description="Run unit tests with PHPUnit"> <target name="phpunit" unless="phpunit.done" depends="prepare" description="Run unit tests with PHPUnit">
<exec executable="${phpunit}" taskname="phpunit"> <exec executable="${phpunit}" logoutput="true" passthru="true" checkreturn="true" taskname="phpunit">
<arg value="--configuration" /> <arg value="--configuration" />
<arg path="build/phpunit.xml" /> <arg path="build/phpunit.xml" />
</exec> </exec>
@ -135,7 +145,7 @@
</target> </target>
<target name="phpunit-no-coverage" depends="prepare" unless="phpunit.done" description="Run unit tests with PHPUnit (without generating code coverage reports)"> <target name="phpunit-no-coverage" depends="prepare" unless="phpunit.done" description="Run unit tests with PHPUnit (without generating code coverage reports)">
<exec executable="${phpunit}" failonerror="true" taskname="phpunit"> <exec executable="${phpunit}" passthru="true" taskname="phpunit">
<arg value="--configuration" /> <arg value="--configuration" />
<arg path="build/phpunit.xml" /> <arg path="build/phpunit.xml" />
<arg value="--no-coverage" /> <arg value="--no-coverage" />
@ -145,13 +155,13 @@
</target> </target>
<target name="phpdox" depends="phploc-ci,phpunit" unless="phpdox.done" description="Generate project documentation using phpDox"> <target name="phpdox" depends="phploc-ci,phpunit" unless="phpdox.done" description="Generate project documentation using phpDox">
<exec dir="build" executable="${phpdox}" taskname="phpdox" /> <exec dir="build" executable="${phpdox}" passthru="true" taskname="phpdox" />
<property name="phpdox.done" value="true" /> <property name="phpdox.done" value="true" />
</target> </target>
<target name="sonar" depends="phpunit" unless="sonar.done" description="Generate code analysis with sonarqube"> <target name="sonar" depends="phpunit" unless="sonar.done" description="Generate code analysis with sonarqube">
<exec executable="${sonar}" taskname="sonar" /> <exec executable="${sonar}" passthru="true" taskname="sonar" />
<property name="sonar.done" value="true" /> <property name="sonar.done" value="true" />
</target> </target>

View File

@ -17,5 +17,8 @@
"psr/log": "~1.0", "psr/log": "~1.0",
"robmorgan/phinx": "0.4.*", "robmorgan/phinx": "0.4.*",
"yosymfony/toml": "0.3.*" "yosymfony/toml": "0.3.*"
},
"require-dev": {
"codeclimate/php-test-reporter": "dev-master"
} }
} }

View File

@ -4,134 +4,174 @@
* *
* An API client for Hummingbird to manage anime and manga watch lists * An API client for Hummingbird to manage anime and manga watch lists
* *
* @package HummingbirdAnimeClient * @package HummingbirdAnimeClient
* @author Timothy J. Warren * @author Timothy J. Warren
* @copyright Copyright (c) 2015 - 2016 * @copyright Copyright (c) 2015 - 2016
* @link https://github.com/timw4mail/HummingBirdAnimeClient * @link https://github.com/timw4mail/HummingBirdAnimeClient
* @license MIT * @license MIT
*/ */
namespace Aviat\EasyMin;
require_once('./min.php');
/**
* Simple CSS Minifier
*/
class CSSMin extends BaseMin {
protected $css_root;
protected $path_from;
protected $path_to;
protected $group;
protected $last_modified;
protected $requested_time;
public function __construct(array $config, array $groups)
{
$group = $_GET['g'];
$this->css_root = $config['css_root'];
$this->path_from = $config['path_from'];
$this->path_to = $config['path_to'];
$this->group = $groups[$group];
$this->last_modified = $this->get_last_modified();
$this->send();
}
/**
* Send the CSS
*
* @return void
*/
protected function send()
{
if($this->last_modified >= $this->get_if_modified() && $this->is_not_debug())
{
throw new FileNotChangedException();
}
$css = ( ! array_key_exists('debug', $_GET))
? $this->compress($this->get_css())
: $this->get_css();
$this->output($css);
}
/**
* Function for compressing the CSS as tightly as possible
*
* @param string $buffer
* @return string
*/
protected function compress($buffer)
{
//Remove CSS comments
$buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);
//Remove tabs, spaces, newlines, etc.
$buffer = preg_replace('`\s+`', ' ', $buffer);
$replace = array(
' )' => ')',
') ' => ')',
' }' => '}',
'} ' => '}',
' {' => '{',
'{ ' => '{',
', ' => ',',
': ' => ':',
'; ' => ';',
);
//Eradicate every last space!
$buffer = trim(strtr($buffer, $replace));
$buffer = str_replace('{ ', '{', $buffer);
$buffer = str_replace('} ', '}', $buffer);
return $buffer;
}
/**
* Get the most recent file modification date
*
* @return int
*/
protected function get_last_modified()
{
$modified = array();
// Get all the css files, and concatenate them together
if(isset($this->group))
{
foreach($this->group as $file)
{
$new_file = realpath("{$this->css_root}{$file}");
$modified[] = filemtime($new_file);
}
}
//Add this page for last modified check
$modified[] = filemtime(__FILE__);
//Get the latest modified date
rsort($modified);
return array_shift($modified);
}
/**
* Get the css to display
*
* @return string
*/
protected function get_css()
{
$css = '';
foreach($this->group as $file)
{
$new_file = realpath("{$this->css_root}{$file}");
$css .= file_get_contents($new_file);
}
// Correct paths that have changed due to concatenation
// based on rules in the config file
$css = str_replace($this->path_from, $this->path_to, $css);
return $css;
}
/**
* Output the CSS
*
* @return void
*/
protected function output($css)
{
$this->send_final_output($css, 'text/css', $this->last_modified);
}
}
// --------------------------------------------------------------------------
// ! Start Minifying
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//Get config files //Get config files
require('../app/config/minify_config.php'); $config = require('../app/config/minify_config.php');
$groups = require($config['css_groups_file']);
//Include the css groups if ( ! array_key_exists($_GET['g'], $groups))
$groups = require("../app/config/minify_css_groups.php");
//Function for compressing the CSS as tightly as possible
/**
* @param string $buffer
*/
function compress($buffer) {
//Remove CSS comments
$buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);
//Remove tabs, spaces, newlines, etc.
$buffer = preg_replace('`\s+`', ' ', $buffer);
$replace = array(
' )' => ')',
') ' => ')',
' }' => '}',
'} ' => '}',
' {' => '{',
'{ ' => '{',
', ' => ',',
': ' => ':',
'; ' => ';',
);
//Eradicate every last space!
$buffer = trim(strtr($buffer, $replace));
$buffer = str_replace('{ ', '{', $buffer);
$buffer = str_replace('} ', '}', $buffer);
return $buffer;
}
function get_last_modifed()
{ {
global $groups, $css_root; throw new InvalidArgumentException('You must specify a css group that exists');
$modified = array();
// Get all the css files, and concatenate them together
if(isset($groups[$_GET['g']]))
{
foreach($groups[$_GET['g']] as $file)
{
$new_file = realpath($css_root.$file);
$modified[] = filemtime($new_file);
}
}
//Add myth css file for last modified check
$modified[] = filemtime(realpath("css/base.myth.css"));
//Add this page for last modified check
$modified[] = filemtime(__FILE__);
//Get the latest modified date
rsort($modified);
$last_modified = $modified[0];
return $last_modified;
} }
function get_css() try
{ {
global $groups, $path_from, $path_to, $css_root; new CSSMin($config, $groups);
$css = '';
if(isset($groups[$_GET['g']]))
{
foreach($groups[$_GET['g']] as $file)
{
$new_file = realpath($css_root.$file);
$css .= file_get_contents($new_file);
$modified[] = filemtime($new_file);
}
}
// If not in debug mode, minify the css
if( ! isset($_GET['debug']))
{
$css = compress($css);
}
// Correct paths that have changed due to concatenation
// based on rules in the config file
$css = strtr($css, $path_from, $path_to);
return $css;
} }
catch (FileNotChangedException $e)
// --------------------------------------------------------------------------
$last_modified = get_last_modifed();
$requested_time=(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']))
? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])
: 0;
// Send 304 when not modified for faster response
if($last_modified === $requested_time)
{ {
header("HTTP/1.1 304 Not Modified"); BaseMin::send304();
exit();
} }
//This GZIPs the CSS for transmission to the user
//making file size smaller and transfer rate quicker
ob_start("ob_gzhandler");
header("Content-Type: text/css; charset=utf8");
header("Cache-control: public, max-age=691200, must-revalidate");
header("Last-Modified: ".gmdate('D, d M Y H:i:s', $last_modified)." GMT");
header("Expires: ".gmdate('D, d M Y H:i:s', (filemtime(basename(__FILE__)) + 691200))." GMT");
echo get_css();
ob_end_flush();
//End of css.php //End of css.php

View File

@ -6,53 +6,46 @@ body {
margin: 0.5em; margin: 0.5em;
} }
a:hover, button {
a:active { background: rgba(255,255,255,0.65);
color: #7d12db; margin: 0;
} }
table { table {
width: 85%; min-width: 85%;
margin: 0 auto; margin: 0 auto;
} }
tbody > tr:nth-child(odd) { td {
background: #ddd; padding: 1em;
padding: 1rem;
}
thead td,
thead th {
padding: 0.5em;
padding: 0.5rem;
} }
input[type=number] { input[type=number] {
width: 4em; width: 4em;
} }
.form { tbody > tr:nth-child(odd) {
width: 100%; background: #ddd;
} }
.form tr > td:nth-child(odd) { a:hover,
text-align: right; a:active {
min-width: 25px; color: #7d12db;
max-width: 30%;
} }
.form tr > td:nth-child(even) { /* -----------------------------------------------------------------------------
text-align: left; Utility classes
min-width: 70%; ------------------------------------------------------------------------------*/
}
.form thead th, .bracketed {
.form thead tr { color: #12db18;
background: inherit;
border: 0;
}
.form.invisible tr:nth-child(odd) {
background: inherit;
}
.form.invisible tr,
.form.invisible td,
.form.invisible th {
border: 0;
} }
.bracketed, .bracketed,
@ -68,10 +61,6 @@ h1 a {
content: '\00a0]'; content: '\00a0]';
} }
.bracketed {
color: #12db18;
}
.bracketed:hover, .bracketed:hover,
.bracketed:active { .bracketed:active {
color: #db7d12; color: #db7d12;
@ -132,6 +121,10 @@ h1 a {
font-size: 1.6rem; font-size: 1.6rem;
} }
.justify {
text-align: justify;
}
.align_center { .align_center {
text-align: center; text-align: center;
} }
@ -144,11 +137,257 @@ h1 a {
text-align: right; text-align: right;
} }
.no_border {
border: none;
}
.media-wrap { .media-wrap {
text-align: center; text-align: center;
margin: 0 auto; margin: 0 auto;
} }
/* -----------------------------------------------------------------------------
CSS loading icon
------------------------------------------------------------------------------*/
.cssload-loader {
position: relative;
left: calc(50% - 31px);
width: 62px;
height: 62px;
border-radius: 50%;
-webkit-perspective: 780px;
perspective: 780px;
}
.cssload-inner {
position: absolute;
width: 100%;
height: 100%;
box-sizing: border-box;
border-radius: 50%;
}
.cssload-inner.cssload-one {
left: 0%;
top: 0%;
-webkit-animation: cssload-rotate-one 1.15s linear infinite;
animation: cssload-rotate-one 1.15s linear infinite;
border-bottom: 3px solid rgb(0,0,0);
}
.cssload-inner.cssload-two {
right: 0%;
top: 0%;
-webkit-animation: cssload-rotate-two 1.15s linear infinite;
animation: cssload-rotate-two 1.15s linear infinite;
border-right: 3px solid rgb(0,0,0);
}
.cssload-inner.cssload-three {
right: 0%;
bottom: 0%;
-webkit-animation: cssload-rotate-three 1.15s linear infinite;
animation: cssload-rotate-three 1.15s linear infinite;
border-top: 3px solid rgb(0,0,0);
}
@-webkit-keyframes cssload-rotate-one {
0% {
-webkit-transform: rotateX(35deg) rotateY(-45deg) rotateZ(0deg);
transform: rotateX(35deg) rotateY(-45deg) rotateZ(0deg);
}
100% {
-webkit-transform: rotateX(35deg) rotateY(-45deg) rotateZ(360deg);
transform: rotateX(35deg) rotateY(-45deg) rotateZ(360deg);
}
}
@keyframes cssload-rotate-one {
0% {
-webkit-transform: rotateX(35deg) rotateY(-45deg) rotateZ(0deg);
transform: rotateX(35deg) rotateY(-45deg) rotateZ(0deg);
}
100% {
-webkit-transform: rotateX(35deg) rotateY(-45deg) rotateZ(360deg);
transform: rotateX(35deg) rotateY(-45deg) rotateZ(360deg);
}
}
@-webkit-keyframes cssload-rotate-two {
0% {
-webkit-transform: rotateX(50deg) rotateY(10deg) rotateZ(0deg);
transform: rotateX(50deg) rotateY(10deg) rotateZ(0deg);
}
100% {
-webkit-transform: rotateX(50deg) rotateY(10deg) rotateZ(360deg);
transform: rotateX(50deg) rotateY(10deg) rotateZ(360deg);
}
}
@keyframes cssload-rotate-two {
0% {
-webkit-transform: rotateX(50deg) rotateY(10deg) rotateZ(0deg);
transform: rotateX(50deg) rotateY(10deg) rotateZ(0deg);
}
100% {
-webkit-transform: rotateX(50deg) rotateY(10deg) rotateZ(360deg);
transform: rotateX(50deg) rotateY(10deg) rotateZ(360deg);
}
}
@-webkit-keyframes cssload-rotate-three {
0% {
-webkit-transform: rotateX(35deg) rotateY(55deg) rotateZ(0deg);
transform: rotateX(35deg) rotateY(55deg) rotateZ(0deg);
}
100% {
-webkit-transform: rotateX(35deg) rotateY(55deg) rotateZ(360deg);
transform: rotateX(35deg) rotateY(55deg) rotateZ(360deg);
}
}
@keyframes cssload-rotate-three {
0% {
-webkit-transform: rotateX(35deg) rotateY(55deg) rotateZ(0deg);
transform: rotateX(35deg) rotateY(55deg) rotateZ(0deg);
}
100% {
-webkit-transform: rotateX(35deg) rotateY(55deg) rotateZ(360deg);
transform: rotateX(35deg) rotateY(55deg) rotateZ(360deg);
}
}
/* -----------------------------------------------------------------------------
Table sorting and form styles
------------------------------------------------------------------------------*/
.sorting,
.sorting_asc,
.sorting_desc {
vertical-align: text-bottom;
}
.sorting::before {
content: " ↕\00a0";
}
.sorting_asc::before {
content: " ↑\00a0";
}
.sorting_desc::before {
content: " ↓\00a0";
}
.form {
width: 100%;
}
.form thead th,
.form thead tr {
background: inherit;
border: 0;
}
.form tr > td:nth-child(odd) {
text-align: right;
min-width: 25px;
max-width: 30%;
}
.form tr > td:nth-child(even) {
text-align: left;
min-width: 70%;
}
.form.invisible tr:nth-child(odd) {
background: inherit;
}
.form.invisible tr,
.form.invisible td,
.form.invisible th {
border: 0;
}
/* -----------------------------------------------------------------------------
Message boxes
------------------------------------------------------------------------------*/
.message {
position: relative;
margin: 0.5em auto;
padding: 0.5em;
width: 95%;
}
.message .close {
width: 1em;
height: 1em;
position: absolute;
right: 0.5em;
top: 0.5em;
text-align: center;
vertical-align: middle;
line-height: 1em;
}
/*.message .close:after {
content: '☐';
}*/
.message:hover .close:after {
content: '☒';
}
.message:hover {
cursor: pointer;
}
.message .icon {
left: 0.5em;
top: 0.5em;
margin-right: 1em;
}
.message.error {
border: 1px solid #924949;
background: #f3e6e6;
}
.message.error .icon::after {
content: '✘';
}
.message.success {
border: 1px solid #1f8454;
background: #70dda9;
}
.message.success .icon::after {
content: '✔';
}
.message.info {
border: 1px solid #bfbe3a;
background: #FFFFCC;
}
.message.info .icon::after {
content: '⚠';
}
/* -----------------------------------------------------------------------------
Base list styles
------------------------------------------------------------------------------*/
.media { .media {
position: relative; position: relative;
vertical-align: top; vertical-align: top;
@ -159,11 +398,6 @@ h1 a {
margin: 0.25em; margin: 0.25em;
} }
button {
background: rgba(255,255,255,0.65);
margin: 0;
}
.media .edit_buttons > button { .media .edit_buttons > button {
margin: 0.5em auto; margin: 0.5em auto;
} }
@ -224,53 +458,6 @@ button {
text-shadow: 1px 2px 1px rgba(0, 0, 0, 0.85); text-shadow: 1px 2px 1px rgba(0, 0, 0, 0.85);
} }
/* -----------------------------------------------------------------------------
Message boxes
------------------------------------------------------------------------------*/
.message {
position: relative;
margin: 0.5em auto;
padding: 0.5em;
width: 95%;
}
.message .close {
width: 1em;
height: 1em;
position: absolute;
right: 0.5em;
top: 0.5em;
text-align: center;
vertical-align: middle;
line-height: 1em;
}
.message .close:hover {
cursor: pointer;
}
.message .icon {
left: 0.5em;
top: 0.5em;
margin-right: 1em;
}
.message.error {
border: 1px solid #924949;
background: #f3e6e6;
}
.message.success {
border: 1px solid #1f8454;
background: #70dda9;
}
.message.info {
border: 1px solid #bfbe3a;
background: #FFFFCC;
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
Anime-list-specific styles Anime-list-specific styles
------------------------------------------------------------------------------*/ ------------------------------------------------------------------------------*/
@ -371,3 +558,52 @@ button {
left: 5px; left: 5px;
left: calc(50% - 95px); left: calc(50% - 95px);
} }
/* -----------------------------------------------------------------------------
Page-specific styles
------------------------------------------------------------------------------*/
.media.search > .name {
background-color: #555;
background-color: rgba(000,000,000,0.35);
background-size: cover;
background-size: contain;
background-repeat: no-repeat;
}
.big-check {
display: none;
}
.big-check:checked + label {
-webkit-transition: .25s ease;
transition: .25s ease;
background: rgba(0,0,0,0.75);
}
.big-check:checked + label:after {
content: '✓';
font-size: 15em;
font-size: 15rem;
text-align: center;
color: greenyellow;
position: absolute;
top: 5px;
left: 0;
height: 100%;
width: 100%;
}
#series_list article.media {
position: relative;
}
#series_list .name,
#series_list .name label {
position: absolute;
display: block;
top: 0;
height: 100%;
width: 100%;
vertical-align: middle;
}

View File

@ -13,54 +13,50 @@ template {display:none}
body {margin: 0.5em;} body {margin: 0.5em;}
a:hover, a:active { button {
color: var(--link-hover-color) background:rgba(255,255,255,0.65);
margin: 0;
} }
table { table {
width:85%; min-width:85%;
margin: 0 auto; margin: 0 auto;
} }
tbody > tr:nth-child(odd) { td {
background: #ddd; padding:1em;
padding:1rem;
}
thead td, thead th {
padding:0.5em;
padding:0.5rem;
} }
input[type=number] { input[type=number] {
width: 4em; width: 4em;
} }
.form { width:100%; } tbody > tr:nth-child(odd) {
.form tr > td:nth-child(odd) { background: #ddd;
text-align:right;
min-width:25px;
max-width:30%;
}
.form tr > td:nth-child(even) {
text-align:left;
min-width:70%;
} }
.form thead th, .form thead tr { a:hover, a:active {
background: inherit; color: var(--link-hover-color)
border:0;
} }
.form.invisible tr:nth-child(odd) { /* -----------------------------------------------------------------------------
background: inherit; Utility classes
} ------------------------------------------------------------------------------*/
.form.invisible tr, .form.invisible td, .form.invisible th {
border:0;
}
.bracketed {
color: var(--edit-link-color);
}
.bracketed, h1 a { .bracketed, h1 a {
text-shadow: var(--link-shadow); text-shadow: var(--link-shadow);
} }
.bracketed:before {content: '[\00a0'} .bracketed:before {content: '[\00a0'}
.bracketed:after {content: '\00a0]'} .bracketed:after {content: '\00a0]'}
.bracketed {
color: var(--edit-link-color);
}
.bracketed:hover, .bracketed:active { .bracketed:hover, .bracketed:active {
color: var(--edit-link-hover-color) color: var(--edit-link-hover-color)
} }
@ -78,15 +74,202 @@ input[type=number] {
font-size:1.6rem; font-size:1.6rem;
} }
.justify {text-align:justify}
.align_center {text-align:center} .align_center {text-align:center}
.align_left {text-align:left;} .align_left {text-align:left}
.align_right {text-align:right;} .align_right {text-align:right}
.no_border {border:none}
.media-wrap { .media-wrap {
text-align:center; text-align:center;
margin:0 auto; margin:0 auto;
} }
/* -----------------------------------------------------------------------------
CSS loading icon
------------------------------------------------------------------------------*/
.cssload-loader {
position: relative;
left: calc(50% - 31px);
width: 62px;
height: 62px;
border-radius: 50%;
perspective: 780px;
}
.cssload-inner {
position: absolute;
width: 100%;
height: 100%;
box-sizing: border-box;
border-radius: 50%;
}
.cssload-inner.cssload-one {
left: 0%;
top: 0%;
animation: cssload-rotate-one 1.15s linear infinite;
border-bottom: 3px solid rgb(0,0,0);
}
.cssload-inner.cssload-two {
right: 0%;
top: 0%;
animation: cssload-rotate-two 1.15s linear infinite;
border-right: 3px solid rgb(0,0,0);
}
.cssload-inner.cssload-three {
right: 0%;
bottom: 0%;
animation: cssload-rotate-three 1.15s linear infinite;
border-top: 3px solid rgb(0,0,0);
}
@keyframes cssload-rotate-one {
0% {
transform: rotateX(35deg) rotateY(-45deg) rotateZ(0deg);
}
100% {
transform: rotateX(35deg) rotateY(-45deg) rotateZ(360deg);
}
}
@keyframes cssload-rotate-two {
0% {
transform: rotateX(50deg) rotateY(10deg) rotateZ(0deg);
}
100% {
transform: rotateX(50deg) rotateY(10deg) rotateZ(360deg);
}
}
@keyframes cssload-rotate-three {
0% {
transform: rotateX(35deg) rotateY(55deg) rotateZ(0deg);
}
100% {
transform: rotateX(35deg) rotateY(55deg) rotateZ(360deg);
}
}
/* -----------------------------------------------------------------------------
Table sorting and form styles
------------------------------------------------------------------------------*/
.sorting,
/*.sorting::before,*/
.sorting_asc,
/*.sorting_asc::before,*/
.sorting_desc
/*.sorting_desc::before*/ {
vertical-align:text-bottom;
}
.sorting::before {
content: " ↕\00a0";
}
.sorting_asc::before {
content: " ↑\00a0";
}
.sorting_desc::before {
content: " ↓\00a0";
}
.form { width:100%; }
.form thead th, .form thead tr {
background: inherit;
border:0;
}
.form tr > td:nth-child(odd) {
text-align:right;
min-width:25px;
max-width:30%;
}
.form tr > td:nth-child(even) {
text-align:left;
min-width:70%;
}
.form.invisible tr:nth-child(odd) {
background: inherit;
}
.form.invisible tr, .form.invisible td, .form.invisible th {
border:0;
}
/* -----------------------------------------------------------------------------
Message boxes
------------------------------------------------------------------------------*/
.message{
position:relative;
margin:0.5em auto;
padding:0.5em;
width:95%;
}
.message .close{
width:1em;
height:1em;
position:absolute;
right:0.5em;
top:0.5em;
text-align:center;
vertical-align:middle;
line-height:1em;
}
/*.message .close:after {
content: '☐';
}*/
.message:hover .close:after {
content: '☒';
}
.message:hover {
cursor:pointer;
}
.message .icon{
left:0.5em;
top:0.5em;
margin-right:1em;
}
.message.error{
border:1px solid #924949;
background: #f3e6e6;
}
.message.error .icon::after {
content: '✘';
}
.message.success{
border:1px solid #1f8454;
background: #70dda9;
}
.message.success .icon::after {
content: '✔'
}
.message.info{
border:1px solid #bfbe3a;
background: #FFFFCC;
}
.message.info .icon::after {
content: '⚠';
}
/* -----------------------------------------------------------------------------
Base list styles
------------------------------------------------------------------------------*/
.media { .media {
position:relative; position:relative;
vertical-align:top; vertical-align:top;
@ -97,11 +280,6 @@ input[type=number] {
margin: var(--normal-padding); margin: var(--normal-padding);
} }
button {
background:rgba(255,255,255,0.65);
margin: 0;
}
.media .edit_buttons > button { .media .edit_buttons > button {
margin:0.5em auto; margin:0.5em auto;
} }
@ -161,52 +339,7 @@ button {
text-shadow: var(--shadow); text-shadow: var(--shadow);
} }
/* -----------------------------------------------------------------------------
Message boxes
------------------------------------------------------------------------------*/
.message{
position:relative;
margin:0.5em auto;
padding:0.5em;
width:95%;
}
.message .close{
width:1em;
height:1em;
position:absolute;
right:0.5em;
top:0.5em;
text-align:center;
vertical-align:middle;
line-height:1em;
}
.message .close:hover {
cursor:pointer;
}
.message .icon{
left:0.5em;
top:0.5em;
margin-right:1em;
}
.message.error{
border:1px solid #924949;
background: #f3e6e6;
}
.message.success{
border:1px solid #1f8454;
background: #70dda9;
}
.message.info{
border:1px solid #bfbe3a;
background: #FFFFCC;
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
Anime-list-specific styles Anime-list-specific styles
@ -293,3 +426,52 @@ button {
left: 5px; left: 5px;
left: calc(50% - 95px); left: calc(50% - 95px);
} }
/* -----------------------------------------------------------------------------
Page-specific styles
------------------------------------------------------------------------------*/
.media.search > .name {
background-color:#555;
background-color: rgba(000,000,000,0.35);
background-size: cover;
background-size: contain;
background-repeat: no-repeat;
}
.big-check {
display:none;
}
.big-check:checked + label {
transition: .25s ease;
background:rgba(0,0,0,0.75);
}
.big-check:checked + label:after {
content: '✓';
font-size: 15em;
font-size: 15rem;
text-align:center;
color: greenyellow;
position:absolute;
top:5px;
left:0;
height:100%;
width:100%;
}
#series_list article.media {
position:relative;
}
#series_list .name, #series_list .name label {
position:absolute;
display:block;
top:0;
height:100%;
width:100%;
vertical-align:middle;
}

View File

@ -111,7 +111,6 @@ button,
input, input,
select, select,
textarea { textarea {
/*background-color: transparent;*/
border: .1rem solid #ccc; border: .1rem solid #ccc;
color: inherit; color: inherit;
font-family: inherit; font-family: inherit;
@ -507,7 +506,7 @@ textarea {
input[type=submit], input[type=submit],
button { button {
background-color: transparent; /*background-color: transparent;*/
border: .2rem solid #444; border: .2rem solid #444;
border-radius: 0; border-radius: 0;
color: #444; color: #444;

View File

@ -78,7 +78,6 @@ audio, canvas, iframe, img, svg, video {
vertical-align: middle; } vertical-align: middle; }
button, input, select, textarea { button, input, select, textarea {
/*background-color: transparent;*/
border: .1rem solid #ccc; border: .1rem solid #ccc;
color: inherit; color: inherit;
font-family: inherit; font-family: inherit;
@ -342,7 +341,7 @@ textarea {
vertical-align: middle; } vertical-align: middle; }
input[type=submit], button { input[type=submit], button {
background-color: transparent; /*background-color: transparent;*/
border: .2rem solid #444; border: .2rem solid #444;
border-radius: 0; border-radius: 0;
color: #444; color: #444;

View File

@ -4,223 +4,243 @@
* *
* An API client for Hummingbird to manage anime and manga watch lists * An API client for Hummingbird to manage anime and manga watch lists
* *
* @package HummingbirdAnimeClient * @package HummingbirdAnimeClient
* @author Timothy J. Warren * @author Timothy J. Warren
* @copyright Copyright (c) 2015 - 2016 * @copyright Copyright (c) 2015 - 2016
* @link https://github.com/timw4mail/HummingBirdAnimeClient * @link https://github.com/timw4mail/HummingBirdAnimeClient
* @license MIT * @license MIT
*/ */
// -------------------------------------------------------------------------- namespace Aviat\EasyMin;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request; use GuzzleHttp\Psr7\Request;
//Get config files
require_once('../app/config/minify_config.php');
//Include the js groups
$groups_file = "../app/config/minify_js_groups.php";
$groups = require_once($groups_file);
// Include guzzle // Include guzzle
require_once('../vendor/autoload.php'); require_once('../vendor/autoload.php');
require_once('./min.php');
//The name of this file
$this_file = __FILE__;
// --------------------------------------------------------------------------
/** /**
* Get Files * Simple Javascript minfier, using google closure compiler
*
* Concatenates the javascript files for the current
* group as a string
* @return string
*/ */
function get_files() class JSMin extends BaseMin {
{
global $groups, $js_root;
$js = ''; protected $js_root;
protected $js_group;
protected $js_groups_file;
protected $cache_file;
foreach($groups[$_GET['g']] as $file) protected $last_modified;
protected $requested_time;
protected $cache_modified;
public function __construct(array $config, array $groups)
{ {
$new_file = realpath($js_root.$file); $group = $_GET['g'];
$js .= file_get_contents($new_file) . "\n\n";
$this->js_root = $config['js_root'];
$this->js_group = $groups[$group];
$this->js_groups_file = $config['js_groups_file'];
$this->cache_file = "{$this->js_root}cache/{$group}";
$this->last_modified = $this->get_last_modified();
$this->cache_modified = (is_file($this->cache_file))
? filemtime($this->cache_file)
: 0;
// Output some JS!
$this->send();
} }
return $js; protected function send()
}
// --------------------------------------------------------------------------
/**
* Google Min
*
* Minifies javascript using google's closure compiler
* @param string $new_file
* @return string
*/
function google_min($new_file)
{
$options = [
'output_info' => 'errors',
'output_format' => 'json',
'compilation_level' => 'SIMPLE_OPTIMIZATIONS',
'js_code' => $new_file,
'language' => 'ECMASCRIPT5',
'language_out' => 'ECMASCRIPT5_STRICT'
];
// First check for errors
$error_client = new Client();
$error_res = $error_client->post('http://closure-compiler.appspot.com/compile', [
'headers' => [
'Accept-Encoding' => 'gzip',
"Content-type" => "application/x-www-form-urlencoded"
],
'form_params' => $options
]);
$error_json = $error_res->getBody();
$error_obj = json_decode($error_json);
if ( ! empty($error_obj->errors))
{ {
?><pre><?= json_encode($err_obj, JSON_PRETTY_PRINT) ?></pre><?php // Override caching if debug key is set
die(); if($this->is_debug_call())
{
return $this->output($this->get_files());
}
// If the browser's cached version is up to date,
// don't resend the file
if($this->last_modified == $this->get_if_modified() && $this->is_not_debug())
{
throw new FileNotChangedException();
}
if($this->cache_modified < $this->last_modified)
{
$js = $this->minify($this->get_files());
//Make sure cache file gets created/updated
if (file_put_contents($this->cache_file, $js) === FALSE)
{
echo 'Cache file was not created. Make sure you have the correct folder permissions.';
return;
}
return $this->output($js);
}
else
{
return $this->output(file_get_contents($this->cache_file));
}
} }
// Now actually retrieve the compiled code /**
$options['output_info'] = 'compiled_code'; * Makes a call to google closure compiler service
$client = new Client(); *
$res = $client->post('http://closure-compiler.appspot.com/compile', [ * @param array $options - Form parameters
'headers' => [ * @return object
'Accept-Encoding' => 'gzip', */
"Content-type" => "application/x-www-form-urlencoded" protected function closure_call(array $options)
],
'form_params' => $options
]);
$json = $res->getBody();
$obj = json_decode($json);
return $obj->compiledCode;
}
// --------------------------------------------------------------------------
//Creative rewriting of /g/groupname to ?g=groupname
$pi = $_SERVER['PATH_INFO'];
$pia = explode('/', $pi);
$pia_len = count($pia);
$i = 1;
while($i < $pia_len)
{
$j = $i+1;
$j = (isset($pia[$j])) ? $j : $i;
$_GET[$pia[$i]] = $pia[$j];
$i = $j + 1;
};
// --------------------------------------------------------------------------
$js = '';
$modified = array();
// --------------------------------------------------------------------------
//Aggregate the last modified times of the files
if(isset($groups[$_GET['g']]))
{
if ( ! is_dir($js_root . 'cache'))
{ {
mkdir($js_root . 'cache'); $client = new Client();
} $response = $client->post('http://closure-compiler.appspot.com/compile', [
$cache_file = $js_root.'cache/'.$_GET['g']; 'headers' => [
'Accept-Encoding' => 'gzip',
'Content-type' => 'application/x-www-form-urlencoded'
],
'form_params' => $options
]);
foreach($groups[$_GET['g']] as $file) return $response;
{
$new_file = realpath($js_root.$file);
$modified[] = filemtime($new_file);
} }
//Add this page too, as well as the groups file /**
$modified[] = filemtime($this_file); * Do a call to the closure compiler to check for compilation errors
$modified[] = filemtime($groups_file); *
* @param array $options
$cache_modified = 0; * @return void
*/
//Add the cache file protected function check_minify_errors($options)
if(is_file($cache_file))
{ {
$cache_modified = filemtime($cache_file); $error_res = $this->closure_call($options);
$error_json = $error_res->getBody();
$error_obj = json_decode($error_json) ?: (object)[];
// Show error if exists
if ( ! empty($error_obj->errors) || ! empty($error_obj->serverErrors))
{
$error_json = json_encode($error_obj, JSON_PRETTY_PRINT);
header('Content-type: application/javascript');
echo "console.error(${error_json});";
die();
}
}
/**
* Get Files
*
* Concatenates the javascript files for the current
* group as a string
*
* @return string
*/
protected function get_files()
{
$js = '';
foreach($this->js_group as $file)
{
$new_file = realpath("{$this->js_root}{$file}");
$js .= file_get_contents($new_file) . "\n\n";
}
return $js;
}
/**
* Get the most recent modified date
*
* @return int
*/
protected function get_last_modified()
{
$modified = array();
foreach($this->js_group as $file)
{
$new_file = realpath("{$this->js_root}{$file}");
$modified[] = filemtime($new_file);
}
//Add this page too, as well as the groups file
$modified[] = filemtime(__FILE__);
$modified[] = filemtime($this->js_groups_file);
rsort($modified);
$last_modified = $modified[0];
return $last_modified;
}
/**
* Minifies javascript using google's closure compiler
*
* @param string $js
* @return string
*/
protected function minify($js)
{
$options = [
'output_info' => 'errors',
'output_format' => 'json',
'compilation_level' => 'SIMPLE_OPTIMIZATIONS',
//'compilation_level' => 'ADVANCED_OPTIMIZATIONS',
'js_code' => $js,
'language' => 'ECMASCRIPT6_STRICT',
'language_out' => 'ECMASCRIPT5_STRICT'
];
// Check for errors
$this->check_minify_errors($options);
// Now actually retrieve the compiled code
$options['output_info'] = 'compiled_code';
$res = $this->closure_call($options);
$json = $res->getBody();
$obj = json_decode($json);
return $obj->compiledCode;
}
/**
* Output the minified javascript
*
* @param string $js
* @return void
*/
protected function output($js)
{
$this->send_final_output($js, 'application/javascript', $this->last_modified);
} }
} }
else //Nothing to display? Just exit
{
die("You must specify a group that exists");
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// ! Start Minifying
//Get the latest modified date
rsort($modified);
$last_modified = $modified[0];
$requested_time=(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']))
? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])
: time();
// If the browser's cached version is up to date,
// don't resend the file
if($last_modified === $requested_time)
{
header("HTTP/1.1 304 Not Modified");
exit();
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//Determine what to do: rebuild cache, send files as is, or send cache. $config = require_once('../app/config/minify_config.php');
// If debug is set, just concatenate $groups = require_once($config['js_groups_file']);
if(isset($_GET['debug'])) $cache_dir = "{$config['js_root']}cache";
{
$js = get_files();
}
else if($cache_modified < $last_modified)
{
$js = google_min(get_files());
//Make sure cache file gets created/updated if ( ! is_dir($cache_dir))
if(file_put_contents($cache_file, $js) === FALSE)
{
die("Cache file was not created. Make sure you have the correct folder permissions.");
}
}
// Otherwise, send the cached file
else
{ {
$js = file_get_contents($cache_file); mkdir($cache_dir);
} }
// -------------------------------------------------------------------------- if ( ! array_key_exists($_GET['g'], $groups))
{
throw new InvalidArgumentException('You must specify a js group that exists');
}
//This GZIPs the js for transmission to the user try
//making file size smaller and transfer rate quicker {
ob_start("ob_gzhandler"); new JSMin($config, $groups);
}
catch (FileNotChangedException $e)
{
BaseMin::send304();
}
// Set important caching headers
header("Content-Type: application/javascript; charset=utf8");
header("Cache-control: public, max-age=691200, must-revalidate");
header("Last-Modified: ".gmdate('D, d M Y H:i:s', $last_modified)." GMT");
header("Expires: ".gmdate('D, d M Y H:i:s', (filemtime($this_file) + 691200))." GMT");
echo $js;
ob_end_flush();
//end of js.php //end of js.php

View File

@ -1,17 +1,32 @@
(function($, undefined) { ((_) => {
function search(query, callback) 'use strict';
{
$.get(BASE_URL + 'collection/search', {'query':query}, callback);
}
$("#search").on('keypress', $.throttle(750, function(e) { const search = (tempHtml, query) => {
var query = encodeURIComponent($(this).val()); _.$('.cssload-loader')[0].removeAttribute('hidden');
search(query, function(res) { _.get(_.url('/collection/search'), {'query':query}, (searchResults, status) => {
var template = $.templates("#show_list"); searchResults = JSON.parse(searchResults);
var html = template.render(res); _.$('.cssload-loader')[0].setAttribute('hidden', 'hidden');
$('#series_list').html(html);
// Give mustache a key to iterate over
searchResults = {
anime: searchResults
};
Mustache.parse(tempHtml);
_.$('#series_list')[0].innerHTML = Mustache.render(tempHtml, searchResults);
}); });
})); };
}(jQuery)); _.get('/public/templates/anime-ajax-search-results.html', tempHtml => {
_.on('#search', 'keyup', _.throttle(250, function(e) {
let query = encodeURIComponent(this.value);
if (query === '') {
return;
}
search(tempHtml, query);
}));
});
})(AnimeClient);

View File

@ -1,62 +1,58 @@
/** /**
* Javascript for editing anime, if logged in * Javascript for editing anime, if logged in
*/ */
(function($){ ((_) => {
"use strict"; 'use strict';
if (CONTROLLER !== "anime") return;
// Action to increment episode count // Action to increment episode count
$(".plus_one").on("click", function(e) { _.on('body.anime.list', 'click', '.plus_one', function(e) {
e.stopPropagation(); let this_sel = this;
let parent_sel = _.closestParent(this, 'article');
var self = this; let watched_count = parseInt(_.$('.completed_number', parent_sel)[0].textContent, 10);
var this_sel = $(this); let total_count = parseInt(_.$('.total_number', parent_sel)[0].textContent, 10);
var parent_sel = $(this).closest("article, td"); let title = _.$('.name a', parent_sel)[0].textContent;
var watched_count = parseInt(parent_sel.find('.completed_number').text(), 10);
var total_count = parseInt(parent_sel.find('.total_number').text(), 10);
var title = parent_sel.find('.name a').text();
// Setup the update data // Setup the update data
var data = { let data = {
id: this_sel.parent('article, td').attr('id'), id: parent_sel.id,
increment_episodes: true increment_episodes: true
}; };
// If the episode count is 0, and incremented, // If the episode count is 0, and incremented,
// change status to currently watching // change status to currently watching
if (isNaN(watched_count) || watched_count === 0) if (isNaN(watched_count) || watched_count === 0) {
{ data.status = 'currently-watching';
data.status = "currently-watching";
} }
// If you increment at the last episode, mark as completed // If you increment at the last episode, mark as completed
if (( ! isNaN(watched_count)) && (watched_count + 1) === total_count) if (( ! isNaN(watched_count)) && (watched_count + 1) === total_count) {
{
delete data.increment_episodes; delete data.increment_episodes;
data.status = "completed"; data.status = 'completed';
} }
// okay, lets actually make some changes! // okay, lets actually make some changes!
$.ajax({ _.ajax(_.url('/anime/update'), {
data: data, data: data,
dataType: 'json', dataType: 'json',
method: 'POST', type: 'POST',
mimeType: 'application/json', mimeType: 'application/json',
url: BASE_URL + CONTROLLER + '/update' success: (res) => {
}).done(function(res) { if (res.status === 'completed') {
if (res.status === 'completed') this.parentElement.addAttribute('hidden', 'hidden');
{ }
$(self).closest('article, tr').hide();
}
add_message('success', "Sucessfully updated " + title); _.showMessage('success', `Sucessfully updated ${title}`);
parent_sel.find('.completed_number').text(++watched_count); _.$('.completed_number', parent_sel)[0].textContent = ++watched_count;
}).fail(function() { _.scrollToTop();
add_message('error', "Failed to updated " + title); },
error: (xhr, errorType, error) => {
console.error(error);
_.showMessage('error', `Failed to updated ${title}. `);
_.scrollToTop();
}
}); });
}); });
}(jQuery)); })(AnimeClient);

View File

@ -0,0 +1,274 @@
var AnimeClient = (function(w) {
'use strict';
const slice = Array.prototype.slice;
// -------------------------------------------------------------------------
// ! Base
// -------------------------------------------------------------------------
function matches(elm, selector) {
let matches = (elm.document || elm.ownerDocument).querySelectorAll(selector),
i = matches.length;
while (--i >= 0 && matches.item(i) !== elm);
return i > -1;
}
const _ = {
/**
* Placeholder function
*/
noop: () => {},
/**
* DOM selector
*
* @param {string} selector - The dom selector string
* @param {object} context
* @return {array} - array of dom elements
*/
$(selector, context) {
if (typeof selector != "string" || selector === undefined) {
return selector;
}
context = (context != null && context.nodeType === 1)
? context
: document;
let elements = [];
if (selector.match(/^#([\w]+$)/)) {
elements.push(document.getElementById(selector.split('#')[1]));
} else {
elements = slice.apply(context.querySelectorAll(selector));
}
return elements;
},
/**
* Scroll to the top of the Page
*
* @return {void}
*/
scrollToTop() {
w.scroll(0,0);
},
/**
* Display a message box
*
* @param {String} type - message type: info, error, success
* @param {String} message - the message itself
* @return {void}
*/
showMessage(type, message) {
let template =
`<div class="message ${type}">
<span class="icon"></span>
${message}
<span class="close"></span>
</div>`;
let sel = AnimeClient.$('.message')[0];
if (sel !== undefined) {
sel.innerHTML = template;
sel.removeAttribute('hidden');
} else {
_.$('header')[0].insertAdjacentHTML('beforeend', template);
}
},
/**
* Finds the closest parent element matching the passed selector
*
* @param {DOMElement} current - the current DOMElement
* @param {string} parentSelector - selector for the parent element
* @return {DOMElement|null} - the parent element
*/
closestParent(current, parentSelector) {
if (Element.prototype.closest !== undefined) {
return current.closest(parentSelector);
}
while (current !== document.documentElement) {
if (matches(current, parentSelector)) {
return current;
}
current = current.parentElement;
}
return null;
},
/**
* Generate a full url from a relative path
*
* @param {String} path - url path
* @return {String} - full url
*/
url(path) {
let uri = `//${document.location.host}`;
uri += (path.charAt(0) === '/') ? path : `/${path}`;
return uri;
},
/**
* Throttle execution of a function
*
* @see https://remysharp.com/2010/07/21/throttling-function-calls
* @see https://jsfiddle.net/jonathansampson/m7G64/
* @param {Number} interval - the minimum throttle time in ms
* @param {Function} fn - the function to throttle
* @param {Object} scope - the 'this' object for the function
* @return {void}
*/
throttle(interval, fn, scope) {
var wait = false;
return function () {
var context = scope || this;
var args = arguments;
if ( ! wait) {
fn.apply(context, args);
wait = true;
setTimeout(function() {
wait = false;
}, interval);
}
};
},
};
// -------------------------------------------------------------------------
// ! Events
// -------------------------------------------------------------------------
function addEvent(sel, event, listener) {
// Recurse!
if (! event.match(/^([\w\-]+)$/)) {
event.split(' ').forEach((evt) => {
addEvent(sel, evt, listener);
});
}
sel.addEventListener(event, listener, false);
}
function delegateEvent(sel, target, event, listener) {
// Attach the listener to the parent
addEvent(sel, event, (e) => {
// Get live version of the target selector
_.$(target, sel).forEach((element) => {
if(e.target == element) {
listener.call(element, e);
e.stopPropagation();
}
});
});
}
_.on = function (sel, event, target, listener) {
if (arguments.length === 3) {
listener = target;
_.$(sel).forEach((el) => {
addEvent(el, event, listener);
});
} else {
_.$(sel).forEach((el) => {
delegateEvent(el, target, event, listener);
});
}
}
// -------------------------------------------------------------------------
// ! Ajax
// -------------------------------------------------------------------------
/**
* Url encoding for non-get requests
*
* @param data
* @returns {string}
* @private
*/
function ajaxSerialize(data) {
let pairs = [];
Object.keys(data).forEach((name) => {
let value = data[name].toString();
name = encodeURIComponent(name);
value = encodeURIComponent(value);
pairs.push(`${name}=${value}`);
});
return pairs.join("&");
};
_.ajax = function(url, config) {
// Set some sane defaults
config = config || {};
config.data = config.data || {};
config.type = config.type || 'GET';
config.dataType = config.dataType || '';
config.success = config.success || _.noop;
config.error = config.error || _.noop;
let request = new XMLHttpRequest();
let method = String(config.type).toUpperCase();
if (method === "GET") {
url += (url.match(/\?/))
? ajaxSerialize(config.data)
: `?${ajaxSerialize(config.data)}`;
}
request.open(method, url);
request.onreadystatechange = () => {
if (request.readyState === 4) {
let responseText = '';
if (request.responseType == 'json') {
responseText = JSON.parse(request.responseText);
} else {
responseText = request.responseText;
}
if (request.status > 400) {
config.error.call(null, request.status, responseText, request.response);
} else {
config.success.call(null, responseText, request.status);
}
}
};
switch (method) {
case "GET":
request.send(null);
break;
default:
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
request.send(ajaxSerialize(config.data));
break;
}
};
_.get = function(url, data, callback) {
if (arguments.length === 2) {
callback = data;
data = {};
}
return _.ajax(url, {
data: data,
success: callback
});
};
// -------------------------------------------------------------------------
// Export
// -------------------------------------------------------------------------
return _;
})(window);

227
public/js/base/classList.js Normal file
View File

@ -0,0 +1,227 @@
/*
* classList.js: Cross-browser full element.classList implementation.
* 2014-07-23
*
* By Eli Grey, http://eligrey.com
* Public Domain.
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
*/
/*global self, document, DOMException */
/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/
if ("document" in self) {
// Full polyfill for browsers with no classList support
if (!("classList" in document.createElement("_"))) {
(function(view) {
"use strict";
if (!('Element' in view)) return;
var
classListProp = "classList",
protoProp = "prototype",
elemCtrProto = view.Element[protoProp],
objCtr = Object,
strTrim = String[protoProp].trim || function() {
return this.replace(/^\s+|\s+$/g, "");
},
arrIndexOf = Array[protoProp].indexOf || function(item) {
var
i = 0,
len = this.length;
for (; i < len; i++) {
if (i in this && this[i] === item) {
return i;
}
}
return -1;
}
// Vendors: please allow content code to instantiate DOMExceptions
,
DOMEx = function(type, message) {
this.name = type;
this.code = DOMException[type];
this.message = message;
},
checkTokenAndGetIndex = function(classList, token) {
if (token === "") {
throw new DOMEx(
"SYNTAX_ERR", "An invalid or illegal string was specified"
);
}
if (/\s/.test(token)) {
throw new DOMEx(
"INVALID_CHARACTER_ERR", "String contains an invalid character"
);
}
return arrIndexOf.call(classList, token);
},
ClassList = function(elem) {
var
trimmedClasses = strTrim.call(elem.getAttribute("class") || ""),
classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [],
i = 0,
len = classes.length;
for (; i < len; i++) {
this.push(classes[i]);
}
this._updateClassName = function() {
elem.setAttribute("class", this.toString());
};
},
classListProto = ClassList[protoProp] = [],
classListGetter = function() {
return new ClassList(this);
};
// Most DOMException implementations don't allow calling DOMException's toString()
// on non-DOMExceptions. Error's toString() is sufficient here.
DOMEx[protoProp] = Error[protoProp];
classListProto.item = function(i) {
return this[i] || null;
};
classListProto.contains = function(token) {
token += "";
return checkTokenAndGetIndex(this, token) !== -1;
};
classListProto.add = function() {
var
tokens = arguments,
i = 0,
l = tokens.length,
token, updated = false;
do {
token = tokens[i] + "";
if (checkTokenAndGetIndex(this, token) === -1) {
this.push(token);
updated = true;
}
}
while (++i < l);
if (updated) {
this._updateClassName();
}
};
classListProto.remove = function() {
var
tokens = arguments,
i = 0,
l = tokens.length,
token, updated = false,
index;
do {
token = tokens[i] + "";
index = checkTokenAndGetIndex(this, token);
while (index !== -1) {
this.splice(index, 1);
updated = true;
index = checkTokenAndGetIndex(this, token);
}
}
while (++i < l);
if (updated) {
this._updateClassName();
}
};
classListProto.toggle = function(token, force) {
token += "";
var
result = this.contains(token),
method = result ?
force !== true && "remove" :
force !== false && "add";
if (method) {
this[method](token);
}
if (force === true || force === false) {
return force;
} else {
return !result;
}
};
classListProto.toString = function() {
return this.join(" ");
};
if (objCtr.defineProperty) {
var classListPropDesc = {
get: classListGetter,
enumerable: true,
configurable: true
};
try {
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
} catch (ex) { // IE 8 doesn't support enumerable:true
if (ex.number === -0x7FF5EC54) {
classListPropDesc.enumerable = false;
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
}
}
} else if (objCtr[protoProp].__defineGetter__) {
elemCtrProto.__defineGetter__(classListProp, classListGetter);
}
}(self));
} else {
// There is full or partial native classList support, so just check if we need
// to normalize the add/remove and toggle APIs.
(function() {
"use strict";
var testElement = document.createElement("_");
testElement.classList.add("c1", "c2");
// Polyfill for IE 10/11 and Firefox <26, where classList.add and
// classList.remove exist but support only one argument at a time.
if (!testElement.classList.contains("c2")) {
var createMethod = function(method) {
var original = DOMTokenList.prototype[method];
DOMTokenList.prototype[method] = function(token) {
var i, len = arguments.length;
for (i = 0; i < len; i++) {
token = arguments[i];
original.call(this, token);
}
};
};
createMethod('add');
createMethod('remove');
}
testElement.classList.toggle("c3", false);
// Polyfill for IE 10 and Firefox <24, where classList.toggle does not
// support the second argument.
if (testElement.classList.contains("c3")) {
var _toggle = DOMTokenList.prototype.toggle;
DOMTokenList.prototype.toggle = function(token, force) {
if (1 in arguments && !this.contains(token) === !force) {
return force;
} else {
return _toggle.call(this, token);
}
};
}
testElement = null;
}());
}
}

13
public/js/base/events.js Normal file
View File

@ -0,0 +1,13 @@
/**
* Event handlers
*/
((ac) => {
'use strict';
// Close event for messages
ac.on('header', 'click', '.message', function () {
this.setAttribute('hidden', 'hidden');
});
})(AnimeClient);

View File

@ -0,0 +1,75 @@
const LightTableSorter = (function() {
let _cellIndex, _onClickEvent, _order, _reset, _sort, _text, _th, _toggle;
_th = null;
_cellIndex = null;
_order = '';
_text = function(row) {
return row.cells.item(_cellIndex).textContent.toLowerCase();
};
_sort = function(a, b) {
let n, textA, textB;
textA = _text(a);
textB = _text(b);
n = parseInt(textA, 10);
if (n) {
textA = n;
textB = parseInt(textB, 10);
}
if (textA > textB) {
return 1;
}
if (textA < textB) {
return -1;
}
return 0;
};
_toggle = function() {
let c;
c = _order !== 'sorting_asc' ? 'sorting_asc' : 'sorting_desc';
_th.className = (_th.className.replace(_order, '') + ' ' + c).trim();
return _order = c;
};
_reset = function() {
_th.className = _th.className.replace('sorting_asc', 'sorting').replace('sorting_desc', 'sorting');
return _order = '';
};
_onClickEvent = function(e) {
let row, rows, tbody, _i, _len;
if (_th && (_cellIndex !== e.target.cellIndex)) {
_reset();
}
_th = e.target;
if (_th.nodeName.toLowerCase() === 'th') {
_cellIndex = _th.cellIndex;
tbody = _th.offsetParent.getElementsByTagName('tbody')[0];
rows = tbody.rows;
if (rows) {
rows = Array.prototype.slice.call(rows, 0);
rows = Array.prototype.sort.call(rows, _sort);
if (_order === 'sorting_asc') {
Array.prototype.reverse.call(rows);
}
_toggle();
tbody.innerHtml = '';
for (_i = 0, _len = rows.length; _i < _len; _i++) {
row = rows[_i];
tbody.appendChild(row);
}
}
}
};
return {
init: function() {
let ths = document.getElementsByTagName('th');
let _results = [];
for (let _i = 0, _len = ths.length; _i < _len; _i++) {
let th = ths[_i];
th.className = 'sorting';
_results.push(th.onclick = _onClickEvent);
}
return _results;
}
};
})();
LightTableSorter.init();

File diff suppressed because one or more lines are too long

View File

@ -1,252 +0,0 @@
/*!
* jQuery throttle / debounce - v1.1 - 3/7/2010
* http://benalman.com/projects/jquery-throttle-debounce-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/
// Script: jQuery throttle / debounce: Sometimes, less is more!
//
// *Version: 1.1, Last updated: 3/7/2010*
//
// Project Home - http://benalman.com/projects/jquery-throttle-debounce-plugin/
// GitHub - http://github.com/cowboy/jquery-throttle-debounce/
// Source - http://github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.js
// (Minified) - http://github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.min.js (0.7kb)
//
// About: License
//
// Copyright (c) 2010 "Cowboy" Ben Alman,
// Dual licensed under the MIT and GPL licenses.
// http://benalman.com/about/license/
//
// About: Examples
//
// These working examples, complete with fully commented code, illustrate a few
// ways in which this plugin can be used.
//
// Throttle - http://benalman.com/code/projects/jquery-throttle-debounce/examples/throttle/
// Debounce - http://benalman.com/code/projects/jquery-throttle-debounce/examples/debounce/
//
// About: Support and Testing
//
// Information about what version or versions of jQuery this plugin has been
// tested with, what browsers it has been tested in, and where the unit tests
// reside (so you can test it yourself).
//
// jQuery Versions - none, 1.3.2, 1.4.2
// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.6, Safari 3-4, Chrome 4-5, Opera 9.6-10.1.
// Unit Tests - http://benalman.com/code/projects/jquery-throttle-debounce/unit/
//
// About: Release History
//
// 1.1 - (3/7/2010) Fixed a bug in <jQuery.throttle> where trailing callbacks
// executed later than they should. Reworked a fair amount of internal
// logic as well.
// 1.0 - (3/6/2010) Initial release as a stand-alone project. Migrated over
// from jquery-misc repo v0.4 to jquery-throttle repo v1.0, added the
// no_trailing throttle parameter and debounce functionality.
//
// Topic: Note for non-jQuery users
//
// jQuery isn't actually required for this plugin, because nothing internal
// uses any jQuery methods or properties. jQuery is just used as a namespace
// under which these methods can exist.
//
// Since jQuery isn't actually required for this plugin, if jQuery doesn't exist
// when this plugin is loaded, the method described below will be created in
// the `Cowboy` namespace. Usage will be exactly the same, but instead of
// $.method() or jQuery.method(), you'll need to use Cowboy.method().
(function(window,undefined){
'$:nomunge'; // Used by YUI compressor.
// Since jQuery really isn't required for this plugin, use `jQuery` as the
// namespace only if it already exists, otherwise use the `Cowboy` namespace,
// creating it if necessary.
var $ = window.jQuery || window.Cowboy || ( window.Cowboy = {} ),
// Internal method reference.
jq_throttle;
// Method: jQuery.throttle
//
// Throttle execution of a function. Especially useful for rate limiting
// execution of handlers on events like resize and scroll. If you want to
// rate-limit execution of a function to a single time, see the
// <jQuery.debounce> method.
//
// In this visualization, | is a throttled-function call and X is the actual
// callback execution:
//
// > Throttled with `no_trailing` specified as false or unspecified:
// > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
// > X X X X X X X X X X X X
// >
// > Throttled with `no_trailing` specified as true:
// > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
// > X X X X X X X X X X
//
// Usage:
//
// > var throttled = jQuery.throttle( delay, [ no_trailing, ] callback );
// >
// > jQuery('selector').bind( 'someevent', throttled );
// > jQuery('selector').unbind( 'someevent', throttled );
//
// This also works in jQuery 1.4+:
//
// > jQuery('selector').bind( 'someevent', jQuery.throttle( delay, [ no_trailing, ] callback ) );
// > jQuery('selector').unbind( 'someevent', callback );
//
// Arguments:
//
// delay - (Number) A zero-or-greater delay in milliseconds. For event
// callbacks, values around 100 or 250 (or even higher) are most useful.
// no_trailing - (Boolean) Optional, defaults to false. If no_trailing is
// true, callback will only execute every `delay` milliseconds while the
// throttled-function is being called. If no_trailing is false or
// unspecified, callback will be executed one final time after the last
// throttled-function call. (After the throttled-function has not been
// called for `delay` milliseconds, the internal counter is reset)
// callback - (Function) A function to be executed after delay milliseconds.
// The `this` context and all arguments are passed through, as-is, to
// `callback` when the throttled-function is executed.
//
// Returns:
//
// (Function) A new, throttled, function.
$.throttle = jq_throttle = function( delay, no_trailing, callback, debounce_mode ) {
// After wrapper has stopped being called, this timeout ensures that
// `callback` is executed at the proper times in `throttle` and `end`
// debounce modes.
var timeout_id,
// Keep track of the last time `callback` was executed.
last_exec = 0;
// `no_trailing` defaults to falsy.
if ( typeof no_trailing !== 'boolean' ) {
debounce_mode = callback;
callback = no_trailing;
no_trailing = undefined;
}
// The `wrapper` function encapsulates all of the throttling / debouncing
// functionality and when executed will limit the rate at which `callback`
// is executed.
function wrapper() {
var that = this,
elapsed = +new Date() - last_exec,
args = arguments;
// Execute `callback` and update the `last_exec` timestamp.
function exec() {
last_exec = +new Date();
callback.apply( that, args );
};
// If `debounce_mode` is true (at_begin) this is used to clear the flag
// to allow future `callback` executions.
function clear() {
timeout_id = undefined;
};
if ( debounce_mode && !timeout_id ) {
// Since `wrapper` is being called for the first time and
// `debounce_mode` is true (at_begin), execute `callback`.
exec();
}
// Clear any existing timeout.
timeout_id && clearTimeout( timeout_id );
if ( debounce_mode === undefined && elapsed > delay ) {
// In throttle mode, if `delay` time has been exceeded, execute
// `callback`.
exec();
} else if ( no_trailing !== true ) {
// In trailing throttle mode, since `delay` time has not been
// exceeded, schedule `callback` to execute `delay` ms after most
// recent execution.
//
// If `debounce_mode` is true (at_begin), schedule `clear` to execute
// after `delay` ms.
//
// If `debounce_mode` is false (at end), schedule `callback` to
// execute after `delay` ms.
timeout_id = setTimeout( debounce_mode ? clear : exec, debounce_mode === undefined ? delay - elapsed : delay );
}
};
// Set the guid of `wrapper` function to the same of original callback, so
// it can be removed in jQuery 1.4+ .unbind or .die by using the original
// callback as a reference.
if ( $.guid ) {
wrapper.guid = callback.guid = callback.guid || $.guid++;
}
// Return the wrapper function.
return wrapper;
};
// Method: jQuery.debounce
//
// Debounce execution of a function. Debouncing, unlike throttling,
// guarantees that a function is only executed a single time, either at the
// very beginning of a series of calls, or at the very end. If you want to
// simply rate-limit execution of a function, see the <jQuery.throttle>
// method.
//
// In this visualization, | is a debounced-function call and X is the actual
// callback execution:
//
// > Debounced with `at_begin` specified as false or unspecified:
// > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
// > X X
// >
// > Debounced with `at_begin` specified as true:
// > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
// > X X
//
// Usage:
//
// > var debounced = jQuery.debounce( delay, [ at_begin, ] callback );
// >
// > jQuery('selector').bind( 'someevent', debounced );
// > jQuery('selector').unbind( 'someevent', debounced );
//
// This also works in jQuery 1.4+:
//
// > jQuery('selector').bind( 'someevent', jQuery.debounce( delay, [ at_begin, ] callback ) );
// > jQuery('selector').unbind( 'someevent', callback );
//
// Arguments:
//
// delay - (Number) A zero-or-greater delay in milliseconds. For event
// callbacks, values around 100 or 250 (or even higher) are most useful.
// at_begin - (Boolean) Optional, defaults to false. If at_begin is false or
// unspecified, callback will only be executed `delay` milliseconds after
// the last debounced-function call. If at_begin is true, callback will be
// executed only at the first debounced-function call. (After the
// throttled-function has not been called for `delay` milliseconds, the
// internal counter is reset)
// callback - (Function) A function to be executed after delay milliseconds.
// The `this` context and all arguments are passed through, as-is, to
// `callback` when the debounced-function is executed.
//
// Returns:
//
// (Function) A new, debounced, function.
$.debounce = function( delay, at_begin, callback ) {
return callback === undefined
? jq_throttle( delay, at_begin, false )
: jq_throttle( delay, callback, at_begin !== false );
};
})(this);

File diff suppressed because it is too large Load Diff

629
public/js/lib/mustache.js Normal file
View File

@ -0,0 +1,629 @@
/*!
* mustache.js - Logic-less {{mustache}} templates with JavaScript
* http://github.com/janl/mustache.js
*/
/*global define: false Mustache: true*/
(function defineMustache (global, factory) {
if (typeof exports === 'object' && exports && typeof exports.nodeName !== 'string') {
factory(exports); // CommonJS
} else if (typeof define === 'function' && define.amd) {
define(['exports'], factory); // AMD
} else {
global.Mustache = {};
factory(global.Mustache); // script, wsh, asp
}
}(this, function mustacheFactory (mustache) {
var objectToString = Object.prototype.toString;
var isArray = Array.isArray || function isArrayPolyfill (object) {
return objectToString.call(object) === '[object Array]';
};
function isFunction (object) {
return typeof object === 'function';
}
/**
* More correct typeof string handling array
* which normally returns typeof 'object'
*/
function typeStr (obj) {
return isArray(obj) ? 'array' : typeof obj;
}
function escapeRegExp (string) {
return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
}
/**
* Null safe way of checking whether or not an object,
* including its prototype, has a given property
*/
function hasProperty (obj, propName) {
return obj != null && typeof obj === 'object' && (propName in obj);
}
// Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
// See https://github.com/janl/mustache.js/issues/189
var regExpTest = RegExp.prototype.test;
function testRegExp (re, string) {
return regExpTest.call(re, string);
}
var nonSpaceRe = /\S/;
function isWhitespace (string) {
return !testRegExp(nonSpaceRe, string);
}
var entityMap = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
'/': '&#x2F;',
'`': '&#x60;',
'=': '&#x3D;'
};
function escapeHtml (string) {
return String(string).replace(/[&<>"'`=\/]/g, function fromEntityMap (s) {
return entityMap[s];
});
}
var whiteRe = /\s*/;
var spaceRe = /\s+/;
var equalsRe = /\s*=/;
var curlyRe = /\s*\}/;
var tagRe = /#|\^|\/|>|\{|&|=|!/;
/**
* Breaks up the given `template` string into a tree of tokens. If the `tags`
* argument is given here it must be an array with two string values: the
* opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of
* course, the default is to use mustaches (i.e. mustache.tags).
*
* A token is an array with at least 4 elements. The first element is the
* mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag
* did not contain a symbol (i.e. {{myValue}}) this element is "name". For
* all text that appears outside a symbol this element is "text".
*
* The second element of a token is its "value". For mustache tags this is
* whatever else was inside the tag besides the opening symbol. For text tokens
* this is the text itself.
*
* The third and fourth elements of the token are the start and end indices,
* respectively, of the token in the original template.
*
* Tokens that are the root node of a subtree contain two more elements: 1) an
* array of tokens in the subtree and 2) the index in the original template at
* which the closing tag for that section begins.
*/
function parseTemplate (template, tags) {
if (!template)
return [];
var sections = []; // Stack to hold section tokens
var tokens = []; // Buffer to hold the tokens
var spaces = []; // Indices of whitespace tokens on the current line
var hasTag = false; // Is there a {{tag}} on the current line?
var nonSpace = false; // Is there a non-space char on the current line?
// Strips all whitespace tokens array for the current line
// if there was a {{#tag}} on it and otherwise only space.
function stripSpace () {
if (hasTag && !nonSpace) {
while (spaces.length)
delete tokens[spaces.pop()];
} else {
spaces = [];
}
hasTag = false;
nonSpace = false;
}
var openingTagRe, closingTagRe, closingCurlyRe;
function compileTags (tagsToCompile) {
if (typeof tagsToCompile === 'string')
tagsToCompile = tagsToCompile.split(spaceRe, 2);
if (!isArray(tagsToCompile) || tagsToCompile.length !== 2)
throw new Error('Invalid tags: ' + tagsToCompile);
openingTagRe = new RegExp(escapeRegExp(tagsToCompile[0]) + '\\s*');
closingTagRe = new RegExp('\\s*' + escapeRegExp(tagsToCompile[1]));
closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tagsToCompile[1]));
}
compileTags(tags || mustache.tags);
var scanner = new Scanner(template);
var start, type, value, chr, token, openSection;
while (!scanner.eos()) {
start = scanner.pos;
// Match any text between tags.
value = scanner.scanUntil(openingTagRe);
if (value) {
for (var i = 0, valueLength = value.length; i < valueLength; ++i) {
chr = value.charAt(i);
if (isWhitespace(chr)) {
spaces.push(tokens.length);
} else {
nonSpace = true;
}
tokens.push([ 'text', chr, start, start + 1 ]);
start += 1;
// Check for whitespace on the current line.
if (chr === '\n')
stripSpace();
}
}
// Match the opening tag.
if (!scanner.scan(openingTagRe))
break;
hasTag = true;
// Get the tag type.
type = scanner.scan(tagRe) || 'name';
scanner.scan(whiteRe);
// Get the tag value.
if (type === '=') {
value = scanner.scanUntil(equalsRe);
scanner.scan(equalsRe);
scanner.scanUntil(closingTagRe);
} else if (type === '{') {
value = scanner.scanUntil(closingCurlyRe);
scanner.scan(curlyRe);
scanner.scanUntil(closingTagRe);
type = '&';
} else {
value = scanner.scanUntil(closingTagRe);
}
// Match the closing tag.
if (!scanner.scan(closingTagRe))
throw new Error('Unclosed tag at ' + scanner.pos);
token = [ type, value, start, scanner.pos ];
tokens.push(token);
if (type === '#' || type === '^') {
sections.push(token);
} else if (type === '/') {
// Check section nesting.
openSection = sections.pop();
if (!openSection)
throw new Error('Unopened section "' + value + '" at ' + start);
if (openSection[1] !== value)
throw new Error('Unclosed section "' + openSection[1] + '" at ' + start);
} else if (type === 'name' || type === '{' || type === '&') {
nonSpace = true;
} else if (type === '=') {
// Set the tags for the next time around.
compileTags(value);
}
}
// Make sure there are no open sections when we're done.
openSection = sections.pop();
if (openSection)
throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
return nestTokens(squashTokens(tokens));
}
/**
* Combines the values of consecutive text tokens in the given `tokens` array
* to a single token.
*/
function squashTokens (tokens) {
var squashedTokens = [];
var token, lastToken;
for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
token = tokens[i];
if (token) {
if (token[0] === 'text' && lastToken && lastToken[0] === 'text') {
lastToken[1] += token[1];
lastToken[3] = token[3];
} else {
squashedTokens.push(token);
lastToken = token;
}
}
}
return squashedTokens;
}
/**
* Forms the given array of `tokens` into a nested tree structure where
* tokens that represent a section have two additional items: 1) an array of
* all tokens that appear in that section and 2) the index in the original
* template that represents the end of that section.
*/
function nestTokens (tokens) {
var nestedTokens = [];
var collector = nestedTokens;
var sections = [];
var token, section;
for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
token = tokens[i];
switch (token[0]) {
case '#':
case '^':
collector.push(token);
sections.push(token);
collector = token[4] = [];
break;
case '/':
section = sections.pop();
section[5] = token[2];
collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;
break;
default:
collector.push(token);
}
}
return nestedTokens;
}
/**
* A simple string scanner that is used by the template parser to find
* tokens in template strings.
*/
function Scanner (string) {
this.string = string;
this.tail = string;
this.pos = 0;
}
/**
* Returns `true` if the tail is empty (end of string).
*/
Scanner.prototype.eos = function eos () {
return this.tail === '';
};
/**
* Tries to match the given regular expression at the current position.
* Returns the matched text if it can match, the empty string otherwise.
*/
Scanner.prototype.scan = function scan (re) {
var match = this.tail.match(re);
if (!match || match.index !== 0)
return '';
var string = match[0];
this.tail = this.tail.substring(string.length);
this.pos += string.length;
return string;
};
/**
* Skips all text until the given regular expression can be matched. Returns
* the skipped string, which is the entire tail if no match can be made.
*/
Scanner.prototype.scanUntil = function scanUntil (re) {
var index = this.tail.search(re), match;
switch (index) {
case -1:
match = this.tail;
this.tail = '';
break;
case 0:
match = '';
break;
default:
match = this.tail.substring(0, index);
this.tail = this.tail.substring(index);
}
this.pos += match.length;
return match;
};
/**
* Represents a rendering context by wrapping a view object and
* maintaining a reference to the parent context.
*/
function Context (view, parentContext) {
this.view = view;
this.cache = { '.': this.view };
this.parent = parentContext;
}
/**
* Creates a new context using the given view with this context
* as the parent.
*/
Context.prototype.push = function push (view) {
return new Context(view, this);
};
/**
* Returns the value of the given name in this context, traversing
* up the context hierarchy if the value is absent in this context's view.
*/
Context.prototype.lookup = function lookup (name) {
var cache = this.cache;
var value;
if (cache.hasOwnProperty(name)) {
value = cache[name];
} else {
var context = this, names, index, lookupHit = false;
while (context) {
if (name.indexOf('.') > 0) {
value = context.view;
names = name.split('.');
index = 0;
/**
* Using the dot notion path in `name`, we descend through the
* nested objects.
*
* To be certain that the lookup has been successful, we have to
* check if the last object in the path actually has the property
* we are looking for. We store the result in `lookupHit`.
*
* This is specially necessary for when the value has been set to
* `undefined` and we want to avoid looking up parent contexts.
**/
while (value != null && index < names.length) {
if (index === names.length - 1)
lookupHit = hasProperty(value, names[index]);
value = value[names[index++]];
}
} else {
value = context.view[name];
lookupHit = hasProperty(context.view, name);
}
if (lookupHit)
break;
context = context.parent;
}
cache[name] = value;
}
if (isFunction(value))
value = value.call(this.view);
return value;
};
/**
* A Writer knows how to take a stream of tokens and render them to a
* string, given a context. It also maintains a cache of templates to
* avoid the need to parse the same template twice.
*/
function Writer () {
this.cache = {};
}
/**
* Clears all cached templates in this writer.
*/
Writer.prototype.clearCache = function clearCache () {
this.cache = {};
};
/**
* Parses and caches the given `template` and returns the array of tokens
* that is generated from the parse.
*/
Writer.prototype.parse = function parse (template, tags) {
var cache = this.cache;
var tokens = cache[template];
if (tokens == null)
tokens = cache[template] = parseTemplate(template, tags);
return tokens;
};
/**
* High-level method that is used to render the given `template` with
* the given `view`.
*
* The optional `partials` argument may be an object that contains the
* names and templates of partials that are used in the template. It may
* also be a function that is used to load partial templates on the fly
* that takes a single argument: the name of the partial.
*/
Writer.prototype.render = function render (template, view, partials) {
var tokens = this.parse(template);
var context = (view instanceof Context) ? view : new Context(view);
return this.renderTokens(tokens, context, partials, template);
};
/**
* Low-level method that renders the given array of `tokens` using
* the given `context` and `partials`.
*
* Note: The `originalTemplate` is only ever used to extract the portion
* of the original template that was contained in a higher-order section.
* If the template doesn't use higher-order sections, this argument may
* be omitted.
*/
Writer.prototype.renderTokens = function renderTokens (tokens, context, partials, originalTemplate) {
var buffer = '';
var token, symbol, value;
for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
value = undefined;
token = tokens[i];
symbol = token[0];
if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate);
else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate);
else if (symbol === '>') value = this.renderPartial(token, context, partials, originalTemplate);
else if (symbol === '&') value = this.unescapedValue(token, context);
else if (symbol === 'name') value = this.escapedValue(token, context);
else if (symbol === 'text') value = this.rawValue(token);
if (value !== undefined)
buffer += value;
}
return buffer;
};
Writer.prototype.renderSection = function renderSection (token, context, partials, originalTemplate) {
var self = this;
var buffer = '';
var value = context.lookup(token[1]);
// This function is used to render an arbitrary template
// in the current context by higher-order sections.
function subRender (template) {
return self.render(template, context, partials);
}
if (!value) return;
if (isArray(value)) {
for (var j = 0, valueLength = value.length; j < valueLength; ++j) {
buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate);
}
} else if (typeof value === 'object' || typeof value === 'string' || typeof value === 'number') {
buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate);
} else if (isFunction(value)) {
if (typeof originalTemplate !== 'string')
throw new Error('Cannot use higher-order sections without the original template');
// Extract the portion of the original template that the section contains.
value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender);
if (value != null)
buffer += value;
} else {
buffer += this.renderTokens(token[4], context, partials, originalTemplate);
}
return buffer;
};
Writer.prototype.renderInverted = function renderInverted (token, context, partials, originalTemplate) {
var value = context.lookup(token[1]);
// Use JavaScript's definition of falsy. Include empty arrays.
// See https://github.com/janl/mustache.js/issues/186
if (!value || (isArray(value) && value.length === 0))
return this.renderTokens(token[4], context, partials, originalTemplate);
};
Writer.prototype.renderPartial = function renderPartial (token, context, partials) {
if (!partials) return;
var value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
if (value != null)
return this.renderTokens(this.parse(value), context, partials, value);
};
Writer.prototype.unescapedValue = function unescapedValue (token, context) {
var value = context.lookup(token[1]);
if (value != null)
return value;
};
Writer.prototype.escapedValue = function escapedValue (token, context) {
var value = context.lookup(token[1]);
if (value != null)
return mustache.escape(value);
};
Writer.prototype.rawValue = function rawValue (token) {
return token[1];
};
mustache.name = 'mustache.js';
mustache.version = '2.2.1';
mustache.tags = [ '{{', '}}' ];
// All high-level mustache.* functions use this writer.
var defaultWriter = new Writer();
/**
* Clears all cached templates in the default writer.
*/
mustache.clearCache = function clearCache () {
return defaultWriter.clearCache();
};
/**
* Parses and caches the given template in the default writer and returns the
* array of tokens it contains. Doing this ahead of time avoids the need to
* parse templates on the fly as they are rendered.
*/
mustache.parse = function parse (template, tags) {
return defaultWriter.parse(template, tags);
};
/**
* Renders the `template` with the given `view` and `partials` using the
* default writer.
*/
mustache.render = function render (template, view, partials) {
if (typeof template !== 'string') {
throw new TypeError('Invalid template! Template should be a "string" ' +
'but "' + typeStr(template) + '" was given as the first ' +
'argument for mustache#render(template, view, partials)');
}
return defaultWriter.render(template, view, partials);
};
// This is here for backwards compatibility with 0.4.x.,
/*eslint-disable */ // eslint wants camel cased function name
mustache.to_html = function to_html (template, view, partials, send) {
/*eslint-enable*/
var result = mustache.render(template, view, partials);
if (isFunction(send)) {
send(result);
} else {
return result;
}
};
// Export the escaping function so that the user may override it.
// See https://github.com/janl/mustache.js/issues/244
mustache.escape = escapeHtml;
// Export these mainly for testing, but also for advanced usage.
mustache.Scanner = Scanner;
mustache.Context = Context;
mustache.Writer = Writer;
}));

View File

@ -1,122 +0,0 @@
/*
* Metadata - jQuery plugin for parsing metadata from elements
*
* Copyright (c) 2006 John Resig, Yehuda Katz, J<EFBFBD>örn Zaefferer, Paul McLanahan
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Revision: $Id$
*
*/
/**
* Sets the type of metadata to use. Metadata is encoded in JSON, and each property
* in the JSON will become a property of the element itself.
*
* There are three supported types of metadata storage:
*
* attr: Inside an attribute. The name parameter indicates *which* attribute.
*
* class: Inside the class attribute, wrapped in curly braces: { }
*
* elem: Inside a child element (e.g. a script tag). The
* name parameter indicates *which* element.
*
* The metadata for an element is loaded the first time the element is accessed via jQuery.
*
* As a result, you can define the metadata type, use $(expr) to load the metadata into the elements
* matched by expr, then redefine the metadata type and run another $(expr) for other elements.
*
* @name $.metadata.setType
*
* @example <p id="one" class="some_class {item_id: 1, item_label: 'Label'}">This is a p</p>
* @before $.metadata.setType("class")
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
* @desc Reads metadata from the class attribute
*
* @example <p id="one" class="some_class" data="{item_id: 1, item_label: 'Label'}">This is a p</p>
* @before $.metadata.setType("attr", "data")
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
* @desc Reads metadata from a "data" attribute
*
* @example <p id="one" class="some_class"><script>{item_id: 1, item_label: 'Label'}</script>This is a p</p>
* @before $.metadata.setType("elem", "script")
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
* @desc Reads metadata from a nested script element
*
* @param String type The encoding type
* @param String name The name of the attribute to be used to get metadata (optional)
* @cat Plugins/Metadata
* @descr Sets the type of encoding to be used when loading metadata for the first time
* @type undefined
* @see metadata()
*/
(function($) {
$.extend({
metadata : {
defaults : {
type: 'class',
name: 'metadata',
cre: /({.*})/,
single: 'metadata'
},
setType: function( type, name ){
this.defaults.type = type;
this.defaults.name = name;
},
get: function( elem, opts ){
var settings = $.extend({},this.defaults,opts);
// check for empty string in single property
if ( !settings.single.length ) settings.single = 'metadata';
var data = $.data(elem, settings.single);
// returned cached data if it already exists
if ( data ) return data;
data = "{}";
if ( settings.type == "class" ) {
var m = settings.cre.exec( elem.className );
if ( m )
data = m[1];
} else if ( settings.type == "elem" ) {
if( !elem.getElementsByTagName )
return undefined;
var e = elem.getElementsByTagName(settings.name);
if ( e.length )
data = $.trim(e[0].innerHTML);
} else if ( elem.getAttribute != undefined ) {
var attr = elem.getAttribute( settings.name );
if ( attr )
data = attr;
}
if ( data.indexOf( '{' ) <0 )
data = "{" + data + "}";
data = eval("(" + data + ")");
$.data( elem, settings.single, data );
return data;
}
}
});
/**
* Returns the metadata object for the first member of the jQuery object.
*
* @name metadata
* @descr Returns element's metadata object
* @param Object opts An object contianing settings to override the defaults
* @type jQuery
* @cat Plugins/Metadata
*/
$.fn.metadata = function( opts ){
return $.metadata.get( this[0], opts );
};
})(jQuery);

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

902
public/js/lib/zepto.js Normal file
View File

@ -0,0 +1,902 @@
/* Zepto v1.1.4-95-g601372a - zepto event ajax form - zeptojs.com/license */
var Zepto = (function() {
var undefined, key, $, classList, emptyArray = [], concat = emptyArray.concat, filter = emptyArray.filter, slice = emptyArray.slice,
document = window.document,
elementDisplay = {}, classCache = {},
cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1,'opacity': 1, 'z-index': 1, 'zoom': 1 },
fragmentRE = /^\s*<(\w+|!)[^>]*>/,
singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
rootNodeRE = /^(?:body|html)$/i,
capitalRE = /([A-Z])/g,
// special attributes that should be get/set via method calls
methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'],
adjacencyOperators = [ 'after', 'prepend', 'before', 'append' ],
table = document.createElement('table'),
tableRow = document.createElement('tr'),
containers = {
'tr': document.createElement('tbody'),
'tbody': table, 'thead': table, 'tfoot': table,
'td': tableRow, 'th': tableRow,
'*': document.createElement('div')
},
readyRE = /complete|loaded|interactive/,
simpleSelectorRE = /^[\w-]*$/,
class2type = {},
toString = class2type.toString,
zepto = {},
camelize, uniq,
tempParent = document.createElement('div'),
propMap = {
'tabindex': 'tabIndex',
'readonly': 'readOnly',
'for': 'htmlFor',
'class': 'className',
'maxlength': 'maxLength',
'cellspacing': 'cellSpacing',
'cellpadding': 'cellPadding',
'rowspan': 'rowSpan',
'colspan': 'colSpan',
'usemap': 'useMap',
'frameborder': 'frameBorder',
'contenteditable': 'contentEditable'
},
isArray = Array.isArray ||
function(object){ return object instanceof Array }
zepto.matches = function(element, selector) {
if (!selector || !element || element.nodeType !== 1) return false
var matchesSelector = element.webkitMatchesSelector || element.mozMatchesSelector ||
element.oMatchesSelector || element.matchesSelector
if (matchesSelector) return matchesSelector.call(element, selector)
// fall back to performing a selector:
var match, parent = element.parentNode, temp = !parent
if (temp) (parent = tempParent).appendChild(element)
match = ~zepto.qsa(parent, selector).indexOf(element)
temp && tempParent.removeChild(element)
return match
}
function type(obj) {
return obj == null ? String(obj) :
class2type[toString.call(obj)] || "object"
}
function isFunction(value) { return type(value) == "function" }
function isWindow(obj) { return obj != null && obj == obj.window }
function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE }
function isObject(obj) { return type(obj) == "object" }
function isPlainObject(obj) {
return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype
}
function likeArray(obj) { return typeof obj.length == 'number' }
function compact(array) { return filter.call(array, function(item){ return item != null }) }
function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array }
camelize = function(str){ return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) }
function dasherize(str) {
return str.replace(/::/g, '/')
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
.replace(/([a-z\d])([A-Z])/g, '$1_$2')
.replace(/_/g, '-')
.toLowerCase()
}
uniq = function(array){ return filter.call(array, function(item, idx){ return array.indexOf(item) == idx }) }
function classRE(name) {
return name in classCache ?
classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)'))
}
function maybeAddPx(name, value) {
return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value
}
function defaultDisplay(nodeName) {
var element, display
if (!elementDisplay[nodeName]) {
element = document.createElement(nodeName)
document.body.appendChild(element)
display = getComputedStyle(element, '').getPropertyValue("display")
element.parentNode.removeChild(element)
display == "none" && (display = "block")
elementDisplay[nodeName] = display
}
return elementDisplay[nodeName]
}
function children(element) {
return 'children' in element ?
slice.call(element.children) :
$.map(element.childNodes, function(node){ if (node.nodeType == 1) return node })
}
function Z(dom, selector) {
var i, len = dom ? dom.length : 0
for (i = 0; i < len; i++) this[i] = dom[i]
this.length = len
this.selector = selector || ''
}
// `$.zepto.fragment` takes a html string and an optional tag name
// to generate DOM nodes from the given html string.
// The generated DOM nodes are returned as an array.
// This function can be overridden in plugins for example to make
// it compatible with browsers that don't support the DOM fully.
zepto.fragment = function(html, name, properties) {
var dom, nodes, container
// A special case optimization for a single tag
if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1))
if (!dom) {
if (html.replace) html = html.replace(tagExpanderRE, "<$1></$2>")
if (name === undefined) name = fragmentRE.test(html) && RegExp.$1
if (!(name in containers)) name = '*'
container = containers[name]
container.innerHTML = '' + html
dom = $.each(slice.call(container.childNodes), function(){
container.removeChild(this)
})
}
if (isPlainObject(properties)) {
nodes = $(dom)
$.each(properties, function(key, value) {
if (methodAttributes.indexOf(key) > -1) nodes[key](value)
else nodes.attr(key, value)
})
}
return dom
}
// `$.zepto.Z` swaps out the prototype of the given `dom` array
// of nodes with `$.fn` and thus supplying all the Zepto functions
// to the array. This method can be overridden in plugins.
zepto.Z = function(dom, selector) {
return new Z(dom, selector)
}
// `$.zepto.isZ` should return `true` if the given object is a Zepto
// collection. This method can be overridden in plugins.
zepto.isZ = function(object) {
return object instanceof zepto.Z
}
// `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and
// takes a CSS selector and an optional context (and handles various
// special cases).
// This method can be overridden in plugins.
zepto.init = function(selector, context) {
var dom
// If nothing given, return an empty Zepto collection
if (!selector) return zepto.Z()
// Optimize for string selectors
else if (typeof selector == 'string') {
selector = selector.trim()
// If it's a html fragment, create nodes from it
// Note: In both Chrome 21 and Firefox 15, DOM error 12
// is thrown if the fragment doesn't begin with <
if (selector[0] == '<' && fragmentRE.test(selector))
dom = zepto.fragment(selector, RegExp.$1, context), selector = null
// If there's a context, create a collection on that context first, and select
// nodes from there
else if (context !== undefined) return $(context).find(selector)
// If it's a CSS selector, use it to select nodes.
else dom = zepto.qsa(document, selector)
}
// If a function is given, call it when the DOM is ready
else if (isFunction(selector)) return $(document).ready(selector)
// If a Zepto collection is given, just return it
else if (zepto.isZ(selector)) return selector
else {
// normalize array if an array of nodes is given
if (isArray(selector)) dom = compact(selector)
// Wrap DOM nodes.
else if (isObject(selector))
dom = [selector], selector = null
// If it's a html fragment, create nodes from it
else if (fragmentRE.test(selector))
dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
// If there's a context, create a collection on that context first, and select
// nodes from there
else if (context !== undefined) return $(context).find(selector)
// And last but no least, if it's a CSS selector, use it to select nodes.
else dom = zepto.qsa(document, selector)
}
// create a new Zepto collection from the nodes found
return zepto.Z(dom, selector)
}
// `$` will be the base `Zepto` object. When calling this
// function just call `$.zepto.init, which makes the implementation
// details of selecting nodes and creating Zepto collections
// patchable in plugins.
$ = function(selector, context){
return zepto.init(selector, context)
}
function extend(target, source, deep) {
for (key in source)
if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {
if (isPlainObject(source[key]) && !isPlainObject(target[key]))
target[key] = {}
if (isArray(source[key]) && !isArray(target[key]))
target[key] = []
extend(target[key], source[key], deep)
}
else if (source[key] !== undefined) target[key] = source[key]
}
// Copy all but undefined properties from one or more
// objects to the `target` object.
$.extend = function(target){
var deep, args = slice.call(arguments, 1)
if (typeof target == 'boolean') {
deep = target
target = args.shift()
}
args.forEach(function(arg){ extend(target, arg, deep) })
return target
}
// `$.zepto.qsa` is Zepto's CSS selector implementation which
// uses `document.querySelectorAll` and optimizes for some special cases, like `#id`.
// This method can be overridden in plugins.
zepto.qsa = function(element, selector){
var found,
maybeID = selector[0] == '#',
maybeClass = !maybeID && selector[0] == '.',
nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked
isSimple = simpleSelectorRE.test(nameOnly)
return (element.getElementById && isSimple && maybeID) ? // Safari DocumentFragment doesn't have getElementById
( (found = element.getElementById(nameOnly)) ? [found] : [] ) :
(element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11) ? [] :
slice.call(
isSimple && !maybeID && element.getElementsByClassName ? // DocumentFragment doesn't have getElementsByClassName/TagName
maybeClass ? element.getElementsByClassName(nameOnly) : // If it's simple, it could be a class
element.getElementsByTagName(selector) : // Or a tag
element.querySelectorAll(selector) // Or it's not simple, and we need to query all
)
}
function filtered(nodes, selector) {
return selector == null ? $(nodes) : $(nodes).filter(selector)
}
$.contains = document.documentElement.contains ?
function(parent, node) {
return parent !== node && parent.contains(node)
} :
function(parent, node) {
while (node && (node = node.parentNode))
if (node === parent) return true
return false
}
function funcArg(context, arg, idx, payload) {
return isFunction(arg) ? arg.call(context, idx, payload) : arg
}
function setAttribute(node, name, value) {
value == null ? node.removeAttribute(name) : node.setAttribute(name, value)
}
// access className property while respecting SVGAnimatedString
function className(node, value){
var klass = node.className || '',
svg = klass && klass.baseVal !== undefined
if (value === undefined) return svg ? klass.baseVal : klass
svg ? (klass.baseVal = value) : (node.className = value)
}
// "true" => true
// "false" => false
// "null" => null
// "42" => 42
// "42.5" => 42.5
// "08" => "08"
// JSON => parse if valid
// String => self
function deserializeValue(value) {
try {
return value ?
value == "true" ||
( value == "false" ? false :
value == "null" ? null :
+value + "" == value ? +value :
/^[\[\{]/.test(value) ? $.parseJSON(value) :
value )
: value
} catch(e) {
return value
}
}
$.type = type
$.isFunction = isFunction
$.isWindow = isWindow
$.isArray = isArray
$.isPlainObject = isPlainObject
$.isEmptyObject = function(obj) {
var name
for (name in obj) return false
return true
}
$.inArray = function(elem, array, i){
return emptyArray.indexOf.call(array, elem, i)
}
$.camelCase = camelize
$.trim = function(str) {
return str == null ? "" : String.prototype.trim.call(str)
}
// plugin compatibility
$.uuid = 0
$.support = { }
$.expr = { }
$.noop = function() {}
$.map = function(elements, callback){
var value, values = [], i, key
if (likeArray(elements))
for (i = 0; i < elements.length; i++) {
value = callback(elements[i], i)
if (value != null) values.push(value)
}
else
for (key in elements) {
value = callback(elements[key], key)
if (value != null) values.push(value)
}
return flatten(values)
}
$.each = function(elements, callback){
var i, key
if (likeArray(elements)) {
for (i = 0; i < elements.length; i++)
if (callback.call(elements[i], i, elements[i]) === false) return elements
} else {
for (key in elements)
if (callback.call(elements[key], key, elements[key]) === false) return elements
}
return elements
}
$.grep = function(elements, callback){
return filter.call(elements, callback)
}
if (window.JSON) $.parseJSON = JSON.parse
// Populate the class2type map
$.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
class2type[ "[object " + name + "]" ] = name.toLowerCase()
})
// Define methods that will be available on all
// Zepto collections
$.fn = {
constructor: zepto.Z,
length: 0,
// Because a collection acts like an array
// copy over these useful array functions.
forEach: emptyArray.forEach,
reduce: emptyArray.reduce,
push: emptyArray.push,
sort: emptyArray.sort,
splice: emptyArray.splice,
indexOf: emptyArray.indexOf,
concat: function(){
var i, value, args = []
for (i = 0; i < arguments.length; i++) {
value = arguments[i]
args[i] = zepto.isZ(value) ? value.toArray() : value
}
return concat.apply(zepto.isZ(this) ? this.toArray() : this, args)
},
// `map` and `slice` in the jQuery API work differently
// from their array counterparts
map: function(fn){
return $($.map(this, function(el, i){ return fn.call(el, i, el) }))
},
slice: function(){
return $(slice.apply(this, arguments))
},
ready: function(callback){
// need to check if document.body exists for IE as that browser reports
// document ready when it hasn't yet created the body element
if (readyRE.test(document.readyState) && document.body) callback($)
else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false)
return this
},
get: function(idx){
return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length]
},
toArray: function(){ return this.get() },
size: function(){
return this.length
},
remove: function(){
return this.each(function(){
if (this.parentNode != null)
this.parentNode.removeChild(this)
})
},
each: function(callback){
emptyArray.every.call(this, function(el, idx){
return callback.call(el, idx, el) !== false
})
return this
},
filter: function(selector){
if (isFunction(selector)) return this.not(this.not(selector))
return $(filter.call(this, function(element){
return zepto.matches(element, selector)
}))
},
add: function(selector,context){
return $(uniq(this.concat($(selector,context))))
},
is: function(selector){
return this.length > 0 && zepto.matches(this[0], selector)
},
not: function(selector){
var nodes=[]
if (isFunction(selector) && selector.call !== undefined)
this.each(function(idx){
if (!selector.call(this,idx)) nodes.push(this)
})
else {
var excludes = typeof selector == 'string' ? this.filter(selector) :
(likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector)
this.forEach(function(el){
if (excludes.indexOf(el) < 0) nodes.push(el)
})
}
return $(nodes)
},
has: function(selector){
return this.filter(function(){
return isObject(selector) ?
$.contains(this, selector) :
$(this).find(selector).size()
})
},
eq: function(idx){
return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1)
},
first: function(){
var el = this[0]
return el && !isObject(el) ? el : $(el)
},
last: function(){
var el = this[this.length - 1]
return el && !isObject(el) ? el : $(el)
},
find: function(selector){
var result, $this = this
if (!selector) result = $()
else if (typeof selector == 'object')
result = $(selector).filter(function(){
var node = this
return emptyArray.some.call($this, function(parent){
return $.contains(parent, node)
})
})
else if (this.length == 1) result = $(zepto.qsa(this[0], selector))
else result = this.map(function(){ return zepto.qsa(this, selector) })
return result
},
closest: function(selector, context){
var node = this[0], collection = false
if (typeof selector == 'object') collection = $(selector)
while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector)))
node = node !== context && !isDocument(node) && node.parentNode
return $(node)
},
parents: function(selector){
var ancestors = [], nodes = this
while (nodes.length > 0)
nodes = $.map(nodes, function(node){
if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) {
ancestors.push(node)
return node
}
})
return filtered(ancestors, selector)
},
parent: function(selector){
return filtered(uniq(this.pluck('parentNode')), selector)
},
children: function(selector){
return filtered(this.map(function(){ return children(this) }), selector)
},
contents: function() {
return this.map(function() { return this.contentDocument || slice.call(this.childNodes) })
},
siblings: function(selector){
return filtered(this.map(function(i, el){
return filter.call(children(el.parentNode), function(child){ return child!==el })
}), selector)
},
empty: function(){
return this.each(function(){ this.innerHTML = '' })
},
// `pluck` is borrowed from Prototype.js
pluck: function(property){
return $.map(this, function(el){ return el[property] })
},
show: function(){
return this.each(function(){
this.style.display == "none" && (this.style.display = '')
if (getComputedStyle(this, '').getPropertyValue("display") == "none")
this.style.display = defaultDisplay(this.nodeName)
})
},
replaceWith: function(newContent){
return this.before(newContent).remove()
},
wrap: function(structure){
var func = isFunction(structure)
if (this[0] && !func)
var dom = $(structure).get(0),
clone = dom.parentNode || this.length > 1
return this.each(function(index){
$(this).wrapAll(
func ? structure.call(this, index) :
clone ? dom.cloneNode(true) : dom
)
})
},
wrapAll: function(structure){
if (this[0]) {
$(this[0]).before(structure = $(structure))
var children
// drill down to the inmost element
while ((children = structure.children()).length) structure = children.first()
$(structure).append(this)
}
return this
},
wrapInner: function(structure){
var func = isFunction(structure)
return this.each(function(index){
var self = $(this), contents = self.contents(),
dom = func ? structure.call(this, index) : structure
contents.length ? contents.wrapAll(dom) : self.append(dom)
})
},
unwrap: function(){
this.parent().each(function(){
$(this).replaceWith($(this).children())
})
return this
},
clone: function(){
return this.map(function(){ return this.cloneNode(true) })
},
hide: function(){
return this.css("display", "none")
},
toggle: function(setting){
return this.each(function(){
var el = $(this)
;(setting === undefined ? el.css("display") == "none" : setting) ? el.show() : el.hide()
})
},
prev: function(selector){ return $(this.pluck('previousElementSibling')).filter(selector || '*') },
next: function(selector){ return $(this.pluck('nextElementSibling')).filter(selector || '*') },
html: function(html){
return 0 in arguments ?
this.each(function(idx){
var originHtml = this.innerHTML
$(this).empty().append( funcArg(this, html, idx, originHtml) )
}) :
(0 in this ? this[0].innerHTML : null)
},
text: function(text){
return 0 in arguments ?
this.each(function(idx){
var newText = funcArg(this, text, idx, this.textContent)
this.textContent = newText == null ? '' : ''+newText
}) :
(0 in this ? this.pluck('textContent').join("") : null)
},
attr: function(name, value){
var result
return (typeof name == 'string' && !(1 in arguments)) ?
(!this.length || this[0].nodeType !== 1 ? undefined :
(!(result = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : result
) :
this.each(function(idx){
if (this.nodeType !== 1) return
if (isObject(name)) for (key in name) setAttribute(this, key, name[key])
else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name)))
})
},
removeAttr: function(name){
return this.each(function(){ this.nodeType === 1 && name.split(' ').forEach(function(attribute){
setAttribute(this, attribute)
}, this)})
},
prop: function(name, value){
name = propMap[name] || name
return (1 in arguments) ?
this.each(function(idx){
this[name] = funcArg(this, value, idx, this[name])
}) :
(this[0] && this[0][name])
},
data: function(name, value){
var attrName = 'data-' + name.replace(capitalRE, '-$1').toLowerCase()
var data = (1 in arguments) ?
this.attr(attrName, value) :
this.attr(attrName)
return data !== null ? deserializeValue(data) : undefined
},
val: function(value){
return 0 in arguments ?
this.each(function(idx){
this.value = funcArg(this, value, idx, this.value)
}) :
(this[0] && (this[0].multiple ?
$(this[0]).find('option').filter(function(){ return this.selected }).pluck('value') :
this[0].value)
)
},
offset: function(coordinates){
if (coordinates) return this.each(function(index){
var $this = $(this),
coords = funcArg(this, coordinates, index, $this.offset()),
parentOffset = $this.offsetParent().offset(),
props = {
top: coords.top - parentOffset.top,
left: coords.left - parentOffset.left
}
if ($this.css('position') == 'static') props['position'] = 'relative'
$this.css(props)
})
if (!this.length) return null
if (!$.contains(document.documentElement, this[0]))
return {top: 0, left: 0}
var obj = this[0].getBoundingClientRect()
return {
left: obj.left + window.pageXOffset,
top: obj.top + window.pageYOffset,
width: Math.round(obj.width),
height: Math.round(obj.height)
}
},
css: function(property, value){
if (arguments.length < 2) {
var computedStyle, element = this[0]
if(!element) return
computedStyle = getComputedStyle(element, '')
if (typeof property == 'string')
return element.style[camelize(property)] || computedStyle.getPropertyValue(property)
else if (isArray(property)) {
var props = {}
$.each(property, function(_, prop){
props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop))
})
return props
}
}
var css = ''
if (type(property) == 'string') {
if (!value && value !== 0)
this.each(function(){ this.style.removeProperty(dasherize(property)) })
else
css = dasherize(property) + ":" + maybeAddPx(property, value)
} else {
for (key in property)
if (!property[key] && property[key] !== 0)
this.each(function(){ this.style.removeProperty(dasherize(key)) })
else
css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';'
}
return this.each(function(){ this.style.cssText += ';' + css })
},
index: function(element){
return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0])
},
hasClass: function(name){
if (!name) return false
return emptyArray.some.call(this, function(el){
return this.test(className(el))
}, classRE(name))
},
addClass: function(name){
if (!name) return this
return this.each(function(idx){
if (!('className' in this)) return
classList = []
var cls = className(this), newName = funcArg(this, name, idx, cls)
newName.split(/\s+/g).forEach(function(klass){
if (!$(this).hasClass(klass)) classList.push(klass)
}, this)
classList.length && className(this, cls + (cls ? " " : "") + classList.join(" "))
})
},
removeClass: function(name){
return this.each(function(idx){
if (!('className' in this)) return
if (name === undefined) return className(this, '')
classList = className(this)
funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass){
classList = classList.replace(classRE(klass), " ")
})
className(this, classList.trim())
})
},
toggleClass: function(name, when){
if (!name) return this
return this.each(function(idx){
var $this = $(this), names = funcArg(this, name, idx, className(this))
names.split(/\s+/g).forEach(function(klass){
(when === undefined ? !$this.hasClass(klass) : when) ?
$this.addClass(klass) : $this.removeClass(klass)
})
})
},
scrollTop: function(value){
if (!this.length) return
var hasScrollTop = 'scrollTop' in this[0]
if (value === undefined) return hasScrollTop ? this[0].scrollTop : this[0].pageYOffset
return this.each(hasScrollTop ?
function(){ this.scrollTop = value } :
function(){ this.scrollTo(this.scrollX, value) })
},
scrollLeft: function(value){
if (!this.length) return
var hasScrollLeft = 'scrollLeft' in this[0]
if (value === undefined) return hasScrollLeft ? this[0].scrollLeft : this[0].pageXOffset
return this.each(hasScrollLeft ?
function(){ this.scrollLeft = value } :
function(){ this.scrollTo(value, this.scrollY) })
},
position: function() {
if (!this.length) return
var elem = this[0],
// Get *real* offsetParent
offsetParent = this.offsetParent(),
// Get correct offsets
offset = this.offset(),
parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset()
// Subtract element margins
// note: when an element has margin: auto the offsetLeft and marginLeft
// are the same in Safari causing offset.left to incorrectly be 0
offset.top -= parseFloat( $(elem).css('margin-top') ) || 0
offset.left -= parseFloat( $(elem).css('margin-left') ) || 0
// Add offsetParent borders
parentOffset.top += parseFloat( $(offsetParent[0]).css('border-top-width') ) || 0
parentOffset.left += parseFloat( $(offsetParent[0]).css('border-left-width') ) || 0
// Subtract the two offsets
return {
top: offset.top - parentOffset.top,
left: offset.left - parentOffset.left
}
},
offsetParent: function() {
return this.map(function(){
var parent = this.offsetParent || document.body
while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css("position") == "static")
parent = parent.offsetParent
return parent
})
}
}
// for now
$.fn.detach = $.fn.remove
// Generate the `width` and `height` functions
;['width', 'height'].forEach(function(dimension){
var dimensionProperty =
dimension.replace(/./, function(m){ return m[0].toUpperCase() })
$.fn[dimension] = function(value){
var offset, el = this[0]
if (value === undefined) return isWindow(el) ? el['inner' + dimensionProperty] :
isDocument(el) ? el.documentElement['scroll' + dimensionProperty] :
(offset = this.offset()) && offset[dimension]
else return this.each(function(idx){
el = $(this)
el.css(dimension, funcArg(this, value, idx, el[dimension]()))
})
}
})
function traverseNode(node, fun) {
fun(node)
for (var i = 0, len = node.childNodes.length; i < len; i++)
traverseNode(node.childNodes[i], fun)
}
// Generate the `after`, `prepend`, `before`, `append`,
// `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods.
adjacencyOperators.forEach(function(operator, operatorIndex) {
var inside = operatorIndex % 2 //=> prepend, append
$.fn[operator] = function(){
// arguments can be nodes, arrays of nodes, Zepto objects and HTML strings
var argType, nodes = $.map(arguments, function(arg) {
argType = type(arg)
return argType == "object" || argType == "array" || arg == null ?
arg : zepto.fragment(arg)
}),
parent, copyByClone = this.length > 1
if (nodes.length < 1) return this
return this.each(function(_, target){
parent = inside ? target : target.parentNode
// convert all methods to a "before" operation
target = operatorIndex == 0 ? target.nextSibling :
operatorIndex == 1 ? target.firstChild :
operatorIndex == 2 ? target :
null
var parentInDocument = $.contains(document.documentElement, parent)
nodes.forEach(function(node){
if (copyByClone) node = node.cloneNode(true)
else if (!parent) return $(node).remove()
parent.insertBefore(node, target)
if (parentInDocument) traverseNode(node, function(el){
if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' &&
(!el.type || el.type === 'text/javascript') && !el.src)
window['eval'].call(window, el.innerHTML)
})
})
})
}
// after => insertAfter
// prepend => prependTo
// before => insertBefore
// append => appendTo
$.fn[inside ? operator+'To' : 'insert'+(operatorIndex ? 'Before' : 'After')] = function(html){
$(html)[operator](this)
return this
}
})
zepto.Z.prototype = Z.prototype = $.fn
// Export internal API functions in the `$.zepto` namespace
zepto.uniq = uniq
zepto.deserializeValue = deserializeValue
$.zepto = zepto
return $
})()
window.Zepto = Zepto
window.$ === undefined && (window.$ = Zepto)

View File

@ -0,0 +1,27 @@
((_) => {
'use strict';
const search = (tempHtml, query) => {
_.$('.cssload-loader')[0].removeAttribute('hidden');
_.get(_.url('/manga/search'), {'query':query,}, (searchResults, status) => {
searchResults = JSON.parse(searchResults);
_.$('.cssload-loader')[0].setAttribute('hidden', 'hidden');
Mustache.parse(tempHtml);
_.$('#series_list')[0].innerHTML = Mustache.render(tempHtml, searchResults);
});
};
_.get('/public/templates/manga-ajax-search-results.html', tempHtml => {
_.on('#search', 'keyup', _.throttle(250, function(e) {
let query = encodeURIComponent(this.value);
if (query === '') {
return;
}
search(tempHtml, query);
}));
});
})(AnimeClient);

View File

@ -1,48 +1,46 @@
/** /**
* Javascript for editing manga, if logged in * Javascript for editing manga, if logged in
*/ */
(function ($) { ((_) => {
"use strict"; 'use strict';
if (CONTROLLER !== "manga") return; _.on('.manga.list', 'click', '.edit_buttons button', function(e) {
let this_sel = this;
let parent_sel = _.closestParent(this, 'article');
let manga_id = parent_sel.id.replace("manga-", "");
let type = this_sel.classList.contains("plus_one_chapter") ? 'chapter' : 'volume';
let completed = parseInt(_.$(`.${type}s_read`, parent_sel)[0].textContent, 10);
let total = parseInt(_.$(`.${type}_count`, parent_sel)[0].textContent, 10);
let manga_name = _.$('.name', parent_sel)[0].textContent;
$(".edit_buttons button").on("click", function(e) { if (isNaN(completed)) {
var this_sel = $(this);
var parent_sel = $(this).closest("article");
var manga_id = parent_sel.attr("id").replace("manga-", "");
var type = this_sel.is(".plus_one_chapter") ? 'chapter' : 'volume';
var completed = parseInt(parent_sel.find("." + type + "s_read").text(), 10);
var total = parseInt(parent_sel.find("."+type+"_count").text(), 10);
console.log(completed);
console.log(total);
if (isNaN(completed))
{
completed = 0; completed = 0;
} }
var data = { let data = {
id: manga_id id: manga_id
}; };
// Update the total count // Update the total count
data[type + "s_read"] = ++completed; data[type + "s_read"] = ++completed;
$.ajax({ _.ajax(_.url('/manga/update'), {
data: data, data: data,
dataType: 'json', dataType: 'json',
method: 'POST', type: 'POST',
mimeType: 'application/json', mimeType: 'application/json',
url: BASE_URL + CONTROLLER + '/update' success: (res) => {
}).done(function(res) { _.$(`.${type}s_read`, parent_sel)[0].textContent = completed;
console.table(res); _.showMessage('success', `Sucessfully updated ${manga_name}`);
parent_sel.find("."+type+"s_read").text(completed); _.scrollToTop();
add_message('success', "Sucessfully updated " + res.manga[0].romaji_title); },
}).fail(function() { error: (xhr, errorType, error) => {
add_message('error', "Failed to updated " + res.manga[0].romaji_title); console.error(error);
_.showMessage('error', `Failed to updated ${manga_name}`);
_.scrollToTop();
}
}); });
}); });
}(jQuery)); })(AnimeClient);

View File

@ -1,13 +0,0 @@
function add_message(type, message)
{
var template = '<div class="message ' + type + '"><span class="icon"></span>' + message + '<span class="close" onclick="this.parentElement.style.display=\'none\'">x</span></div>';
if ($(".message").length > 0)
{
$(".message").replaceWith(template);
}
else
{
$("main").prepend(template);
}
}

View File

@ -1,3 +0,0 @@
$(function() {
$('table').tablesorter();
});

117
public/min.php Normal file
View File

@ -0,0 +1,117 @@
<?php
/**
* Hummingbird Anime Client
*
* An API client for Hummingbird to manage anime and manga watch lists
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren
* @copyright Copyright (c) 2015 - 2016
* @link https://github.com/timw4mail/HummingBirdAnimeClient
* @license MIT
*/
namespace Aviat\EasyMin;
//Creative rewriting of /g/groupname to ?g=groupname
$pi = $_SERVER['PATH_INFO'];
$pia = explode('/', $pi);
$pia_len = count($pia);
$i = 1;
while($i < $pia_len)
{
$j = $i+1;
$j = (isset($pia[$j])) ? $j : $i;
$_GET[$pia[$i]] = $pia[$j];
$i = $j + 1;
};
class FileNotChangedException extends \Exception {}
class BaseMin {
/**
* Get value of the if-modified-since header
*
* @return int - timestamp to compare for cache control
*/
protected function get_if_modified()
{
return (array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER))
? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])
: time();
}
/**
* Get value of etag to compare to hash of output
*
* @return string - the etag to compare
*/
protected function get_if_none_match()
{
return (array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER))
? $_SERVER['HTTP_IF_NONE_MATCH']
: '';
}
/**
* Determine whether or not to send debug version
*
* @return boolean
*/
protected function is_not_debug()
{
return ! $this->is_debug_call();
}
/**
* Determine whether or not to send debug version
*
* @return boolean
*/
protected function is_debug_call()
{
return array_key_exists('debug', $_GET);
}
/**
* Send actual output to browser
*
* @param string $content - the body of the response
* @param string $mime_type - the content type
* @param int $last_modified - the last modified date
* @return void
*/
protected function send_final_output($content, $mime_type, $last_modified)
{
//This GZIPs the CSS for transmission to the user
//making file size smaller and transfer rate quicker
ob_start("ob_gzhandler");
$expires = $last_modified + 691200;
$last_modified_date = gmdate('D, d M Y H:i:s', $last_modified);
$expires_date = gmdate('D, d M Y H:i:s', $expires);
header("Content-Type: {$mime_type}; charset=utf8");
header("Cache-control: public, max-age=691200, must-revalidate");
header("Last-Modified: {$last_modified_date} GMT");
header("Expires: {$expires_date} GMT");
echo $content;
ob_end_flush();
}
/**
* Send a 304 Not Modified header
*
* @return void
*/
public static function send304()
{
header("status: 304 Not Modified", true, 304);
}
}

View File

@ -0,0 +1,10 @@
{{#anime}}
<article class="media search">
<div class="name" style="background-image:url({{cover_image}})">
<input type="radio" class="big-check" id="{{slug}}" name="id" value="{{slug}}" />
<label for="{{slug}}">
<span>{{title}}<br />{{alternate_title}}</span>
</label>
</div>
</article>
{{/anime}}

View File

@ -0,0 +1,10 @@
{{#search}}
<article class="media search">
<div class="name" style="background-image:url({{image}})">
<input type="radio" class="big-check" id="{{link}}" name="id" value="{{link}}" />
<label for="{{link}}">
<span>{{title}}</span>
</label>
</div>
</article>
{{/search}}

33
public/test/ajax.php Normal file
View File

@ -0,0 +1,33 @@
<?php
$verb = strtolower($_SERVER['REQUEST_METHOD']);
// Send request method if nothing else is specified
if (empty($_GET))
{
echo $verb;
}
else if (isset($_GET['data']))
{
switch($verb)
{
case "get":
$var =& $_GET;
break;
case "post":
$var =& $_POST;
break;
default:
parse_str(file_get_contents('php://input'), $var);
break;
}
header('Content-type: application/json');
echo json_encode($var);
}
else if (isset($_GET['bad']))
{
http_response_code('401');
}

44
public/test/index.html Normal file
View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hummingbird AnimeClient Front-end Testsuite</title>
<link rel="stylesheet" href="lib/mocha.css">
</head>
<body>
<section id="parentTest">
<article class="child">
<div class="grandChild"></div>
</article>
</section>
<div id="mocha">
<ul id="mocha-stats">
<li class="progress"></li>
<li class="passes"></li>
<li class="failures"></li>
<li class="duration"></li>
</ul>
<ul id="mocha-report"></ul>
</div>
<script src="../js/base/classList.js"></script>
<script src="lib/testBundle.js"></script>
<script>
var expect = chai.expect;
mocha.setup('tdd');
</script>
<!-- include source files here... -->
<script src="../js/base/AnimeClient.js"></script>
<!-- include test files here... -->
<script src="tests/AnimeClient.js"></script>
<script src="tests/ajax.js"></script>
<script>
mocha.checkLeaks();
mocha.globals(['AnimeClient']);
mocha.run();
</script>
</body>
</html>

305
public/test/lib/mocha.css Normal file
View File

@ -0,0 +1,305 @@
@charset "utf-8";
body {
margin:0;
}
#mocha {
font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 60px 50px;
}
#mocha ul,
#mocha li {
margin: 0;
padding: 0;
}
#mocha ul {
list-style: none;
}
#mocha h1,
#mocha h2 {
margin: 0;
}
#mocha h1 {
margin-top: 15px;
font-size: 1em;
font-weight: 200;
}
#mocha h1 a {
text-decoration: none;
color: inherit;
}
#mocha h1 a:hover {
text-decoration: underline;
}
#mocha .suite .suite h1 {
margin-top: 0;
font-size: .8em;
}
#mocha .hidden {
display: none;
}
#mocha h2 {
font-size: 12px;
font-weight: normal;
cursor: pointer;
}
#mocha .suite {
margin-left: 15px;
}
#mocha .test {
margin-left: 15px;
overflow: hidden;
}
#mocha .test.pending:hover h2::after {
content: '(pending)';
font-family: arial, sans-serif;
}
#mocha .test.pass.medium .duration {
background: #c09853;
}
#mocha .test.pass.slow .duration {
background: #b94a48;
}
#mocha .test.pass::before {
content: '✓';
font-size: 12px;
display: block;
float: left;
margin-right: 5px;
color: #00d6b2;
}
#mocha .test.pass .duration {
font-size: 9px;
margin-left: 5px;
padding: 2px 5px;
color: #fff;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
-moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-o-border-radius: 5px;
border-radius: 5px;
}
#mocha .test.pass.fast .duration {
display: none;
}
#mocha .test.pending {
color: #0b97c4;
}
#mocha .test.pending::before {
content: '◦';
color: #0b97c4;
}
#mocha .test.fail {
color: #c00;
}
#mocha .test.fail pre {
color: black;
}
#mocha .test.fail::before {
content: '✖';
font-size: 12px;
display: block;
float: left;
margin-right: 5px;
color: #c00;
}
#mocha .test pre.error {
color: #c00;
max-height: 300px;
overflow: auto;
}
#mocha .test .html-error {
overflow: auto;
color: black;
line-height: 1.5;
display: block;
float: left;
clear: left;
font: 12px/1.5 monaco, monospace;
margin: 5px;
padding: 15px;
border: 1px solid #eee;
max-width: 85%; /*(1)*/
max-width: calc(100% - 42px); /*(2)*/
max-height: 300px;
word-wrap: break-word;
border-bottom-color: #ddd;
-webkit-border-radius: 3px;
-webkit-box-shadow: 0 1px 3px #eee;
-moz-border-radius: 3px;
-moz-box-shadow: 0 1px 3px #eee;
border-radius: 3px;
}
#mocha .test .html-error pre.error {
border: none;
-webkit-border-radius: none;
-webkit-box-shadow: none;
-moz-border-radius: none;
-moz-box-shadow: none;
padding: 0;
margin: 0;
margin-top: 18px;
max-height: none;
}
/**
* (1): approximate for browsers not supporting calc
* (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border)
* ^^ seriously
*/
#mocha .test pre {
display: block;
float: left;
clear: left;
font: 12px/1.5 monaco, monospace;
margin: 5px;
padding: 15px;
border: 1px solid #eee;
max-width: 85%; /*(1)*/
max-width: calc(100% - 42px); /*(2)*/
word-wrap: break-word;
border-bottom-color: #ddd;
-webkit-border-radius: 3px;
-webkit-box-shadow: 0 1px 3px #eee;
-moz-border-radius: 3px;
-moz-box-shadow: 0 1px 3px #eee;
border-radius: 3px;
}
#mocha .test h2 {
position: relative;
}
#mocha .test a.replay {
position: absolute;
top: 3px;
right: 0;
text-decoration: none;
vertical-align: middle;
display: block;
width: 15px;
height: 15px;
line-height: 15px;
text-align: center;
background: #eee;
font-size: 15px;
-moz-border-radius: 15px;
border-radius: 15px;
-webkit-transition: opacity 200ms;
-moz-transition: opacity 200ms;
transition: opacity 200ms;
opacity: 0.3;
color: #888;
}
#mocha .test:hover a.replay {
opacity: 1;
}
#mocha-report.pass .test.fail {
display: none;
}
#mocha-report.fail .test.pass {
display: none;
}
#mocha-report.pending .test.pass,
#mocha-report.pending .test.fail {
display: none;
}
#mocha-report.pending .test.pass.pending {
display: block;
}
#mocha-error {
color: #c00;
font-size: 1.5em;
font-weight: 100;
letter-spacing: 1px;
}
#mocha-stats {
position: fixed;
top: 15px;
right: 10px;
font-size: 12px;
margin: 0;
color: #888;
z-index: 1;
}
#mocha-stats .progress {
float: right;
padding-top: 0;
}
#mocha-stats em {
color: black;
}
#mocha-stats a {
text-decoration: none;
color: inherit;
}
#mocha-stats a:hover {
border-bottom: 1px solid #eee;
}
#mocha-stats li {
display: inline-block;
margin: 0 5px;
list-style: none;
padding-top: 11px;
}
#mocha-stats canvas {
width: 40px;
height: 40px;
}
#mocha code .comment { color: #ddd; }
#mocha code .init { color: #2f6fad; }
#mocha code .string { color: #5890ad; }
#mocha code .keyword { color: #8a6343; }
#mocha code .number { color: #2f6fad; }
@media screen and (max-device-width: 480px) {
#mocha {
margin: 60px 0px;
}
#mocha #stats {
position: absolute;
}
}

View File

@ -0,0 +1,312 @@
(function e$$0(m,g,c){function l(e,a){if(!g[e]){if(!m[e]){var h="function"==typeof require&&require;if(!a&&h)return h(e,!0);if(b)return b(e,!0);h=Error("Cannot find module '"+e+"'");throw h.code="MODULE_NOT_FOUND",h;}h=g[e]={exports:{}};m[e][0].call(h.exports,function(a){var b=m[e][1][a];return l(b?b:a)},h,h.exports,e$$0,m,g,c)}return g[e].exports}for(var b="function"==typeof require&&require,e=0;e<c.length;e++)l(c[e]);return l})({1:[function(f,m,g){g=f("_process");m.exports=g.env.COV?f("./lib-cov/mocha"):
f("./lib/mocha")},{"./lib-cov/mocha":void 0,"./lib/mocha":14,_process:51}],2:[function(f,m,g){m.exports=function(c){return function(){}}},{}],3:[function(f,m,g){function c(e){return"[object Array]"===b.call(e)}function l(){}g.EventEmitter=l;var b=Object.prototype.toString;l.prototype.on=function(b,k){this.$events||(this.$events={});this.$events[b]?c(this.$events[b])?this.$events[b].push(k):this.$events[b]=[this.$events[b],k]:this.$events[b]=k;return this};l.prototype.addListener=l.prototype.on;l.prototype.once=
function(b,k){function a(){h.removeListener(b,a);k.apply(this,arguments)}var h=this;a.listener=k;this.on(b,a);return this};l.prototype.removeListener=function(b,k){if(this.$events&&this.$events[b]){var a=this.$events[b];if(c(a)){for(var h=-1,d=0,l=a.length;d<l;d++)if(a[d]===k||a[d].listener&&a[d].listener===k){h=d;break}if(0>h)return this;a.splice(h,1);a.length||delete this.$events[b]}else(a===k||a.listener&&a.listener===k)&&delete this.$events[b]}return this};l.prototype.removeAllListeners=function(b){if(void 0===
b)return this.$events={},this;this.$events&&this.$events[b]&&(this.$events[b]=null);return this};l.prototype.listeners=function(b){this.$events||(this.$events={});this.$events[b]||(this.$events[b]=[]);c(this.$events[b])||(this.$events[b]=[this.$events[b]]);return this.$events[b]};l.prototype.emit=function(b){if(!this.$events)return!1;var k=this.$events[b];if(!k)return!1;var a=Array.prototype.slice.call(arguments,1);if("function"===typeof k)k.apply(this,a);else if(c(k))for(var k=k.slice(),h=0,d=k.length;h<
d;h++)k[h].apply(this,a);else return!1;return!0}},{}],4:[function(f,m,g){function c(){this.percent=0;this.size(0);this.fontSize(11);this.font("helvetica, arial, sans-serif")}m.exports=c;c.prototype.size=function(c){this._size=c;return this};c.prototype.text=function(c){this._text=c;return this};c.prototype.fontSize=function(c){this._fontSize=c;return this};c.prototype.font=function(c){this._font=c;return this};c.prototype.update=function(c){this.percent=c;return this};c.prototype.draw=function(c){try{var b=
Math.min(this.percent,100),e=this._size,k=e/2,a=k-1,h=this._fontSize;c.font=h+"px "+this._font;var d=b/100*Math.PI*2;c.clearRect(0,0,e,e);c.strokeStyle="#9f9f9f";c.beginPath();c.arc(k,k,a,0,d,!1);c.stroke();c.strokeStyle="#eee";c.beginPath();c.arc(k,k,a-1,0,d,!0);c.stroke();var t=this._text||(b|0)+"%",f=c.measureText(t).width;c.fillText(t,k-f/2+1,k+h/2-1)}catch(g){}return this}},{}],5:[function(f,m,g){(function(c){g.isatty=function(){return!0};g.getWindowSize=function(){return"innerHeight"in c?[c.innerHeight,
c.innerWidth]:[640,480]}}).call(this,"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{})},{}],6:[function(f,m,g){function c(){}m.exports=c;c.prototype.runnable=function(c){if(!arguments.length)return this._runnable;this.test=this._runnable=c;return this};c.prototype.timeout=function(c){if(!arguments.length)return this.runnable().timeout();this.runnable().timeout(c);return this};c.prototype.enableTimeouts=function(c){this.runnable().enableTimeouts(c);
return this};c.prototype.slow=function(c){this.runnable().slow(c);return this};c.prototype.skip=function(){this.runnable().skip();return this};c.prototype.retries=function(c){if(!arguments.length)return this.runnable().retries();this.runnable().retries(c);return this};c.prototype.inspect=function(){return JSON.stringify(this,function(c,b){return"runnable"===c||"test"===c?void 0:b},2)}},{}],7:[function(f,m,g){function c(b,c){l.call(this,b,c);this.type="hook"}var l=f("./runnable");f=f("./utils").inherits;
m.exports=c;f(c,l);c.prototype.error=function(b){if(!arguments.length)return b=this._error,this._error=null,b;this._error=b}},{"./runnable":35,"./utils":39}],8:[function(f,m,g){var c=f("../suite"),l=f("../test"),b=f("escape-string-regexp");m.exports=function(e){var k=[e];e.on("pre-require",function(a,h,d){var t=f("./common")(k,a);a.before=t.before;a.after=t.after;a.beforeEach=t.beforeEach;a.afterEach=t.afterEach;a.run=d.options.delay&&t.runWithSuite(e);a.describe=a.context=function(a,d){var b=c.create(k[0],
a);b.file=h;k.unshift(b);d.call(b);k.shift();return b};a.xdescribe=a.xcontext=a.describe.skip=function(a,d){var b=c.create(k[0],a);b.pending=!0;k.unshift(b);d.call(b);k.shift()};a.describe.only=function(b,h){var c=a.describe(b,h);d.grep(c.fullTitle());return c};var g=a.it=a.specify=function(a,d){var b=k[0];b.pending&&(d=null);var c=new l(a,d);c.file=h;b.addTest(c);return c};a.it.only=function(a,h){var c=g(a,h),e="^"+b(c.fullTitle())+"$";d.grep(new RegExp(e));return c};a.xit=a.xspecify=a.it.skip=function(d){a.it(d)};
a.it.retries=function(d){a.retries(d)}})}},{"../suite":37,"../test":38,"./common":9,"escape-string-regexp":68}],9:[function(f,m,g){m.exports=function(c,l){return{runWithSuite:function(b){return function(){b.run()}},before:function(b,e){c[0].beforeAll(b,e)},after:function(b,e){c[0].afterAll(b,e)},beforeEach:function(b,e){c[0].beforeEach(b,e)},afterEach:function(b,e){c[0].afterEach(b,e)},test:{skip:function(b){l.test(b)},retries:function(b){l.retries(b)}}}}},{}],10:[function(f,m,g){var c=f("../suite"),
l=f("../test");m.exports=function(b){function e(a,b){var d,t;for(t in a)if("function"===typeof a[t])switch(d=a[t],t){case "before":k[0].beforeAll(d);break;case "after":k[0].afterAll(d);break;case "beforeEach":k[0].beforeEach(d);break;case "afterEach":k[0].afterEach(d);break;default:d=new l(t,d),d.file=b,k[0].addTest(d)}else d=c.create(k[0],t),k.unshift(d),e(a[t],b),k.shift()}var k=[b];b.on("require",e)}},{"../suite":37,"../test":38}],11:[function(f,m,g){g.bdd=f("./bdd");g.tdd=f("./tdd");g.qunit=f("./qunit");
g.exports=f("./exports")},{"./bdd":8,"./exports":10,"./qunit":12,"./tdd":13}],12:[function(f,m,g){var c=f("../suite"),l=f("../test"),b=f("escape-string-regexp");m.exports=function(e){var k=[e];e.on("pre-require",function(a,h,d){var t=f("./common")(k,a);a.before=t.before;a.after=t.after;a.beforeEach=t.beforeEach;a.afterEach=t.afterEach;a.run=d.options.delay&&t.runWithSuite(e);a.suite=function(a){1<k.length&&k.shift();a=c.create(k[0],a);a.file=h;k.unshift(a);return a};a.suite.only=function(b,h){var c=
a.suite(b,h);d.grep(c.fullTitle())};a.test=function(a,d){var b=new l(a,d);b.file=h;k[0].addTest(b);return b};a.test.only=function(h,c){var e=a.test(h,c),e="^"+b(e.fullTitle())+"$";d.grep(new RegExp(e))};a.test.skip=t.test.skip;a.test.retries=t.test.retries})}},{"../suite":37,"../test":38,"./common":9,"escape-string-regexp":68}],13:[function(f,m,g){var c=f("../suite"),l=f("../test"),b=f("escape-string-regexp");m.exports=function(e){var k=[e];e.on("pre-require",function(a,h,d){var t=f("./common")(k,
a);a.setup=t.beforeEach;a.teardown=t.afterEach;a.suiteSetup=t.before;a.suiteTeardown=t.after;a.run=d.options.delay&&t.runWithSuite(e);a.suite=function(a,b){var d=c.create(k[0],a);d.file=h;k.unshift(d);b.call(d);k.shift();return d};a.suite.skip=function(a,d){var b=c.create(k[0],a);b.pending=!0;k.unshift(b);d.call(b);k.shift()};a.suite.only=function(b,h){var c=a.suite(b,h);d.grep(c.fullTitle())};a.test=function(a,b){var d=k[0];d.pending&&(b=null);var c=new l(a,b);c.file=h;d.addTest(c);return c};a.test.only=
function(c,h){var e=a.test(c,h),e="^"+b(e.fullTitle())+"$";d.grep(new RegExp(e))};a.test.skip=t.test.skip;a.test.retries=t.test.retries})}},{"../suite":37,"../test":38,"./common":9,"escape-string-regexp":68}],14:[function(f,m,g){(function(c,l,b){function e(a){a=a||{};this.files=[];this.options=a;a.grep&&this.grep(new RegExp(a.grep));a.fgrep&&this.grep(a.fgrep);this.suite=new g.Suite("",new g.Context);this.ui(a.ui);this.bail(a.bail);this.reporter(a.reporter,a.reporterOptions);"undefined"!==typeof a.timeout&&
null!==a.timeout&&this.timeout(a.timeout);"undefined"!==typeof a.retries&&null!==a.retries&&this.retries(a.retries);this.useColors(a.useColors);null!==a.enableTimeouts&&this.enableTimeouts(a.enableTimeouts);a.slow&&this.slow(a.slow);this.suite.on("pre-require",function(a){g.afterEach=a.afterEach||a.teardown;g.after=a.after||a.suiteTeardown;g.beforeEach=a.beforeEach||a.setup;g.before=a.before||a.suiteSetup;g.describe=a.describe||a.suite;g.it=a.it||a.test;g.setup=a.setup||a.beforeEach;g.suiteSetup=
a.suiteSetup||a.before;g.suiteTeardown=a.suiteTeardown||a.after;g.suite=a.suite||a.describe;g.teardown=a.teardown||a.afterEach;g.test=a.test||a.it;g.run=a.run})}var k=f("escape-string-regexp"),a=f("path"),h=f("./reporters"),d=f("./utils");g=m.exports=e;c.browser||(c=c.cwd(),m.paths.push(c,a.join(c,"node_modules")));g.utils=d;g.interfaces=f("./interfaces");g.reporters=h;g.Runnable=f("./runnable");g.Context=f("./context");g.Runner=f("./runner");g.Suite=f("./suite");g.Hook=f("./hook");g.Test=f("./test");
e.prototype.bail=function(a){arguments.length||(a=!0);this.suite.bail(a);return this};e.prototype.addFile=function(a){this.files.push(a);return this};e.prototype.reporter=function(a,b){if("function"===typeof a)this._reporter=a;else{a=a||"spec";var d;h[a]&&(d=h[a]);if(!d)try{d=f(a)}catch(c){-1!==c.message.indexOf("Cannot find module")?console.warn('"'+a+'" reporter not found'):console.warn('"'+a+'" reporter blew up with error:\n'+c.stack)}d||"teamcity"!==a||console.warn("The Teamcity reporter was moved to a package named mocha-teamcity-reporter (https://npmjs.org/package/mocha-teamcity-reporter).");
if(!d)throw Error('invalid reporter "'+a+'"');this._reporter=d}this.options.reporterOptions=b;return this};e.prototype.ui=function(a){a=a||"bdd";this._ui=g.interfaces[a];if(!this._ui)try{this._ui=f(a)}catch(d){throw Error('invalid interface "'+a+'"');}this._ui=this._ui(this.suite);return this};e.prototype.loadFiles=function(d){var b=this,c=this.suite;this.files.forEach(function(d){d=a.resolve(d);c.emit("pre-require",l,d,b);c.emit("require",f(d),d,b);c.emit("post-require",l,d,b)});d&&d()};e.prototype._growl=
function(d,c){var h=f("growl");d.on("end",function(){var e=c.stats;e.failures?h(e.failures+" of "+d.total+" tests failed",{name:"mocha",title:"Failed",image:a.join(b,"../images","error.png")}):h(e.passes+" tests passed in "+e.duration+"ms",{name:"mocha",title:"Passed",image:a.join(b,"../images","ok.png")})})};e.prototype.grep=function(a){this.options.grep="string"===typeof a?new RegExp(k(a)):a;return this};e.prototype.invert=function(){this.options.invert=!0;return this};e.prototype.ignoreLeaks=function(a){this.options.ignoreLeaks=
!!a;return this};e.prototype.checkLeaks=function(){this.options.ignoreLeaks=!1;return this};e.prototype.fullTrace=function(){this.options.fullStackTrace=!0;return this};e.prototype.growl=function(){this.options.growl=!0;return this};e.prototype.globals=function(a){this.options.globals=(this.options.globals||[]).concat(a);return this};e.prototype.useColors=function(a){void 0!==a&&(this.options.useColors=a);return this};e.prototype.useInlineDiffs=function(a){this.options.useInlineDiffs=void 0!==a&&
a;return this};e.prototype.timeout=function(a){this.suite.timeout(a);return this};e.prototype.retries=function(a){this.suite.retries(a);return this};e.prototype.slow=function(a){this.suite.slow(a);return this};e.prototype.enableTimeouts=function(a){this.suite.enableTimeouts(arguments.length&&void 0!==a?a:!0);return this};e.prototype.asyncOnly=function(){this.options.asyncOnly=!0;return this};e.prototype.noHighlighting=function(){this.options.noHighlighting=!0;return this};e.prototype.allowUncaught=
function(){this.options.allowUncaught=!0;return this};e.prototype.delay=function(){this.options.delay=!0;return this};e.prototype.run=function(a){this.files.length&&this.loadFiles();var d=this.suite,b=this.options;b.files=this.files;var d=new g.Runner(d,b.delay),c=new this._reporter(d,b);d.ignoreLeaks=!1!==b.ignoreLeaks;d.fullStackTrace=b.fullStackTrace;d.asyncOnly=b.asyncOnly;d.allowUncaught=b.allowUncaught;b.grep&&d.grep(b.grep,b.invert);b.globals&&d.globals(b.globals);b.growl&&this._growl(d,c);
void 0!==b.useColors&&(g.reporters.Base.useColors=b.useColors);g.reporters.Base.inlineDiffs=b.useInlineDiffs;return d.run(function(d){c.done?c.done(d,a):a&&a(d)})}}).call(this,f("_process"),"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{},"/lib")},{"./context":6,"./hook":7,"./interfaces":11,"./reporters":22,"./runnable":35,"./runner":36,"./suite":37,"./test":38,"./utils":39,_process:51,"escape-string-regexp":68,growl:69,path:41}],15:[function(f,
m,g){function c(b){if(b=/^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(b)){var c=parseFloat(b[1]);switch((b[2]||"ms").toLowerCase()){case "years":case "year":case "y":return 315576E5*c;case "days":case "day":case "d":return 864E5*c;case "hours":case "hour":case "h":return 36E5*c;case "minutes":case "minute":case "m":return 6E4*c;case "seconds":case "second":case "s":return 1E3*c;case "ms":return c}}}function l(b,c,k){if(!(b<c))return b<1.5*c?Math.floor(b/c)+" "+
k:Math.ceil(b/c)+" "+k+"s"}m.exports=function(b,e){e=e||{};return"string"===typeof b?c(b):e["long"]?l(b,864E5,"day")||l(b,36E5,"hour")||l(b,6E4,"minute")||l(b,1E3,"second")||b+" ms":864E5<=b?Math.round(b/864E5)+"d":36E5<=b?Math.round(b/36E5)+"h":6E4<=b?Math.round(b/6E4)+"m":1E3<=b?Math.round(b/1E3)+"s":b+"ms"}},{}],16:[function(f,m,g){m.exports=function(c){this.message=c}},{}],17:[function(f,m,g){(function(c,l){function b(a){var d=this.stats={suites:0,tests:0,passes:0,pending:0,failures:0},b=this.failures=
[];a&&(this.runner=a,a.stats=d,a.on("start",function(){d.start=new D}),a.on("suite",function(a){d.suites=d.suites||0;a.root||d.suites++}),a.on("test end",function(){d.tests=d.tests||0;d.tests++}),a.on("pass",function(a){d.passes=d.passes||0;a.duration>a.slow()?a.speed="slow":a.duration>a.slow()/2?a.speed="medium":a.speed="fast";d.passes++}),a.on("fail",function(a,c){d.failures=d.failures||0;d.failures++;a.err=c;b.push(a)}),a.on("end",function(){d.end=new D;d.duration=new D-d.start}),a.on("pending",
function(){d.pending++}))}function e(d,b){var c=a(d,"WordsWithSpace",b),h=c.split("\n");if(4<h.length)var n=String(h.length).length,c=h.map(function(a,d){var b=++d,b=String(b);return Array(n-b.length+1).join(" ")+b+" | "+a}).join("\n");c="\n"+w("diff removed","actual")+" "+w("diff added","expected")+"\n\n"+c+"\n";return c=c.replace(/^/gm," ")}function k(a,b){var c=r.createPatch("string",a.actual,a.expected).split("\n").splice(4);return"\n "+d("diff added","+ expected")+" "+d("diff removed",
"- actual")+"\n\n"+c.map(function(a){b&&(a=h(a));return"+"===a[0]?" "+d("diff added",a):"-"===a[0]?" "+d("diff removed",a):a.match(/\@\@/)||a.match(/\\ No newline/)?null:" "+a}).filter(function(a){return"undefined"!==typeof a&&null!==a}).join("\n")}function a(a,b,c){var e=c?h(a.actual):a.actual;a=c?h(a.expected):a.expected;return r["diff"+b](e,a).map(function(a){return a.added?d("diff added",a.value):a.removed?d("diff removed",a.value):a.value}).join("")}function h(a){return a.replace(/\t/g,
"<tab>").replace(/\r/g,"<CR>").replace(/\n/g,"<LF>\n")}function d(a,d){return d.split("\n").map(function(d){return w(a,d)}).join("\n")}var t=f("tty"),r=f("diff"),q=f("../ms"),x=f("../utils"),u=c.browser?null:f("supports-color");g=m.exports=b;var D=l.Date,E=t.isatty(1)&&t.isatty(2);g.useColors=!c.browser&&(u||void 0!==c.env.MOCHA_COLORS);g.inlineDiffs=!1;g.colors={pass:90,fail:31,"bright pass":92,"bright fail":91,"bright yellow":93,pending:36,suite:0,"error title":0,"error message":31,"error stack":90,
checkmark:32,fast:90,medium:33,slow:31,green:32,light:90,"diff gutter":90,"diff added":32,"diff removed":31};g.symbols={ok:"\u2713",err:"\u2716",dot:"\u2024"};"win32"===c.platform&&(g.symbols.ok="\u221a",g.symbols.err="\u00d7",g.symbols.dot=".");var w=g.color=function(a,d){return g.useColors?"\u001b["+g.colors[a]+"m"+d+"\u001b[0m":String(d)};g.window={width:75};E&&(g.window.width=c.stdout.getWindowSize?c.stdout.getWindowSize(1)[0]:t.getWindowSize()[1]);g.cursor={hide:function(){E&&c.stdout.write("\u001b[?25l")},
show:function(){E&&c.stdout.write("\u001b[?25h")},deleteLine:function(){E&&c.stdout.write("\u001b[2K")},beginningOfLine:function(){E&&c.stdout.write("\u001b[0G")},CR:function(){E?(g.cursor.deleteLine(),g.cursor.beginningOfLine()):c.stdout.write("\r")}};g.list=function(a){console.log();a.forEach(function(a,d){var b=w("error title"," %s) %s:\n")+w("error message"," %s")+w("error stack","\n%s\n"),c,h=a.err,l;l=h.message?h.message:"function"===typeof h.inspect?h.inspect()+"":"";var f=h.stack||l,
t=f.indexOf(l),r=h.actual,C=h.expected,H=!0;-1===t?c=l:(t+=l.length,c=f.slice(0,t),f=f.slice(t+1));h.uncaught&&(c="Uncaught "+c);if(H=!1!==h.showDiff)H=A.call(r)===A.call(C);H&&void 0!==C&&(H=!1,x.isString(r)&&x.isString(C)||(h.actual=x.stringify(r),h.expected=x.stringify(C)),b=w("error title"," %s) %s:\n%s")+w("error stack","\n%s\n"),l=l.match(/^([^:]+): expected/),c="\n "+w("error message",l?l[1]:c),c=g.inlineDiffs?c+e(h,H):c+k(h,H));f=f.replace(/^/gm," ");console.log(b,d+1,a.fullTitle(),
c,f)})};b.prototype.epilogue=function(){var a=this.stats,d;console.log();d=w("bright pass"," ")+w("green"," %d passing")+w("light"," (%s)");console.log(d,a.passes||0,q(a.duration));a.pending&&(d=w("pending"," ")+w("pending"," %d pending"),console.log(d,a.pending));a.failures&&(d=w("fail"," %d failing"),console.log(d,a.failures),b.list(this.failures),console.log());console.log()};var A=Object.prototype.toString}).call(this,f("_process"),"undefined"!==typeof global?global:"undefined"!==typeof self?
self:"undefined"!==typeof window?window:{})},{"../ms":15,"../utils":39,_process:51,diff:67,"supports-color":41,tty:5}],18:[function(f,m,g){var c=f("./base"),l=f("../utils");m.exports=function(b){function e(){return Array(k).join(" ")}c.call(this,b);var k=2;b.on("suite",function(a){a.root||(++k,console.log('%s<section class="suite">',e()),++k,console.log("%s<h1>%s</h1>",e(),l.escape(a.title)),console.log("%s<dl>",e()))});b.on("suite end",function(a){a.root||(console.log("%s</dl>",e()),--k,console.log("%s</section>",
e()),--k)});b.on("pass",function(a){console.log("%s <dt>%s</dt>",e(),l.escape(a.title));a=l.escape(l.clean(a.body));console.log("%s <dd><pre><code>%s</code></pre></dd>",e(),a)});b.on("fail",function(a,b){console.log('%s <dt class="error">%s</dt>',e(),l.escape(a.title));var d=l.escape(l.clean(a.fn.body));console.log('%s <dd class="error"><pre><code>%s</code></pre></dd>',e(),d);console.log('%s <dd class="error">%s</dd>',e(),l.escape(b))})}},{"../utils":39,"./base":17}],19:[function(f,m,g){(function(c){function l(a){b.call(this,
a);var h=this,d=.75*b.window.width|0,e=-1;a.on("start",function(){c.stdout.write("\n")});a.on("pending",function(){0===++e%d&&c.stdout.write("\n ");c.stdout.write(k("pending",b.symbols.dot))});a.on("pass",function(a){0===++e%d&&c.stdout.write("\n ");"slow"===a.speed?c.stdout.write(k("bright yellow",b.symbols.dot)):c.stdout.write(k(a.speed,b.symbols.dot))});a.on("fail",function(){0===++e%d&&c.stdout.write("\n ");c.stdout.write(k("fail",b.symbols.dot))});a.on("end",function(){console.log();h.epilogue()})}
var b=f("./base"),e=f("../utils").inherits,k=b.color;m.exports=l;e(l,b)}).call(this,f("_process"))},{"../utils":39,"./base":17,_process:51}],20:[function(f,m,g){(function(c,l){function b(a){return 75<=a?"high":50<=a?"medium":25<=a?"low":"terrible"}var e=f("./json-cov"),k=f("fs").readFileSync,a=f("path").join;m.exports=function(h){var d=f("jade"),g=a(l,"/templates/coverage.jade"),r=k(g,"utf8"),m=d.compile(r,{filename:g}),x=this;e.call(this,h,!1);h.on("end",function(){c.stdout.write(m({cov:x.cov,coverageClass:b}))})}}).call(this,
f("_process"),"/lib/reporters")},{"./json-cov":23,_process:51,fs:41,jade:41,path:41}],21:[function(f,m,g){(function(c){function l(b){g.call(this,b);var c=this,l=this.stats,f=e(E),y=f.getElementsByTagName("li"),z=y[1].getElementsByTagName("em")[0],n=y[1].getElementsByTagName("a")[0],p=y[2].getElementsByTagName("em")[0],G=y[2].getElementsByTagName("a")[0],J=y[3].getElementsByTagName("em")[0],y=f.getElementsByTagName("canvas")[0],v=e('<ul id="mocha-report"></ul>'),m=[v],C,H,I=document.getElementById("mocha");
if(y.getContext){var L=window.devicePixelRatio||1;y.style.width=y.width;y.style.height=y.height;y.width*=L;y.height*=L;H=y.getContext("2d");H.scale(L,L);C=new q}I?(d(n,"click",function(){a();var d=/pass/.test(v.className)?"":" pass";v.className=v.className.replace(/fail|pass/g,"")+d;v.className.trim()&&k("test pass")}),d(G,"click",function(){a();var d=/fail/.test(v.className)?"":" fail";v.className=v.className.replace(/fail|pass/g,"")+d;v.className.trim()&&k("test fail")}),I.appendChild(f),I.appendChild(v),
C&&C.size(40),b.on("suite",function(a){if(!a.root){var d=c.suiteURL(a);a=e('<li class="suite"><h1><a href="%s">%s</a></h1></li>',d,u(a.title));m[0].appendChild(a);m.unshift(document.createElement("ul"));a.appendChild(m[0])}}),b.on("suite end",function(a){a.root||m.shift()}),b.on("fail",function(a){"hook"!==a.type&&"test"!==a.type||b.emit("test end",a)}),b.on("test end",function(a){var b=l.tests/this.total*100|0;C&&C.update(b).draw(H);b=new D-l.start;h(z,l.passes);h(p,l.failures);h(J,(b/1E3).toFixed(2));
if("passed"===a.state)b=c.testURL(a),b=e('<li class="test pass %e"><h2>%e<span class="duration">%ems</span> <a href="%s" class="replay">\u2023</a></h2></li>',a.speed,a.title,a.duration,b);else if(a.pending)b=e('<li class="test pass pending"><h2>%e</h2></li>',a.title);else{var b=e('<li class="test fail"><h2>%e <a href="%e" class="replay">\u2023</a></h2></li>',a.title,c.testURL(a)),n,k=a.err.toString();"[object Error]"===k&&(k=a.err.message);a.err.stack?(n=a.err.stack.indexOf(a.err.message),n=-1===
n?a.err.stack:a.err.stack.substr(a.err.message.length+n)):a.err.sourceURL&&void 0!==a.err.line&&(n="\n("+a.err.sourceURL+":"+a.err.line+")");n=n||"";a.err.htmlMessage&&n?b.appendChild(e('<div class="html-error">%s\n<pre class="error">%e</pre></div>',a.err.htmlMessage,n)):a.err.htmlMessage?b.appendChild(e('<div class="html-error">%s</div>',a.err.htmlMessage)):b.appendChild(e('<pre class="error">%e%e</pre>',k,n))}if(!a.pending){n=b.getElementsByTagName("h2")[0];d(n,"click",function(){I.style.display=
"none"===I.style.display?"block":"none"});var I=e("<pre><code>%e</code></pre>",r.clean(a.body));b.appendChild(I);I.style.display="none"}m[0]&&m[0].appendChild(b)})):document.body.appendChild(e('<div id="mocha-error">%s</div>',"#mocha div missing, add it to your document"))}function b(a){var d=window.location.search;d&&(d=d.replace(/[?&]grep=[^&\s]*/g,"").replace(/^&/,"?"));return window.location.pathname+(d?d+"&":"?")+"grep="+encodeURIComponent(x(a))}function e(a){var d=arguments,b=document.createElement("div"),
c=1;b.innerHTML=a.replace(/%([se])/g,function(a,b){switch(b){case "s":return String(d[c++]);case "e":return u(d[c++])}});return b.firstChild}function k(a){for(var d=document.getElementsByClassName("suite"),b=0;b<d.length;b++)d[b].getElementsByClassName(a).length||(d[b].className+=" hidden")}function a(){for(var a=document.getElementsByClassName("suite hidden"),d=0;d<a.length;++d)a[d].className=a[d].className.replace("suite hidden","suite")}function h(a,d){a.textContent?a.textContent=d:a.innerText=
d}function d(a,d,b){a.addEventListener?a.addEventListener(d,b,!1):a.attachEvent("on"+d,b)}var g=f("./base"),r=f("../utils"),q=f("../browser/progress"),x=f("escape-string-regexp"),u=r.escape,D=c.Date;m.exports=l;var E='<ul id="mocha-stats"><li class="progress"><canvas width="40" height="40"></canvas></li><li class="passes"><a href="javascript:void(0);">passes:</a> <em>0</em></li><li class="failures"><a href="javascript:void(0);">failures:</a> <em>0</em></li><li class="duration">duration: <em>0</em>s</li></ul>';
l.prototype.suiteURL=function(a){return b(a.fullTitle())};l.prototype.testURL=function(a){return b(a.fullTitle())}}).call(this,"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{})},{"../browser/progress":4,"../utils":39,"./base":17,"escape-string-regexp":68}],22:[function(f,m,g){g.Base=g.base=f("./base");g.Dot=g.dot=f("./dot");g.Doc=g.doc=f("./doc");g.TAP=g.tap=f("./tap");g.JSON=g.json=f("./json");g.HTML=g.html=f("./html");g.List=g.list=f("./list");
g.Min=g.min=f("./min");g.Spec=g.spec=f("./spec");g.Nyan=g.nyan=f("./nyan");g.XUnit=g.xunit=f("./xunit");g.Markdown=g.markdown=f("./markdown");g.Progress=g.progress=f("./progress");g.Landing=g.landing=f("./landing");g.JSONCov=g["json-cov"]=f("./json-cov");g.HTMLCov=g["html-cov"]=f("./html-cov");g.JSONStream=g["json-stream"]=f("./json-stream")},{"./base":17,"./doc":18,"./dot":19,"./html":21,"./html-cov":20,"./json":25,"./json-cov":23,"./json-stream":24,"./landing":26,"./list":27,"./markdown":28,"./min":29,
"./nyan":30,"./progress":31,"./spec":32,"./tap":33,"./xunit":34}],23:[function(f,m,g){(function(c,l){function b(a){var d={instrumentation:"node-jscoverage",sloc:0,hits:0,misses:0,coverage:0,files:[]},b;for(b in a)if(Object.prototype.hasOwnProperty.call(a,b)){var c=e(b,a[b]);d.files.push(c);d.hits+=c.hits;d.misses+=c.misses;d.sloc+=c.sloc}d.files.sort(function(a,d){return a.filename.localeCompare(d.filename)});0<d.sloc&&(d.coverage=d.hits/d.sloc*100);return d}function e(a,d){var b={filename:a,coverage:0,
hits:0,misses:0,sloc:0,source:{}};d.source.forEach(function(a,c){c++;0===d[c]?(b.misses++,b.sloc++):void 0!==d[c]&&(b.hits++,b.sloc++);b.source[c]={source:a,coverage:void 0===d[c]?"":d[c]}});b.coverage=b.hits/b.sloc*100;return b}function k(a){return{duration:a.duration,currentRetry:a.currentRetry(),fullTitle:a.fullTitle(),title:a.title}}var a=f("./base");m.exports=function(h,d){a.call(this,h);d=1===arguments.length||d;var e=this,f=[],g=[],m=[];h.on("test end",function(a){f.push(a)});h.on("pass",function(a){m.push(a)});
h.on("fail",function(a){g.push(a)});h.on("end",function(){var a=e.cov=b(l._$jscoverage||{});a.stats=e.stats;a.tests=f.map(k);a.failures=g.map(k);a.passes=m.map(k);d&&c.stdout.write(JSON.stringify(a,null,2))})}}).call(this,f("_process"),"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{})},{"./base":17,_process:51}],24:[function(f,m,g){(function(c){function l(b){return{title:b.title,fullTitle:b.fullTitle(),duration:b.duration,currentRetry:b.currentRetry()}}
var b=f("./base");m.exports=function(e){b.call(this,e);var k=this,a=e.total;e.on("start",function(){console.log(JSON.stringify(["start",{total:a}]))});e.on("pass",function(a){console.log(JSON.stringify(["pass",l(a)]))});e.on("fail",function(a,d){a=l(a);a.err=d.message;a.stack=d.stack||null;console.log(JSON.stringify(["fail",a]))});e.on("end",function(){c.stdout.write(JSON.stringify(["end",k.stats]))})}}).call(this,f("_process"))},{"./base":17,_process:51}],25:[function(f,m,g){(function(c){function l(c){return{title:c.title,
fullTitle:c.fullTitle(),duration:c.duration,currentRetry:c.currentRetry(),err:b(c.err||{})}}function b(b){var a={};Object.getOwnPropertyNames(b).forEach(function(c){a[c]=b[c]},b);return a}var e=f("./base");m.exports=function(b){e.call(this,b);var a=this,h=[],d=[],f=[],g=[];b.on("test end",function(a){h.push(a)});b.on("pass",function(a){g.push(a)});b.on("fail",function(a){f.push(a)});b.on("pending",function(a){d.push(a)});b.on("end",function(){var e={stats:a.stats,tests:h.map(l),pending:d.map(l),failures:f.map(l),
passes:g.map(l)};b.testResults=e;c.stdout.write(JSON.stringify(e,null,2))})}}).call(this,f("_process"))},{"./base":17,_process:51}],26:[function(f,m,g){(function(c){function l(h){function d(){var b=Array(l).join("-");return" "+a("runway",b)}b.call(this,h);var e=this,l=.75*b.window.width|0,f=h.total,g=c.stdout,m=a("plane","\u2708"),D=-1,E=0;h.on("start",function(){g.write("\n\n\n ");k.hide()});h.on("test end",function(b){var c=-1===D?l*++E/f|0:D;"failed"===b.state&&(m=a("plane crash","\u2708"),D=
c);g.write("\u001b["+(l+1)+"D\u001b[2A");g.write(d());g.write("\n ");g.write(a("runway",Array(c).join("\u22c5")));g.write(m);g.write(a("runway",Array(l-c).join("\u22c5")+"\n"));g.write(d());g.write("\u001b[0m")});h.on("end",function(){k.show();console.log();e.epilogue()})}var b=f("./base"),e=f("../utils").inherits,k=b.cursor,a=b.color;m.exports=l;b.colors.plane=0;b.colors["plane crash"]=31;b.colors.runway=90;e(l,b)}).call(this,f("_process"))},{"../utils":39,"./base":17,_process:51}],27:[function(f,
m,g){(function(c){function l(h){b.call(this,h);var d=0;h.on("start",function(){console.log()});h.on("test",function(a){c.stdout.write(k("pass"," "+a.fullTitle()+": "))});h.on("pending",function(a){var b=k("checkmark"," -")+k("pending"," %s");console.log(b,a.fullTitle())});h.on("pass",function(d){var c=k("checkmark"," "+b.symbols.dot)+k("pass"," %s: ")+k(d.speed,"%dms");a.CR();console.log(c,d.fullTitle(),d.duration)});h.on("fail",function(b){a.CR();console.log(k("fail"," %d) %s"),++d,b.fullTitle())});
h.on("end",this.epilogue.bind(this))}var b=f("./base"),e=f("../utils").inherits,k=b.color,a=b.cursor;m.exports=l;e(l,b)}).call(this,f("_process"))},{"../utils":39,"./base":17,_process:51}],28:[function(f,m,g){(function(c){var l=f("./base"),b=f("../utils");m.exports=function(e){function k(a,b){var d=b,c="$"+a.title;b=b[c]=b[c]||{suite:a};a.suites.forEach(function(a){k(a,b)});return d}function a(d,c){++c;var h="",e,k;for(k in d)"suite"!==k&&("$"!==k&&(e=" - ["+k.substring(1)+"]",e+="(#"+b.slug(d[k].suite.fullTitle())+
")\n",h+=Array(c).join(" ")+e),h+=a(d[k],c));return h}function h(b){b=k(b,{});return a(b,0)}l.call(this,e);var d=0,f="";h(e.suite);e.on("suite",function(a){++d;var c=b.slug(a.fullTitle()),c=f+='<a name="'+c+'"></a>\n';a=a.title;a=Array(d).join("#")+" "+a;f=c+(a+"\n")});e.on("suite end",function(){--d});e.on("pass",function(a){var d=b.clean(a.body);f+=a.title+".\n";f+="\n```js\n";f+=d+"\n";f+="```\n\n"});e.on("end",function(){c.stdout.write("# TOC\n");c.stdout.write(h(e.suite));c.stdout.write(f)})}}).call(this,
f("_process"))},{"../utils":39,"./base":17,_process:51}],29:[function(f,m,g){(function(c){function l(e){b.call(this,e);e.on("start",function(){c.stdout.write("\u001b[2J");c.stdout.write("\u001b[1;3H")});e.on("end",this.epilogue.bind(this))}var b=f("./base"),e=f("../utils").inherits;m.exports=l;e(l,b)}).call(this,f("_process"))},{"../utils":39,"./base":17,_process:51}],30:[function(f,m,g){(function(c){function l(a){e.call(this,a);var c=this,d=.75*e.window.width|0,k=this.nyanCatWidth=11;this.colorIndex=
0;this.numberOfLines=4;this.rainbowColors=c.generateColors();this.scoreboardWidth=5;this.tick=0;this.trajectories=[[],[],[],[]];this.trajectoryWidthMax=d-k;a.on("start",function(){e.cursor.hide();c.draw()});a.on("pending",function(){c.draw()});a.on("pass",function(){c.draw()});a.on("fail",function(){c.draw()});a.on("end",function(){e.cursor.show();for(var a=0;a<c.numberOfLines;a++)b("\n");c.epilogue()})}function b(a){c.stdout.write(a)}var e=f("./base"),k=f("../utils").inherits;m.exports=l;k(l,e);
l.prototype.draw=function(){this.appendRainbow();this.drawScoreboard();this.drawRainbow();this.drawNyanCat();this.tick=!this.tick};l.prototype.drawScoreboard=function(){function a(a,c){b(" ");b(e.color(a,c));b("\n")}var c=this.stats;a("green",c.passes);a("fail",c.failures);a("pending",c.pending);b("\n");this.cursorUp(this.numberOfLines)};l.prototype.appendRainbow=function(){for(var a=this.rainbowify(this.tick?"_":"-"),b=0;b<this.numberOfLines;b++){var d=this.trajectories[b];d.length>=this.trajectoryWidthMax&&
d.shift();d.push(a)}};l.prototype.drawRainbow=function(){var a=this;this.trajectories.forEach(function(c){b("\u001b["+a.scoreboardWidth+"C");b(c.join(""));b("\n")});this.cursorUp(this.numberOfLines)};l.prototype.drawNyanCat=function(){var a="\u001b["+(this.scoreboardWidth+this.trajectories[0].length)+"C",c="";b(a);b("_,------,");b("\n");b(a);c=this.tick?" ":" ";b("_|"+c+"/\\_/\\ ");b("\n");b(a);c=this.tick?"_":"__";b((this.tick?"~":"^")+"|"+c+this.face()+" ");b("\n");b(a);c=this.tick?" ":" ";
b(c+'"" "" ');b("\n");this.cursorUp(this.numberOfLines)};l.prototype.face=function(){var a=this.stats;return a.failures?"( x .x)":a.pending?"( o .o)":a.passes?"( ^ .^)":"( - .-)"};l.prototype.cursorUp=function(a){b("\u001b["+a+"A")};l.prototype.cursorDown=function(a){b("\u001b["+a+"B")};l.prototype.generateColors=function(){for(var a=[],b=0;42>b;b++){var d=Math.floor(Math.PI/3),c=1/6*b;a.push(36*Math.floor(3*Math.sin(c)+3)+6*Math.floor(3*Math.sin(c+2*d)+3)+Math.floor(3*Math.sin(c+4*d)+3)+16)}return a};
l.prototype.rainbowify=function(a){if(!e.useColors)return a;var b=this.rainbowColors[this.colorIndex%this.rainbowColors.length];this.colorIndex+=1;return"\u001b[38;5;"+b+"m"+a+"\u001b[0m"}}).call(this,f("_process"))},{"../utils":39,"./base":17,_process:51}],31:[function(f,m,g){(function(c){function l(e,d){b.call(this,e);var f=this,l=.5*b.window.width|0,g=e.total,m=0,u=-1;d=d||{};d.open=d.open||"[";d.complete=d.complete||"\u25ac";d.incomplete=d.incomplete||b.symbols.dot;d.close=d.close||"]";d.verbose=
!1;e.on("start",function(){console.log();a.hide()});e.on("test end",function(){m++;var b=m/g*l|0,e=l-b;if(b!==u||d.verbose)u=b,a.CR(),c.stdout.write("\u001b[J"),c.stdout.write(k("progress"," "+d.open)),c.stdout.write(Array(b).join(d.complete)),c.stdout.write(Array(e).join(d.incomplete)),c.stdout.write(k("progress",d.close)),d.verbose&&c.stdout.write(k("progress"," "+m+" of "+g))});e.on("end",function(){a.show();console.log();f.epilogue()})}var b=f("./base"),e=f("../utils").inherits,k=b.color,a=b.cursor;
m.exports=l;b.colors.progress=90;e(l,b)}).call(this,f("_process"))},{"../utils":39,"./base":17,_process:51}],32:[function(f,m,g){function c(c){function a(){return Array(h).join(" ")}l.call(this,c);var h=0,d=0;c.on("start",function(){console.log()});c.on("suite",function(d){++h;console.log(b("suite","%s%s"),a(),d.title)});c.on("suite end",function(){--h;1===h&&console.log()});c.on("pending",function(d){var c=a()+b("pending"," - %s");console.log(c,d.title)});c.on("pass",function(d){var c;"fast"===
d.speed?(c=a()+b("checkmark"," "+l.symbols.ok)+b("pass"," %s"),e.CR(),console.log(c,d.title)):(c=a()+b("checkmark"," "+l.symbols.ok)+b("pass"," %s")+b(d.speed," (%dms)"),e.CR(),console.log(c,d.title,d.duration))});c.on("fail",function(c){e.CR();console.log(a()+b("fail"," %d) %s"),++d,c.title)});c.on("end",this.epilogue.bind(this))}var l=f("./base");f=f("../utils").inherits;var b=l.color,e=l.cursor;m.exports=c;f(c,l)},{"../utils":39,"./base":17}],33:[function(f,m,g){var c=f("./base");m.exports=
function(f){c.call(this,f);var b=1,e=0,k=0;f.on("start",function(){var a=f.grepTotal(f.suite);console.log("%d..%d",1,a)});f.on("test end",function(){++b});f.on("pending",function(a){console.log("ok %d %s # SKIP -",b,a.fullTitle().replace(/#/g,""))});f.on("pass",function(a){e++;console.log("ok %d %s",b,a.fullTitle().replace(/#/g,""))});f.on("fail",function(a,c){k++;console.log("not ok %d %s",b,a.fullTitle().replace(/#/g,""));c.stack&&console.log(c.stack.replace(/^/gm," "))});f.on("end",function(){console.log("# tests "+
(e+k));console.log("# pass "+e);console.log("# fail "+k)})}},{"./base":17}],34:[function(f,m,g){(function(c,l){function b(b,d){a.call(this,b);var c=this.stats,h=[],k=this;if(d.reporterOptions&&d.reporterOptions.output){if(!g.createWriteStream)throw Error("file output not supported in browser");q.sync(x.dirname(d.reporterOptions.output));k.fileStream=g.createWriteStream(d.reporterOptions.output)}b.on("pending",function(a){h.push(a)});b.on("pass",function(a){h.push(a)});b.on("fail",function(a){h.push(a)});
b.on("end",function(){k.write(e("testsuite",{name:"Mocha Tests",tests:c.tests,failures:c.failures,errors:c.failures,skipped:c.tests-c.failures-c.passes,timestamp:(new u).toUTCString(),time:c.duration/1E3||0},!1));h.forEach(function(a){k.test(a)});k.write("</testsuite>")})}function e(a,b,d,c){d=d?"/>":">";var e=[],h;for(h in b)Object.prototype.hasOwnProperty.call(b,h)&&e.push(h+'="'+r(b[h])+'"');b="<"+a+(e.length?" "+e.join(" "):"")+d;c&&(b+=c+"</"+a+d);return b}function k(a){return"<![CDATA["+r(a)+
"]]\x3e"}var a=f("./base"),h=f("../utils"),d=h.inherits,g=f("fs"),r=h.escape,q=f("mkdirp"),x=f("path"),u=l.Date;m.exports=b;d(b,a);b.prototype.done=function(a,b){this.fileStream?this.fileStream.end(function(){b(a)}):b(a)};b.prototype.write=function(a){this.fileStream?this.fileStream.write(a+"\n"):"object"===typeof c&&c.stdout?c.stdout.write(a+"\n"):console.log(a)};b.prototype.test=function(a){var b={classname:a.parent.fullTitle(),name:a.title,time:a.duration/1E3||0};"failed"===a.state?(a=a.err,this.write(e("testcase",
b,!1,e("failure",{},!1,k(r(a.message)+"\n"+a.stack))))):a.pending?this.write(e("testcase",b,!1,e("skipped",{},!0))):this.write(e("testcase",b,!0))}}).call(this,f("_process"),"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{})},{"../utils":39,"./base":17,_process:51,fs:41,mkdirp:70,path:41}],35:[function(f,m,g){(function(c){function l(a,b){this.title=a;this.async=(this.fn=b)&&b.length;this.sync=!this.async;this._timeout=2E3;this._slow=75;this._enableTimeouts=
!0;this.timedOut=!1;this._trace=Error("done() called multiple times");this._retries=-1;this._currentRetry=0}var b=f("events").EventEmitter,e=f("./pending"),k=f("debug")("mocha:runnable"),a=f("./ms"),h=f("./utils"),d=h.inherits,g=c.Date,r=c.setTimeout,q=c.clearTimeout,x=Object.prototype.toString;m.exports=l;d(l,b);l.prototype.timeout=function(b){if(!arguments.length)return this._timeout;0===b&&(this._enableTimeouts=!1);"string"===typeof b&&(b=a(b));k("timeout %d",b);this._timeout=b;this.timer&&this.resetTimeout();
return this};l.prototype.slow=function(b){if(!arguments.length)return this._slow;"string"===typeof b&&(b=a(b));k("timeout %d",b);this._slow=b;return this};l.prototype.enableTimeouts=function(a){if(!arguments.length)return this._enableTimeouts;k("enableTimeouts %s",a);this._enableTimeouts=a;return this};l.prototype.skip=function(){throw new e;};l.prototype.retries=function(a){if(!arguments.length)return this._retries;this._retries=a};l.prototype.currentRetry=function(a){if(!arguments.length)return this._currentRetry;
this._currentRetry=a};l.prototype.fullTitle=function(){return this.parent.fullTitle()+" "+this.title};l.prototype.clearTimeout=function(){q(this.timer)};l.prototype.inspect=function(){return JSON.stringify(this,function(a,b){if("_"!==a[0])return"parent"===a?"#<Suite>":"ctx"===a?"#<Context>":b},2)};l.prototype.resetTimeout=function(){var a=this,b=this.timeout()||1E9;this._enableTimeouts&&(this.clearTimeout(),this.timer=r(function(){a._enableTimeouts&&(a.callback(Error("timeout of "+b+"ms exceeded. Ensure the done() callback is being called in this test.")),
a.timedOut=!0)},b))};l.prototype.globals=function(a){if(!arguments.length)return this._allowedGlobals;this._allowedGlobals=a};l.prototype.run=function(a){function b(d){var c=e.timeout();e.timedOut||(l?(d=d||e._trace,z||(z=!0,e.emit("error",d||Error("done() called multiple times; stacktrace may be inaccurate")))):(e.clearTimeout(),e.duration=new g-k,l=!0,!d&&e.duration>c&&e._enableTimeouts&&(d=Error("timeout of "+c+"ms exceeded. Ensure the done() callback is being called in this test.")),a(d)))}function d(a){if((a=
a.call(f))&&"function"===typeof a.then)e.resetTimeout(),a.then(function(){b();return null},function(a){b(a||Error("Promise rejected with no or falsy reason"))});else{if(e.asyncOnly)return b(Error("--async-only option in use without declaring `done()` or returning a promise"));b()}}function c(a){a.call(f,function(a){if(a instanceof Error||"[object Error]"===x.call(a))return b(a);if(a)return"[object Object]"===Object.prototype.toString.call(a)?b(Error("done() invoked with non-Error: "+JSON.stringify(a))):
b(Error("done() invoked with non-Error: "+a));b()})}var e=this,k=new g,f=this.ctx,l,z;f&&f.runnable&&f.runnable(this);this.callback=b;if(this.async){this.resetTimeout();if(this.allowUncaught)return c(this.fn);try{c(this.fn)}catch(n){b(h.getError(n))}}else if(this.allowUncaught)d(this.fn),b();else try{this.pending?b():d(this.fn)}catch(n){b(h.getError(n))}}}).call(this,"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{})},{"./ms":15,"./pending":16,
"./utils":39,debug:2,events:3}],36:[function(f,m,g){(function(c,l){function b(b,d){var c=this;this._globals=[];this._abort=!1;this._delay=d;this.suite=b;this.started=!1;this.total=b.total();this.failures=0;this.on("test end",function(a){c.checkGlobals(a)});this.on("hook end",function(a){c.checkGlobals(a)});this._defaultGrep=/.*/;this.grep(this._defaultGrep);this.globals(this.globalProps().concat(a()))}function e(a){function b(a){for(var d=0;d<a.length;d++)delete a[d].fn}y(a._beforeAll)&&b(a._beforeAll);
y(a._beforeEach)&&b(a._beforeEach);y(a._afterAll)&&b(a._afterAll);y(a._afterEach)&&b(a._afterEach);for(var d=0;d<a.tests.length;d++)delete a.tests[d].fn}function k(a,b){return u(b,function(b){return/^d+/.test(b)||l.navigator&&/^getInterface/.test(b)||l.navigator&&/^\d+/.test(b)||/^mocha-/.test(b)?!1:!u(a,function(a){return~a.indexOf("*")?0===b.indexOf(a.split("*")[0]):b===a}).length&&(!l.navigator||"onerror"!==b)})}function a(){if("object"===typeof c&&"string"===typeof c.version){var a=c.version.split(".");
if(2315>g.reduce(a,function(a,b){return a<<8|b}))return["errno"]}return[]}var h=f("events").EventEmitter,d=f("./pending"),g=f("./utils"),r=g.inherits,q=f("debug")("mocha:runner"),x=f("./runnable"),u=g.filter,D=g.indexOf,E=g.keys,w=g.stackTraceFilter(),A=g.stringify,F=g.type,B=g.undefinedError,y=g.isArray,z="setTimeout clearTimeout setInterval clearInterval XMLHttpRequest Date setImmediate clearImmediate".split(" ");m.exports=b;b.immediately=l.setImmediate||c.nextTick;r(b,h);b.prototype.grep=function(a,
b){q("grep %s",a);this._grep=a;this._invert=b;this.total=this.grepTotal(this.suite);return this};b.prototype.grepTotal=function(a){var b=this,d=0;a.eachTest(function(a){a=b._grep.test(a.fullTitle());b._invert&&(a=!a);a&&d++});return d};b.prototype.globalProps=function(){for(var a=E(l),b=0;b<z.length;++b)~D(a,z[b])||a.push(z[b]);return a};b.prototype.globals=function(a){if(!arguments.length)return this._globals;q("globals %j",a);this._globals=this._globals.concat(a);return this};b.prototype.checkGlobals=
function(a){if(!this.ignoreLeaks){var b=this._globals,d=this.globalProps();a&&(b=b.concat(a._allowedGlobals||[]));this.prevGlobalsLength!==d.length&&(this.prevGlobalsLength=d.length,b=k(b,d),this._globals=this._globals.concat(b),1<b.length?this.fail(a,Error("global leaks detected: "+b.join(", ")+"")):b.length&&this.fail(a,Error("global leak detected: "+b[0])))}};b.prototype.fail=function(a,b){++this.failures;a.state="failed";b instanceof Error||b&&"string"===typeof b.message||(b=Error("the "+F(b)+
" "+A(b)+" was thrown, throw an Error :)"));b.stack=this.fullStackTrace||!b.stack?b.stack:w(b.stack);this.emit("fail",a,b)};b.prototype.failHook=function(a,b){a.ctx&&a.ctx.currentTest&&(a.originalTitle=a.originalTitle||a.title,a.title=a.originalTitle+' for "'+a.ctx.currentTest.title+'"');this.fail(a,b);this.suite.bail()&&this.emit("end")};b.prototype.hook=function(a,c){function e(a){var b=k[a];if(!b)return c();f.currentRunnable=b;b.ctx.currentTest=f.test;f.emit("hook",b);if(!b.listeners("error").length)b.on("error",
function(a){f.failHook(b,a)});b.run(function(I){var k=b.error();k&&f.fail(f.test,k);if(I)if(I instanceof d)h.pending=!0;else return f.failHook(b,I),c(I);f.emit("hook end",b);delete b.ctx.currentTest;e(++a)})}var h=this.suite,k=h["_"+a],f=this;b.immediately(function(){e(0)})};b.prototype.hooks=function(a,b,d){function c(C){e.suite=C;if(!C)return e.suite=h,d();e.hook(a,function(a){if(a){var C=e.suite;e.suite=h;return d(a,C)}c(b.pop())})}var e=this,h=this.suite;c(b.pop())};b.prototype.hookUp=function(a,
b){var d=[this.suite].concat(this.parents()).reverse();this.hooks(a,d,b)};b.prototype.hookDown=function(a,b){var d=[this.suite].concat(this.parents());this.hooks(a,d,b)};b.prototype.parents=function(){for(var a=this.suite,b=[];a.parent;)a=a.parent,b.push(a);return b};b.prototype.runTest=function(a){var b=this,d=this.test;this.asyncOnly&&(d.asyncOnly=!0);if(this.allowUncaught)return d.allowUncaught=!0,d.run(a);try{d.on("error",function(a){b.fail(d,a)}),d.run(a)}catch(c){a(c)}};b.prototype.runTests=
function(a,c){function e(a,b,d){var C=k.suite;k.suite=d?b.parent:b;k.suite?k.hookUp("afterEach",function(a,d){k.suite=C;if(a)return e(a,d,!0);c(b)}):(k.suite=C,c(b))}function h(H,I){function l(a){return a.pending||a.parent&&l(a.parent)}if(k.failures&&a._bail||k._abort)return c();if(H)return e(H,I,!0);C=f.shift();if(!C)return c();var g=k._grep.test(C.fullTitle());k._invert&&(g=!g);if(g){if(C.pending||l(C.parent))return k.emit("pending",C),k.emit("test end",C),h();k.emit("test",k.test=C);k.hookDown("beforeEach",
function(b,c){if(a.pending)return k.emit("pending",C),k.emit("test end",C),h();if(b)return e(b,c,!1);k.currentRunnable=k.test;k.runTest(function(a){C=k.test;if(a){var b=C.currentRetry();if(a instanceof d)C.pending=!0,k.emit("pending",C);else{if(b<C.retries())return a=C.clone(),a.currentRetry(b+1),f.unshift(a),k.hookUp("afterEach",h);k.fail(C,a)}k.emit("test end",C);return a instanceof d?h():k.hookUp("afterEach",h)}C.state="passed";k.emit("pass",C);k.emit("test end",C);k.hookUp("afterEach",h)})})}else k._grep!==
k._defaultGrep?b.immediately(h):h()}var k=this,f=a.tests.slice(),C;this.next=h;this.hookErr=e;h()};b.prototype.runSuite=function(a,d){function c(d){if(d)return d===a?e():e(d);if(k._abort)return e();var C=a.suites[h++];if(!C)return e();k._grep!==k._defaultGrep?b.immediately(function(){k.runSuite(C,c)}):k.runSuite(C,c)}function e(b){k.suite=a;k.nextSuite=c;H?d(b):(H=!0,delete k.test,k.hook("afterAll",function(){k.emit("suite end",a);d(b)}))}var h=0,k=this,C=this.grepTotal(a),H=!1;q("run suite %s",a.fullTitle());
if(!C||k.failures&&a._bail)return d();this.emit("suite",this.suite=a);this.nextSuite=c;this.hook("beforeAll",function(b){if(b)return e();k.runTests(a,c)})};b.prototype.uncaught=function(a){a?q("uncaught exception %s",a!==function(){return this}.call(a)?a:a.message||a):(q("uncaught undefined exception"),a=B());a.uncaught=!0;var b=this.currentRunnable;if(b){if(b.clearTimeout(),!b.state)if(this.fail(b,a),"test"===b.type)this.emit("test end",b),this.hookUp("afterEach",this.next);else{if("hook"===b.type){var d=
this.suite;return-1<b.fullTitle().indexOf("after each")?this.hookErr(a,d,!0):-1<b.fullTitle().indexOf("before each")?this.hookErr(a,d,!1):this.nextSuite(d)}this.emit("end")}}else b=new x("Uncaught error outside test suite"),b.parent=this.suite,this.started?this.fail(b,a):(this.emit("start"),this.fail(b,a),this.emit("end"))};b.prototype.run=function(a){function b(a){h.uncaught(a)}function d(){h.started=!0;h.emit("start");h.runSuite(k,function(){q("finished running");h.emit("end")})}var h=this,k=this.suite;
a=a||function(){};q("start");this.on("suite end",e);this.on("end",function(){q("end");c.removeListener("uncaughtException",b);a(h.failures)});c.on("uncaughtException",b);this._delay?(this.emit("waiting",k),k.once("run",d)):d();return this};b.prototype.abort=function(){q("aborting");this._abort=!0;return this}}).call(this,f("_process"),"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{})},{"./pending":16,"./runnable":35,"./utils":39,_process:51,debug:2,
events:3}],37:[function(f,m,g){function c(a,b){function c(){}this.title=a;c.prototype=b;this.ctx=new c;this.suites=[];this.tests=[];this.pending=!1;this._beforeEach=[];this._beforeAll=[];this._afterEach=[];this._afterAll=[];this.root=!a;this._timeout=2E3;this._enableTimeouts=!0;this._slow=75;this._bail=!1;this._retries=-1;this.delayed=!1}var l=f("events").EventEmitter,b=f("./hook"),e=f("./utils"),k=e.inherits,a=f("debug")("mocha:suite"),h=f("./ms");g=m.exports=c;g.create=function(a,b){var e=new c(b,
a.ctx);e.parent=a;a.pending&&(e.pending=!0);e.fullTitle();a.addSuite(e);return e};k(c,l);c.prototype.clone=function(){var b=new c(this.title);a("clone");b.ctx=this.ctx;b.timeout(this.timeout());b.retries(this.retries());b.enableTimeouts(this.enableTimeouts());b.slow(this.slow());b.bail(this.bail());return b};c.prototype.timeout=function(b){if(!arguments.length)return this._timeout;"0"===b.toString()&&(this._enableTimeouts=!1);"string"===typeof b&&(b=h(b));a("timeout %d",b);this._timeout=parseInt(b,
10);return this};c.prototype.retries=function(b){if(!arguments.length)return this._retries;a("retries %d",b);this._retries=parseInt(b,10)||0;return this};c.prototype.enableTimeouts=function(b){if(!arguments.length)return this._enableTimeouts;a("enableTimeouts %s",b);this._enableTimeouts=b;return this};c.prototype.slow=function(b){if(!arguments.length)return this._slow;"string"===typeof b&&(b=h(b));a("slow %d",b);this._slow=b;return this};c.prototype.bail=function(b){if(!arguments.length)return this._bail;
a("bail %s",b);this._bail=b;return this};c.prototype.beforeAll=function(a,c){if(this.pending)return this;"function"===typeof a&&(c=a,a=c.name);var e=new b('"before all" hook'+(a?": "+a:""),c);e.parent=this;e.timeout(this.timeout());e.retries(this.retries());e.enableTimeouts(this.enableTimeouts());e.slow(this.slow());e.ctx=this.ctx;this._beforeAll.push(e);this.emit("beforeAll",e);return this};c.prototype.afterAll=function(a,c){if(this.pending)return this;"function"===typeof a&&(c=a,a=c.name);var e=
new b('"after all" hook'+(a?": "+a:""),c);e.parent=this;e.timeout(this.timeout());e.retries(this.retries());e.enableTimeouts(this.enableTimeouts());e.slow(this.slow());e.ctx=this.ctx;this._afterAll.push(e);this.emit("afterAll",e);return this};c.prototype.beforeEach=function(a,c){if(this.pending)return this;"function"===typeof a&&(c=a,a=c.name);var e=new b('"before each" hook'+(a?": "+a:""),c);e.parent=this;e.timeout(this.timeout());e.retries(this.retries());e.enableTimeouts(this.enableTimeouts());
e.slow(this.slow());e.ctx=this.ctx;this._beforeEach.push(e);this.emit("beforeEach",e);return this};c.prototype.afterEach=function(a,c){if(this.pending)return this;"function"===typeof a&&(c=a,a=c.name);var e=new b('"after each" hook'+(a?": "+a:""),c);e.parent=this;e.timeout(this.timeout());e.retries(this.retries());e.enableTimeouts(this.enableTimeouts());e.slow(this.slow());e.ctx=this.ctx;this._afterEach.push(e);this.emit("afterEach",e);return this};c.prototype.addSuite=function(a){a.parent=this;a.timeout(this.timeout());
a.retries(this.retries());a.enableTimeouts(this.enableTimeouts());a.slow(this.slow());a.bail(this.bail());this.suites.push(a);this.emit("suite",a);return this};c.prototype.addTest=function(a){a.parent=this;a.timeout(this.timeout());a.retries(this.retries());a.enableTimeouts(this.enableTimeouts());a.slow(this.slow());a.ctx=this.ctx;this.tests.push(a);this.emit("test",a);return this};c.prototype.fullTitle=function(){if(this.parent){var a=this.parent.fullTitle();if(a)return a+" "+this.title}return this.title};
c.prototype.total=function(){return e.reduce(this.suites,function(a,b){return a+b.total()},0)+this.tests.length};c.prototype.eachTest=function(a){e.forEach(this.tests,a);e.forEach(this.suites,function(b){b.eachTest(a)});return this};c.prototype.run=function(){this.root&&this.emit("run")}},{"./hook":7,"./ms":15,"./utils":39,debug:2,events:3}],38:[function(f,m,g){function c(b,c){l.call(this,b,c);this.pending=!c;this.type="test";this.body=(c||"").toString()}var l=f("./runnable");f=f("./utils").inherits;
m.exports=c;f(c,l);c.prototype.clone=function(){var b=new c(this.title,this.fn);b.timeout(this.timeout());b.slow(this.slow());b.enableTimeouts(this.enableTimeouts());b.retries(this.retries());b.currentRetry(this.currentRetry());b.globals(this.globals());b.parent=this.parent;b.file=this.file;b.ctx=this.ctx;return b}},{"./runnable":35,"./utils":39}],39:[function(f,m,g){(function(c,l){function b(a){return!~D.indexOf(a)}function e(a,b){b=b||g.type(a);switch(b){case "function":return"[Function]";case "object":return"{}";
case "array":return"[]";default:return a.toString()}}function k(a,b,c){function d(a,b){return Array(b).join(a)}function e(a){switch(g.type(a)){case "null":case "undefined":a="["+a+"]";break;case "array":case "object":a=k(a,b,c+1);break;case "boolean":case "regexp":case "number":a=0===a&&-Infinity===1/a?"-0":a.toString();break;case "date":a="[Date: "+(isNaN(a.getTime())?a.toString():a.toISOString())+"]";break;case "buffer":a=a.toJSON();a=a.data&&a.type?a.data:a;a="[Buffer: "+k(a,2,c+1)+"]";break;default:a=
"[Function]"===a||"[Circular]"===a?a:JSON.stringify(a)}return a}if("undefined"===typeof b)return e(a);c=c||1;var h=b*c,f=E(a)?"[":"{",l=E(a)?"]":"}",G=a.length||g.keys(a).length,t;for(t in a)a.hasOwnProperty(t)&&(--G,f+="\n "+d(" ",h)+(E(a)?"":'"'+t+'": ')+e(a[t])+(G?",":""));return f+(1!==f.length?"\n"+d(" ",--h)+l:l)}var a=f("path").basename,h=f("debug")("mocha:watch"),d=f("fs").existsSync||f("path").existsSync,t=f("glob"),m=f("path").join,q=f("fs").readdirSync,x=f("fs").statSync,u=f("fs").watchFile,
D=["node_modules",".git"];g.inherits=f("util").inherits;g.escape=function(a){return String(a).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")};g.forEach=function(a,b,c){for(var d=0,e=a.length;d<e;d++)b.call(c,a[d],d)};g.isString=function(a){return"string"===typeof a};g.map=function(a,b,c){for(var d=[],e=0,h=a.length;e<h;e++)d.push(b.call(c,a[e],e,a));return d};g.indexOf=function(a,b,c){c=c||0;for(var d=a.length;c<d;c++)if(a[c]===b)return c;return-1};g.reduce=
function(a,b,c){for(var d=0,e=a.length;d<e;d++)c=b(c,a[d],d,a);return c};g.filter=function(a,b){for(var c=[],d=0,e=a.length;d<e;d++){var h=a[d];b(h,d,a)&&c.push(h)}return c};g.keys="function"===typeof Object.keys?Object.keys:function(a){var b=[],c=Object.prototype.hasOwnProperty,d;for(d in a)c.call(a,d)&&b.push(d);return b};g.watch=function(a,b){var c={interval:100};a.forEach(function(a){h("file %s",a);u(a,c,function(c,d){d.mtime<c.mtime&&b(a)})})};var E="function"===typeof Array.isArray?Array.isArray:
function(a){return"[object Array]"===Object.prototype.toString.call(a)};g.isArray=E;"undefined"!==typeof l&&l.prototype&&(l.prototype.toJSON=l.prototype.toJSON||function(){return Array.prototype.slice.call(this,0)});g.files=function(a,c,d){d=d||[];c=c||["js"];var e=new RegExp("\\.("+c.join("|")+")$");q(a).filter(b).forEach(function(b){b=m(a,b);x(b).isDirectory()?g.files(b,c,d):b.match(e)&&d.push(b)});return d};g.slug=function(a){return a.toLowerCase().replace(/ +/g,"-").replace(/[^-\w]/g,"")};g.clean=
function(a){a=a.replace(/\r\n?|[\n\u2028\u2029]/g,"\n").replace(/^\uFEFF/,"").replace(/^function *\(.*\)\s*\{|\(.*\) *=> *\{?/,"").replace(/\s+\}$/,"");var b=a.match(/^\n?( *)/)[1].length,c=a.match(/^\n?(\t*)/)[1].length;a=a.replace(new RegExp("^\n?"+(c?"\t":" ")+"{"+(c?c:b)+"}","gm"),"");return g.trim(a)};g.trim=function(a){return a.replace(/^\s+|\s+$/g,"")};g.parseQuery=function(a){return g.reduce(a.replace("?","").split("&"),function(a,b){var c=b.indexOf("="),d=b.slice(0,c),c=b.slice(++c);a[d]=
decodeURIComponent(c);return a},{})};g.highlightTags=function(a){a=document.getElementById("mocha").getElementsByTagName(a);for(var b=0,c=a.length;b<c;++b)a[b].innerHTML=a[b].innerHTML.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\/\/(.*)/gm,'<span class="comment">//$1</span>').replace(/('.*?')/gm,'<span class="string">$1</span>').replace(/(\d+\.\d+)/gm,'<span class="number">$1</span>').replace(/(\d+)/gm,'<span class="number">$1</span>').replace(/\bnew[ \t]+(\w+)/gm,'<span class="keyword">new</span> <span class="init">$1</span>').replace(/\b(function|new|throw|return|var|if|else)\b/gm,
'<span class="keyword">$1</span>')};g.type=function(a){return void 0===a?"undefined":null===a?"null":"undefined"!==typeof l&&l.isBuffer(a)?"buffer":Object.prototype.toString.call(a).replace(/^\[.+\s(.+?)\]$/,"$1").toLowerCase()};g.stringify=function(a){var b=g.type(a);if(!~g.indexOf(["object","array","function"],b)){if("buffer"!==b)return k(a);a=a.toJSON();return k(a.data&&a.type?a.data:a,2).replace(/,(\n|$)/g,"$1")}for(var c in a)if(Object.prototype.hasOwnProperty.call(a,c))return k(g.canonicalize(a),
2).replace(/,(\n|$)/g,"$1");return e(a,b)};g.isBuffer=function(a){return"undefined"!==typeof l&&l.isBuffer(a)};g.canonicalize=function(a,b){function c(a,d){b.push(a);d();b.pop()}var d,h,k=g.type(a);b=b||[];if(-1!==g.indexOf(b,a))return"[Circular]";switch(k){case "undefined":case "buffer":case "null":d=a;break;case "array":c(a,function(){d=g.map(a,function(a){return g.canonicalize(a,b)})});break;case "function":for(h in a){d={};break}if(!d){d=e(a,k);break}case "object":d=d||{};c(a,function(){g.forEach(g.keys(a).sort(),
function(c){d[c]=g.canonicalize(a[c],b)})});break;case "date":case "number":case "regexp":case "boolean":d=a;break;default:d=a+""}return d};g.lookupFiles=function A(b,c,e){var h=[],k=new RegExp("\\.("+c.join("|")+")$");if(!d(b))if(d(b+".js"))b+=".js";else{h=t.sync(b);if(!h.length)throw Error("cannot resolve path (or pattern) '"+b+"'");return h}try{if(x(b).isFile())return b}catch(f){return}q(b).forEach(function(d){d=m(b,d);try{var f=x(d);if(f.isDirectory()){e&&(h=h.concat(A(d,c,e)));return}}catch(l){return}f.isFile()&&
k.test(d)&&"."!==a(d)[0]&&h.push(d)});return h};g.undefinedError=function(){return Error("Caught undefined error, did you throw without specifying what?")};g.getError=function(a){return a||g.undefinedError()};g.stackTraceFilter=function(){var a="undefined"===typeof document?{node:!0}:{browser:!0},b=a.node?c.cwd()+"/":("undefined"===typeof location?window.location:location).href.replace(/\/[^\/]*$/,"/");return function(c){c=c.split("\n");c=g.reduce(c,function(c,d){if(~d.indexOf("node_modules/mocha/")||
~d.indexOf("components/mochajs/")||~d.indexOf("components/mocha/")||~d.indexOf("/mocha.js"))return c;var e;if(e=a.node)e=~d.indexOf("(timers.js:")||~d.indexOf("(events.js:")||~d.indexOf("(node.js:")||~d.indexOf("(module.js:")||~d.indexOf("GeneratorFunctionPrototype.next (native)")||!1;if(e)return c;c.push(d.replace(b,""));return c},[]);return c.join("\n")}}}).call(this,f("_process"),f("buffer").Buffer)},{_process:51,buffer:43,debug:2,fs:41,glob:41,path:41,util:66}],40:[function(f,m,g){(function(c){function l(c){if(!(this instanceof
l))return new l(c);c=c||{};b.call(this,c);this.label=void 0!==c.label?c.label:"stdout"}var b=f("stream").Writable,e=f("util").inherits;m.exports=l;e(l,b);l.prototype._write=function(b,a,e){b=b.toString?b.toString():b;!1===this.label?console.log(b):console.log(this.label+":",b);c.nextTick(e)}}).call(this,f("_process"))},{_process:51,stream:63,util:66}],41:[function(f,m,g){},{}],42:[function(f,m,g){arguments[4][41][0].apply(g,arguments)},{dup:41}],43:[function(f,m,g){function c(a){if(!(this instanceof
c))return 1<arguments.length?new c(a,arguments[1]):new c(a);this.length=0;this.parent=void 0;if("number"===typeof a){var b;b=e(this,0>a?0:k(a)|0);if(!c.TYPED_ARRAY_SUPPORT)for(var d=0;d<a;d++)b[d]=0;return b}if("string"===typeof a){b=this;d=1<arguments.length?arguments[1]:"utf8";if("string"!==typeof d||""===d)d="utf8";var f=h(a,d)|0;b=e(b,f);b.write(a,d);return b}return l(this,a)}function l(a,d){if(c.isBuffer(d)){var h=a,f=k(d.length)|0,h=e(h,f);d.copy(h,0,0,f);return h}if(p(d)){for(var h=a,f=k(d.length)|
0,h=e(h,f),l=0;l<f;l+=1)h[l]=d[l]&255;return h}if(null==d)throw new TypeError("must start with number, buffer, array or string");if("undefined"!==typeof ArrayBuffer){if(d.buffer instanceof ArrayBuffer)return b(a,d);if(d instanceof ArrayBuffer)return h=a,c.TYPED_ARRAY_SUPPORT?(d.byteLength,h=c._augment(new Uint8Array(d))):h=b(h,new Uint8Array(d)),h}if(d.length){h=a;f=k(d.length)|0;h=e(h,f);for(l=0;l<f;l+=1)h[l]=d[l]&255;return h}h=a;l=0;"Buffer"===d.type&&p(d.data)&&(f=d.data,l=k(f.length)|0);for(var h=
e(h,l),g=0;g<l;g+=1)h[g]=f[g]&255;return h}function b(a,b){var c=k(b.length)|0;a=e(a,c);for(var d=0;d<c;d+=1)a[d]=b[d]&255;return a}function e(a,b){c.TYPED_ARRAY_SUPPORT?a=c._augment(new Uint8Array(b)):(a.length=b,a._isBuffer=!0);0!==b&&b<=c.poolSize>>>1&&(a.parent=G);return a}function k(a){if(a>=(c.TYPED_ARRAY_SUPPORT?2147483647:1073741823))throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+(c.TYPED_ARRAY_SUPPORT?2147483647:1073741823).toString(16)+" bytes");return a|
0}function a(b,d){if(!(this instanceof a))return new a(b,d);var e=new c(b,d);delete e.parent;return e}function h(a,b){"string"!==typeof a&&(a=""+a);var c=a.length;if(0===c)return 0;for(var d=!1;;)switch(b){case "ascii":case "binary":case "raw":case "raws":return c;case "utf8":case "utf-8":return F(a).length;case "ucs2":case "ucs-2":case "utf16le":case "utf-16le":return 2*c;case "hex":return c>>>1;case "base64":return z.toByteArray(A(a)).length;default:if(d)return F(a).length;b=(""+b).toLowerCase();
d=!0}}function d(a,b,c){var d=!1;b|=0;c=void 0===c||Infinity===c?this.length:c|0;a||(a="utf8");0>b&&(b=0);c>this.length&&(c=this.length);if(c<=b)return"";for(;;)switch(a){case "hex":a=b;b=c;c=this.length;if(!a||0>a)a=0;if(!b||0>b||b>c)b=c;d="";for(c=a;c<b;c++)a=d,d=this[c],d=16>d?"0"+d.toString(16):d.toString(16),d=a+d;return d;case "utf8":case "utf-8":return t(this,b,c);case "ascii":a="";for(c=Math.min(this.length,c);b<c;b++)a+=String.fromCharCode(this[b]&127);return a;case "binary":a="";for(c=Math.min(this.length,
c);b<c;b++)a+=String.fromCharCode(this[b]);return a;case "base64":return b=0===b&&c===this.length?z.fromByteArray(this):z.fromByteArray(this.slice(b,c)),b;case "ucs2":case "ucs-2":case "utf16le":case "utf-16le":b=this.slice(b,c);c="";for(a=0;a<b.length;a+=2)c+=String.fromCharCode(b[a]+256*b[a+1]);return c;default:if(d)throw new TypeError("Unknown encoding: "+a);a=(a+"").toLowerCase();d=!0}}function t(a,b,c){c=Math.min(a.length,c);for(var d=[];b<c;){var e=a[b],h=null,k=239<e?4:223<e?3:191<e?2:1;if(b+
k<=c){var f,l,g;switch(k){case 1:128>e&&(h=e);break;case 2:f=a[b+1];128===(f&192)&&(e=(e&31)<<6|f&63,127<e&&(h=e));break;case 3:f=a[b+1];l=a[b+2];128===(f&192)&&128===(l&192)&&(e=(e&15)<<12|(f&63)<<6|l&63,2047<e&&(55296>e||57343<e)&&(h=e));break;case 4:f=a[b+1],l=a[b+2],g=a[b+3],128===(f&192)&&128===(l&192)&&128===(g&192)&&(e=(e&15)<<18|(f&63)<<12|(l&63)<<6|g&63,65535<e&&1114112>e&&(h=e))}}null===h?(h=65533,k=1):65535<h&&(h-=65536,d.push(h>>>10&1023|55296),h=56320|h&1023);d.push(h);b+=k}a=d.length;
if(a<=J)d=String.fromCharCode.apply(String,d);else{c="";for(b=0;b<a;)c+=String.fromCharCode.apply(String,d.slice(b,b+=J));d=c}return d}function r(a,b,c){if(0!==a%1||0>a)throw new RangeError("offset is not uint");if(a+b>c)throw new RangeError("Trying to access beyond buffer length");}function q(a,b,d,e,h,k){if(!c.isBuffer(a))throw new TypeError("buffer must be a Buffer instance");if(b>h||b<k)throw new RangeError("value is out of bounds");if(d+e>a.length)throw new RangeError("index out of range");}
function x(a,b,c,d){0>b&&(b=65535+b+1);for(var e=0,h=Math.min(a.length-c,2);e<h;e++)a[c+e]=(b&255<<8*(d?e:1-e))>>>8*(d?e:1-e)}function u(a,b,c,d){0>b&&(b=4294967295+b+1);for(var e=0,h=Math.min(a.length-c,4);e<h;e++)a[c+e]=b>>>8*(d?e:3-e)&255}function D(a,b,c,d,e,h){if(b>e||b<h)throw new RangeError("value is out of bounds");if(c+d>a.length)throw new RangeError("index out of range");if(0>c)throw new RangeError("index out of range");}function E(a,b,c,d,e){e||D(a,b,c,4,3.4028234663852886E38,-3.4028234663852886E38);
n.write(a,b,c,d,23,4);return c+4}function w(a,b,c,d,e){e||D(a,b,c,8,1.7976931348623157E308,-1.7976931348623157E308);n.write(a,b,c,d,52,8);return c+8}function A(a){a=a.trim?a.trim():a.replace(/^\s+|\s+$/g,"");a=a.replace(K,"");if(2>a.length)return"";for(;0!==a.length%4;)a+="=";return a}function F(a,b){b=b||Infinity;for(var c,d=a.length,e=null,h=[],k=0;k<d;k++){c=a.charCodeAt(k);if(55295<c&&57344>c){if(!e){if(56319<c){-1<(b-=3)&&h.push(239,191,189);continue}else if(k+1===d){-1<(b-=3)&&h.push(239,191,
189);continue}e=c;continue}if(56320>c){-1<(b-=3)&&h.push(239,191,189);e=c;continue}c=e-55296<<10|c-56320|65536}else e&&-1<(b-=3)&&h.push(239,191,189);e=null;if(128>c){if(0>--b)break;h.push(c)}else if(2048>c){if(0>(b-=2))break;h.push(c>>6|192,c&63|128)}else if(65536>c){if(0>(b-=3))break;h.push(c>>12|224,c>>6&63|128,c&63|128)}else if(1114112>c){if(0>(b-=4))break;h.push(c>>18|240,c>>12&63|128,c>>6&63|128,c&63|128)}else throw Error("Invalid code point");}return h}function B(a){for(var b=[],c=0;c<a.length;c++)b.push(a.charCodeAt(c)&
255);return b}function y(a,b,c,d){for(var e=0;e<d&&!(e+c>=b.length||e>=a.length);e++)b[e+c]=a[e];return e}var z=f("base64-js"),n=f("ieee754"),p=f("is-array");g.Buffer=c;g.SlowBuffer=a;g.INSPECT_MAX_BYTES=50;c.poolSize=8192;var G={};c.TYPED_ARRAY_SUPPORT=function(){function a(){}try{var b=new Uint8Array(1);b.foo=function(){return 42};b.constructor=a;return 42===b.foo()&&b.constructor===a&&"function"===typeof b.subarray&&0===b.subarray(1,1).byteLength}catch(c){return!1}}();c.isBuffer=function(a){return!(null==
a||!a._isBuffer)};c.compare=function(a,b){if(!c.isBuffer(a)||!c.isBuffer(b))throw new TypeError("Arguments must be Buffers");if(a===b)return 0;for(var d=a.length,e=b.length,h=0,k=Math.min(d,e);h<k&&a[h]===b[h];)++h;h!==k&&(d=a[h],e=b[h]);return d<e?-1:e<d?1:0};c.isEncoding=function(a){switch(String(a).toLowerCase()){case "hex":case "utf8":case "utf-8":case "ascii":case "binary":case "base64":case "raw":case "ucs2":case "ucs-2":case "utf16le":case "utf-16le":return!0;default:return!1}};c.concat=function(a,
b){if(!p(a))throw new TypeError("list argument must be an Array of Buffers.");if(0===a.length)return new c(0);var d;if(void 0===b)for(d=b=0;d<a.length;d++)b+=a[d].length;var e=new c(b),h=0;for(d=0;d<a.length;d++){var k=a[d];k.copy(e,h);h+=k.length}return e};c.byteLength=h;c.prototype.length=void 0;c.prototype.parent=void 0;c.prototype.toString=function(){var a=this.length|0;return 0===a?"":0===arguments.length?t(this,0,a):d.apply(this,arguments)};c.prototype.equals=function(a){if(!c.isBuffer(a))throw new TypeError("Argument must be a Buffer");
return this===a?!0:0===c.compare(this,a)};c.prototype.inspect=function(){var a="",b=g.INSPECT_MAX_BYTES;0<this.length&&(a=this.toString("hex",0,b).match(/.{2}/g).join(" "),this.length>b&&(a+=" ... "));return"<Buffer "+a+">"};c.prototype.compare=function(a){if(!c.isBuffer(a))throw new TypeError("Argument must be a Buffer");return this===a?0:c.compare(this,a)};c.prototype.indexOf=function(a,b){function d(a,b,c){for(var e=-1,h=0;c+h<a.length;h++)if(a[c+h]===b[-1===e?0:h-e]){if(-1===e&&(e=h),h-e+1===
b.length)return c+e}else e=-1;return-1}2147483647<b?b=2147483647:-2147483648>b&&(b=-2147483648);b>>=0;if(0===this.length||b>=this.length)return-1;0>b&&(b=Math.max(this.length+b,0));if("string"===typeof a)return 0===a.length?-1:String.prototype.indexOf.call(this,a,b);if(c.isBuffer(a))return d(this,a,b);if("number"===typeof a)return c.TYPED_ARRAY_SUPPORT&&"function"===Uint8Array.prototype.indexOf?Uint8Array.prototype.indexOf.call(this,a,b):d(this,[a],b);throw new TypeError("val must be string, number or Buffer");
};c.prototype.get=function(a){console.log(".get() is deprecated. Access using array indexes instead.");return this.readUInt8(a)};c.prototype.set=function(a,b){console.log(".set() is deprecated. Access using array indexes instead.");return this.writeUInt8(a,b)};c.prototype.write=function(a,b,c,d){if(void 0===b)d="utf8",c=this.length,b=0;else if(void 0===c&&"string"===typeof b)d=b,c=this.length,b=0;else if(isFinite(b))b|=0,isFinite(c)?(c|=0,void 0===d&&(d="utf8")):(d=c,c=void 0);else{var e=d;d=b;b=
c|0;c=e}e=this.length-b;if(void 0===c||c>e)c=e;if(0<a.length&&(0>c||0>b)||b>this.length)throw new RangeError("attempt to write outside buffer bounds");d||(d="utf8");for(e=!1;;)switch(d){case "hex":b=Number(b)||0;d=this.length-b;c?(c=Number(c),c>d&&(c=d)):c=d;d=a.length;if(0!==d%2)throw Error("Invalid hex string");c>d/2&&(c=d/2);for(d=0;d<c;d++){e=parseInt(a.substr(2*d,2),16);if(isNaN(e))throw Error("Invalid hex string");this[b+d]=e}return d;case "utf8":case "utf-8":return y(F(a,this.length-b),this,
b,c);case "ascii":return y(B(a),this,b,c);case "binary":return y(B(a),this,b,c);case "base64":return y(z.toByteArray(A(a)),this,b,c);case "ucs2":case "ucs-2":case "utf16le":case "utf-16le":d=this.length-b;for(var h=void 0,h=e=void 0,k=[],f=0;f<a.length&&!(0>(d-=2));f++)h=a.charCodeAt(f),e=h>>8,h%=256,k.push(h),k.push(e);return y(k,this,b,c);default:if(e)throw new TypeError("Unknown encoding: "+d);d=(""+d).toLowerCase();e=!0}};c.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||
this,0)}};var J=4096;c.prototype.slice=function(a,b){var d=this.length;a=~~a;b=void 0===b?d:~~b;0>a?(a+=d,0>a&&(a=0)):a>d&&(a=d);0>b?(b+=d,0>b&&(b=0)):b>d&&(b=d);b<a&&(b=a);if(c.TYPED_ARRAY_SUPPORT)d=c._augment(this.subarray(a,b));else for(var e=b-a,d=new c(e,void 0),h=0;h<e;h++)d[h]=this[h+a];d.length&&(d.parent=this.parent||this);return d};c.prototype.readUIntLE=function(a,b,c){a|=0;b|=0;c||r(a,b,this.length);c=this[a];for(var d=1,e=0;++e<b&&(d*=256);)c+=this[a+e]*d;return c};c.prototype.readUIntBE=
function(a,b,c){a|=0;b|=0;c||r(a,b,this.length);c=this[a+--b];for(var d=1;0<b&&(d*=256);)c+=this[a+--b]*d;return c};c.prototype.readUInt8=function(a,b){b||r(a,1,this.length);return this[a]};c.prototype.readUInt16LE=function(a,b){b||r(a,2,this.length);return this[a]|this[a+1]<<8};c.prototype.readUInt16BE=function(a,b){b||r(a,2,this.length);return this[a]<<8|this[a+1]};c.prototype.readUInt32LE=function(a,b){b||r(a,4,this.length);return(this[a]|this[a+1]<<8|this[a+2]<<16)+16777216*this[a+3]};c.prototype.readUInt32BE=
function(a,b){b||r(a,4,this.length);return 16777216*this[a]+(this[a+1]<<16|this[a+2]<<8|this[a+3])};c.prototype.readIntLE=function(a,b,c){a|=0;b|=0;c||r(a,b,this.length);c=this[a];for(var d=1,e=0;++e<b&&(d*=256);)c+=this[a+e]*d;c>=128*d&&(c-=Math.pow(2,8*b));return c};c.prototype.readIntBE=function(a,b,c){a|=0;b|=0;c||r(a,b,this.length);c=b;for(var d=1,e=this[a+--c];0<c&&(d*=256);)e+=this[a+--c]*d;e>=128*d&&(e-=Math.pow(2,8*b));return e};c.prototype.readInt8=function(a,b){b||r(a,1,this.length);return this[a]&
128?-1*(255-this[a]+1):this[a]};c.prototype.readInt16LE=function(a,b){b||r(a,2,this.length);var c=this[a]|this[a+1]<<8;return c&32768?c|4294901760:c};c.prototype.readInt16BE=function(a,b){b||r(a,2,this.length);var c=this[a+1]|this[a]<<8;return c&32768?c|4294901760:c};c.prototype.readInt32LE=function(a,b){b||r(a,4,this.length);return this[a]|this[a+1]<<8|this[a+2]<<16|this[a+3]<<24};c.prototype.readInt32BE=function(a,b){b||r(a,4,this.length);return this[a]<<24|this[a+1]<<16|this[a+2]<<8|this[a+3]};
c.prototype.readFloatLE=function(a,b){b||r(a,4,this.length);return n.read(this,a,!0,23,4)};c.prototype.readFloatBE=function(a,b){b||r(a,4,this.length);return n.read(this,a,!1,23,4)};c.prototype.readDoubleLE=function(a,b){b||r(a,8,this.length);return n.read(this,a,!0,52,8)};c.prototype.readDoubleBE=function(a,b){b||r(a,8,this.length);return n.read(this,a,!1,52,8)};c.prototype.writeUIntLE=function(a,b,c,d){a=+a;b|=0;c|=0;d||q(this,a,b,c,Math.pow(2,8*c),0);d=1;var e=0;for(this[b]=a&255;++e<c&&(d*=256);)this[b+
e]=a/d&255;return b+c};c.prototype.writeUIntBE=function(a,b,c,d){a=+a;b|=0;c|=0;d||q(this,a,b,c,Math.pow(2,8*c),0);d=c-1;var e=1;for(this[b+d]=a&255;0<=--d&&(e*=256);)this[b+d]=a/e&255;return b+c};c.prototype.writeUInt8=function(a,b,d){a=+a;b|=0;d||q(this,a,b,1,255,0);c.TYPED_ARRAY_SUPPORT||(a=Math.floor(a));this[b]=a;return b+1};c.prototype.writeUInt16LE=function(a,b,d){a=+a;b|=0;d||q(this,a,b,2,65535,0);c.TYPED_ARRAY_SUPPORT?(this[b]=a,this[b+1]=a>>>8):x(this,a,b,!0);return b+2};c.prototype.writeUInt16BE=
function(a,b,d){a=+a;b|=0;d||q(this,a,b,2,65535,0);c.TYPED_ARRAY_SUPPORT?(this[b]=a>>>8,this[b+1]=a):x(this,a,b,!1);return b+2};c.prototype.writeUInt32LE=function(a,b,d){a=+a;b|=0;d||q(this,a,b,4,4294967295,0);c.TYPED_ARRAY_SUPPORT?(this[b+3]=a>>>24,this[b+2]=a>>>16,this[b+1]=a>>>8,this[b]=a):u(this,a,b,!0);return b+4};c.prototype.writeUInt32BE=function(a,b,d){a=+a;b|=0;d||q(this,a,b,4,4294967295,0);c.TYPED_ARRAY_SUPPORT?(this[b]=a>>>24,this[b+1]=a>>>16,this[b+2]=a>>>8,this[b+3]=a):u(this,a,b,!1);
return b+4};c.prototype.writeIntLE=function(a,b,c,d){a=+a;b|=0;d||(d=Math.pow(2,8*c-1),q(this,a,b,c,d-1,-d));d=0;var e=1,h=0>a?1:0;for(this[b]=a&255;++d<c&&(e*=256);)this[b+d]=(a/e>>0)-h&255;return b+c};c.prototype.writeIntBE=function(a,b,c,d){a=+a;b|=0;d||(d=Math.pow(2,8*c-1),q(this,a,b,c,d-1,-d));d=c-1;var e=1,h=0>a?1:0;for(this[b+d]=a&255;0<=--d&&(e*=256);)this[b+d]=(a/e>>0)-h&255;return b+c};c.prototype.writeInt8=function(a,b,d){a=+a;b|=0;d||q(this,a,b,1,127,-128);c.TYPED_ARRAY_SUPPORT||(a=Math.floor(a));
0>a&&(a=255+a+1);this[b]=a;return b+1};c.prototype.writeInt16LE=function(a,b,d){a=+a;b|=0;d||q(this,a,b,2,32767,-32768);c.TYPED_ARRAY_SUPPORT?(this[b]=a,this[b+1]=a>>>8):x(this,a,b,!0);return b+2};c.prototype.writeInt16BE=function(a,b,d){a=+a;b|=0;d||q(this,a,b,2,32767,-32768);c.TYPED_ARRAY_SUPPORT?(this[b]=a>>>8,this[b+1]=a):x(this,a,b,!1);return b+2};c.prototype.writeInt32LE=function(a,b,d){a=+a;b|=0;d||q(this,a,b,4,2147483647,-2147483648);c.TYPED_ARRAY_SUPPORT?(this[b]=a,this[b+1]=a>>>8,this[b+
2]=a>>>16,this[b+3]=a>>>24):u(this,a,b,!0);return b+4};c.prototype.writeInt32BE=function(a,b,d){a=+a;b|=0;d||q(this,a,b,4,2147483647,-2147483648);0>a&&(a=4294967295+a+1);c.TYPED_ARRAY_SUPPORT?(this[b]=a>>>24,this[b+1]=a>>>16,this[b+2]=a>>>8,this[b+3]=a):u(this,a,b,!1);return b+4};c.prototype.writeFloatLE=function(a,b,c){return E(this,a,b,!0,c)};c.prototype.writeFloatBE=function(a,b,c){return E(this,a,b,!1,c)};c.prototype.writeDoubleLE=function(a,b,c){return w(this,a,b,!0,c)};c.prototype.writeDoubleBE=
function(a,b,c){return w(this,a,b,!1,c)};c.prototype.copy=function(a,b,d,e){d||(d=0);e||0===e||(e=this.length);b>=a.length&&(b=a.length);b||(b=0);0<e&&e<d&&(e=d);if(e===d||0===a.length||0===this.length)return 0;if(0>b)throw new RangeError("targetStart out of bounds");if(0>d||d>=this.length)throw new RangeError("sourceStart out of bounds");if(0>e)throw new RangeError("sourceEnd out of bounds");e>this.length&&(e=this.length);a.length-b<e-d&&(e=a.length-b+d);var h=e-d;if(this===a&&d<b&&b<e)for(e=h-1;0<=
e;e--)a[e+b]=this[e+d];else if(1E3>h||!c.TYPED_ARRAY_SUPPORT)for(e=0;e<h;e++)a[e+b]=this[e+d];else a._set(this.subarray(d,d+h),b);return h};c.prototype.fill=function(a,b,c){a||(a=0);b||(b=0);c||(c=this.length);if(c<b)throw new RangeError("end < start");if(c!==b&&0!==this.length){if(0>b||b>=this.length)throw new RangeError("start out of bounds");if(0>c||c>this.length)throw new RangeError("end out of bounds");if("number"===typeof a)for(;b<c;b++)this[b]=a;else{a=F(a.toString());for(var d=a.length;b<
c;b++)this[b]=a[b%d]}return this}};c.prototype.toArrayBuffer=function(){if("undefined"!==typeof Uint8Array){if(c.TYPED_ARRAY_SUPPORT)return(new c(this)).buffer;for(var a=new Uint8Array(this.length),b=0,d=a.length;b<d;b+=1)a[b]=this[b];return a.buffer}throw new TypeError("Buffer.toArrayBuffer not supported in this browser");};var v=c.prototype;c._augment=function(a){a.constructor=c;a._isBuffer=!0;a._set=a.set;a.get=v.get;a.set=v.set;a.write=v.write;a.toString=v.toString;a.toLocaleString=v.toString;
a.toJSON=v.toJSON;a.equals=v.equals;a.compare=v.compare;a.indexOf=v.indexOf;a.copy=v.copy;a.slice=v.slice;a.readUIntLE=v.readUIntLE;a.readUIntBE=v.readUIntBE;a.readUInt8=v.readUInt8;a.readUInt16LE=v.readUInt16LE;a.readUInt16BE=v.readUInt16BE;a.readUInt32LE=v.readUInt32LE;a.readUInt32BE=v.readUInt32BE;a.readIntLE=v.readIntLE;a.readIntBE=v.readIntBE;a.readInt8=v.readInt8;a.readInt16LE=v.readInt16LE;a.readInt16BE=v.readInt16BE;a.readInt32LE=v.readInt32LE;a.readInt32BE=v.readInt32BE;a.readFloatLE=v.readFloatLE;
a.readFloatBE=v.readFloatBE;a.readDoubleLE=v.readDoubleLE;a.readDoubleBE=v.readDoubleBE;a.writeUInt8=v.writeUInt8;a.writeUIntLE=v.writeUIntLE;a.writeUIntBE=v.writeUIntBE;a.writeUInt16LE=v.writeUInt16LE;a.writeUInt16BE=v.writeUInt16BE;a.writeUInt32LE=v.writeUInt32LE;a.writeUInt32BE=v.writeUInt32BE;a.writeIntLE=v.writeIntLE;a.writeIntBE=v.writeIntBE;a.writeInt8=v.writeInt8;a.writeInt16LE=v.writeInt16LE;a.writeInt16BE=v.writeInt16BE;a.writeInt32LE=v.writeInt32LE;a.writeInt32BE=v.writeInt32BE;a.writeFloatLE=
v.writeFloatLE;a.writeFloatBE=v.writeFloatBE;a.writeDoubleLE=v.writeDoubleLE;a.writeDoubleBE=v.writeDoubleBE;a.fill=v.fill;a.inspect=v.inspect;a.toArrayBuffer=v.toArrayBuffer;return a};var K=/[^+\/0-9A-Za-z-_]/g},{"base64-js":44,ieee754:45,"is-array":46}],44:[function(f,m,g){(function(c){function f(b){b=b.charCodeAt(0);if(43===b||45===b)return 62;if(47===b||95===b)return 63;if(48>b)return-1;if(58>b)return b-48+52;if(91>b)return b-65;if(123>b)return b-97+26}var b="undefined"!==typeof Uint8Array?Uint8Array:
Array;c.toByteArray=function(c){function k(a){m[q++]=a}var a,h,d,g,m;if(0<c.length%4)throw Error("Invalid string. Length must be a multiple of 4");a=c.length;g="="===c.charAt(a-2)?2:"="===c.charAt(a-1)?1:0;m=new b(3*c.length/4-g);h=0<g?c.length-4:c.length;var q=0;for(a=0;a<h;a+=4)d=f(c.charAt(a))<<18|f(c.charAt(a+1))<<12|f(c.charAt(a+2))<<6|f(c.charAt(a+3)),k((d&16711680)>>16),k((d&65280)>>8),k(d&255);2===g?(d=f(c.charAt(a))<<2|f(c.charAt(a+1))>>4,k(d&255)):1===g&&(d=f(c.charAt(a))<<10|f(c.charAt(a+
1))<<4|f(c.charAt(a+2))>>2,k(d>>8&255),k(d&255));return m};c.fromByteArray=function(b){var c,a=b.length%3,h="",d,f;c=0;for(f=b.length-a;c<f;c+=3)d=(b[c]<<16)+(b[c+1]<<8)+b[c+2],d="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d>>18&63)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d>>12&63)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d>>6&63)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d&
63),h+=d;switch(a){case 1:d=b[b.length-1];h+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d>>2);h+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d<<4&63);h+="==";break;case 2:d=(b[b.length-2]<<8)+b[b.length-1],h+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d>>10),h+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d>>4&63),h+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d<<
2&63),h+="="}return h}})("undefined"===typeof g?this.base64js={}:g)},{}],45:[function(f,m,g){g.read=function(c,f,b,e,k){var a;a=8*k-e-1;var h=(1<<a)-1,d=h>>1,g=-7;k=b?k-1:0;var m=b?-1:1,q=c[f+k];k+=m;b=q&(1<<-g)-1;q>>=-g;for(g+=a;0<g;b=256*b+c[f+k],k+=m,g-=8);a=b&(1<<-g)-1;b>>=-g;for(g+=e;0<g;a=256*a+c[f+k],k+=m,g-=8);if(0===b)b=1-d;else{if(b===h)return a?NaN:Infinity*(q?-1:1);a+=Math.pow(2,e);b-=d}return(q?-1:1)*a*Math.pow(2,b-e)};g.write=function(c,f,b,e,k,a){var h,d=8*a-k-1,g=(1<<d)-1,m=g>>1,q=
23===k?Math.pow(2,-24)-Math.pow(2,-77):0;a=e?0:a-1;var x=e?1:-1,u=0>f||0===f&&0>1/f?1:0;f=Math.abs(f);isNaN(f)||Infinity===f?(f=isNaN(f)?1:0,e=g):(e=Math.floor(Math.log(f)/Math.LN2),1>f*(h=Math.pow(2,-e))&&(e--,h*=2),f=1<=e+m?f+q/h:f+q*Math.pow(2,1-m),2<=f*h&&(e++,h/=2),e+m>=g?(f=0,e=g):1<=e+m?(f=(f*h-1)*Math.pow(2,k),e+=m):(f=f*Math.pow(2,m-1)*Math.pow(2,k),e=0));for(;8<=k;c[b+a]=f&255,a+=x,f/=256,k-=8);e=e<<k|f;for(d+=k;0<d;c[b+a]=e&255,a+=x,e/=256,d-=8);c[b+a-x]|=128*u}},{}],46:[function(f,m,g){var c=
Object.prototype.toString;m.exports=Array.isArray||function(f){return!!f&&"[object Array]"==c.call(f)}},{}],47:[function(f,m,g){function c(){this._events=this._events||{};this._maxListeners=this._maxListeners||void 0}function l(b){return"function"===typeof b}function b(b){return"object"===typeof b&&null!==b}m.exports=c;c.EventEmitter=c;c.prototype._events=void 0;c.prototype._maxListeners=void 0;c.defaultMaxListeners=10;c.prototype.setMaxListeners=function(b){if("number"!==typeof b||0>b||isNaN(b))throw TypeError("n must be a positive number");
this._maxListeners=b;return this};c.prototype.emit=function(c){var f,a,h,d;this._events||(this._events={});if("error"===c&&(!this._events.error||b(this._events.error)&&!this._events.error.length)){f=arguments[1];if(f instanceof Error)throw f;throw TypeError('Uncaught, unspecified "error" event.');}a=this._events[c];if(void 0===a)return!1;if(l(a))switch(arguments.length){case 1:a.call(this);break;case 2:a.call(this,arguments[1]);break;case 3:a.call(this,arguments[1],arguments[2]);break;default:f=arguments.length;
h=Array(f-1);for(d=1;d<f;d++)h[d-1]=arguments[d];a.apply(this,h)}else if(b(a)){f=arguments.length;h=Array(f-1);for(d=1;d<f;d++)h[d-1]=arguments[d];a=a.slice();f=a.length;for(d=0;d<f;d++)a[d].apply(this,h)}return!0};c.prototype.addListener=function(e,f){var a;if(!l(f))throw TypeError("listener must be a function");this._events||(this._events={});this._events.newListener&&this.emit("newListener",e,l(f.listener)?f.listener:f);this._events[e]?b(this._events[e])?this._events[e].push(f):this._events[e]=
[this._events[e],f]:this._events[e]=f;b(this._events[e])&&!this._events[e].warned&&(a=void 0!==this._maxListeners?this._maxListeners:c.defaultMaxListeners)&&0<a&&this._events[e].length>a&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"===typeof console.trace&&console.trace());return this};c.prototype.on=c.prototype.addListener;c.prototype.once=
function(b,c){function a(){this.removeListener(b,a);h||(h=!0,c.apply(this,arguments))}if(!l(c))throw TypeError("listener must be a function");var h=!1;a.listener=c;this.on(b,a);return this};c.prototype.removeListener=function(c,f){var a,h,d;if(!l(f))throw TypeError("listener must be a function");if(!this._events||!this._events[c])return this;a=this._events[c];d=a.length;h=-1;if(a===f||l(a.listener)&&a.listener===f)delete this._events[c],this._events.removeListener&&this.emit("removeListener",c,f);
else if(b(a)){for(;0<d--;)if(a[d]===f||a[d].listener&&a[d].listener===f){h=d;break}if(0>h)return this;1===a.length?(a.length=0,delete this._events[c]):a.splice(h,1);this._events.removeListener&&this.emit("removeListener",c,f)}return this};c.prototype.removeAllListeners=function(b){var c;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[b]&&delete this._events[b],this;if(0===arguments.length){for(c in this._events)"removeListener"!==
c&&this.removeAllListeners(c);this.removeAllListeners("removeListener");this._events={};return this}c=this._events[b];if(l(c))this.removeListener(b,c);else for(;c.length;)this.removeListener(b,c[c.length-1]);delete this._events[b];return this};c.prototype.listeners=function(b){return this._events&&this._events[b]?l(this._events[b])?[this._events[b]]:this._events[b].slice():[]};c.listenerCount=function(b,c){return b._events&&b._events[c]?l(b._events[c])?1:b._events[c].length:0}},{}],48:[function(f,
m,g){m.exports="function"===typeof Object.create?function(c,f){c.super_=f;c.prototype=Object.create(f.prototype,{constructor:{value:c,enumerable:!1,writable:!0,configurable:!0}})}:function(c,f){c.super_=f;var b=function(){};b.prototype=f.prototype;c.prototype=new b;c.prototype.constructor=c}},{}],49:[function(f,m,g){m.exports=Array.isArray||function(c){return"[object Array]"==Object.prototype.toString.call(c)}},{}],50:[function(f,m,g){g.endianness=function(){return"LE"};g.hostname=function(){return"undefined"!==
typeof location?location.hostname:""};g.loadavg=function(){return[]};g.uptime=function(){return 0};g.freemem=function(){return Number.MAX_VALUE};g.totalmem=function(){return Number.MAX_VALUE};g.cpus=function(){return[]};g.type=function(){return"Browser"};g.release=function(){return"undefined"!==typeof navigator?navigator.appVersion:""};g.networkInterfaces=g.getNetworkInterfaces=function(){return{}};g.arch=function(){return"javascript"};g.platform=function(){return"browser"};g.tmpdir=g.tmpDir=function(){return"/tmp"};
g.EOL="\n"},{}],51:[function(f,m,g){function c(){a=!1;h.length?k=h.concat(k):d=-1;k.length&&l()}function l(){if(!a){var b=setTimeout(c);a=!0;for(var e=k.length;e;){h=k;for(k=[];++d<e;)h&&h[d].run();d=-1;e=k.length}h=null;a=!1;clearTimeout(b)}}function b(a,b){this.fun=a;this.array=b}function e(){}f=m.exports={};var k=[],a=!1,h,d=-1;f.nextTick=function(c){var d=Array(arguments.length-1);if(1<arguments.length)for(var e=1;e<arguments.length;e++)d[e-1]=arguments[e];k.push(new b(c,d));1!==k.length||a||
setTimeout(l,0)};b.prototype.run=function(){this.fun.apply(null,this.array)};f.title="browser";f.browser=!0;f.env={};f.argv=[];f.version="";f.versions={};f.on=e;f.addListener=e;f.once=e;f.off=e;f.removeListener=e;f.removeAllListeners=e;f.emit=e;f.binding=function(a){throw Error("process.binding is not supported");};f.cwd=function(){return"/"};f.chdir=function(a){throw Error("process.chdir is not supported");};f.umask=function(){return 0}},{}],52:[function(f,m,g){m.exports=f("./lib/_stream_duplex.js")},
{"./lib/_stream_duplex.js":53}],53:[function(f,m,g){(function(c){function g(c){if(!(this instanceof g))return new g(c);a.call(this,c);h.call(this,c);c&&!1===c.readable&&(this.readable=!1);c&&!1===c.writable&&(this.writable=!1);this.allowHalfOpen=!0;c&&!1===c.allowHalfOpen&&(this.allowHalfOpen=!1);this.once("end",b)}function b(){this.allowHalfOpen||this._writableState.ended||c.nextTick(this.end.bind(this))}m.exports=g;var e=Object.keys||function(a){var b=[],c;for(c in a)b.push(c);return b},k=f("core-util-is");
k.inherits=f("inherits");var a=f("./_stream_readable"),h=f("./_stream_writable");k.inherits(g,a);(function(a,b){for(var c=0,e=a.length;c<e;c++)b(a[c],c)})(e(h.prototype),function(a){g.prototype[a]||(g.prototype[a]=h.prototype[a])})}).call(this,f("_process"))},{"./_stream_readable":55,"./_stream_writable":57,_process:51,"core-util-is":58,inherits:48}],54:[function(f,m,g){function c(b){if(!(this instanceof c))return new c(b);l.call(this,b)}m.exports=c;var l=f("./_stream_transform");m=f("core-util-is");
m.inherits=f("inherits");m.inherits(c,l);c.prototype._transform=function(b,c,f){f(null,b)}},{"./_stream_transform":56,"core-util-is":58,inherits:48}],55:[function(f,m,g){(function(c){function g(a,b){var c=f("./_stream_duplex");a=a||{};var d=a.highWaterMark,e=a.objectMode?16:16384;this.highWaterMark=d||0===d?d:e;this.highWaterMark=~~this.highWaterMark;this.buffer=[];this.length=0;this.pipes=null;this.pipesCount=0;this.flowing=null;this.reading=this.endEmitted=this.ended=!1;this.sync=!0;this.readableListening=
this.emittedReadable=this.needReadable=!1;this.objectMode=!!a.objectMode;b instanceof c&&(this.objectMode=this.objectMode||!!a.readableObjectMode);this.defaultEncoding=a.defaultEncoding||"utf8";this.ranOut=!1;this.awaitDrain=0;this.readingMore=!1;this.encoding=this.decoder=null;a.encoding&&(y||(y=f("string_decoder/").StringDecoder),this.decoder=new y(a.encoding),this.encoding=a.encoding)}function b(a){f("./_stream_duplex");if(!(this instanceof b))return new b(a);this._readableState=new g(a,this);
this.readable=!0;F.call(this)}function e(b,c,e,h,f){var k;k=e;var g=null;B.isBuffer(k)||B.isString(k)||B.isNullOrUndefined(k)||c.objectMode||(g=new TypeError("Invalid non-string/buffer chunk"));(k=g)?b.emit("error",k):B.isNullOrUndefined(e)?(c.reading=!1,c.ended||(c.decoder&&!c.ended&&(e=c.decoder.end())&&e.length&&(c.buffer.push(e),c.length+=c.objectMode?1:e.length),c.ended=!0,a(b))):c.objectMode||e&&0<e.length?c.ended&&!f?(e=Error("stream.push() after EOF"),b.emit("error",e)):c.endEmitted&&f?(e=
Error("stream.unshift() after end event"),b.emit("error",e)):(!c.decoder||f||h||(e=c.decoder.write(e)),f||(c.reading=!1),c.flowing&&0===c.length&&!c.sync?(b.emit("data",e),b.read(0)):(c.length+=c.objectMode?1:e.length,f?c.buffer.unshift(e):c.buffer.push(e),c.needReadable&&a(b)),d(b,c)):f||(c.reading=!1);return!c.ended&&(c.needReadable||c.length<c.highWaterMark||0===c.length)}function k(a,b){if(0===b.length&&b.ended)return 0;if(b.objectMode)return 0===a?0:1;if(isNaN(a)||B.isNull(a))return b.flowing&&
b.buffer.length?b.buffer[0].length:b.length;if(0>=a)return 0;if(a>b.highWaterMark){var c=a;if(8388608<=c)c=8388608;else{c--;for(var d=1;32>d;d<<=1)c|=c>>d;c++}b.highWaterMark=c}if(a>b.length){if(b.ended)return b.length;b.needReadable=!0;return 0}return a}function a(a){var b=a._readableState;b.needReadable=!1;b.emittedReadable||(z("emitReadable",b.flowing),b.emittedReadable=!0,b.sync?c.nextTick(function(){h(a)}):h(a))}function h(a){z("emit readable");a.emit("readable");q(a)}function d(a,b){b.readingMore||
(b.readingMore=!0,c.nextTick(function(){for(var c=b.length;!b.reading&&!b.flowing&&!b.ended&&b.length<b.highWaterMark&&(z("maybeReadMore read 0"),a.read(0),c!==b.length);)c=b.length;b.readingMore=!1}))}function t(a){return function(){var b=a._readableState;z("pipeOnDrain",b.awaitDrain);b.awaitDrain&&b.awaitDrain--;0===b.awaitDrain&&A.listenerCount(a,"data")&&(b.flowing=!0,q(a))}}function r(a,b){b.resumeScheduled||(b.resumeScheduled=!0,c.nextTick(function(){b.resumeScheduled=!1;a.emit("resume");q(a);
b.flowing&&!b.reading&&a.read(0)}))}function q(a){var b=a._readableState;z("flow",b.flowing);if(b.flowing){do var c=a.read();while(null!==c&&b.flowing)}}function x(a,b){var c=b.buffer,d=b.length,e=!!b.decoder,h=!!b.objectMode;if(0===c.length)return null;if(0===d)d=null;else if(h)d=c.shift();else if(!a||a>=d)d=e?c.join(""):w.concat(c,d),c.length=0;else if(a<c[0].length)h=c[0],d=h.slice(0,a),c[0]=h.slice(a);else if(a===c[0].length)d=c.shift();else for(var d=e?"":new w(a),f=0,k=0,g=c.length;k<g&&f<a;k++){var h=
c[0],l=Math.min(a-f,h.length);e?d+=h.slice(0,l):h.copy(d,f,0,l);l<h.length?c[0]=h.slice(l):c.shift();f+=l}return d}function u(a){var b=a._readableState;if(0<b.length)throw Error("endReadable called on non-empty stream");b.endEmitted||(b.ended=!0,c.nextTick(function(){b.endEmitted||0!==b.length||(b.endEmitted=!0,a.readable=!1,a.emit("end"))}))}function D(a,b){for(var c=0,d=a.length;c<d;c++)b(a[c],c)}m.exports=b;var E=f("isarray"),w=f("buffer").Buffer;b.ReadableState=g;var A=f("events").EventEmitter;
A.listenerCount||(A.listenerCount=function(a,b){return a.listeners(b).length});var F=f("stream"),B=f("core-util-is");B.inherits=f("inherits");var y,z=f("util"),z=z&&z.debuglog?z.debuglog("stream"):function(){};B.inherits(b,F);b.prototype.push=function(a,b){var c=this._readableState;B.isString(a)&&!c.objectMode&&(b=b||c.defaultEncoding,b!==c.encoding&&(a=new w(a,b),b=""));return e(this,c,a,b,!1)};b.prototype.unshift=function(a){return e(this,this._readableState,a,"",!0)};b.prototype.setEncoding=function(a){y||
(y=f("string_decoder/").StringDecoder);this._readableState.decoder=new y(a);this._readableState.encoding=a;return this};b.prototype.read=function(b){z("read",b);var c=this._readableState,d=b;if(!B.isNumber(b)||0<b)c.emittedReadable=!1;if(0===b&&c.needReadable&&(c.length>=c.highWaterMark||c.ended))return z("read: emitReadable",c.length,c.ended),0===c.length&&c.ended?u(this):a(this),null;b=k(b,c);if(0===b&&c.ended)return 0===c.length&&u(this),null;var e=c.needReadable;z("need readable",e);if(0===c.length||
c.length-b<c.highWaterMark)e=!0,z("length less than watermark",e);if(c.ended||c.reading)e=!1,z("reading or ended",e);e&&(z("do read"),c.reading=!0,c.sync=!0,0===c.length&&(c.needReadable=!0),this._read(c.highWaterMark),c.sync=!1);e&&!c.reading&&(b=k(d,c));e=0<b?x(b,c):null;B.isNull(e)&&(c.needReadable=!0,b=0);c.length-=b;0!==c.length||c.ended||(c.needReadable=!0);d!==b&&c.ended&&0===c.length&&u(this);B.isNull(e)||this.emit("data",e);return e};b.prototype._read=function(a){this.emit("error",Error("not implemented"))};
b.prototype.pipe=function(a,b){function d(a){z("onunpipe");a===y&&h()}function e(){z("onend");a.end()}function h(){z("cleanup");a.removeListener("close",g);a.removeListener("finish",l);a.removeListener("drain",B);a.removeListener("error",k);a.removeListener("unpipe",d);y.removeListener("end",e);y.removeListener("end",h);y.removeListener("data",f);!r.awaitDrain||a._writableState&&!a._writableState.needDrain||B()}function f(b){z("ondata");!1===a.write(b)&&(z("false write response, pause",y._readableState.awaitDrain),
y._readableState.awaitDrain++,y.pause())}function k(b){z("onerror",b);m();a.removeListener("error",k);0===A.listenerCount(a,"error")&&a.emit("error",b)}function g(){a.removeListener("finish",l);m()}function l(){z("onfinish");a.removeListener("close",g);m()}function m(){z("unpipe");y.unpipe(a)}var y=this,r=this._readableState;switch(r.pipesCount){case 0:r.pipes=a;break;case 1:r.pipes=[r.pipes,a];break;default:r.pipes.push(a)}r.pipesCount+=1;z("pipe count=%d opts=%j",r.pipesCount,b);var u=b&&!1===b.end||
a===c.stdout||a===c.stderr?h:e;if(r.endEmitted)c.nextTick(u);else y.once("end",u);a.on("unpipe",d);var B=t(y);a.on("drain",B);y.on("data",f);if(a._events&&a._events.error)E(a._events.error)?a._events.error.unshift(k):a._events.error=[k,a._events.error];else a.on("error",k);a.once("close",g);a.once("finish",l);a.emit("pipe",y);r.flowing||(z("pipe resume"),y.resume());return a};b.prototype.unpipe=function(a){var b=this._readableState;if(0===b.pipesCount)return this;if(1===b.pipesCount){if(a&&a!==b.pipes)return this;
a||(a=b.pipes);b.pipes=null;b.pipesCount=0;b.flowing=!1;a&&a.emit("unpipe",this);return this}if(!a){a=b.pipes;var c=b.pipesCount;b.pipes=null;b.pipesCount=0;b.flowing=!1;for(var d=0;d<c;d++)a[d].emit("unpipe",this);return this}a:{for(var d=b.pipes,c=0,e=d.length;c<e;c++)if(d[c]===a){d=c;break a}d=-1}if(-1===d)return this;b.pipes.splice(d,1);--b.pipesCount;1===b.pipesCount&&(b.pipes=b.pipes[0]);a.emit("unpipe",this);return this};b.prototype.on=function(b,d){var e=F.prototype.on.call(this,b,d);"data"===
b&&!1!==this._readableState.flowing&&this.resume();if("readable"===b&&this.readable){var h=this._readableState;if(!h.readableListening)if(h.readableListening=!0,h.emittedReadable=!1,h.needReadable=!0,h.reading)h.length&&a(this,h);else{var f=this;c.nextTick(function(){z("readable nexttick read 0");f.read(0)})}}return e};b.prototype.addListener=b.prototype.on;b.prototype.resume=function(){var a=this._readableState;a.flowing||(z("resume"),a.flowing=!0,a.reading||(z("resume read 0"),this.read(0)),r(this,
a));return this};b.prototype.pause=function(){z("call pause flowing=%j",this._readableState.flowing);!1!==this._readableState.flowing&&(z("pause"),this._readableState.flowing=!1,this.emit("pause"));return this};b.prototype.wrap=function(a){var b=this._readableState,c=!1,d=this;a.on("end",function(){z("wrapped end");if(b.decoder&&!b.ended){var a=b.decoder.end();a&&a.length&&d.push(a)}d.push(null)});a.on("data",function(e){z("wrapped data");b.decoder&&(e=b.decoder.write(e));e&&(b.objectMode||e.length)&&
!d.push(e)&&(c=!0,a.pause())});for(var e in a)B.isFunction(a[e])&&B.isUndefined(this[e])&&(this[e]=function(b){return function(){return a[b].apply(a,arguments)}}(e));D(["error","close","destroy","pause","resume"],function(b){a.on(b,d.emit.bind(d,b))});d._read=function(b){z("wrapped _read",b);c&&(c=!1,a.resume())};return d};b._fromList=x}).call(this,f("_process"))},{"./_stream_duplex":53,_process:51,buffer:43,"core-util-is":58,events:47,inherits:48,isarray:49,stream:63,"string_decoder/":64,util:42}],
56:[function(f,m,g){function c(a,b){this.afterTransform=function(a,c){var e;e=b._transformState;e.transforming=!1;var f=e.writecb;f?(e.writechunk=null,e.writecb=null,k.isNullOrUndefined(c)||b.push(c),f&&f(a),e=b._readableState,e.reading=!1,(e.needReadable||e.length<e.highWaterMark)&&b._read(e.highWaterMark),e=void 0):e=b.emit("error",Error("no writecb in Transform class"));return e};this.transforming=this.needTransform=!1;this.writechunk=this.writecb=null}function l(a){if(!(this instanceof l))return new l(a);
e.call(this,a);this._transformState=new c(a,this);var h=this;this._readableState.needReadable=!0;this._readableState.sync=!1;this.once("prefinish",function(){k.isFunction(this._flush)?this._flush(function(a){b(h,a)}):b(h)})}function b(a,b){if(b)return a.emit("error",b);var c=a._transformState;if(a._writableState.length)throw Error("calling transform done when ws.length != 0");if(c.transforming)throw Error("calling transform done when still transforming");return a.push(null)}m.exports=l;var e=f("./_stream_duplex"),
k=f("core-util-is");k.inherits=f("inherits");k.inherits(l,e);l.prototype.push=function(a,b){this._transformState.needTransform=!1;return e.prototype.push.call(this,a,b)};l.prototype._transform=function(a,b,c){throw Error("not implemented");};l.prototype._write=function(a,b,c){var e=this._transformState;e.writecb=c;e.writechunk=a;e.writeencoding=b;e.transforming||(a=this._readableState,(e.needTransform||a.needReadable||a.length<a.highWaterMark)&&this._read(a.highWaterMark))};l.prototype._read=function(a){a=
this._transformState;k.isNull(a.writechunk)||!a.writecb||a.transforming?a.needTransform=!0:(a.transforming=!0,this._transform(a.writechunk,a.writeencoding,a.afterTransform))}},{"./_stream_duplex":53,"core-util-is":58,inherits:48}],57:[function(f,m,g){(function(c){function g(a,b,c){this.chunk=a;this.encoding=b;this.callback=c}function b(a,b){var c=f("./_stream_duplex");a=a||{};var d=a.highWaterMark,e=a.objectMode?16:16384;this.highWaterMark=d||0===d?d:e;this.objectMode=!!a.objectMode;b instanceof c&&
(this.objectMode=this.objectMode||!!a.writableObjectMode);this.highWaterMark=~~this.highWaterMark;this.finished=this.ended=this.ending=this.needDrain=!1;this.decodeStrings=!1!==a.decodeStrings;this.defaultEncoding=a.defaultEncoding||"utf8";this.length=0;this.writing=!1;this.corked=0;this.sync=!0;this.bufferProcessing=!1;this.onwrite=function(a){q(b,a)};this.writecb=null;this.writelen=0;this.buffer=[];this.pendingcb=0;this.errorEmitted=this.prefinished=!1}function e(a){var c=f("./_stream_duplex");
if(!(this instanceof e||this instanceof c))return new e(a);this._writableState=new b(a,this);this.writable=!0;A.call(this)}function k(a,b,d){var e=Error("write after end");a.emit("error",e);c.nextTick(function(){d(e)})}function a(a,b,d,e){var h=!0;if(!(w.isBuffer(d)||w.isString(d)||w.isNullOrUndefined(d)||b.objectMode)){var f=new TypeError("Invalid non-string/buffer chunk");a.emit("error",f);c.nextTick(function(){e(f)});h=!1}return h}function h(a,b,c,e,h){var f=e;!b.objectMode&&!1!==b.decodeStrings&&
w.isString(c)&&(c=new E(c,f));w.isBuffer(c)&&(e="buffer");f=b.objectMode?1:c.length;b.length+=f;var k=b.length<b.highWaterMark;k||(b.needDrain=!0);b.writing||b.corked?b.buffer.push(new g(c,e,h)):d(a,b,!1,f,c,e,h);return k}function d(a,b,c,d,e,h,f){b.writelen=d;b.writecb=f;b.writing=!0;b.sync=!0;c?a._writev(e,b.onwrite):a._write(e,h,b.onwrite);b.sync=!1}function t(a,b,d,e,h){d?c.nextTick(function(){b.pendingcb--;h(e)}):(b.pendingcb--,h(e));a._writableState.errorEmitted=!0;a.emit("error",e)}function r(a){a.writing=
!1;a.writecb=null;a.length-=a.writelen;a.writelen=0}function q(a,b){var d=a._writableState,e=d.sync,h=d.writecb;r(d);if(b)t(a,d,e,b,h);else{var f=d.ending&&0===d.length&&!d.finished&&!d.writing;f||d.corked||d.bufferProcessing||!d.buffer.length||u(a,d);e?c.nextTick(function(){x(a,d,f,h)}):x(a,d,f,h)}}function x(a,b,c,d){!c&&0===b.length&&b.needDrain&&(b.needDrain=!1,a.emit("drain"));b.pendingcb--;d();D(a,b)}function u(a,b){b.bufferProcessing=!0;if(a._writev&&1<b.buffer.length){for(var c=[],e=0;e<b.buffer.length;e++)c.push(b.buffer[e].callback);
b.pendingcb++;d(a,b,!0,b.length,b.buffer,"",function(a){for(var d=0;d<c.length;d++)b.pendingcb--,c[d](a)});b.buffer=[]}else{for(e=0;e<b.buffer.length;e++){var h=b.buffer[e],f=h.chunk;d(a,b,!1,b.objectMode?1:f.length,f,h.encoding,h.callback);if(b.writing){e++;break}}e<b.buffer.length?b.buffer=b.buffer.slice(e):b.buffer.length=0}b.bufferProcessing=!1}function D(a,b){var c=b.ending&&0===b.length&&!b.finished&&!b.writing;c&&(0===b.pendingcb?(b.prefinished||(b.prefinished=!0,a.emit("prefinish")),b.finished=
!0,a.emit("finish")):b.prefinished||(b.prefinished=!0,a.emit("prefinish")));return c}m.exports=e;var E=f("buffer").Buffer;e.WritableState=b;var w=f("core-util-is");w.inherits=f("inherits");var A=f("stream");w.inherits(e,A);e.prototype.pipe=function(){this.emit("error",Error("Cannot pipe. Not readable."))};e.prototype.write=function(b,c,d){var e=this._writableState,f=!1;w.isFunction(c)&&(d=c,c=null);w.isBuffer(b)?c="buffer":c||(c=e.defaultEncoding);w.isFunction(d)||(d=function(){});e.ended?k(this,
e,d):a(this,e,b,d)&&(e.pendingcb++,f=h(this,e,b,c,d));return f};e.prototype.cork=function(){this._writableState.corked++};e.prototype.uncork=function(){var a=this._writableState;a.corked&&(a.corked--,a.writing||a.corked||a.finished||a.bufferProcessing||!a.buffer.length||u(this,a))};e.prototype._write=function(a,b,c){c(Error("not implemented"))};e.prototype._writev=null;e.prototype.end=function(a,b,d){var e=this._writableState;w.isFunction(a)?(d=a,b=a=null):w.isFunction(b)&&(d=b,b=null);w.isNullOrUndefined(a)||
this.write(a,b);e.corked&&(e.corked=1,this.uncork());if(!e.ending&&!e.finished){a=d;e.ending=!0;D(this,e);if(a)if(e.finished)c.nextTick(a);else this.once("finish",a);e.ended=!0}}}).call(this,f("_process"))},{"./_stream_duplex":53,_process:51,buffer:43,"core-util-is":58,inherits:48,stream:63}],58:[function(f,m,g){(function(c){function f(b){return"object"===typeof b&&null!==b}g.isArray=function(b){return Array.isArray(b)};g.isBoolean=function(b){return"boolean"===typeof b};g.isNull=function(b){return null===
b};g.isNullOrUndefined=function(b){return null==b};g.isNumber=function(b){return"number"===typeof b};g.isString=function(b){return"string"===typeof b};g.isSymbol=function(b){return"symbol"===typeof b};g.isUndefined=function(b){return void 0===b};g.isRegExp=function(b){return f(b)&&"[object RegExp]"===Object.prototype.toString.call(b)};g.isObject=f;g.isDate=function(b){return f(b)&&"[object Date]"===Object.prototype.toString.call(b)};g.isError=function(b){return f(b)&&("[object Error]"===Object.prototype.toString.call(b)||
b instanceof Error)};g.isFunction=function(b){return"function"===typeof b};g.isPrimitive=function(b){return null===b||"boolean"===typeof b||"number"===typeof b||"string"===typeof b||"symbol"===typeof b||"undefined"===typeof b};g.isBuffer=function(b){return c.isBuffer(b)}}).call(this,f("buffer").Buffer)},{buffer:43}],59:[function(f,m,g){m.exports=f("./lib/_stream_passthrough.js")},{"./lib/_stream_passthrough.js":54}],60:[function(f,m,g){g=m.exports=f("./lib/_stream_readable.js");g.Stream=f("stream");
g.Readable=g;g.Writable=f("./lib/_stream_writable.js");g.Duplex=f("./lib/_stream_duplex.js");g.Transform=f("./lib/_stream_transform.js");g.PassThrough=f("./lib/_stream_passthrough.js")},{"./lib/_stream_duplex.js":53,"./lib/_stream_passthrough.js":54,"./lib/_stream_readable.js":55,"./lib/_stream_transform.js":56,"./lib/_stream_writable.js":57,stream:63}],61:[function(f,m,g){m.exports=f("./lib/_stream_transform.js")},{"./lib/_stream_transform.js":56}],62:[function(f,m,g){m.exports=f("./lib/_stream_writable.js")},
{"./lib/_stream_writable.js":57}],63:[function(f,m,g){function c(){l.call(this)}m.exports=c;var l=f("events").EventEmitter;f("inherits")(c,l);c.Readable=f("readable-stream/readable.js");c.Writable=f("readable-stream/writable.js");c.Duplex=f("readable-stream/duplex.js");c.Transform=f("readable-stream/transform.js");c.PassThrough=f("readable-stream/passthrough.js");c.Stream=c;c.prototype.pipe=function(b,c){function f(a){b.writable&&!1===b.write(a)&&q.pause&&q.pause()}function a(){q.readable&&q.resume&&
q.resume()}function h(){x||(x=!0,b.end())}function d(){x||(x=!0,"function"===typeof b.destroy&&b.destroy())}function g(a){m();if(0===l.listenerCount(this,"error"))throw a;}function m(){q.removeListener("data",f);b.removeListener("drain",a);q.removeListener("end",h);q.removeListener("close",d);q.removeListener("error",g);b.removeListener("error",g);q.removeListener("end",m);q.removeListener("close",m);b.removeListener("close",m)}var q=this;q.on("data",f);b.on("drain",a);b._isStdio||c&&!1===c.end||
(q.on("end",h),q.on("close",d));var x=!1;q.on("error",g);b.on("error",g);q.on("end",m);q.on("close",m);b.on("close",m);b.emit("pipe",q);return b}},{events:47,inherits:48,"readable-stream/duplex.js":52,"readable-stream/passthrough.js":59,"readable-stream/readable.js":60,"readable-stream/transform.js":61,"readable-stream/writable.js":62}],64:[function(f,m,g){function c(a){return a.toString(this.encoding)}function l(a){this.charLength=(this.charReceived=a.length%2)?2:0}function b(a){this.charLength=
(this.charReceived=a.length%3)?3:0}var e=f("buffer").Buffer,k=e.isEncoding||function(a){switch(a&&a.toLowerCase()){case "hex":case "utf8":case "utf-8":case "ascii":case "binary":case "base64":case "ucs2":case "ucs-2":case "utf16le":case "utf-16le":case "raw":return!0;default:return!1}};f=g.StringDecoder=function(a){this.encoding=(a||"utf8").toLowerCase().replace(/[-_]/,"");if(a&&!k(a))throw Error("Unknown encoding: "+a);switch(this.encoding){case "utf8":this.surrogateSize=3;break;case "ucs2":case "utf16le":this.surrogateSize=
2;this.detectIncompleteChar=l;break;case "base64":this.surrogateSize=3;this.detectIncompleteChar=b;break;default:this.write=c;return}this.charBuffer=new e(6);this.charLength=this.charReceived=0};f.prototype.write=function(a){for(var b="";this.charLength;){b=a.length>=this.charLength-this.charReceived?this.charLength-this.charReceived:a.length;a.copy(this.charBuffer,this.charReceived,0,b);this.charReceived+=b;if(this.charReceived<this.charLength)return"";a=a.slice(b,a.length);var b=this.charBuffer.slice(0,
this.charLength).toString(this.encoding),c=b.charCodeAt(b.length-1);if(55296<=c&&56319>=c)this.charLength+=this.surrogateSize,b="";else{this.charReceived=this.charLength=0;if(0===a.length)return b;break}}this.detectIncompleteChar(a);var e=a.length;this.charLength&&(a.copy(this.charBuffer,0,a.length-this.charReceived,e),e-=this.charReceived);b+=a.toString(this.encoding,0,e);e=b.length-1;c=b.charCodeAt(e);return 55296<=c&&56319>=c?(c=this.surrogateSize,this.charLength+=c,this.charReceived+=c,this.charBuffer.copy(this.charBuffer,
c,0,c),a.copy(this.charBuffer,0,0,c),b.substring(0,e)):b};f.prototype.detectIncompleteChar=function(a){for(var b=3<=a.length?3:a.length;0<b;b--){var c=a[a.length-b];if(1==b&&6==c>>5){this.charLength=2;break}if(2>=b&&14==c>>4){this.charLength=3;break}if(3>=b&&30==c>>3){this.charLength=4;break}}this.charReceived=b};f.prototype.end=function(a){var b="";a&&a.length&&(b=this.write(a));this.charReceived&&(a=this.encoding,b+=this.charBuffer.slice(0,this.charReceived).toString(a));return b}},{buffer:43}],
65:[function(f,m,g){m.exports=function(c){return c&&"object"===typeof c&&"function"===typeof c.copy&&"function"===typeof c.fill&&"function"===typeof c.readUInt8}},{}],66:[function(f,m,g){(function(c,l){function b(a,b){var c={seen:[],stylize:k};3<=arguments.length&&(c.depth=arguments[2]);4<=arguments.length&&(c.colors=arguments[3]);D(b)?c.showHidden=b:b&&g._extend(c,b);A(c.showHidden)&&(c.showHidden=!1);A(c.depth)&&(c.depth=2);A(c.colors)&&(c.colors=!1);A(c.customInspect)&&(c.customInspect=!0);c.colors&&
(c.stylize=e);return h(c,a,c.depth)}function e(a,c){var d=b.styles[c];return d?"\u001b["+b.colors[d][0]+"m"+a+"\u001b["+b.colors[d][1]+"m":a}function k(a,b){return a}function a(a){var b={};a.forEach(function(a,c){b[a]=!0});return b}function h(b,c,e){if(b.customInspect&&c&&n(c.inspect)&&c.inspect!==g.inspect&&(!c.constructor||c.constructor.prototype!==c)){var f=c.inspect(e,b);w(f)||(f=h(b,f,e));return f}if(f=d(b,c))return f;var k=Object.keys(c),l=a(k);b.showHidden&&(k=Object.getOwnPropertyNames(c));
if(z(c)&&(0<=k.indexOf("message")||0<=k.indexOf("description")))return m(c);if(0===k.length){if(n(c))return b.stylize("[Function"+(c.name?": "+c.name:"")+"]","special");if(F(c))return b.stylize(RegExp.prototype.toString.call(c),"regexp");if(y(c))return b.stylize(Date.prototype.toString.call(c),"date");if(z(c))return m(c)}var f="",G=!1,v=["{","}"];u(c)&&(G=!0,v=["[","]"]);n(c)&&(f=" [Function"+(c.name?": "+c.name:"")+"]");F(c)&&(f=" "+RegExp.prototype.toString.call(c));y(c)&&(f=" "+Date.prototype.toUTCString.call(c));
z(c)&&(f=" "+m(c));if(0===k.length&&(!G||0==c.length))return v[0]+f+v[1];if(0>e)return F(c)?b.stylize(RegExp.prototype.toString.call(c),"regexp"):b.stylize("[Object]","special");b.seen.push(c);k=G?r(b,c,e,l,k):k.map(function(a){return q(b,c,e,l,a,G)});b.seen.pop();return x(k,f,v)}function d(a,b){if(A(b))return a.stylize("undefined","undefined");if(w(b)){var c="'"+JSON.stringify(b).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return a.stylize(c,"string")}if(E(b))return a.stylize(""+
b,"number");if(D(b))return a.stylize(""+b,"boolean");if(null===b)return a.stylize("null","null")}function m(a){return"["+Error.prototype.toString.call(a)+"]"}function r(a,b,c,d,e){for(var h=[],f=0,k=b.length;f<k;++f)Object.prototype.hasOwnProperty.call(b,String(f))?h.push(q(a,b,c,d,String(f),!0)):h.push("");e.forEach(function(e){e.match(/^\d+$/)||h.push(q(a,b,c,d,e,!0))});return h}function q(a,b,c,d,e,f){var k,g;b=Object.getOwnPropertyDescriptor(b,e)||{value:b[e]};b.get?g=b.set?a.stylize("[Getter/Setter]",
"special"):a.stylize("[Getter]","special"):b.set&&(g=a.stylize("[Setter]","special"));Object.prototype.hasOwnProperty.call(d,e)||(k="["+e+"]");g||(0>a.seen.indexOf(b.value)?(g=null===c?h(a,b.value,null):h(a,b.value,c-1),-1<g.indexOf("\n")&&(g=f?g.split("\n").map(function(a){return" "+a}).join("\n").substr(2):"\n"+g.split("\n").map(function(a){return" "+a}).join("\n"))):g=a.stylize("[Circular]","special"));if(A(k)){if(f&&e.match(/^\d+$/))return g;k=JSON.stringify(""+e);k.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?
(k=k.substr(1,k.length-2),k=a.stylize(k,"name")):(k=k.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),k=a.stylize(k,"string"))}return k+": "+g}function x(a,b,c){var d=0;return 60<a.reduce(function(a,b){d++;0<=b.indexOf("\n")&&d++;return a+b.replace(/\u001b\[\d\d?m/g,"").length+1},0)?c[0]+(""===b?"":b+"\n ")+" "+a.join(",\n ")+" "+c[1]:c[0]+b+" "+a.join(", ")+" "+c[1]}function u(a){return Array.isArray(a)}function D(a){return"boolean"===typeof a}function E(a){return"number"===typeof a}
function w(a){return"string"===typeof a}function A(a){return void 0===a}function F(a){return B(a)&&"[object RegExp]"===Object.prototype.toString.call(a)}function B(a){return"object"===typeof a&&null!==a}function y(a){return B(a)&&"[object Date]"===Object.prototype.toString.call(a)}function z(a){return B(a)&&("[object Error]"===Object.prototype.toString.call(a)||a instanceof Error)}function n(a){return"function"===typeof a}function p(a){return 10>a?"0"+a.toString(10):a.toString(10)}function G(){var a=
new Date,b=[p(a.getHours()),p(a.getMinutes()),p(a.getSeconds())].join(":");return[a.getDate(),C[a.getMonth()],b].join(" ")}var J=/%[sdj%]/g;g.format=function(a){if(!w(a)){for(var c=[],d=0;d<arguments.length;d++)c.push(b(arguments[d]));return c.join(" ")}for(var d=1,e=arguments,h=e.length,c=String(a).replace(J,function(a){if("%%"===a)return"%";if(d>=h)return a;switch(a){case "%s":return String(e[d++]);case "%d":return Number(e[d++]);case "%j":try{return JSON.stringify(e[d++])}catch(b){return"[Circular]"}default:return a}}),
f=e[d];d<h;f=e[++d])c=null!==f&&B(f)?c+(" "+b(f)):c+(" "+f);return c};g.deprecate=function(a,b){if(A(l.process))return function(){return g.deprecate(a,b).apply(this,arguments)};if(!0===c.noDeprecation)return a;var d=!1;return function(){if(!d){if(c.throwDeprecation)throw Error(b);c.traceDeprecation?console.trace(b):console.error(b);d=!0}return a.apply(this,arguments)}};var v={},K;g.debuglog=function(a){A(K)&&(K=c.env.NODE_DEBUG||"");a=a.toUpperCase();if(!v[a])if((new RegExp("\\b"+a+"\\b","i")).test(K)){var b=
c.pid;v[a]=function(){var c=g.format.apply(g,arguments);console.error("%s %d: %s",a,b,c)}}else v[a]=function(){};return v[a]};g.inspect=b;b.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]};b.styles={special:"cyan",number:"yellow","boolean":"yellow",undefined:"grey","null":"bold",string:"green",date:"magenta",regexp:"red"};g.isArray=u;g.isBoolean=D;g.isNull=
function(a){return null===a};g.isNullOrUndefined=function(a){return null==a};g.isNumber=E;g.isString=w;g.isSymbol=function(a){return"symbol"===typeof a};g.isUndefined=A;g.isRegExp=F;g.isObject=B;g.isDate=y;g.isError=z;g.isFunction=n;g.isPrimitive=function(a){return null===a||"boolean"===typeof a||"number"===typeof a||"string"===typeof a||"symbol"===typeof a||"undefined"===typeof a};g.isBuffer=f("./support/isBuffer");var C="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" ");g.log=function(){console.log("%s - %s",
G(),g.format.apply(g,arguments))};g.inherits=f("inherits");g._extend=function(a,b){if(!b||!B(b))return a;for(var c=Object.keys(b),d=c.length;d--;)a[c[d]]=b[c[d]];return a}}).call(this,f("_process"),"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{})},{"./support/isBuffer":65,_process:51,inherits:48}],67:[function(f,m,g){(function(c,f){function b(a,b,c){if(Array.prototype.map)return Array.prototype.map.call(a,b,c);for(var d=Array(a.length),e=0,f=
a.length;e<f;e++)d[e]=b.call(c,a[e],e,a);return d}function e(a){for(var b=[],c=0;c<a.length;c++)a[c]&&b.push(a[c]);return b}function k(a){a=a.replace(/&/g,"&amp;");a=a.replace(/</g,"&lt;");a=a.replace(/>/g,"&gt;");return a=a.replace(/"/g,"&quot;")}function a(b,c,d){c=c||[];d=d||[];var e;for(e=0;e<c.length;e+=1)if(c[e]===b)return d[e];var f;if("[object Array]"===g.call(b)){c.push(b);f=Array(b.length);d.push(f);for(e=0;e<b.length;e+=1)f[e]=a(b[e],c,d);c.pop();d.pop()}else if("object"===typeof b&&null!==
b){c.push(b);f={};d.push(f);var h=[],k;for(k in b)h.push(k);h.sort();for(e=0;e<h.length;e+=1)k=h[e],f[k]=a(b[k],c,d);c.pop();d.pop()}else f=b;return f}function h(a,c,d,e){for(var f=0,h=a.length,k=0,g=0;f<h;f++){var l=a[f];if(l.removed)l.value=d.slice(g,g+l.count).join(""),g+=l.count,f&&a[f-1].added&&(l=a[f-1],a[f-1]=a[f],a[f]=l);else{if(!l.added&&e){var m=c.slice(k,k+l.count),m=b(m,function(a,b){var c=d[g+b];return c.length>a.length?c:a});l.value=m.join("")}else l.value=c.slice(k,k+l.count).join("");
k+=l.count;l.added||(g+=l.count)}}return a}function d(a){this.ignoreWhitespace=a}var g=Object.prototype.toString;d.prototype={diff:function(a,b,c){function d(a){return c?(setTimeout(function(){c(f,a)},0),!0):a}function e(){for(var c=-1*t;c<=t;c+=2){var G;G=r[c-1];var n=r[c+1],u=(n?n.newPos:0)-c;G&&(r[c-1]=f);var D=G&&G.newPos+1<g,u=n&&0<=u&&u<m;if(D||u){!D||u&&G.newPos<n.newPos?(G={newPos:n.newPos,components:n.components.slice(0)},k.pushComponent(G.components,f,!0)):(G.newPos++,k.pushComponent(G.components,
!0,f));u=k.extractCommon(G,b,a,c);if(G.newPos+1>=g&&u+1>=m)return d(h(G.components,b,a,k.useLongestToken));r[c]=G}else r[c]=f}t++}var k=this;if(b===a)return d([{value:b}]);if(!b)return d([{value:a,removed:!0}]);if(!a)return d([{value:b,added:!0}]);b=this.tokenize(b);a=this.tokenize(a);var g=b.length,m=a.length,t=1,u=g+m,r=[{newPos:-1,components:[]}],D=this.extractCommon(r[0],b,a,0);if(r[0].newPos+1>=g&&D+1>=m)return d([{value:b.join("")}]);if(c)(function M(){setTimeout(function(){if(t>u)return c();
e()||M()},0)})();else for(;t<=u;)if(D=e())return D},pushComponent:function(a,b,c){var d=a[a.length-1];d&&d.added===b&&d.removed===c?a[a.length-1]={count:d.count+1,added:b,removed:c}:a.push({count:1,added:b,removed:c})},extractCommon:function(a,b,c,d){var e=b.length,f=c.length,h=a.newPos;d=h-d;for(var k=0;h+1<e&&d+1<f&&this.equals(b[h+1],c[d+1]);)h++,d++,k++;k&&a.components.push({count:k});a.newPos=h;return d},equals:function(a,b){var c=/\S/;return a===b||this.ignoreWhitespace&&!c.test(a)&&!c.test(b)},
tokenize:function(a){return a.split("")}};var r=new d,q=new d(!0),x=new d;q.tokenize=x.tokenize=function(a){return e(a.split(/(\s+|\b)/))};var u=new d(!0);u.tokenize=function(a){return e(a.split(/([{}:;,]|\s+)/))};var D=new d,E=new d;E.ignoreTrim=!0;D.tokenize=E.tokenize=function(a){var b=[];a=a.split(/^/m);for(var c=0;c<a.length;c++){var d=a[c],e=a[c-1],e=e&&e[e.length-1];"\n"===d&&"\r"===e?b[b.length-1]=b[b.length-1].slice(0,-1)+"\r\n":(this.ignoreTrim&&(d=d.trim(),c<a.length-1&&(d+="\n")),b.push(d))}return b};
var w=new d;w.tokenize=function(a){var b=[];a=a.split(/(\n|\r\n)/);a[a.length-1]||a.pop();for(var c=0;c<a.length;c++){var d=a[c];c%2?b[b.length-1]+=d:b.push(d)}return b};var A=new d;A.tokenize=function(a){return e(a.split(/(\S.+?[.!?])(?=\s+|$)/))};var F=new d;F.useLongestToken=!0;F.tokenize=D.tokenize;F.equals=function(a,b){return D.equals(a.replace(/,([\r\n])/g,"$1"),b.replace(/,([\r\n])/g,"$1"))};var B={Diff:d,diffChars:function(a,b,c){return r.diff(a,b,c)},diffWords:function(a,b,c){return q.diff(a,
b,c)},diffWordsWithSpace:function(a,b,c){return x.diff(a,b,c)},diffLines:function(a,b,c){return D.diff(a,b,c)},diffTrimmedLines:function(a,b,c){return E.diff(a,b,c)},diffSentences:function(a,b,c){return A.diff(a,b,c)},diffCss:function(a,b,c){return u.diff(a,b,c)},diffJson:function(b,c,d){return F.diff("string"===typeof b?b:JSON.stringify(a(b),f," "),"string"===typeof c?c:JSON.stringify(a(c),f," "),d)},createTwoFilesPatch:function(a,c,d,e,f,h){function k(a){return b(a,function(a){return" "+a})}function g(a,
b,c){var d=m[m.length-2],e=b===m.length-2;b=b===m.length-3&&c.added!==d.added;/\n$/.test(c.value)||!e&&!b||a.push("\\ No newline at end of file")}var l=[];a==c&&l.push("Index: "+a);l.push("===================================================================");l.push("--- "+a+("undefined"===typeof f?"":"\t"+f));l.push("+++ "+c+("undefined"===typeof h?"":"\t"+h));var m=w.diff(d,e);m.push({value:"",lines:[]});c=a=0;d=[];f=e=1;for(h=0;h<m.length;h++){var t=m[h],u=t.lines||t.value.replace(/\n$/,"").split("\n");
t.lines=u;if(t.added||t.removed){if(!a){var r=m[h-1];a=e;c=f;r&&(d=k(r.lines.slice(-4)),a-=d.length,c-=d.length)}d.push.apply(d,b(u,function(a){return(t.added?"+":"-")+a}));g(d,h,t);t.added?f+=u.length:e+=u.length}else a&&(8>=u.length&&h<m.length-2?d.push.apply(d,k(u)):(r=Math.min(u.length,4),l.push("@@ -"+a+","+(e-a+r)+" +"+c+","+(f-c+r)+" @@"),l.push.apply(l,d),l.push.apply(l,k(u.slice(0,r))),4>=u.length&&g(l,h,t),c=a=0,d=[])),e+=u.length,f+=u.length}return l.join("\n")+"\n"},createPatch:function(a,
b,c,d,e){return B.createTwoFilesPatch(a,a,b,c,d,e)},applyPatch:function(a,b){for(var c=b.split("\n"),d=[],e=0,f=!1,h=!1;e<c.length&&!/^@@/.test(c[e]);)e++;for(;e<c.length;e++)if("@"===c[e][0]){var k=c[e].split(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/);d.unshift({start:k[3],oldlength:+k[2],removed:[],newlength:k[4],added:[]})}else"+"===c[e][0]?d[0].added.push(c[e].substr(1)):"-"===c[e][0]?d[0].removed.push(c[e].substr(1)):" "===c[e][0]?(d[0].added.push(c[e].substr(1)),d[0].removed.push(c[e].substr(1))):
"\\"===c[e][0]&&("+"===c[e-1][0]?f=!0:"-"===c[e-1][0]&&(h=!0));c=a.split("\n");for(e=d.length-1;0<=e;e--){for(var k=d[e],g=0;g<k.oldlength;g++)if(c[k.start-1+g]!==k.removed[g])return!1;Array.prototype.splice.apply(c,[k.start-1,k.oldlength].concat(k.added))}if(f)for(;!c[c.length-1];)c.pop();else h&&c.push("");return c.join("\n")},convertChangesToXML:function(a){for(var b=[],c=0;c<a.length;c++){var d=a[c];d.added?b.push("<ins>"):d.removed&&b.push("<del>");b.push(k(d.value));d.added?b.push("</ins>"):
d.removed&&b.push("</del>")}return b.join("")},convertChangesToDMP:function(a){for(var b=[],c,d,e=0;e<a.length;e++)c=a[e],d=c.added?1:c.removed?-1:0,b.push([d,c.value]);return b},canonicalize:a};"undefined"!==typeof m&&m.exports?m.exports=B:"function"===typeof define&&define.amd?define([],function(){return B}):"undefined"===typeof c.JsDiff&&(c.JsDiff=B)})(this)},{}],68:[function(f,m,g){var c=/[|\\{}()[\]^$+*?.]/g;m.exports=function(f){if("string"!==typeof f)throw new TypeError("Expected a string");
return f.replace(c,"\\$&")}},{}],69:[function(f,m,g){(function(c){function l(b){for(var d=c.env.PATH.split(":"),e,f=0,h=d.length;f<h;++f)if(e=k.join(d[f],b),a(e))return e}var b=f("child_process").exec,e=f("fs"),k=f("path"),a=e.existsSync||k.existsSync,e=f("os"),h=JSON.stringify,d;switch(e.type()){case "Darwin":d=l("terminal-notifier")?{type:"Darwin-NotificationCenter",pkg:"terminal-notifier",msg:"-message",title:"-title",subtitle:"-subtitle",priority:{cmd:"-execute",range:[]}}:{type:"Darwin-Growl",
pkg:"growlnotify",msg:"-m",sticky:"--sticky",priority:{cmd:"--priority",range:[-2,-1,0,1,2,"Very Low","Moderate","Normal","High","Emergency"]}};break;case "Linux":d={type:"Linux",pkg:"notify-send",msg:"",sticky:"-t 0",icon:"-i",priority:{cmd:"-u",range:["low","normal","critical"]}};break;case "Windows_NT":d={type:"Windows",pkg:"growlnotify",msg:"",sticky:"/s:true",title:"/t:",icon:"/i:",priority:{cmd:"/p:",range:[-2,-1,0,1,2]}}}g=m.exports=function(a,c,e){var f,g;c=c||{};e=e||function(){};if(!d)return e(Error("growl not supported on this platform"));
g=[d.pkg];if(f=c.image)switch(d.type){case "Darwin-Growl":var l,m=k.extname(f).substr(1);l=(l=(l=(l=l||"icns"==m&&"iconpath"||/^[A-Z]/.test(f)&&"appIcon")||/^png|gif|jpe?g$/.test(m)&&"image")||m&&(f=m)&&"icon")||"icon";g.push("--"+l,h(f));break;case "Linux":g.push(d.icon,h(f));c.sticky||g.push("--hint=int:transient:1");break;case "Windows":g.push(d.icon+h(f))}c.sticky&&g.push(d.sticky);c.priority&&(f=c.priority+"",d.priority.range.indexOf(f),~d.priority.range.indexOf(f)&&g.push(d.priority,c.priority));
c.name&&"Darwin-Growl"===d.type&&g.push("--name",c.name);switch(d.type){case "Darwin-Growl":g.push(d.msg);g.push(h(a));c.title&&g.push(h(c.title));break;case "Darwin-NotificationCenter":g.push(d.msg);g.push(h(a));c.title&&(g.push(d.title),g.push(h(c.title)));c.subtitle&&(g.push(d.subtitle),g.push(h(c.subtitle)));break;case "Darwin-Growl":g.push(d.msg);g.push(h(a));c.title&&g.push(h(c.title));break;case "Linux":c.title&&(g.push(h(c.title)),g.push(d.msg));g.push(h(a));break;case "Windows":g.push(h(a)),
c.title&&g.push(d.title+h(c.title))}b(g.join(" "),e)};g.version="1.4.1"}).call(this,f("_process"))},{_process:51,child_process:41,fs:41,os:50,path:41}],70:[function(f,m,g){(function(c){function g(f,a,h,d){"function"===typeof a?(h=a,a={}):a&&"object"===typeof a||(a={mode:a});var m=a.mode,r=a.fs||e;void 0===m&&(m=511&~c.umask());d||(d=null);var q=h||function(){};f=b.resolve(f);r.mkdir(f,m,function(c){if(!c)return d=d||f,q(null,d);switch(c.code){case "ENOENT":g(b.dirname(f),a,function(b,c){b?q(b,c):
g(f,a,q,c)});break;default:r.stat(f,function(a,b){a||!b.isDirectory()?q(c,d):q(null,d)})}})}var b=f("path"),e=f("fs");m.exports=g.mkdirp=g.mkdirP=g;g.sync=function a(f,d,g){d&&"object"===typeof d||(d={mode:d});var l=d.mode,m=d.fs||e;void 0===l&&(l=511&~c.umask());g||(g=null);f=b.resolve(f);try{m.mkdirSync(f,l),g=g||f}catch(u){switch(u.code){case "ENOENT":g=a(b.dirname(f),d,g);a(f,d,g);break;default:var x;try{x=m.statSync(f)}catch(D){throw u;}if(!x.isDirectory())throw u;}}return g}}).call(this,f("_process"))},
{_process:51,fs:41,path:41}],71:[function(f,m,g){(function(c,g){function b(){for(var c=(new a).getTime();r.length&&100>(new a).getTime()-c;)r.shift()();q=r.length?h(b,0):null}c.stdout=f("browser-stdout")();var e=f("../"),k=new e({reporter:"html"}),a=g.Date,h=g.setTimeout,d=[],m=g.onerror;c.removeListener=function(a,b){if("uncaughtException"==a){g.onerror=m?m:function(){};var c=e.utils.indexOf(d,b);-1!=c&&d.splice(c,1)}};c.on=function(a,b){"uncaughtException"==a&&(g.onerror=function(a,c,d){b(Error(a+
" ("+c+":"+d+")"));return!k.allowUncaught},d.push(b))};k.suite.removeAllListeners("pre-require");var r=[],q;e.Runner.immediately=function(a){r.push(a);q||(q=h(b,0))};k.throwError=function(a){e.utils.forEach(d,function(b){b(a)});throw a;};k.ui=function(a){e.prototype.ui.call(this,a);this.suite.emit("pre-require",g,null,this);return this};k.setup=function(a){"string"==typeof a&&(a={ui:a});for(var b in a)this[b](a[b]);return this};k.run=function(a){var b=k.options;k.globals("location");var c=e.utils.parseQuery(g.location.search||
"");c.grep&&k.grep(new RegExp(c.grep));c.fgrep&&k.grep(c.fgrep);c.invert&&k.invert();return e.prototype.run.call(k,function(c){var d=g.document;d&&d.getElementById("mocha")&&!0!==b.noHighlighting&&e.utils.highlightTags("code");a&&a(c)})};e.process=c;g.Mocha=e;g.mocha=k}).call(this,f("_process"),"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{})},{"../":1,_process:51,"browser-stdout":40}]},{},[71]);(function(){function f(m){var g=f.modules[m];if(!g)throw Error('failed to require "'+m+'"');"exports"in g||"function"!==typeof g.definition||(g.client=g.component=!0,g.definition.call(this,g.exports={},g),delete g.definition);return g.exports}f.loader="component";f.helper={};f.helper.semVerSort=function(f,g){for(var c=f.version.split("."),l=g.version.split("."),b=0;b<c.length;++b){var e=parseInt(c[b],10),k=parseInt(l[b],10);if(e===k){e=c[b].substr((""+e).length);k=l[b].substr((""+k).length);if(""===
e&&""!==k)return 1;if(""!==e&&""===k)return-1;if(""!==e&&""!==k)return e>k?1:-1}else return e>k?1:-1}return 0};f.latest=function(m,g){function c(a){throw Error('failed to find latest module of "'+a+'"');}var l=/(.*)~(.*)@v?(\d+\.\d+\.\d+[^\/]*)$/;/(.*)~(.*)/.test(m)||c(m);for(var b=Object.keys(f.modules),e=[],k=[],a=0;a<b.length;a++){var h=b[a];if((new RegExp(m+"@")).test(h)){var d=h.substr(m.length+1);null!=l.exec(h)?e.push({version:d,name:h}):k.push({version:d,name:h})}}0===e.concat(k).length&&
c(m);if(0<e.length)return l=e.sort(f.helper.semVerSort).pop().name,!0===g?l:f(l);l=k.sort(function(a,b){return a.name>b.name})[0].name;return!0===g?l:f(l)};f.modules={};f.register=function(m,g){f.modules[m]={definition:g}};f.define=function(m,g){f.modules[m]={exports:g}};f.register("chaijs~assertion-error@1.0.0",function(f,g){function c(){function b(b,a){Object.keys(a).forEach(function(f){~c.indexOf(f)||(b[f]=a[f])})}var c=[].slice.call(arguments);return function(){for(var c=[].slice.call(arguments),
a=0,e={};a<c.length;a++)b(e,c[a]);return e}}function l(b,e,f){var a=c("name","message","stack","constructor","toJSON")(e||{});this.message=b||"Unspecified AssertionError";this.showDiff=!1;for(var h in a)this[h]=a[h];(f=f||arguments.callee)&&Error.captureStackTrace&&Error.captureStackTrace(this,f)}g.exports=l;l.prototype=Object.create(Error.prototype);l.prototype.name="AssertionError";l.prototype.constructor=l;l.prototype.toJSON=function(b){var e=c("constructor","toJSON","stack")({name:this.name},
this);!1!==b&&this.stack&&(e.stack=this.stack);return e}});f.register("chaijs~type-detect@0.1.1",function(f,g){function c(c){var f=Object.prototype.toString.call(c);return b[f]?b[f]:null===c?"null":void 0===c?"undefined":c===Object(c)?"object":typeof c}function l(){this.tests={}}f=g.exports=c;var b={"[object Array]":"array","[object RegExp]":"regexp","[object Function]":"function","[object Arguments]":"arguments","[object Date]":"date"};f.Library=l;l.prototype.of=c;l.prototype.define=function(b,c){if(1===
arguments.length)return this.tests[b];this.tests[b]=c;return this};l.prototype.test=function(b,f){if(f===c(b))return!0;var a=this.tests[f];if(a&&"regexp"===c(a))return a.test(b);if(a&&"function"===c(a))return a(b);throw new ReferenceError('Type test "'+f+'" not defined or invalid.');}});f.register("chaijs~deep-eql@0.1.3",function(m,g){function c(b,f,g){return l(b,f)?!0:"date"===a(b)?(g="date"!==a(f)?!1:l(b.getTime(),f.getTime()),g):"regexp"===a(b)?(g="regexp"!==a(f)?!1:l(b.toString(),f.toString()),
g):h.isBuffer(b)?(g=h.isBuffer(f)?e(b,f):!1,g):"arguments"===a(b)?("arguments"!==a(f)?g=!1:(b=[].slice.call(b),f=[].slice.call(f),g=c(b,f,g)),g):a(b)!==a(f)?!1:"object"!==a(b)&&"object"!==a(f)&&"array"!==a(b)&&"array"!==a(f)?l(b,f):k(b,f,g)}function l(a,b){return a===b?0!==a||1/a===1/b:a!==a&&b!==b}function b(a){var b=[],c;for(c in a)b.push(c);return b}function e(a,b){if(a.length!==b.length)return!1;for(var c=0,e=!0;c<a.length;c++)if(a[c]!==b[c]){e=!1;break}return e}function k(a,f,h){if(null===a||
void 0===a||null===f||void 0===f||a.prototype!==f.prototype)return!1;var g;if(h)for(g=0;g<h.length;g++){if(h[g][0]===a&&h[g][1]===f||h[g][0]===f&&h[g][1]===a)return!0}else h=[];try{var k=b(a),l=b(f)}catch(m){return!1}k.sort();l.sort();if(!e(k,l))return!1;h.push([a,f]);for(g=k.length-1;0<=g;g--)if(l=k[g],!c(a[l],f[l],h))return!1;return!0}var a=f("chaijs~type-detect@0.1.1"),h;try{h=f("buffer").Buffer}catch(d){h={isBuffer:function(){return!1}}}g.exports=c});f.register("chai",function(m,g){g.exports=
f("chai/lib/chai.js")});f.register("chai/lib/chai.js",function(m,g){var c=[];m=g.exports={};m.version="2.1.0";m.AssertionError=f("chaijs~assertion-error@1.0.0");var l=f("chai/lib/chai/utils/index.js");m.use=function(b){~c.indexOf(b)||(b(this,l),c.push(b));return this};m.util=l;var b=f("chai/lib/chai/config.js");m.config=b;b=f("chai/lib/chai/assertion.js");m.use(b);b=f("chai/lib/chai/core/assertions.js");m.use(b);b=f("chai/lib/chai/interface/expect.js");m.use(b);b=f("chai/lib/chai/interface/should.js");
m.use(b);b=f("chai/lib/chai/interface/assert.js");m.use(b)});f.register("chai/lib/chai/assertion.js",function(m,g){var c=f("chai/lib/chai/config.js");g.exports=function(f,b){function e(b,c,e){a(this,"ssfi",e||arguments.callee);a(this,"object",b);a(this,"message",c)}var g=f.AssertionError,a=b.flag;f.Assertion=e;Object.defineProperty(e,"includeStack",{get:function(){console.warn("Assertion.includeStack is deprecated, use chai.config.includeStack instead.");return c.includeStack},set:function(a){console.warn("Assertion.includeStack is deprecated, use chai.config.includeStack instead.");
c.includeStack=a}});Object.defineProperty(e,"showDiff",{get:function(){console.warn("Assertion.showDiff is deprecated, use chai.config.showDiff instead.");return c.showDiff},set:function(a){console.warn("Assertion.showDiff is deprecated, use chai.config.showDiff instead.");c.showDiff=a}});e.addProperty=function(a,c){b.addProperty(this.prototype,a,c)};e.addMethod=function(a,c){b.addMethod(this.prototype,a,c)};e.addChainableMethod=function(a,c,e){b.addChainableMethod(this.prototype,a,c,e)};e.overwriteProperty=
function(a,c){b.overwriteProperty(this.prototype,a,c)};e.overwriteMethod=function(a,c){b.overwriteMethod(this.prototype,a,c)};e.overwriteChainableMethod=function(a,c,e){b.overwriteChainableMethod(this.prototype,a,c,e)};e.prototype.assert=function(e,d,f,l,m,x){var u=b.test(this,arguments);!0!==x&&(x=!1);!0!==c.showDiff&&(x=!1);if(!u)throw d=b.getMessage(this,arguments),u=b.getActual(this,arguments),new g(d,{actual:u,expected:l,showDiff:x},c.includeStack?this.assert:a(this,"ssfi"));};Object.defineProperty(e.prototype,
"_obj",{get:function(){return a(this,"object")},set:function(b){a(this,"object",b)}})}});f.register("chai/lib/chai/config.js",function(f,g){g.exports={includeStack:!1,showDiff:!0,truncateThreshold:40}});f.register("chai/lib/chai/core/assertions.js",function(f,g){g.exports=function(c,f){function b(a,b){b&&p(this,"message",b);a=a.toLowerCase();var c=p(this,"object"),d=~["a","e","i","o","u"].indexOf(a.charAt(0))?"an ":"a ";this.assert(a===f.type(c),"expected #{this} to be "+d+a,"expected #{this} not to be "+
d+a)}function e(){p(this,"contains",!0)}function g(a,b){b&&p(this,"message",b);var c=p(this,"object"),d=!1;if("array"===f.type(c)&&"object"===f.type(a))for(var e in c){if(f.eql(c[e],a)){d=!0;break}}else if("object"===f.type(a)){if(!p(this,"negate")){for(var h in a)(new n(c)).property(h,a[h]);return}d={};for(h in a)d[h]=c[h];d=f.eql(d,a)}else d=c&&~c.indexOf(a);this.assert(d,"expected #{this} to include "+f.inspect(a),"expected #{this} to not include "+f.inspect(a))}function a(){var a=p(this,"object"),
a=Object.prototype.toString.call(a);this.assert("[object Arguments]"===a,"expected #{this} to be arguments but got "+a,"expected #{this} to not be arguments")}function h(a,b){b&&p(this,"message",b);var c=p(this,"object");if(p(this,"deep"))return this.eql(a);this.assert(a===c,"expected #{this} to equal #{exp}","expected #{this} to not equal #{exp}",a,this._obj,!0)}function d(a,b){b&&p(this,"message",b);this.assert(f.eql(a,p(this,"object")),"expected #{this} to deeply equal #{exp}","expected #{this} to not deeply equal #{exp}",
a,this._obj,!0)}function m(a,b){b&&p(this,"message",b);var c=p(this,"object");p(this,"doLength")?((new n(c,b)).to.have.property("length"),c=c.length,this.assert(c>a,"expected #{this} to have a length above #{exp} but got #{act}","expected #{this} to not have a length above #{exp}",a,c)):this.assert(c>a,"expected #{this} to be above "+a,"expected #{this} to be at most "+a)}function r(a,b){b&&p(this,"message",b);var c=p(this,"object");p(this,"doLength")?((new n(c,b)).to.have.property("length"),c=c.length,
this.assert(c>=a,"expected #{this} to have a length at least #{exp} but got #{act}","expected #{this} to have a length below #{exp}",a,c)):this.assert(c>=a,"expected #{this} to be at least "+a,"expected #{this} to be below "+a)}function q(a,b){b&&p(this,"message",b);var c=p(this,"object");p(this,"doLength")?((new n(c,b)).to.have.property("length"),c=c.length,this.assert(c<a,"expected #{this} to have a length below #{exp} but got #{act}","expected #{this} to not have a length below #{exp}",a,c)):this.assert(c<
a,"expected #{this} to be below "+a,"expected #{this} to be at least "+a)}function x(a,b){b&&p(this,"message",b);var c=p(this,"object");p(this,"doLength")?((new n(c,b)).to.have.property("length"),c=c.length,this.assert(c<=a,"expected #{this} to have a length at most #{exp} but got #{act}","expected #{this} to have a length above #{exp}",a,c)):this.assert(c<=a,"expected #{this} to be at most "+a,"expected #{this} to be above "+a)}function u(a,b){b&&p(this,"message",b);var c=f.getName(a);this.assert(p(this,
"object")instanceof a,"expected #{this} to be an instance of "+c,"expected #{this} to not be an instance of "+c)}function D(a,b){b&&p(this,"message",b);var c=p(this,"object");this.assert(c.hasOwnProperty(a),"expected #{this} to have own property "+f.inspect(a),"expected #{this} to not have own property "+f.inspect(a))}function E(a,b){b&&p(this,"message",b);var c=p(this,"object");(new n(c,b)).to.have.property("length");c=c.length;this.assert(c==a,"expected #{this} to have a length of #{exp} but got #{act}",
"expected #{this} to not have a length of #{act}",a,c)}function w(a){var b=p(this,"object"),c,d=!0;switch(f.type(a)){case "array":if(1<arguments.length)throw Error("keys must be given single argument of Array|Object|String, or multiple String arguments");break;case "object":if(1<arguments.length)throw Error("keys must be given single argument of Array|Object|String, or multiple String arguments");a=Object.keys(a);break;default:a=Array.prototype.slice.call(arguments)}if(!a.length)throw Error("keys required");
var e=Object.keys(b),b=a,h=a.length,g=p(this,"any"),k=p(this,"all");g||k||(k=!0);g&&(d=0<b.filter(function(a){return~e.indexOf(a)}).length);k&&(d=a.every(function(a){return~e.indexOf(a)}),p(this,"negate")||p(this,"contains")||(d=d&&a.length==e.length));if(1<h){a=a.map(function(a){return f.inspect(a)});var m=a.pop();k&&(c=a.join(", ")+", and "+m);g&&(c=a.join(", ")+", or "+m)}else c=f.inspect(a[0]);c=(1<h?"keys ":"key ")+c;c=(p(this,"contains")?"contain ":"have ")+c;this.assert(d,"expected #{this} to "+
c,"expected #{this} to not "+c,b.slice(0).sort(),e.sort(),!0)}function A(a,b,c){c&&p(this,"message",c);var d=p(this,"object");(new n(d,c)).is.a("function");var e=!1,h=null,g=null,k=null;0===arguments.length?a=b=null:a&&(a instanceof RegExp||"string"===typeof a)?(b=a,a=null):a&&a instanceof Error?(h=a,b=a=null):"function"===typeof a?(g=a.prototype.name||a.name,"Error"===g&&a!==Error&&(g=(new a).name)):a=null;try{d()}catch(m){if(h)return this.assert(m===h,"expected #{this} to throw #{exp} but #{act} was thrown",
"expected #{this} to not throw #{exp}",h instanceof Error?h.toString():h,m instanceof Error?m.toString():m),p(this,"object",m),this;if(a&&(this.assert(m instanceof a,"expected #{this} to throw #{exp} but #{act} was thrown","expected #{this} to not throw #{exp} but #{act} was thrown",g,m instanceof Error?m.toString():m),!b))return p(this,"object",m),this;e="object"===f.type(m)&&"message"in m?m.message:""+m;if(null!=e&&b&&b instanceof RegExp)return this.assert(b.exec(e),"expected #{this} to throw error matching #{exp} but got #{act}",
"expected #{this} to throw error not matching #{exp}",b,e),p(this,"object",m),this;if(null!=e&&b&&"string"===typeof b)return this.assert(~e.indexOf(b),"expected #{this} to throw error including #{exp} but got #{act}","expected #{this} to throw error not including #{act}",b,e),p(this,"object",m),this;e=!0;k=m}d="";g=null!==g?g:h?"#{exp}":"an error";e&&(d=" but #{act} was thrown");this.assert(!0===e,"expected #{this} to throw "+g+d,"expected #{this} to not throw "+g+d,h instanceof Error?h.toString():
h,k instanceof Error?k.toString():k);p(this,"object",k)}function F(a,b,c){return a.every(function(a){return c?b.some(function(b){return c(a,b)}):-1!==b.indexOf(a)})}function B(a,b,c){c&&p(this,"message",c);var d=p(this,"object");(new n(a,c)).to.have.property(b);(new n(d)).is.a("function");c=a[b];d();this.assert(c!==a[b],"expected ."+b+" to change","expected ."+b+" to not change")}function y(a,b,c){c&&p(this,"message",c);var d=p(this,"object");(new n(a,c)).to.have.property(b);(new n(d)).is.a("function");
c=a[b];d();this.assert(0<a[b]-c,"expected ."+b+" to increase","expected ."+b+" to not increase")}function z(a,b,c){c&&p(this,"message",c);var d=p(this,"object");(new n(a,c)).to.have.property(b);(new n(d)).is.a("function");c=a[b];d();this.assert(0>a[b]-c,"expected ."+b+" to decrease","expected ."+b+" to not decrease")}var n=c.Assertion,p=f.flag;"to be been is and has have with that which at of same".split(" ").forEach(function(a){n.addProperty(a,function(){return this})});n.addProperty("not",function(){p(this,
"negate",!0)});n.addProperty("deep",function(){p(this,"deep",!0)});n.addProperty("any",function(){p(this,"any",!0);p(this,"all",!1)});n.addProperty("all",function(){p(this,"all",!0);p(this,"any",!1)});n.addChainableMethod("an",b);n.addChainableMethod("a",b);n.addChainableMethod("include",g,e);n.addChainableMethod("contain",g,e);n.addChainableMethod("contains",g,e);n.addChainableMethod("includes",g,e);n.addProperty("ok",function(){this.assert(p(this,"object"),"expected #{this} to be truthy","expected #{this} to be falsy")});
n.addProperty("true",function(){this.assert(!0===p(this,"object"),"expected #{this} to be true","expected #{this} to be false",this.negate?!1:!0)});n.addProperty("false",function(){this.assert(!1===p(this,"object"),"expected #{this} to be false","expected #{this} to be true",this.negate?!0:!1)});n.addProperty("null",function(){this.assert(null===p(this,"object"),"expected #{this} to be null","expected #{this} not to be null")});n.addProperty("undefined",function(){this.assert(void 0===p(this,"object"),
"expected #{this} to be undefined","expected #{this} not to be undefined")});n.addProperty("exist",function(){this.assert(null!=p(this,"object"),"expected #{this} to exist","expected #{this} to not exist")});n.addProperty("empty",function(){var a=p(this,"object"),b=a;Array.isArray(a)||"string"===typeof object?b=a.length:"object"===typeof a&&(b=Object.keys(a).length);this.assert(!b,"expected #{this} to be empty","expected #{this} not to be empty")});n.addProperty("arguments",a);n.addProperty("Arguments",
a);n.addMethod("equal",h);n.addMethod("equals",h);n.addMethod("eq",h);n.addMethod("eql",d);n.addMethod("eqls",d);n.addMethod("above",m);n.addMethod("gt",m);n.addMethod("greaterThan",m);n.addMethod("least",r);n.addMethod("gte",r);n.addMethod("below",q);n.addMethod("lt",q);n.addMethod("lessThan",q);n.addMethod("most",x);n.addMethod("lte",x);n.addMethod("within",function(a,b,c){c&&p(this,"message",c);var d=p(this,"object"),e=a+".."+b;p(this,"doLength")?((new n(d,c)).to.have.property("length"),c=d.length,
this.assert(c>=a&&c<=b,"expected #{this} to have a length within "+e,"expected #{this} to not have a length within "+e)):this.assert(d>=a&&d<=b,"expected #{this} to be within "+e,"expected #{this} to not be within "+e)});n.addMethod("instanceof",u);n.addMethod("instanceOf",u);n.addMethod("property",function(a,b,c){c&&p(this,"message",c);var d=!!p(this,"deep"),e=d?"deep property ":"property ",h=p(this,"negate"),g=p(this,"object"),k=d?f.getPathInfo(a,g):null,m=d?k.exists:f.hasProperty(a,g),d=d?k.value:
g[a];if(h&&void 0!==b){if(void 0===d)throw Error((null!=c?c+": ":"")+f.inspect(g)+" has no "+e+f.inspect(a));}else this.assert(m,"expected #{this} to have a "+e+f.inspect(a),"expected #{this} to not have "+e+f.inspect(a));void 0!==b&&this.assert(b===d,"expected #{this} to have a "+e+f.inspect(a)+" of #{exp}, but got #{act}","expected #{this} to not have a "+e+f.inspect(a)+" of #{act}",b,d);p(this,"object",d)});n.addMethod("ownProperty",D);n.addMethod("haveOwnProperty",D);n.addChainableMethod("length",
E,function(){p(this,"doLength",!0)});n.addMethod("lengthOf",E);n.addMethod("match",function(a,b){b&&p(this,"message",b);var c=p(this,"object");this.assert(a.exec(c),"expected #{this} to match "+a,"expected #{this} not to match "+a)});n.addMethod("string",function(a,b){b&&p(this,"message",b);var c=p(this,"object");(new n(c,b)).is.a("string");this.assert(~c.indexOf(a),"expected #{this} to contain "+f.inspect(a),"expected #{this} to not contain "+f.inspect(a))});n.addMethod("keys",w);n.addMethod("key",
w);n.addMethod("throw",A);n.addMethod("throws",A);n.addMethod("Throw",A);n.addMethod("respondTo",function(a,b){b&&p(this,"message",b);var c=p(this,"object"),d=p(this,"itself"),c="function"!==f.type(c)||d?c[a]:c.prototype[a];this.assert("function"===typeof c,"expected #{this} to respond to "+f.inspect(a),"expected #{this} to not respond to "+f.inspect(a))});n.addProperty("itself",function(){p(this,"itself",!0)});n.addMethod("satisfy",function(a,b){b&&p(this,"message",b);var c=p(this,"object"),c=a(c);
this.assert(c,"expected #{this} to satisfy "+f.objDisplay(a),"expected #{this} to not satisfy"+f.objDisplay(a),this.negate?!1:!0,c)});n.addMethod("closeTo",function(a,b,c){c&&p(this,"message",c);var d=p(this,"object");(new n(d,c)).is.a("number");if("number"!==f.type(a)||"number"!==f.type(b))throw Error("the arguments to closeTo must be numbers");this.assert(Math.abs(d-a)<=b,"expected #{this} to be close to "+a+" +/- "+b,"expected #{this} not to be close to "+a+" +/- "+b)});n.addMethod("members",function(a,
b){b&&p(this,"message",b);var c=p(this,"object");(new n(c)).to.be.an("array");(new n(a)).to.be.an("array");var d=p(this,"deep")?f.eql:void 0;if(p(this,"contains"))return this.assert(F(a,c,d),"expected #{this} to be a superset of #{act}","expected #{this} to not be a superset of #{act}",c,a);this.assert(F(c,a,d)&&F(a,c,d),"expected #{this} to have the same members as #{act}","expected #{this} to not have the same members as #{act}",c,a)});n.addChainableMethod("change",B);n.addChainableMethod("changes",
B);n.addChainableMethod("increase",y);n.addChainableMethod("increases",y);n.addChainableMethod("decrease",z);n.addChainableMethod("decreases",z)}});f.register("chai/lib/chai/interface/assert.js",function(f,g){g.exports=function(c,f){var b=c.Assertion,e=f.flag,g=c.assert=function(a,e){(new b(null,null,c.assert)).assert(a,e,"[ negation message unavailable ]")};g.fail=function(a,b,d,e){throw new c.AssertionError(d||"assert.fail()",{actual:a,expected:b,operator:e},g.fail);};g.ok=function(a,c){(new b(a,
c)).is.ok};g.notOk=function(a,c){(new b(a,c)).is.not.ok};g.equal=function(a,c,d){d=new b(a,d,g.equal);d.assert(c==e(d,"object"),"expected #{this} to equal #{exp}","expected #{this} to not equal #{act}",c,a)};g.notEqual=function(a,c,d){d=new b(a,d,g.notEqual);d.assert(c!=e(d,"object"),"expected #{this} to not equal #{exp}","expected #{this} to equal #{act}",c,a)};g.strictEqual=function(a,c,d){(new b(a,d)).to.equal(c)};g.notStrictEqual=function(a,c,d){(new b(a,d)).to.not.equal(c)};g.deepEqual=function(a,
c,d){(new b(a,d)).to.eql(c)};g.notDeepEqual=function(a,c,d){(new b(a,d)).to.not.eql(c)};g.isAbove=function(a,c,d){(new b(a,d)).to.be.above(c)};g.isBelow=function(a,c,d){(new b(a,d)).to.be.below(c)};g.isTrue=function(a,c){(new b(a,c)).is["true"]};g.isFalse=function(a,c){(new b(a,c)).is["false"]};g.isNull=function(a,c){(new b(a,c)).to.equal(null)};g.isNotNull=function(a,c){(new b(a,c)).to.not.equal(null)};g.isUndefined=function(a,c){(new b(a,c)).to.equal(void 0)};g.isDefined=function(a,c){(new b(a,
c)).to.not.equal(void 0)};g.isFunction=function(a,c){(new b(a,c)).to.be.a("function")};g.isNotFunction=function(a,c){(new b(a,c)).to.not.be.a("function")};g.isObject=function(a,c){(new b(a,c)).to.be.a("object")};g.isNotObject=function(a,c){(new b(a,c)).to.not.be.a("object")};g.isArray=function(a,c){(new b(a,c)).to.be.an("array")};g.isNotArray=function(a,c){(new b(a,c)).to.not.be.an("array")};g.isString=function(a,c){(new b(a,c)).to.be.a("string")};g.isNotString=function(a,c){(new b(a,c)).to.not.be.a("string")};
g.isNumber=function(a,c){(new b(a,c)).to.be.a("number")};g.isNotNumber=function(a,c){(new b(a,c)).to.not.be.a("number")};g.isBoolean=function(a,c){(new b(a,c)).to.be.a("boolean")};g.isNotBoolean=function(a,c){(new b(a,c)).to.not.be.a("boolean")};g.typeOf=function(a,c,d){(new b(a,d)).to.be.a(c)};g.notTypeOf=function(a,c,d){(new b(a,d)).to.not.be.a(c)};g.instanceOf=function(a,c,d){(new b(a,d)).to.be.instanceOf(c)};g.notInstanceOf=function(a,c,d){(new b(a,d)).to.not.be.instanceOf(c)};g.include=function(a,
c,d){(new b(a,d,g.include)).include(c)};g.notInclude=function(a,c,d){(new b(a,d,g.notInclude)).not.include(c)};g.match=function(a,c,d){(new b(a,d)).to.match(c)};g.notMatch=function(a,c,d){(new b(a,d)).to.not.match(c)};g.property=function(a,c,d){(new b(a,d)).to.have.property(c)};g.notProperty=function(a,c,d){(new b(a,d)).to.not.have.property(c)};g.deepProperty=function(a,c,d){(new b(a,d)).to.have.deep.property(c)};g.notDeepProperty=function(a,c,d){(new b(a,d)).to.not.have.deep.property(c)};g.propertyVal=
function(a,c,d,e){(new b(a,e)).to.have.property(c,d)};g.propertyNotVal=function(a,c,d,e){(new b(a,e)).to.not.have.property(c,d)};g.deepPropertyVal=function(a,c,d,e){(new b(a,e)).to.have.deep.property(c,d)};g.deepPropertyNotVal=function(a,c,d,e){(new b(a,e)).to.not.have.deep.property(c,d)};g.lengthOf=function(a,c,d){(new b(a,d)).to.have.length(c)};g.Throw=function(a,c,d,f){if("string"===typeof c||c instanceof RegExp)d=c,c=null;a=(new b(a,f)).to.Throw(c,d);return e(a,"object")};g.doesNotThrow=function(a,
c,d){"string"===typeof c&&(d=c,c=null);(new b(a,d)).to.not.Throw(c)};g.operator=function(a,c,d,g){if(!~"== === > >= < <= != !==".split(" ").indexOf(c))throw Error('Invalid operator "'+c+'"');g=new b(eval(a+c+d),g);g.assert(!0===e(g,"object"),"expected "+f.inspect(a)+" to be "+c+" "+f.inspect(d),"expected "+f.inspect(a)+" to not be "+c+" "+f.inspect(d))};g.closeTo=function(a,c,d,e){(new b(a,e)).to.be.closeTo(c,d)};g.sameMembers=function(a,c,d){(new b(a,d)).to.have.same.members(c)};g.sameDeepMembers=
function(a,c,d){(new b(a,d)).to.have.same.deep.members(c)};g.includeMembers=function(a,c,d){(new b(a,d)).to.include.members(c)};g.changes=function(a,c,d){(new b(a)).to.change(c,d)};g.doesNotChange=function(a,c,d){(new b(a)).to.not.change(c,d)};g.increases=function(a,c,d){(new b(a)).to.increase(c,d)};g.doesNotIncrease=function(a,c,d){(new b(a)).to.not.increase(c,d)};g.decreases=function(a,c,d){(new b(a)).to.decrease(c,d)};g.doesNotDecrease=function(a,c,d){(new b(a)).to.not.decrease(c,d)};g.ifError=
function(a,c){(new b(a,c)).to.not.be.ok};(function h(b,c){g[c]=g[b];return h})("Throw","throw")("Throw","throws")}});f.register("chai/lib/chai/interface/expect.js",function(f,g){g.exports=function(c,f){c.expect=function(b,e){return new c.Assertion(b,e)};c.expect.fail=function(b,e,f,a){throw new c.AssertionError(f||"expect.fail()",{actual:b,expected:e,operator:a},c.expect.fail);}}});f.register("chai/lib/chai/interface/should.js",function(f,g){g.exports=function(c,f){function b(){function b(){return this instanceof
String||this instanceof Number?new e(this.constructor(this),null,b):this instanceof Boolean?new e(1==this,null,b):new e(this,null,b)}Object.defineProperty(Object.prototype,"should",{set:function(a){Object.defineProperty(this,"should",{value:a,enumerable:!0,configurable:!0,writable:!0})},get:b,configurable:!0});var a={fail:function(b,d,e,f){throw new c.AssertionError(e||"should.fail()",{actual:b,expected:d,operator:f},a.fail);},equal:function(a,b,c){(new e(a,c)).to.equal(b)},Throw:function(a,b,c,f){(new e(a,
f)).to.Throw(b,c)},exist:function(a,b){(new e(a,b)).to.exist},not:{}};a.not.equal=function(a,b,c){(new e(a,c)).to.not.equal(b)};a.not.Throw=function(a,b,c,f){(new e(a,f)).to.not.Throw(b,c)};a.not.exist=function(a,b){(new e(a,b)).to.not.exist};a["throw"]=a.Throw;a.not["throw"]=a.not.Throw;return a}var e=c.Assertion;c.should=b;c.Should=b}});f.register("chai/lib/chai/utils/addChainableMethod.js",function(m,g){var c=f("chai/lib/chai/utils/transferFlags.js"),l=f("chai/lib/chai/utils/flag.js"),b=f("chai/lib/chai/config.js"),
e="__proto__"in Object,k=/^(?:length|name|arguments|caller)$/,a=Function.prototype.call,h=Function.prototype.apply;g.exports=function(d,f,g,m){"function"!==typeof m&&(m=function(){});var x={method:g,chainingBehavior:m};d.__methods||(d.__methods={});d.__methods[f]=x;Object.defineProperty(d,f,{get:function(){x.chainingBehavior.call(this);var f=function w(){l(this,"ssfi")&&!1===b.includeStack&&l(this,"ssfi",w);var a=x.method.apply(this,arguments);return void 0===a?this:a};if(e){var g=f.__proto__=Object.create(this);
g.call=a;g.apply=h}else Object.getOwnPropertyNames(d).forEach(function(a){if(!k.test(a)){var b=Object.getOwnPropertyDescriptor(d,a);Object.defineProperty(f,a,b)}});c(this,f);return f},configurable:!0})}});f.register("chai/lib/chai/utils/addMethod.js",function(m,g){var c=f("chai/lib/chai/config.js"),l=f("chai/lib/chai/utils/flag.js");g.exports=function(b,e,f){b[e]=function(){l(this,"ssfi")&&!1===c.includeStack&&l(this,"ssfi",b[e]);var a=f.apply(this,arguments);return void 0===a?this:a}}});f.register("chai/lib/chai/utils/addProperty.js",
function(f,g){g.exports=function(c,f,b){Object.defineProperty(c,f,{get:function(){var c=b.call(this);return void 0===c?this:c},configurable:!0})}});f.register("chai/lib/chai/utils/flag.js",function(f,g){g.exports=function(c,f,b){var e=c.__flags||(c.__flags=Object.create(null));if(3===arguments.length)e[f]=b;else return e[f]}});f.register("chai/lib/chai/utils/getActual.js",function(f,g){g.exports=function(c,f){return 4<f.length?f[4]:c._obj}});f.register("chai/lib/chai/utils/getEnumerableProperties.js",
function(f,g){g.exports=function(c){var f=[],b;for(b in c)f.push(b);return f}});f.register("chai/lib/chai/utils/getMessage.js",function(m,g){var c=f("chai/lib/chai/utils/flag.js"),l=f("chai/lib/chai/utils/getActual.js");f("chai/lib/chai/utils/inspect.js");var b=f("chai/lib/chai/utils/objDisplay.js");g.exports=function(e,f){var a=c(e,"negate"),g=c(e,"object"),d=f[3],m=l(e,f),a=a?f[2]:f[1],r=c(e,"message");"function"===typeof a&&(a=a());a=(a||"").replace(/#{this}/g,b(g)).replace(/#{act}/g,b(m)).replace(/#{exp}/g,
b(d));return r?r+": "+a:a}});f.register("chai/lib/chai/utils/getName.js",function(f,g){g.exports=function(c){return c.name?c.name:(c=/^\s?function ([^(]*)\(/.exec(c))&&c[1]?c[1]:""}});f.register("chai/lib/chai/utils/getPathValue.js",function(m,g){var c=f("chai/lib/chai/utils/getPathInfo.js");g.exports=function(f,b){return c(f,b).value}});f.register("chai/lib/chai/utils/getPathInfo.js",function(m,g){function c(b){return b.replace(/\[/g,".[").match(/(\\\.|[^.]+?)+/g).map(function(b){var a=/\[(\d+)\]$/.exec(b);
return a?{i:parseFloat(a[1])}:{p:b}})}function l(b,c,a){var f;a=void 0===a?b.length:a;for(var d=0;d<a;d++){var g=b[d];c?("undefined"!==typeof g.p?c=c[g.p]:"undefined"!==typeof g.i&&(c=c[g.i]),d==a-1&&(f=c)):f=void 0}return f}var b=f("chai/lib/chai/utils/hasProperty.js");g.exports=function(e,f){var a=c(e),g=a[a.length-1],a={parent:l(a,f,a.length-1),name:g.p||g.i,value:l(a,f)};a.exists=b(a.name,a.parent);return a}});f.register("chai/lib/chai/utils/hasProperty.js",function(m,g){var c=f("chai/lib/chai/utils/type.js"),
l={number:Number,string:String};g.exports=function(b,e){var f=c(e);if("null"===f||"undefined"===f)return!1;l[f]&&"object"!==typeof e&&(e=new l[f](e));return b in e}});f.register("chai/lib/chai/utils/getProperties.js",function(f,g){g.exports=function(c){function f(c){-1===b.indexOf(c)&&b.push(c)}var b=Object.getOwnPropertyNames(subject);for(c=Object.getPrototypeOf(subject);null!==c;)Object.getOwnPropertyNames(c).forEach(f),c=Object.getPrototypeOf(c);return b}});f.register("chai/lib/chai/utils/index.js",
function(m,g){m=g.exports={};m.test=f("chai/lib/chai/utils/test.js");m.type=f("chai/lib/chai/utils/type.js");m.getMessage=f("chai/lib/chai/utils/getMessage.js");m.getActual=f("chai/lib/chai/utils/getActual.js");m.inspect=f("chai/lib/chai/utils/inspect.js");m.objDisplay=f("chai/lib/chai/utils/objDisplay.js");m.flag=f("chai/lib/chai/utils/flag.js");m.transferFlags=f("chai/lib/chai/utils/transferFlags.js");m.eql=f("chaijs~deep-eql@0.1.3");m.getPathValue=f("chai/lib/chai/utils/getPathValue.js");m.getPathInfo=
f("chai/lib/chai/utils/getPathInfo.js");m.hasProperty=f("chai/lib/chai/utils/hasProperty.js");m.getName=f("chai/lib/chai/utils/getName.js");m.addProperty=f("chai/lib/chai/utils/addProperty.js");m.addMethod=f("chai/lib/chai/utils/addMethod.js");m.overwriteProperty=f("chai/lib/chai/utils/overwriteProperty.js");m.overwriteMethod=f("chai/lib/chai/utils/overwriteMethod.js");m.addChainableMethod=f("chai/lib/chai/utils/addChainableMethod.js");m.overwriteChainableMethod=f("chai/lib/chai/utils/overwriteChainableMethod.js")});
f.register("chai/lib/chai/utils/inspect.js",function(m,g){function c(f,g,E){if(g&&"function"===typeof g.inspect&&g.inspect!==m.inspect&&(!g.constructor||g.constructor.prototype!==g)){var w=g.inspect(E);"string"!==typeof w&&(w=c(f,w,E));return w}var A=l(f,g);if(A)return A;A="object"===typeof HTMLElement?g instanceof HTMLElement:g&&"object"===typeof g&&1===g.nodeType&&"string"===typeof g.nodeName;if(A){if("outerHTML"in g)return g.outerHTML;try{if(document.xmlVersion)return(new XMLSerializer).serializeToString(g);
w=document.createElementNS("http://www.w3.org/1999/xhtml","_");w.appendChild(g.cloneNode(!1));html=w.innerHTML.replace("><",">"+g.innerHTML+"<");w.innerHTML="";return html}catch(z){}}var F=x(g),A=f.showHidden?q(g):F;if(0===A.length||t(g)&&(1===A.length&&"stack"===A[0]||2===A.length&&"description"===A[0]&&"stack"===A[1])){if("function"===typeof g){var B=r(g);return f.stylize("[Function"+(B?": "+B:"")+"]","special")}if(h(g))return f.stylize(RegExp.prototype.toString.call(g),"regexp");if(d(g))return f.stylize(Date.prototype.toUTCString.call(g),
"date");if(t(g))return"["+Error.prototype.toString.call(g)+"]"}var B="",y=!1,w=["{","}"];a(g)&&(y=!0,w=["[","]"]);"function"===typeof g&&(B=r(g),B=" [Function"+(B?": "+B:"")+"]");h(g)&&(B=" "+RegExp.prototype.toString.call(g));d(g)&&(B=" "+Date.prototype.toUTCString.call(g));if(t(g))return"["+Error.prototype.toString.call(g)+"]";if(0===A.length&&(!y||0==g.length))return w[0]+B+w[1];if(0>E)return h(g)?f.stylize(RegExp.prototype.toString.call(g),"regexp"):f.stylize("[Object]","special");f.seen.push(g);
A=y?b(f,g,E,F,A):A.map(function(a){return e(f,g,E,F,a,y)});f.seen.pop();return k(A,B,w)}function l(a,b){switch(typeof b){case "undefined":return a.stylize("undefined","undefined");case "string":var c="'"+JSON.stringify(b).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return a.stylize(c,"string");case "number":return 0===b&&-Infinity===1/b?a.stylize("-0","number"):a.stylize(""+b,"number");case "boolean":return a.stylize(""+b,"boolean")}if(null===b)return a.stylize("null","null")}
function b(a,b,c,d,f){for(var g=[],h=0,k=b.length;h<k;++h)Object.prototype.hasOwnProperty.call(b,String(h))?g.push(e(a,b,c,d,String(h),!0)):g.push("");f.forEach(function(f){f.match(/^\d+$/)||g.push(e(a,b,c,d,f,!0))});return g}function e(a,b,d,e,f,g){var h,k;b.__lookupGetter__&&(b.__lookupGetter__(f)?k=b.__lookupSetter__(f)?a.stylize("[Getter/Setter]","special"):a.stylize("[Getter]","special"):b.__lookupSetter__(f)&&(k=a.stylize("[Setter]","special")));0>e.indexOf(f)&&(h="["+f+"]");k||(0>a.seen.indexOf(b[f])?
(k=null===d?c(a,b[f],null):c(a,b[f],d-1),-1<k.indexOf("\n")&&(k=g?k.split("\n").map(function(a){return" "+a}).join("\n").substr(2):"\n"+k.split("\n").map(function(a){return" "+a}).join("\n"))):k=a.stylize("[Circular]","special"));if("undefined"===typeof h){if(g&&f.match(/^\d+$/))return k;h=JSON.stringify(""+f);h.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(h=h.substr(1,h.length-2),h=a.stylize(h,"name")):(h=h.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),h=a.stylize(h,"string"))}return h+
": "+k}function k(a,b,c){var d=0;return 60<a.reduce(function(a,b){d++;0<=b.indexOf("\n")&&d++;return a+b.length+1},0)?c[0]+(""===b?"":b+"\n ")+" "+a.join(",\n ")+" "+c[1]:c[0]+b+" "+a.join(", ")+" "+c[1]}function a(a){return Array.isArray(a)||"object"===typeof a&&"[object Array]"===Object.prototype.toString.call(a)}function h(a){return"object"===typeof a&&"[object RegExp]"===Object.prototype.toString.call(a)}function d(a){return"object"===typeof a&&"[object Date]"===Object.prototype.toString.call(a)}
function t(a){return"object"===typeof a&&"[object Error]"===Object.prototype.toString.call(a)}var r=f("chai/lib/chai/utils/getName.js"),q=f("chai/lib/chai/utils/getProperties.js"),x=f("chai/lib/chai/utils/getEnumerableProperties.js");g.exports=function(a,b,d,e){return c({showHidden:b,seen:[],stylize:function(a){return a}},a,"undefined"===typeof d?2:d)}});f.register("chai/lib/chai/utils/objDisplay.js",function(m,g){var c=f("chai/lib/chai/utils/inspect.js"),l=f("chai/lib/chai/config.js");g.exports=
function(b){var e=c(b),f=Object.prototype.toString.call(b);if(l.truncateThreshold&&e.length>=l.truncateThreshold){if("[object Function]"===f)return b.name&&""!==b.name?"[Function: "+b.name+"]":"[Function]";if("[object Array]"===f)return"[ Array("+b.length+") ]";if("[object Object]"===f)return b=Object.keys(b),"{ Object ("+(2<b.length?b.splice(0,2).join(", ")+", ...":b.join(", "))+") }"}return e}});f.register("chai/lib/chai/utils/overwriteMethod.js",function(f,g){g.exports=function(c,f,b){var e=c[f],
g=function(){return this};e&&"function"===typeof e&&(g=e);c[f]=function(){var a=b(g).apply(this,arguments);return void 0===a?this:a}}});f.register("chai/lib/chai/utils/overwriteProperty.js",function(f,g){g.exports=function(c,f,b){var e=Object.getOwnPropertyDescriptor(c,f),g=function(){};e&&"function"===typeof e.get&&(g=e.get);Object.defineProperty(c,f,{get:function(){var a=b(g).call(this);return void 0===a?this:a},configurable:!0})}});f.register("chai/lib/chai/utils/overwriteChainableMethod.js",function(f,
g){g.exports=function(c,f,b,e){c=c.__methods[f];var g=c.chainingBehavior;c.chainingBehavior=function(){var a=e(g).call(this);return void 0===a?this:a};var a=c.method;c.method=function(){var c=b(a).apply(this,arguments);return void 0===c?this:c}}});f.register("chai/lib/chai/utils/test.js",function(m,g){var c=f("chai/lib/chai/utils/flag.js");g.exports=function(f,b){var e=c(f,"negate"),g=b[0];return e?!g:g}});f.register("chai/lib/chai/utils/transferFlags.js",function(f,g){g.exports=function(c,f,b){var e=
c.__flags||(c.__flags=Object.create(null));f.__flags||(f.__flags=Object.create(null));b=3===arguments.length?b:!0;for(var g in e)if(b||"object"!==g&&"ssfi"!==g&&"message"!=g)f.__flags[g]=e[g]}});f.register("chai/lib/chai/utils/type.js",function(f,g){var c={"[object Arguments]":"arguments","[object Array]":"array","[object Date]":"date","[object Function]":"function","[object Number]":"number","[object RegExp]":"regexp","[object String]":"string"};g.exports=function(f){var b=Object.prototype.toString.call(f);
return c[b]?c[b]:null===f?"null":void 0===f?"undefined":f===Object(f)?"object":typeof f}});"object"==typeof exports?module.exports=f("chai"):"function"==typeof define&&define.amd?define("chai",[],function(){return f("chai")}):(this||window).chai=f("chai")})();

View File

@ -0,0 +1,59 @@
var slice = Array.prototype.slice;
suite('AnimeClient methods exist', function () {
test("AnimeClient exists", function () {
expect(AnimeClient).to.be.ok;
});
['$', 'scrollToTop', 'showMessage', 'closestParent', 'url', 'throttle', 'on', 'ajax', 'get'].forEach((method) => {
test("AnimeClient." + method + ' exists.', function () {
expect(AnimeClient[method]).to.be.ok;
});
});
});
suite('AnimeClient.$', function () {
test('$ returns an array', function () {
var matched = AnimeClient.$('div');
expect(matched).to.be.an('array');
});
test('$ returns same element as "getElementById"', function () {
var actual = AnimeClient.$('#mocha')[0];
var expected = document.getElementById('mocha');
expect(actual).to.equal(expected);
});
test('$ returns same elements as "getElementsByClassName"', function () {
var actual = AnimeClient.$('.progress');
var expected = slice.apply(document.getElementsByClassName('progress'));
expect(actual).to.deep.equal(expected);
});
test('$ returns same elements as "getElementsByTagName"', function () {
var actual = AnimeClient.$('ul');
var expected = slice.apply(document.getElementsByTagName('ul'));
expect(actual).to.deep.equal(expected);
});
});
suite('AnimeClient.url', function () {
test('url method has expected result', function () {
let expected = `//${document.location.host}/path`;
expect(AnimeClient.url('/path')).to.equal(expected);
});
});
suite('AnimeClient.closestParent', function () {
test('".grandChild" closest "section" is "#parentTest"', function () {
let sel = AnimeClient.$('.grandChild')[0];
let expected = document.getElementById('parentTest');
expect(AnimeClient.closestParent(sel, 'section')).to.equal(expected);
});
test('".child" closest "article" is "#parentTest"', function () {
let sel = AnimeClient.$('.child')[0];
let expected = document.getElementById('parentTest');
expect(AnimeClient.closestParent(sel, 'section')).to.equal(expected);
});
});

100
public/test/tests/ajax.js Normal file
View File

@ -0,0 +1,100 @@
suite('AnimeClient.ajax', function () {
'use strict';
test('AnimeClient.get method', function (done) {
AnimeClient.get('ajax.php', function (res) {
expect(res).to.be.ok;
done();
});
});
test('GET', function (done) {
AnimeClient.ajax('ajax.php', {
success: function (res) {
expect(res).to.be.ok;
done();
},
error: function (err) {
expect.fail;
done();
}
});
});
test('POST', function (done) {
AnimeClient.ajax('ajax.php', {
type: 'POST',
success: function (res) {
expect(res).to.be.ok;
done();
},
error: function (err) {
expect.fail;
done();
}
});
});
test('PUT', function (done) {
AnimeClient.ajax('ajax.php', {
type: 'PUT',
success: function (res) {
expect(res).to.be.ok;
done();
},
error: function (err) {
expect.fail;
done();
}
});
});
test('DELETE', function (done) {
AnimeClient.ajax('ajax.php', {
type: 'DELETE',
success: function (res) {
expect(res).to.be.ok;
done();
},
error: function (err) {
expect.fail;
done();
}
});
});
test('POST with data', function (done) {
var expected = '{"foo":"data"}';
AnimeClient.ajax('ajax.php?data', {
data: {foo:'data'},
type: 'POST',
success: function (res) {
expect(res).to.be.equal(expected);
done();
},
error: function (err) {
expect.fail;
done();
}
});
});
test('PUT with data', function (done) {
var expected = '{"bar":"data"}';
AnimeClient.ajax('ajax.php?data', {
data: {bar:'data'},
type: 'POST',
success: function (res) {
expect(res).to.be.equal(expected);
done();
},
error: function (err) {
expect.fail;
done();
}
});
});
test('Bad request', function (done) {
AnimeClient.ajax('ajax.php?bad', {
error: function (status) {
expect(status).to.be.equal(401);
done();
}
});
});
});

View File

@ -382,11 +382,13 @@ class Controller {
* Output a JSON Response * Output a JSON Response
* *
* @param mixed $data * @param mixed $data
* @param int $code - the http status code
* @return void * @return void
*/ */
protected function outputJSON($data = []) protected function outputJSON($data = [], $code = 200)
{ {
$view = new JsonView($this->container); $view = new JsonView($this->container);
$view->setStatusCode($code);
$view->setOutput($data); $view->setOutput($data);
} }

View File

@ -244,16 +244,36 @@ class Anime extends BaseController {
/** /**
* Update an anime item * Update an anime item
*
* @return boolean|null
*/ */
public function update() public function update()
{ {
$this->outputJSON( $response = $this->model->update($this->request->post->get());
$this->model->update( $this->outputJSON($response['body'], $response['statusCode']);
$this->request->post->get() }
)
); /**
* Remove an anime from the list
*/
public function delete()
{
$response = $this->model->update($this->request->post->get());
$this->outputJSON($response['body'], $response['statusCode']);
}
/**
* View details of an anime
*
* @param string anime_id
* @return void
*/
public function details($anime_id)
{
$data = $this->model->get_anime($anime_id);
$this->outputHTML('anime/details', [
'title' => $data['title'],
'data' => $data,
]);
} }
} }
// End of AnimeController.php // End of AnimeController.php

View File

@ -12,6 +12,7 @@
*/ */
namespace Aviat\AnimeClient\Controller; namespace Aviat\AnimeClient\Controller;
use Aviat\Ion\Json;
use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\ContainerInterface;
use Aviat\AnimeClient\Controller; use Aviat\AnimeClient\Controller;
use Aviat\AnimeClient\Config; use Aviat\AnimeClient\Config;
@ -91,6 +92,61 @@ class Manga extends Controller {
]); ]);
} }
/**
* Form to add an manga
*
* @return void
*/
public function add_form()
{
$raw_status_list = MangaReadingStatus::getConstList();
$statuses = [];
foreach ($raw_status_list as $status_item)
{
$statuses[$status_item] = (string)$this->string($status_item)
->underscored()
->humanize()
->titleize();
}
$this->set_session_redirect();
$this->outputHTML('manga/add', [
'title' => $this->config->get('whose_list') .
"'s Manga List &middot; Add",
'action_url' => $this->urlGenerator->url('manga/add'),
'status_list' => $statuses
]);
}
/**
* Add an manga to the list
*
* @return void
*/
public function add()
{
$data = $this->request->post->get();
if ( ! array_key_exists('id', $data))
{
$this->redirect("manga/add", 303);
}
$result = $this->model->add($data);
if ($result['statusCode'] >= 200 && $result['statusCode'] < 300)
{
$this->set_flash_message('Added new manga to list', 'success');
}
else
{
$this->set_flash_message('Failed to add new manga to list' . $result['body'], 'error');
}
$this->session_redirect();
}
/** /**
* Show the manga edit form * Show the manga edit form
* *
@ -113,6 +169,17 @@ class Manga extends Controller {
]); ]);
} }
/**
* Search for a manga to add to the list
*
* @return void
*/
public function search()
{
$query = $this->request->query->get('query');
$this->outputJSON($this->model->search($query));
}
/** /**
* Update an anime item via a form submission * Update an anime item via a form submission
* *
@ -128,9 +195,9 @@ class Manga extends Controller {
$post_data = $transformer->untransform($post_data); $post_data = $transformer->untransform($post_data);
$full_result = $this->model->update($post_data); $full_result = $this->model->update($post_data);
$result = $full_result['body']; $result = Json::decode((string)$full_result['body']);
if (array_key_exists('manga', $result)) if ($full_result['statusCode'] == 200)
{ {
$m =& $result['manga'][0]; $m =& $result['manga'][0];
$title = ( ! empty($m['english_title'])) $title = ( ! empty($m['english_title']))
@ -141,7 +208,7 @@ class Manga extends Controller {
} }
else else
{ {
$this->set_flash_message('Failed to update anime.', 'error'); $this->set_flash_message('Failed to update manga.', 'error');
} }
$this->session_redirect(); $this->session_redirect();
@ -154,7 +221,8 @@ class Manga extends Controller {
*/ */
public function update() public function update()
{ {
$this->outputJSON($this->model->update($this->request->post->get())); $result = $this->model->update($this->request->post->get());
$this->outputJSON($result['body'], $result['statusCode']);
} }
} }
// End of MangaController.php // End of MangaController.php

View File

@ -104,7 +104,7 @@ class Dispatcher extends RoutingBase {
$logger->debug(print_r($route, TRUE)); $logger->debug(print_r($route, TRUE));
} }
if($route) if ($route)
{ {
$parsed = $this->process_route($route); $parsed = $this->process_route($route);
$controller_name = $parsed['controller_name']; $controller_name = $parsed['controller_name'];
@ -272,7 +272,7 @@ class Dispatcher extends RoutingBase {
'message' => 'Invalid HTTP Verb' 'message' => 'Invalid HTTP Verb'
]; ];
} }
else if($failure->failedAccept()) else if ($failure->failedAccept())
{ {
$params = [ $params = [
'http_code' => 406, 'http_code' => 406,

View File

@ -105,7 +105,7 @@ class MangaListTransformer extends AbstractTransformer {
'notes' => $item['notes'], 'notes' => $item['notes'],
]; ];
if ($item['new_rating'] !== $item['old_rating']) if ($item['new_rating'] !== $item['old_rating'] && $item['new_rating'] !== "")
{ {
$map['rating'] = ($item['new_rating'] > 0) $map['rating'] = ($item['new_rating'] > 0)
? $item['new_rating'] / 2 ? $item['new_rating'] / 2

View File

@ -178,5 +178,18 @@ class API extends BaseModel {
return FALSE; return FALSE;
} }
/**
* Dummy function that should be abstract. Is not abstract because
* this class is used concretely for authorizing API calls
*
* @TODO Refactor, and make this abstract
* @param string $status
* @return array
*/
protected function _get_list_from_api($status)
{
return [];
}
} }
// End of BaseApiModel.php // End of BaseApiModel.php

View File

@ -74,6 +74,33 @@ class Anime extends API {
]; ];
} }
/**
* Remove an anime from a list
*
* @param array $data
* @return array|false
*/
public function delete($data)
{
$auth = $this->container->get('auth');
if ( ! $auth->is_authenticated() || ! array_key_exists('id', $data))
{
return FALSE;
}
$id = $data['id'];
$data['auth_token'] = $auth->get_auth_token();
$response = $this->client->post("libraries/{$id}/remove", [
'form_params' => $data
]);
return [
'statusCode' => $response->getStatusCode(),
'body' => Json::decode($response->getBody(), TRUE)
];
}
/** /**
* Get the full set of anime lists * Get the full set of anime lists
* *

View File

@ -51,15 +51,15 @@ class Manga extends API {
protected $base_url = "https://hummingbird.me/"; protected $base_url = "https://hummingbird.me/";
/** /**
* Update the selected manga * Make an authenticated manga API call
* *
* @param array $data * @param string $type - the HTTP verb
* @param string $url
* @param string|null $json
* @return array * @return array
*/ */
public function update($data) protected function _manga_api_call($type, $url, $json = NULL)
{ {
$id = $data['id'];
$token = $this->container->get('auth') $token = $this->container->get('auth')
->get_auth_token(); ->get_auth_token();
@ -73,17 +73,101 @@ class Manga extends API {
]); ]);
$cookieJar->setCookie($cookie_data); $cookieJar->setCookie($cookie_data);
$result = $this->put("manga_library_entries/{$id}", [ $config = [
'cookies' => $cookieJar, 'cookies' => $cookieJar
'json' => ['manga_library_entry' => $data] ];
]);
if ( ! is_null($json))
{
$config['json'] = $json;
}
$result = $this->client->request(strtoupper($type), $url, $config);
return [ return [
'statusCode' => $result->getStatusCode(), 'statusCode' => $result->getStatusCode(),
'body' => Json::decode($result->getBody(), TRUE) 'body' => $result->getBody()
]; ];
} }
/**
* Add a manga to the list
*
* @param array $data
*/
public function add($data)
{
$object = [
'manga_library_entry' => [
'status' => $data['status'],
'manga_id' => $data['id']
]
];
return $this->_manga_api_call('post', 'manga_library_entries', $object);
}
/**
* Update the selected manga
*
* @param array $data
* @return array
*/
public function update($data)
{
$id = $data['id'];
return $this->_manga_api_call(
'put',
"manga_library_entries/{$id}",
['manga_library_entry' => $data]
);
}
/**
* Delete a manga entry
*
* @param array $data
* @return array
*/
public function delete($data)
{
$id = $data['id'];
return $this->_manga_api_call('delete', "manga_library_entries/{$id}");
}
/**
* Search for manga by name
*
* @param string $name
* @return array
*/
public function search($name)
{
$logger = $this->container->getLogger('default');
$config = [
'query' => [
'scope' => 'manga',
'depth' => 'full',
'query' => $name
]
];
$response = $this->get('search.json', $config);
if ($response->getStatusCode() != 200)
{
$logger->warning("Non 200 response for search api call");
$logger->warning($response->getBody());
throw new RuntimeException($response->getEffectiveUrl());
}
return Json::decode($response->getBody(), TRUE);
}
/** /**
* Get the full set of anime lists * Get the full set of anime lists
* *

View File

@ -39,6 +39,12 @@ class RoutingBase {
*/ */
protected $routes; protected $routes;
/**
* Route configuration options
* @var array
*/
protected $route_config;
/** /**
* Constructor * Constructor
* *
@ -48,8 +54,9 @@ class RoutingBase {
{ {
$this->container = $container; $this->container = $container;
$this->config = $container->get('config'); $this->config = $container->get('config');
$this->base_routes = $this->config->get('routes'); $base_routes = $this->config->get('routes');
$this->routes = $this->base_routes['routes']; $this->routes = $base_routes['routes'];
$this->route_config = $base_routes['route_config'];
} }
/** /**
@ -60,7 +67,7 @@ class RoutingBase {
*/ */
public function __get($key) public function __get($key)
{ {
$routing_config = $this->base_routes['route_config']; $routing_config =& $this->route_config;
if (array_key_exists($key, $routing_config)) if (array_key_exists($key, $routing_config))
{ {

View File

@ -23,8 +23,8 @@ class Json {
* Encode data in json format * Encode data in json format
* *
* @param mixed $data * @param mixed $data
* @param int $options=0 * @param int $options
* @param int $depth=512 * @param int $depth
* @return string * @return string
*/ */
public static function encode($data, $options = 0, $depth = 512) public static function encode($data, $options = 0, $depth = 512)

View File

@ -65,6 +65,11 @@ class HttpView extends BaseView {
*/ */
protected function output() protected function output()
{ {
$this->response->headers->set('Content-Security-Policy', "script-src 'self'");
$this->response->headers->set('X-Content-Type-Options', 'nosniff');
$this->response->headers->set('X-XSS-Protection', '1;mode=block');
$this->response->headers->set('X-Frame-Options', 'SAMEORIGIN');
$content =& $this->response->content; $content =& $this->response->content;
$content->set($this->output); $content->set($this->output);
$content->setType($this->contentType); $content->setType($this->contentType);

View File

@ -144,6 +144,10 @@ class MockBaseApiModel extends BaseApiModel {
use MockInjectionTrait; use MockInjectionTrait;
protected $base_url = 'https://httpbin.org/'; protected $base_url = 'https://httpbin.org/';
protected function _get_list_from_api($status)
{
return [];
}
} }
class TestAnimeModel extends AnimeModel { class TestAnimeModel extends AnimeModel {