Giter VIP home page Giter VIP logo

juvia's Introduction

About Juvia

Logo

Juvia is currently maintained, but we surely will appreciate new contributors.

Juvia is an open source commenting system. It allows you to outsource your commenting needs to an external system so that you don't have to build your own commenting system for each website or each web app. Embedding a Juvia commenting page only involves pasting a JavaScript snippet into your web page.

Juvia is similar to Disqus and IntenseDebate. However both of them seem to be designed in the early 2000s before the rise of AJAX: trying to integrate either of them in an AJAX web application results in many wasted afternoons and a screen full of inexplicable JavaScript errors. Juvia offers full support for AJAX web pages and any JavaScript is written in such a way that it avoids conflicts with the page's existing JavaScripts.

Juvia currently also makes no effort to support nested comments. I believe nested comments only make sense for extremely active discussion forums. Instead, Juvia strives for simplicity.

Other notable highlights:

  • Moderation support, either manually or automatically via Akismet.
  • Multi-user support. With this I don't mean commenters but users who operate the Juvia admin panel. Each user account is isolated and can only see and manage its own sites, topics and comments, except for administrators who can see and manage everything.
  • Email notification of new comments.
  • Wordpress comment import (thanks to JangoSteve).

Installation

  1. Clone this repository into a desired directory and cd to it.
  2. Configure your database details by editing config/database.yml. An example is provided in config/database.yml.example. Only edit the information under the 'production' section.
  3. Configure other things by editing config/application.yml. An example is provided in config/application.yml.example. Only edit the information under the 'production' section.
  4. Install the necessary dependencies: bundle install --without='development test postgres sqlite' --path=help
  5. Install the database schema: bundle exec rake db:schema:load RAILS_ENV=production
  6. Compile the static assets: bundle exec rake assets:precompile RAILS_ENV=production RAILS_GROUPS=assets
  7. Deploy this application to Phusion Passenger or whatever application server you prefer.

You can now access Juvia through the address that you configured. It will ask you to create an initial administrator account and to register a site.

