From 93ac160201e82335b5637bf2508b5e5b2e2eb5f0 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Sun, 22 Jan 2017 10:16:57 +0800 Subject: [PATCH] Use C extension to remove ImageMagick dependency (#40) --- .gitignore | 4 + .travis.yml | 7 +- CHANGELOG.md | 12 + Gemfile.lock | 7 +- README.md | 45 +-- Rakefile | 13 + .../ru_captcha/captcha_controller.rb | 6 +- ext/rucaptcha/colors.h | 345 ++++++++++++++++++ ext/rucaptcha/extconf.rb | 2 + ext/rucaptcha/font.h | 27 ++ ext/rucaptcha/rucaptcha.c | 214 +++++++++++ lib/rucaptcha.rb | 13 +- lib/rucaptcha/cache.rb | 42 --- lib/rucaptcha/captcha.rb | 125 ------- lib/rucaptcha/configuration.rb | 13 +- lib/rucaptcha/controller_helpers.rb | 6 +- lib/rucaptcha/engine.rb | 5 - lib/rucaptcha/version.rb | 2 +- lib/rucaptcha/view_helpers.rb | 4 +- rucaptcha.gemspec | 8 +- spec/cache_spec.rb | 26 -- spec/captcha_spec.rb | 76 +--- spec/configure_spec.rb | 3 - spec/controller_helpers_spec.rb | 6 +- spec/spec_helper.rb | 3 - test | 2 + 26 files changed, 682 insertions(+), 334 deletions(-) create mode 100644 ext/rucaptcha/colors.h create mode 100644 ext/rucaptcha/extconf.rb create mode 100644 ext/rucaptcha/font.h create mode 100644 ext/rucaptcha/rucaptcha.c delete mode 100644 lib/rucaptcha/captcha.rb delete mode 100644 spec/cache_spec.rb create mode 100755 test diff --git a/.gitignore b/.gitignore index d20dc54..652257d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,10 @@ /test/version_tmp/ /tmp/ .DS_Store +*.bundle +*.o +ext/rucaptcha/Makefile +ext/rucaptcha/*.gif ## RubyMine Ide files .idea/ diff --git a/.travis.yml b/.travis.yml index bbdbe04..f3fd9b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,5 @@ rvm: - 2.2.3 services: - memcached -addons: - apt: - packages: - - imagemagick - - tesseract-ocr +script: + - bundle exec rake compile && bundle exec rake diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f24c48..3fe0346 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +2.0.0 +----- + +*Break Changes!* + +WARNING!: This version have so many break changes! + +- Use C ext instead of ImageMagick, now it's no dependencies! +- New captcha style. +- Remove `len`, `font_size`, `cache_limit` config key, no support now. +- Output `GIF` format. + 1.2.0 ----- diff --git a/Gemfile.lock b/Gemfile.lock index cd11400..80834f9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - rucaptcha (1.2.0) + rucaptcha (2.0.0) railties (>= 3.2) GEM @@ -96,6 +96,8 @@ GEM rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rake (11.3.0) + rake-compiler (1.0.3) + rake rspec (3.3.0) rspec-core (~> 3.3.0) rspec-expectations (~> 3.3.0) @@ -135,8 +137,9 @@ DEPENDENCIES dalli rails rake + rake-compiler (~> 1) rspec rucaptcha! BUNDLED WITH - 1.13.6 + 1.13.7 diff --git a/README.md b/README.md index 4dae17e..4446682 100644 --- a/README.md +++ b/README.md @@ -4,44 +4,20 @@ [![Build Status](https://travis-ci.org/huacnlee/rucaptcha.svg)](https://travis-ci.org/huacnlee/rucaptcha) [![Code Climate](https://codeclimate.com/github/huacnlee/rucaptcha/badges/gpa.svg)](https://codeclimate.com/github/huacnlee/rucaptcha) -This is a Captcha gem for Rails Applications. It runs an ImageMagick command to draw Captcha image - so it has NO performance issues or memory leak issues. **There is NO: RMagick** +This is a Captcha gem for Rails Applications. It drawing captcha image with C code. ## Example -![1](https://cloud.githubusercontent.com/assets/5518/15423974/b186b0d6-1eb2-11e6-9c0e-4cc3a66f32c8.png) -![2](https://cloud.githubusercontent.com/assets/5518/15423975/b1887b6e-1eb2-11e6-895f-5629f82697d3.png) -![3](https://cloud.githubusercontent.com/assets/5518/15423978/b18f08ee-1eb2-11e6-9670-c21dba290e04.png) -![4](https://cloud.githubusercontent.com/assets/5518/15423976/b18b6946-1eb2-11e6-8413-700ded157262.png) -![5](https://cloud.githubusercontent.com/assets/5518/15423977/b18e7c62-1eb2-11e6-96f7-5bd6981d4185.png) -![6](https://cloud.githubusercontent.com/assets/5518/15423979/b19175d4-1eb2-11e6-9417-7d496fb996b4.png) -![7](https://cloud.githubusercontent.com/assets/5518/15423980/b1caf944-1eb2-11e6-862e-78c0a9360b43.png) - -Idea by: https://ruby-china.org/topics/20558#reply4 + [中文介绍和使用说明](https://ruby-china.org/topics/27832) ## Feature -- Only need `ImageMagick`, No `RMagick`, No `mini_magick`; +- No dependencies. No ImageMagick, No RMagick. - For Rails Application; - Simple, Easy to use; -- File Caching for performance. - -## Requirements - -- ImageMagick 6.9+ - -#### Ubuntu - -``` -sudo apt-get install imagemagick ghostscript -``` - -#### Mac OS X - -```bash -brew install imagemagick ghostscript -``` +- High performance. ## Usage @@ -55,17 +31,10 @@ Create `config/initializers/rucaptcha.rb` ```rb RuCaptcha.configure do - # Number of chars, default: 4 - self.len = 4 - # Image font size, default: 45 - self.font_size = 45 - # Cache generated images in file store, this is config files limit, default: 100 - # set 0 to disable file cache. - self.cache_limit = 100 - # Custom captcha code expire time if you need, default: 2 minutes - # self.expires_in = 120 # Color style, default: :colorful, allows: [:colorful, :black_white] # self.style = :colorful + # Custom captcha code expire time if you need, default: 2 minutes + # self.expires_in = 120 # [Requirement] # Store Captcha code where, this config more like Rails config.cache_store # default: Rails application config.cache_store @@ -99,7 +68,7 @@ class AccountController < ApplicationController end ``` -> TIP: Sometime you may need keep last verified captcha code in session on `verify_rucaptcha?` method call, you can use `keep_session: true`. For example: ` Verify_rucaptcha? (@user, keep_session: true) `. +> TIP: Sometime you may need keep last verified captcha code in session on `verify_rucaptcha?` method call, you can use `keep_session: true`. For example: `verify_rucaptcha? @user, keep_session: true`. View `app/views/account/new.html.erb` diff --git a/Rakefile b/Rakefile index 378dab3..3c74416 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,18 @@ require "bundler/gem_tasks" require "rspec/core/rake_task" +require 'rake/extensiontask' + +Rake::ExtensionTask.new "rucaptcha" do |ext| + ext.lib_dir = "lib/rucaptcha" +end RSpec::Core::RakeTask.new(:spec) task default: :spec + + +task :preview do + require 'rucaptcha' + + res = RuCaptcha.create(1) + puts res[1] +end \ No newline at end of file diff --git a/app/controllers/ru_captcha/captcha_controller.rb b/app/controllers/ru_captcha/captcha_controller.rb index c85afbf..a77ecea 100644 --- a/app/controllers/ru_captcha/captcha_controller.rb +++ b/app/controllers/ru_captcha/captcha_controller.rb @@ -3,11 +3,13 @@ module RuCaptcha def index headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate' headers['Pragma'] = 'no-cache' + data = generate_rucaptcha + opts = { disposition: 'inline', type: 'image/gif' } if Gem.win_platform? - send_file generate_rucaptcha, disposition: 'inline', type: 'image/png' + send_file data, opts else - send_data generate_rucaptcha, disposition: 'inline', type: 'image/png' + send_data data, opts end end end diff --git a/ext/rucaptcha/colors.h b/ext/rucaptcha/colors.h new file mode 100644 index 0000000..876ac31 --- /dev/null +++ b/ext/rucaptcha/colors.h @@ -0,0 +1,345 @@ +// Colors from +// https://material.io/guidelines/style/color.html#color-ui-color-palette +static char *colors[] = { + // Black 500 #000000 + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\x11\x11\x11" + "\x11\x11\x11" + "\x11\x11\x11" + "\x11\x11\x11" + "\x11\x11\x11" + "\x11\x11\x11" + "\x11\x11\x11" + "\x11\x11\x11" + "\x11\x11\x11" + "\x11\x11\x11" + "\x11\x11\x11" + "\x11\x11\x11" + "\x11\x11\x11" + "\x11\x11\x11" + "\x11\x11\x11" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04", + + // Red 500 #F44336 + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\xF4\x43\x36" + "\xF4\x43\x36" + "\xF4\x43\x36" + "\xF4\x43\x36" + "\xF4\x43\x36" + "\xF4\x43\x36" + "\xF4\x43\x36" + "\xF4\x43\x36" + "\xF4\x43\x36" + "\xF4\x43\x36" + "\xF4\x43\x36" + "\xF4\x43\x36" + "\xF4\x43\x36" + "\xF4\x43\x36" + "\xF4\x43\x36" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04", + + // Pink 500 #E91E63 + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\xE9\x1E\x63" + "\xE9\x1E\x63" + "\xE9\x1E\x63" + "\xE9\x1E\x63" + "\xE9\x1E\x63" + "\xE9\x1E\x63" + "\xE9\x1E\x63" + "\xE9\x1E\x63" + "\xE9\x1E\x63" + "\xE9\x1E\x63" + "\xE9\x1E\x63" + "\xE9\x1E\x63" + "\xE9\x1E\x63" + "\xE9\x1E\x63" + "\xE9\x1E\x63" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04", + + // Purple 500 #9C27B0 + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\x9C\x27\xB0" + "\x9C\x27\xB0" + "\x9C\x27\xB0" + "\x9C\x27\xB0" + "\x9C\x27\xB0" + "\x9C\x27\xB0" + "\x9C\x27\xB0" + "\x9C\x27\xB0" + "\x9C\x27\xB0" + "\x9C\x27\xB0" + "\x9C\x27\xB0" + "\x9C\x27\xB0" + "\x9C\x27\xB0" + "\x9C\x27\xB0" + "\x9C\x27\xB0" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04", + + // Deep Purple 500 #673AB7 + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\x67\x3A\xB7" + "\x67\x3A\xB7" + "\x67\x3A\xB7" + "\x67\x3A\xB7" + "\x67\x3A\xB7" + "\x67\x3A\xB7" + "\x67\x3A\xB7" + "\x67\x3A\xB7" + "\x67\x3A\xB7" + "\x67\x3A\xB7" + "\x67\x3A\xB7" + "\x67\x3A\xB7" + "\x67\x3A\xB7" + "\x67\x3A\xB7" + "\x67\x3A\xB7" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04", + + // Indigo 500 #3F51B5 + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\x3F\x51\xB5" + "\x3F\x51\xB5" + "\x3F\x51\xB5" + "\x3F\x51\xB5" + "\x3F\x51\xB5" + "\x3F\x51\xB5" + "\x3F\x51\xB5" + "\x3F\x51\xB5" + "\x3F\x51\xB5" + "\x3F\x51\xB5" + "\x3F\x51\xB5" + "\x3F\x51\xB5" + "\x3F\x51\xB5" + "\x3F\x51\xB5" + "\x3F\x51\xB5" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04", + + // Blue 500 #2196F3 + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\x21\x96\xF3" + "\x21\x96\xF3" + "\x21\x96\xF3" + "\x21\x96\xF3" + "\x21\x96\xF3" + "\x21\x96\xF3" + "\x21\x96\xF3" + "\x21\x96\xF3" + "\x21\x96\xF3" + "\x21\x96\xF3" + "\x21\x96\xF3" + "\x21\x96\xF3" + "\x21\x96\xF3" + "\x21\x96\xF3" + "\x21\x96\xF3" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04", + + // Light Blue 500 #03A9F4 + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\x03\xA9\xF4" + "\x03\xA9\xF4" + "\x03\xA9\xF4" + "\x03\xA9\xF4" + "\x03\xA9\xF4" + "\x03\xA9\xF4" + "\x03\xA9\xF4" + "\x03\xA9\xF4" + "\x03\xA9\xF4" + "\x03\xA9\xF4" + "\x03\xA9\xF4" + "\x03\xA9\xF4" + "\x03\xA9\xF4" + "\x03\xA9\xF4" + "\x03\xA9\xF4" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04", + + // Cyan 500 #00BCD4 + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\x00\xBC\xD4" + "\x00\xBC\xD4" + "\x00\xBC\xD4" + "\x00\xBC\xD4" + "\x00\xBC\xD4" + "\x00\xBC\xD4" + "\x00\xBC\xD4" + "\x00\xBC\xD4" + "\x00\xBC\xD4" + "\x00\xBC\xD4" + "\x00\xBC\xD4" + "\x00\xBC\xD4" + "\x00\xBC\xD4" + "\x00\xBC\xD4" + "\x00\xBC\xD4" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04", + + // Teal 500 #009688 + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\x00\x96\x88" + "\x00\x96\x88" + "\x00\x96\x88" + "\x00\x96\x88" + "\x00\x96\x88" + "\x00\x96\x88" + "\x00\x96\x88" + "\x00\x96\x88" + "\x00\x96\x88" + "\x00\x96\x88" + "\x00\x96\x88" + "\x00\x96\x88" + "\x00\x96\x88" + "\x00\x96\x88" + "\x00\x96\x88" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04", + + // Green 500 #4CAF50 + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\x4C\xAF\x50" + "\x4C\xAF\x50" + "\x4C\xAF\x50" + "\x4C\xAF\x50" + "\x4C\xAF\x50" + "\x4C\xAF\x50" + "\x4C\xAF\x50" + "\x4C\xAF\x50" + "\x4C\xAF\x50" + "\x4C\xAF\x50" + "\x4C\xAF\x50" + "\x4C\xAF\x50" + "\x4C\xAF\x50" + "\x4C\xAF\x50" + "\x4C\xAF\x50" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04", + + // Light Green 500 #8BC34A + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\x8B\xC3\x4A" + "\x8B\xC3\x4A" + "\x8B\xC3\x4A" + "\x8B\xC3\x4A" + "\x8B\xC3\x4A" + "\x8B\xC3\x4A" + "\x8B\xC3\x4A" + "\x8B\xC3\x4A" + "\x8B\xC3\x4A" + "\x8B\xC3\x4A" + "\x8B\xC3\x4A" + "\x8B\xC3\x4A" + "\x8B\xC3\x4A" + "\x8B\xC3\x4A" + "\x8B\xC3\x4A" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04", + + // Lime 500 #CDDC39 + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\xCD\xDC\x39" + "\xCD\xDC\x39" + "\xCD\xDC\x39" + "\xCD\xDC\x39" + "\xCD\xDC\x39" + "\xCD\xDC\x39" + "\xCD\xDC\x39" + "\xCD\xDC\x39" + "\xCD\xDC\x39" + "\xCD\xDC\x39" + "\xCD\xDC\x39" + "\xCD\xDC\x39" + "\xCD\xDC\x39" + "\xCD\xDC\x39" + "\xCD\xDC\x39" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04", + + // Yellow 500 #FFEB3B + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\xFF\xEB\x3B" + "\xFF\xEB\x3B" + "\xFF\xEB\x3B" + "\xFF\xEB\x3B" + "\xFF\xEB\x3B" + "\xFF\xEB\x3B" + "\xFF\xEB\x3B" + "\xFF\xEB\x3B" + "\xFF\xEB\x3B" + "\xFF\xEB\x3B" + "\xFF\xEB\x3B" + "\xFF\xEB\x3B" + "\xFF\xEB\x3B" + "\xFF\xEB\x3B" + "\xFF\xEB\x3B" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04", + + // Amber 500 #FFC107 + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\xFF\xC1\x07" + "\xFF\xC1\x07" + "\xFF\xC1\x07" + "\xFF\xC1\x07" + "\xFF\xC1\x07" + "\xFF\xC1\x07" + "\xFF\xC1\x07" + "\xFF\xC1\x07" + "\xFF\xC1\x07" + "\xFF\xC1\x07" + "\xFF\xC1\x07" + "\xFF\xC1\x07" + "\xFF\xC1\x07" + "\xFF\xC1\x07" + "\xFF\xC1\x07" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04", + + // Orange 500 #FF9800 + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\xFF\x98\x00" + "\xFF\x98\x00" + "\xFF\x98\x00" + "\xFF\x98\x00" + "\xFF\x98\x00" + "\xFF\x98\x00" + "\xFF\x98\x00" + "\xFF\x98\x00" + "\xFF\x98\x00" + "\xFF\x98\x00" + "\xFF\x98\x00" + "\xFF\x98\x00" + "\xFF\x98\x00" + "\xFF\x98\x00" + "\xFF\x98\x00" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04", + + // Deep Orange 500 #FF5722 + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\xFF\x57\x22" + "\xFF\x57\x22" + "\xFF\x57\x22" + "\xFF\x57\x22" + "\xFF\x57\x22" + "\xFF\x57\x22" + "\xFF\x57\x22" + "\xFF\x57\x22" + "\xFF\x57\x22" + "\xFF\x57\x22" + "\xFF\x57\x22" + "\xFF\x57\x22" + "\xFF\x57\x22" + "\xFF\x57\x22" + "\xFF\x57\x22" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04", + + // Brown 500 #795548 + "GIF89a" "\xc8\0\x46\0" "\x83" "\0\0" + "\x79\x55\x48" + "\x79\x55\x48" + "\x79\x55\x48" + "\x79\x55\x48" + "\x79\x55\x48" + "\x79\x55\x48" + "\x79\x55\x48" + "\x79\x55\x48" + "\x79\x55\x48" + "\x79\x55\x48" + "\x79\x55\x48" + "\x79\x55\x48" + "\x79\x55\x48" + "\x79\x55\x48" + "\x79\x55\x48" + "\xff\xff\xff" "," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04" +}; \ No newline at end of file diff --git a/ext/rucaptcha/extconf.rb b/ext/rucaptcha/extconf.rb new file mode 100644 index 0000000..dfa482c --- /dev/null +++ b/ext/rucaptcha/extconf.rb @@ -0,0 +1,2 @@ +require 'mkmf' +create_makefile('rucaptcha/rucaptcha') \ No newline at end of file diff --git a/ext/rucaptcha/font.h b/ext/rucaptcha/font.h new file mode 100644 index 0000000..e5ab712 --- /dev/null +++ b/ext/rucaptcha/font.h @@ -0,0 +1,27 @@ +static int8_t lt0[]={-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-4,11,7,5,3,1,0,0,0,1,3,7,13,-100,-2,11,3,0,0,0,0,0,0,0,0,0,0,0,0,9,-100,-1,7,0,0,0,0,0,0,3,9,11,9,3,0,0,0,0,13,-100,9,0,0,0,0,0,0,3,-5,3,0,0,0,7,-100,5,0,0,0,0,0,1,13,-5,9,0,0,0,1,-100,7,0,0,0,0,1,13,-6,13,0,0,0,0,-100,-1,9,1,0,5,13,-8,0,0,0,0,13,-100,-14,0,0,0,0,11,-100,-14,0,0,0,0,11,-100,-14,0,0,0,0,11,-100,-12,13,5,0,0,0,0,11,-100,-8,13,9,5,1,0,0,0,0,0,0,11,-100,-4,13,7,3,1,0,0,0,0,1,1,0,0,0,0,11,-100,-2,13,5,0,0,0,0,0,5,9,13,-2,0,0,0,0,11,-100,-1,13,1,0,0,0,0,7,-6,0,0,0,0,11,-100,13,1,0,0,0,0,13,-7,0,0,0,0,11,-100,5,0,0,0,0,5,-8,0,0,0,0,11,-100,0,0,0,0,0,11,-8,0,0,0,0,11,-100,0,0,0,0,0,13,-7,13,0,0,0,0,11,-100,1,0,0,0,0,-7,9,0,0,0,0,0,9,-3,9,-100,5,0,0,0,0,3,13,-3,11,3,0,0,0,0,0,0,0,9,13,3,5,-100,13,0,0,0,0,0,0,1,1,0,0,0,1,11,9,0,0,0,0,0,0,1,13,-100,-1,11,1,0,0,0,0,0,0,0,0,5,-3,9,0,0,0,0,0,11,-100,-2,13,7,3,0,0,0,3,7,13,-5,9,0,1,3,9,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt1[]={-100,-100,-4,13,5,0,3,-100,-3,11,1,0,0,0,7,-100,-2,7,0,0,0,0,0,3,-100,13,3,0,0,0,0,0,0,5,-100,1,0,0,0,0,0,0,0,9,-100,1,0,0,0,0,0,0,0,13,-100,13,3,0,0,0,0,0,1,-100,-2,5,0,0,0,0,5,-100,-3,0,0,0,0,9,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,9,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,3,13,9,5,3,1,0,0,1,3,5,9,-100,-3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,13,-100,-3,0,0,0,0,0,5,13,-2,13,11,9,5,0,0,0,0,1,13,-100,-3,0,0,0,0,1,-8,13,1,0,0,0,5,-100,-3,3,0,0,0,5,-9,13,0,0,0,0,11,-100,-3,0,0,0,0,9,-10,7,0,0,0,5,-100,-3,1,0,0,0,11,-10,13,0,0,0,0,-100,-3,3,0,0,0,11,-11,3,0,0,0,11,-100,-3,1,0,0,0,11,-11,7,0,0,0,7,-100,-3,0,0,0,0,11,-11,9,0,0,0,3,-100,-3,0,0,0,0,11,-11,11,0,0,0,1,-100,-3,0,0,0,0,11,-11,11,0,0,0,1,-100,-3,0,0,0,0,11,-11,11,0,0,0,0,-100,-3,0,0,0,0,11,-11,9,0,0,0,0,-100,-3,0,0,0,0,11,-11,7,0,0,0,3,-100,-3,0,0,0,0,11,-11,3,0,0,0,7,-100,-3,0,0,0,0,11,-11,0,0,0,0,11,-100,-3,0,0,0,0,11,-10,9,0,0,0,3,-100,-3,0,0,0,0,9,-10,3,0,0,0,11,-100,-3,0,0,0,0,3,-9,11,0,0,0,5,-100,-2,13,0,0,0,0,0,9,-7,11,1,0,0,3,-100,-2,7,0,0,0,0,0,0,7,13,-2,13,9,3,0,0,0,3,13,-100,-2,13,0,0,5,13,11,1,0,0,0,0,0,0,0,0,0,7,-100,-3,9,11,-4,7,3,1,0,0,1,5,9,13,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt2[]={-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-6,13,7,3,1,0,0,1,3,7,13,-100,-5,9,0,0,0,0,0,0,0,0,0,0,5,13,-100,-3,13,3,0,0,0,5,13,13,7,0,0,0,0,0,1,13,-100,-2,13,1,0,0,0,9,-4,7,0,0,0,0,0,1,-100,-1,13,1,0,0,0,9,-6,5,0,0,0,0,0,13,-100,-1,5,0,0,0,3,-8,1,0,0,0,3,-100,13,0,0,0,0,11,-8,13,3,0,3,-100,7,0,0,0,1,-100,5,0,0,0,5,-100,3,0,0,0,9,-100,1,0,0,0,11,-100,0,0,0,0,11,-100,0,0,0,0,11,-100,0,0,0,0,11,-100,0,0,0,0,9,-100,1,0,0,0,5,-100,5,0,0,0,0,13,-100,11,0,0,0,0,7,-100,-1,3,0,0,0,0,13,-100,-1,11,0,0,0,0,3,-12,9,-100,-2,7,0,0,0,0,3,13,-8,9,1,3,-100,-3,5,0,0,0,0,1,9,-5,9,3,0,0,11,-100,-4,5,0,0,0,0,0,0,1,1,1,0,0,0,0,11,-100,-5,9,1,0,0,0,0,0,0,0,0,0,3,13,-100,-7,11,7,3,1,0,1,3,7,11,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt3[]={-100,-100,-100,-100,-18,11,3,0,-100,-16,13,3,0,0,0,-100,-14,9,3,0,0,0,0,0,-100,-13,3,0,0,0,0,0,0,0,-100,-13,0,0,0,0,0,0,0,0,-100,-13,9,1,0,0,0,0,0,0,-100,-15,13,5,0,0,0,0,-100,-17,1,0,0,0,-100,-17,3,0,0,0,-100,-17,1,0,0,0,-100,-17,0,0,0,0,-100,-16,13,0,0,0,0,-100,-16,13,0,0,0,0,-100,-6,11,5,3,1,0,0,1,5,9,13,13,0,0,0,0,-100,-4,13,3,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,-100,-3,13,1,0,0,0,0,5,11,-1,13,11,3,0,0,0,0,0,0,-100,-2,13,1,0,0,0,0,7,-6,11,0,0,0,0,0,-100,-2,3,0,0,0,0,9,-8,11,0,0,0,0,-100,-1,9,0,0,0,0,7,-9,11,0,0,0,0,-100,-1,1,0,0,0,0,13,-9,11,0,0,0,0,-100,11,0,0,0,0,3,-10,11,0,0,0,0,-100,5,0,0,0,0,13,-10,11,0,0,0,0,-100,3,0,0,0,3,-11,11,0,0,0,0,-100,0,0,0,0,7,-11,11,0,0,0,0,-100,0,0,0,0,11,-11,11,0,0,0,0,-100,0,0,0,0,11,-11,11,0,0,0,0,-100,0,0,0,0,11,-11,11,0,0,0,0,-100,1,0,0,0,9,-11,11,0,0,0,0,-100,3,0,0,0,7,-11,11,0,0,0,0,-100,7,0,0,0,3,-11,11,0,0,0,0,-100,13,0,0,0,0,13,-10,13,0,0,0,0,-100,-1,3,0,0,0,5,-11,0,0,0,0,-100,-1,13,0,0,0,0,11,-10,0,0,0,0,-100,-2,7,0,0,0,1,13,-8,13,0,0,0,0,13,-100,-3,5,0,0,0,1,11,-7,5,0,0,0,0,9,-100,-4,5,0,0,0,0,3,9,13,-1,13,11,1,0,0,0,0,0,0,0,5,-100,-5,9,1,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,1,13,-100,-7,9,3,1,0,0,3,7,13,-1,11,1,0,1,5,7,11,-100,-18,13,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt4[]={-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-7,13,5,1,1,0,1,3,9,13,-100,-6,5,0,0,0,0,0,0,0,0,0,9,-100,-4,11,1,0,0,3,11,-1,13,7,1,0,0,0,9,-100,-3,9,0,0,0,1,13,-5,3,0,0,1,-100,-2,9,0,0,0,0,13,-6,11,0,0,0,9,-100,-1,13,0,0,0,0,9,-8,0,0,0,1,-100,-1,5,0,0,0,0,13,-8,3,0,0,0,11,-100,-1,0,0,0,0,0,-8,13,1,0,0,0,5,-100,9,0,0,0,0,0,3,11,-4,13,11,1,0,0,0,0,1,-100,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-100,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,-100,1,0,0,0,1,13,-100,0,0,0,0,11,-100,0,0,0,0,11,-100,1,0,0,0,9,-100,3,0,0,0,7,-100,7,0,0,0,5,-100,13,0,0,0,0,11,-100,-1,5,0,0,0,1,13,-100,-1,13,1,0,0,0,1,13,-10,13,11,-100,-2,11,0,0,0,0,1,13,-8,13,1,1,-100,-3,11,0,0,0,0,0,7,13,-4,11,7,0,0,9,-100,-4,11,1,0,0,0,0,0,1,1,1,0,0,0,0,7,-100,-5,13,5,0,0,0,0,0,0,0,0,0,1,9,-100,-7,13,7,3,0,0,0,1,5,9,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt5[]={-100,-100,-100,-100,-9,13,9,3,1,0,1,5,13,-100,-8,7,0,0,0,0,0,0,0,3,-100,-7,3,0,0,0,0,0,0,0,0,1,-100,-6,5,0,0,0,0,0,0,0,0,0,3,-100,-5,13,0,0,3,13,9,1,0,0,0,0,11,-100,-5,9,0,0,13,-2,13,5,0,1,9,-100,-5,5,0,0,-100,-5,1,0,1,-100,-5,1,0,0,-100,-5,0,0,0,-100,-5,0,0,0,13,-100,-5,0,0,0,9,-100,-5,0,0,0,7,-100,-5,0,0,0,5,-100,-3,13,7,0,0,0,0,9,-1,13,11,13,-100,3,0,0,0,0,0,0,0,0,0,0,0,0,0,9,-100,3,0,0,0,0,0,0,0,0,0,0,0,0,0,9,-100,-1,11,13,-1,7,0,0,0,0,5,-1,13,11,13,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,7,-100,-3,13,5,0,0,0,0,0,7,13,-100,-1,5,0,0,0,0,0,0,0,0,0,0,0,1,11,-100,-1,7,1,0,0,0,0,0,0,0,0,1,3,7,13,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt6[]={-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-7,11,7,3,1,0,0,1,3,7,13,-4,13,7,5,7,11,-100,-5,11,3,0,0,0,0,0,0,0,0,0,0,5,13,13,5,0,0,0,0,0,-100,-4,9,0,0,0,5,13,-1,13,9,3,0,0,0,0,0,0,0,0,0,0,0,1,-100,-3,11,0,0,0,5,-6,5,0,0,0,0,0,11,13,9,3,0,9,-100,-2,13,0,0,0,0,13,-7,1,0,0,0,0,13,-100,-2,1,0,0,0,7,-8,7,0,0,0,0,7,-100,-2,0,0,0,0,9,-8,11,0,0,0,0,3,-100,-2,0,0,0,0,11,-9,0,0,0,0,1,-100,-2,0,0,0,0,11,-9,0,0,0,0,0,-100,-2,0,0,0,0,9,-8,13,0,0,0,0,1,-100,-2,3,0,0,0,5,-8,9,0,0,0,0,7,-100,-2,13,1,0,0,0,13,-7,5,0,0,0,0,13,-100,-3,11,0,0,0,3,13,-5,7,0,0,0,0,11,-100,-4,7,0,0,0,1,9,13,-1,13,7,0,0,0,1,11,-100,-4,13,0,0,0,0,0,0,0,0,0,0,0,5,13,-100,-4,13,0,0,0,0,0,0,1,3,5,9,-100,-2,13,5,0,11,-100,-1,13,1,0,0,-100,-1,3,0,0,0,1,7,13,-100,-1,0,0,0,0,0,0,0,1,3,7,9,11,13,-100,-1,5,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,5,11,-100,-2,11,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,11,-100,-4,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,-100,-3,9,1,0,3,9,13,13,11,7,3,0,0,0,0,0,0,0,0,0,13,-100,-1,7,1,0,0,9,-8,11,7,3,0,0,0,0,0,5,-100,9,0,0,0,3,-13,11,1,0,0,1,-100,1,0,0,0,9,-15,0,0,0,-100,0,0,0,0,9,-14,13,0,0,1,-100,3,0,0,0,1,-14,7,0,0,5,-100,11,0,0,0,0,5,-12,11,0,0,0,13,-100,-1,11,1,0,0,0,1,7,11,13,-1,13,13,11,9,5,3,1,0,0,3,13,-100,-3,9,3,0,0,0,0,0,0,0,0,0,0,0,0,0,1,9,-100,-6,9,7,3,1,1,0,0,1,1,3,7,11,-100,-101}; +static int8_t lt7[]={-100,-100,-100,-100,-4,13,7,1,9,-100,-2,13,7,0,0,0,3,-100,-1,7,0,0,0,0,0,5,-100,1,0,0,0,0,0,0,7,-100,3,0,0,0,0,0,0,7,-100,13,7,0,0,0,0,0,9,-100,-2,5,0,0,0,0,9,-100,-2,11,0,0,0,0,9,-100,-3,0,0,0,0,9,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-5,11,5,1,0,1,7,-100,-3,0,0,0,0,11,-3,13,3,0,0,0,0,0,0,3,-100,-3,0,0,0,0,11,-2,7,0,0,0,0,0,0,0,0,0,9,-100,-3,0,0,0,0,11,11,3,0,5,11,-1,13,9,1,0,0,0,3,-100,-3,0,0,0,0,3,0,1,11,-6,1,0,0,0,13,-100,-3,0,0,0,0,0,5,-8,11,0,0,0,11,-100,-3,0,0,0,0,11,-10,0,0,0,7,-100,-3,0,0,0,0,13,-10,0,0,0,7,-100,-3,0,0,0,0,11,-10,0,0,0,7,-100,-3,0,0,0,0,11,-10,0,0,0,7,-100,-3,0,0,0,0,13,-10,0,0,0,9,-100,-3,0,0,0,0,13,-10,0,0,0,9,-100,-3,0,0,0,0,-11,0,0,0,11,-100,-3,0,0,0,1,-11,0,0,0,13,-100,-3,0,0,0,1,-11,0,0,0,13,-100,-3,0,0,0,3,-11,0,0,0,-100,-3,0,0,0,3,-11,0,0,0,-100,-3,0,0,0,3,-11,0,0,0,-100,-3,0,0,0,3,-10,13,0,0,0,13,-100,-3,0,0,0,1,-10,13,0,0,0,11,-100,-2,9,0,0,0,0,-10,11,0,0,0,5,-100,-1,7,0,0,0,0,0,5,13,-7,13,3,0,0,0,0,7,-100,5,0,0,0,0,0,0,0,0,3,-5,1,0,0,0,0,0,0,1,3,11,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt8[]={-100,-100,-100,-100,-3,5,1,0,3,11,-100,-2,7,0,0,0,0,0,11,-100,-2,1,0,0,0,0,0,5,-100,-2,0,0,0,0,0,0,5,-100,-2,5,0,0,0,0,0,11,-100,-3,7,0,0,3,9,-100,-4,13,-100,-100,-100,-100,-100,-100,-100,-4,11,3,0,9,-100,-2,9,3,0,0,0,9,-100,11,1,0,0,0,0,0,7,-100,1,0,0,0,0,0,0,7,-100,1,0,0,0,0,0,0,9,-100,-1,11,0,0,0,0,0,9,-100,-2,7,0,0,0,0,11,-100,-3,0,0,0,0,13,-100,-3,1,0,0,0,-100,-3,1,0,0,0,13,-100,-3,1,0,0,0,13,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-2,13,0,0,0,0,7,-100,-2,13,0,0,0,0,1,-100,-2,7,0,0,0,0,0,9,-100,7,0,0,0,0,0,0,0,0,3,-100,9,5,1,1,0,0,1,1,3,5,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt9[]={-100,-100,-100,-100,-6,5,0,1,5,13,-100,-5,5,0,0,0,0,1,-100,-5,1,0,0,0,0,0,13,-100,-5,0,0,0,0,0,0,-100,-5,5,0,0,0,0,3,-100,-6,7,1,0,5,13,-100,-100,-100,-100,-100,-100,-100,-100,-6,13,7,3,0,13,-100,-5,7,0,0,0,0,11,-100,-3,7,1,0,0,0,0,0,11,-100,-2,13,0,0,0,0,0,0,0,11,-100,-3,11,3,0,0,0,0,0,11,-100,-5,9,0,0,0,0,11,-100,-6,1,0,0,0,11,-100,-6,3,0,0,0,11,-100,-6,5,0,0,0,11,-100,-6,5,0,0,0,11,-100,-6,5,0,0,0,11,-100,-6,5,0,0,0,11,-100,-6,3,0,0,0,11,-100,-6,3,0,0,0,11,-100,-6,1,0,0,0,11,-100,-6,1,0,0,0,13,-100,-6,1,0,0,0,13,-100,-6,1,0,0,0,13,-100,-6,1,0,0,0,13,-100,-6,1,0,0,0,13,-100,-6,1,0,0,0,-100,-6,1,0,0,0,-100,-6,1,0,0,1,-100,-6,1,0,0,3,-100,-6,0,0,0,5,-100,-6,0,0,0,7,-100,-6,0,0,0,11,-100,11,0,0,0,5,5,0,0,5,-100,3,0,0,0,0,0,0,3,-100,0,0,0,0,0,0,0,13,-100,1,0,0,0,0,0,11,-100,13,3,0,0,3,11,-100,-100,-101}; +static int8_t lt10[]={-100,-100,-100,-100,-6,9,1,13,-100,-3,13,5,0,0,0,11,-100,-1,13,5,0,0,0,0,0,11,-100,13,1,0,0,0,0,0,0,11,-100,3,0,0,0,0,0,0,0,11,-100,11,3,0,0,0,0,0,0,11,-100,-2,13,0,0,0,0,0,11,-100,-3,9,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-7,3,0,0,0,0,0,0,0,0,0,3,-100,-4,0,0,0,0,11,-7,5,0,0,0,0,0,0,0,1,7,13,-100,-4,0,0,0,0,11,-8,9,0,0,0,1,9,-100,-4,0,0,0,0,11,-7,13,1,0,0,7,-100,-4,0,0,0,0,11,-7,5,0,3,13,-100,-4,0,0,0,0,11,-6,5,0,5,-100,-4,0,0,0,0,11,-5,5,1,11,-100,-4,0,0,0,0,11,-3,11,3,1,-100,-4,0,0,0,0,11,-1,11,3,0,0,1,-100,-4,0,0,0,0,11,9,0,0,0,0,0,11,-100,-4,0,0,0,0,0,0,1,0,0,0,0,3,-100,-4,0,0,0,0,0,9,-1,11,1,0,0,0,9,-100,-4,0,0,0,0,5,-4,3,0,0,0,11,-100,-4,0,0,0,0,11,-4,13,1,0,0,0,13,-100,-4,0,0,0,0,11,-5,11,0,0,0,1,13,-100,-4,0,0,0,0,11,-6,3,0,0,0,3,-100,-4,0,0,0,0,11,-6,11,0,0,0,0,7,-100,-4,0,0,0,0,11,-7,3,0,0,0,0,7,-100,-3,13,0,0,0,0,11,-7,13,0,0,0,0,0,7,-100,-2,13,3,0,0,0,0,7,-7,9,0,0,0,0,0,0,3,11,-100,-1,1,0,0,0,0,0,0,0,0,1,3,-4,0,0,0,0,0,0,0,0,0,0,3,-100,-1,7,1,0,0,0,0,0,0,0,0,7,-4,3,0,0,0,0,0,0,1,1,5,9,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt11[]={-100,-100,-100,-6,11,7,11,-100,-4,11,3,0,0,5,-100,-3,5,0,0,0,0,5,-100,-1,11,1,0,0,0,0,0,7,-100,7,0,0,0,0,0,0,0,7,-100,0,0,0,0,0,0,0,0,9,-100,7,0,0,0,0,0,0,0,9,-100,-2,9,1,0,0,0,0,9,-100,-3,11,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,7,-100,-3,5,0,0,0,0,0,13,-100,-1,9,1,0,0,0,0,0,0,0,1,9,-100,-1,5,1,0,0,0,0,0,0,0,1,11,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt12[]={-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-5,11,5,0,-21,7,1,0,3,9,-100,-4,7,0,0,0,13,-4,11,5,1,1,0,1,7,-7,11,3,0,0,0,0,0,5,-100,-2,11,1,0,0,0,0,11,-2,9,1,0,0,0,0,0,0,0,9,-4,13,5,0,0,0,0,0,0,0,0,7,-100,13,3,0,0,0,0,0,0,7,13,3,0,0,0,1,0,0,0,0,0,0,7,-1,13,7,0,0,0,0,0,0,0,0,0,0,0,11,-100,3,0,0,0,0,0,0,0,1,0,0,5,11,-3,11,0,0,0,0,0,0,0,3,9,13,13,-3,7,0,0,0,0,5,-100,13,3,0,0,0,0,0,0,0,7,13,-6,3,0,0,0,0,0,9,-8,5,0,0,0,1,-100,-2,11,0,0,0,0,0,3,-8,9,0,0,0,0,7,-9,11,0,0,0,0,-100,-3,3,0,0,0,0,7,-8,13,0,0,0,0,-10,11,0,0,0,0,-100,-3,7,0,0,0,0,11,-9,0,0,0,0,-10,11,0,0,0,1,-100,-3,11,0,0,0,0,11,-9,0,0,0,0,-10,11,0,0,0,3,-100,-3,13,0,0,0,0,11,-8,13,0,0,0,0,-10,11,0,0,0,5,-100,-3,13,0,0,0,0,11,-8,11,0,0,0,0,-10,11,0,0,0,5,-100,-4,0,0,0,0,13,-8,9,0,0,0,0,-10,11,0,0,0,5,-100,-4,0,0,0,0,13,-8,11,0,0,0,0,-10,11,0,0,0,3,-100,-4,0,0,0,0,13,-8,11,0,0,0,0,-10,11,0,0,0,0,-100,-3,13,0,0,0,1,-9,13,0,0,0,0,-10,11,0,0,0,0,-100,-3,11,0,0,0,13,-10,0,0,0,0,-10,11,0,0,0,0,-100,-4,0,0,0,11,-10,0,0,0,0,-10,11,0,0,0,0,-100,-3,13,0,0,0,3,-9,13,0,0,0,0,13,-9,9,0,0,0,0,-100,-3,7,0,0,0,0,13,-8,11,0,0,0,0,11,-9,7,0,0,0,0,13,-100,-3,3,0,0,0,0,9,-8,5,0,0,0,0,5,-9,5,0,0,0,0,7,-100,-1,13,3,0,0,0,0,0,1,11,-6,9,0,0,0,0,0,0,3,-7,11,1,0,0,0,0,1,13,-100,11,0,0,0,0,0,0,0,0,0,3,-4,3,0,0,0,0,0,0,0,0,5,-5,1,0,0,0,0,0,0,0,0,9,-100,13,1,0,0,0,0,0,0,0,1,9,-4,1,0,0,0,0,0,0,0,1,5,-5,1,0,0,0,0,0,0,0,0,7,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt13[]={-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-3,13,7,3,0,13,-5,13,7,1,0,0,3,7,-100,-2,5,0,0,0,0,-4,13,3,0,0,0,0,0,0,0,7,-100,7,1,0,0,0,0,0,-3,7,0,0,0,0,0,0,0,0,0,0,13,-100,1,0,0,0,0,0,0,13,9,1,0,5,11,13,-1,11,3,0,0,0,0,9,-100,13,3,0,0,0,0,0,1,1,7,-7,3,0,0,0,3,-100,-2,1,0,0,0,0,7,-9,13,0,0,0,1,-100,-2,7,0,0,0,0,-11,1,0,0,0,-100,-2,9,0,0,0,0,-11,1,0,0,0,13,-100,-2,11,0,0,0,0,-11,3,0,0,0,13,-100,-2,11,0,0,0,0,-11,5,0,0,0,11,-100,-2,11,0,0,0,0,-11,3,0,0,0,11,-100,-2,11,0,0,0,0,-11,1,0,0,0,11,-100,-2,11,0,0,0,0,-11,0,0,0,0,11,-100,-2,11,0,0,0,0,-11,0,0,0,0,11,-100,-2,11,0,0,0,0,-11,1,0,0,0,11,-100,-2,11,0,0,0,0,-11,3,0,0,0,11,-100,-2,11,0,0,0,0,-11,3,0,0,0,11,-100,-2,11,0,0,0,0,13,-10,5,0,0,0,11,-100,-2,11,0,0,0,0,13,-10,5,0,0,0,11,-100,-2,11,0,0,0,0,9,-10,5,0,0,0,9,-100,-2,7,0,0,0,0,5,-10,3,0,0,0,7,-100,-1,13,1,0,0,0,0,1,11,-7,11,5,0,0,0,0,0,3,9,-100,-1,1,0,0,0,0,0,0,0,0,3,-4,3,0,0,0,0,0,0,0,0,0,3,-100,-1,0,0,0,0,0,0,0,0,0,3,-4,5,1,0,0,0,0,0,0,0,0,1,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt14[]={-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-7,13,7,3,1,0,0,1,5,9,-100,-6,7,0,0,0,0,0,0,0,0,0,1,7,-100,-4,11,1,0,0,1,9,13,-1,13,11,5,0,0,0,3,13,-100,-3,11,0,0,0,3,13,-6,13,1,0,0,0,13,-100,-2,11,0,0,0,1,13,-8,13,0,0,0,5,-100,-2,0,0,0,0,9,-10,5,0,0,0,11,-100,-1,7,0,0,0,1,-11,13,0,0,0,1,-100,-1,1,0,0,0,5,-12,1,0,0,0,9,-100,11,0,0,0,0,11,-12,5,0,0,0,3,-100,7,0,0,0,0,13,-12,9,0,0,0,0,-100,3,0,0,0,0,13,-12,11,0,0,0,0,-100,1,0,0,0,0,-13,11,0,0,0,1,-100,0,0,0,0,0,-13,11,0,0,0,1,-100,0,0,0,0,0,13,-12,11,0,0,0,0,-100,1,0,0,0,0,13,-12,9,0,0,0,1,-100,5,0,0,0,0,11,-12,5,0,0,0,3,-100,9,0,0,0,0,9,-12,3,0,0,0,7,-100,-1,1,0,0,0,5,-12,0,0,0,0,11,-100,-1,9,0,0,0,3,-11,13,0,0,0,3,-100,-2,3,0,0,0,13,-10,7,0,0,0,11,-100,-2,13,1,0,0,3,-9,13,0,0,0,7,-100,-3,13,1,0,0,3,13,-6,13,1,0,0,5,-100,-4,13,1,0,0,1,7,13,-3,9,0,0,0,7,-100,-6,7,0,0,0,0,0,0,0,0,0,3,11,-100,-7,13,7,3,0,0,0,0,3,11,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt15[]={-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-6,11,7,-100,-4,11,3,0,0,7,11,5,3,0,0,0,1,5,9,-100,-2,11,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,-100,13,5,0,0,0,0,0,0,0,1,7,11,13,-1,13,3,0,0,0,5,-100,1,0,0,0,0,0,0,0,3,-7,7,0,0,0,7,-100,1,0,0,0,0,0,0,0,11,-8,7,0,0,0,13,-100,-1,11,5,0,0,0,0,0,11,-9,1,0,0,3,-100,-3,7,0,0,0,0,11,-9,5,0,0,0,11,-100,-3,9,0,0,0,0,11,-9,9,0,0,0,5,-100,-3,11,0,0,0,0,11,-9,11,0,0,0,0,13,-100,-3,11,0,0,0,0,11,-9,13,0,0,0,0,11,-100,-3,13,0,0,0,0,11,-10,0,0,0,0,11,-100,-3,13,0,0,0,0,11,-10,0,0,0,0,11,-100,-3,13,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,13,-100,-4,0,0,0,0,11,-10,0,0,0,0,13,-100,-4,0,0,0,0,13,-10,0,0,0,0,-100,-4,0,0,0,9,-11,0,0,0,3,-100,-4,0,0,0,3,-11,0,0,0,9,-100,-4,0,0,0,0,13,-10,0,0,0,13,-100,-4,0,0,0,0,11,-9,5,0,0,0,-100,-4,0,0,0,0,11,-8,7,0,0,0,7,-100,-4,0,0,0,0,5,-7,9,0,0,0,3,-100,-4,0,0,0,0,0,3,11,13,-3,9,0,0,0,1,-100,-4,0,0,0,0,5,7,0,0,0,1,1,0,0,0,1,13,-100,-4,0,0,0,0,11,-2,9,5,1,0,0,3,7,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,7,-100,-4,0,0,0,0,3,-100,-3,7,0,0,0,0,0,9,-100,-1,5,0,0,0,0,0,0,0,0,0,0,5,-100,-1,3,1,0,0,0,0,0,0,0,0,0,5,-100,-101}; +static int8_t lt16[]={-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-19,7,11,-100,-6,11,5,1,0,0,1,5,11,-4,5,0,3,-100,-4,13,3,0,0,0,0,0,0,0,0,1,11,13,5,0,0,1,-100,-3,13,1,0,0,1,5,11,-3,11,3,0,0,0,0,0,3,-100,-2,13,1,0,0,3,-8,3,0,0,0,0,5,-100,-1,13,1,0,0,0,13,-8,7,0,0,0,0,5,-100,-1,3,0,0,0,5,-9,11,0,0,0,0,7,-100,9,0,0,0,0,11,-9,13,0,0,0,0,9,-100,3,0,0,0,0,-10,13,0,0,0,0,9,-100,1,0,0,0,1,-11,0,0,0,0,9,-100,0,0,0,0,3,-11,0,0,0,0,11,-100,0,0,0,0,5,-11,0,0,0,0,11,-100,0,0,0,0,9,-11,0,0,0,0,11,-100,0,0,0,0,11,-11,0,0,0,0,11,-100,0,0,0,0,11,-11,0,0,0,0,11,-100,1,0,0,0,11,-11,0,0,0,0,11,-100,3,0,0,0,9,-11,0,0,0,0,11,-100,7,0,0,0,5,-11,0,0,0,0,11,-100,11,0,0,0,0,-11,0,0,0,0,11,-100,-1,1,0,0,0,7,-9,11,0,0,0,0,11,-100,-1,9,0,0,0,0,13,-8,9,0,0,0,0,11,-100,-2,3,0,0,0,1,13,-7,5,0,0,0,0,11,-100,-2,13,3,0,0,0,1,9,13,-3,13,7,0,0,0,0,0,11,-100,-4,9,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,11,-100,-6,11,7,3,1,0,0,5,9,-1,13,0,0,0,0,11,-100,-16,0,0,0,0,13,-100,-16,0,0,0,0,13,-100,-16,0,0,0,0,13,-100,-16,0,0,0,0,13,-100,-15,13,0,0,0,0,13,-100,-15,9,0,0,0,0,11,-100,-15,1,0,0,0,0,5,-100,-12,7,5,1,0,0,0,0,0,0,1,3,9,-100,-11,13,1,0,0,0,0,0,0,0,0,0,0,7,-100,-101}; +static int8_t lt17[]={-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-3,13,5,0,3,-5,9,3,1,0,0,3,-100,-1,11,3,0,0,0,0,-3,7,0,0,0,0,0,0,0,5,-100,9,0,0,0,0,0,0,-2,3,0,0,0,0,0,0,0,0,1,-100,0,0,0,0,0,0,0,11,3,0,0,0,0,0,0,0,0,0,1,-100,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,-100,-1,7,0,0,0,0,0,0,7,13,-2,11,7,3,1,3,11,-100,-2,3,0,0,0,0,3,-100,-2,7,0,0,0,0,9,-100,-2,11,0,0,0,0,13,-100,-2,13,0,0,0,0,-100,-3,0,0,0,0,-100,-3,0,0,0,0,13,-100,-3,0,0,0,0,13,-100,-3,0,0,0,0,13,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,9,-100,-1,13,3,0,0,0,0,1,13,-100,3,0,0,0,0,0,0,0,0,0,0,13,-100,5,1,0,0,0,0,0,0,0,0,3,13,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt18[]={-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-3,13,7,1,0,1,3,9,11,9,9,13,-100,-2,13,1,0,0,0,0,0,0,0,0,0,5,-100,-2,1,0,5,13,-1,13,11,3,0,0,0,1,-100,-1,9,0,1,-6,9,0,0,0,13,-100,-1,3,0,9,-7,11,1,0,9,-100,-1,0,0,-9,13,1,5,-100,-1,0,0,11,-9,13,11,-100,13,0,0,1,13,-100,13,0,0,0,1,9,-100,-1,0,0,0,0,0,0,5,9,-100,-1,5,0,0,0,0,0,0,0,1,7,13,-100,-1,13,0,0,0,0,0,0,0,0,0,0,9,-100,-2,13,1,0,0,0,0,0,0,0,0,0,7,-100,-4,11,5,0,0,0,0,0,0,0,0,7,-100,-7,9,5,0,0,0,0,0,0,13,-100,-9,13,7,0,0,0,0,7,-100,-11,13,3,0,0,3,-100,-13,0,0,0,-100,7,5,-11,1,0,0,-100,1,0,5,-10,1,0,3,-100,0,0,0,3,-9,0,0,9,-100,1,0,0,0,3,13,-6,5,0,3,-100,7,0,0,0,0,1,7,11,13,13,9,3,0,1,13,-100,13,0,0,0,0,0,0,0,0,0,0,0,3,13,-100,-1,5,3,9,7,3,1,0,0,1,5,11,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt19[]={-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-6,5,0,5,-100,-5,13,0,0,0,7,-100,-5,7,0,0,0,9,-100,-5,3,0,0,0,13,-100,-4,11,0,0,0,0,-100,-4,3,0,0,0,0,-100,-3,5,0,0,0,0,1,-100,-2,3,0,0,0,0,0,7,-100,13,1,0,0,0,0,0,0,1,11,-100,3,0,0,0,0,0,0,0,0,0,0,0,0,0,5,13,-100,1,0,0,0,0,0,0,0,0,0,0,0,0,0,5,-100,-3,9,0,0,0,0,7,13,-100,-4,0,0,0,0,11,-100,-4,1,0,0,0,11,-100,-4,1,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,1,0,0,0,11,-100,-4,3,0,0,0,11,-100,-4,5,0,0,0,11,-100,-4,3,0,0,0,11,-100,-4,3,0,0,0,11,-100,-4,1,0,0,0,9,-100,-4,0,0,0,0,5,-100,-4,0,0,0,0,1,-100,-4,1,0,0,0,0,11,-100,-4,3,0,0,0,0,1,13,-1,9,5,1,3,-100,-4,9,0,0,0,0,0,0,0,0,0,0,5,-100,-5,5,0,0,0,0,0,0,0,0,5,-100,-6,9,3,1,0,0,1,5,11,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt20[]={-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-4,13,9,1,0,13,-11,11,5,1,5,-100,-2,11,3,0,0,0,0,11,-8,11,5,0,0,0,0,1,-100,13,3,0,0,0,0,0,0,11,-6,7,1,0,0,0,0,0,0,7,-100,5,0,0,0,0,0,0,0,11,-5,5,0,0,0,0,0,0,0,0,11,-100,11,1,0,0,0,0,0,0,11,-5,9,0,0,0,0,0,0,0,0,11,-100,-2,11,1,0,0,0,0,11,-6,13,7,3,0,0,0,0,0,11,-100,-3,9,0,0,0,0,11,-9,9,0,0,0,0,11,-100,-3,11,0,0,0,0,11,-10,0,0,0,0,11,-100,-3,13,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,1,0,0,0,11,-9,13,0,0,0,0,11,-100,-4,1,0,0,0,11,-9,5,0,0,0,0,11,-100,-4,5,0,0,0,7,-8,7,0,0,0,0,0,11,-100,-4,7,0,0,0,0,13,-5,13,5,0,0,0,0,0,0,11,-100,-4,13,0,0,0,0,1,11,-1,13,11,5,0,0,7,5,0,0,0,0,3,13,-100,-5,3,0,0,0,0,0,0,0,0,0,3,13,-2,0,0,0,0,0,0,7,-100,-5,11,0,0,0,0,0,0,0,1,9,-4,0,0,0,0,0,0,0,-100,-6,13,5,1,0,1,3,9,-6,3,1,3,7,9,11,13,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt21[]={-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-6,13,9,1,3,13,-5,13,1,0,0,0,0,1,3,9,-100,1,0,0,0,0,0,0,0,0,0,1,-5,1,0,0,0,0,0,0,0,0,9,-100,3,0,0,0,0,0,0,0,0,0,5,-5,3,0,0,0,0,0,0,0,0,13,-100,-1,9,3,0,0,0,0,0,5,13,-7,13,9,0,0,0,0,1,11,-100,-3,7,0,0,0,0,-11,7,0,0,5,-100,-4,0,0,0,0,9,-10,9,0,5,-100,-4,5,0,0,0,1,-10,5,0,11,-100,-4,11,0,0,0,0,9,-9,0,1,-100,-5,1,0,0,0,3,-8,9,0,7,-100,-5,7,0,0,0,0,13,-7,3,0,13,-100,-5,13,0,0,0,0,7,-6,13,0,3,-100,-6,3,0,0,0,1,-6,7,0,11,-100,-6,9,0,0,0,0,9,-5,0,1,-100,-6,13,0,0,0,0,3,-4,7,0,7,-100,-7,5,0,0,0,0,11,-3,1,0,13,-100,-7,11,0,0,0,0,1,-2,9,0,5,-100,-8,1,0,0,0,0,5,-1,1,0,11,-100,-8,7,0,0,0,0,0,0,0,3,-100,-8,13,0,0,0,0,0,0,0,9,-100,-9,3,0,0,0,0,0,1,-100,-9,9,0,0,0,0,0,7,-100,-10,0,0,0,0,0,13,-100,-10,5,0,0,0,1,-100,-10,13,1,0,0,7,-100,-11,11,1,5,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt22[]={-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-29,13,-100,5,0,0,1,1,1,3,3,5,7,-3,7,0,0,0,0,0,0,0,0,0,11,-4,3,0,0,0,0,0,0,1,3,11,-100,5,0,0,0,0,0,0,0,1,7,-3,9,0,0,0,0,0,0,0,0,1,11,-4,9,1,0,0,0,0,0,0,1,13,-100,-1,13,5,0,0,0,0,0,13,-5,13,5,0,0,0,0,0,3,-8,9,0,0,0,0,5,-100,-3,5,0,0,0,0,-8,11,0,0,0,0,9,-9,9,0,0,9,-100,-4,1,0,0,0,13,-8,11,0,0,0,3,-10,0,3,-100,-4,7,0,0,0,11,-8,13,0,0,0,0,13,-8,9,0,11,-100,-4,13,0,0,0,7,-8,11,0,0,0,0,7,-8,1,1,-100,-5,5,0,0,1,-8,7,0,0,0,0,3,-8,5,11,-100,-5,11,0,0,0,9,-7,1,0,0,0,0,0,13,-100,-6,0,0,0,3,-6,9,0,3,13,0,0,0,7,-6,5,-100,-6,3,0,0,0,13,-5,1,0,11,-1,3,0,0,3,-6,1,-100,-6,9,0,0,0,9,-4,11,0,3,-2,7,0,0,0,13,-4,11,1,-100,-6,13,0,0,0,3,-4,5,0,9,-2,13,0,0,0,7,-4,5,3,-100,-7,3,0,0,0,13,-3,1,1,-4,0,0,0,1,-4,1,7,-100,-7,9,0,0,0,5,-2,13,0,7,-4,5,0,0,0,9,-2,9,0,13,-100,-8,1,0,0,0,13,-1,7,1,-5,11,0,0,0,1,-2,1,3,-100,-8,7,0,0,0,1,13,1,5,-6,1,0,0,0,13,9,0,9,-100,-8,13,0,0,0,0,0,0,11,-6,7,0,0,0,1,0,1,-100,-9,3,0,0,0,0,3,-7,13,0,0,0,0,0,9,-100,-9,9,0,0,0,0,5,-8,3,0,0,0,0,13,-100,-9,13,0,0,0,0,11,-8,9,0,0,0,1,-100,-10,3,0,0,0,-10,3,0,0,5,-100,-10,11,0,0,7,-10,13,1,1,13,-100,-11,11,11,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt23[]={-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-16,13,13,-1,13,9,5,1,0,1,5,13,-100,-1,3,0,0,0,0,0,0,0,0,1,7,-4,1,0,0,0,0,0,0,0,0,0,1,-100,-1,1,0,0,0,0,0,0,0,0,1,11,-4,7,0,0,0,0,0,0,0,0,0,5,-100,-2,13,7,0,0,0,0,0,0,13,-6,13,5,0,0,0,0,5,9,13,-100,-4,13,3,0,0,0,0,3,-7,13,0,0,5,13,-100,-6,3,0,0,0,0,5,-6,7,0,7,-100,-7,3,0,0,0,0,11,-4,11,0,9,-100,-8,5,0,0,0,1,-3,11,0,7,-100,-9,3,0,0,0,1,11,11,0,7,-100,-9,13,1,0,0,0,0,0,7,-100,-10,13,1,0,0,0,0,9,-100,-11,11,0,0,0,0,1,-100,-12,0,0,0,0,0,7,-100,-11,9,0,0,0,0,0,0,11,-100,-10,9,0,5,13,3,0,0,0,1,13,-100,-9,11,0,3,-2,13,1,0,0,0,1,13,-100,-8,11,0,3,13,-3,13,1,0,0,0,1,13,-100,-7,9,0,1,13,-5,11,0,0,0,0,1,13,-100,-6,9,0,0,7,-7,9,0,0,0,0,1,11,-100,-5,5,0,0,0,13,-8,7,0,0,0,0,0,9,-100,-3,13,3,0,0,0,0,13,-8,13,0,0,0,0,0,0,5,-100,9,3,1,0,0,0,0,0,0,1,11,-6,11,1,0,0,0,0,0,0,0,1,3,13,-100,3,0,0,0,0,0,0,0,0,0,3,-6,11,5,3,1,0,0,0,1,1,3,5,-100,13,13,13,13,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101}; +static int8_t lt24[]={-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-1,13,13,-2,13,13,11,11,11,13,-6,11,11,11,11,11,11,11,11,13,-100,3,0,0,0,0,0,0,0,0,0,0,3,-4,1,0,0,0,0,0,0,0,0,1,-100,7,0,0,0,0,0,0,0,0,0,0,5,-4,3,0,0,0,0,0,0,0,0,9,-100,-2,11,5,0,0,0,0,0,0,11,-6,11,0,0,0,0,1,7,13,-100,-4,11,0,0,0,0,0,-8,9,0,0,1,13,-100,-5,7,0,0,0,0,13,-7,9,0,0,13,-100,-6,1,0,0,0,9,-7,5,0,5,-100,-6,7,0,0,0,3,-7,1,0,13,-100,-6,13,0,0,0,0,13,-5,11,0,1,-100,-7,5,0,0,0,7,-5,7,0,7,-100,-7,11,0,0,0,3,-5,1,0,11,-100,-8,1,0,0,0,13,-3,13,0,3,-100,-8,7,0,0,0,7,-3,7,0,9,-100,-8,13,0,0,0,3,-3,1,1,-100,-9,5,0,0,0,13,-1,9,0,7,-100,-9,11,0,0,0,3,13,1,0,13,-100,-10,1,0,0,0,0,0,3,-100,-10,9,0,0,0,0,0,9,-100,-11,1,0,0,0,1,-100,-11,5,0,0,0,7,-100,-11,9,0,0,0,13,-100,-11,13,0,0,3,-100,-12,0,0,9,-100,-12,0,1,-100,-11,13,0,7,-100,-11,7,0,11,-100,-11,1,0,-100,-2,7,0,1,7,-4,11,0,3,-100,-1,11,0,0,0,0,1,9,13,11,1,0,9,-100,-1,3,0,0,0,0,0,0,0,0,0,3,-100,-1,0,0,0,0,0,0,0,0,0,1,13,-100,-1,7,0,0,0,0,0,0,0,1,13,-100,-2,9,3,0,0,1,3,7,-100,-101}; +static int8_t *lt[]={lt0,lt1,lt2,lt3,lt0,lt5,lt0,lt7,lt8,lt9,lt10,lt11,lt12,lt13,lt14,lt15,lt16,lt17,lt18,lt19,lt20,lt21,lt22,lt23,lt24,}; + diff --git a/ext/rucaptcha/rucaptcha.c b/ext/rucaptcha/rucaptcha.c new file mode 100644 index 0000000..a39fbad --- /dev/null +++ b/ext/rucaptcha/rucaptcha.c @@ -0,0 +1,214 @@ +// http://github.com/ITikhonov/captcha +const int gifsize; +void captcha(unsigned char im[70*200], unsigned char l[6]); +void makegif(unsigned char im[70*200], unsigned char gif[gifsize], int style); + +#include +#include +#include +#include +#include +#include +#include +#include "font.h" +#include "colors.h" + +static int8_t *lt[]; +const int gifsize=17646; + +void makegif(unsigned char im[70*200], unsigned char gif[gifsize], int style) { + // tag ; widthxheight ; GCT:0:0:7 ; bgcolor + aspect // GCT + // Image Separator // left x top // widthxheight // Flags + // LZW code size + srand(time(NULL)); + int color_len = (int) sizeof(colors) / sizeof(colors[0]); + int color_idx = rand() % color_len; + if (style == 0) { + color_idx = 0; + } + memcpy(gif,colors[color_idx],13+48+10+1); + + int x,y; + unsigned char *i=im; + unsigned char *p=gif+13+48+10+1; + for(y=0;y<70;y++) { + *p++=250; // Data length 5*50=250 + for(x=0;x<50;x++) + { + unsigned char a=i[0]>>4,b=i[1]>>4,c=i[2]>>4,d=i[3]>>4; + + p[0]=16|(a<<5); // bbb10000 + p[1]=(a>>3)|64|(b<<7); // b10000xb + p[2]=b>>1; // 0000xbbb + p[3]=1|(c<<1); // 00xbbbb1 + p[4]=4|(d<<3); // xbbbb100 + i+=4; + p+=5; + } + } + + // Data length // End of LZW (b10001) // Terminator // GIF End + memcpy(gif+gifsize-4,"\x01" "\x11" "\x00" ";",4); +} + +static const int8_t sw[200]={0, 4, 8, 12, 16, 20, 23, 27, 31, 35, 39, 43, 47, 50, 54, 58, 61, 65, 68, 71, 75, 78, 81, 84, 87, 90, 93, 96, 98, 101, 103, 105, 108, 110, 112, 114, 115, 117, 119, 120, 121, 122, 123, 124, 125, 126, 126, 127, 127, 127, 127, 127, 127, 127, 126, 126, 125, 124, 123, 122, 121, 120, 119, 117, 115, 114, 112, 110, 108, 105, 103, 101, 98, 96, 93, 90, 87, 84, 81, 78, 75, 71, 68, 65, 61, 58, 54, 50, 47, 43, 39, 35, 31, 27, 23, 20, 16, 12, 8, 4, 0, -4, -8, -12, -16, -20, -23, -27, -31, -35, -39, -43, -47, -50, -54, -58, -61, -65, -68, -71, -75, -78, -81, -84, -87, -90, -93, -96, -98, -101, -103, -105, -108, -110, -112, -114, -115, -117, -119, -120, -121, -122, -123, -124, -125, -126, -126, -127, -127, -127, -127, -127, -127, -127, -126, -126, -125, -124, -123, -122, -121, -120, -119, -117, -115, -114, -112, -110, -108, -105, -103, -101, -98, -96, -93, -90, -87, -84, -81, -78, -75, -71, -68, -65, -61, -58, -54, -50, -47, -43, -39, -35, -31, -27, -23, -20, -16, -12, -8, -4}; + + +#define MAX(x,y) ((x>y)?(x):(y)) + +static int letter(int n, int pos, unsigned char im[70*200], unsigned char swr[200], uint8_t s1, uint8_t s2) { + int8_t *p=lt[n]; + unsigned char *r=im+200*16+pos; + unsigned char *i=r; + int sk1=s1+pos; + int sk2=s2+pos; + int mpos=pos; + int row=0; + for(;*p!=-101;p++) { + if(*p<0) { + if(*p==-100) { r+=200; i=r; sk1=s1+pos; row++; continue; } + i+=-*p; + continue; + } + + if(sk1>=200) sk1=sk1%200; + int skew=sw[sk1]/16; + sk1+=(swr[pos+i-r]&0x1)+1; + + if(sk2>=200) sk2=sk2%200; + int skewh=sw[sk2]/70; + sk2+=(swr[row]&0x1); + + unsigned char *x=i+skew*200+skewh; + mpos=MAX(mpos,pos+i-r); + + if((x-im)<70*200) *x=(*p)<<4; + i++; + } + return mpos; +} + +#define NDOTS 100 + +uint32_t dr[NDOTS]; + +static void line(unsigned char im[70*200], unsigned char swr[200], uint8_t s1) { + int x; + int sk1=s1; + for(x=0;x<199;x++) { + if(sk1>=200) sk1=sk1%200; + int skew=sw[sk1]/16; + sk1+=swr[x]&0x3+1; + unsigned char *i= im+(200*(45+skew)+x); + i[0]=0; i[1]=0; i[200]=0; i[201]=0; + } +} + +static void dots(unsigned char im[70*200]) { + int n; + for(n=0;n0xf0 && i[1]<0xf0) { o[0]=0; o[1]=0; } + else if(i[0]<0xf0 && i[1]>0xf0) { o[0]=0; o[1]=0; } + + i++; + o++; + } + } + + memmove(im,om,sizeof(om)); +} + +static const char *letters="abcdafahijklmnopqrstuvwxyz"; + +void captcha(unsigned char im[70*200], unsigned char l[6]) { + unsigned char swr[200]; + uint8_t s1,s2; + + int f=open("/dev/urandom",O_RDONLY); + read(f,l,5); read(f,swr,200); read(f,dr,sizeof(dr)); read(f,&s1,1); read(f,&s2,1); + close(f); + + memset(im,0xff,200*70); s1=s1&0x7f; s2=s2&0x3f; l[0]%=25; l[1]%=25; l[2]%=25; l[3]%=25; l[4]%=25; l[5]=0; + int p=30; p=letter(l[0],p,im,swr,s1,s2); p=letter(l[1],p,im,swr,s1,s2); p=letter(l[2],p,im,swr,s1,s2); p=letter(l[3],p,im,swr,s1,s2); letter(l[4],p,im,swr,s1,s2); + line(im,swr,s1); dots(im); // blur(im); // filter(im); + l[0]=letters[l[0]]; l[1]=letters[l[1]]; l[2]=letters[l[2]]; l[3]=letters[l[3]]; l[4]=letters[l[4]]; +} + +// #ifdef CAPTCHA +// +// int main() { +// char l[6]; +// unsigned char im[70*200]; +// unsigned char gif[gifsize]; +// +// captcha(im,l); +// makegif(im,gif); +// +// write(1,gif,gifsize); +// write(2,l,5); +// +// return 0; +// } +// +// #endif + +VALUE RuCaptcha = Qnil; + +void Init_rucaptcha(); + +VALUE create(VALUE self, VALUE style); + +void Init_rucaptcha() { + RuCaptcha = rb_define_module("RuCaptcha"); + rb_define_singleton_method(RuCaptcha, "create", create, 1); +} + +VALUE create(VALUE self, VALUE style) { + char l[6]; + unsigned char im[80*200]; + unsigned char gif[gifsize]; + int i_style = FIX2INT(style); + + captcha(im, l); + makegif(im, gif, i_style); + + VALUE result = rb_ary_new2(2); + rb_ary_push(result, rb_str_new2(l)); + rb_ary_push(result, rb_str_new(gif, gifsize)); + + return result; +} + + diff --git a/lib/rucaptcha.rb b/lib/rucaptcha.rb index 0c44b49..66cdec8 100644 --- a/lib/rucaptcha.rb +++ b/lib/rucaptcha.rb @@ -1,12 +1,12 @@ require 'rails' require 'action_controller' require 'active_support/all' +require_relative 'rucaptcha/rucaptcha' require_relative 'rucaptcha/version' require_relative 'rucaptcha/configuration' require_relative 'rucaptcha/controller_helpers' require_relative 'rucaptcha/view_helpers' require_relative 'rucaptcha/cache' -require_relative 'rucaptcha/captcha' require_relative 'rucaptcha/engine' module RuCaptcha @@ -14,12 +14,8 @@ module RuCaptcha def config return @config if defined?(@config) @config = Configuration.new - @config.len = 4 - @config.font_size = 45 - @config.implode = 0.3 - @config.cache_limit = 100 - @config.expires_in = 2.minutes @config.style = :colorful + @config.expires_in = 2.minutes if Rails.application @config.cache_store = Rails.application.config.cache_store else @@ -31,6 +27,11 @@ module RuCaptcha def configure(&block) config.instance_exec(&block) end + + def generate() + style = config.style == :colorful ? 1 : 0 + self.create(style) + end end end diff --git a/lib/rucaptcha/cache.rb b/lib/rucaptcha/cache.rb index 8d4a9fd..1416bfa 100644 --- a/lib/rucaptcha/cache.rb +++ b/lib/rucaptcha/cache.rb @@ -8,46 +8,4 @@ module RuCaptcha @cache end end - - # File Cache - module Cache - def self.prepended(base) - class << base - prepend ClassMethods - end - end - - module ClassMethods - def create(code) - file_cache.fetch(code, expires_in: 1.days) do - super(code) - end - end - - def random_chars - if cached_codes.length >= RuCaptcha.config.cache_limit - return cached_codes.sample - end - - code = super - cached_codes << code - code - end - - def file_cache - return @file_cache if defined?(@file_cache) - - cache_path = Rails.root.join('tmp', 'cache', 'rucaptcha') - FileUtils.mkdir_p(cache_path) unless File.exist? cache_path - @file_cache = ActiveSupport::Cache::FileStore.new(cache_path) - # clear expired captcha cache files on Process restart - @file_cache.cleanup - @file_cache - end - - def cached_codes - @cached_codes ||= [] - end - end - end end diff --git a/lib/rucaptcha/captcha.rb b/lib/rucaptcha/captcha.rb deleted file mode 100644 index 51bf2da..0000000 --- a/lib/rucaptcha/captcha.rb +++ /dev/null @@ -1,125 +0,0 @@ -require 'open3' - -module RuCaptcha - class Captcha - class << self - # Genrate ranom RGB color - def random_color - if RuCaptcha.config.style == :colorful - color1 = rand(56) + 15 - color2 = rand(10) + 140 - color = [color1, color2, rand(15)] - color.shuffle! - color - else - color_seed = rand(40) + 10 - [color_seed, color_seed, color_seed] - end - end - - # Genrate random Captcha code - def random_chars - chars = SecureRandom.hex(RuCaptcha.config.len / 2).downcase - chars.gsub!(/[0ol1]/i, (rand(8) + 2).to_s) - chars - end - - # Create Captcha image by code - def create(code) - chars = code.split('') - full_width = RuCaptcha.config.font_size * chars.size - full_height = RuCaptcha.config.font_size - size = "#{full_width}x#{full_height}" - - return convert_for_windows(size, code) if Gem.win_platform? - - opts = command_line_opts(chars, full_width) - convert(size, opts) - end - - private - - def command_line_opts(chars, full_width) - font_size = RuCaptcha.config.font_size - all_left = 20 - half_width = full_width / 2 - text_top = 0 - text_left = 0 - (font_size * 0.28).to_i - text_width = font_size + text_left - - opts = { text: [], line: [] } - rgbs = uniq_rgbs_for_each_chars(chars) - - chars.each_with_index do |char, i| - rgb = RuCaptcha.config.style == :colorful ? rgbs[i] : rgbs[0] - text_color = "rgba(#{rgb.join(',')}, 1)" - line_color = "rgba(#{rgb.join(',')}, 0.6)" - opts[:text] << %(-fill '#{text_color}' -draw 'text #{(text_left + text_width) * i + all_left},#{text_top} "#{char}"') - - left_y = rand_line_top(text_top, font_size) - right_x = half_width + (half_width * 0.3).to_i - right_y = rand_line_top(text_top, font_size) - opts[:line] << %(-draw 'stroke #{line_color} line #{rand(10)},#{left_y} #{right_x},#{right_y}') - end - opts - end - - def convert(size, opts) - stroke_width = (RuCaptcha.config.font_size * 0.05).to_i + 1 - command = <<-CODE - convert -size #{size} \ - -strokewidth #{stroke_width} \ - #{opts[:line].join(' ')} \ - -pointsize #{RuCaptcha.config.font_size} -weight 500 \ - #{opts[:text].join(' ')} \ - -wave #{rand(2) + 3}x#{rand(2) + 1} \ - -rotate #{rand(10) - 5} \ - -gravity NorthWest -sketch 1x10+#{rand(2)} \ - -fill none \ - -implode #{RuCaptcha.config.implode} -trim label:- png:- - CODE - command.strip! - out, err, _st = Open3.capture3(command) - warn " RuCaptcha #{err.strip}" if err.present? - out - end - - # Generate a simple captcha image for Windows Platform - def convert_for_windows(size, code) - png_file_path = Rails.root.join('tmp', 'cache', "#{code}.png") - command = "convert -size #{size} xc:White -gravity Center -weight 12 -pointsize 20 -annotate 0 \"#{code}\" -trim #{png_file_path}" - _out, err, _st = Open3.capture3(command) - warn " RuCaptcha #{err.strip}" if err.present? - png_file_path - end - - # Geneate a uniq rgba colors for each chars - def uniq_rgbs_for_each_chars(chars) - rgbs = [] - chars.count.times do |i| - color = random_color - if i > 0 - preview_color = rgbs[i - 1] - # Avoid color same as preview color - if color.index(color.min) == preview_color.index(preview_color.min) && - color.index(color.max) == preview_color.index(preview_color.max) - # adjust RGB order - color = [color[1], color[2], color[0]] - end - end - rgbs << color - end - rgbs - end - - def rand_line_top(text_top, font_size) - text_top + rand(font_size * 0.7).to_i - end - - def warn(msg) - msg = " RuCaptcha #{msg}" - Rails.logger.error(msg) - end - end - end -end diff --git a/lib/rucaptcha/configuration.rb b/lib/rucaptcha/configuration.rb index 4330e33..d034143 100644 --- a/lib/rucaptcha/configuration.rb +++ b/lib/rucaptcha/configuration.rb @@ -1,20 +1,11 @@ module RuCaptcha class Configuration - # Image font size, default 45 - attr_accessor :font_size - # Number of chars, default 4 - attr_accessor :len - # implode, default 0.3 - attr_accessor :implode # Store Captcha code where, this config more like Rails config.cache_store # default: Rails application config.cache_store attr_accessor :cache_store - # Number of Captcha codes limit - # set 0 to disable limit and file cache, default: 100 - attr_accessor :cache_limit - # Color style, default: :colorful, allows: [:colorful, :black_white] - attr_accessor :style # rucaptcha expire time, default 2 minutes attr_accessor :expires_in + # Color style, default: :colorful, allows: [:colorful, :black_white] + attr_accessor :style end end diff --git a/lib/rucaptcha/controller_helpers.rb b/lib/rucaptcha/controller_helpers.rb index a76488f..fe187e3 100644 --- a/lib/rucaptcha/controller_helpers.rb +++ b/lib/rucaptcha/controller_helpers.rb @@ -14,13 +14,13 @@ module RuCaptcha # Generate a new Captcha def generate_rucaptcha - code = RuCaptcha::Captcha.random_chars + res = RuCaptcha.generate() session_val = { - code: code, + code: res[0], time: Time.now.to_i } RuCaptcha.cache.write(rucaptcha_sesion_key_key, session_val, expires_in: RuCaptcha.config.expires_in) - RuCaptcha::Captcha.create(code) + res[1] end # Verify captcha code diff --git a/lib/rucaptcha/engine.rb b/lib/rucaptcha/engine.rb index e76a1e6..e4ff30f 100644 --- a/lib/rucaptcha/engine.rb +++ b/lib/rucaptcha/engine.rb @@ -3,11 +3,6 @@ module RuCaptcha isolate_namespace RuCaptcha initializer 'rucaptcha.prepend.cache' do - # enable cache if cache_limit less than 1 - if RuCaptcha.config.cache_limit >= 1 - RuCaptcha::Captcha.send(:prepend, RuCaptcha::Cache) - end - cache_store = RuCaptcha.config.cache_store store_name = cache_store.is_a?(Array) ? cache_store.first : cache_store if [:memory_store, :null_store, :file_store].include?(store_name) diff --git a/lib/rucaptcha/version.rb b/lib/rucaptcha/version.rb index c05046e..78d10e8 100644 --- a/lib/rucaptcha/version.rb +++ b/lib/rucaptcha/version.rb @@ -1,3 +1,3 @@ module RuCaptcha - VERSION = '1.2.0' + VERSION = '2.0.0' end diff --git a/lib/rucaptcha/view_helpers.rb b/lib/rucaptcha/view_helpers.rb index c60bacd..a979654 100644 --- a/lib/rucaptcha/view_helpers.rb +++ b/lib/rucaptcha/view_helpers.rb @@ -5,8 +5,8 @@ module RuCaptcha opts[:type] = 'text' opts[:autocorrect] = 'off' opts[:autocapitalize] = 'off' - opts[:pattern] = '[0-9a-zA-Z]*' - opts[:maxlength] = RuCaptcha.config.len + opts[:pattern] = '[a-zA-Z]*' + opts[:maxlength] = 5 opts[:autocomplete] = 'off' tag(:input, opts) end diff --git a/rucaptcha.gemspec b/rucaptcha.gemspec index 4e3393f..ff50488 100644 --- a/rucaptcha.gemspec +++ b/rucaptcha.gemspec @@ -8,12 +8,18 @@ Gem::Specification.new do |s| s.version = RuCaptcha::VERSION s.authors = 'Jason Lee' s.email = 'huacnlee@gmail.com' - s.files = Dir.glob('lib/**/*') + Dir.glob('app/**/*') + Dir.glob('config/**/*') + %w(README.md CHANGELOG.md) + s.files = Dir.glob('lib/**/*.{rb}') + + Dir.glob("ext/**/*.{h,c,rb}") + + Dir.glob('app/**/*') + + Dir.glob('config/**/*') + + %w[README.md CHANGELOG.md] s.homepage = 'https://github.com/huacnlee/rucaptcha' s.require_paths = ['lib'] + s.extensions = %w[ext/rucaptcha/extconf.rb] s.summary = 'This is a Captcha gem for Rails Application. It run ImageMagick command to draw Captcha image.' s.license = "MIT" s.required_ruby_version = ">= 2.0.0" s.add_dependency 'railties', '>= 3.2' + s.add_development_dependency 'rake-compiler', '~> 1' end diff --git a/spec/cache_spec.rb b/spec/cache_spec.rb deleted file mode 100644 index 7b03fca..0000000 --- a/spec/cache_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -require 'spec_helper' - -describe RuCaptcha::Cache do - before(:all) do - RuCaptcha::Captcha.send(:prepend, RuCaptcha::Cache) - end - - describe '.random_chars_with_cache' do - it 'should generate max chars by config.cache_limit' do - allow(RuCaptcha.config).to receive(:cache_limit).and_return(5) - items = [] - 100.times do - items << RuCaptcha::Captcha.random_chars - end - expect(items.uniq.length).to eq RuCaptcha.config.cache_limit - expect(RuCaptcha::Captcha.cached_codes).to eq items.uniq - end - end - - describe '.create' do - it 'should work' do - expect(RuCaptcha::Captcha).to receive(:create).and_return('aabb') - expect(RuCaptcha::Captcha.create('abcd')).to eq('aabb') - end - end -end diff --git a/spec/captcha_spec.rb b/spec/captcha_spec.rb index e594bec..a7a79fc 100644 --- a/spec/captcha_spec.rb +++ b/spec/captcha_spec.rb @@ -1,64 +1,28 @@ require 'spec_helper' -describe RuCaptcha::Captcha do - describe '.random_chars' do +describe RuCaptcha do + describe '.generate' do + it 'should work' do + res = RuCaptcha.generate() + expect(res.length).to eq(2) + expect(res[0].length).to eq(5) + expect(res[1]).not_to eq(nil) + end + end + + describe '.create' do it 'should len equal config.len' do - expect(RuCaptcha::Captcha.random_chars.length).to eq(RuCaptcha.config.len) + res = RuCaptcha.create(0) + expect(res.length).to eq(2) + expect(res[0].length).to eq(5) + expect(res[1]).not_to eq(nil) end - it 'should return 0-9 and lower str' do - expect(RuCaptcha::Captcha.random_chars).to match(/[a-z0-9]/) - end - - it 'should not include [0ol1]' do - 10_000.times do - expect(RuCaptcha::Captcha.random_chars).not_to match(/[0ol1]/i) - end - end - end - - describe '.random_color' do - it 'should return colorful array' do - allow(RuCaptcha.config).to receive(:style).and_return(:colorful) - colors = RuCaptcha::Captcha.random_color - expect(colors.uniq.size >= 2).to eq true - colors1 = RuCaptcha::Captcha.random_color - expect(colors).not_to eq colors1 - end - - it 'should return black color array' do - allow(RuCaptcha.config).to receive(:style).and_return(:black_white) - colors = RuCaptcha::Captcha.random_color - expect(colors.uniq.size).to eq 1 - colors1 = RuCaptcha::Captcha.random_color - expect(colors).not_to eq colors1 - end - end - - describe '.rand_line_top' do - it 'should work' do - expect(RuCaptcha::Captcha.send(:rand_line_top, 1, 24)).to be_a(Integer) - end - end - - describe '.uniq_rgbs_for_each_chars' do - let(:chars) { %w(a b c d e) } - let(:colors) { RuCaptcha::Captcha.send(:uniq_rgbs_for_each_chars, chars) } - - it 'should work' do - expect(colors.length).to eq chars.length - expect(colors[0].length).to eq 3 - end - - it 'Be sure the color not same as preview color' do - pre_rgb = nil - colors.each do |rgb| - if pre_rgb - same = rgb.index(rgb.min) == pre_rgb.index(rgb.min) && rgb.index(rgb.max) == pre_rgb.index(pre_rgb.max) - expect(same).not_to eq true - end - pre_rgb = rgb - end + it 'should work with color style' do + res = RuCaptcha.create(1) + expect(res.length).to eq(2) + expect(res[0].length).to eq(5) + expect(res[1]).not_to eq(nil) end end end diff --git a/spec/configure_spec.rb b/spec/configure_spec.rb index 90c9e50..fc5dd75 100644 --- a/spec/configure_spec.rb +++ b/spec/configure_spec.rb @@ -3,9 +3,6 @@ require 'spec_helper' describe RuCaptcha do describe 'normal' do it 'should read right config with spec_helper set' do - expect(RuCaptcha.config.len).to eq(2) - expect(RuCaptcha.config.font_size).to eq(48) - expect(RuCaptcha.config.implode).to eq(0.111) expect(RuCaptcha.config.expires_in).to eq(2.minutes) end end diff --git a/spec/controller_helpers_spec.rb b/spec/controller_helpers_spec.rb index fd43266..995c403 100644 --- a/spec/controller_helpers_spec.rb +++ b/spec/controller_helpers_spec.rb @@ -37,9 +37,9 @@ describe RuCaptcha do describe '.generate_rucaptcha' do it 'should work' do - expect(RuCaptcha::Captcha).to receive(:random_chars).and_return('abcd') - expect(simple.generate_rucaptcha).not_to be_nil - expect(simple.custom_session[:code]).to eq('abcd') + allow(RuCaptcha).to receive(:create).and_return(['abcde', 'fake image data']) + expect(simple.generate_rucaptcha).to eq 'fake image data' + expect(simple.custom_session[:code]).to eq('abcde') end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0e13a35..f53d402 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -21,8 +21,5 @@ module Rails end RuCaptcha.configure do - self.len = 2 - self.font_size = 48 - self.implode = 0.111 self.cache_store = :mem_cache_store end diff --git a/test b/test new file mode 100755 index 0000000..39a9f4d --- /dev/null +++ b/test @@ -0,0 +1,2 @@ +rake clean && rake compile > /dev/null 2& > /dev/null +rake preview > /tmp/rucaptcha-test.gif && open /tmp/rucaptcha-test.gif \ No newline at end of file