zepto_rails 1.0
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.
- data/.gitignore +8 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +91 -0
- data/MIT-LICENSE +20 -0
- data/README.md +46 -0
- data/Rakefile +27 -0
- data/lib/zepto/rails.rb +2 -0
- data/lib/zepto/rails/engine.rb +6 -0
- data/lib/zepto/rails/version.rb +5 -0
- data/lib/zepto_rails.rb +1 -0
- data/vendor/assets/javascripts/zepto.js +7 -0
- data/vendor/assets/javascripts/zepto/ajax.js +314 -0
- data/vendor/assets/javascripts/zepto/all.js +14 -0
- data/vendor/assets/javascripts/zepto/assets.js +21 -0
- data/vendor/assets/javascripts/zepto/data.js +67 -0
- data/vendor/assets/javascripts/zepto/detect.js +55 -0
- data/vendor/assets/javascripts/zepto/event.js +248 -0
- data/vendor/assets/javascripts/zepto/form.js +40 -0
- data/vendor/assets/javascripts/zepto/fx.js +102 -0
- data/vendor/assets/javascripts/zepto/fx_methods.js +71 -0
- data/vendor/assets/javascripts/zepto/gesture.js +35 -0
- data/vendor/assets/javascripts/zepto/polyfill.js +36 -0
- data/vendor/assets/javascripts/zepto/selector.js +81 -0
- data/vendor/assets/javascripts/zepto/stack.js +22 -0
- data/vendor/assets/javascripts/zepto/touch.js +115 -0
- data/vendor/assets/javascripts/zepto/zepto.js +790 -0
- data/zepto_rails.gemspec +21 -0
- metadata +110 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
//= require zepto/polyfill
|
2
|
+
//= require zepto/zepto
|
3
|
+
//= require zepto/event
|
4
|
+
//= require zepto/detect
|
5
|
+
//= require zepto/fx
|
6
|
+
//= require zepto/fx_methods
|
7
|
+
//= require zepto/ajax
|
8
|
+
//= require zepto/form
|
9
|
+
//= require zepto/assets
|
10
|
+
//= require zepto/data
|
11
|
+
//= require zepto/selector
|
12
|
+
//= require zepto/touch
|
13
|
+
//= require zepto/gesture
|
14
|
+
//= require zepto/stack
|
@@ -0,0 +1,21 @@
|
|
1
|
+
// Zepto.js
|
2
|
+
// (c) 2010-2012 Thomas Fuchs
|
3
|
+
// Zepto.js may be freely distributed under the MIT license.
|
4
|
+
|
5
|
+
;(function($){
|
6
|
+
var cache = [], timeout
|
7
|
+
|
8
|
+
$.fn.remove = function(){
|
9
|
+
return this.each(function(){
|
10
|
+
if(this.parentNode){
|
11
|
+
if(this.tagName === 'IMG'){
|
12
|
+
cache.push(this)
|
13
|
+
this.src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='
|
14
|
+
if (timeout) clearTimeout(timeout)
|
15
|
+
timeout = setTimeout(function(){ cache = [] }, 60000)
|
16
|
+
}
|
17
|
+
this.parentNode.removeChild(this)
|
18
|
+
}
|
19
|
+
})
|
20
|
+
}
|
21
|
+
})(Zepto)
|
@@ -0,0 +1,67 @@
|
|
1
|
+
// Zepto.js
|
2
|
+
// (c) 2010-2012 Thomas Fuchs
|
3
|
+
// Zepto.js may be freely distributed under the MIT license.
|
4
|
+
|
5
|
+
// The following code is heavily inspired by jQuery's $.fn.data()
|
6
|
+
|
7
|
+
;(function($) {
|
8
|
+
var data = {}, dataAttr = $.fn.data, camelize = $.camelCase,
|
9
|
+
exp = $.expando = 'Zepto' + (+new Date())
|
10
|
+
|
11
|
+
// Get value from node:
|
12
|
+
// 1. first try key as given,
|
13
|
+
// 2. then try camelized key,
|
14
|
+
// 3. fall back to reading "data-*" attribute.
|
15
|
+
function getData(node, name) {
|
16
|
+
var id = node[exp], store = id && data[id]
|
17
|
+
if (name === undefined) return store || setData(node)
|
18
|
+
else {
|
19
|
+
if (store) {
|
20
|
+
if (name in store) return store[name]
|
21
|
+
var camelName = camelize(name)
|
22
|
+
if (camelName in store) return store[camelName]
|
23
|
+
}
|
24
|
+
return dataAttr.call($(node), name)
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
// Store value under camelized key on node
|
29
|
+
function setData(node, name, value) {
|
30
|
+
var id = node[exp] || (node[exp] = ++$.uuid),
|
31
|
+
store = data[id] || (data[id] = attributeData(node))
|
32
|
+
if (name !== undefined) store[camelize(name)] = value
|
33
|
+
return store
|
34
|
+
}
|
35
|
+
|
36
|
+
// Read all "data-*" attributes from a node
|
37
|
+
function attributeData(node) {
|
38
|
+
var store = {}
|
39
|
+
$.each(node.attributes, function(i, attr){
|
40
|
+
if (attr.name.indexOf('data-') == 0)
|
41
|
+
store[camelize(attr.name.replace('data-', ''))] =
|
42
|
+
$.zepto.deserializeValue(attr.value)
|
43
|
+
})
|
44
|
+
return store
|
45
|
+
}
|
46
|
+
|
47
|
+
$.fn.data = function(name, value) {
|
48
|
+
return value === undefined ?
|
49
|
+
// set multiple values via object
|
50
|
+
$.isPlainObject(name) ?
|
51
|
+
this.each(function(i, node){
|
52
|
+
$.each(name, function(key, value){ setData(node, key, value) })
|
53
|
+
}) :
|
54
|
+
// get value from first element
|
55
|
+
this.length == 0 ? undefined : getData(this[0], name) :
|
56
|
+
// set value on all elements
|
57
|
+
this.each(function(){ setData(this, name, value) })
|
58
|
+
}
|
59
|
+
|
60
|
+
$.fn.removeData = function(names) {
|
61
|
+
if (typeof names == 'string') names = names.split(/\s+/)
|
62
|
+
return this.each(function(){
|
63
|
+
var id = this[exp], store = id && data[id]
|
64
|
+
if (store) $.each(names, function(){ delete store[camelize(this)] })
|
65
|
+
})
|
66
|
+
}
|
67
|
+
})(Zepto)
|
@@ -0,0 +1,55 @@
|
|
1
|
+
// Zepto.js
|
2
|
+
// (c) 2010-2012 Thomas Fuchs
|
3
|
+
// Zepto.js may be freely distributed under the MIT license.
|
4
|
+
|
5
|
+
;(function($){
|
6
|
+
function detect(ua){
|
7
|
+
var os = this.os = {}, browser = this.browser = {},
|
8
|
+
webkit = ua.match(/WebKit\/([\d.]+)/),
|
9
|
+
android = ua.match(/(Android)\s+([\d.]+)/),
|
10
|
+
ipad = ua.match(/(iPad).*OS\s([\d_]+)/),
|
11
|
+
iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/),
|
12
|
+
webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/),
|
13
|
+
touchpad = webos && ua.match(/TouchPad/),
|
14
|
+
kindle = ua.match(/Kindle\/([\d.]+)/),
|
15
|
+
silk = ua.match(/Silk\/([\d._]+)/),
|
16
|
+
blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/),
|
17
|
+
bb10 = ua.match(/(BB10).*Version\/([\d.]+)/),
|
18
|
+
rimtabletos = ua.match(/(RIM\sTablet\sOS)\s([\d.]+)/),
|
19
|
+
playbook = ua.match(/PlayBook/),
|
20
|
+
chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/),
|
21
|
+
firefox = ua.match(/Firefox\/([\d.]+)/)
|
22
|
+
|
23
|
+
// Todo: clean this up with a better OS/browser seperation:
|
24
|
+
// - discern (more) between multiple browsers on android
|
25
|
+
// - decide if kindle fire in silk mode is android or not
|
26
|
+
// - Firefox on Android doesn't specify the Android version
|
27
|
+
// - possibly devide in os, device and browser hashes
|
28
|
+
|
29
|
+
if (browser.webkit = !!webkit) browser.version = webkit[1]
|
30
|
+
|
31
|
+
if (android) os.android = true, os.version = android[2]
|
32
|
+
if (iphone) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.')
|
33
|
+
if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.')
|
34
|
+
if (webos) os.webos = true, os.version = webos[2]
|
35
|
+
if (touchpad) os.touchpad = true
|
36
|
+
if (blackberry) os.blackberry = true, os.version = blackberry[2]
|
37
|
+
if (bb10) os.bb10 = true, os.version = bb10[2]
|
38
|
+
if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2]
|
39
|
+
if (playbook) browser.playbook = true
|
40
|
+
if (kindle) os.kindle = true, os.version = kindle[1]
|
41
|
+
if (silk) browser.silk = true, browser.version = silk[1]
|
42
|
+
if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true
|
43
|
+
if (chrome) browser.chrome = true, browser.version = chrome[1]
|
44
|
+
if (firefox) browser.firefox = true, browser.version = firefox[1]
|
45
|
+
|
46
|
+
os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) || (firefox && ua.match(/Tablet/)))
|
47
|
+
os.phone = !!(!os.tablet && (android || iphone || webos || blackberry || bb10 ||
|
48
|
+
(chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\/([\d.]+)/)) || (firefox && ua.match(/Mobile/))))
|
49
|
+
}
|
50
|
+
|
51
|
+
detect.call($, navigator.userAgent)
|
52
|
+
// make available to unit tests
|
53
|
+
$.__detect = detect
|
54
|
+
|
55
|
+
})(Zepto)
|
@@ -0,0 +1,248 @@
|
|
1
|
+
// Zepto.js
|
2
|
+
// (c) 2010-2012 Thomas Fuchs
|
3
|
+
// Zepto.js may be freely distributed under the MIT license.
|
4
|
+
|
5
|
+
;(function($){
|
6
|
+
var $$ = $.zepto.qsa, handlers = {}, _zid = 1, specialEvents={},
|
7
|
+
hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' }
|
8
|
+
|
9
|
+
specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents'
|
10
|
+
|
11
|
+
function zid(element) {
|
12
|
+
return element._zid || (element._zid = _zid++)
|
13
|
+
}
|
14
|
+
function findHandlers(element, event, fn, selector) {
|
15
|
+
event = parse(event)
|
16
|
+
if (event.ns) var matcher = matcherFor(event.ns)
|
17
|
+
return (handlers[zid(element)] || []).filter(function(handler) {
|
18
|
+
return handler
|
19
|
+
&& (!event.e || handler.e == event.e)
|
20
|
+
&& (!event.ns || matcher.test(handler.ns))
|
21
|
+
&& (!fn || zid(handler.fn) === zid(fn))
|
22
|
+
&& (!selector || handler.sel == selector)
|
23
|
+
})
|
24
|
+
}
|
25
|
+
function parse(event) {
|
26
|
+
var parts = ('' + event).split('.')
|
27
|
+
return {e: parts[0], ns: parts.slice(1).sort().join(' ')}
|
28
|
+
}
|
29
|
+
function matcherFor(ns) {
|
30
|
+
return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)')
|
31
|
+
}
|
32
|
+
|
33
|
+
function eachEvent(events, fn, iterator){
|
34
|
+
if ($.type(events) != "string") $.each(events, iterator)
|
35
|
+
else events.split(/\s/).forEach(function(type){ iterator(type, fn) })
|
36
|
+
}
|
37
|
+
|
38
|
+
function eventCapture(handler, captureSetting) {
|
39
|
+
return handler.del &&
|
40
|
+
(handler.e == 'focus' || handler.e == 'blur') ||
|
41
|
+
!!captureSetting
|
42
|
+
}
|
43
|
+
|
44
|
+
function realEvent(type) {
|
45
|
+
return hover[type] || type
|
46
|
+
}
|
47
|
+
|
48
|
+
function add(element, events, fn, selector, getDelegate, capture){
|
49
|
+
var id = zid(element), set = (handlers[id] || (handlers[id] = []))
|
50
|
+
eachEvent(events, fn, function(event, fn){
|
51
|
+
var handler = parse(event)
|
52
|
+
handler.fn = fn
|
53
|
+
handler.sel = selector
|
54
|
+
// emulate mouseenter, mouseleave
|
55
|
+
if (handler.e in hover) fn = function(e){
|
56
|
+
var related = e.relatedTarget
|
57
|
+
if (!related || (related !== this && !$.contains(this, related)))
|
58
|
+
return handler.fn.apply(this, arguments)
|
59
|
+
}
|
60
|
+
handler.del = getDelegate && getDelegate(fn, event)
|
61
|
+
var callback = handler.del || fn
|
62
|
+
handler.proxy = function (e) {
|
63
|
+
var result = callback.apply(element, [e].concat(e.data))
|
64
|
+
if (result === false) e.preventDefault(), e.stopPropagation()
|
65
|
+
return result
|
66
|
+
}
|
67
|
+
handler.i = set.length
|
68
|
+
set.push(handler)
|
69
|
+
element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
|
70
|
+
})
|
71
|
+
}
|
72
|
+
function remove(element, events, fn, selector, capture){
|
73
|
+
var id = zid(element)
|
74
|
+
eachEvent(events || '', fn, function(event, fn){
|
75
|
+
findHandlers(element, event, fn, selector).forEach(function(handler){
|
76
|
+
delete handlers[id][handler.i]
|
77
|
+
element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
|
78
|
+
})
|
79
|
+
})
|
80
|
+
}
|
81
|
+
|
82
|
+
$.event = { add: add, remove: remove }
|
83
|
+
|
84
|
+
$.proxy = function(fn, context) {
|
85
|
+
if ($.isFunction(fn)) {
|
86
|
+
var proxyFn = function(){ return fn.apply(context, arguments) }
|
87
|
+
proxyFn._zid = zid(fn)
|
88
|
+
return proxyFn
|
89
|
+
} else if (typeof context == 'string') {
|
90
|
+
return $.proxy(fn[context], fn)
|
91
|
+
} else {
|
92
|
+
throw new TypeError("expected function")
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
$.fn.bind = function(event, callback){
|
97
|
+
return this.each(function(){
|
98
|
+
add(this, event, callback)
|
99
|
+
})
|
100
|
+
}
|
101
|
+
$.fn.unbind = function(event, callback){
|
102
|
+
return this.each(function(){
|
103
|
+
remove(this, event, callback)
|
104
|
+
})
|
105
|
+
}
|
106
|
+
$.fn.one = function(event, callback){
|
107
|
+
return this.each(function(i, element){
|
108
|
+
add(this, event, callback, null, function(fn, type){
|
109
|
+
return function(){
|
110
|
+
var result = fn.apply(element, arguments)
|
111
|
+
remove(element, type, fn)
|
112
|
+
return result
|
113
|
+
}
|
114
|
+
})
|
115
|
+
})
|
116
|
+
}
|
117
|
+
|
118
|
+
var returnTrue = function(){return true},
|
119
|
+
returnFalse = function(){return false},
|
120
|
+
ignoreProperties = /^([A-Z]|layer[XY]$)/,
|
121
|
+
eventMethods = {
|
122
|
+
preventDefault: 'isDefaultPrevented',
|
123
|
+
stopImmediatePropagation: 'isImmediatePropagationStopped',
|
124
|
+
stopPropagation: 'isPropagationStopped'
|
125
|
+
}
|
126
|
+
function createProxy(event) {
|
127
|
+
var key, proxy = { originalEvent: event }
|
128
|
+
for (key in event)
|
129
|
+
if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key]
|
130
|
+
|
131
|
+
$.each(eventMethods, function(name, predicate) {
|
132
|
+
proxy[name] = function(){
|
133
|
+
this[predicate] = returnTrue
|
134
|
+
return event[name].apply(event, arguments)
|
135
|
+
}
|
136
|
+
proxy[predicate] = returnFalse
|
137
|
+
})
|
138
|
+
return proxy
|
139
|
+
}
|
140
|
+
|
141
|
+
// emulates the 'defaultPrevented' property for browsers that have none
|
142
|
+
function fix(event) {
|
143
|
+
if (!('defaultPrevented' in event)) {
|
144
|
+
event.defaultPrevented = false
|
145
|
+
var prevent = event.preventDefault
|
146
|
+
event.preventDefault = function() {
|
147
|
+
this.defaultPrevented = true
|
148
|
+
prevent.call(this)
|
149
|
+
}
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
$.fn.delegate = function(selector, event, callback){
|
154
|
+
return this.each(function(i, element){
|
155
|
+
add(element, event, callback, selector, function(fn){
|
156
|
+
return function(e){
|
157
|
+
var evt, match = $(e.target).closest(selector, element).get(0)
|
158
|
+
if (match) {
|
159
|
+
evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element})
|
160
|
+
return fn.apply(match, [evt].concat([].slice.call(arguments, 1)))
|
161
|
+
}
|
162
|
+
}
|
163
|
+
})
|
164
|
+
})
|
165
|
+
}
|
166
|
+
$.fn.undelegate = function(selector, event, callback){
|
167
|
+
return this.each(function(){
|
168
|
+
remove(this, event, callback, selector)
|
169
|
+
})
|
170
|
+
}
|
171
|
+
|
172
|
+
$.fn.live = function(event, callback){
|
173
|
+
$(document.body).delegate(this.selector, event, callback)
|
174
|
+
return this
|
175
|
+
}
|
176
|
+
$.fn.die = function(event, callback){
|
177
|
+
$(document.body).undelegate(this.selector, event, callback)
|
178
|
+
return this
|
179
|
+
}
|
180
|
+
|
181
|
+
$.fn.on = function(event, selector, callback){
|
182
|
+
return !selector || $.isFunction(selector) ?
|
183
|
+
this.bind(event, selector || callback) : this.delegate(selector, event, callback)
|
184
|
+
}
|
185
|
+
$.fn.off = function(event, selector, callback){
|
186
|
+
return !selector || $.isFunction(selector) ?
|
187
|
+
this.unbind(event, selector || callback) : this.undelegate(selector, event, callback)
|
188
|
+
}
|
189
|
+
|
190
|
+
$.fn.trigger = function(event, data){
|
191
|
+
if (typeof event == 'string' || $.isPlainObject(event)) event = $.Event(event)
|
192
|
+
fix(event)
|
193
|
+
event.data = data
|
194
|
+
return this.each(function(){
|
195
|
+
// items in the collection might not be DOM elements
|
196
|
+
// (todo: possibly support events on plain old objects)
|
197
|
+
if('dispatchEvent' in this) this.dispatchEvent(event)
|
198
|
+
})
|
199
|
+
}
|
200
|
+
|
201
|
+
// triggers event handlers on current element just as if an event occurred,
|
202
|
+
// doesn't trigger an actual event, doesn't bubble
|
203
|
+
$.fn.triggerHandler = function(event, data){
|
204
|
+
var e, result
|
205
|
+
this.each(function(i, element){
|
206
|
+
e = createProxy(typeof event == 'string' ? $.Event(event) : event)
|
207
|
+
e.data = data
|
208
|
+
e.target = element
|
209
|
+
$.each(findHandlers(element, event.type || event), function(i, handler){
|
210
|
+
result = handler.proxy(e)
|
211
|
+
if (e.isImmediatePropagationStopped()) return false
|
212
|
+
})
|
213
|
+
})
|
214
|
+
return result
|
215
|
+
}
|
216
|
+
|
217
|
+
// shortcut methods for `.bind(event, fn)` for each event type
|
218
|
+
;('focusin focusout load resize scroll unload click dblclick '+
|
219
|
+
'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+
|
220
|
+
'change select keydown keypress keyup error').split(' ').forEach(function(event) {
|
221
|
+
$.fn[event] = function(callback) {
|
222
|
+
return callback ?
|
223
|
+
this.bind(event, callback) :
|
224
|
+
this.trigger(event)
|
225
|
+
}
|
226
|
+
})
|
227
|
+
|
228
|
+
;['focus', 'blur'].forEach(function(name) {
|
229
|
+
$.fn[name] = function(callback) {
|
230
|
+
if (callback) this.bind(name, callback)
|
231
|
+
else this.each(function(){
|
232
|
+
try { this[name]() }
|
233
|
+
catch(e) {}
|
234
|
+
})
|
235
|
+
return this
|
236
|
+
}
|
237
|
+
})
|
238
|
+
|
239
|
+
$.Event = function(type, props) {
|
240
|
+
if (typeof type != 'string') props = type, type = props.type
|
241
|
+
var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true
|
242
|
+
if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name])
|
243
|
+
event.initEvent(type, bubbles, true, null, null, null, null, null, null, null, null, null, null, null, null)
|
244
|
+
event.isDefaultPrevented = function(){ return this.defaultPrevented }
|
245
|
+
return event
|
246
|
+
}
|
247
|
+
|
248
|
+
})(Zepto)
|
@@ -0,0 +1,40 @@
|
|
1
|
+
// Zepto.js
|
2
|
+
// (c) 2010-2012 Thomas Fuchs
|
3
|
+
// Zepto.js may be freely distributed under the MIT license.
|
4
|
+
|
5
|
+
;(function ($) {
|
6
|
+
$.fn.serializeArray = function () {
|
7
|
+
var result = [], el
|
8
|
+
$( Array.prototype.slice.call(this.get(0).elements) ).each(function () {
|
9
|
+
el = $(this)
|
10
|
+
var type = el.attr('type')
|
11
|
+
if (this.nodeName.toLowerCase() != 'fieldset' &&
|
12
|
+
!this.disabled && type != 'submit' && type != 'reset' && type != 'button' &&
|
13
|
+
((type != 'radio' && type != 'checkbox') || this.checked))
|
14
|
+
result.push({
|
15
|
+
name: el.attr('name'),
|
16
|
+
value: el.val()
|
17
|
+
})
|
18
|
+
})
|
19
|
+
return result
|
20
|
+
}
|
21
|
+
|
22
|
+
$.fn.serialize = function () {
|
23
|
+
var result = []
|
24
|
+
this.serializeArray().forEach(function (elm) {
|
25
|
+
result.push( encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value) )
|
26
|
+
})
|
27
|
+
return result.join('&')
|
28
|
+
}
|
29
|
+
|
30
|
+
$.fn.submit = function (callback) {
|
31
|
+
if (callback) this.bind('submit', callback)
|
32
|
+
else if (this.length) {
|
33
|
+
var event = $.Event('submit')
|
34
|
+
this.eq(0).trigger(event)
|
35
|
+
if (!event.defaultPrevented) this.get(0).submit()
|
36
|
+
}
|
37
|
+
return this
|
38
|
+
}
|
39
|
+
|
40
|
+
})(Zepto)
|