condo 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. checksums.yaml +7 -0
  2. data/README.textile +133 -133
  3. data/app/assets/javascripts/condo.js +9 -6
  4. data/app/assets/javascripts/condo/amazon.js +403 -406
  5. data/app/assets/javascripts/condo/condo.js +184 -0
  6. data/app/assets/javascripts/condo/config.js +69 -80
  7. data/app/assets/javascripts/condo/google.js +338 -255
  8. data/app/assets/javascripts/condo/md5/hash.worker.emulator.js +23 -23
  9. data/app/assets/javascripts/condo/md5/hash.worker.js +11 -11
  10. data/app/assets/javascripts/condo/md5/hasher.js +119 -100
  11. data/app/assets/javascripts/condo/md5/spark-md5.js +276 -161
  12. data/app/assets/javascripts/condo/rackspace.js +326 -329
  13. data/app/assets/javascripts/condo/{abstract-md5.js.erb → services/abstract-md5.js.erb} +86 -93
  14. data/app/assets/javascripts/condo/{base64.js → services/base64.js} +2 -10
  15. data/app/assets/javascripts/condo/services/broadcaster.js +26 -0
  16. data/app/assets/javascripts/condo/services/uploader.js +302 -0
  17. data/app/assets/javascripts/core/core.js +4 -0
  18. data/app/assets/javascripts/core/services/1-safe-apply.js +17 -0
  19. data/app/assets/javascripts/core/services/2-messaging.js +171 -0
  20. data/lib/condo.rb +269 -269
  21. data/lib/condo/configuration.rb +137 -139
  22. data/lib/condo/errors.rb +8 -8
  23. data/lib/condo/strata/amazon_s3.rb +301 -301
  24. data/lib/condo/strata/google_cloud_storage.rb +315 -314
  25. data/lib/condo/strata/rackspace_cloud_files.rb +245 -223
  26. data/lib/condo/version.rb +1 -1
  27. metadata +21 -44
  28. data/app/assets/javascripts/condo/broadcaster.js +0 -60
  29. data/app/assets/javascripts/condo/controller.js +0 -194
  30. data/app/assets/javascripts/condo/uploader.js +0 -310
  31. data/test/dummy/db/test.sqlite3 +0 -0
  32. data/test/dummy/log/test.log +0 -25
@@ -1,3 +1,3 @@
1
1
  module Condo
2
- VERSION = "1.0.4"
2
+ VERSION = "1.0.6"
3
3
  end
metadata CHANGED
@@ -1,62 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: condo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
5
- prerelease:
4
+ version: 1.0.6
6
5
  platform: ruby
7
6
  authors:
8
7
  - Stephen von Takach
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-12-06 00:00:00.000000000 Z
11
+ date: 2014-09-20 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rails
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
- version: 3.0.0
19
+ version: 4.0.0
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
- version: 3.0.0
26
+ version: 4.0.0
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: fog
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
44
- - !ruby/object:Gem::Version
45
- version: '0'
46
- - !ruby/object:Gem::Dependency
47
- name: sqlite3
48
- requirement: !ruby/object:Gem::Requirement
49
- none: false
50
- requirements:
51
- - - ! '>='
52
- - !ruby/object:Gem::Version
53
- version: '0'
54
- type: :development
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - ! '>='
38
+ - - '>='
60
39
  - !ruby/object:Gem::Version
61
40
  version: '0'
62
41
  description: Provides signed upload signatures to your users browsers so they can
@@ -67,20 +46,23 @@ executables: []
67
46
  extensions: []
68
47
  extra_rdoc_files: []
69
48
  files:
70
- - app/assets/javascripts/condo/abstract-md5.js.erb
71
49
  - app/assets/javascripts/condo/amazon.js
72
- - app/assets/javascripts/condo/base64.js
73
- - app/assets/javascripts/condo/broadcaster.js
50
+ - app/assets/javascripts/condo/condo.js
74
51
  - app/assets/javascripts/condo/config.js
75
- - app/assets/javascripts/condo/controller.js
76
52
  - app/assets/javascripts/condo/google.js
