redditor 0.1.0 → 0.1.1

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.
@@ -1,724 +0,0 @@
1
- # FileAPI — a set of tools for working with files.
2
-
3
-
4
- <p align="center">
5
- ~~~ <a href="http://mailru.github.com/FileAPI/">DEMO</a>
6
- ~~~ <a href="http://mailru.github.com/FileAPI/example.userpic.html">user pic</a>
7
- ~~~
8
- </p>
9
-
10
-
11
- ## Support
12
- * Multiupload: all browsers that support HTML5 or [Flash](#flash-settings)
13
- * Drag'n'Drop upload: files (HTML5) & directories (Chrome 21+)
14
- * [Chunked](#chunked) file upload (HTML5)
15
- * Upload one file: all browsers
16
- * Working with [Images](#images): IE6+, FF 3.6+, Chrome 10+, Opera 11.1+, Safari 5.4+
17
- + crop, resize, preview & rotate (HTML5 or Flash)
18
- + auto orientation by exif (HTML5, if include FileAPI.exif.js or Flash)
19
-
20
-
21
-
22
-
23
- ## Example
24
- ```html
25
- <span class="js-fileapi-wrapper" style="position: relative;">
26
- <input id="user-files" type="file" multiple />
27
- </span>
28
-
29
- <div id="preview-list">
30
- </div>
31
- ```
32
- ```js
33
- var input = document.getElementById('user-files');
34
- var previewNode = document.getElementById('preview-list');
35
-
36
- // Drag'n'Drop
37
- FileAPI.event.dnd(previewNode, function (over){
38
- $(this).css('background', over ? 'red' : '');
39
- }, function (files){
40
- // ..
41
- });
42
-
43
-
44
-
45
- FileAPI.event.on(input, 'change', function (evt){
46
- var files = FileAPI.getFiles(evt.target); // or FileAPI.getFiles(evt)
47
-
48
- // filtering
49
- FileAPI.filterFiles(files, function (file, info){
50
- if( /image/.test(file.type) && info ){
51
- return info.width >= 320 && info.height >= 240;
52
- }
53
- else {
54
- return file.size > 128;
55
- }
56
- }, function (fileList, ignor){
57
- if( ignor.length ){
58
- // ...
59
- }
60
-
61
- if( !fileList.length ){
62
- // empty file list
63
- return;
64
- }
65
-
66
-
67
- // do preview
68
- var imageList = FileAPI.filter(fileList, function (file){ return /image/.test(file.type); });
69
- FileAPI.each(imageList, function (imageFile){
70
- FileAPI.Image(imageFile)
71
- .preview(100, 120)
72
- .get(function (err, image){
73
- if( err ){
74
- // ...
75
- }
76
- else {
77
- previewNode.appendChild(image);
78
- }
79
- })
80
- ;
81
- });
82
-
83
-
84
- // upload on server
85
- var xhr = FileAPI.upload({
86
- url: '...',
87
- data: { foo: 'bar' }, // POST-data (iframe, flash, html5)
88
- headers: { 'x-header': '...' }, // request headers (html5)
89
- files: {
90
- files: FileAPI.filter(fileList, function (file){ return !/image/.test(file.type); }),
91
- pictures: imageList
92
- },
93
- imageTransform: {
94
- maxWidth: 1024,
95
- maxHeight: 768
96
- },
97
- imageAutoOrientation: true,
98
- fileprogress: function (evt){ // (flash, html5)
99
- var percent = evt.loaded/evt.total*100;
100
- // ...
101
- },
102
- progress: function (evt){ // (flash, html5)
103
- var percent = evt.loaded/evt.total*100;
104
- // ...
105
- },
106
- complete: function (err, xhr){
107
- // ...
108
- }
109
- });
110
- });
111
- });
112
- ```
113
-
114
- ### HTML structure (templates)
115
- * [Default](#html-default)
116
- * [Button](#html-button)
117
- * [Link](#html-link)
118
-
119
-
120
- ### API
121
- * FileAPI.[getFiles](#getFiles)(`source:HTMLInput|Event`)`:Array`
122
- * FileAPI.[getDropFiles](#getDropFiles)(`files:Array`, `callback:Function`)
123
- * FileAPI.[filterFiles](#filterFiles)(`files:Array`, `iterator:Function`, `complete:Function`)
124
- * FileAPI.[upload](#upload)(`options:Object`)`:XMLHttpRequest`
125
- * FileAPI.[getInfo](#getInfo)(`file:File`, `callback:Function`)
126
- * FileAPI.[readAsImage](#readAs)(`file:File`, `callback:function`)
127
- * FileAPI.[readAsDataURL](#readAs)(`file:File`, `callback:function`)
128
- * FileAPI.[readAsBinaryString](#readAs)(`file:File`, `callback:function`)
129
- * FileAPI.[readAsArrayBuffer](#readAs)(`file:File`, `callback:function`)
130
- * FileAPI.[readAsText](#readAs)(`file:File`, `callback:function`)
131
- * FileAPI.[readAsText](#readAs)(`file:File`, `encoding:String`, `callback:function`)
132
-
133
-
134
- ### Events
135
- * FileAPI.event.on(`el:HTMLElement`, `eventType:String`, `fn:Function`)
136
- * FileAPI.event.off(`el:HTMLElement`, `eventType:String`, `fn:Function`)
137
- * FileAPI.event.one(`el:HTMLElement`, `eventType:String`, `fn:Function`)
138
- * FileAPI.event.dnd(`el:HTMLElement`, `onHover:Function`, `onDrop:Function`)
139
- * jQuery('#el').dnd(onHover, onDrop)
140
-
141
-
142
- <a name="images"></a>
143
- ### FileAPI.Image
144
- * .crop(width[, height])
145
- * .crop(x, y, width[, height])
146
- * .resize(width[, height])
147
- * .resize(width, height, `type:Enum(min,max,preview)`)
148
- * .preview(width[, height])
149
- * .rotate(deg)
150
- * .get(`fn:Function`)
151
-
152
-
153
-
154
- ### Utils
155
- * FileAPI.KB
156
- * FileAPI.MB
157
- * FileAPI.GB
158
- * FileAPI.TB
159
- * FileAPI.support.`html5:Boolean`
160
- * FileAPI.support.`cors:Boolean`
161
- * FileAPI.support.`dnd:Boolean`
162
- * FileAPI.support.`flash:Boolean`
163
- * FileAPI.support.`canvas:Boolean`
164
- * FileAPI.support.`dataURI:Boolean`
165
- * FileAPI.support.`chunked:Boolean`
166
- * FileAPI.each(`obj:Object|Array`, `fn:function`, `context:Mixed`)
167
- * FileAPI.extend(`dst:Object`, `src:Object`)`:Object`
168
- * FileAPI.filter(`list:Array`, `iterator:Function`)`:Array`
169
- * FileAPI.isFile(`file:Mixed`)`:Boolean`
170
- * FileAPI.toBinaryString(`str:Base64`)`:String`
171
-
172
-
173
-
174
- ---------------------------------------
175
-
176
-
177
- <a name="getFiles"></a>
178
- ### FileAPI.getFiles
179
- ```js
180
- FileAPI.event.on('#my-file-1', 'change', onSelect);
181
-
182
- // or jQuery
183
- $('#my-file-2').on('change', onSelect);
184
-
185
- function onSelect(evt/**Event*/){
186
- // (1) extract fileList from event
187
- var files = FileAPI.getFiles(evt);
188
-
189
- // (2) or so
190
- var files = FileAPI.getFiles(evt.target);
191
- }
192
- ```
193
-
194
-
195
- <a name="getDropFiles"></a>
196
- ### FileAPI.getDropFiles
197
- ```js
198
- function onDrop(evt){
199
- FileAPI.getDropFiles(evt, function (files){
200
- if( files.length ){
201
- // ...
202
- }
203
- });
204
- }
205
-
206
- // OR
207
-
208
- var el = document.getElementById('el');
209
- FileAPI.event.dnd(el, function (over/**Boolean*/, evt/**Event*/){
210
- el.style.background = over ? 'red' : '';
211
- }, function (files/**Array*/, evt/**Event*/){
212
- // ...
213
- });
214
- ```
215
-
216
-
217
- <a name="getInfo"></a>
218
- ### FileAPI.getInfo
219
- ```js
220
- FileAPI.getInfo(imageFile/**File*/, function (err/**Boolean*/, info/**Object*/){
221
- if( !err ){
222
- switch( info.exif.Orientation ){
223
- // ...
224
- }
225
- }
226
- });
227
-
228
- // ...
229
-
230
- FileAPI.addInfoReader(/^image/, function (file/**File*/, callback/**Function*/){
231
- // http://www.nihilogic.dk/labs/exif/exif.js
232
- // http://www.nihilogic.dk/labs/binaryajax/binaryajax.js
233
- FileAPI.readAsBinaryString(file, function (evt){
234
- if( evt.type == 'load' ){
235
- var binaryString = evt.result;
236
- var oFile = new BinaryFile(binaryString, 0, file.size);
237
- var exif = EXIF.readFromBinaryFile(oFile);
238
- callback(false, { 'exif': exif || {} });
239
- }
240
- else if( evt.type == 'error' ){
241
- callback('read_as_binary_string');
242
- }
243
- else if( evt.type == 'progress' ){
244
- // ...
245
- }
246
- });
247
- });
248
- ```
249
-
250
-
251
- <a name="filterFiles"></a>
252
- ### FileAPI.filterFiles
253
- ```js
254
- FileAPI.filterFiles(files, function (file, info){
255
- if( /image/.test(file.type) && info ){
256
- return info.width > 320 && info.height > 240;
257
- }
258
- return file.size < 10 * FileAPI.MB;
259
- }, function (result, ignor){
260
- // ...
261
- });
262
- ```
263
-
264
-
265
- <a name="readAs"></a>
266
- ### FileAPI.readAsImage, FileAPI.readAsDataURL (FileAPI.readAsBinaryString)
267
- ```js
268
- FileAPI.readAsImage(file, function (evt){
269
- if( evt.type == 'load' ){
270
- var images = document.getElementById('images');
271
- images.appendChild(evt.result);
272
- }
273
- else {
274
- // ...
275
- }
276
- });
277
-
278
-
279
- FileAPI.readAsDataURL(file, function (evt){
280
- if( evt.type == 'load' ){
281
- // success
282
- var result = evt.result;
283
- }
284
- else if( evt.type == 'progress' ){
285
- var pr = evt.loaded/evt.total * 100;
286
- }
287
- else {
288
- // error
289
- }
290
- });
291
- ```
292
-
293
-
294
- <a name="upload"></a>
295
- ### FileAPI.upload
296
- ```js
297
- var xhr = FileAPI.upload({
298
- url: '...',
299
- data: { foo: 'bar' },
300
- headers: { 'x-header': '...' },
301
- files: {
302
- images: FileAPI.filter(files, function (file){ return /image/.test(file.type); }),
303
- customFile: { file: 'generate.txt', blob: customFileBlob }
304
- },
305
-
306
- chunkSize: 0, // or chunk size in bytes, eg: FileAPI.MB*.5 (html5)
307
- chunkUploadRetry: 0, // number of retries during upload chunks (html5)
308
-
309
- imageTransform: {
310
- maxWidth: 1024,
311
- maxHeight: 768
312
- },
313
- imageAutoOrientation: true,
314
- prepare: function (file, options){
315
- // prepare options for current file
316
- options.data.filename = file.name;
317
- },
318
- upload: function (xhr, options){
319
- // start uploading
320
- },
321
- fileupload: function (xhr, options){
322
- // start file uploading
323
- },
324
- fileprogress: function (evt){
325
- // progress file uploading
326
- var filePercent = evt.loaded/evt.total*100;
327
- },
328
- filecomplete: function (err, xhr){
329
- if( !err ){
330
- var response = xhr.responseText;
331
- }
332
- },
333
- progress: function (evt){
334
- // total progress uploading
335
- var totalPercent = evt.loaded/evt.total*100;
336
- },
337
- complete: function (err, xhr){
338
- if( !err ){
339
- // Congratulations, the uploading was successful!
340
- }
341
- }
342
- });
343
- ```
344
-
345
-
346
- <a href="imageTransform"></a>
347
- ### imageTransform
348
- * width`:Number`
349
- * height`:Number`
350
- * preview`:Boolean`
351
- * maxWidth`:Number`
352
- * maxHeight`:Number`
353
- * rotate`:Number`
354
- ```js
355
- FileAPI.upload({
356
- // ..
357
- imageOriginal: false, // don't send original on server
358
-
359
- imageTransform: {
360
- // (1) Resize to 120x200
361
- resize: { width: 120, height: 200 }
362
-
363
- // (2) create preview 320x240
364
- thumb: { width: 320, height: 240, preview: true }
365
-
366
- // (3) Resize by max side
367
- max: { maxWidth: 800, maxHeight: 600 }
368
-
369
- // (4) Custom resize
370
- custom: function (info, transform){
371
- return transform
372
- .crop(100, 100, 300, 200)
373
- .resize(100, 50)
374
- ;
375
- }
376
- }
377
- });
378
- ```
379
-
380
-
381
- <a name="imageAutoOrientation"></a>
382
- ### imageAutoOrientation
383
- ```js
384
- // (1) all images
385
- FileAPI.upload({
386
- // ..
387
- imageAutoOrientation: true
388
- });
389
-
390
- // (2) or so
391
- FileAPI.upload({
392
- // ..
393
- imageAutoOrientation: true,
394
- imageTransform: { width: .., height: .. }
395
- });
396
-
397
- // (3) or so
398
- FileAPI.upload({
399
- // ..
400
- imageTransform: { rotate: 'auto' }
401
- });
402
-
403
- // (4) only "800x600", original not modified
404
- FileAPI.upload({
405
- // ..
406
- imageTransform: {
407
- "800x600": { width: 800, height: 600, rotate: 'auto' }
408
- }
409
- });
410
- ```
411
-
412
-
413
- -----
414
-
415
-
416
- <a name="flash-settings"></a>
417
- ### Flash settings
418
- ```html
419
- <script>
420
- var FileAPI = {
421
- // @required
422
- staticPath: '/js/' // @default: "./"
423
-
424
- // @optional
425
- , flashUrl: '/js/FileAPI.flash.swf' // @default: FileAPI.staticPath + "FileAPI.flash.swf"
426
- , flashImageUrl: '/js/FileAPI.flash.image.swf' // @default: FileAPI.staticPath + "FileAPI.flash.image.swf"
427
- };
428
- </script>
429
- <script src="/js/FileAPI.min.js"></script>
430
- ```
431
-
432
- #### Flash-request ([FileReference](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/FileReference.html))
433
- The following sample HTTP POST request is sent from Flash Player to a server-side script if no parameters are specified:
434
- ```
435
- POST /handler.cfm HTTP/1.1
436
- Accept: text/*
437
- Content-Type: multipart/form-data;
438
- boundary=----------Ij5ae0ae0KM7GI3KM7
439
- User-Agent: Shockwave Flash
440
- Host: www.example.com
441
- Content-Length: 421
442
- Connection: Keep-Alive
443
- Cache-Control: no-cache
444
-
445
- ------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
446
- Content-Disposition: form-data; name="Filename"
447
-
448
- MyFile.jpg
449
- ------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
450
- Content-Disposition: form-data; name="Filedata"; filename="MyFile.jpg"
451
- Content-Type: application/octet-stream
452
-
453
- FileDataHere
454
- ------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
455
- Content-Disposition: form-data; name="Upload"
456
-
457
- Submit Query
458
- ------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7--
459
- ```
460
-
461
-
462
-
463
- -----
464
-
465
-
466
-
467
- <a name="chunked"></a>
468
- ### Chunked file upload (html5)
469
- ```js
470
- FileAPI.upload({
471
- url: '...'
472
- , files: fileList
473
- , chunkSize: .5 * FileAPI.MB // 512KB
474
- , chunkUploadRetry: 1
475
- , complete: function (err, xhr){}
476
- });
477
- ```
478
-
479
- Client and server communicate to each other using the following HTTP headers and status codes.
480
-
481
- Client explicitly sets the following headers:
482
- * [Content-Range](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16): bytes \<start-offset\>-\<end-offset\>/\<total\>
483
- * [Content-Disposition](http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1): attachment; filename=\<file-name\>
484
-
485
- Any other headers are set by a target browser and are not used by client.
486
- Library does not provide any facilities to track a file uniqueness across requests, it's left on developer's consideration.
487
-
488
- Client recognizes the following response codes:
489
- * 200, 201 - chunk is successfully saved
490
- * 416, 500 - recoverable error, library tries to resend chunk 'chunkUploadRetry' times then fails
491
-
492
- All the other codes - fatal error, user's involvement is recommend.
493
-
494
-
495
- -----
496
-
497
-
498
-
499
- ### File object (https://developer.mozilla.org/en/DOM/File)
500
- ```js
501
- {
502
- name: 'fileName',
503
- type: 'mime-type',
504
- size: 'fileSize'
505
- }
506
- ```
507
-
508
-
509
- ### XMLHttpRequest
510
- ```js
511
- {
512
- status: Number,
513
- statusText: Number,
514
- readyState: Number,
515
- response: Blob,
516
- responseXML: XML,
517
- responseText: String,
518
- responseBody: String,
519
- getResponseHeader: function (name/**String*/)/**String*/{},
520
- getAllResponseHeaders: function ()/**Object*/{},
521
- abort: function (){}
522
- }
523
- ```
524
-
525
-
526
- ### Cross-Domain upload-controller headers
527
- ```php
528
- <?
529
- header('Access-Control-Allow-Methods: POST, OPTIONS');
530
- header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Range, Content-Disposition, Content-Type'); // and other custom headers
531
- header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']); // a comma-separated list of domains
532
-
533
- if( $_SERVER['REQUEST_METHOD'] == 'OPTIONS' ){
534
- exit;
535
- }
536
-
537
- if( $_SERVER['REQUEST_METHOD'] == 'POST' ){
538
- // ...
539
- }
540
- ?>
541
- ```
542
-
543
-
544
- ### iframe
545
- #### POST-query
546
- ```
547
- /controller.php
548
- ?foo=bar
549
- &images=...
550
- &callback=...
551
- ```
552
-
553
-
554
- #### POST-response
555
- ```php
556
- <script type="text/javascript">
557
- (function (ctx, jsonp){
558
- if( ctx && ctx[jsonp] ){
559
- ctx[jsonp](<?=$statusCode/*200 — OK*/?>, "<?=addslashes($statusText)?>", "<?=addslashes($response)?>");
560
- }
561
- })(this.parent, "<?=htmlspecialchars($_POST['callback'])?>");
562
- </script>
563
- ```
564
-
565
-
566
-
567
- ---
568
-
569
-
570
-
571
- ### HTML structure (templates)
572
-
573
- <a name="html-default"></a>
574
- ### Default
575
- ```html
576
- <span class="js-fileapi-wrapper" style="position: relative; display: inline-block;">
577
- <input name="files" type="file" multiple />
578
- </span>
579
- ```
580
-
581
-
582
- <a name="html-button"></a>
583
- ### Button
584
- ```html
585
- <style>
586
- .upload-btn {
587
- width: 130px;
588
- height: 25px;
589
- overflow: hidden;
590
- position: relative;
591
- border: 3px solid #06c;
592
- border-radius: 5px;
593
- background: #0cf;
594
-
595
- }
596
- .upload-btn:hover {
597
- background: #09f;
598
- }
599
- .upload-btn__txt {
600
- z-index: 1;
601
- position: relative;
602
- color: #fff;
603
- font-size: 18px;
604
- font-family: "Helvetica Neue";
605
- line-height: 24px;
606
- text-align: center;
607
- text-shadow: 0 1px 1px #000;
608
- }
609
- .upload-btn__inp {
610
- top: -10px;
611
- right: -40px;
612
- z-index: 2;
613
- position: absolute;
614
- cursor: pointer;
615
- opacity: 0;
616
- filter: alpha(opacity=0);
617
- font-size: 50px;
618
- }
619
- </style>
620
- <div class="upload-btn js-fileapi-wrapper">
621
- <div class="upload-btn__txt">Upload files</div>
622
- <input class="upload-btn__inp" name="files" type="file" multiple />
623
- </div>
624
- ```
625
-
626
-
627
- <a name="html-link"></a>
628
- ### Link
629
- ```html
630
- <style>
631
- .upload-link {
632
- color: #36c;
633
- display: inline-block;
634
- *zoom: 1;
635
- *display: inline;
636
- overflow: hidden;
637
- position: relative;
638
- padding-bottom: 2px;
639
- text-decoration: none;
640
- }
641
- .upload-link__txt {
642
- z-index: 1;
643
- position: relative;
644
- border-bottom: 1px dotted #36c;
645
- }
646
- .upload-link:hover .upload-link__txt {
647
- color: #f00;
648
- border-bottom-color: #f00;
649
- }
650
-
651
- .upload-link__inp {
652
- top: -10px;
653
- right: -40px;
654
- z-index: 2;
655
- position: absolute;
656
- cursor: pointer;
657
- opacity: 0;
658
- filter: alpha(opacity=0);
659
- font-size: 50px;
660
- }
661
- </style>
662
- <a class="upload-link js-fileapi-wrapper">
663
- <span class="upload-link__txt">Upload photo</span>
664
- <input class="upload-link__inp" name="photo" type="file" accept=".jpg,.jpeg,.gif" />
665
- </a>
666
- ```
667
-
668
-
669
- ---
670
-
671
-
672
- ## Changelog
673
- ### 1.2.5
674
- * [#86](https://github.com/mailru/FileAPI/issues/86): Smarter upload recovery
675
- * [#87](https://github.com/mailru/FileAPI/issues/87): Fixed upload files into browsers that do not support FormData
676
- * Fixed support "accept" attribute for Flash.
677
- * Fixed detection of HTML5 support for FireFox 3.6
678
- * + FileAPI.html5 option, default "true"
679
-
680
-
681
- ### 1.2.4
682
- * Fixed auto orientation image by EXIF (Flash)
683
- * Fixed image dimensions after rotate (Flash)
684
- * [#82](https://github.com/mailru/FileAPI/issues/82): "undefined" data-fields cause exceptions
685
- * [#83](https://github.com/mailru/FileAPI/issues/83): Allow requests without files
686
- * [#84](https://github.com/mailru/FileAPI/pull/84): Fixed connection abort when waiting for connection recovery
687
-
688
-
689
- ### 1.2.3
690
- * [#77](https://github.com/mailru/FileAPI/pull/77): Fixed flash.abort(), [#75](https://github.com/mailru/FileAPI/issues/75)
691
- * - `FileAPI.addMime`
692
- * + `FileAPI.accept` — fallback for flash.
693
-
694
-
695
- ### 1.2.2
696
- * [#67](https://github.com/mailru/FileAPI/pull/67): Added correct httpStatus for upload fail, [#62](https://github.com/mailru/FileAPI/pull/68)
697
- * [#68](https://github.com/mailru/FileAPI/pull/68) Added "Content-Type" for chunked upload, [#65](https://github.com/mailru/FileAPI/pull/65)
698
- * [#69](https://github.com/mailru/FileAPI/issues/69): Fixed network down recovery
699
- * Fixed progress event, [#66](https://github.com/mailru/FileAPI/issues/66)
700
- * Increase flash stage size, [#73](https://github.com/mailru/FileAPI/pull/73)
701
- * - array index from POST-param "name", [#72](https://github.com/mailru/FileAPI/issues/72)
702
- * - dependency on FileAPI.Image for FileAPI.Flash
703
-
704
-
705
- ### 1.2.1
706
- * [#64](https://github.com/mailru/FileAPI/issues/64): Bufixed for [#63](https://github.com/mailru/FileAPI/issues/63)
707
-
708
-
709
-
710
- ### 1.2.0
711
- * [#57](https://github.com/mailru/FileAPI/issues/57): Chunked file upload
712
-
713
-
714
- ### 1.1.0
715
- * [#54](https://github.com/mailru/FileAPI/issues/54): added `FileAPI.flashUrl` and `FileAPI.flashImageUrl`
716
-
717
-
718
- ### 1.0.1
719
- * [#51](https://github.com/mailru/FileAPI/issues/51): remove circular references from `file-objects` (Flash transport)
720
- * added `changelog`
721
-
722
-
723
- ### 1.0.0
724
- * first release