💾 Archived View for gmi.noulin.net › gitRepositories › git-off › file › src › node_modules › aws-sdk… captured on 2024-09-29 at 00:46:02. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-01-29)

-=-=-=-=-=-=-

git-off

Log

Files

Refs

README

util.js (26894B)

     1 /* eslint guard-for-in:0 */
     2 var AWS;
     3 
     4 /**
     5  * A set of utility methods for use with the AWS SDK.
     6  *
     7  * @!attribute abort
     8  *   Return this value from an iterator function {each} or {arrayEach}
     9  *   to break out of the iteration.
    10  *   @example Breaking out of an iterator function
    11  *     AWS.util.each({a: 1, b: 2, c: 3}, function(key, value) {
    12  *       if (key == 'b') return AWS.util.abort;
    13  *     });
    14  *   @see each
    15  *   @see arrayEach
    16  * @api private
    17  */
    18 var util = {
    19   engine: function engine() {
    20     if (util.isBrowser() && typeof navigator !== 'undefined') {
    21       return navigator.userAgent;
    22     } else {
    23       return process.platform + '/' + process.version;
    24     }
    25   },
    26 
    27   userAgent: function userAgent() {
    28     var name = util.isBrowser() ? 'js' : 'nodejs';
    29     var agent = 'aws-sdk-' + name + '/' + require('./core').VERSION;
    30     if (name === 'nodejs') agent += ' ' + util.engine();
    31     return agent;
    32   },
    33 
    34   isBrowser: function isBrowser() { return process && process.browser; },
    35   isNode: function isNode() { return !util.isBrowser(); },
    36   uriEscape: function uriEscape(string) {
    37     var output = encodeURIComponent(string);
    38     output = output.replace(/[^A-Za-z0-9_.~\-%]+/g, escape);
    39 
    40     // AWS percent-encodes some extra non-standard characters in a URI
    41     output = output.replace(/[*]/g, function(ch) {
    42       return '%' + ch.charCodeAt(0).toString(16).toUpperCase();
    43     });
    44 
    45     return output;
    46   },
    47 
    48   uriEscapePath: function uriEscapePath(string) {
    49     var parts = [];
    50     util.arrayEach(string.split('/'), function (part) {
    51       parts.push(util.uriEscape(part));
    52     });
    53     return parts.join('/');
    54   },
    55 
    56   urlParse: function urlParse(url) {
    57     return util.url.parse(url);
    58   },
    59 
    60   urlFormat: function urlFormat(url) {
    61     return util.url.format(url);
    62   },
    63 
    64   queryStringParse: function queryStringParse(qs) {
    65     return util.querystring.parse(qs);
    66   },
    67 
    68   queryParamsToString: function queryParamsToString(params) {
    69     var items = [];
    70     var escape = util.uriEscape;
    71     var sortedKeys = Object.keys(params).sort();
    72 
    73     util.arrayEach(sortedKeys, function(name) {
    74       var value = params[name];
    75       var ename = escape(name);
    76       var result = ename + '=';
    77       if (Array.isArray(value)) {
    78         var vals = [];
    79         util.arrayEach(value, function(item) { vals.push(escape(item)); });
    80         result = ename + '=' + vals.sort().join('&' + ename + '=');
    81       } else if (value !== undefined && value !== null) {
    82         result = ename + '=' + escape(value);
    83       }
    84       items.push(result);
    85     });
    86 
    87     return items.join('&');
    88   },
    89 
    90   readFileSync: function readFileSync(path) {
    91     if (util.isBrowser()) return null;
    92     return require('fs').readFileSync(path, 'utf-8');
    93   },
    94 
    95   base64: {
    96 
    97     encode: function encode64(string) {
    98       return new util.Buffer(string).toString('base64');
    99     },
   100 
   101     decode: function decode64(string) {
   102       return new util.Buffer(string, 'base64');
   103     }
   104 
   105   },
   106 
   107   buffer: {
   108     toStream: function toStream(buffer) {
   109       if (!util.Buffer.isBuffer(buffer)) buffer = new util.Buffer(buffer);
   110 
   111       var readable = new (util.stream.Readable)();
   112       var pos = 0;
   113       readable._read = function(size) {
   114         if (pos >= buffer.length) return readable.push(null);
   115 
   116         var end = pos + size;
   117         if (end > buffer.length) end = buffer.length;
   118         readable.push(buffer.slice(pos, end));
   119         pos = end;
   120       };
   121 
   122       return readable;
   123     },
   124 
   125     /**
   126      * Concatenates a list of Buffer objects.
   127      */
   128     concat: function(buffers) {
   129       var length = 0,
   130           offset = 0,
   131           buffer = null, i;
   132 
   133       for (i = 0; i < buffers.length; i++) {
   134         length += buffers[i].length;
   135       }
   136 
   137       buffer = new util.Buffer(length);
   138 
   139       for (i = 0; i < buffers.length; i++) {
   140         buffers[i].copy(buffer, offset);
   141         offset += buffers[i].length;
   142       }
   143 
   144       return buffer;
   145     }
   146   },
   147 
   148   string: {
   149     byteLength: function byteLength(string) {
   150       if (string === null || string === undefined) return 0;
   151       if (typeof string === 'string') string = new util.Buffer(string);
   152 
   153       if (typeof string.byteLength === 'number') {
   154         return string.byteLength;
   155       } else if (typeof string.length === 'number') {
   156         return string.length;
   157       } else if (typeof string.size === 'number') {
   158         return string.size;
   159       } else if (typeof string.path === 'string') {
   160         return require('fs').lstatSync(string.path).size;
   161       } else {
   162         throw util.error(new Error('Cannot determine length of ' + string),
   163           { object: string });
   164       }
   165     },
   166 
   167     upperFirst: function upperFirst(string) {
   168       return string[0].toUpperCase() + string.substr(1);
   169     },
   170 
   171     lowerFirst: function lowerFirst(string) {
   172       return string[0].toLowerCase() + string.substr(1);
   173     }
   174   },
   175 
   176   ini: {
   177     parse: function string(ini) {
   178       var currentSection, map = {};
   179       util.arrayEach(ini.split(/\r?\n/), function(line) {
   180         line = line.split(/(^|\s)[;#]/)[0]; // remove comments
   181         var section = line.match(/^\s*\[([^\[\]]+)\]\s*$/);
   182         if (section) {
   183           currentSection = section[1];
   184         } else if (currentSection) {
   185           var item = line.match(/^\s*(.+?)\s*=\s*(.+?)\s*$/);
   186           if (item) {
   187             map[currentSection] = map[currentSection] || {};
   188             map[currentSection][item[1]] = item[2];
   189           }
   190         }
   191       });
   192 
   193       return map;
   194     }
   195   },
   196 
   197   fn: {
   198     noop: function() {},
   199 
   200     /**
   201      * Turn a synchronous function into as "async" function by making it call
   202      * a callback. The underlying function is called with all but the last argument,
   203      * which is treated as the callback. The callback is passed passed a first argument
   204      * of null on success to mimick standard node callbacks.
   205      */
   206     makeAsync: function makeAsync(fn, expectedArgs) {
   207       if (expectedArgs && expectedArgs <= fn.length) {
   208         return fn;
   209       }
   210 
   211       return function() {
   212         var args = Array.prototype.slice.call(arguments, 0);
   213         var callback = args.pop();
   214         var result = fn.apply(null, args);
   215         callback(result);
   216       };
   217     }
   218   },
   219 
   220   /**
   221    * Date and time utility functions.
   222    */
   223   date: {
   224 
   225     /**
   226      * @return [Date] the current JavaScript date object. Since all
   227      *   AWS services rely on this date object, you can override
   228      *   this function to provide a special time value to AWS service
   229      *   requests.
   230      */
   231     getDate: function getDate() {
   232       if (!AWS) AWS = require('./core');
   233       if (AWS.config.systemClockOffset) { // use offset when non-zero
   234         return new Date(new Date().getTime() + AWS.config.systemClockOffset);
   235       } else {
   236         return new Date();
   237       }
   238     },
   239 
   240     /**
   241      * @return [String] the date in ISO-8601 format
   242      */
   243     iso8601: function iso8601(date) {
   244       if (date === undefined) { date = util.date.getDate(); }
   245       return date.toISOString().replace(/\.\d{3}Z$/, 'Z');
   246     },
   247 
   248     /**
   249      * @return [String] the date in RFC 822 format
   250      */
   251     rfc822: function rfc822(date) {
   252       if (date === undefined) { date = util.date.getDate(); }
   253       return date.toUTCString();
   254     },
   255 
   256     /**
   257      * @return [Integer] the UNIX timestamp value for the current time
   258      */
   259     unixTimestamp: function unixTimestamp(date) {
   260       if (date === undefined) { date = util.date.getDate(); }
   261       return date.getTime() / 1000;
   262     },
   263 
   264     /**
   265      * @param [String,number,Date] date
   266      * @return [Date]
   267      */
   268     from: function format(date) {
   269       if (typeof date === 'number') {
   270         return new Date(date * 1000); // unix timestamp
   271       } else {
   272         return new Date(date);
   273       }
   274     },
   275 
   276     /**
   277      * Given a Date or date-like value, this function formats the
   278      * date into a string of the requested value.
   279      * @param [String,number,Date] date
   280      * @param [String] formatter Valid formats are:
   281      #   * 'iso8601'
   282      #   * 'rfc822'
   283      #   * 'unixTimestamp'
   284      * @return [String]
   285      */
   286     format: function format(date, formatter) {
   287       if (!formatter) formatter = 'iso8601';
   288       return util.date[formatter](util.date.from(date));
   289     },
   290 
   291     parseTimestamp: function parseTimestamp(value) {
   292       if (typeof value === 'number') { // unix timestamp (number)
   293         return new Date(value * 1000);
   294       } else if (value.match(/^\d+$/)) { // unix timestamp
   295         return new Date(value * 1000);
   296       } else if (value.match(/^\d{4}/)) { // iso8601
   297         return new Date(value);
   298       } else if (value.match(/^\w{3},/)) { // rfc822
   299         return new Date(value);
   300       } else {
   301         throw util.error(
   302           new Error('unhandled timestamp format: ' + value),
   303           {code: 'TimestampParserError'});
   304       }
   305     }
   306 
   307   },
   308 
   309   crypto: {
   310     crc32Table: [
   311      0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419,
   312      0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
   313      0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07,
   314      0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
   315      0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856,
   316      0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
   317      0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
   318      0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
   319      0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
   320      0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A,
   321      0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,
   322      0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
   323      0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190,
   324      0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
   325      0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E,
   326      0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
   327      0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
   328      0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
   329      0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3,
   330      0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
   331      0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
   332      0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
   333      0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010,
   334      0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
   335      0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17,
   336      0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6,
   337      0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
   338      0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
   339      0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344,
   340      0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
   341      0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A,
   342      0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
   343      0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1,
   344      0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
   345      0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
   346      0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
   347      0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE,
   348      0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
   349      0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C,
   350      0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
   351      0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B,
   352      0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
   353      0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1,
   354      0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
   355      0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
   356      0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
   357      0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66,
   358      0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
   359      0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
   360      0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8,
   361      0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
   362      0x2D02EF8D],
   363 
   364     crc32: function crc32(data) {
   365       var tbl = util.crypto.crc32Table;
   366       var crc = 0 ^ -1;
   367 
   368       if (typeof data === 'string') {
   369         data = new util.Buffer(data);
   370       }
   371 
   372       for (var i = 0; i < data.length; i++) {
   373         var code = data.readUInt8(i);
   374         crc = (crc >>> 8) ^ tbl[(crc ^ code) & 0xFF];
   375       }
   376       return (crc ^ -1) >>> 0;
   377     },
   378 
   379     hmac: function hmac(key, string, digest, fn) {
   380       if (!digest) digest = 'binary';
   381       if (digest === 'buffer') { digest = undefined; }
   382       if (!fn) fn = 'sha256';
   383       if (typeof string === 'string') string = new util.Buffer(string);
   384       return util.crypto.lib.createHmac(fn, key).update(string).digest(digest);
   385     },
   386 
   387     md5: function md5(data, digest, callback) {
   388       return util.crypto.hash('md5', data, digest, callback);
   389     },
   390 
   391     sha256: function sha256(data, digest, callback) {
   392       return util.crypto.hash('sha256', data, digest, callback);
   393     },
   394 
   395     hash: function(algorithm, data, digest, callback) {
   396       var hash = util.crypto.createHash(algorithm);
   397       if (!digest) { digest = 'binary'; }
   398       if (digest === 'buffer') { digest = undefined; }
   399       if (typeof data === 'string') data = new util.Buffer(data);
   400       var sliceFn = util.arraySliceFn(data);
   401       var isBuffer = util.Buffer.isBuffer(data);
   402       //Identifying objects with an ArrayBuffer as buffers
   403       if (util.isBrowser() && typeof ArrayBuffer !== 'undefined' && data && data.buffer instanceof ArrayBuffer) isBuffer = true;
   404 
   405       if (callback && typeof data === 'object' &&
   406           typeof data.on === 'function' && !isBuffer) {
   407         data.on('data', function(chunk) { hash.update(chunk); });
   408         data.on('error', function(err) { callback(err); });
   409         data.on('end', function() { callback(null, hash.digest(digest)); });
   410       } else if (callback && sliceFn && !isBuffer &&
   411                  typeof FileReader !== 'undefined') {
   412         // this might be a File/Blob
   413         var index = 0, size = 1024 * 512;
   414         var reader = new FileReader();
   415         reader.onerror = function() {
   416           callback(new Error('Failed to read data.'));
   417         };
   418         reader.onload = function() {
   419           var buf = new util.Buffer(new Uint8Array(reader.result));
   420           hash.update(buf);
   421           index += buf.length;
   422           reader._continueReading();
   423         };
   424         reader._continueReading = function() {
   425           if (index >= data.size) {
   426             callback(null, hash.digest(digest));
   427             return;
   428           }
   429 
   430           var back = index + size;
   431           if (back > data.size) back = data.size;
   432           reader.readAsArrayBuffer(sliceFn.call(data, index, back));
   433         };
   434 
   435         reader._continueReading();
   436       } else {
   437         if (util.isBrowser() && typeof data === 'object' && !isBuffer) {
   438           data = new util.Buffer(new Uint8Array(data));
   439         }
   440         var out = hash.update(data).digest(digest);
   441         if (callback) callback(null, out);
   442         return out;
   443       }
   444     },
   445 
   446     toHex: function toHex(data) {
   447       var out = [];
   448       for (var i = 0; i < data.length; i++) {
   449         out.push(('0' + data.charCodeAt(i).toString(16)).substr(-2, 2));
   450       }
   451       return out.join('');
   452     },
   453 
   454     createHash: function createHash(algorithm) {
   455       return util.crypto.lib.createHash(algorithm);
   456     }
   457 
   458   },
   459 
   460   /** @!ignore */
   461 
   462   /* Abort constant */
   463   abort: {},
   464 
   465   each: function each(object, iterFunction) {
   466     for (var key in object) {
   467       if (Object.prototype.hasOwnProperty.call(object, key)) {
   468         var ret = iterFunction.call(this, key, object[key]);
   469         if (ret === util.abort) break;
   470       }
   471     }
   472   },
   473 
   474   arrayEach: function arrayEach(array, iterFunction) {
   475     for (var idx in array) {
   476       if (Object.prototype.hasOwnProperty.call(array, idx)) {
   477         var ret = iterFunction.call(this, array[idx], parseInt(idx, 10));
   478         if (ret === util.abort) break;
   479       }
   480     }
   481   },
   482 
   483   update: function update(obj1, obj2) {
   484     util.each(obj2, function iterator(key, item) {
   485       obj1[key] = item;
   486     });
   487     return obj1;
   488   },
   489 
   490   merge: function merge(obj1, obj2) {
   491     return util.update(util.copy(obj1), obj2);
   492   },
   493 
   494   copy: function copy(object) {
   495     if (object === null || object === undefined) return object;
   496     var dupe = {};
   497     // jshint forin:false
   498     for (var key in object) {
   499       dupe[key] = object[key];
   500     }
   501     return dupe;
   502   },
   503 
   504   isEmpty: function isEmpty(obj) {
   505     for (var prop in obj) {
   506       if (Object.prototype.hasOwnProperty.call(obj, prop)) {
   507         return false;
   508       }
   509     }
   510     return true;
   511   },
   512 
   513   arraySliceFn: function arraySliceFn(obj) {
   514     var fn = obj.slice || obj.webkitSlice || obj.mozSlice;
   515     return typeof fn === 'function' ? fn : null;
   516   },
   517 
   518   isType: function isType(obj, type) {
   519     // handle cross-"frame" objects
   520     if (typeof type === 'function') type = util.typeName(type);
   521     return Object.prototype.toString.call(obj) === '[object ' + type + ']';
   522   },
   523 
   524   typeName: function typeName(type) {
   525     if (Object.prototype.hasOwnProperty.call(type, 'name')) return type.name;
   526     var str = type.toString();
   527     var match = str.match(/^\s*function (.+)\(/);
   528     return match ? match[1] : str;
   529   },
   530 
   531   error: function error(err, options) {
   532     var originalError = null;
   533     if (typeof err.message === 'string' && err.message !== '') {
   534       if (typeof options === 'string' || (options && options.message)) {
   535         originalError = util.copy(err);
   536         originalError.message = err.message;
   537       }
   538     }
   539     err.message = err.message || null;
   540 
   541     if (typeof options === 'string') {
   542       err.message = options;
   543     } else if (typeof options === 'object' && options !== null) {
   544       util.update(err, options);
   545       if (options.message)
   546         err.message = options.message;
   547       if (options.code || options.name)
   548         err.code = options.code || options.name;
   549       if (options.stack)
   550         err.stack = options.stack;
   551     }
   552 
   553     if (typeof Object.defineProperty === 'function') {
   554       Object.defineProperty(err, 'name', {writable: true, enumerable: false});
   555       Object.defineProperty(err, 'message', {enumerable: true});
   556     }
   557 
   558     err.name = options && options.name || err.name || err.code || 'Error';
   559     err.time = new Date();
   560 
   561     if (originalError) err.originalError = originalError;
   562 
   563     return err;
   564   },
   565 
   566   /**
   567    * @api private
   568    */
   569   inherit: function inherit(klass, features) {
   570     var newObject = null;
   571     if (features === undefined) {
   572       features = klass;
   573       klass = Object;
   574       newObject = {};
   575     } else {
   576       var ctor = function ConstructorWrapper() {};
   577       ctor.prototype = klass.prototype;
   578       newObject = new ctor();
   579     }
   580 
   581     // constructor not supplied, create pass-through ctor
   582     if (features.constructor === Object) {
   583       features.constructor = function() {
   584         if (klass !== Object) {
   585           return klass.apply(this, arguments);
   586         }
   587       };
   588     }
   589 
   590     features.constructor.prototype = newObject;
   591     util.update(features.constructor.prototype, features);
   592     features.constructor.__super__ = klass;
   593     return features.constructor;
   594   },
   595 
   596   /**
   597    * @api private
   598    */
   599   mixin: function mixin() {
   600     var klass = arguments[0];
   601     for (var i = 1; i < arguments.length; i++) {
   602       // jshint forin:false
   603       for (var prop in arguments[i].prototype) {
   604         var fn = arguments[i].prototype[prop];
   605         if (prop !== 'constructor') {
   606           klass.prototype[prop] = fn;
   607         }
   608       }
   609     }
   610     return klass;
   611   },
   612 
   613   /**
   614    * @api private
   615    */
   616   hideProperties: function hideProperties(obj, props) {
   617     if (typeof Object.defineProperty !== 'function') return;
   618 
   619     util.arrayEach(props, function (key) {
   620       Object.defineProperty(obj, key, {
   621         enumerable: false, writable: true, configurable: true });
   622     });
   623   },
   624 
   625   /**
   626    * @api private
   627    */
   628   property: function property(obj, name, value, enumerable, isValue) {
   629     var opts = {
   630       configurable: true,
   631       enumerable: enumerable !== undefined ? enumerable : true
   632     };
   633     if (typeof value === 'function' && !isValue) {
   634       opts.get = value;
   635     }
   636     else {
   637       opts.value = value; opts.writable = true;
   638     }
   639 
   640     Object.defineProperty(obj, name, opts);
   641   },
   642 
   643   /**
   644    * @api private
   645    */
   646   memoizedProperty: function memoizedProperty(obj, name, get, enumerable) {
   647     var cachedValue = null;
   648 
   649     // build enumerable attribute for each value with lazy accessor.
   650     util.property(obj, name, function() {
   651       if (cachedValue === null) {
   652         cachedValue = get();
   653       }
   654       return cachedValue;
   655     }, enumerable);
   656   },
   657 
   658   /**
   659    * TODO Remove in major version revision
   660    * This backfill populates response data without the
   661    * top-level payload name.
   662    *
   663    * @api private
   664    */
   665   hoistPayloadMember: function hoistPayloadMember(resp) {
   666     var req = resp.request;
   667     var operation = req.operation;
   668     var output = req.service.api.operations[operation].output;
   669     if (output.payload) {
   670       var payloadMember = output.members[output.payload];
   671       var responsePayload = resp.data[output.payload];
   672       if (payloadMember.type === 'structure') {
   673         util.each(responsePayload, function(key, value) {
   674           util.property(resp.data, key, value, false);
   675         });
   676       }
   677     }
   678   },
   679 
   680   /**
   681    * Compute SHA-256 checksums of streams
   682    *
   683    * @api private
   684    */
   685   computeSha256: function computeSha256(body, done) {
   686     if (util.isNode()) {
   687       var Stream = util.stream.Stream;
   688       var fs = require('fs');
   689       if (body instanceof Stream) {
   690         if (typeof body.path === 'string') { // assume file object
   691           var settings = {};
   692           if (typeof body.start === 'number') {
   693             settings.start = body.start;
   694           }
   695           if (typeof body.end === 'number') {
   696             settings.end = body.end;
   697           }
   698           body = fs.createReadStream(body.path, settings);
   699         } else { // TODO support other stream types
   700           return done(new Error('Non-file stream objects are ' +
   701                                 'not supported with SigV4'));
   702         }
   703       }
   704     }
   705 
   706     util.crypto.sha256(body, 'hex', function(err, sha) {
   707       if (err) done(err);
   708       else done(null, sha);
   709     });
   710   },
   711 
   712   /**
   713    * @api private
   714    */
   715   isClockSkewed: function isClockSkewed(serverTime) {
   716     if (serverTime) {
   717       util.property(AWS.config, 'isClockSkewed',
   718         Math.abs(new Date().getTime() - serverTime) >= 300000, false);
   719       return AWS.config.isClockSkewed;
   720     }
   721   },
   722 
   723   applyClockOffset: function applyClockOffset(serverTime) {
   724     if (serverTime)
   725       AWS.config.systemClockOffset = serverTime - new Date().getTime();
   726   },
   727 
   728   /**
   729    * @api private
   730    */
   731   extractRequestId: function extractRequestId(resp) {
   732     var requestId = resp.httpResponse.headers['x-amz-request-id'] ||
   733                      resp.httpResponse.headers['x-amzn-requestid'];
   734 
   735     if (!requestId && resp.data && resp.data.ResponseMetadata) {
   736       requestId = resp.data.ResponseMetadata.RequestId;
   737     }
   738 
   739     if (requestId) {
   740       resp.requestId = requestId;
   741     }
   742 
   743     if (resp.error) {
   744       resp.error.requestId = requestId;
   745     }
   746   },
   747 
   748   /**
   749    * @api private
   750    */
   751   addPromises: function addPromises(constructors, PromiseDependency) {
   752     if (PromiseDependency === undefined && AWS && AWS.config) {
   753       PromiseDependency = AWS.config.getPromisesDependency();
   754     }
   755     if (PromiseDependency === undefined && typeof Promise !== 'undefined') {
   756       PromiseDependency = Promise;
   757     }
   758     if (typeof PromiseDependency !== 'function') var deletePromises = true;
   759     if (!Array.isArray(constructors)) constructors = [constructors];
   760 
   761     for (var ind = 0; ind < constructors.length; ind++) {
   762       var constructor = constructors[ind];
   763       if (deletePromises) {
   764         if (constructor.deletePromisesFromClass) {
   765           constructor.deletePromisesFromClass();
   766         }
   767       } else if (constructor.addPromisesToClass) {
   768         constructor.addPromisesToClass(PromiseDependency);
   769       }
   770     }
   771   },
   772 
   773   /**
   774    * @api private
   775    */
   776   promisifyMethod: function promisifyMethod(methodName, PromiseDependency) {
   777     return function promise() {
   778       var self = this;
   779       return new PromiseDependency(function(resolve, reject) {
   780         self[methodName](function(err, data) {
   781           if (err) {
   782             reject(err);
   783           } else {
   784             resolve(data);
   785           }
   786         });
   787       });
   788     };
   789   },
   790 
   791   /**
   792    * @api private
   793    */
   794   isDualstackAvailable: function isDualstackAvailable(service) {
   795     if (!service) return false;
   796     var metadata = require('../apis/metadata.json');
   797     if (typeof service !== 'string') service = service.serviceIdentifier;
   798     if (typeof service !== 'string' || !metadata.hasOwnProperty(service)) return false;
   799     return !!metadata[service].dualstackAvailable;
   800   },
   801 
   802   /**
   803    * @api private
   804    */
   805   calculateRetryDelay: function calculateRetryDelay(retryCount, retryDelayOptions) {
   806     if (!retryDelayOptions) retryDelayOptions = {};
   807     var customBackoff = retryDelayOptions.customBackoff || null;
   808     if (typeof customBackoff === 'function') {
   809       return customBackoff(retryCount);
   810     }
   811     var base = retryDelayOptions.base || 100;
   812     var delay = Math.random() * (Math.pow(2, retryCount) * base);
   813     return delay;
   814   },
   815 
   816   /**
   817    * @api private
   818    */
   819   handleRequestWithRetries: function handleRequestWithRetries(httpRequest, options, cb) {
   820     if (!options) options = {};
   821     var http = AWS.HttpClient.getInstance();
   822     var httpOptions = options.httpOptions || {};
   823     var retryCount = 0;
   824 
   825     var errCallback = function(err) {
   826       var maxRetries = options.maxRetries || 0;
   827       if (err && err.code === 'TimeoutError') err.retryable = true;
   828       if (err && err.retryable && retryCount < maxRetries) {
   829         retryCount++;
   830         var delay = util.calculateRetryDelay(retryCount, options.retryDelayOptions);
   831         setTimeout(sendRequest, delay + (err.retryAfter || 0));
   832       } else {
   833         cb(err);
   834       }
   835     };
   836 
   837     var sendRequest = function() {
   838       var data = '';
   839       http.handleRequest(httpRequest, httpOptions, function(httpResponse) {
   840         httpResponse.on('data', function(chunk) { data += chunk.toString(); });
   841         httpResponse.on('end', function() {
   842           var statusCode = httpResponse.statusCode;
   843           if (statusCode < 300) {
   844             cb(null, data);
   845           } else {
   846             var retryAfter = parseInt(httpResponse.headers['retry-after'], 10) * 1000 || 0;
   847             var err = util.error(new Error(),
   848               { retryable: statusCode >= 500 || statusCode === 429 }
   849             );
   850             if (retryAfter && err.retryable) err.retryAfter = retryAfter;
   851             errCallback(err);
   852           }
   853         });
   854       }, errCallback);
   855     };
   856 
   857     process.nextTick(sendRequest);
   858   }
   859 
   860 };
   861 
   862 module.exports = util;