77
53
  - app/assets/javascripts/condo/md5/hash.worker.emulator.js
78
54
  - app/assets/javascripts/condo/md5/hash.worker.js
79
55
  - app/assets/javascripts/condo/md5/hasher.js
80
56
  - app/assets/javascripts/condo/md5/spark-md5.js
81
57
  - app/assets/javascripts/condo/rackspace.js
82
- - app/assets/javascripts/condo/uploader.js
58
+ - app/assets/javascripts/condo/services/abstract-md5.js.erb
59
+ - app/assets/javascripts/condo/services/base64.js
60
+ - app/assets/javascripts/condo/services/broadcaster.js
61
+ - app/assets/javascripts/condo/services/uploader.js
83
62
  - app/assets/javascripts/condo.js
63
+ - app/assets/javascripts/core/core.js
64
+ - app/assets/javascripts/core/services/1-safe-apply.js
65
+ - app/assets/javascripts/core/services/2-messaging.js
84
66
  - lib/condo/configuration.rb
85
67
  - lib/condo/engine.rb
86
68
  - lib/condo/errors.rb
@@ -115,8 +97,6 @@ files:
115
97
  - test/dummy/config/locales/en.yml
116
98
  - test/dummy/config/routes.rb
117
99
  - test/dummy/config.ru
118
- - test/dummy/db/test.sqlite3
119
- - test/dummy/log/test.log
120
100
  - test/dummy/public/404.html
121
101
  - test/dummy/public/422.html
122
102
  - test/dummy/public/500.html
@@ -128,27 +108,26 @@ files:
128
108
  - test/test_helper.rb
129
109
  homepage: http://cotag.me/
130
110
  licenses: []
111
+ metadata: {}
131
112
  post_install_message:
132
113
  rdoc_options: []
133
114
  require_paths:
134
115
  - lib
135
116
  required_ruby_version: !ruby/object:Gem::Requirement
136
- none: false
137
117
  requirements:
138
- - - ! '>='
118
+ - - '>='
139
119
  - !ruby/object:Gem::Version
140
120
  version: '0'
141
121
  required_rubygems_version: !ruby/object:Gem::Requirement
142
- none: false
143
122
  requirements:
144
- - - ! '>='
123
+ - - '>='
145
124
  - !ruby/object:Gem::Version
146
125
  version: '0'
147
126
  requirements: []
148
127
  rubyforge_project:
149
- rubygems_version: 1.8.24
128
+ rubygems_version: 2.0.14
150
129
  signing_key:
151
- specification_version: 3
130
+ specification_version: 4
152
131
  summary: Direct Cloud Storage Uploader
153
132
  test_files:
154
133
  - test/condo_test.rb
@@ -173,8 +152,6 @@ test_files:
173
152
  - test/dummy/config/locales/en.yml
174
153
  - test/dummy/config/routes.rb
175
154
  - test/dummy/config.ru
176
- - test/dummy/db/test.sqlite3
177
- - test/dummy/log/test.log
178
155
  - test/dummy/public/404.html
179
156
  - test/dummy/public/422.html
180
157
  - test/dummy/public/500.html
