uglifier 1.3.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,6 +1,45 @@
1
- # Uglifier [![Build Status](https://secure.travis-ci.org/lautis/uglifier.png?branch=master)](http://travis-ci.org/lautis/uglifier) [![Dependency Status](https://gemnasium.com/lautis/uglifier.png?travis)](https://gemnasium.com/lautis/uglifier)
1
+ # Uglifier
2
2
 
3
- Ruby wrapper for [UglifyJS](https://github.com/mishoo/UglifyJS) JavaScript compressor.
3
+ Ruby wrapper for [UglifyJS](https://github.com/mishoo/UglifyJS2) JavaScript
4
+ compressor.
5
+
6
+ UglifyJS currently is extensively tested with ES5, but also includes experimental ES6/ES2015+/Harmony support.
7
+
8
+ More stable alternatives for working with ES6 code is to first transpile to ES5 with e.g. [babel-transpiler](https://github.com/babel/ruby-babel-transpiler) or using [Closure Compiler](https://github.com/documentcloud/closure-compiler) to directly minify ES6 code.
9
+
10
+ [![Build Status](https://travis-ci.org/lautis/uglifier.svg?branch=master)](https://travis-ci.org/lautis/uglifier)
11
+
12
+ ## ES6 / ES2015+ / Harmony mode
13
+
14
+ When using Uglifier with ES6 syntax without any options, an error will be
15
+ thrown.
16
+
17
+ ```
18
+ Uglifier::Error: Unexpected token: punc ((). To use ES6 syntax, harmony mode must be enabled with Uglifier.new(:harmony => true).
19
+ ```
20
+
21
+ The experimental ES6 syntax support can be enabled by passing `:harmony => true`
22
+ option to Uglifier.
23
+
24
+ ```ruby
25
+ Uglifier.compile(js, harmony: true)
26
+ ```
27
+
28
+ ### Rails
29
+
30
+ When used in Rails, replace
31
+
32
+ ```ruby
33
+ config.assets.js_compressor = :uglifier
34
+ ```
35
+
36
+ with
37
+
38
+ ```ruby
39
+ config.assets.js_compressor = Uglifier.new(harmony: true)
40
+ ```
41
+
42
+ in `config/environments/production.rb`.
4
43
 
5
44
  ## Installation
6
45
 
@@ -8,71 +47,152 @@ Uglifier is available as a ruby gem.
8
47
 
9
48
  $ gem install uglifier
10
49
 
11
- Ensure that your environment has a JavaScript interpreter supported by [ExecJS](https://github.com/sstephenson/execjs). Installing `therubyracer` gem is a safe choice and having `node` in `PATH` works too.
50
+ Ensure that your environment has a JavaScript interpreter supported by
51
+ [ExecJS](https://github.com/sstephenson/execjs). Using `therubyracer` gem
52
+ is a safe choice if a runtime isn't already present. Note that while JScript built-in Windows 7 and older works, it is extremely slow.
12
53
 
13
54
  ## Usage
14
55
 
15
- require 'uglifier'
16
-
17
- Uglifier.new.compile(File.read("source.js"))
18
- # => js file minified
56
+ ```ruby
57
+ require 'uglifier'
19
58
 
20
- # Or alternatively
21
- Uglifier.compile(File.read("source.js"))
59
+ Uglifier.new.compile(File.read("source.js"))
60
+ # => js file minified
22
61
 
23
- When initializing UglifyJS, you can tune the behavior of UglifyJS by passing options. For example, if you want top-level variable names to be mangled:
62
+ # Or alternatively
63
+ Uglifier.compile(File.read("source.js"))
64
+ ```
24
65
 
25
- Uglifier.new(:toplevel => true).compile(source)
66
+ Uglifier also supports generating source maps:
26
67
 
27
- # Or
28
- Uglifier.compile(source, :toplevel => true)
68
+ ```ruby
69
+ uglified, source_map = Uglifier.new.compile_with_map(source)
70
+ ```
29
71
 
30
- Available options and their defaults are
31
-
32
- {
33
- :mangle => true, # Mangle variable and function names, use :variables to skip function mangling
34
- :toplevel => false, # Mangle top-level variable names
35
- :except => [], # Variable names to be excluded from mangling
36
- :max_line_length => 32 * 1024, # Maximum line length
37
- :squeeze => true, # Squeeze code resulting in smaller, but less-readable code
38
- :seqs => true, # Reduce consecutive statements in blocks into single statement
39
- :dead_code => true, # Remove dead code (e.g. after return)
40
- :lift_vars => false, # Lift all var declarations at the start of the scope
41
- :unsafe => false, # Optimizations known to be unsafe in some situations
42
- :copyright => true, # Show copyright message
43
- :ascii_only => false, # Encode non-ASCII characters as Unicode code points
44
- :inline_script => false, # Escape </script
45
- :quote_keys => false, # Quote keys in object literals
46
- :define => {}, # Define values for symbol replacement
47
- :beautify => false, # Ouput indented code
48
- :beautify_options => {
49
- :indent_level => 4,
50
- :indent_start => 0,
51
- :space_colon => false
52
- }
53
- }
72
+ When initializing UglifyJS, you can tune the behavior of UglifyJS by passing options. For example, if you want disable variable name mangling:
54
73
 
55
- ## Development
74
+ ```ruby
75
+ Uglifier.new(:mangle => false).compile(source)
56
76
 
57
- Uglifier uses [stitch](https://github.com/sstephenson/stitch) to compile UglifyJs for non-node JS runtimes. If you need to update or patch UglifyJS, you can stitch UglifyJS using
77
+ # Or
78
+ Uglifier.compile(source, :mangle => false)
79
+ ```
58
80
 
59
- node build.js
81
+ Available options and their defaults are
60
82
 
61
- ## Submitting an issue
83
+ ```ruby
84
+ {
85
+ :output => {
86
+ :ascii_only => true, # Escape non-ASCII characters
87
+ :comments => :copyright, # Preserve comments (:all, :jsdoc, :copyright, :none, Regexp (see below))
88
+ :inline_script => false, # Escape occurrences of </script in strings
89
+ :quote_keys => false, # Quote keys in object literals
90
+ :max_line_len => 32 * 1024, # Maximum line length in minified code
91
+ :bracketize => false, # Bracketize if, for, do, while or with statements, even if their body is a single statement
92
+ :semicolons => true, # Separate statements with semicolons
93
+ :preserve_line => false, # Preserve line numbers in outputs
94
+ :beautify => false, # Beautify output
95
+ :indent_level => 4, # Indent level in spaces
96
+ :indent_start => 0, # Starting indent level
97
+ :width => 80, # Specify line width when beautifier is used (only with beautifier)
98
+ :preamble => nil, # Preamble for the generated JS file. Can be used to insert any code or comment.
99
+ :wrap_iife => false # Wrap IIFEs in parenthesis. Note: this disables the negate_iife compression option.
100
+ :shebang => true # Preserve shebang (#!) in preamble (shell scripts)
101
+ :quote_style => 0, # Quote style, possible values :auto (default), :single, :double, :original
102
+ :keep_quoted_props => false # Keep quotes property names
103
+ },
104
+ :mangle => {
105
+ :eval => false, # Mangle names when eval of when is used in scope
106
+ :reserved => ["$super"], # Argument names to be excluded from mangling
107
+ :sort => false, # Assign shorter names to most frequently used variables. Often results in bigger output after gzip.
108
+ :toplevel => false, # Mangle names declared in the toplevel scope
109
+ :properties => false, # Mangle property names
110
+ :keep_fnames => false # Do not modify function names
111
+ }, # Mangle variable and function names, set to false to skip mangling
112
+ :mangle_properties => {
113
+ :regex => nil, # A regular expression to filter property names to be mangled
114
+ :ignore_quoted => false, # Only mangle unquoted property names
115
+ :debug => false, # Mangle names with the original name still present
116
+ } # Mangle property names, disabled by default
117
+ :compress => {
118
+ :sequences => true, # Allow statements to be joined by commas
119
+ :properties => true, # Rewrite property access using the dot notation
120
+ :dead_code => true, # Remove unreachable code
121
+ :drop_debugger => true, # Remove debugger; statements
122
+ :unsafe => false, # Apply "unsafe" transformations
123
+ :unsafe_comps => false, # Reverse < and <= to > and >= to allow improved compression. This might be unsafe when an at least one of two operands is an object with computed values due the use of methods like get, or valueOf. This could cause change in execution order after operands in the comparison are switching. Compression only works if both comparisons and unsafe_comps are both set to true.
124
+ :unsafe_math => false, # Optimize numerical expressions like 2 * x * 3 into 6 * x, which may give imprecise floating point results.
125
+ :unsafe_proto => false, # Optimize expressions like Array.prototype.slice.call(a) into [].slice.call(a)
126
+ :conditionals => true, # Optimize for if-s and conditional expressions
127
+ :comparisons => true, # Apply binary node optimizations for comparisons
128
+ :evaluate => true, # Attempt to evaluate constant expressions
129
+ :booleans => true, # Various optimizations to boolean contexts
130
+ :loops => true, # Optimize loops when condition can be statically determined
131
+ :unused => true, # Drop unreferenced functions and variables
132
+ :toplevel => false, # Drop unreferenced top-level functions and variables
133
+ :top_retain => [], # prevent specific toplevel functions and variables from `unused` removal
134
+ :hoist_funs => true, # Hoist function declarations
135
+ :hoist_vars => false, # Hoist var declarations
136
+ :if_return => true, # Optimizations for if/return and if/continue
137
+ :join_vars => true, # Join consecutive var statements
138
+ :collapse_vars => false, # Collapse single-use var and const definitions when possible.
139
+ :reduce_funcs => false, # Inline single-use functions as function expressions. Depends on reduce_vars.
140
+ :reduce_vars => false, # Collapse variables assigned with and used as constant values.
141
+ :negate_iife => true, # Negate immediately invoked function expressions to avoid extra parens
142
+ :pure_getters => false, # Assume that object property access does not have any side-effects
143
+ :pure_funcs => nil, # List of functions without side-effects. Can safely discard function calls when the result value is not used
144
+ :drop_console => false, # Drop calls to console.* functions
145
+ :keep_fargs => false, # Preserve unused function arguments
146
+ :keep_fnames => false, # Do not drop names in function definitions
147
+ :passes => 1, # Number of times to run compress. Raising the number of passes will increase compress time, but can produce slightly smaller code.
148
+ :keep_infinity => false, # Prevent compression of Infinity to 1/0
149
+ :side_effects => true, # Pass false to disable potentially dropping functions marked as "pure" using pure comment annotation. See UglifyJS documentation for details.
150
+ :switches => true, # de-duplicate and remove unreachable switch branches
151
+ }, # Apply transformations to code, set to false to skip
152
+ :parse => {
153
+ :bare_returns => false, # Allow top-level return statements.
154
+ :expression => false, # Parse a single expression, rather than a program (for parsing JSON).
155
+ :html5_comments => true, # Ignore HTML5 comments in input
156
+ :shebang => true, # support #!command as the first line
157
+ :strict => false
158
+ },
159
+ :define => {}, # Define values for symbol replacement
160
+ :enclose => false, # Enclose in output function wrapper, define replacements as key-value pairs
161
+ :keep_fnames => false, # Generate code safe for the poor souls relying on Function.prototype.name at run-time. Sets both compress and mangle keep_fanems to true.
162
+ :source_map => {
163
+ :map_url => false, # Url for source mapping to be appended in minified source
164
+ :url => false, # Url for original source to be appended in minified source
165
+ :sources_content => false, # Include original source content in map
166
+ :filename => nil, # The filename of the input file
167
+ :root => nil, # The URL of the directory which contains :filename
168
+ :output_filename => nil, # The filename or URL where the minified output can be found
169
+ :input_source_map => nil # The contents of the source map describing the input
170
+ },
171
+ :error_context_lines => 8, # How many context lines surrounding the error line. Env var ERROR_CONTEXT_LINES overrides this option
172
+ :harmony => false # Enable ES6/Harmony mode (experimental). Disabling mangling and compressing is recommended with Harmony mode.
173
+ }
174
+ ```
175
+
176
+ When passing a regular expression to the output => comments option, be sure to pass a valid Ruby Regexp.
177
+ The beginning and ending of comments are removed and cannot be matched (/*, */, //). For example:
178
+ When matching
179
+
180
+ ```
181
+ /*!
182
+ * comment
183
+ */
184
+ ```
185
+
186
+ use `Uglifier.new(output: {comments: /^!/})`.
62
187
 
63
- Uglifier uses the [GitHub issue tracker](https://github.com/lautis/uglifier/issues) to track bugs and features. Before submitting a bug report or feature request, check to make sure it hasn't already been submitted. You can indicate support for an existing issuse by voting it up. When submitting a bug report, please include a Gist that includes a stack trace and any details that may be necessary to reproduce the bug, including your gem version, Ruby version, **MultiJSON engine** and **ExecJS runtime**. Ideally, a bug report should include a pull request with failing specs.
188
+ ## Development
64
189
 
65
- ## Contributing to uglifier
190
+ Tests are run using
66
191
 
67
- * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
68
- * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
69
- * Fork the project
70
- * Start a feature/bugfix branch
71
- * Commit and push until you are happy with your contribution
72
- * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
73
- * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
192
+ bundle exec rake
74
193
 
194
+ See [CONTRIBUTING](https://github.com/lautis/uglifier/blob/master/CONTRIBUTING.md) for details about working on and contributing to Uglifier.
75
195
 
76
196
  ## Copyright
77
197
 
78
- © Ville Lautanala, [Flowdock](https://flowdock.com/). Released under MIT license, see [LICENSE.txt](https://github.com/lautis/uglifier/blob/master/LICENSE.txt) for more details.
198
+ © Ville Lautanala. Released under MIT license, see [LICENSE](https://github.com/lautis/uglifier/blob/master/LICENSE.txt) for details.
data/Rakefile CHANGED
@@ -1,39 +1,137 @@
1
- require 'rubygems'
2
- require 'bundler'
3
- begin
4
- Bundler.setup(:default, :development)
5
- rescue Bundler::BundlerError => e
6
- $stderr.puts e.message
7
- $stderr.puts "Run `bundle install` to install missing gems"
8
- exit e.status_code
9
- end
10
- require 'rake'
11
-
12
- require 'jeweler'
13
- Jeweler::Tasks.new do |gem|
14
- # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
- gem.name = "uglifier"
16
- gem.summary = %Q{Ruby wrapper for UglifyJS JavaScript compressor}
17
- gem.email = "lautis@gmail.com"
18
- gem.homepage = "http://github.com/lautis/uglifier"
19
- gem.authors = ["Ville Lautanala"]
20
- end
21
- Jeweler::RubygemsDotOrgTasks.new
22
-
23
- require 'rspec/core'
1
+ # encoding: utf-8
2
+
3
+ require 'fileutils'
4
+ require 'bundler/gem_tasks'
24
5
  require 'rspec/core/rake_task'
25
6
  RSpec::Core::RakeTask.new(:spec) do |spec|
26
7
  spec.pattern = FileList['spec/**/*_spec.rb']
27
8
  end
28
9
 
29
- task :default => :spec
10
+ def version
11
+ ENV.fetch('VERSION')
12
+ end
13
+
14
+ HEADER = "## next"
15
+
16
+ def changelog_tail
17
+ changelog = File.read("CHANGELOG.md")
18
+ if changelog.start_with?(HEADER)
19
+ changelog[HEADER.length + 2..-1]
20
+ else
21
+ "\n" + changelog
22
+ end
23
+ end
24
+
25
+ def compare_url(from, to)
26
+ "https://github.com/mishoo/UglifyJS2/compare/#{from}...#{to}"
27
+ end
28
+
29
+ def previous_version
30
+ match = File.read("CHANGELOG.md").scan(/- update UglifyJS to \[(.*)\]\(/)
31
+ match ? match[0][0].chomp : nil
32
+ end
33
+
34
+ def git_commit(files, message)
35
+ `git add #{files.join(' ')}`
36
+ `git commit -S -m "#{message.gsub('"', "\\\"")}"`
37
+ end
38
+
39
+ # rubocop:disable Metrics/BlockLength
40
+ namespace :uglifyjs do
41
+ desc "Update UglifyJS source to version specified in VERSION environment variable"
42
+ task :update do
43
+ cd 'vendor/uglifyjs' do
44
+ `git fetch && git checkout v#{version}`
45
+ end
46
+ end
47
+
48
+ desc "Rebuild lib/uglify*.js"
49
+ task :build do
50
+ cd 'vendor/source-map/' do
51
+ `npm install --no-package-lock --no-save`
52
+ end
53
+
54
+ cd 'vendor/uglifyjs/' do
55
+ # required to run ./uglifyjs2 --self; not bundled.
56
+ `npm install --no-package-lock --no-save`
57
+ end
58
+
59
+ cd 'vendor/uglifyjs-harmony' do
60
+ # required to run ./uglifyjs2 --self; not bundled.
61
+ `npm install --no-package-lock --no-save`
62
+ end
63
+
64
+ FileUtils.cp("vendor/source-map/dist/source-map.js", "lib/source-map.js")
65
+
66
+ source = `./vendor/uglifyjs/bin/uglifyjs --self --comments /Copyright/`
67
+ File.write("lib/uglify.js", source)
68
+
69
+ harmony_source = `./vendor/uglifyjs-harmony/bin/uglifyjs --self --comments /Copyright/`
70
+ File.write("lib/uglify-harmony.js", harmony_source)
71
+
72
+ FileUtils.cp("vendor/split/split.js", "lib/split.js")
73
+ `patch -p1 -i patches/es5-string-split.patch`
74
+ end
75
+
76
+ desc "Add UglifyJS version bump to changelog"
77
+ task :changelog do
78
+ url = compare_url("v#{previous_version}", "v#{version}")
79
+ item = "- update UglifyJS to [#{version}](#{url})"
80
+ changelog = "#{HEADER}\n\n#{item}\n#{changelog_tail}"
81
+ File.write("CHANGELOG.md", changelog)
82
+ end
83
+
84
+ desc "Commit changes from UglifyJS version bump"
85
+ task :commit do
86
+ files = [
87
+ 'CHANGELOG.md',
88
+ 'lib/uglify.js',
89
+ 'lib/uglify-harmony.js',
90
+ 'vendor/uglifyjs',
91
+ 'vendor/uglifyjs-harmony'
92
+ ]
93
+ git_commit(files, "Update UglifyJS to #{version}")
94
+ end
95
+ end
96
+ # rubocop:enable Metrics/BlockLength
97
+
98
+ desc "Update UglifyJS to version specified in VERSION environment variable"
99
+ task :uglifyjs => ['uglifyjs:update', 'uglifyjs:build', 'uglifyjs:changelog', 'uglifyjs:commit']
100
+
101
+ namespace :version do
102
+ desc "Write version to CHANGELOG.md"
103
+ task :changelog do
104
+ content = File.read("CHANGELOG.md")
105
+ date = Time.now.strftime("%d %B %Y")
106
+ File.write("CHANGELOG.md", content.gsub("## next", "## #{version} (#{date})"))
107
+ end
30
108
 
31
- require 'rdoc/task'
32
- Rake::RDocTask.new do |rdoc|
33
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
109
+ desc "Write version to uglifier.rb"
110
+ task :ruby do
111
+ file = "lib/uglifier/version.rb"
112
+ content = File.read("lib/uglifier/version.rb")
113
+ File.write(file, content.gsub(/VERSION = "(.*)"/, "VERSION = \"#{version}\""))
114
+ end
34
115
 
35
- rdoc.rdoc_dir = 'rdoc'
36
- rdoc.title = "uglifier #{version}"
37
- rdoc.rdoc_files.include('README*')
38
- rdoc.rdoc_files.include('lib/**/*.rb')
116
+ desc "Commit changes from Uglifier version bump"
117
+ task :commit do
118
+ files = ["CHANGELOG.md", "lib/uglifier/version.rb"]
119
+ git_commit(files, "Bump version to #{version}")
120
+ end
121
+
122
+ desc "Create git tag for version"
123
+ task :tag do
124
+ `git tag -s -m "Version #{version}" v#{version}`
125
+ end
126
+ end
127
+
128
+ desc "Update Uglifier to version specified in VERSION environment variable"
129
+ task :version => ['version:changelog', 'version:ruby', 'version:commit', 'version:tag']
130
+
131
+ begin
132
+ require 'rubocop/rake_task'
133
+ RuboCop::RakeTask.new(:rubocop)
134
+ task :default => [:rubocop, :spec]
135
+ rescue LoadError
136
+ task :default => [:spec]
39
137
  end
data/lib/es5.js CHANGED
@@ -185,3 +185,137 @@ if (!Array.prototype.indexOf) {
185
185
  return -1;
186
186
  }
187
187
  }
188
+
189
+ // https://developer.mozilla.org/en/docs/JavaScript/Reference/Global_Objects/Object/keys
190
+ if (!Object.keys) {
191
+ Object.keys = (function () {
192
+ var hasOwnProperty = Object.prototype.hasOwnProperty,
193
+ hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
194
+ dontEnums = [
195
+ 'toString',
196
+ 'toLocaleString',
197
+ 'valueOf',
198
+ 'hasOwnProperty',
199
+ 'isPrototypeOf',
200
+ 'propertyIsEnumerable',
201
+ 'constructor'
202
+ ],
203
+ dontEnumsLength = dontEnums.length;
204
+
205
+ return function (obj) {
206
+ if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');
207
+
208
+ var result = [];
209
+
210
+ for (var prop in obj) {
211
+ if (hasOwnProperty.call(obj, prop)) result.push(prop);
212
+ }
213
+
214
+ if (hasDontEnumBug) {
215
+ for (var i=0; i < dontEnumsLength; i++) {
216
+ if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
217
+ }
218
+ }
219
+ return result;
220
+ }
221
+ })()
222
+ };
223
+
224
+ // https://developer.mozilla.org/en/docs/JavaScript/Reference/Global_Objects/Object/create
225
+ if (!Object.create) {
226
+ Object.create = function (o) {
227
+ if (arguments.length > 1) {
228
+ throw new Error('Object.create implementation only accepts the first parameter.');
229
+ }
230
+ function F() {}
231
+ F.prototype = o;
232
+ return new F();
233
+ };
234
+ }
235
+
236
+ // https://developer.mozilla.org/en/docs/JavaScript/Reference/Global_Objects/Array/filter
237
+ if (!Array.prototype.filter)
238
+ {
239
+ Array.prototype.filter = function(fun /*, thisp*/)
240
+ {
241
+ "use strict";
242
+
243
+ if (this == null)
244
+ throw new TypeError();
245
+
246
+ var t = Object(this);
247
+ var len = t.length >>> 0;
248
+ if (typeof fun != "function")
249
+ throw new TypeError();
250
+
251
+ var res = [];
252
+ var thisp = arguments[1];
253
+ for (var i = 0; i < len; i++)
254
+ {
255
+ if (i in t)
256
+ {
257
+ var val = t[i]; // in case fun mutates this
258
+ if (fun.call(thisp, val, i, t))
259
+ res.push(val);
260
+ }
261
+ }
262
+
263
+ return res;
264
+ };
265
+ }
266
+
267
+ // https://developer.mozilla.org/en/docs/JavaScript/Reference/Global_Objects/Function/bind
268
+ if (!Function.prototype.bind) {
269
+ Function.prototype.bind = function (oThis) {
270
+ if (typeof this !== "function") {
271
+ // closest thing possible to the ECMAScript 5 internal IsCallable function
272
+ throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
273
+ }
274
+
275
+ var aArgs = Array.prototype.slice.call(arguments, 1),
276
+ fToBind = this,
277
+ fNOP = function () {},
278
+ fBound = function () {
279
+ return fToBind.apply(this instanceof fNOP && oThis
280
+ ? this
281
+ : oThis,
282
+ aArgs.concat(Array.prototype.slice.call(arguments)));
283
+ };
284
+
285
+ fNOP.prototype = this.prototype;
286
+ fBound.prototype = new fNOP();
287
+
288
+ return fBound;
289
+ };
290
+ }
291
+
292
+ // https://developer.mozilla.org/en/docs/JavaScript/Reference/Global_Objects/Array/isArray
293
+ if(!Array.isArray) {
294
+ Array.isArray = function (vArg) {
295
+ return Object.prototype.toString.call(vArg) === "[object Array]";
296
+ };
297
+ }
298
+
299
+ // https://developer.mozilla.org/en/docs/JavaScript/Reference/Global_Objects/String/trim
300
+ if(!String.prototype.trim) {
301
+ String.prototype.trim = function () {
302
+ return this.replace(/^\s+|\s+$/g,'');
303
+ };
304
+ }
305
+
306
+
307
+ function definePropertyWorks() {
308
+ try {
309
+ Object.defineProperty({}, "property", {});
310
+ return true;
311
+ } catch (exception) {
312
+ return false;
313
+ }
314
+ }
315
+
316
+ if (!definePropertyWorks()) {
317
+ Object.defineProperty = function defineProperty(object) {
318
+ // fail silently
319
+ return object;
320
+ }
321
+ }