zucchini-ios 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. data/README.md +51 -0
  2. data/bin/zucchini +19 -0
  3. data/lib/config.rb +51 -0
  4. data/lib/feature.rb +87 -0
  5. data/lib/generator.rb +18 -0
  6. data/lib/report/css/zucchini.report.css +239 -0
  7. data/lib/report/js/jquery.effects.core.js +31 -0
  8. data/lib/report/js/jquery.js +4 -0
  9. data/lib/report/js/jquery.ui.core.js +18 -0
  10. data/lib/report/js/zucchini.report.js +59 -0
  11. data/lib/report/template.erb +47 -0
  12. data/lib/report/view.rb +16 -0
  13. data/lib/report.rb +30 -0
  14. data/lib/runner.rb +67 -0
  15. data/lib/screenshot.rb +82 -0
  16. data/lib/uia/base.coffee +63 -0
  17. data/lib/uia/screen.coffee +21 -0
  18. data/lib/version.rb +3 -0
  19. data/spec/lib/config_spec.rb +25 -0
  20. data/spec/lib/generator_spec.rb +27 -0
  21. data/spec/lib/report_spec.rb +34 -0
  22. data/spec/lib/runner_spec.rb +52 -0
  23. data/spec/lib/screenshot_spec.rb +73 -0
  24. data/spec/sample_setup/feature_one/feature.zucchini +1 -0
  25. data/spec/sample_setup/feature_one/masks/retina_ios5/06_sign up_spinner.png +0 -0
  26. data/spec/sample_setup/feature_one/reference/retina_ios5/06_sign up_spinner.png +0 -0
  27. data/spec/sample_setup/feature_one/reference/retina_ios5/06_sign up_spinner_error.png +0 -0
  28. data/spec/sample_setup/feature_one/run_data/Run 1/06_sign up_spinner.png +0 -0
  29. data/spec/sample_setup/feature_two/feature.zucchini +1 -0
  30. data/spec/sample_setup/feature_two/masks/retina_ios5/06_sign up_spinner.png +0 -0
  31. data/spec/sample_setup/feature_two/reference/retina_ios5/06_sign up_spinner.png +0 -0
  32. data/spec/sample_setup/feature_two/reference/retina_ios5/06_sign up_spinner_error.png +0 -0
  33. data/spec/sample_setup/feature_two/run_data/Run 1/06_sign up_spinner.png +0 -0
  34. data/spec/sample_setup/support/config.yml +13 -0
  35. data/spec/sample_setup/support/masks/retina_ios5.png +0 -0
  36. data/spec/sample_setup/support/screens/splash.coffee +8 -0
  37. data/spec/spec_helper.rb +16 -0
  38. data/templates/feature/feature.zucchini +6 -0
  39. data/templates/feature/masks/retina_ios5/.gitkeep +0 -0
  40. data/templates/feature/pending/retina_ios5/.gitkeep +0 -0
  41. data/templates/feature/reference/retina_ios5/.gitkeep +0 -0
  42. data/templates/feature/run_data/.gitignore +5 -0
  43. data/templates/feature/setup.rb +10 -0
  44. data/templates/project/features/support/config.yml +13 -0
  45. data/templates/project/features/support/masks/ipad_ios5.png +0 -0
  46. data/templates/project/features/support/masks/low_ios4.png +0 -0
  47. data/templates/project/features/support/masks/retina_ios5.png +0 -0
  48. data/templates/project/features/support/screens/welcome.coffee +13 -0
  49. data/zucchini.gemspec +24 -0
  50. metadata +155 -0
