zucchini-ios 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
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);