@@ -1,60 +0,0 @@
1
- /**
2
- * CoTag Condo Amazon S3 Strategy
3
- * Direct to cloud resumable uploads for Google Cloud Storage
4
- *
5
- * Copyright (c) 2012 CoTag Media.
6
- *
7
- * @author Stephen von Takach <steve@cotag.me>
8
- * @copyright 2012 cotag.me
9
- *
10
- *
11
- * References:
12
- * * https://github.com/umdjs/umd
13
- * * https://github.com/addyosmani/jquery-plugin-patterns
14
- * *
15
- *
16
- **/
17
-
18
- (function (factory) {
19
- if (typeof define === 'function' && define.amd) {
20
- // AMD
21
- define('condo-broadcaster', factory);
22
- } else {
23
- // Browser globals
24
- factory();
25
- }
26
- }(function (undefined) {
27
- 'use strict';
28
-
29
-
30
- //
31
- //
32
- //
33
-
34
-
35
- angular.module('CondoBroadcaster', []).factory('Condo.Broadcast', ['$rootScope', function($rootScope) {
36
- // eventBroadcaster is the object created by the factory method.
37
- var eventBroadcaster = {};
38
-
39
- // The message is a string or object to carry data with the event.
40
- eventBroadcaster.message = {};
41
-
42
- // The event name is a string used to define event types.
43
- eventBroadcaster.eventName = '';
44
-
45
- // This method is called from within a controller to define an event and attach data to the eventBroadcaster object.
46
- eventBroadcaster.broadcast = function(evName, msg) {
47
- this.message = msg;
48
- this.eventName = evName;
49
- this.broadcastItem();
50
- };
51
-
52
- // This method broadcasts an event with the specified name.
53
- eventBroadcaster.broadcastItem = function() {
54
- $rootScope.$broadcast(this.eventName);
55
- };
56
-
57
- return eventBroadcaster;
58
- }]);
59
-
60
- }));
@@ -1,194 +0,0 @@
1
- /**
2
- * CoTag Condo
3
- * Direct to cloud resumable uploads
4
- *
5
- * Copyright (c) 2012 CoTag Media.
6
- *
7
- * @author Stephen von Takach <steve@cotag.me>
8
- * @copyright 2012 cotag.me
9
- *
10
- *
11
- * References:
12
- * * https://github.com/umdjs/umd
13
- * * https://github.com/addyosmani/jquery-plugin-patterns
14
- * * http://ericterpstra.com/2012/09/angular-cats-part-3-communicating-with-broadcast/
15
- * * http://docs.angularjs.org/api/ng.$rootScope.Scope#$watch
16
- *
17
- **/
18
-
19
- (function (factory) {
20
- if (typeof define === 'function' && define.amd) {
21
- // AMD
22
- define('condo-controller', ['jquery', 'condo-uploader'], factory);
23
- } else {
24
- // Browser globals
25
- factory(jQuery, window.CondoUploader);
26
- }
27
- }(function ($, uploads, undefined) {
28
- 'use strict';
29
-
30
-
31
-
32
- //
33
- // Create a controller for managing the upload states
34
- //
35
- uploads.controller('Condo.Controller', ['$scope', 'Condo.Api', 'Condo.Broadcast', 'Condo.Config', function($scope, api, broadcaster, config) {
36
-
37
- $scope.uploads = [];
38
- $scope.upload_count = 0;
39
-
40
-
41
- //
42
- // See Condo.Config for configuration options
43
- //
44
- $scope.endpoint = config.endpoint;
45
- $scope.autostart = config.autostart;
46
- $scope.ignore_errors = config.ignore_errors; // Continue to autostart after an error?
47
- $scope.parallelism = config.parallelism; // number of uploads at once
48
-
49
-
50
- $scope.add = function(files) {
51
- var length = files.length,
52
- i = 0,
53
- ret = 0, // We only want to check for auto-start after the files have been added
54
- file;
55
-
56
- for (; i < length; i += 1) {
57
- file = files[i];
58
-
59
- if(file.size <= 0 || file.type == '')
60
- continue;
61
-
62
- //
63
- // check file size is acceptable
64
- //
65
- if(!config.file_checker(file) || (config.size_limit != undefined && file.size > config.size_limit)) {
66
- broadcaster.broadcast('coNotice', {
67
- type: 'warn',
68
- number: 0,
69
- file: file
70
- });
71
- continue;
72
- }
73
-
74
- $scope.upload_count += 1;
75
-
76
- api.check_provider($scope.endpoint, files[i]).then(function(upload){
77
- ret += 1;
78
- $scope.uploads.push(upload);
79
- if(ret == length)
80
- $scope.check_autostart();
81
- }, function(failure) {
82
-
83
- $scope.upload_count -= 1;
84
-
85
- ret += 1;
86
- if(ret == length)
87
- $scope.check_autostart();
88
-
89
- //
90
- // broadcast this so it can be handled by a directive
91
- //
92
- broadcaster.broadcast('coNotice', failure);
93
- });
94
- }
95
- };
96
-
97
-
98
- $scope.abort = function(upload) {
99
- upload.abort();
100
- $scope.check_autostart();
101
- };
102
-
103
-
104
- $scope.remove = function(upload) {
105
- //
106
- // Splice(upload, 1) was unreliable. This is better
107
- //
108
- for (var i = 0, length = $scope.uploads.length; i < length; i += 1) {
109
- if($scope.uploads[i] === upload) {
110
- $scope.uploads.splice(i, 1);
111
- $scope.upload_count -= 1;
112
- break;
113
- }
114
- }
115
- };
116
-
117
-
118
- $scope.playpause = function(upload) {
119
- if (upload.state == 3) // Uploading
120
- upload.pause();
121
- else
122
- upload.start();
123
- };
124
-
125
-
126
- //
127
- // Watch autostart and trigger a check when it is changed
128
- //
129
- $scope.$watch('autostart', function(newValue, oldValue) {
130
- if (newValue === true)
131
- $scope.check_autostart();
132
- });
133
-
134
-
135
- //
136
- // Autostart more uploads as this is bumped up
137
- //
138
- $scope.$watch('parallelism', function(newValue, oldValue) {
139
- if(newValue > oldValue)
140
- $scope.check_autostart();
141
- });
142
-
143
-
144
- $scope.check_autostart = function() {
145
- //
146
- // Check if any uploads have been started already
147
- // If there are no active uploads we'll auto-start
148
- //
149
- // PENDING = 0,
150
- // STARTED = 1,
151
- // PAUSED = 2,
152
- // UPLOADING = 3,
153
- // COMPLETED = 4,
154
- // ABORTED = 5
155
- //
156
- if ($scope.autostart) {
157
- var shouldStart = true,
158
- state, i, length, started = 0;
159
-
160
- for (i = 0, length = $scope.uploads.length; i < length; i += 1) {
161
- state = $scope.uploads[i].state;
162
-
163
- //
164
- // Count started uploads (that don't have errors if we are ignoring errors)
165
- // Up until we've reached our parallel limit, then stop
166
- //
167
- if (state > 0 && state < 4 && !($scope.uploads[i].error && $scope.ignore_errors)) {
168
- started += 1;
169
- if(started >= $scope.parallelism) {
170
- shouldStart = false;
171
- break;
172
- }
173
- }
174
- }
175
-
176
- if (shouldStart) {
177
- started = $scope.parallelism - started; // How many can we start
178
-
179
- for (i = 0; i < length; i += 1) {
180
- if ($scope.uploads[i].state == 0) {
181
- $scope.uploads[i].start();
182
-
183
- started -= 1;
184
- if(started <= 0) // Break if we can't start anymore
185
- break;
186
- }
187
- }
188
- }
189
- }
190
- };
191
-
192
- }]);
193
-
194
- }));
@@ -1,310 +0,0 @@
1
- /**
2
- * CoTag Condo
3
- * Direct to cloud resumable uploads
4
- *
5
- * Copyright (c) 2012 CoTag Media.
6
- *
7
- * @author Stephen von Takach <steve@cotag.me>
8
- * @copyright 2012 cotag.me
9
- *
10
- *
11
- * References:
12
- * * https://github.com/umdjs/umd
13
- * * https://github.com/addyosmani/jquery-plugin-patterns
14
- * * http://docs.angularjs.org/api/ng.$http
15
- * * http://docs.angularjs.org/api/ng.$q
16
- *
17
- **/
18
-
19
- (function (factory) {
20
- if (typeof define === 'function' && define.amd) {
21
- // AMD
22
- define('condo-uploader', ['jquery', 'condo-broadcaster'], factory);
23
- } else {
24
- // Browser globals
25
- window.CondoUploader = factory(jQuery);
26
- }
27
- }(function ($) {
28
- 'use strict';
29
-
30
- var uploads = angular.module('CondoUploader', ['CondoBroadcaster']),
31
- residencies = {};
32
-
33
-
34
- //
35
- // Implements the Condo API
36
- //
37
- uploads.factory('Condo.Api', ['$http', '$rootScope', '$q', function($http, $rootScope, $q) {
38
-
39
-
40
- var token = $('meta[name="csrf-token"]').attr('content'),
41
-
42
-
43
- condoConnection = function(api_endpoint, params) {
44
- this.endpoint = api_endpoint; // The API mounting point
45
- this.params = params; // Custom API parameters
46
-
47
- this.upload_id = null; // The current upload ID
48
- this.aborting = false; // Has the user has requested an abort?
49
- this.xhr = null; // Any active cloud file xhr requests
50
- };
51
-
52
-
53
- $http.defaults.headers = {};
54
- $http.defaults.headers['common'] = {'X-Requested-With': 'XMLHttpRequest'};
55
- $http.defaults.headers['post'] = {'X-CSRF-Token': token};
56
- $http.defaults.headers['put'] = {'X-CSRF-Token': token};
57
- $http.defaults.headers['delete'] = {'X-CSRF-Token': token};
58
-
59
- condoConnection.prototype = {
60
-
61
-
62
- //
63
- // Creates an entry in the database for the requested file and returns the upload signature
64
- // If an entry already exists it returns a parts request signature for resumable uploads
65
- //
66
- create: function(options) { // file_id: 123, options: {}
67
- var self = this;
68
- options = options || {};
69
- this.aborting = false;
70
-
71
- if(!!options['file_id'])
72
- this.params['file_id'] = options['file_id'];
73
-
74
- if(!!options['parameters'])
75
- this.params['parameters'] = options['parameters']; // We may be requesting the next set of parts
76
-
77
- return $http({
78
- method: 'POST',
79
- url: this.endpoint,
80
- params: this.params
81
- }).then(function(result){
82
- result = result.data;
83
- self.upload_id = result.upload_id; // Extract the upload id from the results
84
-
85
- if (!self.aborting)
86
- return result;
87
- else
88
- return $q.reject(undefined);
89
- }, function(reason) {
90
- return $q.reject('upload error');
91
- });
92
- },
93
-
94
-
95
- //
96
- // This requests a chunk signature
97
- // Only used for resumable uploads
98
- //
99
- edit: function(part_number, part_id) {
100
- var self = this;
101
- this.aborting = false;
102
-
103
- return $http({
104
- method: 'GET',
105
- url: this.endpoint + '/' + this.upload_id + '/edit',
106
- params: {
107
- part: part_number,
108
- file_id: part_id
109
- }
110
- }).then(function(result){
111
- if (!self.aborting)
112
- return result.data;
113
- else
114
- return $q.reject(undefined);
115
- }, function(reason) {
116
- return $q.reject('upload error');
117
- });
118
- },
119
-
120
-
121
- //
122
- // If resumable id is present the upload is updated
123
- // Otherwise the upload deemed complete
124
- //
125
- update: function(params) { // optional parameters (resumable_id, file_id and part)
126
- var self = this;
127
-
128
- this.aborting = false;
129
- params = params || {};
130
-
131
- return $http({
132
- method: 'PUT',
133
- url: this.endpoint + '/' + this.upload_id,
134
- params: params
135
- }).then(function(result){
136
- if (!self.aborting)
137
- return result.data;
138
- else
139
- return $q.reject(undefined);
140
- }, function(reason) {
141
- if (reason.status == 401 && params.resumable_id == undefined) {
142
- return ''; // User may have paused upload as put was being sent. We should let this through just to update the UI
143
- } else
144
- return $q.reject('upload error');
145
- });
146
- },
147
-
148
-
149
- //
150
- // Cancels a resumable upload
151
- // The actual destruction of the file is handled on the server side as we can't trust the client to do this
152
- // We don't care if this succeeds as the back-end will destroy the file eventually anyway.
153
- //
154
- destroy: function() {
155
- return $http({
156
- method: 'DELETE',
157
- url: this.endpoint + '/' + this.upload_id
158
- });
159
- },
160
-
161
-
162
-
163
- //
164
- // Provides a promise for any request this is what communicated with the cloud storage servers
165
- //
166
- process_request: function(signature, progress_callback) {
167
- var self = this,
168
- result = $q.defer(),
169
- params = {
170
- url: signature.signature.url,
171
- type: signature.signature.verb,
172
- headers: signature.signature.headers,
173
- processData: false,
174
- success: function(response, textStatus, jqXHR) {
175
- self.xhr = null;
176
- result.resolve(response);
177
- },
178
- error: function(jqXHR, textStatus, errorThrown) {
179
- self.xhr = null;
180
- if (!self.aborting)
181
- result.reject('upload error');
182
- else
183
- result.reject(undefined);
184
- },
185
- complete: function(jqXHR, textStatus) {
186
- if(!$rootScope.$$phase) {
187
- $rootScope.$apply(); // This triggers the promise response
188
- }
189
- }
190
- };
191
-
192
- this.aborting = false;
193
-
194
- if (!!self.xhr) {
195
- result.reject('request in progress'); // This is awesome
196
- return result.promise;
197
- }
198
-
199
- if(!!signature.data){
200
- params['data'] = signature.data;
201
- }
202
-
203
- if(!!progress_callback) {
204
- params['xhr'] = function() {
205
- var xhr = $.ajaxSettings.xhr();
206
- if(!!xhr.upload){
207
- xhr.upload.addEventListener('progress', function(e) {
208
- if (e.lengthComputable) {
209
- var phase = $rootScope.$$phase;
210
- if(phase == '$apply' || phase == '$digest') {
211
- progress_callback(e.loaded);
212
- } else {
213
- $rootScope.$apply(function(){
214
- progress_callback(e.loaded);
215
- });
216
- }
217
- }
218
- }, false);
219
- }
220
- return xhr;
221
- };
222
- }
223
-
224
- this.xhr = $.ajax(params);
225
-
226
- return result.promise;
227
- },
228
-
229
-
230
- //
231
- // Will trigger the error call-back of the xhr object
232
- //
233
- abort: function() {
234
- this.aborting = true;
235
- if(!!this.xhr) {
236
- this.xhr.abort();
237
- }
238
- }
239
- };
240
-
241
- return {
242
- //
243
- // Used to determine what upload strategy to use (Amazon, Google, etc)
244
- //
245
- check_provider: function(api_endpoint, the_file, params) {
246
- params = params || {};
247
- params['file_size'] = the_file.size;
248
- params['file_name'] = the_file.name;
249
-
250
- if(!!the_file.dir_path)
251
- params['file_path'] = the_file.dir_path;
252
-
253
- return $http({
254
- method: 'GET',
255
- url: api_endpoint + '/new',
256
- params: params
257
- }).then(function(result){
258
- if(!!residencies[result.data.residence]) {
259
-
260
- var api = new condoConnection(api_endpoint, params);
261
-
262
- //
263
- // TODO:: Check if a file is already in the list and reject if it is
264
- //
265
- return residencies[result.data.residence].new_upload(api, the_file); // return the instantiated provider
266
-
267
- } else {
268
- return $q.reject({
269
- type: 'error',
270
- number: 0,
271
- file: the_file
272
- });
273
- }
274
- }, function(reason) {
275
- if(reason.status == 406) {
276
- return $q.reject({
277
- type: 'warn',
278
- number: 0,
279
- details: reason.data,
280
- file: the_file
281
- });
282
- } else {
283
- return $q.reject({
284
- type: 'warn',
285
- number: 1,
286
- file: the_file
287
- });
288
- }
289
- });
290
- }
291
- };
292
- }]).factory('Condo.Registrar', function(){
293
- return {
294
- //
295
- // Simple dependency injection allows us to load only the providers we need
296
- //
297
- register: function(provider_name, iface) {
298
- residencies[provider_name] = iface;
299
- }
300
- };
301
- });
302
-
303
-
304
-
305
- //
306
- // Anonymous function return
307
- //
308
- return uploads;
309
-
310
- }));