Upgrade

  1. cd to the source directory and update the code to the latest version: git fetch && git reset --hard origin/master
  2. Install the necessary dependencies: bundle install --without='development test' --path=help
  3. Upgrade the database schema: bundle exec rake db:migrate RAILS_ENV=production
  4. Compile the static assets: bundle exec rake assets:precompile RAILS_ENV=production RAILS_GROUPS=assets
  5. Run touch tmp/restart.txt (if you're using Phusion Passenger) or restart your application server.

Cryptographic verification

I do not release source tarballs for Juvia. Users are expected to get the source code from Github.

From time to time, I create Git tags for milestones. These milestones are signed with the Phusion Software Signing key. After importing this key you can verify Git tags as follows:

git tag --verify milestone-2013-03-11

Rails helper

James Smith has written a Rails helper gem for embedding Juvia comments into Rails web applications. See juvia_rails.

TODO

Juvia is pretty broken and outdated at the moment. That means we have to stabilize and update components first. That's what we are gonna do:

  • Update libraries and gems, replace highly outdated dependencies, make project work on modern Ruby branch, lint code (probably have to push to Rails 5 or 6, Rails 4 is pretty outdated at the moment already)
  • Add dependabot, github actions to CI/CD, mandatody CI for pull requests (if possible)
  • Make and publish a rodmap based on issues, TODO and common sense
  • Work on the TODO list
  • Documentation, user guides

Some features we will like to implement in the future:

  • Juvia works fine but we need more tests to prevent things from breaking in the future.
  • Document the list_topics API call.
  • A Quote/Reply button for each comment.
  • Export support. Not sure whether this is necessary, the user may as well backup the entire database.
  • Email notification for commenters.
  • Moderation teams. Currently each site is owned by exactly one user, and only that user or the administrator can moderate comments. And right now only the site's owner is notified by email of new comments.
  • Better interface for low-resolution screens like mobile phones.
  • Allow commenters to edit their comments. Of course, this requires some way to authenticate the commenter. Maybe Juvia can send an email with a time-limited authentication code (assuming the commenter specified his email in the first place).

juvia's People

Contributors

adnikiforov avatar camjn avatar dependabot[bot] avatar dmayer avatar floord avatar foobarwidget avatar ianrenton avatar jangosteve avatar olafure avatar stbuehler avatar tinco avatar tribut avatar vitorhp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

juvia's Issues

Login via Twitter?

What about a login via Twitter to have the profile-image etc. from there and don't have to remember another password + don't have to store it ^^

Rails gem

Not an issue as such, but I made a Rails gem to make using Juvia trivially easy at https://github.com/theodi/juvia_rails, so people don't have to paste in the code, make their own helpers, etc.

I'll do a proper gem release when we've got it up and running in production here, and added some tests.

Capcha on posting

It would be nice to add capcha on posting feature. I think it a better alternative than Akismet, which is more of remedial measurement.

Fire javascript event when comments have loaded

I wanted to make sure you thought this was a good idea before adding it myself.

I have certain code I'd like to run after the comments content has loaded. For example, I need to add a special styling class to the form submit button so that it'll get styled according to the btn class from twitter bootstrap. I currently accomplished this by adding this to the bottom of the juvia javascript:

s.onload = s.onreadystatechange = function(){
  $(options.container).find('input[type="submit"]').addClass('btn btn-success');
};

However, it'd be a lot cleaner if maybe juvia fired a juvia:loaded event or something like that on the juvia container that could be easily handled.

Browsers Supported?

What browsers are or are planned to be supported?

I have a need to support IE8 clients with similar functionality. I accessed the demo site and received a javascript issue. I assume IE8 is probably shunned, but was looking for an official disclaimer on browsers supported.

Setup github actions for specs and linters

We are gonna run those checks:

  • specs
  • rubocop + performance, rspec, rails modules using reviewdog
  • reek (probably good idea, despite he is kinda capricious)

So we need to setup github actions for those.

activerecord-mysql-adapter is not a gem

Please install the mysql adapter: gem install activerecord-mysql-adapter (mysql is not part of the bundle. Add it to Gemfile.)

Tasks: TOP => db:schema:load => environment
(See full trace by running task with --trace)
teiko@cactus ~/juvia $ gem install activerecord-mysql-adapter
ERROR: Could not find a valid gem 'activerecord-mysql-adapter' (>= 0) in any repository
ERROR: Possible alternatives: activerecord-jdbcmysql-adapter, activerecord-odbc-adapter, activerecord-jdbc-adapter, activerecord-jdbcmssql-adapter, activerecord-mysql-adapter-flags

How to go on further?

The order when last comments appear below is required.

Hey!

The order when the last comment appears above is very confusing and different from other commenting systems. I would like to see an option to change the comments' order so that last comments appear below.

Best regards,
Vladimir.

Topic key is 'underfined' for example JS code

As I create a new site, I see an example JS code to use as is. But the example code includes line

topic_key   : location.path

This code produces 'undefined' topic_key, and should be replaced by

topic_key   : location.pathname

Debian package

Installing Juvia is a pain for people who are not Rails developers. Today I heard of https://github.com/crohr/pkgr, a tool for easily converting Rails apps to Debian packages. Maybe it would be a good idea to offer Debian packages using this tool.

For extra coolness, we can even provide a Docker image.

Can't create any new sites

When creating a new site, I get:

NoMethodError (undefined method  `remove_attributes_protected_from_mass_assignment' for #<Site:0xb8171d7c>):
  app/controllers/admin/sites_controller.rb:34:in `new'
  app/controllers/admin/sites_controller.rb:34:in `new'

This is with Ruby 2.1.1 and the latest master of juvia. I'm examining whether this also happens with Ruby 1.9.x.

Can't compile assets

Firstly, I have looked at the other closed issue with the same topic and this is a different issue.

Looking at the solution of the other issue, I have already checked all my version number and they are the latest. Here is an output of

bundle show
Gems included by the bundle:
  * actionmailer (3.2.18)
  * actionpack (3.2.18)
  * activemodel (3.2.18)
  * activerecord (3.2.18)
  * activeresource (3.2.18)
  * activesupport (3.2.18)
  * arel (3.0.3)
  * bcrypt (3.1.7)
  * bcrypt-ruby (3.1.5)
  * bluecloth (2.2.0)
  * builder (3.0.4)
  * bundler (1.3.5)
  * cancan (1.6.10)
  * coffee-rails (3.2.2)
  * coffee-script (2.2.0)
  * coffee-script-source (1.7.0)
  * css3buttons (1.0.1)
  * default_value_for (3.0.0)
  * devise (2.2.8)
  * erubis (2.7.0)
  * execjs (2.0.2)
  * has_scope (0.6.0.rc)
  * hike (1.2.3)
  * i18n (0.6.9)
  * inherited_resources (1.4.1)
  * journey (1.0.4)
  * jquery-rails (3.1.0)
  * json (1.8.1)
  * mail (2.5.4)
  * mime-types (1.25.1)
  * mini_portile (0.5.3)
  * multi_json (1.10.0)
  * mysql2 (0.3.15)
  * nokogiri (1.6.1)
  * orm_adapter (0.5.0)
  * polyglot (0.3.4)
  * rack (1.4.5)
  * rack-cache (1.2)
  * rack-ssl (1.3.4)
  * rack-test (0.6.2)
  * rails (3.2.18)
  * railties (3.2.18)
  * rake (10.3.1)
  * rdoc (3.12.2)
  * responders (1.0.0)
  * sass (3.3.7)
  * sass-rails (3.2.6)
  * schema_plus (1.5.1)
  * sprockets (2.2.2)
  * thor (0.19.1)
  * tilt (1.4.1)
  * treetop (1.4.15)
  * tzinfo (0.3.39)
  * uglifier (2.5.0)
  * valuable (0.9.8)
  * warden (1.2.3)
  * will_paginate (3.0.5)

But still I'm getting the following error when I run:

bundle exec rake --trace assets:precompile RAILS_ENV=production RAILS_GROUPS=assets

Error:

WARNING: Nokogiri was built against LibXML version 2.8.0, but has dynamically loaded 2.7.6
rake aborted!
ExecJS::RuntimeUnavailable: Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a list of available runtimes.
/home3/audichne/juvia/help/ruby/1.9.3/gems/execjs-2.0.2/lib/execjs/runtimes.rb:51:in `autodetect'
/home3/audichne/juvia/help/ruby/1.9.3/gems/execjs-2.0.2/lib/execjs.rb:5:in `<module:ExecJS>'
/home3/audichne/juvia/help/ruby/1.9.3/gems/execjs-2.0.2/lib/execjs.rb:4:in `<top (required)>'
/home3/audichne/juvia/help/ruby/1.9.3/gems/activesupport-3.2.18/lib/active_support/dependencies.rb:251:in `require'
/home3/audichne/juvia/help/ruby/1.9.3/gems/activesupport-3.2.18/lib/active_support/dependencies.rb:251:in `block in require'
/home3/audichne/juvia/help/ruby/1.9.3/gems/activesupport-3.2.18/lib/active_support/dependencies.rb:236:in `load_dependency'
/home3/audichne/juvia/help/ruby/1.9.3/gems/activesupport-3.2.18/lib/active_support/dependencies.rb:251:in `require'
/home3/audichne/juvia/help/ruby/1.9.3/gems/coffee-script-2.2.0/lib/coffee_script.rb:1:in `<top (required)>'
/home3/audichne/juvia/help/ruby/1.9.3/gems/activesupport-3.2.18/lib/active_support/dependencies.rb:251:in `require'
/home3/audichne/juvia/help/ruby/1.9.3/gems/activesupport-3.2.18/lib/active_support/dependencies.rb:251:in `block in require'
/home3/audichne/juvia/help/ruby/1.9.3/gems/activesupport-3.2.18/lib/active_support/dependencies.rb:236:in `load_dependency'
/home3/audichne/juvia/help/ruby/1.9.3/gems/activesupport-3.2.18/lib/active_support/dependencies.rb:251:in `require'
/home3/audichne/juvia/help/ruby/1.9.3/gems/coffee-script-2.2.0/lib/coffee-script.rb:1:in `<top (required)>'
/home3/audichne/juvia/help/ruby/1.9.3/gems/activesupport-3.2.18/lib/active_support/dependencies.rb:251:in `require'
/home3/audichne/juvia/help/ruby/1.9.3/gems/activesupport-3.2.18/lib/active_support/dependencies.rb:251:in `block in require'
/home3/audichne/juvia/help/ruby/1.9.3/gems/activesupport-3.2.18/lib/active_support/dependencies.rb:236:in `load_dependency'
/home3/audichne/juvia/help/ruby/1.9.3/gems/activesupport-3.2.18/lib/active_support/dependencies.rb:251:in `require'
/home3/audichne/juvia/help/ruby/1.9.3/gems/coffee-rails-3.2.2/lib/coffee-rails.rb:1:in `<top (required)>'
/usr/lib64/ruby/gems/1.9.3/gems/bundler-1.3.5/lib/bundler/runtime.rb:72:in `require'
/usr/lib64/ruby/gems/1.9.3/gems/bundler-1.3.5/lib/bundler/runtime.rb:72:in `block (2 levels) in require'
/usr/lib64/ruby/gems/1.9.3/gems/bundler-1.3.5/lib/bundler/runtime.rb:70:in `each'
/usr/lib64/ruby/gems/1.9.3/gems/bundler-1.3.5/lib/bundler/runtime.rb:70:in `block in require'
/usr/lib64/ruby/gems/1.9.3/gems/bundler-1.3.5/lib/bundler/runtime.rb:59:in `each'
/usr/lib64/ruby/gems/1.9.3/gems/bundler-1.3.5/lib/bundler/runtime.rb:59:in `require'
/usr/lib64/ruby/gems/1.9.3/gems/bundler-1.3.5/lib/bundler.rb:132:in `require'
/home3/audichne/juvia/config/application.rb:14:in `<top (required)>'
/home3/audichne/juvia/Rakefile:4:in `require'
/home3/audichne/juvia/Rakefile:4:in `<top (required)>'
/home3/audichne/juvia/help/ruby/1.9.3/gems/rake-10.3.1/lib/rake/rake_module.rb:28:in `load'
/home3/audichne/juvia/help/ruby/1.9.3/gems/rake-10.3.1/lib/rake/rake_module.rb:28:in `load_rakefile'
/home3/audichne/juvia/help/ruby/1.9.3/gems/rake-10.3.1/lib/rake/application.rb:683:in `raw_load_rakefile'
/home3/audichne/juvia/help/ruby/1.9.3/gems/rake-10.3.1/lib/rake/application.rb:94:in `block in load_rakefile'
/home3/audichne/juvia/help/ruby/1.9.3/gems/rake-10.3.1/lib/rake/application.rb:176:in `standard_exception_handling'
/home3/audichne/juvia/help/ruby/1.9.3/gems/rake-10.3.1/lib/rake/application.rb:93:in `load_rakefile'
/home3/audichne/juvia/help/ruby/1.9.3/gems/rake-10.3.1/lib/rake/application.rb:77:in `block in run'
/home3/audichne/juvia/help/ruby/1.9.3/gems/rake-10.3.1/lib/rake/application.rb:176:in `standard_exception_handling'
/home3/audichne/juvia/help/ruby/1.9.3/gems/rake-10.3.1/lib/rake/application.rb:75:in `run'
/home3/audichne/juvia/help/ruby/1.9.3/gems/rake-10.3.1/bin/rake:33:in `<top (required)>'
/home3/audichne/juvia/help/ruby/1.9.3/bin/rake:23:in `load'
/home3/audichne/juvia/help/ruby/1.9.3/bin/rake:23:in `<main>'

All the other installation commands ran without a hitch.

Postgresql problems on Heroku

I have set up Juvia following the install instructions, setting my production database type to mysql2. All the rake executions happend without problems, and I have pushed my Juvia install to Heroku.

However, when I try to load a page via Heroku, the app crashes with the following error:

/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.10/lib/active_record/connection_adapters/abstract/connection_specification.rb:71:in `rescue in establish_connection': Please install the postgresql adapter: `gem install activerecord-postgresql-adapter` (pg is not part of the bundle. Add it to Gemfile.) (RuntimeError)

Is there a way to get Juvia to run without postgres support? I am having trouble setting up a postgres environment on my machine, so I cannot easily gem install activerecord-postgresql-adapter or gem install pg. Unless I am misunderstanding, though, Juvia should not require these to talk to mysql?

Syntax error in assets/application.js.coffee

When I try to precompile the assets I get

Could not load sequel gem, so WordPress import will not work.
rake aborted!
SyntaxError: unexpected =
  (in /var/www/.../app/assets/javascripts/application.js.coffee)
/var/www/.../help/ruby/2.0.0/gems/execjs-1.4.0/lib/execjs/external_runtime.rb:66:in `extract_result'
/var/www/.../help/ruby/2.0.0/gems/execjs-1.4.0/lib/execjs/external_runtime.rb:28:in `block in exec'
...

Calling coffee application.js.coffee on the commandline results in the same error:

application.js.coffee:1:3: error: unexpected =
//= require jquery-1.7.1.min.js
  ^

I have next to no experience with rails but from what I find on the web regarding the assets pipeline, it seems #= require should be used instead of //= require in a coffeescript file. Changing this removes the error, but the jquery-code does not show up in the resulting application.js.

Any hints? Thanks.

Difficulty executing installation instructions

Thanks for providing what looks like a very promising open source alternative to disqus.

Unfortunately I've been unable to run your install directions as provided. I'm not experienced with rails apps, so my apologies if this is elementary. First couple steps are fine, but upon running

bundle exec rake db:schema:load RAILS_ENV=production

I hit the error and traceback shown below. Any hints as to what I've done wrong here? Many thanks for your advice.

Could not load sequel gem, so WordPress import will not work.
rake aborted!
No such file or directory - /home/cboettig/Documents/code/thirdparty/juvia/config/application.yml
/home/cboettig/Documents/code/thirdparty/juvia/lib/app_config.rb:76:in `block in <class:Railtie>'
/home/cboettig/Documents/code/thirdparty/juvia/help/ruby/1.9.1/gems/railties-3.1.10/lib/rails/initializable.rb:30:in `instance_exec'
/home/cboettig/Documents/code/thirdparty/juvia/help/ruby/1.9.1/gems/railties-3.1.10/lib/rails/initializable.rb:30:in `run'
/home/cboettig/Documents/code/thirdparty/juvia/help/ruby/1.9.1/gems/railties-3.1.10/lib/rails/initializable.rb:55:in `block in run_initializers'
/home/cboettig/Documents/code/thirdparty/juvia/help/ruby/1.9.1/gems/railties-3.1.10/lib/rails/initializable.rb:54:in `each'
/home/cboettig/Documents/code/thirdparty/juvia/help/ruby/1.9.1/gems/railties-3.1.10/lib/rails/initializable.rb:54:in `run_initializers'
/home/cboettig/Documents/code/thirdparty/juvia/help/ruby/1.9.1/gems/railties-3.1.10/lib/rails/application.rb:96:in `initialize!'
/home/cboettig/Documents/code/thirdparty/juvia/help/ruby/1.9.1/gems/railties-3.1.10/lib/rails/railtie/configurable.rb:30:in `method_missing'
/home/cboettig/Documents/code/thirdparty/juvia/config/environment.rb:5:in `<top (required)>'
/home/cboettig/Documents/code/thirdparty/juvia/help/ruby/1.9.1/gems/activesupport-3.1.10/lib/active_support/dependencies.rb:240:in `require'
/home/cboettig/Documents/code/thirdparty/juvia/help/ruby/1.9.1/gems/activesupport-3.1.10/lib/active_support/dependencies.rb:240:in `block in require'
/home/cboettig/Documents/code/thirdparty/juvia/help/ruby/1.9.1/gems/activesupport-3.1.10/lib/active_support/dependencies.rb:223:in `block in load_dependency'
/home/cboettig/Documents/code/thirdparty/juvia/help/ruby/1.9.1/gems/activesupport-3.1.10/lib/active_support/dependencies.rb:640:in `new_constants_in'
/home/cboettig/Documents/code/thirdparty/juvia/help/ruby/1.9.1/gems/activesupport-3.1.10/lib/active_support/dependencies.rb:223:in `load_dependency'
/home/cboettig/Documents/code/thirdparty/juvia/help/ruby/1.9.1/gems/activesupport-3.1.10/lib/active_support/dependencies.rb:240:in `require'
/home/cboettig/Documents/code/thirdparty/juvia/help/ruby/1.9.1/gems/railties-3.1.10/lib/rails/application.rb:83:in `require_environment!'
/home/cboettig/Documents/code/thirdparty/juvia/help/ruby/1.9.1/gems/railties-3.1.10/lib/rails/application.rb:203:in `block (2 levels) in initialize_tasks'

Syntax error in JS

My comment form is not rendering due to the following error (from Console):

 Uncaught Error: Syntax error, unrecognized expression: (a CSS path)

generated from the following lines of code (since this line was condensed, it didn't tell me what line):

f.event = {
        add: function(a, c, d, e, g) {
            var h, i, j, k, l, m, n, o, p, q, r, s;
            if (!(a.nodeType === 3 || a.nodeType === 8 || !c || !d || !(h = f._data(a)))) {
                d.handler && (p = d, d = p.handler), d.guid || (d.guid = f.guid++), j = h.events, j || (h.events = j = {}), i = h.handle, i || (h.handle = i = function(a) {
                    return typeof f != "undefined" && (!a || f.event.triggered !== a.type) ? f.event.dispatch.apply(i.elem, arguments) : b
                }, i.elem = a), c = f.trim(I(c)).split(" ");
                for (k = 0; k < c.length; k++) {
                    l = A.exec(c[k]) || [], m = l[1], n = (l[2] || "").split(".").sort(), s = f.event.special[m] || {}, m = (g ? s.delegateType : s.bindType) || m, s = f.event.special[m] || {}, o = f.extend({
                        type: m,
                        origType: l[1],
                        data: e,
                        handler: d,
                        guid: d.guid,
                        selector: g,
                        quick: G(g),
                        namespace: n.join(".")
                    }, p), r = j[m];
                    if (!r) {
                        r = j[m] = [], r.delegateCount = 0;
                        if (!s.setup || s.setup.call(a, e, n, i) === !1) a.addEventListener ? a.addEventListener(m, i, !1) : a.attachEvent && a.attachEvent("on" + m, i)
                    }
                    s.add && (s.add.call(a, o), o.handler.guid || (o.handler.guid = d.guid)), g ? r.splice(r.delegateCount++, 0, o) : r.push(o), f.event.global[m] = !0
                }
                a = null
            }
        },
        global: {},
        remove: function(a, b, c, d, e) {
            var g = f.hasData(a) && f._data(a),
                h, i, j, k, l, m, n, o, p, q, r, s;
            if (!!g && !!(o = g.events)) {
                b = f.trim(I(b || "")).split(" ");
                for (h = 0; h < b.length; h++) {
                    i = A.exec(b[h]) || [], j = k = i[1], l = i[2];
                    if (!j) {
                        for (j in o) f.event.remove(a, j + b[h], c, d, !0);
                        continue
                    }
                    p = f.event.special[j] || {}, j = (d ? p.delegateType : p.bindType) || j, r = o[j] || [], m = r.length, l = l ? new RegExp("(^|\\.)" + l.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
                    for (n = 0; n < r.length; n++) s = r[n], (e || k === s.origType) && (!c || c.guid === s.guid) && (!l || l.test(s.namespace)) && (!d || d === s.selector || d === "**" && s.selector) && (r.splice(n--, 1), s.selector && r.delegateCount--, p.remove && p.remove.call(a, s));
                    r.length === 0 && m !== r.length && ((!p.teardown || p.teardown.call(a, l) === !1) && f.removeEvent(a, j, g.handle), delete o[j])
                }
                f.isEmptyObject(o) && (q = g.handle, q && (q.elem = null), f.removeData(a, ["events", "handle"], !0))
            }
        },
        customEvent: {
            getData: !0,
            setData: !0,
            changeData: !0
        },
        trigger: function(c, d, e, g) {
            if (!e || e.nodeType !== 3 && e.nodeType !== 8) {
                var h = c.type || c,
                    i = [],
                    j, k, l, m, n, o, p, q, r, s;
                if (E.test(h + f.event.triggered)) return;
                h.indexOf("!") >= 0 && (h = h.slice(0, -1), k = !0), h.indexOf(".") >= 0 && (i = h.split("."), h = i.shift(), i.sort());
                if ((!e || f.event.customEvent[h]) && !f.event.global[h]) return;
                c = typeof c == "object" ? c[f.expando] ? c : new f.Event(h, c) : new f.Event(h), c.type = h, c.isTrigger = !0, c.exclusive = k, c.namespace = i.join("."), c.namespace_re = c.namespace ? new RegExp("(^|\\.)" + i.join("\\.(?:.*\\.)?") + "(\\.|$)") : null, o = h.indexOf(":") < 0 ? "on" + h : "";
                if (!e) {
                    j = f.cache;
                    for (l in j) j[l].events && j[l].events[h] && f.event.trigger(c, d, j[l].handle.elem, !0);
                    return
                }
                c.result = b, c.target || (c.target = e), d = d != null ? f.makeArray(d) : [], d.unshift(c), p = f.event.special[h] || {};
                if (p.trigger && p.trigger.apply(e, d) === !1) return;
                r = [
                    [e, p.bindType || h]
                ];
                if (!g && !p.noBubble && !f.isWindow(e)) {
                    s = p.delegateType || h, m = E.test(s + h) ? e : e.parentNode, n = null;
                    for (; m; m = m.parentNode) r.push([m, s]), n = m;
                    n && n === e.ownerDocument && r.push([n.defaultView || n.parentWindow || a, s])
                }
                for (l = 0; l < r.length && !c.isPropagationStopped(); l++) m = r[l][0], c.type = r[l][1], q = (f._data(m, "events") || {})[c.type] && f._data(m, "handle"), q && q.apply(m, d), q = o && m[o], q && f.acceptData(m) && q.apply(m, d) === !1 && c.preventDefault();
                c.type = h, !g && !c.isDefaultPrevented() && (!p._default || p._default.apply(e.ownerDocument, d) === !1) && (h !== "click" || !f.nodeName(e, "a")) && f.acceptData(e) && o && e[h] && (h !== "focus" && h !== "blur" || c.target.offsetWidth !== 0) && !f.isWindow(e) && (n = e[o], n && (e[o] = null), f.event.triggered = h, e[h](), f.event.triggered = b, n && (e[o] = n));
                return c.result
            }
        },
        dispatch: function(c) {
            c = f.event.fix(c || a.event);
            var d = (f._data(this, "events") || {})[c.type] || [],
                e = d.delegateCount,
                g = [].slice.call(arguments, 0),
                h = !c.exclusive && !c.namespace,
                i = [],
                j, k, l, m, n, o, p, q, r, s, t;
            g[0] = c, c.delegateTarget = this;
            if (e && !c.target.disabled && (!c.button || c.type !== "click")) {
                m = f(this), m.context = this.ownerDocument || this;
                for (l = c.target; l != this; l = l.parentNode || this) {
                    o = {}, q = [], m[0] = l;
                    for (j = 0; j < e; j++) r = d[j], s = r.selector, o[s] === b && (o[s] = r.quick ? H(l, r.quick) : m.is(s)), o[s] && q.push(r);
                    q.length && i.push({
                        elem: l,
                        matches: q
                    })
                }
            }
            d.length > e && i.push({
                elem: this,
                matches: d.slice(e)
            });
            for (j = 0; j < i.length && !c.isPropagationStopped(); j++) {
                p = i[j], c.currentTarget = p.elem;
                for (k = 0; k < p.matches.length && !c.isImmediatePropagationStopped(); k++) {
                    r = p.matches[k];
                    if (h || !c.namespace && !r.namespace || c.namespace_re && c.namespace_re.test(r.namespace)) c.data = r.data, c.handleObj = r, n = ((f.event.special[r.origType] || {}).handle || r.handler).apply(p.elem, g), n !== b && (c.result = n, n === !1 && (c.preventDefault(), c.stopPropagation()))
                }
            }
            return c.result
        },
        props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
        fixHooks: {},
        keyHooks: {
            props: "char charCode key keyCode".split(" "),
            filter: function(a, b) {
                a.which == null && (a.which = b.charCode != null ? b.charCode : b.keyCode);
                return a
            }
        },
        mouseHooks: {
            props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
            filter: function(a, d) {
                var e, f, g, h = d.button,
                    i = d.fromElement;
                a.pageX == null && d.clientX != null && (e = a.target.ownerDocument || c, f = e.documentElement, g = e.body, a.pageX = d.clientX + (f && f.scrollLeft || g && g.scrollLeft || 0) - (f && f.clientLeft || g && g.clientLeft || 0), a.pageY = d.clientY + (f && f.scrollTop || g && g.scrollTop || 0) - (f && f.clientTop || g && g.clientTop || 0)), !a.relatedTarget && i && (a.relatedTarget = i === a.target ? d.toElement : i), !a.which && h !== b && (a.which = h & 1 ? 1 : h & 2 ? 3 : h & 4 ? 2 : 0);
                return a
            }
        },
        fix: function(a) {
            if (a[f.expando]) return a;
            var d, e, g = a,
                h = f.event.fixHooks[a.type] || {},
                i = h.props ? this.props.concat(h.props) : this.props;
            a = f.Event(g);
            for (d = i.length; d;) e = i[--d], a[e] = g[e];
            a.target || (a.target = g.srcElement || c), a.target.nodeType === 3 && (a.target = a.target.parentNode), a.metaKey === b && (a.metaKey = a.ctrlKey);
            return h.filter ? h.filter(a, g) : a
        },
        special: {
            ready: {
                setup: f.bindReady
            },
            load: {
                noBubble: !0
            },
            focus: {
                delegateType: "focusin"
            },
            blur: {
                delegateType: "focusout"
            },
            beforeunload: {
                setup: function(a, b, c) {
                    f.isWindow(this) && (this.onbeforeunload = c)
                },
                teardown: function(a, b) {
                    this.onbeforeunload === b && (this.onbeforeunload = null)
                }
            }
        },
        simulate: function(a, b, c, d) {
            var e = f.extend(new f.Event, c, {
                type: a,
                isSimulated: !0,
                originalEvent: {}
            });
            d ? f.event.trigger(e, null, b) : f.event.dispatch.call(b, e), e.isDefaultPrevented() && c.preventDefault()
        }
    }, f.event.handle = f.event.dispatch, f.removeEvent = c.removeEventListener ? function(a, b, c) {
        a.removeEventListener && a.removeEventListener(b, c, !1)
    } : function(a, b, c) {
        a.detachEvent && a.detachEvent("on" + b, c)
    }, f.Event = function(a, b) {
        if (!(this instanceof f.Event)) return new f.Event(a, b);
        a && a.type ? (this.originalEvent = a, this.type = a.type, this.isDefaultPrevented = a.defaultPrevented || a.returnValue === !1 || a.getPreventDefault && a.getPreventDefault() ? K : J) : this.type = a, b && f.extend(this, b), this.timeStamp = a && a.timeStamp || f.now(), this[f.expando] = !0
    }, f.Event.prototype = {
        preventDefault: function() {
            this.isDefaultPrevented = K;
            var a = this.originalEvent;
            !a || (a.preventDefault ? a.preventDefault() : a.returnValue = !1)
        },
        stopPropagation: function() {
            this.isPropagationStopped = K;
            var a = this.originalEvent;
            !a || (a.stopPropagation && a.stopPropagation(), a.cancelBubble = !0)
        },
        stopImmediatePropagation: function() {
            this.isImmediatePropagationStopped = K, this.stopPropagation()
        },
        isDefaultPrevented: J,
        isPropagationStopped: J,
        isImmediatePropagationStopped: J
    }, f.each({
        mouseenter: "mouseover",
        mouseleave: "mouseout"
    }, function(a, b) {
        f.event.special[a] = {
            delegateType: b,
            bindType: b,
            handle: function(a) {
                var c = this,
                    d = a.relatedTarget,
                    e = a.handleObj,
                    g = e.selector,
                    h;
                if (!d || d !== c && !f.contains(c, d)) a.type = e.origType, h = e.handler.apply(this, arguments), a.type = b;
                return h
            }
        }
    }), f.support.submitBubbles || (f.event.special.submit = {
        setup: function() {
            if (f.nodeName(this, "form")) return !1;
            f.event.add(this, "click._submit keypress._submit", function(a) {
                var c = a.target,
                    d = f.nodeName(c, "input") || f.nodeName(c, "button") ? c.form : b;
                d && !d._submit_attached && (f.event.add(d, "submit._submit", function(a) {
                    this.parentNode && !a.isTrigger && f.event.simulate("submit", this.parentNode, a, !0)
                }), d._submit_attached = !0)
            })
        },
        teardown: function() {
            if (f.nodeName(this, "form")) return !1;
            f.event.remove(this, "._submit")
        }
    }), f.support.changeBubbles || (f.event.special.change = {
        setup: function() {
            if (z.test(this.nodeName)) {
                if (this.type === "checkbox" || this.type === "radio") f.event.add(this, "propertychange._change", function(a) {
                    a.originalEvent.propertyName === "checked" && (this._just_changed = !0)
                }), f.event.add(this, "click._change", function(a) {
                    this._just_changed && !a.isTrigger && (this._just_changed = !1, f.event.simulate("change", this, a, !0))
                });
                return !1
            }
            f.event.add(this, "beforeactivate._change", function(a) {
                var b = a.target;
                z.test(b.nodeName) && !b._change_attached && (f.event.add(b, "change._change", function(a) {
                    this.parentNode && !a.isSimulated && !a.isTrigger && f.event.simulate("change", this.parentNode, a, !0)
                }), b._change_attached = !0)
            })
        },
        handle: function(a) {
            var b = a.target;
            if (this !== b || a.isSimulated || a.isTrigger || b.type !== "radio" && b.type !== "checkbox") return a.handleObj.handler.apply(this, arguments)
        },
        teardown: function() {
            f.event.remove(this, "._change");
            return z.test(this.nodeName)
        }
    }), f.support.focusinBubbles || f.each({
        focus: "focusin",
        blur: "focusout"
    }, function(a, b) {
        var d = 0,
            e = function(a) {
                f.event.simulate(b, a.target, f.event.fix(a), !0)
            };
        f.event.special[b] = {
            setup: function() {
                d++ === 0 && c.addEventListener(a, e, !0)
            },
            teardown: function() {
                --d === 0 && c.removeEventListener(a, e, !0)
            }
        }
    }), f.fn.extend({
        on: function(a, c, d, e, g) {
            var h, i;
            if (typeof a == "object") {
                typeof c != "string" && (d = c, c = b);
                for (i in a) this.on(i, c, d, a[i], g);
                return this
            }
            d == null && e == null ? (e = c, d = c = b) : e == null && (typeof c == "string" ? (e = d, d = b) : (e = d, d = c, c = b));
            if (e === !1) e = J;
            else if (!e) return this;
            g === 1 && (h = e, e = function(a) {
                f().off(a);
                return h.apply(this, arguments)
            }, e.guid = h.guid || (h.guid = f.guid++));
            return this.each(function() {
                f.event.add(this, a, e, d, c)
            })
        },
        one: function(a, b, c, d) {
            return this.on.call(this, a, b, c, d, 1)
        },
        off: function(a, c, d) {
            if (a && a.preventDefault && a.handleObj) {
                var e = a.handleObj;
                f(a.delegateTarget).off(e.namespace ? e.type + "." + e.namespace : e.type, e.selector, e.handler);
                return this
            }
            if (typeof a == "object") {
                for (var g in a) this.off(g, c, a[g]);
                return this
            }
            if (c === !1 || typeof c == "function") d = c, c = b;
            d === !1 && (d = J);
            return this.each(function() {
                f.event.remove(this, a, d, c)
            })
        },
        bind: function(a, b, c) {
            return this.on(a, null, b, c)
        },
        unbind: function(a, b) {
            return this.off(a, null, b)
        },
        live: function(a, b, c) {
            f(this.context).on(a, this.selector, b, c);
            return this
        },
        die: function(a, b) {
            f(this.context).off(a, this.selector || "**", b);
            return this
        },
        delegate: function(a, b, c, d) {
            return this.on(b, a, c, d)
        },
        undelegate: function(a, b, c) {
            return arguments.length == 1 ? this.off(a, "**") : this.off(b, a, c)
        },
        trigger: function(a, b) {
            return this.each(function() {
                f.event.trigger(a, b, this)
            })
        },
        triggerHandler: function(a, b) {
            if (this[0]) return f.event.trigger(a, b, this[0], !0)
        },
        toggle: function(a) {
            var b = arguments,
                c = a.guid || f.guid++,
                d = 0,
                e = function(c) {
                    var e = (f._data(this, "lastToggle" + a.guid) || 0) % d;
                    f._data(this, "lastToggle" + a.guid, e + 1), c.preventDefault();
                    return b[e].apply(this, arguments) || !1
                };
            e.guid = c;
            while (d < b.length) b[d++].guid = c;
            return this.click(e)
        },
        hover: function(a, b) {
            return this.mouseenter(a).mouseleave(b || a)
        }
    }), f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "), function(a, b) {
        f.fn[b] = function(a, c) {
            c == null && (c = a, a = null);
            return arguments.length > 0 ? this.on(b, null, a, c) : this.trigger(b)
        }, f.attrFn && (f.attrFn[b] = !0), C.test(b) && (f.event.fixHooks[b] = f.event.keyHooks), D.test(b) && (f.event.fixHooks[b] = f.event.mouseHooks)
    }),
    function() {
        function x(a, b, c, e, f, g) {
            for (var h = 0, i = e.length; h < i; h++) {
                var j = e[h];
                if (j) {
                    var k = !1;
                    j = j[a];
                    while (j) {
                        if (j[d] === c) {
                            k = e[j.sizset];
                            break
                        }
                        if (j.nodeType === 1) {
                            g || (j[d] = c, j.sizset = h);
                            if (typeof b != "string") {
                                if (j === b) {
                                    k = !0;
                                    break
                                }
                            } else if (m.filter(b, [j]).length > 0) {
                                k = j;
                                break
                            }
                        }
                        j = j[a]
                    }
                    e[h] = k
                }
            }
        }

        function w(a, b, c, e, f, g) {
            for (var h = 0, i = e.length; h < i; h++) {
                var j = e[h];
                if (j) {
                    var k = !1;
                    j = j[a];
                    while (j) {
                        if (j[d] === c) {
                            k = e[j.sizset];
                            break
                        }
                        j.nodeType === 1 && !g && (j[d] = c, j.sizset = h);
                        if (j.nodeName.toLowerCase() === b) {
                            k = j;
                            break
                        }
                        j = j[a]
                    }
                    e[h] = k
                }
            }
        }
        var a = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
            d = "sizcache" + (Math.random() + "").replace(".", ""),
            e = 0,
            g = Object.prototype.toString,
            h = !1,
            i = !0,
            j = /\\/g,
            k = /\r\n/g,
            l = /\W/;
        [0, 0].sort(function() {
            i = !1;
            return 0
        });
        var m = function(b, d, e, f) {
            e = e || [], d = d || c;
            var h = d;
            if (d.nodeType !== 1 && d.nodeType !== 9) return [];
            if (!b || typeof b != "string") return e;
            var i, j, k, l, n, q, r, t, u = !0,
                v = m.isXML(d),
                w = [],
                x = b;
            do {
                a.exec(""), i = a.exec(x);
                if (i) {
                    x = i[3], w.push(i[1]);
                    if (i[2]) {
                        l = i[3];
                        break
                    }
                }
            } while (i);
            if (w.length > 1 && p.exec(b))
                if (w.length === 2 && o.relative[w[0]]) j = y(w[0] + w[1], d, f);
                else {
                    j = o.relative[w[0]] ? [d] : m(w.shift(), d);
                    while (w.length) b = w.shift(), o.relative[b] && (b += w.shift()), j = y(b, j, f)
                } else {
                !f && w.length > 1 && d.nodeType === 9 && !v && o.match.ID.test(w[0]) && !o.match.ID.test(w[w.length - 1]) && (n = m.find(w.shift(), d, v), d = n.expr ? m.filter(n.expr, n.set)[0] : n.set[0]);
                if (d) {
                    n = f ? {
                        expr: w.pop(),
                        set: s(f)
                    } : m.find(w.pop(), w.length === 1 && (w[0] === "~" || w[0] === "+") && d.parentNode ? d.parentNode : d, v), j = n.expr ? m.filter(n.expr, n.set) : n.set, w.length > 0 ? k = s(j) : u = !1;
                    while (w.length) q = w.pop(), r = q, o.relative[q] ? r = w.pop() : q = "", r == null && (r = d), o.relative[q](k, r, v)
                } else k = w = []
            }
            k || (k = j), k || m.error(q || b);
            if (g.call(k) === "[object Array]")
                if (!u) e.push.apply(e, k);
                else if (d && d.nodeType === 1)
                for (t = 0; k[t] != null; t++) k[t] && (k[t] === !0 || k[t].nodeType === 1 && m.contains(d, k[t])) && e.push(j[t]);
            else
                for (t = 0; k[t] != null; t++) k[t] && k[t].nodeType === 1 && e.push(j[t]);
            else s(k, e);
            l && (m(l, h, e, f), m.uniqueSort(e));
            return e
        };
        m.uniqueSort = function(a) {
            if (u) {
                h = i, a.sort(u);
                if (h)
                    for (var b = 1; b < a.length; b++) a[b] === a[b - 1] && a.splice(b--, 1)
            }
            return a
        }, m.matches = function(a, b) {
            return m(a, null, null, b)
        }, m.matchesSelector = function(a, b) {
            return m(b, null, null, [a]).length > 0
        }, m.find = function(a, b, c) {
            var d, e, f, g, h, i;
            if (!a) return [];
            for (e = 0, f = o.order.length; e < f; e++) {
                h = o.order[e];
                if (g = o.leftMatch[h].exec(a)) {
                    i = g[1], g.splice(1, 1);
                    if (i.substr(i.length - 1) !== "\\") {
                        g[1] = (g[1] || "").replace(j, ""), d = o.find[h](g, b, c);
                        if (d != null) {
                            a = a.replace(o.match[h], "");
                            break
                        }
                    }
                }
            }
            d || (d = typeof b.getElementsByTagName != "undefined" ? b.getElementsByTagName("*") : []);
            return {
                set: d,
                expr: a
            }
        }, m.filter = function(a, c, d, e) {
            var f, g, h, i, j, k, l, n, p, q = a,
                r = [],
                s = c,
                t = c && c[0] && m.isXML(c[0]);
            while (a && c.length) {
                for (h in o.filter)
                    if ((f = o.leftMatch[h].exec(a)) != null && f[2]) {
                        k = o.filter[h], l = f[1], g = !1, f.splice(1, 1);
                        if (l.substr(l.length - 1) === "\\") continue;
                        s === r && (r = []);
                        if (o.preFilter[h]) {
                            f = o.preFilter[h](f, s, d, r, e, t);
                            if (!f) g = i = !0;
                            else if (f === !0) continue
                        }
                        if (f)
                            for (n = 0;
                                (j = s[n]) != null; n++) j && (i = k(j, f, n, s), p = e ^ i, d && i != null ? p ? g = !0 : s[n] = !1 : p && (r.push(j), g = !0));
                        if (i !== b) {
                            d || (s = r), a = a.replace(o.match[h], "");
                            if (!g) return [];
                            break
                        }
                    }
                if (a === q)
                    if (g == null) m.error(a);
                    else break;
                q = a
            }
            return s
        }, m.error = function(a) {
            throw new Error("Syntax error, unrecognized expression: " + a)
        };
        var n = m.getText = function(a) {
                var b, c, d = a.nodeType,
                    e = "";
                if (d) {
                    if (d === 1 || d === 9) {
                        if (typeof a.textContent == "string") return a.textContent;
                        if (typeof a.innerText == "string") return a.innerText.replace(k, "");
                        for (a = a.firstChild; a; a = a.nextSibling) e += n(a)
                    } else if (d === 3 || d === 4) return a.nodeValue
                } else
                    for (b = 0; c = a[b]; b++) c.nodeType !== 8 && (e += n(c));
                return e
            },
            o = m.selectors = {
                order: ["ID", "NAME", "TAG"],
                match: {
                    ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
                    CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
                    NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
                    ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
                    TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
                    CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
                    POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
                    PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
                },
                leftMatch: {},
                attrMap: {
                    "class": "className",
                    "for": "htmlFor"
                },
                attrHandle: {
                    href: function(a) {
                        return a.getAttribute("href")
                    },
                    type: function(a) {
                        return a.getAttribute("type")
                    }
                },
                relative: {
                    "+": function(a, b) {
                        var c = typeof b == "string",
                            d = c && !l.test(b),
                            e = c && !d;
                        d && (b = b.toLowerCase());
                        for (var f = 0, g = a.length, h; f < g; f++)
                            if (h = a[f]) {
                                while ((h = h.previousSibling) && h.nodeType !== 1);
                                a[f] = e || h && h.nodeName.toLowerCase() === b ? h || !1 : h === b
                            }
                        e && m.filter(b, a, !0)
                    },
                    ">": function(a, b) {
                        var c, d = typeof b == "string",
                            e = 0,
                            f = a.length;
                        if (d && !l.test(b)) {
                            b = b.toLowerCase();
                            for (; e < f; e++) {
                                c = a[e];
                                if (c) {
                                    var g = c.parentNode;
                                    a[e] = g.nodeName.toLowerCase() === b ? g : !1
                                }
                            }
                        } else {
                            for (; e < f; e++) c = a[e], c && (a[e] = d ? c.parentNode : c.parentNode === b);
                            d && m.filter(b, a, !0)
                        }
                    },
                    "": function(a, b, c) {
                        var d, f = e++,
                            g = x;
                        typeof b == "string" && !l.test(b) && (b = b.toLowerCase(), d = b, g = w), g("parentNode", b, f, a, d, c)
                    },
                    "~": function(a, b, c) {
                        var d, f = e++,
                            g = x;
                        typeof b == "string" && !l.test(b) && (b = b.toLowerCase(), d = b, g = w), g("previousSibling", b, f, a, d, c)
                    }
                },
                find: {
                    ID: function(a, b, c) {
                        if (typeof b.getElementById != "undefined" && !c) {
                            var d = b.getElementById(a[1]);
                            return d && d.parentNode ? [d] : []
                        }
                    },
                    NAME: function(a, b) {
                        if (typeof b.getElementsByName != "undefined") {
                            var c = [],
                                d = b.getElementsByName(a[1]);
                            for (var e = 0, f = d.length; e < f; e++) d[e].getAttribute("name") === a[1] && c.push(d[e]);
                            return c.length === 0 ? null : c
                        }
                    },
                    TAG: function(a, b) {
                        if (typeof b.getElementsByTagName != "undefined") return b.getElementsByTagName(a[1])
                    }
                },
                preFilter: {
                    CLASS: function(a, b, c, d, e, f) {
                        a = " " + a[1].replace(j, "") + " ";
                        if (f) return a;
                        for (var g = 0, h;
                            (h = b[g]) != null; g++) h && (e ^ (h.className && (" " + h.className + " ").replace(/[\t\n\r]/g, " ").indexOf(a) >= 0) ? c || d.push(h) : c && (b[g] = !1));
                        return !1
                    },
                    ID: function(a) {
                        return a[1].replace(j, "")
                    },
                    TAG: function(a, b) {
                        return a[1].replace(j, "").toLowerCase()
                    },
                    CHILD: function(a) {
                        if (a[1] === "nth") {
                            a[2] || m.error(a[0]), a[2] = a[2].replace(/^\+|\s*/g, "");
                            var b = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2] === "even" && "2n" || a[2] === "odd" && "2n+1" || !/\D/.test(a[2]) && "0n+" + a[2] || a[2]);
                            a[2] = b[1] + (b[2] || 1) - 0, a[3] = b[3] - 0
                        } else a[2] && m.error(a[0]);
                        a[0] = e++;
                        return a
                    },
                    ATTR: function(a, b, c, d, e, f) {
                        var g = a[1] = a[1].replace(j, "");
                        !f && o.attrMap[g] && (a[1] = o.attrMap[g]), a[4] = (a[4] || a[5] || "").replace(j, ""), a[2] === "~=" && (a[4] = " " + a[4] + " ");
                        return a
                    },
                    PSEUDO: function(b, c, d, e, f) {
                        if (b[1] === "not")
                            if ((a.exec(b[3]) || "").length > 1 || /^\w/.test(b[3])) b[3] = m(b[3], null, null, c);
                            else {
                                var g = m.filter(b[3], c, d, !0 ^ f);
                                d || e.push.apply(e, g);
                                return !1
                            } else if (o.match.POS.test(b[0]) || o.match.CHILD.test(b[0])) return !0;
                        return b
                    },
                    POS: function(a) {
                        a.unshift(!0);
                        return a
                    }
                },
                filters: {
                    enabled: function(a) {
                        return a.disabled === !1 && a.type !== "hidden"
                    },
                    disabled: function(a) {
                        return a.disabled === !0
                    },
                    checked: function(a) {
                        return a.checked === !0
                    },
                    selected: function(a) {
                        a.parentNode && a.parentNode.selectedIndex;
                        return a.selected === !0
                    },
                    parent: function(a) {
                        return !!a.firstChild
                    },
                    empty: function(a) {
                        return !a.firstChild
                    },
                    has: function(a, b, c) {
                        return !!m(c[3], a).length
                    },
                    header: function(a) {
                        return /h\d/i.test(a.nodeName)
                    },
                    text: function(a) {
                        var b = a.getAttribute("type"),
                            c = a.type;
                        return a.nodeName.toLowerCase() === "input" && "text" === c && (b === c || b === null)
                    },
                    radio: function(a) {
                        return a.nodeName.toLowerCase() === "input" && "radio" === a.type
                    },
                    checkbox: function(a) {
                        return a.nodeName.toLowerCase() === "input" && "checkbox" === a.type
                    },
                    file: function(a) {
                        return a.nodeName.toLowerCase() === "input" && "file" === a.type
                    },
                    password: function(a) {
                        return a.nodeName.toLowerCase() === "input" && "password" === a.type
                    },
                    submit: function(a) {
                        var b = a.nodeName.toLowerCase();
                        return (b === "input" || b === "button") && "submit" === a.type
                    },
                    image: function(a) {
                        return a.nodeName.toLowerCase() === "input" && "image" === a.type
                    },
                    reset: function(a) {
                        var b = a.nodeName.toLowerCase();
                        return (b === "input" || b === "button") && "reset" === a.type
                    },
                    button: function(a) {
                        var b = a.nodeName.toLowerCase();
                        return b === "input" && "button" === a.type || b === "button"
                    },
                    input: function(a) {
                        return /input|select|textarea|button/i.test(a.nodeName)
                    },
                    focus: function(a) {
                        return a === a.ownerDocument.activeElement
                    }
                },
                setFilters: {
                    first: function(a, b) {
                        return b === 0
                    },
                    last: function(a, b, c, d) {
                        return b === d.length - 1
                    },
                    even: function(a, b) {
                        return b % 2 === 0
                    },
                    odd: function(a, b) {
                        return b % 2 === 1
                    },
                    lt: function(a, b, c) {
                        return b < c[3] - 0
                    },
                    gt: function(a, b, c) {
                        return b > c[3] - 0
                    },
                    nth: function(a, b, c) {
                        return c[3] - 0 === b
                    },
                    eq: function(a, b, c) {
                        return c[3] - 0 === b
                    }
                },
                filter: {
                    PSEUDO: function(a, b, c, d) {
                        var e = b[1],
                            f = o.filters[e];
                        if (f) return f(a, c, b, d);
                        if (e === "contains") return (a.textContent || a.innerText || n([a]) || "").indexOf(b[3]) >= 0;
                        if (e === "not") {
                            var g = b[3];
                            for (var h = 0, i = g.length; h < i; h++)
                                if (g[h] === a) return !1;
                            return !0
                        }
                        m.error(e)
                    },
                    CHILD: function(a, b) {
                        var c, e, f, g, h, i, j, k = b[1],
                            l = a;
                        switch (k) {
                            case "only":
                            case "first":
                                while (l = l.previousSibling)
                                    if (l.nodeType === 1) return !1;
                                if (k === "first") return !0;
                                l = a;
                            case "last":
                                while (l = l.nextSibling)
                                    if (l.nodeType === 1) return !1;
                                return !0;
                            case "nth":
                                c = b[2], e = b[3];
                                if (c === 1 && e === 0) return !0;
                                f = b[0], g = a.parentNode;
                                if (g && (g[d] !== f || !a.nodeIndex)) {
                                    i = 0;
                                    for (l = g.firstChild; l; l = l.nextSibling) l.nodeType === 1 && (l.nodeIndex = ++i);
                                    g[d] = f
                                }
                                j = a.nodeIndex - e;
                                return c === 0 ? j === 0 : j % c === 0 && j / c >= 0
                        }
                    },
                    ID: function(a, b) {
                        return a.nodeType === 1 && a.getAttribute("id") === b
                    },
                    TAG: function(a, b) {
                        return b === "*" && a.nodeType === 1 || !!a.nodeName && a.nodeName.toLowerCase() === b
                    },
                    CLASS: function(a, b) {
                        return (" " + (a.className || a.getAttribute("class")) + " ").indexOf(b) > -1
                    },
                    ATTR: function(a, b) {
                        var c = b[1],
                            d = m.attr ? m.attr(a, c) : o.attrHandle[c] ? o.attrHandle[c](a) : a[c] != null ? a[c] : a.getAttribute(c),
                            e = d + "",
                            f = b[2],
                            g = b[4];
                        return d == null ? f === "!=" : !f && m.attr ? d != null : f === "=" ? e === g : f === "*=" ? e.indexOf(g) >= 0 : f === "~=" ? (" " + e + " ").indexOf(g) >= 0 : g ? f === "!=" ? e !== g : f === "^=" ? e.indexOf(g) === 0 : f === "$=" ? e.substr(e.length - g.length) === g : f === "|=" ? e === g || e.substr(0, g.length + 1) === g + "-" : !1 : e && d !== !1
                    },
                    POS: function(a, b, c, d) {
                        var e = b[2],
                            f = o.setFilters[e];
                        if (f) return f(a, c, b, d)
                    }
                }
            },
            p = o.match.POS,
            q = function(a, b) {
                return "\\" + (b - 0 + 1)
            };
        for (var r in o.match) o.match[r] = new RegExp(o.match[r].source + /(?![^\[]*\])(?![^\(]*\))/.source), o.leftMatch[r] = new RegExp(/(^(?:.|\r|\n)*?)/.source + o.match[r].source.replace(/\\(\d+)/g, q));
        var s = function(a, b) {
            a = Array.prototype.slice.call(a, 0);
            if (b) {
                b.push.apply(b, a);
                return b
            }
            return a
        };
        try {
            Array.prototype.slice.call(c.documentElement.childNodes, 0)[0].nodeType
        } catch (t) {
            s = function(a, b) {
                var c = 0,
                    d = b || [];
                if (g.call(a) === "[object Array]") Array.prototype.push.apply(d, a);
                else if (typeof a.length == "number")
                    for (var e = a.length; c < e; c++) d.push(a[c]);
                else
                    for (; a[c]; c++) d.push(a[c]);
                return d
            }
        }
        var u, v;
        c.documentElement.compareDocumentPosition ? u = function(a, b) {
                if (a === b) {
                    h = !0;
                    return 0
                }
                if (!a.compareDocumentPosition || !b.compareDocumentPosition) return a.compareDocumentPosition ? -1 : 1;
                return a.compareDocumentPosition(b) & 4 ? -1 : 1
            } : (u = function(a, b) {
                if (a === b) {
                    h = !0;
                    return 0
                }
                if (a.sourceIndex && b.sourceIndex) return a.sourceIndex - b.sourceIndex;
                var c, d, e = [],
                    f = [],
                    g = a.parentNode,
                    i = b.parentNode,
                    j = g;
                if (g === i) return v(a, b);
                if (!g) return -1;
                if (!i) return 1;
                while (j) e.unshift(j), j = j.parentNode;
                j = i;
                while (j) f.unshift(j), j = j.parentNode;
                c = e.length, d = f.length;
                for (var k = 0; k < c && k < d; k++)
                    if (e[k] !== f[k]) return v(e[k], f[k]);
                return k === c ? v(a, f[k], -1) : v(e[k], b, 1)
            }, v = function(a, b, c) {
                if (a === b) return c;
                var d = a.nextSibling;
                while (d) {
                    if (d === b) return -1;
                    d = d.nextSibling
                }
                return 1
            }),
            function() {
                var a = c.createElement("div"),
                    d = "script" + (new Date).getTime(),
                    e = c.documentElement;
                a.innerHTML = "<a name='" + d + "'/>", e.insertBefore(a, e.firstChild), c.getElementById(d) && (o.find.ID = function(a, c, d) {
                    if (typeof c.getElementById != "undefined" && !d) {
                        var e = c.getElementById(a[1]);
                        return e ? e.id === a[1] || typeof e.getAttributeNode != "undefined" && e.getAttributeNode("id").nodeValue === a[1] ? [e] : b : []
                    }
                }, o.filter.ID = function(a, b) {
                    var c = typeof a.getAttributeNode != "undefined" && a.getAttributeNode("id");
                    return a.nodeType === 1 && c && c.nodeValue === b
                }), e.removeChild(a), e = a = null
            }(),
            function() {
                var a = c.createElement("div");
                a.appendChild(c.createComment("")), a.getElementsByTagName("*").length > 0 && (o.find.TAG = function(a, b) {
                    var c = b.getElementsByTagName(a[1]);
                    if (a[1] === "*") {
                        var d = [];
                        for (var e = 0; c[e]; e++) c[e].nodeType === 1 && d.push(c[e]);
                        c = d
                    }
                    return c
                }), a.innerHTML = "<a href='#'></a>", a.firstChild && typeof a.firstChild.getAttribute != "undefined" && a.firstChild.getAttribute("href") !== "#" && (o.attrHandle.href = function(a) {
                    return a.getAttribute("href", 2)
                }), a = null
            }(), c.querySelectorAll && function() {
                var a = m,
                    b = c.createElement("div"),
                    d = "__sizzle__";
                b.innerHTML = "<p class='TEST'></p>";
                if (!b.querySelectorAll || b.querySelectorAll(".TEST").length !== 0) {
                    m = function(b, e, f, g) {
                        e = e || c;
                        if (!g && !m.isXML(e)) {
                            var h = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);
                            if (h && (e.nodeType === 1 || e.nodeType === 9)) {
                                if (h[1]) return s(e.getElementsByTagName(b), f);
                                if (h[2] && o.find.CLASS && e.getElementsByClassName) return s(e.getElementsByClassName(h[2]), f)
                            }
                            if (e.nodeType === 9) {
                                if (b === "body" && e.body) return s([e.body], f);
                                if (h && h[3]) {
                                    var i = e.getElementById(h[3]);
                                    if (!i || !i.parentNode) return s([], f);
                                    if (i.id === h[3]) return s([i], f)
                                }
                                try {
                                    return s(e.querySelectorAll(b), f)
                                } catch (j) {}
                            } else if (e.nodeType === 1 && e.nodeName.toLowerCase() !== "object") {
                                var k = e,
                                    l = e.getAttribute("id"),
                                    n = l || d,
                                    p = e.parentNode,
                                    q = /^\s*[+~]/.test(b);
                                l ? n = n.replace(/'/g, "\\$&") : e.setAttribute("id", n), q && p && (e = e.parentNode);
                                try {
                                    if (!q || p) return s(e.querySelectorAll("[id='" + n + "'] " + b), f)
                                } catch (r) {} finally {
                                    l || k.removeAttribute("id")
                                }
                            }
                        }
                        return a(b, e, f, g)
                    };
                    for (var e in a) m[e] = a[e];
                    b = null
                }
            }(),
            function() {
                var a = c.documentElement,
                    b = a.matchesSelector || a.mozMatchesSelector || a.webkitMatchesSelector || a.msMatchesSelector;
                if (b) {
                    var d = !b.call(c.createElement("div"), "div"),
                        e = !1;
                    try {
                        b.call(c.documentElement, "[test!='']:sizzle")
                    } catch (f) {
                        e = !0
                    }
                    m.matchesSelector = function(a, c) {
                        c = c.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
                        if (!m.isXML(a)) try {
                            if (e || !o.match.PSEUDO.test(c) && !/!=/.test(c)) {
                                var f = b.call(a, c);
                                if (f || !d || a.document && a.document.nodeType !== 11) return f
                            }
                        } catch (g) {}
                        return m(c, null, null, [a]).length > 0
                    }
                }
            }(),
            function() {
                var a = c.createElement("div");
                a.innerHTML = "<div class='test e'></div><div class='test'></div>";
                if (!!a.getElementsByClassName && a.getElementsByClassName("e").length !== 0) {
                    a.lastChild.className = "e";
                    if (a.getElementsByClassName("e").length === 1) return;
                    o.order.splice(1, 0, "CLASS"), o.find.CLASS = function(a, b, c) {
                        if (typeof b.getElementsByClassName != "undefined" && !c) return b.getElementsByClassName(a[1])
                    }, a = null
                }
            }(), c.documentElement.contains ? m.contains = function(a, b) {
                return a !== b && (a.contains ? a.contains(b) : !0)
            } : c.documentElement.compareDocumentPosition ? m.contains = function(a, b) {
                return !!(a.compareDocumentPosition(b) & 16)
            } : m.contains = function() {
                return !1
            }, m.isXML = function(a) {
                var b = (a ? a.ownerDocument || a : 0).documentElement;
                return b ? b.nodeName !== "HTML" : !1
            };
        var y = function(a, b, c) {
            var d, e = [],
                f = "",
                g = b.nodeType ? [b] : b;
            while (d = o.match.PSEUDO.exec(a)) f += d[0], a = a.replace(o.match.PSEUDO, "");
            a = o.relative[a] ? a + "*" : a;
            for (var h = 0, i = g.length; h < i; h++) m(a, g[h], e, c);
            return m.filter(f, e)
        };
        m.attr = f.attr, m.selectors.attrMap = {}, f.find = m, f.expr = m.selectors, f.expr[":"] = f.expr.filters, f.unique = m.uniqueSort, f.text = m.getText, f.isXMLDoc = m.isXML, f.contains = m.contains
    }();
var L = /Until$/,
    M = /^(?:parents|prevUntil|prevAll)/,
    N = /,/,
    O = /^.[^:#\[\.,]*$/,
    P = Array.prototype.slice,
    Q = f.expr.match.POS,
    R = {
        children: !0,
        contents: !0,
        next: !0,
        prev: !0
    };
f.fn.extend({
    find: function(a) {
        var b = this,
            c, d;
        if (typeof a != "string") return f(a).filter(function() {
            for (c = 0, d = b.length; c < d; c++)
                if (f.contains(b[c], this)) return !0
        });
        var e = this.pushStack("", "find", a),
            g, h, i;
        for (c = 0, d = this.length; c < d; c++) {
            g = e.length, f.find(a, this[c], e);
            if (c > 0)
                for (h = g; h < e.length; h++)
                    for (i = 0; i < g; i++)
                        if (e[i] === e[h]) {
                            e.splice(h--, 1);
                            break
                        }
        }
        return e
    },
    has: function(a) {
        var b = f(a);
        return this.filter(function() {
            for (var a = 0, c = b.length; a < c; a++)
                if (f.contains(this, b[a])) return !0
        })
    },
    not: function(a) {
        return this.pushStack(T(this, a, !1), "not", a)
    },
    filter: function(a) {
        return this.pushStack(T(this, a, !0), "filter", a)
    },
    is: function(a) {
        return !!a && (typeof a == "string" ? Q.test(a) ? f(a, this.context).index(this[0]) >= 0 : f.filter(a, this).length > 0 : this.filter(a).length > 0)
    },
    closest: function(a, b) {
        var c = [],
            d, e, g = this[0];
        if (f.isArray(a)) {
            var h = 1;
            while (g && g.ownerDocument && g !== b) {
                for (d = 0; d < a.length; d++) f(g).is(a[d]) && c.push({
                    selector: a[d],
                    elem: g,
                    level: h
                });
                g = g.parentNode, h++
            }
            return c
        }
        var i = Q.test(a) || typeof a != "string" ? f(a, b || this.context) : 0;
        for (d = 0, e = this.length; d < e; d++) {
            g = this[d];
            while (g) {
                if (i ? i.index(g) > -1 : f.find.matchesSelector(g, a)) {
                    c.push(g);
                    break
                }
                g = g.parentNode;
                if (!g || !g.ownerDocument || g === b || g.nodeType === 11) break
            }
        }
        c = c.length > 1 ? f.unique(c) : c;
        return this.pushStack(c, "closest", a)
    },
    index: function(a) {
        if (!a) return this[0] && this[0].parentNode ? this.prevAll().length : -1;
        if (typeof a == "string") return f.inArray(this[0], f(a));
        return f.inArray(a.jquery ? a[0] : a, this)
    },
    add: function(a, b) {
        var c = typeof a == "string" ? f(a, b) : f.makeArray(a && a.nodeType ? [a] : a),
            d = f.merge(this.get(), c);
        return this.pushStack(S(c[0]) || S(d[0]) ? d : f.unique(d))
    },
    andSelf: function() {
        return this.add(this.prevObject)
    }
}), f.each({
    parent: function(a) {
        var b = a.parentNode;
        return b && b.nodeType !== 11 ? b : null
    },
    parents: function(a) {
        return f.dir(a, "parentNode")
    },
    parentsUntil: function(a, b, c) {
        return f.dir(a, "parentNode", c)
    },
    next: function(a) {
        return f.nth(a, 2, "nextSibling")
    },
    prev: function(a) {
        return f.nth(a, 2, "previousSibling")
    },
    nextAll: function(a) {
        return f.dir(a, "nextSibling")
    },
    prevAll: function(a) {
        return f.dir(a, "previousSibling")
    },
    nextUntil: function(a, b, c) {
        return f.dir(a, "nextSibling", c)
    },
    prevUntil: function(a, b, c) {
        return f.dir(a, "previousSibling", c)
    },
    siblings: function(a) {
        return f.sibling(a.parentNode.firstChild, a)
    },
    children: function(a) {
        return f.sibling(a.firstChild)
    },
    contents: function(a) {
        return f.nodeName(a, "iframe") ? a.contentDocument || a.contentWindow.document : f.makeArray(a.childNodes)
    }
}, function(a, b) {
    f.fn[a] = function(c, d) {
        var e = f.map(this, b, c);
        L.test(a) || (d = c), d && typeof d == "string" && (e = f.filter(d, e)), e = this.length > 1 && !R[a] ? f.unique(e) : e, (this.length > 1 || N.test(d)) && M.test(a) && (e = e.reverse());
        return this.pushStack(e, a, P.call(arguments).join(","))
    }
}), f.extend({
    filter: function(a, b, c) {
        c && (a = ":not(" + a + ")");
        return b.length === 1 ? f.find.matchesSelector(b[0], a) ? [b[0]] : [] : f.find.matches(a, b)
    },
    dir: function(a, c, d) {
        var e = [],
            g = a[c];
        while (g && g.nodeType !== 9 && (d === b || g.nodeType !== 1 || !f(g).is(d))) g.nodeType === 1 && e.push(g), g = g[c];
        return e
    },
    nth: function(a, b, c, d) {
        b = b || 1;
        var e = 0;
        for (; a; a = a[c])
            if (a.nodeType === 1 && ++e === b) break;
        return a
    },
    sibling: function(a, b) {
        var c = [];
        for (; a; a = a.nextSibling) a.nodeType === 1 && a !== b && c.push(a);
        return c
    }
});
var V = "abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
    W = / jQuery\d+="(?:\d+|null)"/g,
    X = /^\s+/,
    Y = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
    Z = /<([\w:]+)/,
    $ = /<tbody/i,
    _ = /<|&#?\w+;/,
    ba = /<(?:script|style)/i,
    bb = /<(?:script|object|embed|option|style)/i,
    bc = new RegExp("<(?:" + V + ")", "i"),
    bd = /checked\s*(?:[^=]|=\s*.checked.)/i,
    be = /\/(java|ecma)script/i,
    bf = /^\s*<!(?:\[CDATA\[|\-\-)/,
    bg = {
        option: [1, "<select multiple='multiple'>", "</select>"],
        legend: [1, "<fieldset>", "</fieldset>"],
        thead: [1, "<table>", "</table>"],
        tr: [2, "<table><tbody>", "</tbody></table>"],
        td: [3, "<table><tbody><tr>", "</tr></tbody></table>"],
        col: [2, "<table><tbody></tbody><colgroup>", "</colgroup></table>"],
        area: [1, "<map>", "</map>"],
        _default: [0, "", ""]
    },
    bh = U(c);
bg.optgroup = bg.option, bg.tbody = bg.tfoot = bg.colgroup = bg.caption = bg.thead, bg.th = bg.td, f.support.htmlSerialize || (bg._default = [1, "div<div>", "</div>"]), f.fn.extend({
            text: function(a) {
                if (f.isFunction(a)) return this.each(function(b) {
                    var c = f(this);
                    c.text(a.call(this, b, c.text()))
                });
                if (typeof a != "object" && a !== b) return this.empty().append((this[0] && this[0].ownerDocument || c).createTextNode(a));
                return f.text(this)
            },
            wrapAll: function(a) {
                if (f.isFunction(a)) return this.each(function(b) {
                    f(this).wrapAll(a.call(this, b))
                });
                if (this[0]) {
                    var b = f(a, this[0].ownerDocument).eq(0).clone(!0);
                    this[0].parentNode && b.insertBefore(this[0]), b.map(function() {
                        var a = this;
                        while (a.firstChild && a.firstChild.nodeType === 1) a = a.firstChild;
                        return a
                    }).append(this)
                }
                return this
            },
            wrapInner: function(a) {
                if (f.isFunction(a)) return this.each(function(b) {
                    f(this).wrapInner(a.call(this, b))
                });
                return this.each(function() {
                    var b = f(this),
                        c = b.contents();
                    c.length ? c.wrapAll(a) : b.append(a)
                })
            },
            wrap: function(a) {
                var b = f.isFunction(a);
                return this.each(function(c) {
                    f(this).wrapAll(b ? a.call(this, c) : a)
                })
            },
            unwrap: function() {
                return this.parent().each(function() {
                    f.nodeName(this, "body") || f(this).replaceWith(this.childNodes)
                }).end()
            },
            append: function() {
                return this.domManip(arguments, !0, function(a) {
                    this.nodeType === 1 && this.appendChild(a)
                })
            },
            prepend: function() {
                return this.domManip(arguments, !0, function(a) {
                    this.nodeType === 1 && this.insertBefore(a, this.firstChild)
                })
            },
            before: function() {
                if (this[0] && this[0].parentNode) return this.domManip(arguments, !1, function(a) {
                    this.parentNode.insertBefore(a, this)
                });
                if (arguments.length) {
                    var a = f.clean(arguments);
                    a.push.apply(a, this.toArray());
                    return this.pushStack(a, "before", arguments)
                }
            },
            after: function() {
                if (this[0] && this[0].parentNode) return this.domManip(arguments, !1, function(a) {
                    this.parentNode.insertBefore(a, this.nextSibling)
                });
                if (arguments.length) {
                    var a = this.pushStack(this, "after", arguments);
                    a.push.apply(a, f.clean(arguments));
                    return a
                }
            },
            remove: function(a, b) {
                for (var c = 0, d;
                    (d = this[c]) != null; c++)
                    if (!a || f.filter(a, [d]).length) !b && d.nodeType === 1 && (f.cleanData(d.getElementsByTagName("*")), f.cleanData([d])), d.parentNode && d.parentNode.removeChild(d);
                return this
            },
            empty: function()

Juvia not working properly when deployed to a sub URI

I have installed Juvia on my host, but I did not want to create a VirtualHost for it, so I decided to install it in a sub URI (e.g., http://example.com/juvia).

I could successfully run it after some struggling, but unfortunately it does not work properly, and the apparent reason is because it is on a sub URI. The problem specifically occurs when I try to submit a comment, but it also happens on other occasions. These Apache logs seem to confirm that:

[Thu Oct 18 03:04:45 2012] [error] [client 192.168.1.1] File does not exist: /var/www/html/api, referer: http://xyz.com/juvia.html

(The file juvia.html above is just a test).

As you can see, it is requesting the following URL:

http://example.com/api/FOO

instead of:

http://example.com/juvia/api/FOO

The second one would be the correct URL, since (as I explained) Juvia is running in a sub URI. I tried modifying some Ruby files from the project and recompiling the static assets, without success. It would be really great if I could deploy this application in a sub URI.

Please let me know if you need more information. Thanks.

Remove requirement to have a Google account for the discussion group

This isn't related to the software at all, but I thought I'd bring it up.

Right now, one needs to accept Google's terms of service and create a Google account in order to view the current discussion on Juvia. Is it possible to remove this requirement so that people who don't want to create a Google account can at least read what others are talking about?

importing of comments from Wordpress fails when there is a "Pages menu"

On trying to import I get the following error page:

The change you wanted was rejected.

Maybe you tried to change something you didn't have access to.

The console reports this:

Started POST "/admin/comments/import" for 140.***.***.*** at 2013-03-12 19:47:14 +0000
  Processing by Admin::CommentsController#import as HTML
  Parameters: {"utf8"=>"โœ“", "authenticity_token"=>"54eY6xe8t1gZUhyKCeH9IQ81aPetyjwieLmau2EeYXU=", "site_id"=>"1", "import_type"=>"Word Press", "database_host"=>"localhost", "database_name"=>"wordpress", "database_user"=>"root", "database_password"=>"[FILTERED]", "commit"=>"Import"}
Completed 422 Unprocessable Entity in 119ms

ActiveRecord::RecordInvalid (Validation failed: Title can't be blank):
  app/models/topic.rb:31:in `lookup_or_create'
  lib/juvia/migrators/word_press.rb:140:in `process_post'
  lib/juvia/migrators/word_press.rb:120:in `block in process'
  lib/juvia/migrators/word_press.rb:119:in `process'
  lib/juvia/migrators.rb:13:in `process'
  app/controllers/admin/comments_controller.rb:68:in `import'

cache: [POST /admin/comments/import] invalidate, pass

The first 11 comments are nonetheless successfully imported. I trashed them in wordpress and tried again. The same failure, and no new comments transfered. Then I trashed the rest of the comments one by one in wordpress. The same failure. Even when I have no more comments in wordpress (i.e. all of them are in the trash folder) I get the same error.

I can provide a wordpress xml dump for testing.

Any suggestions?

EDIT: see below for a workaround.

Preconfigured "secret" token

Juvia::Application.config.secret_token is supposed to be a secret token; it has to be generated for each instance configured.

Right now probably most people running juvia will use the "secret" published in this repo.

The secret should be set in a config file; in production/development it should not start without a secret, test should probably have its own default secret.

Problems with rack

If I try to start juvia via thin I get an error related to the version of rack.

>> Writing PID to /var/run/thin/juvia.0.pid
>> Changing process privilege to juvia:juvia
>> Using rack adapter
>> Exiting!
/usr/lib/ruby/gems/1.9.1/gems/bundler-1.1.4/lib/bundler/runtime.rb:31:in `block in setup': You have already activated rack 1.4.1, but your Gemfile requires rack 1.3.6. Using bundle exec may solve this. (Gem::LoadError)
        from /usr/lib/ruby/gems/1.9.1/gems/bundler-1.1.4/lib/bundler/runtime.rb:17:in `setup'
        from /usr/lib/ruby/gems/1.9.1/gems/bundler-1.1.4/lib/bundler.rb:107:in `setup'
        from /usr/lib/ruby/gems/1.9.1/gems/bundler-1.1.4/lib/bundler/setup.rb:17:in `<top (required)>'
        from /usr/local/lib/site_ruby/1.9.1/rubygems/custom_require.rb:60:in `require'
        from /usr/local/lib/site_ruby/1.9.1/rubygems/custom_require.rb:60:in `rescue in require'
        from /usr/local/lib/site_ruby/1.9.1/rubygems/custom_require.rb:35:in `require'
        from /web/comments.how2doit.de/juvia/config/boot.rb:6:in `<top (required)>'
        from /usr/local/lib/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
        from /usr/local/lib/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
        from /web/comments.how2doit.de/juvia/config/application.rb:3:in `<top (required)>'
        from /usr/local/lib/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
        from /usr/local/lib/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
        from /web/comments.how2doit.de/juvia/config/environment.rb:2:in `<top (required)>'
        from /usr/local/lib/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
        from /usr/local/lib/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
        from /web/comments.how2doit.de/juvia/config.ru:3:in `block in <main>'
        from /usr/lib/ruby/gems/1.9.1/gems/rack-1.4.1/lib/rack/builder.rb:51:in `instance_eval'
        from /usr/lib/ruby/gems/1.9.1/gems/rack-1.4.1/lib/rack/builder.rb:51:in `initialize'
        from /web/comments.how2doit.de/juvia/config.ru:1:in `new'
        from /web/comments.how2doit.de/juvia/config.ru:1:in `<main>'
        from /usr/lib/ruby/gems/1.9.1/gems/thin-1.3.1/lib/rack/adapter/loader.rb:36:in `eval'
        from /usr/lib/ruby/gems/1.9.1/gems/thin-1.3.1/lib/rack/adapter/loader.rb:36:in `load'
        from /usr/lib/ruby/gems/1.9.1/gems/thin-1.3.1/lib/rack/adapter/loader.rb:45:in `for'
        from /usr/lib/ruby/gems/1.9.1/gems/thin-1.3.1/lib/thin/controllers/controller.rb:169:in `load_adapter'
        from /usr/lib/ruby/gems/1.9.1/gems/thin-1.3.1/lib/thin/controllers/controller.rb:73:in `start'
        from /usr/lib/ruby/gems/1.9.1/gems/thin-1.3.1/lib/thin/runner.rb:185:in `run_command'
        from /usr/lib/ruby/gems/1.9.1/gems/thin-1.3.1/lib/thin/runner.rb:151:in `run!'
        from /usr/lib/ruby/gems/1.9.1/gems/thin-1.3.1/bin/thin:6:in `<top (required)>'
        from /usr/bin/thin:23:in `load'
        from /usr/bin/thin:23:in `<main>'

I already installed both versions of rack

 gem list | grep rack
rack (1.4.1, 1.3.6)
rack-cache (1.2)
rack-openid (1.3.1)
rack-protection (1.2.0)
rack-ssl (1.3.2)
rack-test (0.6.1)

It should be easy to simply use the newest rack - so could you update the Gemfile and the source so that they're able to work with current versions of rack?

Logo shown as broken link

It took me quite a while to figure out why the juvia logo was always shown as a broken link. Manually downloading it always gave a 404 error.

The reason are the two options in config/environments/production.rb
config.serve_static_assets = false
config.action_dispatch.x_sendfile_header = "X-Sendfile" # Use 'X-Accel-Redirect' for nginx

In case there is no surrounding apache or apache is not configured to honor X-Sendfile headers, the static images will never be served.

It would be helpful to have a short blurb documenting this. If you think that this does not fit into the main page, then maybe this ticket might even suffice.

Thanks
Carsten

Strip email in textarea

Hi!

If an email is copied to textarea from another place, it can contain some whitespaces which are invisible but important for the proper identification of Gravatar. So, it's helpful to use strip method before storing the email. May be, the same would be useful for the textarea of user's name.

Maintaining project

Hello!

I would like to make this project alive; though I am not sure that there is enough demand. As it is a self-hosted project, I doubt you have enough statistics about usage, especially for the last year or so. But project by itself seems interesing.

If I would start to maintain this project, I would have such a plan:

  1. Update and complete test suite (before any upgrades of core dependencies)
  2. Update libraries and gems, replace highly outdated dependencies, make project work on modern Ruby branch, lint code (probably have to push to Rails 5 or 6, Rails 4 is pretty outdated at the moment already)
  3. Add dependabot, github actions to CI/CD, mandatody CI for pull requests
  4. Make and publish a rodmap based on issues, TODO and common sense
  5. Work on the roadmap features
  6. Documentation, user guides

Let me know what do you guys think.

Parse error on line 1: Unexpected '=' while installing

I try to install Juvia on a VPS running Ubuntu 13.04-x64. I followed the installation guide in the README, and on step 6, while doing bundle exec rake assets:precompile RAILS_ENV=production RAILS_GROUPS=assets I get this:

Could not load sequel gem, so WordPress import will not work.
rake aborted!
Parse error on line 1: Unexpected '='
  (in /home/unlogic/juvia/app/assets/javascripts/application.js.coffee)
/home/unlogic/juvia/help/ruby/2.0.0/gems/execjs-1.2.13/lib/execjs/ruby_racer_runtime.rb:47:in `rescue in block in call'
/home/unlogic/juvia/help/ruby/2.0.0/gems/execjs-1.2.13/lib/execjs/ruby_racer_runtime.rb:41:in `block in call'
/home/unlogic/juvia/help/ruby/2.0.0/gems/execjs-1.2.13/lib/execjs/ruby_racer_runtime.rb:78:in `block in lock'
/home/unlogic/juvia/help/ruby/2.0.0/gems/execjs-1.2.13/lib/execjs/ruby_racer_runtime.rb:76:in `call'
/home/unlogic/juvia/help/ruby/2.0.0/gems/execjs-1.2.13/lib/execjs/ruby_racer_runtime.rb:76:in `Locker'
/home/unlogic/juvia/help/ruby/2.0.0/gems/execjs-1.2.13/lib/execjs/ruby_racer_runtime.rb:76:in `lock'
/home/unlogic/juvia/help/ruby/2.0.0/gems/execjs-1.2.13/lib/execjs/ruby_racer_runtime.rb:40:in `call'
/home/unlogic/juvia/help/ruby/2.0.0/gems/coffee-script-2.2.0/lib/coffee_script.rb:57:in `compile'
/home/unlogic/juvia/help/ruby/2.0.0/gems/tilt-1.3.5/lib/tilt/coffee.rb:46:in `evaluate'
/home/unlogic/juvia/help/ruby/2.0.0/gems/tilt-1.3.5/lib/tilt/template.rb:77:in `render'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/context.rb:175:in `block in evaluate'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/context.rb:172:in `each'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/context.rb:172:in `evaluate'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/bundled_asset.rb:171:in `build_dependency_context_and_body'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/bundled_asset.rb:135:in `dependency_context'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/bundled_asset.rb:194:in `build_dependencies_paths_and_assets'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/bundled_asset.rb:141:in `dependency_paths'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/bundled_asset.rb:61:in `mtime'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/asset.rb:58:in `block in encode_with'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/asset.rb:57:in `each'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/asset.rb:57:in `encode_with'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/bundled_asset.rb:43:in `encode_with'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/caching.rb:52:in `cache_asset'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/index.rb:67:in `block in build_asset'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/index.rb:76:in `memoize'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/index.rb:65:in `build_asset'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/trail.rb:102:in `find_asset_in_path'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/base.rb:101:in `find_asset'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/index.rb:48:in `find_asset'
/home/unlogic/juvia/help/ruby/2.0.0/gems/actionpack-3.1.10/lib/sprockets/static_compiler.rb:23:in `block in compile'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/base.rb:151:in `block in each_logical_path'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/base.rb:139:in `block (2 levels) in each_file'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/base.rb:129:in `each'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/base.rb:129:in `each_entry'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/base.rb:137:in `block in each_file'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/base.rb:136:in `each'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/base.rb:136:in `each_file'
/home/unlogic/juvia/help/ruby/2.0.0/gems/sprockets-2.0.4/lib/sprockets/base.rb:149:in `each_logical_path'
/home/unlogic/juvia/help/ruby/2.0.0/gems/actionpack-3.1.10/lib/sprockets/static_compiler.rb:18:in `compile'
/home/unlogic/juvia/help/ruby/2.0.0/gems/actionpack-3.1.10/lib/sprockets/assets.rake:52:in `internal_precompile'
/home/unlogic/juvia/help/ruby/2.0.0/gems/actionpack-3.1.10/lib/sprockets/assets.rake:66:in `block (3 levels) in <top (required)>'
/home/unlogic/juvia/help/ruby/2.0.0/gems/actionpack-3.1.10/lib/sprockets/assets.rake:56:in `block (3 levels) in <top (required)>'
/home/unlogic/juvia/help/ruby/2.0.0/gems/actionpack-3.1.10/lib/sprockets/assets.rake:19:in `invoke_or_reboot_rake_task'
/home/unlogic/juvia/help/ruby/2.0.0/gems/actionpack-3.1.10/lib/sprockets/assets.rake:25:in `block (2 levels) in <top (required)>'
Tasks: TOP => assets:precompile:primary
(See full trace by running task with --trace)

All previous steps seemed to complete successfully. Any ideas?

Problem with the instalation

Hi, I'm deploying the system in a server apache mysql.

I don't have any knowledge about ruby on rails but i create a new project of ruby on rails in the server and it's works. The problem becomes when I clone this project and i follow the web instructions, something is wrong.

I only see that when i write the command:

bundle exec rake assets:precompile RAILS_ENV=production RAILS_GROUPS=assets

show this message:

/usr/bin/ruby1.8 /home/sergio/juvia/help/ruby/1.8/bin/rake assets:precompile:nondigest RAILS_ENV=production RAILS_GROUPS=assets

After, i restart apache2 and when go to the page, shows:

Index of /

Name    Last modified   Size    Description
404.html    04-May-2013 18:01   728  
422.html    04-May-2013 18:01   711  
500.html    04-May-2013 18:01   728  
assets/ 04-May-2013 20:21    -   
favicon.ico 04-May-2013 18:01   5.3K     
robots.txt  04-May-2013 18:01   204  
test.html   04-May-2013 18:01   1.5K     

Apache/2.2.22 (Ubuntu) Server at 192.168.1.135 Port 80

NOTE: the tables in the db is correctly created

I'm looking for some information in Internet, but I don't found any

Any suggestions?

A lot of thanks

Support for Ghost Blogging

Is it possible to use Juvia with Ghost Blog and if so how to achieve that?
Can I get some documentation on that or any direction?

Thanks!

Comment.accessible_by broken

(This might be a CanCan bug)

Comment.accessible_by(current_ability) didn't work (test with non-admin user!) -
current_user.accessible_comments works (and should provide the same data if i understand it correctly)

diff --git a/app/controllers/admin/comments_controller.rb b/app/controllers/admin/comments_controller.rb
index f17af66..8b661ea 100644
--- a/app/controllers/admin/comments_controller.rb
+++ b/app/controllers/admin/comments_controller.rb
@@ -7,8 +7,8 @@ class Admin::CommentsController < ApplicationController

   def index
     authorize! :read, Comment
-    @all_comments = Comment.
-      accessible_by(current_ability).
+    @all_comments = current_user.
+      accessible_comments.
       order('created_at DESC').
       includes(:topic)
     @comments = @all_comments.page(params[:page])
diff --git a/app/views/layouts/_admin_sections_bar.html.erb b/app/views/layouts/_admin_sections_bar.html.erb
index be9bca7..e1a4d5b 100644
--- a/app/views/layouts/_admin_sections_bar.html.erb
+++ b/app/views/layouts/_admin_sections_bar.html.erb
@@ -8,7 +8,7 @@
       <% end %>
       <% if can?(:read, Comment) %>
         <div class="section <%= maybe_active(:comments) %>">
-          <% counter = Comment.accessible_by(current_ability).requiring_moderation.count %>
+          <% counter = current_user.accessible_comments.requiring_moderation.count %>
           <% if counter == 0 %>
             <%= link_to "Comments", admin_comments_path %>
           <% else %>

Juvia JS to return HTML without CSS?

When the JS pulls a Juvia topic into a page, it sets the CSS based on the stylesheets within the Juvia source code. Is it currently possible to get Juvia to return only the comment HTML, and not pull in CSS as well?

How to change 'Moderation method'?

Hi, I just set up my juvia installation and created a site. So far so good, but how can I change the Moderation method in the settings after I created the site? I can't find any settings or so.
Thanks :)

Custom class for juvia container loading and loaded

This is along the same lines as #22, but toward a different purpose. Let's say I have a div where juvia loads the comments, which I specify in the juvia options.container property:

<div id="juvia-comments"></div>

It'd be nice if juvia added a juvia-loading class to that container when the ajax request starts and then change it to a juvia-loaded class when the comments have loaded. Separate from firing a javascript event as in #22, this would allow me to do something like this.

<div id="juvia-comments">
  <span id="juvia-loading-msg">Comments are loading...</span>
  <span id="juvia-javascript-msg">JavaScript must be enabled for comments.</span>
</div>

Then in my CSS:

#juvia-loading-msg {
  display: none;
}

.juvia-loading #juvia-loading-msg {
  display: block;
}
.juvia-loading #juvia-javascript-msg {
  display: none;
}

.juvia-loaded #juvia-loading-msg,
.juvia-loaded #juvia-javascript-msg {
  display: none;
}

And of course, I could apply other styles too like making the juvia comment section appear differently before and after comments load. And no javascript needed.

Blacklisting

Or some way to remove inappropriate content from comments. If a word in a comment appears in this list, it'll be replaced with "[removed]" or something similar. Maybe the replacement text can be custom as well?

cms plugin?

Is there (or they get you) extensions "wordpress" and co

Generate Atom/RSS feeds

It would be awesome if Juvia was able to generate a feed for each topic, so users could easily follow a discussion without constantly checking the site for updates.

MySQL error with MariaDB 5.5 during WordPress import

There is a related issue in the mysqlplus gem that makes it impossible to import comments from WordPress with Juvia.

oldmoe/mysqlplus#8

Here's the typical error:

App 21632 stderr: Passenger RackApp: /foo/bar/comments.psy-q.ch/juvia: relocation error:  /foo/bar/help/ruby/2.1.0/gems/mysqlplus-0.1.2/lib/mysql.so: symbol vio_blocking, version libmysqlclient_18 not defined in file libmysqlclient.so.18 with link time reference

Could the import be rewritten to use plain mysql2?

Akismet spam checking not working

Tried to add comments that should have been flagged as spam, but didn't get flagged. Akismet integration not working? If so, how to debug?

Interested in Maintaining this project

If this project is still looking for a maintainer, I would be very interested in taking over. I have used Juvia in some rails projects in the past so I have a vested interest in maintaining it.

static assets don't compile

error while trying to compile static assets (ruby 1.9.1):

bundle exec rake --trace assets:precompile RAILS_ENV=production RAILS_GROUPS=assets
Could not load sequel gem, so WordPress import will not work.
** Invoke assets:precompile (first_time)
** Execute assets:precompile
** Invoke assets:precompile:all (first_time)
** Execute assets:precompile:all
** Invoke assets:precompile:primary (first_time)
** Invoke assets:environment (first_time)
** Execute assets:environment
** Invoke environment (first_time)
** Execute environment
** Invoke tmp:cache:clear (first_time)
** Execute tmp:cache:clear
** Execute assets:precompile:primary
rake aborted!

  (in /home/jarrett/projects/juvia/app/assets/javascripts/application.js.coffee)
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/execjs-1.2.13/lib/execjs/external_runtime.rb:150:in `exec_runtime'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/execjs-1.2.13/lib/execjs/external_runtime.rb:27:in `block in exec'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/execjs-1.2.13/lib/execjs/external_runtime.rb:40:in `compile_to_tempfile'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/execjs-1.2.13/lib/execjs/external_runtime.rb:26:in `exec'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/execjs-1.2.13/lib/execjs/external_runtime.rb:18:in `eval'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/execjs-1.2.13/lib/execjs/external_runtime.rb:32:in `call'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/coffee-script-2.2.0/lib/coffee_script.rb:57:in `compile'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/tilt-1.3.5/lib/tilt/coffee.rb:46:in `evaluate'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/tilt-1.3.5/lib/tilt/template.rb:77:in `render'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/context.rb:175:in `block in evaluate'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/context.rb:172:in `each'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/context.rb:172:in `evaluate'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/bundled_asset.rb:171:in `build_dependency_context_and_body'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/bundled_asset.rb:135:in `dependency_context'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/bundled_asset.rb:194:in `build_dependencies_paths_and_assets'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/bundled_asset.rb:141:in `dependency_paths'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/bundled_asset.rb:61:in `mtime'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/asset.rb:58:in `block in encode_with'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/asset.rb:57:in `each'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/asset.rb:57:in `encode_with'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/bundled_asset.rb:43:in `encode_with'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/caching.rb:52:in `cache_asset'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/index.rb:67:in `block in build_asset'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/index.rb:76:in `memoize'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/index.rb:65:in `build_asset'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/trail.rb:102:in `find_asset_in_path'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/base.rb:101:in `find_asset'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/index.rb:48:in `find_asset'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/actionpack-3.1.10/lib/sprockets/static_compiler.rb:23:in `block in compile'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/base.rb:151:in `block in each_logical_path'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/base.rb:139:in `block (2 levels) in each_file'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/base.rb:129:in `each'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/base.rb:129:in `each_entry'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/base.rb:137:in `block in each_file'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/base.rb:136:in `each'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/base.rb:136:in `each_file'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/sprockets-2.0.4/lib/sprockets/base.rb:149:in `each_logical_path'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/actionpack-3.1.10/lib/sprockets/static_compiler.rb:18:in `compile'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/actionpack-3.1.10/lib/sprockets/assets.rake:52:in `internal_precompile'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/actionpack-3.1.10/lib/sprockets/assets.rake:66:in `block (3 levels) in <top (required)>'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:228:in `call'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:228:in `block in execute'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:223:in `each'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:223:in `execute'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:166:in `block in invoke_with_call_chain'
/usr/lib/ruby/1.9.1/monitor.rb:211:in `mon_synchronize'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:159:in `invoke_with_call_chain'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:152:in `invoke'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/actionpack-3.1.10/lib/sprockets/assets.rake:56:in `block (3 levels) in <top (required)>'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:228:in `call'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:228:in `block in execute'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:223:in `each'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:223:in `execute'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:166:in `block in invoke_with_call_chain'
/usr/lib/ruby/1.9.1/monitor.rb:211:in `mon_synchronize'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:159:in `invoke_with_call_chain'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:152:in `invoke'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/actionpack-3.1.10/lib/sprockets/assets.rake:19:in `invoke_or_reboot_rake_task'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/actionpack-3.1.10/lib/sprockets/assets.rake:25:in `block (2 levels) in <top (required)>'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:228:in `call'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:228:in `block in execute'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:223:in `each'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:223:in `execute'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:166:in `block in invoke_with_call_chain'
/usr/lib/ruby/1.9.1/monitor.rb:211:in `mon_synchronize'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:159:in `invoke_with_call_chain'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/task.rb:152:in `invoke'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:143:in `invoke_task'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:101:in `block (2 levels) in top_level'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:101:in `each'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:101:in `block in top_level'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:110:in `run_with_threads'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:95:in `top_level'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:73:in `block in run'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:160:in `standard_exception_handling'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/lib/rake/application.rb:70:in `run'
/home/jarrett/projects/juvia/help/ruby/1.9.1/gems/rake-10.0.3/bin/rake:33:in `<top (required)>'
/home/jarrett/projects/juvia/help/ruby/1.9.1/bin/rake:23:in `load'
/home/jarrett/projects/juvia/help/ruby/1.9.1/bin/rake:23:in `<main>'
Tasks: TOP => assets:precompile:primary

Zlib::DataError: incorrect header check

I am facing Zlib::DataError: incorrect header check error for few strings. I got stuck into this issue, so please fix this asap.

I am getting exception only for few compressed string, please find example string in console:

ruby-1.9.3-p125> str = "eMKcK0ktLgEABF0Bw4E="
=> "eMKcK0ktLgEABF0Bw4E="
ruby-1.9.3-p125> Zlib::Inflate.inflate(str.unpack('m').first)
Zlib::DataError: incorrect header check
from (irb):3:in `inflate'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.