data/README.md ADDED
@@ -0,0 +1,51 @@
1
+ Pre-requisites
2
+ --------------
3
+ 1. XCode 4.2
4
+ 2. A few command line tools:
5
+
6
+ ```
7
+ brew update && brew install imagemagick && brew install coffee-script
8
+ ```
9
+
10
+ Start using Zucchini
11
+ ----------------------
12
+ ```
13
+ gem install zucchini-ios
14
+ ```
15
+
16
+ Using Zucchini doesn't involve making any modifications to your application code.
17
+ You might as well keep your Zucchini tests in a separate project.
18
+
19
+ Start by creating a project scaffold:
20
+
21
+ ```
22
+ zucchini generate --project /path/to/my_project
23
+ ```
24
+
25
+ Create a feature scaffold for your first feature:
26
+
27
+ ```
28
+ zucchini generate --feature /path/to/my_project/features/my_feature
29
+ ```
30
+
31
+ Add your device to features/support/config.yml.
32
+
33
+ The [udidetect](https://github.com/vaskas/udidetect) utility comes in handy if you plan to add devices from time to time: `udidetect -z`.
34
+
35
+ Start hacking by modifying features/my_feature/feature.zucchini and features/support/screens/welcome.coffee.
36
+
37
+ Alternatively, check out the [zucchini-demo](https://github.com/rajbeniwal/zucchini-demo) project featuring an easy to explore Zucchini setup around Apple's CoreDataBooks sample.
38
+
39
+ Running a feature on the device
40
+ --------------------------------
41
+ ```
42
+ ZUCCHINI_DEVICE="My Device" zucchini run /path/to/my_feature
43
+ ```
44
+
45
+ See also
46
+ ---------
47
+ ```
48
+ zucchini --help
49
+ zucchini run --help
50
+ zucchini generate --help
51
+ ```
data/bin/zucchini ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'clamp'
4
+ require 'fileutils'
5
+
6
+ $LOAD_PATH << File.expand_path("#{File.dirname(__FILE__)}/..")
7
+ require 'lib/config'
8
+ require 'lib/screenshot'
9
+ require 'lib/report'
10
+ require 'lib/feature'
11
+ require 'lib/runner'
12
+ require 'lib/generator'
13
+
14
+ class Zucchini::App < Clamp::Command
15
+ subcommand "generate", "Generate a project scaffold", Zucchini::Generator
16
+ subcommand "run", "Run zucchini", Zucchini::Runner
17
+ end
18
+
19
+ Zucchini::App.run
data/lib/config.rb ADDED
@@ -0,0 +1,51 @@
1
+ require 'yaml'
2
+
3
+ module Zucchini
4
+ class Config
5
+
6
+ def self.base_path
7
+ @@base_path
8
+ end
9
+
10
+ def self.base_path=(base_path)
11
+ @@base_path = base_path
12
+ @@config = YAML::load_file("#{base_path}/support/config.yml")
13
+ end
14
+
15
+ def self.app
16
+ @@config['app']
17
+ end
18
+
19
+ def self.template
20
+ @@config['template']
21
+ end
22
+
23
+ def self.resolution_name(dimension)
24
+ @@config['resolutions'][dimension.to_i]
25
+ end
26
+
27
+ def self.devices
28
+ @@config['devices']
29
+ end
30
+
31
+ def self.device(device_name)
32
+ raise "Device not listed in config.yml" unless (device = devices[device_name])
33
+ {
34
+ :name => device_name,
35
+ :udid => device['UDID'],
36
+ :screen => device['screen']
37
+ }
38
+ end
39
+
40
+ def self.server(server_name)
41
+ @@config['servers'][server_name]
42
+ end
43
+
44
+ def self.url(server_name, href="")
45
+ server_config = server(server_name)
46
+ port = server_config['port'] ? ":#{server_config['port']}" : ""
47
+
48
+ "http://#{server_config['host']}#{port}#{href}"
49
+ end
50
+ end
51
+ end
data/lib/feature.rb ADDED
@@ -0,0 +1,87 @@
1
+ class Zucchini::Feature
2
+ attr_accessor :path
3
+ attr_accessor :device
4
+ attr_accessor :stats
5
+
6
+ attr_reader :succeeded
7
+ attr_reader :name
8
+
9
+ def initialize(path)
10
+ @path = path
11
+ @device = nil
12
+ @succeeded = false
13
+ @name = File.basename(path)
14
+ end
15
+
16
+ def run_data_path
17
+ "#{@path}/run_data"
18
+ end
19
+
20
+ def unmatched_pending_screenshots
21
+ Dir.glob("#{@path}/pending/#{@device[:screen]}/[^0-9]*.png").map do |file|
22
+ screenshot = Zucchini::Screenshot.new(file, nil, true)
23
+ screenshot.test_path = File.expand_path(file)
24
+ screenshot.diff = [:pending, "unmatched"]
25
+ screenshot
26
+ end
27
+ end
28
+
29
+ def screenshots
30
+ @screenshots ||= Dir.glob("#{run_data_path}/Run\ 1/*.png").map do |file|
31
+ screenshot = Zucchini::Screenshot.new(file, @device)
32
+ screenshot.mask
33
+ screenshot.compare
34
+ screenshot
35
+ end + unmatched_pending_screenshots
36
+ end
37
+
38
+ def stats
39
+ @stats ||= screenshots.inject({:passed => [], :failed => [], :pending => []}) do |stats, s|
40
+ stats[s.diff[0]] << s
41
+ stats
42
+ end
43
+ end
44
+
45
+ def compile_js
46
+ zucchini_base_path = File.expand_path("#{File.dirname(__FILE__)}/..")
47
+
48
+ feature_text = File.open("#{@path}/feature.zucchini").read.gsub(/#.+\n/,"").gsub(/\n/, "\\n")
49
+ File.open("#{run_data_path}/feature.coffee", "w+") { |f| f.write("Zucchini.run('#{feature_text}')") }
50
+ `coffee -o #{run_data_path} -j #{run_data_path}/feature.js -c #{zucchini_base_path}/lib/uia #{@path}/../support/screens #{run_data_path}/feature.coffee`
51
+ end
52
+
53
+ def collect
54
+ with_setup do
55
+ `rm -rf #{run_data_path}/*`
56
+ compile_js
57
+
58
+ begin
59
+ out = `instruments -w #{@device[:udid]} -t #{Zucchini::Config.template} #{Zucchini::Config.app} -e UIASCRIPT #{run_data_path}/feature.js -e UIARESULTSPATH #{run_data_path} 2>&1`
60
+ puts out
61
+ # Hack. Instruments don't issue error return codes when JS exceptions occur
62
+ raise "Instruments run error" if (out.match /JavaScript error/) || (out.match /Instruments\ .{0,5}\ Error\ :/ )
63
+ ensure
64
+ `rm -rf instrumentscli*.trace`
65
+ end
66
+ end
67
+ end
68
+
69
+ def compare
70
+ `rm -rf #{run_data_path}/Diff/*`
71
+ @succeeded = (stats[:failed].length == 0)
72
+ end
73
+
74
+ def with_setup
75
+ setup = "#{@path}/setup.rb"
76
+ if File.exists?(setup)
77
+ require setup
78
+ begin
79
+ Setup.before { yield }
80
+ ensure
81
+ Setup.after
82
+ end
83
+ else
84
+ yield
85
+ end
86
+ end
87
+ end
data/lib/generator.rb ADDED
@@ -0,0 +1,18 @@
1
+ class Zucchini::Generator < Clamp::Command
2
+ option %W(-p --project), :flag, "Generate a project"
3
+ option %W(-f --feature), :flag, "Generate a feature"
4
+
5
+ parameter "PATH", "Path"
6
+
7
+ def templates_path
8
+ File.expand_path("#{File.dirname(__FILE__)}/../templates")
9
+ end
10
+
11
+ def execute
12
+ if project?
13
+ FileUtils.mkdir_p(path)
14
+ FileUtils.cp_r("#{templates_path}/project/.", path)
15
+ elsif feature? then FileUtils.cp_r("#{templates_path}/feature", path)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,239 @@
1
+ html {
2
+ font-family: Myriad Pro, sans-serif;
3
+ }
4
+ body {
5
+ margin: 0;
6
+ }
7
+ tr {
8
+ text-align: center;
9
+ }
10
+ td {
11
+ padding: 2px;
12
+ }
13
+ dl {
14
+ -webkit-margin-before: 0;
15
+ }
16
+ dd {
17
+ -webkit-margin-start: 0;
18
+ }
19
+ h1 {
20
+ margin: 16px;
21
+ font-weight: normal;
22
+ font-size: 24px;
23
+ }
24
+ h1 .time {
25
+ margin-left: 10px;
26
+ opacity: 0.5;
27
+ }
28
+ h3 {
29
+ margin: 0 0 6px 4px;
30
+ font-size: 24px;
31
+ width: 763px;
32
+ padding: 0;
33
+ float: left;
34
+ text-shadow: 1px 1px 1px white;
35
+ }
36
+ .indicators {
37
+ font-size: 12px;
38
+ width: 92px;
39
+ float: left;
40
+ margin: 5px 28px 5px 0;
41
+ -webkit-transition: all 0.1s ease-in-out;
42
+ }
43
+ .indicators div {
44
+ border-radius: 8px;
45
+ padding: 3px 8px;
46
+ margin-right: 5px;
47
+ float: right;
48
+ color: #FFF;
49
+ opacity: 0.8;
50
+ height: 11px;
51
+ line-height: 11px;
52
+ font-weight: bold;
53
+ }
54
+ .indicators div:hover {
55
+ -webkit-transition:opacity 0.3s ease-in-out;
56
+ }
57
+ .indicators .passed {
58
+ background: #65C400;
59
+ }
60
+ .indicators .failed {
61
+ background: #C20000;
62
+ }
63
+ .indicators .pending {
64
+ background: #F9E934;
65
+ color: #000;
66
+ }
67
+ .feature {
68
+ padding: 10px 9px 4px 9px;
69
+ border-radius: 5px;
70
+ width: 1012px;
71
+ margin: 15px 15px 24px 15px;
72
+ box-shadow: 0 0 4px rgba(0,0,0,0.2);
73
+ }
74
+ .ci .feature {
75
+ display: none;
76
+ }
77
+ .ci .first.feature {
78
+ display: block;
79
+ }
80
+ .buttons {
81
+ float: left;
82
+ width: 125px;
83
+ display: block;
84
+ }
85
+ .ci .buttons {
86
+ display: none;
87
+ }
88
+ .buttons a {
89
+ text-align: center;
90
+ width: 70px;
91
+ color: #484848;
92
+ text-decoration: none;
93
+ text-shadow: 0 1px 0 white;
94
+ font: bold 12px Helvetica, Arial, sans-serif;
95
+ margin-bottom: 6px;
96
+ line-height: 26px;
97
+ height: 25px;
98
+ display: block;
99
+ float: left;
100
+ padding: 0 5px;
101
+ background: -webkit-linear-gradient(top, #F4F4F4, #ECECEC);
102
+ border: solid 1px #D4D4D4;
103
+ border-radius: 5px;
104
+ box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
105
+ -webkit-transition: border-color .218s;
106
+ cursor: pointer;
107
+ }
108
+ .buttons a.left {
109
+ border-radius: 5px 0 0 5px;
110
+ width: 50px;
111
+ float: left;
112
+ margin: 0;
113
+ }
114
+ .buttons a.right {
115
+ border-radius: 0 5px 5px 0;
116
+ width: 50px;
117
+ float: left;
118
+ position: relative;
119
+ left: -1px;
120
+ margin: 0;
121
+ }
122
+ .buttons a:hover {
123
+ border: solid 1px #7f7f7f;
124
+ color: #282828;
125
+ background: -webkit-linear-gradient(top, #ffffff, #dfdfdf);
126
+ }
127
+ .buttons a:active {
128
+ border: solid 1px #7f7f7f;
129
+ background: #d0d0d0;
130
+ background: -webkit-gradient(linear, left top, left bottom, from(#a8a8a8), color-stop(0.15, #c6c6c6), to(#d8d8d8));
131
+ background: -webkit-linear-gradient(top, #a8a8a8, #c6c6c6 15%, #d8d8d8);
132
+ }
133
+
134
+ .screen {
135
+ -webkit-transition:all 0.2s ease-in-out;
136
+ width: 990px;
137
+ height: 15px;
138
+ padding: 5px 0 5px 9px;
139
+ margin-bottom: 6px;
140
+ border-radius: 5px;
141
+ cursor: pointer;
142
+ overflow: hidden;
143
+ }
144
+ .screen.passed {
145
+ color: #65C400;
146
+ background-color: #DBFFB4;
147
+ border: 1px #65C400 solid;
148
+ border-left: 10px #65C400 solid;
149
+ }
150
+ .screen.passed img {
151
+ box-shadow: 0px 0px 4px #65C400;
152
+ }
153
+ .screen.failed {
154
+ color: #C20000;
155
+ background-color: #FFD6D6;
156
+ border: 1px #C20000 solid;
157
+ border-left: 10px #C20000 solid;
158
+ }
159
+ .screen.failed img {
160
+ box-shadow: 0px 0px 4px #C20000;
161
+ }
162
+ .screen.pending {
163
+ color: #F2CF32;
164
+ background-color: #FFFDBC;
165
+ border: 1px solid #F9E934;
166
+ border-left: 10px solid #F9E934;
167
+ }
168
+ .screen.pending img {
169
+ box-shadow: 0px 0px 4px #F9E934;
170
+ }
171
+ .screen dt {
172
+ color: #000;
173
+ font-size: 13px;
174
+ line-height: 17px;
175
+ margin: 0;
176
+ font-weight: normal;
177
+ }
178
+ .ci .screen dt {
179
+ position: relative;
180
+ z-index: 2;
181
+ }
182
+ .screen dd {
183
+ float: left;
184
+ margin-right: 10px;
185
+ -webkit-transition:all 0.3s ease-in-out;
186
+ opacity: 0;
187
+ position: relative;
188
+ top: -30px;
189
+ }
190
+ .screen dd.hidden {
191
+ visibility: hidden;
192
+ }
193
+ .screen.expanded, .ci .screen {
194
+ -webkit-transition:all 0.2s ease-in-out;
195
+ height: 510px;
196
+ }
197
+ .screen.expanded dd, .ci .screen dd {
198
+ opacity: 1.0;
199
+ -webkit-transition:all 0.3s ease-in-out;
200
+ }
201
+ .screen p {
202
+ margin-bottom: -3px;
203
+ padding: 5px;
204
+ font-size: 13px;
205
+ text-align: center;
206
+ font-weight: bold;
207
+ background-color: rgba(255, 255, 255, 0.5);;
208
+ border-radius: 5px;
209
+ opacity: 0.0;
210
+ position: relative;
211
+ z-index: 0;
212
+ }
213
+ .screen dd:hover p {
214
+ opacity: 1.0;
215
+ }
216
+ .ci .screen dd p {
217
+ opacity: 1.0;
218
+ background: transparent;
219
+ }
220
+ .screen img {
221
+ width: 320px;
222
+ height: 480px;
223
+ position: relative;
224
+ }
225
+ .ci .viewport {
226
+ width: 1018px;
227
+ height: 530px;
228
+ overflow: scroll;
229
+ }
230
+ .ci .surface {
231
+ height: 530px;
232
+ width: 100000px;
233
+ position: relative;
234
+ }
235
+ .ci .surface .screen {
236
+ float: left;
237
+ margin-right: 10px;
238
+ position: relative;
239
+ }
@@ -0,0 +1,31 @@
1
+ /*
2
+ * jQuery UI Effects 1.8.16
3
+ *
4
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
5
+ * Dual licensed under the MIT or GPL Version 2 licenses.
6
+ * http://jquery.org/license
7
+ *
8
+ * http://docs.jquery.com/UI/Effects/
9
+ */
10
+ jQuery.effects||function(f,j){function m(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1],
11
+ 16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return n.transparent;return n[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return m(b)}function o(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,
12
+ a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function p(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d=
13
+ a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function l(c){if(!c||typeof c==="number"||f.fx.speeds[c])return true;if(typeof c==="string"&&!f.effects[c])return true;return false}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor",
14
+ "borderTopColor","borderColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=m(b.end);b.colorInit=true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var n={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,
15
+ 0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,
16
+ 211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},q=["add","remove","toggle"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b,
17
+ d){if(f.isFunction(b)){d=b;b=null}return this.queue(function(){var e=f(this),g=e.attr("style")||" ",h=p(o.call(this)),r,v=e.attr("class");f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});r=p(o.call(this));e.attr("class",v);e.animate(u(h,r),{queue:false,duration:a,easing:b,complete:function(){f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments);f.dequeue(this)}})})};
18
+ f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this,
19
+ [{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.16",save:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.data("ec.storage."+a[b],c[0].style[a[b]])},restore:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.css(a[b],c.data("ec.storage."+a[b]))},setMode:function(c,a){if(a=="toggle")a=c.is(":hidden")?"show":"hide";return a},getBaseline:function(c,a){var b;switch(c[0]){case "top":b=
20
+ 0;break;case "middle":b=0.5;break;case "bottom":b=1;break;default:b=c[0]/a.height}switch(c[1]){case "left":c=0;break;case "center":c=0.5;break;case "right":c=1;break;default:c=c[1]/a.width}return{x:c,y:b}},createWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent();var a={width:c.outerWidth(true),height:c.outerHeight(true),"float":c.css("float")},b=f("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),
21
+ d=document.activeElement;c.wrap(b);if(c[0]===d||f.contains(c[0],d))f(d).focus();b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(e,g){a[g]=c.css(g);if(isNaN(parseInt(a[g],10)))a[g]="auto"});c.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return b.css(a).show()},removeWrapper:function(c){var a,b=document.activeElement;
22
+ if(c.parent().is(".ui-effects-wrapper")){a=c.parent().replaceWith(c);if(c[0]===b||f.contains(c[0],b))f(b).focus();return a}return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)});
23
+ return d.call(this,b)},_show:f.fn.show,show:function(c){if(l(c))return this._show.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(l(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(l(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this,
24
+ arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/
25
+ 2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b,
26
+ d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c,
27
+ a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b,
28
+ d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return-(h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g))+b},easeOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*a)*Math.sin((a*e-c)*2*Math.PI/g)+d+b},easeInOutElastic:function(c,a,b,d,e){c=1.70158;var g=
29
+ 0,h=d;if(a==0)return b;if((a/=e/2)==2)return b+d;g||(g=e*0.3*1.5);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);if(a<1)return-0.5*h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)+b;return h*Math.pow(2,-10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)*0.5+d+b},easeInBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*(a/=e)*a*((g+1)*a-g)+b},easeOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*((a=a/e-1)*a*((g+1)*a+g)+1)+b},easeInOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;
30
+ if((a/=e/2)<1)return d/2*a*a*(((g*=1.525)+1)*a-g)+b;return d/2*((a-=2)*a*(((g*=1.525)+1)*a+g)+2)+b},easeInBounce:function(c,a,b,d,e){return d-f.easing.easeOutBounce(c,e-a,0,d,e)+b},easeOutBounce:function(c,a,b,d,e){return(a/=e)<1/2.75?d*7.5625*a*a+b:a<2/2.75?d*(7.5625*(a-=1.5/2.75)*a+0.75)+b:a<2.5/2.75?d*(7.5625*(a-=2.25/2.75)*a+0.9375)+b:d*(7.5625*(a-=2.625/2.75)*a+0.984375)+b},easeInOutBounce:function(c,a,b,d,e){if(a<e/2)return f.easing.easeInBounce(c,a*2,0,d,e)*0.5+b;return f.easing.easeOutBounce(c,
31
+ a*2-e,0,d,e)*0.5+d*0.5+b}})}(jQuery);