source: trunk/prototype/api/datalayer.js @ 5724

Revision 5724, 121.9 KB checked in by acoutinho, 12 years ago (diff)

Ticket #2434 - Correcao no envio de alarmes javascript e email

  • Property svn:executable set to *
Line 
1internalUrl = /^([A-z0-9-_]+)(:[A-z0-9-_]+)?$/;
2internalUri = /^([a-zA-Z0-9-_]+)\(([a-zA-Z0-9-_]+)\):\/\/(.*)|([a-zA-Z0-9-_]+):\/\/(.*)$/;
3isGeneratedId = /^\d+\(javascript\)$/;
4arrayName = /^([A-z0-9-_]+)\[\]$/;
5startsDoubleDot = /^:/;
6isIframe = /^iframe.*/;
7FILE = 'files';
8// cached_urls = {};
9
10$.ajaxPrefilter(function( options, originalOptions, jqXHR ){
11
12      if( options.url != 'undefined' && internalUrl.test( options.url ) ){
13
14//        if( !cached_urls[options.url] )
15//            return;
16//        alert( options.url + " dentro" );
17
18           var callback = ( options.success || options.complete || $.noop );
19
20          if( isIframe.test( options.dataType ) || options.data instanceof FormData )
21          {
22              options.url = options.fileInput.parents( 'form' ).attr( 'action' );
23           
24              res = internalUrl.exec( options.url );
25
26              var data = {};
27
28              data[ res[1] ] = DataLayer.form( options.fileInput.parents( 'form' ), options.fileInput );
29
30              options.formData = DataLayer.serializeForm( data );
31
32              callback = function( data ){
33
34                    //coutinho, escreva seu codigo aqui.
35
36                    return callback( DataLayer.encode( res[2], data ) );
37
38              }
39
40              options.url = DataLayer.dispatchPath + 'post.php';
41
42              if( options.data instanceof FormData )
43              {
44                  options.data = new FormData();
45
46                  $.each(options.formData, function (index, field) {
47                            options.data.append(field.name, field.value);
48                        });
49                 
50                  $.each(options.files, function (index, file) {
51                            options.data.append(options.paramName, file);
52                        });
53              }
54
55              return( true );
56          }
57
58          jqXHR.abort();
59
60          switch( options.type.toUpperCase() )
61          {
62            case 'GET':
63                  return callback( DataLayer.get( options.url, /*false,*/ options.data ) );
64
65            case 'POST':
66                  return callback( DataLayer.put( options.url, options.data ) );
67          }
68
69          //return( false );
70
71//        options.url = params[1];
72//        options.data = ( options.data || "" ) + "&" + params[2];
73      }
74
75});
76
77// $("a").live("click", function( event ){
78//
79//     event.preventDefault();
80//
81//     $.ajax({
82//
83//     
84//
85//     });
86//
87// });
88
89$("form").live( "submit", function( event ){
90
91    var $this = $(this), action = $this.attr('action'), res = false,
92   
93    method = $this.attr( 'method' ) || 'POST',
94   
95    fileInputs = $this.find('input[type="file"]');
96   
97    if( fileInputs.length && !$this.is('[enctype="multipart/form-data"]') )
98    {
99        event.preventDefault();
100
101        DataLayer.send( action,
102                        [ method, 'iframe json' ], {},
103                        //TODO: check the type for conversion
104                        DataLayer.receive,
105                        false, { 'formData': $this.serializeArray(),  'fileInput': fileInputs, 'paramName': FILE + '[]' } );
106
107        return( false );
108    }
109   
110    if( res = internalUrl.exec( action ) )
111    {
112        event.preventDefault();
113
114        var data = DataLayer.form( this );
115       
116        switch( method.toUpperCase() )
117        {
118          case 'GET':
119                DataLayer.get( res[0], data );
120
121          case 'POST':
122                DataLayer.put( res[1], data );
123        }
124
125        return( false );
126    }
127
128    return( true );
129});
130
131this.storage = new $.store();
132
133DataLayer = {
134
135    links: {},
136    nestedLinks: {},
137    concepts: {},
138    notArray: {},
139    listeners: {},
140    encoders: {},
141    decoders: {},
142    templates: {},
143    criterias: {},
144    tasks: {},
145
146    render: function( templateName, data, filter, formatter, force ){
147
148        if( $.isFunction( filter ) )
149        {
150            force = formatter;
151            formatter = filter;
152            filter = false;
153        }
154
155        if( typeof data === "string" )
156        {
157            data = this.get( data, filter, force ) || {};
158        }
159       
160        var formatting = function( template ){
161
162              if( template === false ) return( false );
163
164              if( template )
165                  DataLayer.templates[ templateName ] = new EJS({ text: template, cache: false });
166
167              var html = DataLayer.templates[ templateName ].render( { data: data } );
168
169              if( !formatter )
170                  return( html );
171
172              return formatter( html );
173        }
174
175        if( this.templates[ templateName ] )
176        {
177            return formatting();
178        }
179
180        return this.send( DataLayer.templatePath + templateName, 'get', false, formatting, !!!formatter );
181    },
182   
183    send: function( url, type, data, callback, sync, extraOptions ){
184     
185          var result = false, fired = false;
186     
187          var envelope = {
188
189              'async': ( typeof sync !== "undefined" ? !sync : !!callback ),
190              'url': url,
191              'success': function( dt, textStatus, jqXHR ){
192
193                    if( callback )
194                    {
195                        fired = true;
196                        result = callback( dt, textStatus, jqXHR );
197                    }
198                    else
199                        result = dt;
200
201                },
202              'complete': function( jqXHR, textStatus ){
203
204                  if( !fired && callback )
205                      result = callback( false, textStatus, jqXHR );
206
207              },
208
209              'type': $.isArray( type ) ? type[0] : type,
210              'data': data
211
212            };
213
214          if( $.isArray( type ) && type[1] )
215              envelope['dataType'] = type[1];
216
217          if( extraOptions )
218              envelope = $.extend( envelope, extraOptions );
219
220          $.ajax( envelope );
221     
222          return( result );
223    },
224   
225    dispatch: function( dispatcher, data, callback, isPost, dataType ){
226     
227      return this.send( this.dispatchPath + dispatcher + ".php",
228                        [ ( isPost ? 'post' : 'get' ), dataType || 'json' ],
229                        data,
230                        callback );
231
232//       $.ajax({
233//            'async': !!callback,
234//            'url': this.dispatchPath + dispatcher + ".php",
235//            'type': ( isPost ? 'post' : 'get' ),
236//            'dataType': 'json',
237//            'data': data,
238//            'success': function( dt, textStatus, jqXHR ){
239//
240//                  if( callback )
241//                  {
242//                      fired = true;
243//                      callback( dt, textStatus, jqXHR );
244//                  }
245//                  else
246//                      result = dt;
247//
248//              },
249//            'complete': function( jqXHR, textStatus ){
250//
251//                if( !fired && callback )
252//                    callback( false, textStatus, jqXHR );
253//
254//            }/*,
255//            'processData': false*/
256//        });
257
258      //return( result );
259    },
260
261    form: function( target, fileInputs ){
262
263        var params = {}, $this = $(target), inputArray = $this.serializeArray();
264
265        if( !$this.is( "form" ) )
266            $this = $this.parents( "form" );
267               
268        if( fileInputs )
269                fileInputs.each( function( i, el ){
270
271              inputArray[ inputArray.length ] = { name: $(this).prop("name"), value: FILE + i };
272
273                });
274
275        $.each( inputArray, function( i, el ){
276
277            if( newName = arrayName.exec( el.name ) )
278                el.name = newName[1];
279            else if( !params[ el.name ] )
280                return( params[ el.name ] = el.value );
281
282            params[ el.name ] = params[ el.name ] || [];
283
284            if( $.type(params[ el.name ]) !== "array" )
285                params[ el.name ] = [ params[ el.name ] ];
286
287            params[ el.name ].push( el.value );
288        });
289
290//      alert(dump(params));
291
292        return this.decode( $this.attr( "action" ), params );
293    },
294       
295        serializeForm: function( data, level ){
296       
297                var formData = [];
298       
299                for( key in data )
300                {
301                        var value = data[key];
302
303                        if( level !== undefined )
304                                key = level+'['+key+']';
305
306                        if( $.isArray(value) || $.isPlainObject(value) )
307                                formData = formData.concat( this.serializeForm( value, key ) );
308                        else
309                                formData[ formData.length ] = { name: key, value: value };
310                }
311               
312                return( formData );
313        },
314
315    blend: function( action, data ){
316
317//      if( notArray = (!$.isArray(data)) )
318//          data = [ data ];
319
320        var form = $('form[action="'+action+'"]');
321
322        form.get(0).reset();
323
324        var named = form.find( 'input[name]' );
325
326        for( var name in data )
327        {
328            named.filter( '[name="'+name+'"]' ).val( data[name] );
329        }
330    },
331
332 
333   
334    put: function( concept, filter, data, oneSide ){
335     
336      ///////////////////////////// normalize ////////////////////////////////
337        if( arguments.length == 2 )
338        {
339            data = filter;
340            filter = false;
341        }
342        if( typeof data === "undefined" ||
343            $.type(data) === "boolean" )
344        {
345            oneSide = data;
346            data = filter;
347            filter = false;
348        }
349       
350        if( !concept || !data )
351            return( false );
352
353        var decoder = "", id = false, bothSides = (typeof oneSide === "undefined"), notArray, res;
354       
355        if( $.type(filter) === "string" )
356        {
357            id = filter;
358            filter = false;
359        }
360
361        if( id )
362            data.id = id;
363
364        if( notArray = ( $.type( data ) !== "array" ) )
365            data = [ data ];
366
367        if( res = internalUrl.exec( concept ) )
368        {
369            //TODO: verificar se a decodificaçao deve ser feita em cada item do array
370            data = this.decode( concept, data );
371            concept = res[1];
372            decoder = res[2];
373        }
374
375      ////////////////////////////////////////////////////////////////////////
376
377        if( bothSides || !oneSide )
378        {
379            var result = false, links = this.links( concept ), nestedLinks = this.links( concept, true ),
380            current = this.check( concept ) || {}, ids = [];
381
382            for( var i = 0; i < data.length; i++ )
383            {
384                var key = ids[ ids.length ] = data[i].id || this.generateId( concept ), updateSet = {};
385
386                ////////////////////////////// linkage /////////////////////////////////   
387                for( var link in links )
388                {
389                    if( data[i][link] )
390                    {
391                        var notArray2 = false;
392
393                        if( notArray2 = this.hasOne( concept, link ) )
394                            data[i][link] = [ data[i][link] ];
395
396                        var _this = this, dependency = this.isDependency( concept, link );
397
398                        $.each( data[i][link], function( ii, el ){
399
400                                var isRef = false;
401
402                                if( isRef = ($.type(el) === "string") )
403                                    el = { id: el };
404
405                                //removido pois o mesmo esta gerando inconsistencia em tudo
406//                              if( DataLayer.isConcept( links[link], nestedLinks[link] ) )
407                                if( !DataLayer.hasOne( links[link], nestedLinks[link] ) )
408                                {
409                                    el[ nestedLinks[link] ] = el[ nestedLinks[link] ] || [];
410                                    el[ nestedLinks[link] ].push( key );
411                                }
412                                else
413                                    el[ nestedLinks[link] ] = key;
414
415                                if( isRef && ( !current[ key ] || !current[ key ][ link ] ||
416                                               (notArray2 ? current[ key ][ link ] !== el.id : !$.inArray( el.id, current[ key ][ link ] )) ) )
417                                {
418                                    updateSet[ links[link] ] = updateSet[ links[link] ] || [];
419                                    updateSet[ links[link] ].push( el );
420                                }
421                                else if( !isRef )
422                                    data[i][link][ii] = _this.put( links[link], el, oneSide );
423                            });
424
425                        if( notArray2 )
426                            data[i][link] = data[i][link][0];
427                    }
428                }
429                //////////////////////////////////////////////////////////////////////////
430
431                if( data[i].id )
432                    data[i] = this.merge( current[ data[i].id ], data[i] );
433
434                 current[ key ] = data[i];
435
436                if( bothSides )
437                  this.report( concept, key, data[i] );
438            }
439
440            this.store( concept, current );
441
442            for( var setKey in updateSet )
443            {
444                if( bothSides )
445                    for( var i = 0; i < updateSet[ setKey ].length; i++ )
446                      this.report( setKey, updateSet[ setKey ][i].id, updateSet[ setKey ][i] );
447                   
448                DataLayer.put( setKey, updateSet[ setKey ], false );
449            }
450        }
451
452        if( oneSide )
453            this.commit( concept, ids/*, true */);
454
455        this.broadcast( concept, oneSide ? 'server' : bothSides ? 'serverclient' : 'client', true );
456
457        return( notArray ? ids[0] : ids );
458
459    },
460   
461    remove: function( concept, id, oneSide ){
462     
463        var bothSides = (typeof oneSide === "undefined"),
464
465        links = this.links( concept ), nestedLinks = this.links( concept, true ), ids = [],
466
467        current = this.check( concept, id );
468
469        if( !current ) return;
470       
471        if( typeof id === "string" )
472            current.id = id;
473
474        if( notArray = ( $.type( current ) !== "array" ) )
475            current = [ current ];
476
477        for( var i = 0; i < current.length; i++ )
478        {
479            var currentId = ids[ ids.length ] = current[i].id;
480
481            if( bothSides )
482              this.report( concept, currentId, false );
483
484            if( bothSides || !oneSide )
485              this.del( concept, currentId );
486
487            for( var link in links )
488            {
489                if( !current[i][link] )
490                    continue;
491
492                if( this.hasOne( concept, link ) )
493                    current[i][link] = [ current[i][link] ];
494
495                $.each( current[i][link], function( ii, el ){
496
497                        el = DataLayer.storage.cache[links[link]][el];
498
499                        if( notArrayNested = ( $.type( el[ nestedLinks[link] ] ) !== "array" ) )
500                            el[ nestedLinks[link] ] = [ el[nestedLinks[link]] ];
501
502                        el[ nestedLinks[link] ] = $.grep( el[ nestedLinks[link] ], function( nested, iii ){
503                            return ( currentId !== nested );
504                        });
505
506                        if( notArrayNested )
507                            el[ nestedLinks[link] ] = el[ nestedLinks[link] ][0] || false;
508                        if(!el[ nestedLinks[link] ] || !el[ nestedLinks[link] ].length)
509                                delete el[ nestedLinks[link] ];
510                });
511            }
512        }
513
514        if( oneSide )
515            this.commit( concept, ids );
516
517        this.broadcast( concept, oneSide ? 'server' : bothSides ? 'serverclient' : 'client', false );
518    },
519   
520    report: function( concept, id, data )
521    {     
522        var current = this.check( ':current', concept ) || {};
523
524        if( !current[ id ] )
525            current[ id ] = this.check( concept, id ) || {};
526       
527        this.store( ':current', concept, current );
528
529        var diff = this.diff( current[ id ], data );
530
531        var diffs = this.check( ':diff', concept ) || {};
532
533        if( diffs[ id ] )
534            diff = this.merge( diffs[ id ], diff );
535
536        if( !diff || !$.isEmptyObject( diff ) )
537            diffs[ id ] = diff;
538
539        this.store( ':diff', concept, diffs );
540    },
541
542//     enqueue: function( queueName, concept, id, data ){
543//
544//      var queue = this.check( ':' + queueName, concept ) || {};
545//
546//
547//     },
548//     
549//     dequeue: function( queueName, concept, id ){
550//
551//     
552//
553//     },
554   
555   
556   
557    rollback: function( concept, ids ){
558     
559        var queue = this.prepareQ( 'current', concept, ids );
560
561        ids = [];
562
563        for( var id in queue )
564        {
565             this.put( concept, id, queue[id], false );
566
567             ids[ ids.length ] = id;
568        }
569
570        this.clearQ( concept, ( ids.length ? ids : false ) );
571
572        this.broadcast( concept, 'revert' );
573     
574    },
575   
576    prepareQ: function( queueName, concept, ids ){
577     
578      var notArray = false;
579     
580      if( notArray = ($.type(concept) !== "array") )
581          concept = [ concept ];
582     
583      var q = {};
584     
585      for( var i = 0; i < concept.length; i++ )
586      {
587          var queue = this.check( ':' + queueName, concept[i] || false );
588         
589          if( !queue ) continue;
590
591          if( ids )
592          {
593              if( $.type(ids) !== "array" )
594                  ids = [ ids ];
595
596              var filtered = {};
597
598              for( var ii = 0; ii < ids.length; ii++ )
599              {
600                  filtered[ ids[ii] ] = queue[ ids[ii] ];
601              }
602
603              queue = filtered;
604          }
605
606          q[ concept[i] ] = queue;
607      }
608     
609      return( notArray ? q[ concept[0] ] : q );
610    },
611   
612    clearQ: function( concept, ids ){
613     
614        var current = this.check( ':current', concept || false );
615        var diffs = this.check( ':diff', concept || false );
616
617        if( !ids )
618            current = diffs = {};
619        else
620        {
621            if( notArray = ($.type(ids) !== "array") )
622              ids = [ ids ];
623
624            for( var i = 0; i < ids.length; i++ )
625            {
626                delete current[ ids[i] ];
627                delete diffs[ ids[i] ];
628            }
629        }
630
631        this.store( ':current', concept, current );
632        this.store( ':diff', concept, diffs );
633    },
634
635    commit: function( concept, ids, callback ){
636     
637        var queue = this.prepareQ( 'diff', concept, ids );
638
639        this.sync( queue, !$.isArray(concept) && concept || false, callback );
640    },
641   
642    sync: function( queue, concept, callback ){
643
644        if( !queue || $.isEmptyObject( queue ) )
645            return;
646
647        if( concept )
648        {
649          var helper = {};
650          helper[concept] = queue;
651          queue = helper;
652        }
653
654        var data = {}, URIs = {};
655
656        for( var concept in queue )
657            for( var id in queue[concept] )
658            {
659                data[ this.URI( concept, id ) ] = queue[concept][id];
660                URIs[ this.URI( concept, id ) ] = { concept: concept, id: id };
661            }
662
663        if( $.isEmptyObject( data ) )
664            return;
665
666        this.dispatch( "Sync", data, function( data, status, jqXHR ){
667
668//          switch( status )
669//          {
670//            case "error":
671//            case "parsererror":
672//              return DataLayer.rollback( concept, URI );
673//            case "success":
674//              return DataLayer.commit();
675//            case "timeout":
676//            case "notmodified":
677//          }
678
679            var received = DataLayer.receive( data );
680
681            for( var URI in URIs )
682                if( typeof received[URI] !== "undefined" )
683                    DataLayer.clearQ( URIs[URI].concept, URIs[URI].id );
684
685            if( callback )
686                callback( received );
687
688//          for( var URI in data )
689//          {
690//              var parsed = DataLayer.parseURI( URI ),
691//   
692//              concept = parsed[1], id = parsed[3];
693//
694//              if( $.type(data[URI]) === "string" )
695//              {
696//                //TODO:threat the exception thrown
697//                DataLayer.rollback( concept, id );
698//                delete URIs[ URI ];
699//                continue;
700//              }
701//
702//              if( data[URI] === false ){
703//                DataLayer.remove( concept, id, false );
704//                continue;
705//              }
706//
707//              if( id !== data[URI].id )
708//                DataLayer.move( concept, id, data[URI].id );
709//             
710//              DataLayer.put( concept, id, data[URI], false );
711//          }
712//         
713//          for( var URI in URIs )
714//               DataLayer.clearQ( URIs[URI].concept, URIs[URI].id );
715//         
716//          if( callback )
717//              callback();
718
719        }, true );
720
721    },
722   
723    receive: function( data ){
724     
725        var received = {};
726       
727            for( var URI in data )
728            {
729                var parsed = DataLayer.parseURI( URI ),
730   
731            concept = parsed[4], id = parsed[5];
732
733            received[ URI ] = data[ URI ];
734
735                if( $.type(data[URI]) === "string" )
736                {
737                  //TODO:threat the exception thrown
738                  DataLayer.rollback( concept, id );
739                  continue;
740                }
741
742                if( data[URI] === false ){
743                  DataLayer.remove( concept, id, false );
744                  continue;
745                }
746
747                if( id !== data[URI].id )
748                  DataLayer.move( concept, id, data[URI].id );
749               
750                DataLayer.put( concept,  data[URI].id || id, data[URI], false );
751            }
752           
753        return( received );
754           
755    },
756   
757    unique: function( origArr ){
758
759        var newArr = [];
760     
761        for ( var x = 0; x < origArr.length; x++ )
762        {
763                var found = false;
764            for ( var y = 0; !found && y < newArr.length; y++ )
765                if ( origArr[x] === newArr[y] ) 
766                  found = true;
767
768            if ( !found )
769                newArr[ newArr.length ] = origArr[x];
770        }
771
772        return newArr;
773    },
774
775    merge: function( current, data ){
776     
777        return this.copy(  data, current );
778
779//      return $.extend( current, data );
780
781    },
782   
783    // clone objects, skip other types.
784    clone: function(target) {
785            if ( typeof target == 'object' ) {
786                    Clone.prototype = target;
787                    return new Clone();
788            } else {
789                    return target;
790            }
791    },
792     
793    // Shallow Copy
794    shallowCopy: function(target) {
795            if (typeof target !== 'object' ) {
796                    return target;  // non-object have value sematics, so target is already a copy.
797            } else {
798                    var value = target.valueOf();
799                    if (target != value) {
800                            // the object is a standard object wrapper for a native type, say String.
801                            // we can make a copy by instantiating a new object around the value.
802                            return new target.constructor(value);
803                    } else {
804                            // ok, we have a normal object. If possible, we'll clone the original's prototype
805                            // (not the original) to get an empty object with the same prototype chain as
806                            // the original.  If just copy the instance properties.  Otherwise, we have to
807                            // copy the whole thing, property-by-property.
808                            if ( target instanceof target.constructor && target.constructor !== Object ) {
809                                    var c = clone(target.constructor.prototype);
810     
811                                    // give the copy all the instance properties of target.  It has the same
812                                    // prototype as target, so inherited properties are already there.
813                                    for ( var property in target) {
814                                            if (target.hasOwnProperty(property)) {
815                                                    c[property] = target[property];
816                                            }
817                                    }
818                            } else {
819                                    var c = {};
820                                    for ( var property in target ) c[property] = target[property];
821                            }
822                           
823                            return c;
824                    }
825            }
826    },
827
828    // entry point for deep copy.
829    // source is the object to be deep copied.
830    // depth is an optional recursion limit. Defaults to 256.
831    // deep copy handles the simple cases itself: non-objects and object's we've seen before.
832    // For complex cases, it first identifies an appropriate DeepCopier, then delegate the details of copying the object to him.
833    copy: function(source, result, depth) {
834     
835            // null is a special case: it's the only value of type 'object' without properties.
836            if ( source === null ) return null;
837
838            // All non-objects use value semantics and don't need explict copying.       
839                if ( typeof source !== 'object' ) return source;
840
841            if( !depth || !(depth instanceof RecursionHelper) ) depth = new RecursionHelper(depth);
842
843            var cachedResult = depth.getCachedResult(source);
844
845            // we've already seen this object during this deep copy operation
846            // so can immediately return the result.  This preserves the cyclic
847            // reference structure and protects us from infinite recursion.
848            if ( cachedResult ) return cachedResult;
849
850            // objects may need special handling depending on their class.  There is
851            // a class of handlers call "DeepCopiers"  that know how to copy certain
852            // objects.  There is also a final, generic deep copier that can handle any object.
853            for ( var i=0; i<this.comparators.length; i++ ) {
854
855                    var comparator = this.comparators[i];
856
857                    if ( comparator.can(source) ) {
858       
859                            // once we've identified which DeepCopier to use, we need to call it in a very
860                            // particular order: create, cache, populate.  This is the key to detecting cycles.
861                            // We also keep track of recursion depth when calling the potentially recursive
862                            // populate(): this is a fail-fast to prevent an infinite loop from consuming all
863                            // available memory and crashing or slowing down the browser.
864     
865                            if( !result )
866                                // Start by creating a stub object that represents the copy.
867                                result = comparator.create(source);
868                            else if( !comparator.can(result) )
869                                throw new Error("can't compare diferent kind of objects.");
870
871                            // we now know the deep copy of source should always be result, so if we encounter
872                            // source again during this deep copy we can immediately use result instead of
873                            // descending into it recursively. 
874                            depth.cacheResult(source, result);
875
876                            // only DeepCopier.populate() can recursively deep copy.  So, to keep track
877                            // of recursion depth, we increment this shared counter before calling it,
878                            // and decrement it afterwards.
879                            depth.depth++;
880                            if ( depth.depth > depth.maxDepth ) {
881                                    throw new Error("Exceeded max recursion depth in deep copy.");
882                            }
883
884                            // It's now safe to let the comparator recursively deep copy its properties.
885                            var returned = comparator.populate( function(source, result) { return DataLayer.copy(source, result, depth); }, source, result );
886       
887                                if(returned)
888                                        result = returned;
889
890                            depth.depth--;
891
892                            return result;
893                    }
894            }
895            // the generic copier can handle anything, so we should never reach this line.
896            throw new Error("no DeepCopier is able to copy " + source);
897    },
898
899    // publicly expose the list of deepCopiers.
900    comparators: [],
901
902    // make deep copy() extensible by allowing others to
903    // register their own custom Comparators.
904    registerComparator: function(comparatorOptions) {
905
906          // publicly expose the Comparator class.
907          var comparator = {
908
909              // determines if this Comparator can handle the given object.
910              can: function(source) { return false; },
911   
912              // starts the deep copying process by creating the copy object.  You
913              // can initialize any properties you want, but you can't call recursively
914              // into the copy().
915              create: function(source) { },
916
917              // Completes the deep copy of the source object by populating any properties
918              // that need to be recursively deep copied.  You can do this by using the
919              // provided deepCopyAlgorithm instance's copy() method.  This will handle
920              // cyclic references for objects already deepCopied, including the source object
921              // itself.  The "result" passed in is the object returned from create().
922              populate: function(deepCopyAlgorithm, source, result) {}
923          };
924
925          for ( var key in comparatorOptions ) comparator[key] = comparatorOptions[key];
926
927          this.comparators.unshift( comparator );
928    },
929 
930    diff: function( base, toDiff ){
931
932        if( typeof base === 'undefined' || $.isEmptyObject(base) )
933            return( toDiff );
934
935        if( toDiff === false )
936            return( false );
937
938        toDiff = $.extend( {}, toDiff );
939
940        for( var key in toDiff )
941        {
942            switch( $.type(toDiff[key]) )
943            {
944              case 'object':
945                if( $.isEmptyObject(toDiff[key] = this.diff( base[key], toDiff[key] )) )
946                  delete toDiff[key];
947              break;
948              case 'array':
949                if( base[key] && !(toDiff[key] = $.grep( toDiff[key], function( el, i ){ return( $.inArray( el, base[key] ) === -1 ); } )).length )
950                  delete toDiff[key];
951              break;
952              default:
953                if( base[key] == toDiff[key] )
954                  delete toDiff[key];
955            }
956        }
957
958        return( toDiff );
959
960    },
961   
962    links: function( concept, reverse ){
963
964        if( !this.links[ concept ] )
965        {
966            var result = this.dispatch( "links", { concept: concept } ) || false;
967
968            if( !result )
969                return( false );
970
971            this.concepts[ concept ] = $.extend( this.concepts[ concept ] || {},
972                                                 result['concepts'] || {} );
973
974            this.links[ concept ] =  result['links'] || {};
975           
976            this.notArray[ concept ] = result['hasOne'] || {};
977
978           this.nestedLinks[ concept ] = result['nestedLinks'] || {};
979        }
980
981        if( reverse )
982        {
983            return( this.nestedLinks[ concept ] );
984        }
985
986        return( this.links[ concept ] );
987
988    },
989   
990    isDependency: function( concept, attr ){
991     
992        if( typeof this.concepts[concept] === "undefined" )
993        {
994            this.links( concept );
995        }
996
997        return !!this.concepts[ concept ][ attr ];
998    },
999   
1000    hasOne: function( concept, attr ){
1001     
1002        if( typeof this.notArray[concept] === "undefined" )
1003        {
1004            this.links( concept );
1005        }
1006
1007        return !!this.notArray[ concept ][ attr ];
1008    },
1009   
1010    URI: function( concept, URI, context ){
1011     
1012        if( res = internalUrl.exec( concept ) )
1013            concept = res[1];
1014       
1015        context = context ? "(" + context + ")" : "";
1016     
1017        if( URI )
1018            return( concept + context + "://" + URI );
1019        else
1020            return( concept );
1021     
1022    },
1023   
1024    parseURI: function( URI ){
1025
1026        return internalUri.exec( URI ) || false;
1027
1028    },
1029   
1030   
1031   
1032   
1033    generateId: function( concept ){
1034     
1035        var newId = this.counter + "(javascript)";
1036     
1037        this.store( ":counter", (this.counter++) + "" );
1038       
1039        return( newId );
1040    },
1041   
1042
1043   
1044
1045    get: function( concept, /*URI, */filter, oneSide ){
1046
1047        ///////////////////////////// normalize ////////////////////////////////
1048        if( arguments.length == 2 && $.type(filter) === "boolean" )
1049        {
1050            oneSide = filter;
1051            filter = false;
1052        }
1053       
1054        var encoder = false, id = false, bothSides = (typeof oneSide === 'undefined'), res;
1055       
1056        if( $.type(filter) === "string" )
1057        {
1058            id = filter;
1059            filter = false;
1060        }
1061
1062        filter = filter || false;
1063
1064        if( !concept )
1065            return( false );
1066
1067        if( res = internalUrl.exec( concept ) )
1068        {
1069            encoder = concept;
1070            concept = res[1];
1071
1072            if( filter )
1073                filter = this.criteria( encoder, filter );
1074        }
1075       
1076        if ( $.type(filter) === "array" )
1077        {
1078            filter = { filter: filter, criteria: false };
1079        }
1080       
1081        //////////////////////////////////////////////////////////////////////////
1082       
1083        var result = false;
1084       
1085        if( bothSides || !oneSide )
1086            result = this.check( concept, id || filter );
1087       
1088        if (bothSides && filter.filter)
1089                result = false;
1090
1091               
1092        if( !result && (bothSides || oneSide) )
1093        {
1094            result = this.request( concept, id || filter.filter, filter.criteria );
1095
1096            if( result && bothSides && (!filter ||
1097                                        !filter.criteria ||
1098                                        !filter.criteria.format) )
1099            {
1100              var newResult = [];
1101           
1102              $.each( result, function( i, res ){
1103                        newResult[ i ] = $.extend( {}, res );
1104                  });
1105
1106              this.put( concept, id, newResult, false );
1107            }
1108        }
1109
1110        if( /*result &&*/ encoder )
1111            result = this.encode( encoder, result, filter ); //TODO: retirar o filtro no método encode
1112
1113        return( result );
1114    },
1115   
1116    filter: function( base, filter, criteria ){
1117     
1118        if( !$.isArray( filter || [] ) )
1119            filter = filter.filter || false;
1120
1121        if( !filter )
1122            return( base );
1123
1124        var filtered = [];
1125     
1126        for( var key in base )
1127            if( this.storage.filter( base[key], filter ) )
1128                filtered[ filtered.length ] = key;
1129
1130        return( filtered );
1131    },
1132
1133        converterType: function( filter ){
1134
1135                        return isNaN(parseInt(filter)) ? filter : parseInt(filter);
1136               
1137        },
1138
1139   
1140    compare: function( operator, base, test ){
1141     
1142        base = this.converterType(base);
1143        test = this.converterType(test);
1144         
1145    switch( operator ){
1146       
1147        case '*':  return RegExp( ".*" + test + ".*" ).test( base );
1148        case '^':  return RegExp( "^" + test +  ".*" ).test( base );
1149        case '$':  return RegExp( ".*"  + test + "$" ).test( base );
1150
1151        case '&':  return ( base && test );
1152        case '|':  return ( base || test );
1153
1154        case '=':  return ( base == test );
1155        case '<=': return ( base <= test );
1156        case '>=': return ( base >= test );
1157        case '>':  return ( base <  test );
1158        case '<':  return ( base >  test );
1159       
1160        default: return true;
1161        }
1162     
1163    },
1164   
1165//     clone: function( object ){
1166//
1167//      new { prototype: object };
1168//
1169//     },
1170
1171    check: function( namespace, filter ){
1172
1173        if( !namespace )
1174            return( false );
1175
1176        var result = this.storage.get( namespace );
1177
1178        if( !filter || !result )
1179          return( result || false );
1180
1181        var keys = DataLayer.copy( filter );
1182
1183        if( notArray = $.type(keys) === "string" )
1184            keys = [ keys ];
1185        else if( $.type(keys) !== "array" )
1186                keys = this.filter( result, keys.filter, keys.criteria );
1187
1188        var res = [];
1189
1190        for( var i = 0; i < keys.length; i++ )
1191            res[ res.length ] = result[keys[i]];
1192
1193        return( notArray ? res[0] || false : res.length ? res : false );
1194    },
1195
1196    storage: {
1197     
1198        cache: {},
1199     
1200        set: function( key, value ){
1201
1202            this.cache[key] = value;
1203
1204        },
1205        get: function( key ){
1206
1207            return DataLayer.copy( this.cache[key] );
1208
1209        },
1210        del: function( key ){
1211
1212            delete this.cache[key];
1213
1214        },
1215       
1216        filter: function( base, filter ){
1217     
1218            var bool, op = filter.shift();
1219
1220            switch( op )
1221            {
1222                case 'IN':
1223                  for( var i = 0, f = []; i < filter[1].length || !(filter = f); i++ )
1224                      f[i] = [ '=', filter[0], filter[1][i] ];
1225                case 'OR':
1226                    op = '|';
1227                    bool = false;
1228                break;
1229                case 'AND':
1230                    op = '&';
1231                    bool = true;
1232                break;
1233                default : return DataLayer.compare( op, base[ filter[0] ], filter[1] );
1234            }
1235           
1236            for( var strict = bool;
1237
1238                filter.length && ( strict ? bool : !bool );
1239           
1240                bool = DataLayer.compare( op, bool, this.filter( base, filter.shift() ) ) );
1241
1242            return( bool );
1243        }
1244    },
1245
1246    flush: function(){
1247
1248    },
1249   
1250    restore: function(){
1251     
1252    },
1253
1254    store: function( namespace, key, data ){
1255
1256        if( !data )
1257          return this.storage.set( namespace, key );
1258
1259        var res = this.check( namespace ) || {};
1260
1261        res[key] = data;
1262
1263        return this.storage.set( namespace, res );
1264    },
1265
1266    del: function( namespace, key ){
1267     
1268        if( !key )
1269          return this.storage.del( namespace );
1270
1271        var res = this.check( namespace ) || {};
1272
1273        delete res[key];
1274
1275        return this.storage.set( namespace, res );
1276     
1277    },
1278   
1279     move: function( concept, oldId, newId ){
1280
1281        this.put( concept, newId, this.check( concept, oldId ), false );
1282
1283        this.remove( concept, oldId, false );
1284    },
1285   
1286
1287   
1288   
1289   
1290    request: function( concept, filter, criteria ){
1291
1292      var id = false, criteria = criteria || {};
1293
1294      if( $.type(filter) === "string" )
1295      {
1296          id = filter;
1297          filter = false;
1298      }
1299
1300      return this.dispatch( "request", {
1301
1302          concept: concept || '',
1303          id: id || '',
1304          filter: filter || '',
1305          criteria: criteria || '',
1306          service: criteria.service || '',
1307          properties: criteria.properties || ''
1308
1309      } );
1310    },
1311
1312   
1313    //         sync: function( data, callback ){
1314//
1315//      if( !data || $.isEmptyObject( data ) )
1316//          return;
1317//       
1318//      this.send( "Sync", data, function( data, status, jqXHR ){
1319//
1320// //       switch( status )
1321// //       {
1322// //         case "error":
1323// //         case "parsererror":
1324// //           return DataLayer.rollback( concept, URI );
1325// //         case "success":
1326// //           return DataLayer.commit();
1327// //         case "timeout":
1328// //         case "notmodified":
1329// //       }
1330//
1331//          if( callback )
1332//          {
1333//              var result = callback( data, status, jqXHR );
1334//
1335//              if( result === false )
1336//                  return;
1337//              else if( typeof result != "undefined" )
1338//                  data = result;
1339//          }
1340//
1341//          for( var URI in data )
1342//          {
1343//              var parsed = DataLayer.parseURI( URI ),
1344//   
1345//              concept = parsed[1], /*URI = parsed[3],*/
1346//
1347//              links = DataLayer.links( concept );
1348//
1349//              for( var linkName in links )
1350//              {
1351//                  var subURI = data[URI][linkName];
1352//
1353//                  if( subURI && data[subURI] )
1354//                  {
1355//                      data[URI][linkName] = DataLayer.put( linkName, subURI, data[subURI], false );
1356//
1357//                      delete( data[subURI] );
1358//                  }
1359//              }
1360//
1361//              DataLayer.put( concept, URI, data[URI], false );
1362//          }
1363//      }, true );
1364//
1365//     },
1366
1367//     report: function( concept, URI, data, sync )
1368//     {
1369//      var current = this.dequeue( 'current', concept, URI );
1370//
1371//      if( !current )
1372//          this.enqueue( 'current', concept, URI, ( current = this.check( concept, URI ) || {} ) );
1373//
1374//      var diff = this.diff( current, data );
1375//
1376//      if( !diff )
1377//          this.dequeue( 'current', concept, URI, true );
1378//      else
1379//          this.enqueue( 'diff', concept, URI, diff );
1380//     
1381//      if( sync )
1382//          this.commit( concept, URI, function(){
1383//
1384//              DataLayer.set( concept, URI, data, false );
1385//
1386//          });
1387//     },
1388   
1389//     enqueue: function( type, concept, URI, obj ){
1390//       
1391//      //var newURI = this.URI( concept, URI );
1392//     
1393//      if( !this.queue[type] )
1394//          this.queue[type] = {};
1395//
1396//      if( !this.queue['all'] )
1397//          this.queue['all'] = {};
1398//     
1399//      if( !this.queue[type][concept] )
1400//          this.queue[type][concept] = {};
1401//     
1402//      if( !this.queue['all'][type] )
1403//          this.queue['all'][type] = {};
1404//     
1405//      if( !this.queue['all'][type][/*new*/URI] )
1406//          this.queue[type][concept][URI] = this.queue['all'][type][/*new*/URI] = obj;
1407//
1408//      this.store( ':queue', this.queue );
1409//     },
1410//     
1411//     dequeue: function( type, concept, URI, remove ){
1412//       
1413//       ///////////////////////////// normalize ////////////////////////////////
1414//      if( arguments.length < 4 && $.type(URI) === 'boolean' )
1415//      {
1416//          remove = URI;
1417//          URI = false;
1418//      }
1419//      if( arguments.length < 3 && $.type(concept) === 'boolean' )
1420//      {
1421//          remove = concept;
1422//          concept = false;
1423//      }
1424//       //////////////////////////////////////////////////////////////////////////
1425//       
1426//      if( !this.queue[type] || !this.queue['all'] )
1427//          return( false );
1428//     
1429//      if( !concept )
1430//      {
1431//          var obj = this.queue['all'][type];
1432//         
1433//          if( remove )
1434//          {
1435//              delete this.queue['all'][type];
1436//              delete this.queue[type];
1437//          }
1438//
1439//          this.store( ':queue', this.queue );
1440//          return( obj );
1441//      }
1442//
1443//      if( !this.queue[type][concept] )
1444//          return( false );
1445//     
1446//      if( !URI )
1447//      {
1448//          var obj = this.queue[type][concept];
1449//
1450//          if( remove )
1451//          {
1452//              var URIs = this.queue[type][concept];
1453//
1454//              for( var subURI in URIs )
1455//                   delete this.queue['all'][type][subURI];
1456//
1457//              delete this.queue[type][concept];
1458//          }
1459//
1460//          this.store( ':queue', this.queue );
1461//          return( obj );
1462//      }
1463//
1464// //   var newURI = URI ? this.URI( concept, URI ) : concept;
1465//     
1466//      var obj = this.queue['all'][type][/*new*/URI];
1467//   
1468//      if( remove )
1469//      {
1470//          delete this.queue['all'][type][/*new*/URI];
1471//          delete this.queue[type][concept][URI];
1472//      }
1473//
1474//      this.store( ':queue', this.queue );
1475//      return( obj );
1476//     },
1477   
1478           //TODO: definir a 'usage' desta função e refatora-la
1479//     set: function( concept, filter, data, oneSide ){
1480//
1481//      ///////////////////////////// normalize ////////////////////////////////
1482//      if( arguments.length == 2 )
1483//      {
1484//          data = filter;
1485//          filter = false;
1486//      }
1487//      if( $.type(data) === "boolean" )
1488//      {
1489//          oneSide = data;
1490//          data = filter;
1491//          filter = false;
1492//      }
1493//     
1494//      if( !concept || !data )
1495//          return( false );
1496//
1497//      var decoder = "", URI = false, bothSides = (typeof oneSide === "undefined");
1498//     
1499//      if( $.type(filter) === "string" )
1500//      {
1501//          URI = filter;
1502//          filter = false;
1503//      }
1504//
1505//      if( res = internalUrl.exec( concept ) )
1506//      {
1507//          //TODO: verificar se a decodificaçao deve ser feita em cada item do array
1508//          data = this.decode( concept, data );
1509//          concept = res[1];
1510//          decoder = res[2];
1511//      }
1512//      ///////////////////////////////////////////////////////////////////////////
1513//
1514//      if( bothSides || oneSide )
1515//          this.report( concept, URI, data, !bothSides );
1516//
1517//      if( bothSides || !oneSide )
1518//      {
1519//          if( URI )
1520//          {
1521//            var helper = {};
1522//            helper[URI] = data;
1523//            data = helper;
1524//          }
1525//
1526//          for( var URI in data )
1527//          {
1528//              var current = this.check( concept, URI ) || {};
1529//
1530//              data[URI] = this.merge( current, data[URI] );
1531//
1532//              this.store( concept, URI, data[URI] );
1533//          }
1534//
1535//      }
1536//
1537//      this.broadcast( concept, oneSide ? 'client' : 'server' );
1538//
1539//      return( true );
1540//     },
1541//     put: function( concept, URI, data, oneSide ){
1542//       
1543//       ///////////////////////////// normalize ////////////////////////////////
1544//      if( $.type(URI) !== "string" && arguments.length < 4 )
1545//      {
1546//          oneSide = data;
1547//          data = URI;
1548//          URI = false;
1549//      }
1550//       ////////////////////////////////////////////////////////////////////////
1551//       
1552//       ////////////////////////////// linkage /////////////////////////////////
1553//      var result = false, links = this.links( concept );
1554//
1555//      for( var link in links )
1556//      {
1557//          if( data[link] )
1558//          {
1559//              if( $.isArray( data[link] ) )
1560//              {
1561//                  data[link] = this.put( links[link], data[link].URI, data[link], oneSide );
1562//              }
1563//              else if( $.isObject( data[link] ) )
1564//              {
1565//                  $.each( data[link], function( i, el ){
1566//
1567//                        data[link][i] = this.put( links[link], el.URI, el, oneSide );
1568//
1569//                  });
1570//              }
1571//          }
1572//      }
1573//       //////////////////////////////////////////////////////////////////////////
1574//     
1575//      if( typeof data.URI === "undefined" )
1576//      {
1577//          URI = this.add( concept, data, oneSide );
1578//      }
1579//      else if( data.URI === false )
1580//      {
1581//          status = this.remove( concept, URI, oneSide );
1582//      }
1583//      else
1584//      {
1585//          status = this.set( concept, URI, data, oneSide );
1586//      }
1587//
1588//      if( URI && data.URI && URI !== data.URI )
1589//          this.move( concept, URI, data.URI );
1590//
1591//      return( data.URI || URI );
1592//
1593//     },
1594   
1595    //     add: function( concept, data, oneSide ){
1596//       
1597//       ///////////////////////////// normalize ////////////////////////////////
1598//      if( !concept || !data )
1599//          return( false );
1600//
1601//      if( res = internalUrl.exec( concept ) )
1602//      {
1603//          //TODO: verificar se a decodificaᅵᅵo deve ser feita em cada item do array
1604//          data = this.decode( concept, data );
1605//          concept = res[1];
1606//          decoder = res[2];
1607//      }
1608//
1609//      var bothSides = (typeof oneSide === "undefined"), uris = [];
1610//
1611//      if( notArray = $.type(data) !== "array" )
1612//          data = [ data ];
1613//       //////////////////////////////////////////////////////////////////////////
1614//
1615//      for( var i = 0; i < data.length; i++ )
1616//      {
1617//          var URI = uris[i] = this.generateURI( concept );
1618//
1619//          this.set( concept, URI, data[i], oneSide );
1620//      }
1621//
1622//      return( notArray ? uris[0] : uris );
1623//     },
1624//      put: function( concept, data ){
1625//
1626//      var decoder = "";
1627//
1628//      if( res = internalUrl.exec( concept ) )
1629//      {
1630//          data = this.decode( concept, data );
1631//          concept = res[1];
1632//          decoder = res[2];
1633//      }
1634//
1635//      var New = [], Update = [], uris = [];
1636//
1637//      if( notArray = $.type(data) !== "array" )
1638//          data = [ data ];
1639//     
1640//      for( var i = 0; i < data.length; i++ )
1641//      {
1642//          if( !data[i].URI )
1643//          {
1644//              uris[ uris.length ] = data[i].URI = this.create( concept, data[i] );
1645//              New[ New.length ] = data[i];
1646//              continue;
1647//          }
1648//
1649//          for( var key in data[i] )
1650//              if( klass = this.isReference( concept, key, data[i][key] ) )
1651//                    data[i][key] = this.put( klass + decoder, data[i][key] );
1652//
1653//          Update[ Update.length ] = this.update( concept, data[i].URI, data[i] );
1654//      }
1655//
1656//      this.report( concept, { "created": New, "updated": Update });
1657//
1658//      return( notArray ? uris[0] : uris );
1659//     },
1660//     merge: function( concept, current, data ){
1661//
1662//      current = current || {};
1663//
1664//      for( var key in data )
1665//          current[key] = (klass = this.isReference( concept, key, data[key] )) ?
1666//                         this.merge( klass, current[key], data[key] ) : data[key];
1667//
1668//      return( current );
1669//     },
1670//
1671//     isReference: function( concept, key, value ){
1672//
1673//       return( ($.type(value) === "object" ||
1674//             $.type(value) === "array" )? this.links[concept][key] : false );
1675//
1676//     },
1677//     
1678//     set: function( concept, data, URI, mergeable ){
1679//     
1680//      if( URI )
1681//      {
1682//          var res = this.get( concept, true ) || {};
1683//         
1684//          if( mergeable )
1685//              data = this.merge( res[URI] || {}, data );
1686//
1687//          res[URI] = data;
1688//
1689//          data = res;
1690//      }
1691//
1692//      return this.store( concept, data );
1693//     },   
1694//
1695//     create: function( concept, data ){
1696//
1697//       if( notArray = ($.type(data) !== "array") )
1698//          data = [ data ];
1699//
1700//       var uris = [];
1701//
1702//       for( var i = 0; i < data.length; i++ )
1703//       {
1704//        uris[ uris.length ] = data[i].URI = "javascript://" + (this.counter + i);
1705//
1706//        this.set( concept, data[i], data[i].URI );
1707//       }
1708// 
1709//       this.set( ":counter", (this.counter += data.length) );
1710//
1711//       return notArray ? uris[0] : uris;
1712//     },
1713//
1714//     update: function( concept, URI, data )
1715//     {
1716//      var target = this.check( concept, URI ) || {};
1717//
1718//      target = this.merge( concept, target, data );
1719//
1720//      if( target.URI !== URI )
1721//          this.remove( concept, URI );
1722//
1723//      this.set( concept, target, target.URI );
1724//
1725//      return( target );
1726//     },
1727//
1728//     remove: function( concept, URI ){
1729//
1730//      if( !URI )
1731//          return this.storage.del( concept );
1732//
1733//      var res = this.check( concept );
1734//
1735//      delete res[URI];
1736//     
1737//      this.set( concept, res );
1738//     },
1739//
1740//     del: function( concept, URI ){
1741//
1742//      this.remove( concept, URI );
1743//
1744//      this.report( concept, { "deleted": { 'URI': URI } });
1745//     },
1746//
1747//     report: function( concept, changes ){
1748//
1749//       this.broadcast( concept, changes.created, changes.updated, changes.deleted );
1750//
1751//      if( changes.created )
1752//          this.sync( concept, changes.created, 'create' );
1753//      if( changes.updated )
1754//          this.sync( concept, changes.updated, 'update' );
1755//      if( changes.deleted )
1756//          this.sync( concept, changes.deleted, 'delete' );
1757//
1758//     },
1759//
1760//
1761//    sync: function( concept, data, type ){
1762//
1763//      if( $.type(data) !== "array" )
1764//          data = [ data ];
1765//
1766//      $.each( data, function( i, el ){
1767//
1768//         DataLayer.send( concept, el, type );
1769//
1770//      });
1771//
1772//     },
1773//     
1774//     
1775//     
1776//     
1777//
1778//     request: function( concept, URI, filter ){
1779//
1780// //       if( startsDoubleDot.test(concept) )
1781// //     return( false );
1782//
1783//       filter = filter || {};
1784//
1785//       if( URI )
1786//      filter.URI = URI;
1787//
1788//       return this.send( concept, filter, "read", true );
1789//
1790//     },
1791//
1792//     send: function( concept, data, type, wait ){
1793//
1794//       switch( type )
1795//       {
1796//      case "create": type = "POST"; break;
1797//      case "update": type = "PUT"; break;
1798//      case "delete": type = "DELETE"; break;
1799//      case "read": type = "GET"; break;
1800//       }
1801//
1802//       var url = this.basePath + concept;
1803//
1804//       var result = [], notArray = false;
1805//
1806// //      alert( data.URI );
1807//
1808//       if( data.URI && data.URI.indexOf("javascript://") !== 0 )
1809//        url += "/" + data.URI;
1810//
1811//       var callback = function( dt, textStatus, jqXHR ){
1812//
1813//          if( notArray = (!$.isArray( dt )) )
1814//              dt = [ dt ];
1815//
1816//          $.each( dt, function( i, el ){
1817//
1818//              if( !el || !el.URI )
1819//                  return;
1820//
1821//              if( data.URI )
1822//                  el = DataLayer.update( concept, data.URI, el );
1823//              else
1824//                  DataLayer.set( concept, el, el.URI );
1825//
1826//              result[ result.length ] = el;
1827//              DataLayer.broadcast( concept );
1828//        });
1829//       };
1830//
1831//       $.ajax({
1832//            'async': ( !wait ),
1833//            'url': url,
1834//            'type': type,
1835//            'success': callback,
1836//            'dataType': 'json',
1837//            'data': data/*,
1838//            'processData': false*/
1839//        });
1840//
1841//       return( notArray ? result[0] || false : result );
1842//     },
1843   
1844   
1845    generateURI: function( concept ){
1846     
1847        return this.URI( concept, this.generateId( concept ), "javascript" );
1848
1849    },
1850   
1851
1852    broadcast: function( concept, status, diff ){
1853
1854        if( this.listeners[ concept ] )
1855            for( var i = 0;
1856                i < this.listeners[ concept ].length;
1857                this.listeners[ concept ][ i++ ]( status, diff ) );
1858    },
1859
1860    listen: function( concept, listener ){
1861
1862        this.register( "listeners", concept, listener );
1863
1864    },
1865
1866    codec: function( concept, namespace, codec ){
1867
1868        if( codec.encoder )
1869            this.encoder( concept, namespace, codec.encoder );
1870        if( codec.decoder )
1871            this.decoder( concept, namespace, codec.decoder );
1872        if( codec.criteria )
1873            this.register( "criterias", concept + ":" + namespace, codec.criteria );
1874
1875    },
1876
1877    encoder: function( concept, namespace, encoder ){
1878
1879        this.register( "encoders", concept + ":" + namespace, encoder );
1880
1881    },
1882
1883    encode: function( encoder, data, filter ){
1884
1885        if( this.encoders[ encoder ] )
1886            for( var i = 0;
1887                i < this.encoders[ encoder ].length;
1888                data = this.encoders[ encoder ][ i++ ]( data, filter ) );
1889
1890        return( data );
1891    },
1892
1893    decoder: function( concept, namespace, decoder ){
1894
1895        this.register( "decoders", concept + ":" + namespace, decoder );
1896
1897    },
1898
1899    decode: function( decoder, data ){
1900
1901        if( this.decoders[ decoder ] )
1902            for( var i = 0;
1903                i < this.decoders[ decoder ].length;
1904                data = this.decoders[ decoder ][ i++ ]( data ) );
1905
1906        return( data );
1907    },
1908
1909    criteria: function( codec, filter ){
1910
1911        if( this.criterias[ codec ] )
1912            for( var i = 0;
1913                i < this.criterias[ codec ].length;
1914                filter = this.criterias[ codec ][ i++ ]( filter ) );
1915
1916        return( filter );
1917
1918    },
1919
1920    register: function( kind, concept, deployable ){
1921
1922      if( arguments.length < 3 )
1923      {
1924          deployable = concept;
1925          concept = kind;
1926          kind = 'global';
1927      }
1928
1929      if( !this[ kind ][ concept ] )
1930            this[ kind ][ concept ] = [];
1931
1932        this[ kind ][ concept ][ this[ kind ][ concept ].length ] = deployable;
1933
1934    },
1935   
1936    start: function(){
1937
1938        var timer = function(){
1939
1940              setTimeout( timer, 1 );
1941
1942              var now = parseInt( $.now() / 1000 );
1943
1944              var tasks = DataLayer.tasks[ now ];
1945
1946              if( !tasks ) return;
1947
1948              for( var i = 0; i < tasks.length; i++ )
1949              {
1950                  var result = tasks[i].task( now );
1951
1952                  if( tasks[i].factor )
1953                  DataLayer.schedule( tasks[i].task, tasks[i].factor );
1954              }
1955     
1956              delete DataLayer.tasks[ now ];
1957        };
1958
1959        setTimeout( timer, 1 );
1960    },
1961   
1962    task: function( timestamp, task, factor )
1963    {
1964        if( !this.tasks[ timestamp ] )
1965            this.tasks[ timestamp ] = [];
1966
1967        this.tasks[ timestamp ][ this.tasks[ timestamp ].length ] = { task: task, factor: factor || false };
1968    },
1969
1970    schedule: function( task, time ){
1971
1972        time = time || 1;
1973       
1974        var index = parseInt( $.now() / 1000 ) + time;
1975
1976        this.task( index, task, time );
1977    },
1978   
1979    poll: function( concept, time ){
1980     
1981      this.schedule( function( now ){
1982 
1983          DataLayer.commit( concept );
1984
1985        }, time || 5 );
1986    },
1987   
1988    init: function(){
1989     
1990        this.counter = parseInt( this.get( ":counter", false ) ) || 0;
1991
1992        if( !this.dispatchPath )
1993            this.dispatchPath = "../../";
1994
1995        if( !this.templatePath )
1996            this.templatePath = "";
1997
1998        if( !this.basePath )
1999            this.basePath = this.dispatchPath + "REST.php?q=";
2000
2001        this.schedule( function( now ){
2002
2003            DataLayer.flush();
2004
2005        });
2006
2007        this.start();
2008    }
2009}
2010
2011// the re-usable constructor function used by clone().
2012function Clone() {}
2013
2014//Recursion Helper
2015function RecursionHelper(){ this.clear(); };
2016
2017RecursionHelper.prototype = {
2018 
2019        constructor: RecursionHelper,
2020
2021        // copiedObjects keeps track of objects already copied by this
2022        // deepCopy operation, so we can correctly handle cyclic references.
2023        copiedObjects: [],
2024
2025        depth: 0,
2026
2027        maxDepth: 256,
2028
2029        //reset the recursion helper cache
2030        clear: function(){
2031                this.copiedObjects = [];
2032                this.depth = 0;
2033        },
2034
2035        // add an object to the cache.  No attempt is made to filter duplicates;
2036        // we always check getCachedResult() before calling it.
2037        cacheResult: function(source, result) {
2038                this.copiedObjects.push([source, result]);
2039        },
2040
2041        // Returns the cached copy of a given object, or undefined if it's an
2042        // object we haven't seen before.
2043        getCachedResult: function(source) {
2044
2045                for ( var i=0; i<this.copiedObjects.length; i++ ) {
2046                        if ( this.copiedObjects[i][0] === source ) {
2047                                return this.copiedObjects[i][1];
2048                        }
2049                }
2050
2051                return undefined;
2052        }
2053};
2054
2055// Generic Object copier
2056// the ultimate fallback DeepCopier, which tries to handle the generic case.  This
2057// should work for base Objects and many user-defined classes.
2058DataLayer.registerComparator({
2059        can: function(source) { return true; },
2060
2061        create: function(source) {
2062                if ( source instanceof source.constructor ) {
2063                        return DataLayer.clone(source.constructor.prototype);
2064                } else {
2065                        return {};
2066                }
2067        },
2068
2069        populate: function(deepCopy, source, result) {
2070                for ( var key in source ) {
2071                        if ( source.hasOwnProperty(key) ) {
2072                                result[key] = deepCopy(source[key], result[key]);
2073                        }
2074                }
2075                return result;
2076        }
2077});
2078
2079// Array copier
2080DataLayer.registerComparator({
2081        can: function(source) {
2082                return ( source instanceof Array );
2083        },
2084
2085        create: function(source) {
2086                return new source.constructor();
2087        },
2088
2089        populate: function(deepCopy, source, result) {
2090                for ( var i=0; i<source.length; i++) {
2091                        result.push( deepCopy(source[i], result[i]) );
2092                }
2093                result =  DataLayer.unique( result )
2094                return result;
2095        }
2096});
2097
2098// Date copier
2099DataLayer.registerComparator({
2100        can: function(source) {
2101                return ( source instanceof Date );
2102        },
2103
2104        create: function(source) {
2105                return new Date(source);
2106        }
2107});
2108
2109// HTML DOM Node copier
2110DataLayer.registerComparator({
2111
2112        // function to detect Nodes.  In particular, we're looking
2113        // for the cloneNode method.  The global document is also defined to
2114        // be a Node, but is a special case in many ways.
2115        can: function(source) {
2116         
2117          if ( window.Node ) {
2118                  return source instanceof Node;
2119          } else {
2120                  // the document is a special Node and doesn't have many of
2121                  // the common properties so we use an identity check instead.
2122                  if ( source === document ) return true;
2123                  return (
2124                          typeof source.nodeType === 'number' &&
2125                          source.attributes &&
2126                          source.childNodes &&
2127                          source.cloneNode
2128                  );
2129          }
2130      },
2131
2132      create: function(source) {
2133              // there can only be one (document).
2134              if ( source === document ) return document;
2135
2136              // start with a shallow copy.  We'll handle the deep copy of
2137              // its children ourselves.
2138              return source.cloneNode(false);
2139      },
2140     
2141      diff: function(base, source){
2142       
2143      },
2144
2145      populate: function(deepCopy, source, result) {
2146              // we're not copying the global document, so don't have to populate it either.
2147              if ( source === document ) return document;
2148
2149              // if this Node has children, deep copy them one-by-one.
2150              if ( source.childNodes && source.childNodes.length ) {
2151                      for ( var i=0; i<source.childNodes.length; i++ ) {
2152                              var childCopy = deepCopy(source.childNodes[i], result.childNodes[i] || false );
2153                              result.appendChild(childCopy);
2154                      }
2155              }
2156                return result;
2157      }
2158});
2159
2160DataLayer.init();
2161
2162// setTimeout(function(){
2163// 
2164//     
2165//
2166// }, 1000 );
2167
2168// var DataLayer = {
2169//
2170//     get: function( concept, filter ){
2171//
2172//      var data = this.storage.get( concept );
2173//
2174//      if( !filter )
2175//          return( data );
2176//
2177//      return this.filter( data, filter );
2178//     },
2179//     
2180//     filter:function( data, filter ){
2181//       
2182//      if( filter.charAt )
2183//          filter = { URI: filter };
2184//     
2185//      var filtered = [];
2186//
2187//      $.each(data, function(i, obj){
2188//       
2189//          for( var attr in filter )
2190//              if( filter[attr] !== obj[attr] )
2191//                  return( true );
2192//
2193//          filtered[i] = obj;
2194//      });
2195//
2196//      return( filtered );
2197//     },
2198//
2199//     find: function( concept, filter, callback ){
2200//
2201//      var data = this.get( concept, filter );
2202//
2203//      if( data )
2204//          return callback( data );
2205//
2206//      //TODO: register callback like a weak listener
2207//
2208// //   $.ajax({
2209// //         type: 'GET',
2210// //         data: $.param( filter ),
2211// //         success: callback, 
2212// //         url: BASE_PATH + filter.URI || concept
2213// //   });
2214//      this.report( concept, filter );
2215//     },
2216//
2217//     put: function( concept, data, filter ){
2218//
2219//      var beforeDiff = this.store( concept, $.extend({},data) );
2220//
2221//      this.report( concept, data, filter, beforeDiff );
2222//     },
2223//     
2224//     
2225//     /*var data = {
2226//                      startTime: $.now(),
2227//                      endTime: $.now() + 1800000,
2228//                      summary: "meu querido evento",
2229//                      description: "desc do evento",
2230//                      location: "prognus software livre",
2231//                      class: 1,
2232//                      calendar: 1,
2233//                      category: 1,
2234//                      participants: [ {
2235//                                         user: { isExternal: true, mail: "user7@prognus.org", name: "user7" }
2236//                                    },{
2237//                                         user: "1003"
2238//                                    } ]
2239//
2240//                };*/
2241//     
2242//
2243//     merge:function( data, target ){
2244//       
2245//      var diff = { New: {}, Update:{}, Delete: {} };
2246//       
2247//      for( var key in data )
2248//      {
2249//          if( !target[ key ] )
2250//              diff.New[ key ] = target[ key ] = data[ key ];
2251//
2252//         
2253//       
2254//      }
2255//       
2256//     }
2257//
2258//     store: function( concept, data, filter ){
2259//
2260//      if( !data.spline )
2261//          data = [ data ];
2262//
2263//      var target = this.storage.get( concept );
2264//     
2265//      var diff = { New: {}, Update:{}, Delete: {} };
2266//
2267//      for( var i = 0; i < data.length; i++ )
2268//      {
2269//          if( data[i].URI && target[ data[i].URI ] )
2270//          {
2271//              diff.Update[ data[i].URI ] = this.merge( target[ data[i].URI ], data[i] );
2272//          }
2273//          else
2274//          {
2275//              diff.New[] = data[i];
2276//          }
2277//      }
2278//
2279//     
2280//
2281//      this.broadcast( concept, data );
2282//
2283//      if( filter )
2284//          target = this.filter( target, filter );
2285//
2286//      if( target )
2287//          data = $.extend( target, data );
2288//
2289//      this.storage.set( concept, data );
2290//
2291// //   return;
2292//     },
2293//     
2294//     set: function( concept, data, filter ){
2295//
2296//       
2297//
2298//     },
2299//
2300//     post: function( concept, data, filter, isNew ){
2301//
2302//      var callback = function(  ){ DataLayer.store( concept, data, filter ) };
2303//
2304//      //TODO: register callback like a weak listener
2305//
2306//      this.report( concept, data, filter, isNew );
2307//     },
2308//     
2309//     report: function( concept, filter, postData, isNew ){
2310//       
2311//      $.ajax({
2312//              type: postData ? isNew ? 'POST' : 'PUT' : 'GET',
2313//              data: postData || $.param( filter ),
2314//              success: function( data ){ DataLayer.broadcast( concept ) },
2315//              url: BASE_PATH + filter.URI || concept
2316//        });
2317//     },
2318//     
2319//     del:function( concept, filter ){
2320//
2321//       
2322//
2323//     }
2324//     
2325//     broadcast: function( concept, data ){
2326//
2327//     
2328//
2329//     },
2330//
2331//     pool: function(){
2332//       
2333//     },
2334//
2335//     refresh: function(){
2336//       
2337//     }
2338// };
2339
2340//
2341// DataLayer = {
2342//   
2343//     get: function( concept, filter ){
2344//
2345//      var data = this.storage.get( concept );
2346//
2347//      if( !filter )
2348//          return( data );
2349//
2350//      if( filter.charAt )
2351//          filter = { URI: filter };
2352//     
2353//      var filtered = [];
2354//
2355//      $.each(data, function(i, obj){
2356//       
2357//          for( var attr in filter )
2358//              if( filter[attr] !== obj[attr] )
2359//                  return( true );
2360//
2361//          filtered[i] = obj;
2362//      });
2363//
2364//      return( filtered );
2365//     },
2366//
2367//     find: function( concept, filter, callback ){
2368//
2369//      var data = this.get( concept, filter );
2370//
2371//      if( data )
2372//          return callback( data );
2373//
2374//       $.ajax({
2375//            type: 'GET',
2376//            data: $.param( filter ),
2377//            success: callback, 
2378//            url: filter.URI || concept
2379//      });
2380//     },
2381//
2382//     put: function( concept, data, filter ){
2383//
2384//      var target = this.get( concept, filter );
2385//
2386//      if( target )
2387//          data = $.extend( target, data );
2388//       
2389//      this.storage.set( concept, data );
2390//     
2391//      //diff
2392//     },
2393//     
2394//     post: function( concept, data, filter ){
2395//
2396//     
2397//
2398//     },
2399//     
2400//     pool: function(){
2401//       
2402//     },
2403//     
2404//     queue: function(){
2405//       
2406//     },
2407//     
2408//     dequeue: function(){
2409//       
2410//     },
2411//     
2412//     refresh: function(){
2413//       
2414//     }
2415// }
2416
2417// var DataLayer = {
2418 
2419//       cache: {},
2420 
2421//       get: function( concept, location ){
2422       
2423           /* if( location )
2424            {*/
2425//              var schema = $.data( this.cache, concept + ':schema' );
2426//              var uri = [];
2427//
2428//              $.each( schema, function( i, addrs ){
2429//                    uri[ uri.length ] = location[addrs];
2430//              });
2431
2432                /*var filter = [], result = false;
2433
2434                while( !(result = $.data( this.cache, uri.join( '.' ) )) || !(uri = uri.join('.')) )
2435                  filter[ filter.length ] = uri.pop();
2436 
2437                if( !filter.length )
2438                {
2439                    var indexes = $.data( this.cache, uri + ':indexes' );
2440
2441                    if( indexes )
2442                        Array.prototype.concat.apply( result, indexes );
2443                   
2444                    return( result );
2445                }
2446
2447                for( var i = 0; i < result.length; i++ )
2448                {
2449                   
2450                }
2451
2452                if( result.length )
2453                    return( result );
2454            }*/
2455
2456//          var data = $.data( this.cache, concept );
2457
2458//          if( !data )
2459//              $.ajax( );
2460
2461//          return( data );
2462//       },
2463     
2464//       data: function(){
2465//
2466//       
2467//
2468//       }
2469//       
2470//       search: function( concept, filter ){
2471//
2472//        var schema = $.data( this.cache, concept + ':schema' );
2473//        var uri = [];
2474//
2475//        $.each( schema, function( i, addrs ){
2476//              uri[ uri.length ] = location[addrs];
2477//        });
2478//       }
2479//       put: function( concept, data, location ){
2480
2481//          if( location )
2482//          {
2483//              var schema = $.data( this.cache, concept + ':schema');
2484//              var uri = [];
2485
2486//              $.each( schema, function( i, addrs ){
2487//                    uri[ uri.length ] = location[addrs];
2488//              });
2489
2490//              var result = false, filter = [];
2491
2492//              while( !(result = $.data( this.cache, uri.join('.')) )
2493//                  filter[ filter.length ] = uri.pop();
2494
2495//              $.data( this.cache, '
2496
2497//          }
2498
2499//              var model = this.storage.get( concept );
2500//
2501//              $.each( model, function( i, o ){
2502//                  $.each( location, function( ii, attr ){
2503//                       if( o[ii] === attr )
2504//                          return( false );
2505//                  });
2506//              });
2507
2508//          return $.data( this.cache, concept, data );
2509
2510//       },
2511//       del: function( concept, location ){
2512//
2513//          if( location )
2514//          {
2515//              var schema = $.data( this.cache, 'concepts', concept );
2516//              var uri = [];
2517//
2518//              $.each( schema, function( i, addrs ){
2519//                    uri[ uri.length ] = location[addrs];
2520//              });
2521//
2522//              concept = uri.join( '.' );
2523
2524//              var model = this.storage.get( concept );
2525//
2526//              $.each( model, function( i, o ){
2527//                  $.each( location, function( ii, attr ){
2528//                       if( o[ii] === attr )
2529//                          return( false );
2530//                  });
2531//              });
2532//          }
2533//         
2534//     
2535//          $.removeData( this.cache, concept );
2536//       }
2537// }
2538
2539// internalUrl = /^([A-z0-9-_]+)(:[A-z0-9-_]+)?$/;
2540// internalUri = /^([a-zA-Z0-9-_]+)\(([a-zA-Z0-9-_]+)\):\/\/(.*)|([a-zA-Z0-9-_]+):\/\/(.*)$/;
2541// isGeneratedId = /^\d+\(javascript\)$/;
2542// arrayName = /^([A-z0-9-_]+)\[\]$/;
2543// startsDoubleDot = /^:/;
2544// FILE = 'files';
2545// // cached_urls = {};
2546//
2547// $.ajaxPrefilter(function( options, originalOptions, jqXHR ){
2548//
2549//       if( options.url != 'undefined' && internalUrl.test( options.url ) ){
2550//
2551// //     if( !cached_urls[options.url] )
2552// //         return;
2553// //     alert( options.url + " dentro" );
2554//        jqXHR.abort();
2555//
2556//        var callback = ( options.success || options.complete || $.noop );
2557//
2558//        switch( options.type.toUpperCase() )
2559//        {
2560//          case 'GET':
2561//                return callback( DataLayer.get( options.url, /*false,*/ options.data ) );
2562//
2563//          case 'POST':
2564//                return callback( DataLayer.put( options.url, options.data ) );
2565//        }
2566//
2567//        //return( false );
2568//
2569// //     options.url = params[1];
2570// //     options.data = ( options.data || "" ) + "&" + params[2];
2571//       }
2572//
2573// });
2574//
2575// // $("a").live("click", function( event ){
2576// //
2577// //     event.preventDefault();
2578// //
2579// //     $.ajax({
2580// //
2581// //   
2582// //
2583// //     });
2584// //
2585// // });
2586//
2587// $("form").live( "submit", function( event ){
2588//
2589//     var $this = $(this), action = $this.attr('action'), res = false,
2590//     
2591//     method = $this.attr( 'method' ),
2592//     
2593//     fileInputs = $this.find('input[type="file"]');
2594//     
2595//     if( fileInputs.length && !$this.is('[enctype="multipart/form-data"]') )
2596//     {
2597//      event.preventDefault();
2598//     
2599//      var formData = $this.serializeArray(), callback = DataLayer.receive;
2600//       
2601//      if( res = internalUrl.exec( action ) )
2602//      {
2603//          var data = {}, action = res[1];
2604//
2605//          data[action] = DataLayer.form( this, fileInputs );
2606//
2607//          formData = DataLayer.serializeForm( data );
2608//             
2609//              action = DataLayer.dispatchPath + 'post.php';
2610//          callback = $.noop;
2611//      }
2612//
2613//      DataLayer.send( action,
2614//                      [ method, 'iframe json' ], {},
2615//                      //TODO: check the type for conversion
2616//                      callback,
2617//                      false, { 'formData': formData,  'fileInput': fileInputs, 'paramName': FILE + '[]' } );
2618//
2619//      return( false );
2620//     }
2621//     
2622//     if( res = internalUrl.exec( action ) )
2623//     {
2624//      event.preventDefault();
2625//
2626//      var data = DataLayer.form( this );
2627//     
2628//      switch( method.toUpperCase() )
2629//      {
2630//        case 'GET':
2631//              DataLayer.get( res[0], data );
2632//
2633//        case 'POST':
2634//              DataLayer.put( res[1], data );
2635//      }
2636//
2637//      return( false );
2638//     }
2639//
2640//     return( true );
2641// });
2642//
2643// this.storage = new $.store();
2644//
2645// DataLayer = {
2646//
2647//     links: {},
2648//     concepts: {},
2649//     listeners: {},
2650//     encoders: {},
2651//     decoders: {},
2652//     templates: {},
2653//     criterias: {},
2654//     tasks: [],
2655//
2656//     render: function( templateName, data, filter, formatter, force ){
2657//
2658//      if( $.isFunction( filter ) )
2659//      {
2660//          force = formatter;
2661//          formatter = filter;
2662//          filter = false;
2663//      }
2664//
2665//      if( typeof data === "string" )
2666//      {
2667//          data = this.get( data, filter, force ) || {};
2668//      }
2669//     
2670//      var formatting = function( template ){
2671//
2672//            if( template === false ) return( false );
2673//
2674//            if( template )
2675//                DataLayer.templates[ templateName ] = new EJS({ text: template, cache: false });
2676//
2677//            var html = DataLayer.templates[ templateName ].render( { data: data } );
2678//
2679//            if( !formatter )
2680//                return( html );
2681//
2682//            return formatter( html );
2683//      }
2684//
2685//      if( this.templates[ templateName ] )
2686//      {
2687//          return formatting();
2688//      }
2689//
2690//      return this.send( DataLayer.templatePath + templateName, 'get', false, formatting, !!!formatter );
2691//     },
2692//     
2693//     send: function( url, type, data, callback, sync, extraOptions ){
2694//       
2695//        var result = false, fired = false;
2696//       
2697//        var envelope = {
2698//
2699//            'async': ( typeof sync !== "undefined" ? !sync : !!callback ),
2700//            'url': url,
2701//            'success': function( dt, textStatus, jqXHR ){
2702//
2703//                  if( callback )
2704//                  {
2705//                      fired = true;
2706//                      result = callback( dt, textStatus, jqXHR );
2707//                  }
2708//                  else
2709//                      result = dt;
2710//
2711//              },
2712//            'complete': function( jqXHR, textStatus ){
2713//
2714//                if( !fired && callback )
2715//                    result = callback( false, textStatus, jqXHR );
2716//
2717//            },
2718//
2719//            'type': $.isArray( type ) ? type[0] : type,
2720//            'data': data
2721//
2722//          };
2723//
2724//        if( $.isArray( type ) && type[1] )
2725//            envelope['dataType'] = type[1];
2726//
2727//        if( extraOptions )
2728//            envelope = $.extend( envelope, extraOptions );
2729//
2730//        $.ajax( envelope );
2731//       
2732//        return( result );
2733//     },
2734//     
2735//     dispatch: function( dispatcher, data, callback, isPost, dataType ){
2736//       
2737//       return this.send( this.dispatchPath + dispatcher + ".php",
2738//                      [ ( isPost ? 'post' : 'get' ), dataType || 'json' ],
2739//                      data,
2740//                      callback );
2741//
2742// //       $.ajax({
2743// //         'async': !!callback,
2744// //         'url': this.dispatchPath + dispatcher + ".php",
2745// //         'type': ( isPost ? 'post' : 'get' ),
2746// //         'dataType': 'json',
2747// //         'data': data,
2748// //         'success': function( dt, textStatus, jqXHR ){
2749// //
2750// //               if( callback )
2751// //               {
2752// //                   fired = true;
2753// //                   callback( dt, textStatus, jqXHR );
2754// //               }
2755// //               else
2756// //                   result = dt;
2757// //
2758// //           },
2759// //         'complete': function( jqXHR, textStatus ){
2760// //
2761// //             if( !fired && callback )
2762// //                 callback( false, textStatus, jqXHR );
2763// //
2764// //         }/*,
2765// //         'processData': false*/
2766// //     });
2767//
2768//       //return( result );
2769//     },
2770//
2771//     form: function( target, fileInputs ){
2772//
2773//      var params = {}, $this = $(target), inputArray = $this.serializeArray();
2774//
2775//      if( !$this.is( "form" ) )
2776//          $this = $this.parents( "form" );
2777//             
2778//      if( fileInputs )
2779//              fileInputs.each( function( i, el ){
2780//
2781//            inputArray[ inputArray.length ] = { name: $(this).prop("name"), value: FILE + i };
2782//
2783//              });
2784//
2785//      $.each( inputArray, function( i, el ){
2786//
2787//          if( newName = arrayName.exec( el.name ) )
2788//              el.name = newName[1];
2789//          else if( !params[ el.name ] )
2790//              return( params[ el.name ] = el.value );
2791//
2792//          params[ el.name ] = params[ el.name ] || [];
2793//
2794//          if( $.type(params[ el.name ]) !== "array" )
2795//              params[ el.name ] = [ params[ el.name ] ];
2796//
2797//          params[ el.name ].push( el.value );
2798//      });
2799//
2800// //   alert(dump(params));
2801//
2802//      return this.decode( $this.attr( "action" ), params );
2803//     },
2804//     
2805//      serializeForm: function( data, level ){
2806//     
2807//              var formData = [];
2808//     
2809//              for( key in data )
2810//              {
2811//                      var value = data[key];
2812//
2813//                      if( level !== undefined )
2814//                              key = level+'['+key+']';
2815//
2816//                      if( $.isArray(value) || $.isPlainObject(value) )
2817//                              formData = formData.concat( this.serializeForm( value, key ) );
2818//                      else
2819//                              formData[ formData.length ] = { name: key, value: value };
2820//              }
2821//             
2822//              return( formData );
2823//      },
2824//
2825//     blend: function( action, data ){
2826//
2827// //   if( notArray = (!$.isArray(data)) )
2828// //       data = [ data ];
2829//
2830//      var form = $('form[action="'+action+'"]');
2831//
2832//      form.get(0).reset();
2833//
2834//      var named = form.find( 'input[name]' );
2835//
2836//      for( var name in data )
2837//      {
2838//          named.filter( '[name="'+name+'"]' ).val( data[name] );
2839//      }
2840//     },
2841//
2842// 
2843//     
2844//     put: function( concept, filter, data, oneSide ){
2845//       
2846//       ///////////////////////////// normalize ////////////////////////////////
2847//      if( arguments.length == 2 )
2848//      {
2849//          data = filter;
2850//          filter = false;
2851//      }
2852//      if( typeof data === "undefined" ||
2853//          $.type(data) === "boolean" )
2854//      {
2855//          oneSide = data;
2856//          data = filter;
2857//          filter = false;
2858//      }
2859//     
2860//      if( !concept || !data )
2861//          return( false );
2862//
2863//      var decoder = "", id = false, bothSides = (typeof oneSide === "undefined"), notArray, res;
2864//     
2865//      if( $.type(filter) === "string" )
2866//      {
2867//          id = filter;
2868//          filter = false;
2869//      }
2870//
2871//      if( id )
2872//          data.id = id;
2873//
2874//      if( notArray = ( $.type( data ) !== "array" ) )
2875//          data = [ data ];
2876//
2877//      if( res = internalUrl.exec( concept ) )
2878//      {
2879//          //TODO: verificar se a decodificaçao deve ser feita em cada item do array
2880//          data = this.decode( concept, data );
2881//          concept = res[1];
2882//          decoder = res[2];
2883//      }
2884//
2885//       ////////////////////////////////////////////////////////////////////////
2886//
2887//      if( bothSides || !oneSide )
2888//      {
2889//          var result = false, links = this.links( concept ),
2890//          current = this.check( concept ) || {}, ids = [];
2891//
2892//          for( var i = 0; i < data.length; i++ )
2893//          {
2894//              var key = ids[ ids.length ] = data[i].id || this.generateId( concept ), updateSet = {};
2895//
2896//              ////////////////////////////// linkage /////////////////////////////////   
2897//              for( var link in links )
2898//              {
2899//                  if( data[i][link] )
2900//                  {
2901//                      var isConcept = false;
2902//                   
2903//                      if( isConcept = this.isConcept( concept, link ) )
2904//                          data[i][link] = [ data[i][link] ];
2905//
2906//                      var _this = this;
2907//
2908//                      $.each( data[i][link], function( ii, el ){
2909//
2910//                              var isRef = false;
2911//
2912//                              if( isRef = ($.type(el) === "string") )
2913//                                  el = { id: el };
2914//
2915//                              var nestedLinks = _this.links( links[link], true );
2916//                              //removido pois o mesmo esta gerando inconsistencia em tudo
2917//                              //if( DataLayer.isConcept( links[link], nestedLinks[concept] ) )
2918//                              if( isConcept )
2919//                              {
2920//                                  el[ nestedLinks[link] ] = el[ nestedLinks[link] ] || [];
2921//                                  el[ nestedLinks[link] ].push( key );
2922//                              }
2923//                              else
2924//                                  el[ nestedLinks[link] ] = key;
2925//
2926//                              if( isRef && ( !current[ key ] || !current[ key ][ link ] ||
2927//                                             (isConcept ? current[ key ][ link ] !== el.id : !$.inArray( el.id, current[ key ][ link ] )) ) )
2928//                              {
2929//                                  updateSet[ links[link] ] = updateSet[ links[link] ] || [];
2930//                                  updateSet[ links[link] ].push( el );
2931//                              }
2932//                              else if( !isRef )
2933//                                  data[i][link][ii] = _this.put( links[link], el, oneSide );
2934//                          });
2935//
2936//                      if( isConcept )
2937//                          data[i][link] = data[i][link][0];
2938//                  }
2939//              }
2940//              //////////////////////////////////////////////////////////////////////////
2941//
2942//              if( data[i].id )
2943//                  data[i] = this.merge( current[ data[i].id ], data[i] );
2944//
2945//               current[ key ] = data[i];
2946//
2947//              if( bothSides )
2948//                this.report( concept, key, data[i] );
2949//          }
2950//
2951//          this.store( concept, current );
2952//
2953//          for( var setKey in updateSet )
2954//          {
2955//              if( bothSides )
2956//                  for( var i = 0; i < updateSet[ setKey ].length; i++ )
2957//                    this.report( setKey, updateSet[ setKey ][i].id, updateSet[ setKey ][i] );
2958//                 
2959//              DataLayer.put( setKey, updateSet[ setKey ], false );
2960//          }
2961//      }
2962//
2963//      if( oneSide )
2964//          this.commit( concept, ids/*, true */);
2965//
2966//      this.broadcast( concept, oneSide ? 'server' : bothSides ? 'serverclient' : 'client', true );
2967//
2968//      return( notArray ? ids[0] : ids );
2969//
2970//     },
2971//     
2972//     remove: function( concept, id, oneSide ){
2973//       
2974//      var bothSides = (typeof oneSide === "undefined"),
2975//
2976//      links = this.links( concept ), ids = [],
2977//
2978//      current = this.check( concept, id );
2979//
2980//      if( !current ) return;
2981//     
2982//      if( id )
2983//          current.id = id;
2984//
2985//      if( notArray = ( $.type( current ) !== "array" ) )
2986//          current = [ current ];
2987//
2988//      for( var i = 0; i < current.length; i++ )
2989//      {
2990//          var currentId = ids[ ids.length ] = current[i].id;
2991//
2992//          if( bothSides )
2993//            this.report( concept, currentId, false );
2994//
2995//          if( bothSides || !oneSide )
2996//            this.del( concept, currentId );
2997//
2998//          for( var link in links )
2999//          {
3000//              if( !current[i][link] )
3001//                  continue;
3002//
3003//              var nestedLinks = this.links( links[link], true );
3004//
3005//              if( isConcept = this.isConcept( concept, link ) )
3006//                  current[i][link] = [ current[i][link] ];
3007//
3008//              $.each( current[i][link], function( ii, el ){
3009//
3010//                      el = DataLayer.storage.cache[links[link]][el];
3011//
3012//                      if( notArrayNested = ( $.type( el[ nestedLinks[link] ] ) !== "array" ) )
3013//                          el[ nestedLinks[link] ] = [ el[nestedLinks[link]] ];
3014//
3015//                      el[ nestedLinks[link] ] = $.grep( el[ nestedLinks[link] ], function( nested, iii ){
3016//                          return ( currentId !== nested );
3017//                      });
3018//
3019//                      if( notArrayNested )
3020//                          el[ nestedLinks[link] ] = el[ nestedLinks[link] ][0] || false;
3021//                      if(!el[ nestedLinks[link] ] || !el[ nestedLinks[link] ].length)
3022//                              delete el[ nestedLinks[link] ];
3023//              });
3024//          }
3025//      }
3026//
3027//      if( oneSide )
3028//          this.commit( concept, ids );
3029//
3030//      this.broadcast( concept, oneSide ? 'server' : bothSides ? 'serverclient' : 'client', false );
3031//     },
3032//     
3033//     report: function( concept, id, data )
3034//     {     
3035//      var current = this.check( ':current', concept ) || {};
3036//
3037//      if( !current[ id ] )
3038//          current[ id ] = this.check( concept, id ) || {};
3039//     
3040//      this.store( ':current', concept, current );
3041//
3042//      var diff = this.diff( current[ id ], data );
3043//
3044//      var diffs = this.check( ':diff', concept ) || {};
3045//
3046//      if( diffs[ id ] )
3047//          diff = this.merge( diffs[ id ], diff );
3048//
3049//      if( !diff || !$.isEmptyObject( diff ) )
3050//          diffs[ id ] = diff;
3051//
3052//      this.store( ':diff', concept, diffs );
3053//     },
3054//
3055// //     enqueue: function( queueName, concept, id, data ){
3056// //
3057// //   var queue = this.check( ':' + queueName, concept ) || {};
3058// //
3059// //
3060// //     },
3061// //     
3062// //     dequeue: function( queueName, concept, id ){
3063// //
3064// //   
3065// //
3066// //     },
3067//     
3068//     
3069//     
3070//     rollback: function( concept, ids ){
3071//       
3072//      var queue = this.prepareQ( 'current', concept, ids );
3073//
3074//      ids = [];
3075//
3076//      for( var id in queue )
3077//      {
3078//           this.put( concept, id, queue[id], false );
3079//
3080//           ids[ ids.length ] = id;
3081//      }
3082//
3083//      this.clearQ( concept, ( ids.length ? ids : false ) );
3084//
3085//      this.broadcast( concept, 'revert' );
3086//       
3087//     },
3088//     
3089//     prepareQ: function( queueName, concept, ids ){
3090//       
3091//       var notArray = false;
3092//       
3093//       if( notArray = ($.type(concept) !== "array") )
3094//        concept = [ concept ];
3095//       
3096//       var q = {};
3097//       
3098//       for( var i = 0; i < concept.length; i++ )
3099//       {
3100//        var queue = this.check( ':' + queueName, concept[i] || false );
3101//       
3102//        if( !queue ) continue;
3103//
3104//        if( ids )
3105//        {
3106//            if( $.type(ids) !== "array" )
3107//                ids = [ ids ];
3108//
3109//            var filtered = {};
3110//
3111//            for( var ii = 0; ii < ids.length; ii++ )
3112//            {
3113//                filtered[ ids[ii] ] = queue[ ids[ii] ];
3114//            }
3115//
3116//            queue = filtered;
3117//        }
3118//
3119//        q[ concept[i] ] = queue;
3120//       }
3121//       
3122//       return( notArray ? q[ concept[0] ] : q );
3123//     },
3124//     
3125//     clearQ: function( concept, ids ){
3126//       
3127//              var current = this.check( ':current', concept || false );
3128//      var diffs = this.check( ':diff', concept || false );
3129//
3130//      if( !ids )
3131//          current = diffs = {};
3132//      else
3133//      {
3134//          if( notArray = ($.type(ids) !== "array") )
3135//            ids = [ ids ];
3136//
3137//          for( var i = 0; i < ids.length; i++ )
3138//          {
3139//              delete current[ ids[i] ];
3140//              delete diffs[ ids[i] ];
3141//          }
3142//      }
3143//
3144//      this.store( ':current', concept, current );
3145//      this.store( ':diff', concept, diffs );
3146//     },
3147//
3148//     commit: function( concept, ids, callback ){
3149//       
3150//      var queue = this.prepareQ( 'diff', concept, ids );
3151//
3152//      this.sync( queue, !$.isArray(concept) && concept || false, callback );
3153//     },
3154//     
3155//     sync: function( queue, concept, callback ){
3156//
3157//      if( !queue || $.isEmptyObject( queue ) )
3158//          return;
3159//
3160//      if( concept )
3161//      {
3162//        var helper = {};
3163//        helper[concept] = queue;
3164//        queue = helper;
3165//      }
3166//
3167//      var data = {}, URIs = {};
3168//
3169//      for( var concept in queue )
3170//          for( var id in queue[concept] )
3171//          {
3172//              data[ this.URI( concept, id ) ] = queue[concept][id];
3173//              URIs[ this.URI( concept, id ) ] = { concept: concept, id: id };
3174//          }
3175//
3176//      if( $.isEmptyObject( data ) )
3177//          return;
3178//
3179//      this.dispatch( "Sync", data, function( data, status, jqXHR ){
3180//
3181// //       switch( status )
3182// //       {
3183// //         case "error":
3184// //         case "parsererror":
3185// //           return DataLayer.rollback( concept, URI );
3186// //         case "success":
3187// //           return DataLayer.commit();
3188// //         case "timeout":
3189// //         case "notmodified":
3190// //       }
3191//
3192//          var received = DataLayer.receive( data );
3193//
3194//          for( var URI in URIs )
3195//              if( typeof received[URI] !== "undefined" )
3196//                  DataLayer.clearQ( URIs[URI].concept, URIs[URI].id );
3197//
3198//          if( callback )
3199//              callback( received );
3200//
3201// //       for( var URI in data )
3202// //       {
3203// //           var parsed = DataLayer.parseURI( URI ),
3204// //   
3205// //           concept = parsed[1], id = parsed[3];
3206// //
3207// //           if( $.type(data[URI]) === "string" )
3208// //           {
3209// //             //TODO:threat the exception thrown
3210// //             DataLayer.rollback( concept, id );
3211// //             delete URIs[ URI ];
3212// //             continue;
3213// //           }
3214// //
3215// //           if( data[URI] === false ){
3216// //             DataLayer.remove( concept, id, false );
3217// //             continue;
3218// //           }
3219// //
3220// //           if( id !== data[URI].id )
3221// //             DataLayer.move( concept, id, data[URI].id );
3222// //           
3223// //           DataLayer.put( concept, id, data[URI], false );
3224// //       }
3225// //       
3226// //       for( var URI in URIs )
3227// //            DataLayer.clearQ( URIs[URI].concept, URIs[URI].id );
3228// //       
3229// //       if( callback )
3230// //           callback();
3231//
3232//      }, true );
3233//
3234//     },
3235//     
3236//     receive: function( data ){
3237//       
3238//      var received = {};
3239//     
3240//          for( var URI in data )
3241//          {
3242//              var parsed = DataLayer.parseURI( URI ),
3243//   
3244//          concept = parsed[4], id = parsed[5];
3245//
3246//          received[ URI ] = data[ URI ];
3247//
3248//              if( $.type(data[URI]) === "string" )
3249//              {
3250//                //TODO:threat the exception thrown
3251//                DataLayer.rollback( concept, id );
3252//                continue;
3253//              }
3254//
3255//              if( data[URI] === false ){
3256//                DataLayer.remove( concept, id, false );
3257//                continue;
3258//              }
3259//
3260//              if( id !== data[URI].id )
3261//                DataLayer.move( concept, id, data[URI].id );
3262//             
3263//              DataLayer.put( concept, id, data[URI], false );
3264//          }
3265//         
3266//      return( received );
3267//         
3268//     },
3269//     
3270//     unique: function( origArr ){
3271//
3272//      var newArr = [];
3273//       
3274//      for ( var x = 0; x < origArr.length; x++ )
3275//      {
3276//              var found = false;
3277//          for ( var y = 0; !found && y < newArr.length; y++ )
3278//              if ( origArr[x] === newArr[y] ) 
3279//                found = true;
3280//
3281//          if ( !found )
3282//              newArr[ newArr.length ] = origArr[x];
3283//      }
3284//
3285//      return newArr;
3286//     },
3287//
3288//     merge: function( current, data ){
3289//       
3290//      return this.copy(  data, current );
3291//
3292// //   return $.extend( current, data );
3293//
3294//     },
3295//     
3296//     // clone objects, skip other types.
3297//     clone: function(target) {
3298//          if ( typeof target == 'object' ) {
3299//                  Clone.prototype = target;
3300//                  return new Clone();
3301//          } else {
3302//                  return target;
3303//          }
3304//     },
3305//       
3306//     // Shallow Copy
3307//     shallowCopy: function(target) {
3308//          if (typeof target !== 'object' ) {
3309//                  return target;  // non-object have value sematics, so target is already a copy.
3310//          } else {
3311//                  var value = target.valueOf();
3312//                  if (target != value) {
3313//                          // the object is a standard object wrapper for a native type, say String.
3314//                          // we can make a copy by instantiating a new object around the value.
3315//                          return new target.constructor(value);
3316//                  } else {
3317//                          // ok, we have a normal object. If possible, we'll clone the original's prototype
3318//                          // (not the original) to get an empty object with the same prototype chain as
3319//                          // the original.  If just copy the instance properties.  Otherwise, we have to
3320//                          // copy the whole thing, property-by-property.
3321//                          if ( target instanceof target.constructor && target.constructor !== Object ) {
3322//                                  var c = clone(target.constructor.prototype);
3323//       
3324//                                  // give the copy all the instance properties of target.  It has the same
3325//                                  // prototype as target, so inherited properties are already there.
3326//                                  for ( var property in target) {
3327//                                          if (target.hasOwnProperty(property)) {
3328//                                                  c[property] = target[property];
3329//                                          }
3330//                                  }
3331//                          } else {
3332//                                  var c = {};
3333//                                  for ( var property in target ) c[property] = target[property];
3334//                          }
3335//                         
3336//                          return c;
3337//                  }
3338//          }
3339//     },
3340//
3341//     // entry point for deep copy.
3342//     // source is the object to be deep copied.
3343//     // depth is an optional recursion limit. Defaults to 256.
3344//     // deep copy handles the simple cases itself: non-objects and object's we've seen before.
3345//     // For complex cases, it first identifies an appropriate DeepCopier, then delegate the details of copying the object to him.
3346//     copy: function(source, result, depth) {
3347//       
3348//          // null is a special case: it's the only value of type 'object' without properties.
3349//          if ( source === null ) return null;
3350//
3351//          // All non-objects use value semantics and don't need explict copying.
3352//          if ( typeof source !== 'object' ) return source;
3353//
3354//          if( !depth || !(depth instanceof RecursionHelper) ) depth = new RecursionHelper(depth);
3355//
3356//          var cachedResult = depth.getCachedResult(source);
3357//
3358//          // we've already seen this object during this deep copy operation
3359//          // so can immediately return the result.  This preserves the cyclic
3360//          // reference structure and protects us from infinite recursion.
3361//          if ( cachedResult ) return cachedResult;
3362//
3363//          // objects may need special handling depending on their class.  There is
3364//          // a class of handlers call "DeepCopiers"  that know how to copy certain
3365//          // objects.  There is also a final, generic deep copier that can handle any object.
3366//          for ( var i=0; i<this.comparators.length; i++ ) {
3367//
3368//                  var comparator = this.comparators[i];
3369//
3370//                  if ( comparator.can(source) ) {
3371//     
3372//                          // once we've identified which DeepCopier to use, we need to call it in a very
3373//                          // particular order: create, cache, populate.  This is the key to detecting cycles.
3374//                          // We also keep track of recursion depth when calling the potentially recursive
3375//                          // populate(): this is a fail-fast to prevent an infinite loop from consuming all
3376//                          // available memory and crashing or slowing down the browser.
3377//       
3378//                          if( !result )
3379//                              // Start by creating a stub object that represents the copy.
3380//                              result = comparator.create(source);
3381//                          else if( !comparator.can(result) )
3382//                              throw new Error("can't compare diferent kind of objects.");
3383//
3384//                          // we now know the deep copy of source should always be result, so if we encounter
3385//                          // source again during this deep copy we can immediately use result instead of
3386//                          // descending into it recursively. 
3387//                          depth.cacheResult(source, result);
3388//
3389//                          // only DeepCopier.populate() can recursively deep copy.  So, to keep track
3390//                          // of recursion depth, we increment this shared counter before calling it,
3391//                          // and decrement it afterwards.
3392//                          depth.depth++;
3393//                          if ( depth.depth > depth.maxDepth ) {
3394//                                  throw new Error("Exceeded max recursion depth in deep copy.");
3395//                          }
3396//
3397//                          // It's now safe to let the comparator recursively deep copy its properties.
3398//                          var returned = comparator.populate( function(source, result) { return DataLayer.copy(source, result, depth); }, source, result );
3399//     
3400//                              if(returned)
3401//                                      result = returned;
3402//
3403//                          depth.depth--;
3404//
3405//                          return result;
3406//                  }
3407//          }
3408//          // the generic copier can handle anything, so we should never reach this line.
3409//          throw new Error("no DeepCopier is able to copy " + source);
3410//     },
3411//
3412//     // publicly expose the list of deepCopiers.
3413//     comparators: [],
3414//
3415//     // make deep copy() extensible by allowing others to
3416//     // register their own custom Comparators.
3417//     registerComparator: function(comparatorOptions) {
3418//
3419//        // publicly expose the Comparator class.
3420//        var comparator = {
3421//
3422//            // determines if this Comparator can handle the given object.
3423//            can: function(source) { return false; },
3424//     
3425//            // starts the deep copying process by creating the copy object.  You
3426//            // can initialize any properties you want, but you can't call recursively
3427//            // into the copy().
3428//            create: function(source) { },
3429//
3430//            // Completes the deep copy of the source object by populating any properties
3431//            // that need to be recursively deep copied.  You can do this by using the
3432//            // provided deepCopyAlgorithm instance's copy() method.  This will handle
3433//            // cyclic references for objects already deepCopied, including the source object
3434//            // itself.  The "result" passed in is the object returned from create().
3435//            populate: function(deepCopyAlgorithm, source, result) {}
3436//        };
3437//
3438//        for ( var key in comparatorOptions ) comparator[key] = comparatorOptions[key];
3439//
3440//        this.comparators.unshift( comparator );
3441//     },
3442// 
3443//     diff: function( base, toDiff ){
3444//
3445//      if( typeof base === 'undefined' || $.isEmptyObject(base) )
3446//          return( toDiff );
3447//
3448//      if( toDiff === false )
3449//          return( false );
3450//
3451//      toDiff = $.extend( {}, toDiff );
3452//
3453//      for( var key in toDiff )
3454//      {
3455//          switch( $.type(toDiff[key]) )
3456//          {
3457//            case 'object':
3458//              if( $.isEmptyObject(toDiff[key] = this.diff( base[key], toDiff[key] )) )
3459//                delete toDiff[key];
3460//            break;
3461//            case 'array':
3462//              if( base[key] && !(toDiff[key] = $.grep( toDiff[key], function( el, i ){ return( $.inArray( el, base[key] ) === -1 ); } )).length )
3463//                delete toDiff[key];
3464//            break;
3465//            default:
3466//              if( base[key] == toDiff[key] )
3467//                delete toDiff[key];
3468//          }
3469//      }
3470//
3471//      return( toDiff );
3472//
3473//     },
3474//     
3475//     links: function( concept, reverse ){
3476//
3477//      if( !this.links[ concept ] )
3478//      {
3479//          var result = this.dispatch( "links", { concept: concept } ) || false;
3480//
3481//          if( !result )
3482//              return( false );
3483//
3484//          this.concepts[ concept ] = $.extend( this.concepts[ concept ] || {},
3485//                                               result['concepts'] || {} );
3486//
3487//          this.links[ concept ] =  result['links'] || {};
3488//          this.nestedLinks[ concept ] = result['nestedLinks'] || {};
3489//      }
3490//
3491//      if( reverse )
3492//      {
3493//          return( this.nestedLinks[ concept ] );
3494// //       var reverted = {}, llinks = this.links[ concept ];
3495// //     
3496// //       for( var key in llinks )
3497// //           reverted[ llinks[key] ] = key;
3498// //
3499// //       return( reverted );
3500//      }
3501//
3502//      return( this.links[ concept ] );
3503//
3504//     },
3505//     
3506//     isConcept: function( concept, attr ){
3507//       
3508//      if( typeof this.concepts[concept] === "undefined" )
3509//      {
3510//          this.links( concept );
3511//      }
3512//
3513//      return !!this.concepts[ concept ][ attr ];
3514//     },
3515//     
3516//     URI: function( concept, URI, context ){
3517//       
3518//      if( res = internalUrl.exec( concept ) )
3519//          concept = res[1];
3520//     
3521//      context = context ? "(" + context + ")" : "";
3522//       
3523//      if( URI )
3524//          return( concept + context + "://" + URI );
3525//      else
3526//          return( concept );
3527//       
3528//     },
3529//     
3530//     parseURI: function( URI ){
3531//
3532//      return internalUri.exec( URI ) || false;
3533//
3534//     },
3535//     
3536//     
3537//   
3538//     
3539//     generateId: function( concept ){
3540//       
3541//      var newId = this.counter + "(javascript)";
3542//       
3543//      this.store( ":counter", (this.counter++) + "" );
3544//     
3545//      return( newId );
3546//     },
3547//   
3548//
3549//   
3550//
3551//     get: function( concept, /*URI, */filter, oneSide ){
3552//
3553//      ///////////////////////////// normalize ////////////////////////////////
3554//      if( arguments.length == 2 && $.type(filter) === "boolean" )
3555//      {
3556//          oneSide = filter;
3557//          filter = false;
3558//      }
3559//     
3560//      var encoder = false, id = false, bothSides = (typeof oneSide === 'undefined'), res;
3561//     
3562//      if( $.type(filter) === "string" )
3563//      {
3564//          id = filter;
3565//          filter = false;
3566//      }
3567//
3568//      filter = filter || false;
3569//
3570//      if( !concept )
3571//          return( false );
3572//
3573//      if( res = internalUrl.exec( concept ) )
3574//      {
3575//          encoder = concept;
3576//          concept = res[1];
3577//
3578//          if( filter )
3579//              filter = this.criteria( encoder, filter );
3580//      }
3581//     
3582//      if ( $.type(filter) === "array" )
3583//      {
3584//          filter = { filter: filter, criteria: false };
3585//      }
3586//     
3587//      //////////////////////////////////////////////////////////////////////////
3588//     
3589//      var result = false;
3590//
3591//      if( bothSides || !oneSide )
3592//          result = this.check( concept, id || filter );
3593//
3594//      if( !result && (bothSides || oneSide) )
3595//      {
3596//          result = this.request( concept, id || filter.filter, filter.criteria );
3597//
3598//          if( result && bothSides && (!filter ||
3599//                                      !filter.criteria ||
3600//                                      !filter.criteria.format) )
3601//          {
3602//            var newResult = [];
3603//         
3604//            for( var i = 0; i < result.length; i++ )
3605//                newResult[i] = $.extend( {}, result[i] );
3606//
3607//            this.put( concept, id, newResult, false );
3608//          }
3609//      }
3610//
3611//      if( /*result &&*/ encoder )
3612//          result = this.encode( encoder, result, filter ); //TODO: retirar o filtro no método encode
3613//
3614//      return( result );
3615//     },
3616//     
3617//     filter: function( base, filter, criteria ){
3618//       
3619//      var filtered = [];
3620//       
3621//      for( var key in base )
3622//      {
3623// //       if( !noGroup )
3624// //           for( var i = 0, current = original; i < filter.length && ( current === original ); i++ )
3625// //               current = this.compare( operator, current, this.compare( base[key], filter[i] ) );
3626//
3627//          if( this.storage.filter( base[key], filter ) )
3628//              filtered[ filtered.length ] = key;
3629//      }
3630//
3631//      return( filtered );
3632//     },
3633//     
3634//     compare: function( operator, base, test ){
3635//       
3636//       switch( operator )
3637//       {
3638//        case '*':  return RegExp( ".*" + test + ".*" ).test( base );
3639//        case '^':  return RegExp( "^" + test +  ".*" ).test( base );
3640//        case '$':  return RegExp( ".*"  + test + "$" ).test( base );
3641//
3642//        case '&':  return ( base && test );
3643//        case '|':  return ( base || test );
3644//
3645//        case '=':  return ( base == test );
3646//        case '<=': return ( base <= test );
3647//        case '>=': return ( base >= test );
3648//        case '>':  return ( base <  test );
3649//        case '<':  return ( base >  test );
3650//       }
3651//       
3652//     },
3653//     
3654// //     clone: function( object ){
3655// //
3656// //   new { prototype: object };
3657// //
3658// //     },
3659//
3660//     check: function( namespace, keys ){
3661//
3662//      if( !namespace )
3663//          return( false );
3664//
3665//      var result = this.storage.get( namespace );
3666//
3667//      if( !keys || !result )
3668//        return( result || false );
3669//
3670//      if( notArray = $.type(keys) === "string" )
3671//          keys = [ keys ];
3672//      else if( $.type(keys) !== "array" )
3673//          keys = this.filter( result, keys.filter, keys.criteria );
3674//
3675//      var res = [];
3676//
3677//      for( var i = 0; i < keys.length; i++ )
3678//          res[ res.length ] = result[keys[i]];
3679//
3680//      return( notArray ? res[0] || false : res.length ? res : false );
3681//     },
3682//
3683//     storage: {
3684//       
3685//      cache: {},
3686//       
3687//      set: function( key, value ){
3688//
3689//          this.cache[key] = value;
3690//
3691//      },
3692//      get: function( key ){
3693//
3694//          return DataLayer.copy( this.cache[key] );
3695//
3696//      },
3697//      del: function( key ){
3698//
3699//          delete this.cache[key];
3700//
3701//      },
3702//     
3703//      filter: function( base, filter ){
3704//       
3705//          var bool, op = filter.shift();
3706//
3707//          switch( op )
3708//          {
3709//              case 'IN':
3710//                for( var i = 0, f = []; i < filter[1].length || !(filter = f); i++ )
3711//                    f[i] = [ '=', filter[0], filter[1][i] ];
3712//              case 'OR':
3713//                  op = '|';
3714//                  bool = false;
3715//              break;
3716//              case 'AND':
3717//                  op = '&';
3718//                  bool = true;
3719//              break;
3720//              default : return DataLayer.compare( op, base[ filter[0] ], filter[1] );
3721//          }
3722//         
3723//          for( var strict = bool;
3724//
3725//              filter.length && ( strict ? bool : !bool );
3726//         
3727//              bool = DataLayer.compare( op, bool, this.filter( base, filter.shift() ) ) );
3728//
3729//          return( bool );
3730//      }
3731//     },
3732//
3733//     flush: function(){
3734//
3735//     },
3736//     
3737//     restore: function(){
3738//       
3739//     },
3740//
3741//     store: function( namespace, key, data ){
3742//
3743//      if( !data )
3744//        return this.storage.set( namespace, key );
3745//
3746//      var res = this.check( namespace ) || {};
3747//
3748//      res[key] = data;
3749//
3750//      return this.storage.set( namespace, res );
3751//     },
3752//
3753//     del: function( namespace, key ){
3754//       
3755//      if( !key )
3756//        return this.storage.del( namespace );
3757//
3758//      var res = this.check( namespace ) || {};
3759//
3760//      delete res[key];
3761//
3762//      return this.storage.set( namespace, res );
3763//       
3764//     },
3765//     
3766//      move: function( concept, oldId, newId ){
3767//
3768//      this.put( concept, newId, this.check( concept, oldId ), false );
3769//
3770//      this.remove( concept, oldId, false );
3771//     },
3772//     
3773//
3774//     
3775//     
3776//     
3777//     request: function( concept, filter, criteria ){
3778//
3779//       var id = false, criteria = criteria || {};
3780//
3781//       if( $.type(filter) === "string" )
3782//       {
3783//        id = filter;
3784//        filter = false;
3785//       }
3786//
3787//       return this.dispatch( "request", {
3788//
3789//        concept: concept || '',
3790//        id: id || '',
3791//        filter: filter || '',
3792//        criteria: criteria || '',
3793//        service: criteria.service || '',
3794//        properties: criteria.properties || ''
3795//
3796//       } );
3797//     },
3798//
3799//     
3800//     //         sync: function( data, callback ){
3801// //
3802// //   if( !data || $.isEmptyObject( data ) )
3803// //       return;
3804// //       
3805// //   this.send( "Sync", data, function( data, status, jqXHR ){
3806// //
3807// // //            switch( status )
3808// // //            {
3809// // //              case "error":
3810// // //              case "parsererror":
3811// // //                return DataLayer.rollback( concept, URI );
3812// // //              case "success":
3813// // //                return DataLayer.commit();
3814// // //              case "timeout":
3815// // //              case "notmodified":
3816// // //            }
3817// //
3818// //       if( callback )
3819// //       {
3820// //           var result = callback( data, status, jqXHR );
3821// //
3822// //           if( result === false )
3823// //               return;
3824// //           else if( typeof result != "undefined" )
3825// //               data = result;
3826// //       }
3827// //
3828// //       for( var URI in data )
3829// //       {
3830// //           var parsed = DataLayer.parseURI( URI ),
3831// //   
3832// //           concept = parsed[1], /*URI = parsed[3],*/
3833// //
3834// //           links = DataLayer.links( concept );
3835// //
3836// //           for( var linkName in links )
3837// //           {
3838// //               var subURI = data[URI][linkName];
3839// //
3840// //               if( subURI && data[subURI] )
3841// //               {
3842// //                   data[URI][linkName] = DataLayer.put( linkName, subURI, data[subURI], false );
3843// //
3844// //                   delete( data[subURI] );
3845// //               }
3846// //           }
3847// //
3848// //           DataLayer.put( concept, URI, data[URI], false );
3849// //       }
3850// //   }, true );
3851// //
3852// //     },
3853//
3854// //     report: function( concept, URI, data, sync )
3855// //     {
3856// //   var current = this.dequeue( 'current', concept, URI );
3857// //
3858// //   if( !current )
3859// //       this.enqueue( 'current', concept, URI, ( current = this.check( concept, URI ) || {} ) );
3860// //
3861// //   var diff = this.diff( current, data );
3862// //
3863// //   if( !diff )
3864// //       this.dequeue( 'current', concept, URI, true );
3865// //   else
3866// //       this.enqueue( 'diff', concept, URI, diff );
3867// //   
3868// //   if( sync )
3869// //       this.commit( concept, URI, function(){
3870// //
3871// //           DataLayer.set( concept, URI, data, false );
3872// //
3873// //       });
3874// //     },
3875//     
3876// //     enqueue: function( type, concept, URI, obj ){
3877// //       
3878// //   //var newURI = this.URI( concept, URI );
3879// //   
3880// //   if( !this.queue[type] )
3881// //       this.queue[type] = {};
3882// //
3883// //   if( !this.queue['all'] )
3884// //       this.queue['all'] = {};
3885// //   
3886// //   if( !this.queue[type][concept] )
3887// //       this.queue[type][concept] = {};
3888// //   
3889// //   if( !this.queue['all'][type] )
3890// //       this.queue['all'][type] = {};
3891// //   
3892// //   if( !this.queue['all'][type][/*new*/URI] )
3893// //       this.queue[type][concept][URI] = this.queue['all'][type][/*new*/URI] = obj;
3894// //
3895// //   this.store( ':queue', this.queue );
3896// //     },
3897// //     
3898// //     dequeue: function( type, concept, URI, remove ){
3899// //       
3900// //       ///////////////////////////// normalize ////////////////////////////////
3901// //   if( arguments.length < 4 && $.type(URI) === 'boolean' )
3902// //   {
3903// //       remove = URI;
3904// //       URI = false;
3905// //   }
3906// //   if( arguments.length < 3 && $.type(concept) === 'boolean' )
3907// //   {
3908// //       remove = concept;
3909// //       concept = false;
3910// //   }
3911// //       //////////////////////////////////////////////////////////////////////////
3912// //       
3913// //   if( !this.queue[type] || !this.queue['all'] )
3914// //       return( false );
3915// //   
3916// //   if( !concept )
3917// //   {
3918// //       var obj = this.queue['all'][type];
3919// //       
3920// //       if( remove )
3921// //       {
3922// //           delete this.queue['all'][type];
3923// //           delete this.queue[type];
3924// //       }
3925// //
3926// //       this.store( ':queue', this.queue );
3927// //       return( obj );
3928// //   }
3929// //
3930// //   if( !this.queue[type][concept] )
3931// //       return( false );
3932// //   
3933// //   if( !URI )
3934// //   {
3935// //       var obj = this.queue[type][concept];
3936// //
3937// //       if( remove )
3938// //       {
3939// //           var URIs = this.queue[type][concept];
3940// //
3941// //           for( var subURI in URIs )
3942// //                delete this.queue['all'][type][subURI];
3943// //
3944// //           delete this.queue[type][concept];
3945// //       }
3946// //
3947// //       this.store( ':queue', this.queue );
3948// //       return( obj );
3949// //   }
3950// //
3951// // //        var newURI = URI ? this.URI( concept, URI ) : concept;
3952// //   
3953// //   var obj = this.queue['all'][type][/*new*/URI];
3954// //   
3955// //   if( remove )
3956// //   {
3957// //       delete this.queue['all'][type][/*new*/URI];
3958// //       delete this.queue[type][concept][URI];
3959// //   }
3960// //
3961// //   this.store( ':queue', this.queue );
3962// //   return( obj );
3963// //     },
3964//     
3965//            //TODO: definir a 'usage' desta função e refatora-la
3966// //     set: function( concept, filter, data, oneSide ){
3967// //
3968// //   ///////////////////////////// normalize ////////////////////////////////
3969// //   if( arguments.length == 2 )
3970// //   {
3971// //       data = filter;
3972// //       filter = false;
3973// //   }
3974// //   if( $.type(data) === "boolean" )
3975// //   {
3976// //       oneSide = data;
3977// //       data = filter;
3978// //       filter = false;
3979// //   }
3980// //   
3981// //   if( !concept || !data )
3982// //       return( false );
3983// //
3984// //   var decoder = "", URI = false, bothSides = (typeof oneSide === "undefined");
3985// //   
3986// //   if( $.type(filter) === "string" )
3987// //   {
3988// //       URI = filter;
3989// //       filter = false;
3990// //   }
3991// //
3992// //   if( res = internalUrl.exec( concept ) )
3993// //   {
3994// //       //TODO: verificar se a decodificaçao deve ser feita em cada item do array
3995// //       data = this.decode( concept, data );
3996// //       concept = res[1];
3997// //       decoder = res[2];
3998// //   }
3999// //   ///////////////////////////////////////////////////////////////////////////
4000// //
4001// //   if( bothSides || oneSide )
4002// //       this.report( concept, URI, data, !bothSides );
4003// //
4004// //   if( bothSides || !oneSide )
4005// //   {
4006// //       if( URI )
4007// //       {
4008// //         var helper = {};
4009// //         helper[URI] = data;
4010// //         data = helper;
4011// //       }
4012// //
4013// //       for( var URI in data )
4014// //       {
4015// //           var current = this.check( concept, URI ) || {};
4016// //
4017// //           data[URI] = this.merge( current, data[URI] );
4018// //
4019// //           this.store( concept, URI, data[URI] );
4020// //       }
4021// //
4022// //   }
4023// //
4024// //   this.broadcast( concept, oneSide ? 'client' : 'server' );
4025// //
4026// //   return( true );
4027// //     },
4028// //     put: function( concept, URI, data, oneSide ){
4029// //       
4030// //       ///////////////////////////// normalize ////////////////////////////////
4031// //   if( $.type(URI) !== "string" && arguments.length < 4 )
4032// //   {
4033// //       oneSide = data;
4034// //       data = URI;
4035// //       URI = false;
4036// //   }
4037// //       ////////////////////////////////////////////////////////////////////////
4038// //       
4039// //       ////////////////////////////// linkage /////////////////////////////////
4040// //   var result = false, links = this.links( concept );
4041// //
4042// //   for( var link in links )
4043// //   {
4044// //       if( data[link] )
4045// //       {
4046// //           if( $.isArray( data[link] ) )
4047// //           {
4048// //               data[link] = this.put( links[link], data[link].URI, data[link], oneSide );
4049// //           }
4050// //           else if( $.isObject( data[link] ) )
4051// //           {
4052// //               $.each( data[link], function( i, el ){
4053// //
4054// //                     data[link][i] = this.put( links[link], el.URI, el, oneSide );
4055// //
4056// //               });
4057// //           }
4058// //       }
4059// //   }
4060// //       //////////////////////////////////////////////////////////////////////////
4061// //     
4062// //   if( typeof data.URI === "undefined" )
4063// //   {
4064// //       URI = this.add( concept, data, oneSide );
4065// //   }
4066// //   else if( data.URI === false )
4067// //   {
4068// //       status = this.remove( concept, URI, oneSide );
4069// //   }
4070// //   else
4071// //   {
4072// //       status = this.set( concept, URI, data, oneSide );
4073// //   }
4074// //
4075// //   if( URI && data.URI && URI !== data.URI )
4076// //       this.move( concept, URI, data.URI );
4077// //
4078// //   return( data.URI || URI );
4079// //
4080// //     },
4081//     
4082//     //     add: function( concept, data, oneSide ){
4083// //       
4084// //       ///////////////////////////// normalize ////////////////////////////////
4085// //   if( !concept || !data )
4086// //       return( false );
4087// //
4088// //   if( res = internalUrl.exec( concept ) )
4089// //   {
4090// //       //TODO: verificar se a decodificaᅵᅵo deve ser feita em cada item do array
4091// //       data = this.decode( concept, data );
4092// //       concept = res[1];
4093// //       decoder = res[2];
4094// //   }
4095// //
4096// //   var bothSides = (typeof oneSide === "undefined"), uris = [];
4097// //
4098// //   if( notArray = $.type(data) !== "array" )
4099// //       data = [ data ];
4100// //       //////////////////////////////////////////////////////////////////////////
4101// //
4102// //   for( var i = 0; i < data.length; i++ )
4103// //   {
4104// //       var URI = uris[i] = this.generateURI( concept );
4105// //
4106// //       this.set( concept, URI, data[i], oneSide );
4107// //   }
4108// //
4109// //   return( notArray ? uris[0] : uris );
4110// //     },
4111// //      put: function( concept, data ){
4112// //
4113// //   var decoder = "";
4114// //
4115// //   if( res = internalUrl.exec( concept ) )
4116// //   {
4117// //       data = this.decode( concept, data );
4118// //       concept = res[1];
4119// //       decoder = res[2];
4120// //   }
4121// //
4122// //   var New = [], Update = [], uris = [];
4123// //
4124// //   if( notArray = $.type(data) !== "array" )
4125// //       data = [ data ];
4126// //   
4127// //   for( var i = 0; i < data.length; i++ )
4128// //   {
4129// //       if( !data[i].URI )
4130// //       {
4131// //           uris[ uris.length ] = data[i].URI = this.create( concept, data[i] );
4132// //           New[ New.length ] = data[i];
4133// //           continue;
4134// //       }
4135// //
4136// //       for( var key in data[i] )
4137// //           if( klass = this.isReference( concept, key, data[i][key] ) )
4138// //                 data[i][key] = this.put( klass + decoder, data[i][key] );
4139// //
4140// //       Update[ Update.length ] = this.update( concept, data[i].URI, data[i] );
4141// //   }
4142// //
4143// //   this.report( concept, { "created": New, "updated": Update });
4144// //
4145// //   return( notArray ? uris[0] : uris );
4146// //     },
4147// //     merge: function( concept, current, data ){
4148// //
4149// //   current = current || {};
4150// //
4151// //   for( var key in data )
4152// //       current[key] = (klass = this.isReference( concept, key, data[key] )) ?
4153// //                      this.merge( klass, current[key], data[key] ) : data[key];
4154// //
4155// //   return( current );
4156// //     },
4157// //
4158// //     isReference: function( concept, key, value ){
4159// //
4160// //       return( ($.type(value) === "object" ||
4161// //          $.type(value) === "array" )? this.links[concept][key] : false );
4162// //
4163// //     },
4164// //     
4165// //     set: function( concept, data, URI, mergeable ){
4166// //   
4167// //   if( URI )
4168// //   {
4169// //       var res = this.get( concept, true ) || {};
4170// //       
4171// //       if( mergeable )
4172// //           data = this.merge( res[URI] || {}, data );
4173// //
4174// //       res[URI] = data;
4175// //
4176// //       data = res;
4177// //   }
4178// //
4179// //   return this.store( concept, data );
4180// //     },   
4181// //
4182// //     create: function( concept, data ){
4183// //
4184// //       if( notArray = ($.type(data) !== "array") )
4185// //       data = [ data ];
4186// //
4187// //       var uris = [];
4188// //
4189// //       for( var i = 0; i < data.length; i++ )
4190// //       {
4191// //     uris[ uris.length ] = data[i].URI = "javascript://" + (this.counter + i);
4192// //
4193// //     this.set( concept, data[i], data[i].URI );
4194// //       }
4195// // 
4196// //       this.set( ":counter", (this.counter += data.length) );
4197// //
4198// //       return notArray ? uris[0] : uris;
4199// //     },
4200// //
4201// //     update: function( concept, URI, data )
4202// //     {
4203// //   var target = this.check( concept, URI ) || {};
4204// //
4205// //   target = this.merge( concept, target, data );
4206// //
4207// //   if( target.URI !== URI )
4208// //       this.remove( concept, URI );
4209// //
4210// //   this.set( concept, target, target.URI );
4211// //
4212// //   return( target );
4213// //     },
4214// //
4215// //     remove: function( concept, URI ){
4216// //
4217// //   if( !URI )
4218// //       return this.storage.del( concept );
4219// //
4220// //   var res = this.check( concept );
4221// //
4222// //   delete res[URI];
4223// //   
4224// //   this.set( concept, res );
4225// //     },
4226// //
4227// //     del: function( concept, URI ){
4228// //
4229// //   this.remove( concept, URI );
4230// //
4231// //   this.report( concept, { "deleted": { 'URI': URI } });
4232// //     },
4233// //
4234// //     report: function( concept, changes ){
4235// //
4236// //       this.broadcast( concept, changes.created, changes.updated, changes.deleted );
4237// //
4238// //   if( changes.created )
4239// //       this.sync( concept, changes.created, 'create' );
4240// //   if( changes.updated )
4241// //       this.sync( concept, changes.updated, 'update' );
4242// //   if( changes.deleted )
4243// //       this.sync( concept, changes.deleted, 'delete' );
4244// //
4245// //     },
4246// //
4247// //
4248// //    sync: function( concept, data, type ){
4249// //
4250// //   if( $.type(data) !== "array" )
4251// //       data = [ data ];
4252// //
4253// //   $.each( data, function( i, el ){
4254// //
4255// //      DataLayer.send( concept, el, type );
4256// //
4257// //   });
4258// //
4259// //     },
4260// //     
4261// //     
4262// //     
4263// //     
4264// //
4265// //     request: function( concept, URI, filter ){
4266// //
4267// // //       if( startsDoubleDot.test(concept) )
4268// // //          return( false );
4269// //
4270// //       filter = filter || {};
4271// //
4272// //       if( URI )
4273// //   filter.URI = URI;
4274// //
4275// //       return this.send( concept, filter, "read", true );
4276// //
4277// //     },
4278// //
4279// //     send: function( concept, data, type, wait ){
4280// //
4281// //       switch( type )
4282// //       {
4283// //   case "create": type = "POST"; break;
4284// //   case "update": type = "PUT"; break;
4285// //   case "delete": type = "DELETE"; break;
4286// //   case "read": type = "GET"; break;
4287// //       }
4288// //
4289// //       var url = this.basePath + concept;
4290// //
4291// //       var result = [], notArray = false;
4292// //
4293// // //      alert( data.URI );
4294// //
4295// //       if( data.URI && data.URI.indexOf("javascript://") !== 0 )
4296// //     url += "/" + data.URI;
4297// //
4298// //       var callback = function( dt, textStatus, jqXHR ){
4299// //
4300// //       if( notArray = (!$.isArray( dt )) )
4301// //           dt = [ dt ];
4302// //
4303// //       $.each( dt, function( i, el ){
4304// //
4305// //           if( !el || !el.URI )
4306// //               return;
4307// //
4308// //           if( data.URI )
4309// //               el = DataLayer.update( concept, data.URI, el );
4310// //           else
4311// //               DataLayer.set( concept, el, el.URI );
4312// //
4313// //           result[ result.length ] = el;
4314// //           DataLayer.broadcast( concept );
4315// //     });
4316// //       };
4317// //
4318// //       $.ajax({
4319// //         'async': ( !wait ),
4320// //         'url': url,
4321// //         'type': type,
4322// //         'success': callback,
4323// //         'dataType': 'json',
4324// //         'data': data/*,
4325// //         'processData': false*/
4326// //     });
4327// //
4328// //       return( notArray ? result[0] || false : result );
4329// //     },
4330//     
4331//     
4332//     generateURI: function( concept ){
4333//       
4334//      return this.URI( concept, this.generateId( concept ), "javascript" );
4335//
4336//     },
4337//     
4338//
4339//     broadcast: function( concept, status, diff ){
4340//
4341//      if( this.listeners[ concept ] )
4342//          for( var i = 0;
4343//              i < this.listeners[ concept ].length;
4344//              this.listeners[ concept ][ i++ ]( status, diff ) );
4345//     },
4346//
4347//     listen: function( concept, listener ){
4348//
4349//      this.register( "listeners", concept, listener );
4350//
4351//     },
4352//
4353//     codec: function( concept, namespace, codec ){
4354//
4355//      if( codec.encoder )
4356//          this.encoder( concept, namespace, codec.encoder );
4357//      if( codec.decoder )
4358//          this.decoder( concept, namespace, codec.decoder );
4359//      if( codec.criteria )
4360//          this.register( "criterias", concept + ":" + namespace, codec.criteria );
4361//
4362//     },
4363//
4364//     encoder: function( concept, namespace, encoder ){
4365//
4366//      this.register( "encoders", concept + ":" + namespace, encoder );
4367//
4368//     },
4369//
4370//     encode: function( encoder, data, filter ){
4371//
4372//      if( this.encoders[ encoder ] )
4373//          for( var i = 0;
4374//              i < this.encoders[ encoder ].length;
4375//              data = this.encoders[ encoder ][ i++ ]( data, filter ) );
4376//
4377//      return( data );
4378//     },
4379//
4380//     decoder: function( concept, namespace, decoder ){
4381//
4382//      this.register( "decoders", concept + ":" + namespace, decoder );
4383//
4384//     },
4385//
4386//     decode: function( decoder, data ){
4387//
4388//      if( this.decoders[ decoder ] )
4389//          for( var i = 0;
4390//              i < this.decoders[ decoder ].length;
4391//              data = this.decoders[ decoder ][ i++ ]( data ) );
4392//
4393//      return( data );
4394//     },
4395//
4396//     criteria: function( codec, filter ){
4397//
4398//      if( this.criterias[ codec ] )
4399//          for( var i = 0;
4400//              i < this.criterias[ codec ].length;
4401//              filter = this.criterias[ codec ][ i++ ]( filter ) );
4402//
4403//      return( filter );
4404//
4405//     },
4406//
4407//     register: function( kind, concept, deployable ){
4408//
4409//       if( arguments.length < 3 )
4410//       {
4411//        deployable = concept;
4412//        concept = kind;
4413//        kind = 'global';
4414//       }
4415//
4416//       if( !this[ kind ][ concept ] )
4417//          this[ kind ][ concept ] = [];
4418//
4419//      this[ kind ][ concept ][ this[ kind ][ concept ].length ] = deployable;
4420//
4421//     },
4422//     
4423//     start: function(){
4424//
4425//      var timer = function(){
4426//
4427//            setTimeout( timer, 1 );
4428//
4429//            var now = parseInt( $.now() / 1000 );
4430//
4431//            var tasks = DataLayer.tasks[ now ];
4432//
4433//            if( !tasks ) return;
4434//
4435//            for( var i = 0; i < tasks.length; i++ )
4436//            {
4437//                var result = tasks[i].task( now );
4438//
4439//                if( tasks[i].factor )
4440//                DataLayer.schedule( tasks[i].task, tasks[i].factor );
4441//            }
4442//       
4443//            delete DataLayer.tasks[ now ];
4444//      };
4445//
4446//      setTimeout( timer, 1 );
4447//     },
4448//     
4449//     task: function( timestamp, task, factor )
4450//     {
4451//      if( !this.tasks[ timestamp ] )
4452//          this.tasks[ timestamp ] = [];
4453//
4454//      this.tasks[ timestamp ][ this.tasks[ timestamp ].length ] = { task: task, factor: factor || false };
4455//     },
4456//
4457//     schedule: function( task, time ){
4458//
4459//      time = time || 1;
4460//     
4461//      var index = parseInt( $.now() / 1000 ) + time;
4462//
4463//      this.task( index, task, time );
4464//     },
4465//     
4466//     poll: function( concept, time ){
4467//       
4468//       this.schedule( function( now ){
4469//   
4470//        DataLayer.commit( concept );
4471//
4472//      }, time || 5 );
4473//     },
4474//     
4475//     init: function(){
4476//       
4477//      this.counter = parseInt( this.get( ":counter", false ) ) || 0;
4478//
4479//      if( !this.dispatchPath )
4480//          this.dispatchPath = "../../";
4481//
4482//      if( !this.templatePath )
4483//          this.templatePath = "";
4484//
4485//      if( !this.basePath )
4486//          this.basePath = this.dispatchPath + "REST.php?q=";
4487//
4488//      this.schedule( function( now ){
4489//
4490//          DataLayer.flush();
4491//
4492//      });
4493//
4494//      this.start();
4495//     }
4496// }
4497//
4498// // the re-usable constructor function used by clone().
4499// function Clone() {}
4500//
4501// //Recursion Helper
4502// function RecursionHelper(){ this.clear(); };
4503//
4504// RecursionHelper.prototype = {
4505//   
4506//      constructor: RecursionHelper,
4507//
4508//      // copiedObjects keeps track of objects already copied by this
4509//      // deepCopy operation, so we can correctly handle cyclic references.
4510//      copiedObjects: [],
4511//
4512//      depth: 0,
4513//
4514//      maxDepth: 256,
4515//
4516//      //reset the recursion helper cache
4517//      clear: function(){
4518//              this.copiedObjects = [];
4519//              this.depth = 0;
4520//      },
4521//
4522//      // add an object to the cache.  No attempt is made to filter duplicates;
4523//      // we always check getCachedResult() before calling it.
4524//      cacheResult: function(source, result) {
4525//              this.copiedObjects.push([source, result]);
4526//      },
4527//
4528//      // Returns the cached copy of a given object, or undefined if it's an
4529//      // object we haven't seen before.
4530//      getCachedResult: function(source) {
4531//
4532//              for ( var i=0; i<this.copiedObjects.length; i++ ) {
4533//                      if ( this.copiedObjects[i][0] === source ) {
4534//                              return this.copiedObjects[i][1];
4535//                      }
4536//              }
4537//
4538//              return undefined;
4539//      }
4540// };
4541//
4542// // Generic Object copier
4543// // the ultimate fallback DeepCopier, which tries to handle the generic case.  This
4544// // should work for base Objects and many user-defined classes.
4545// DataLayer.registerComparator({
4546//      can: function(source) { return true; },
4547//
4548//      create: function(source) {
4549//              if ( source instanceof source.constructor ) {
4550//                      return DataLayer.clone(source.constructor.prototype);
4551//              } else {
4552//                      return {};
4553//              }
4554//      },
4555//
4556//      populate: function(deepCopy, source, result) {
4557//              for ( var key in source ) {
4558//                      if ( source.hasOwnProperty(key) ) {
4559//                              result[key] = deepCopy(source[key], result[key]);
4560//                      }
4561//              }
4562//              return result;
4563//      }
4564// });
4565//
4566// // Array copier
4567// DataLayer.registerComparator({
4568//      can: function(source) {
4569//              return ( source instanceof Array );
4570//      },
4571//
4572//      create: function(source) {
4573//              return new source.constructor();
4574//      },
4575//
4576//      populate: function(deepCopy, source, result) {
4577//              for ( var i=0; i<source.length; i++) {
4578//                      result.push( deepCopy(source[i], result[i]) );
4579//              }
4580//              result =  DataLayer.unique( result )
4581//              return result;
4582//      }
4583// });
4584//
4585// // Date copier
4586// DataLayer.registerComparator({
4587//      can: function(source) {
4588//              return ( source instanceof Date );
4589//      },
4590//
4591//      create: function(source) {
4592//              return new Date(source);
4593//      }
4594// });
4595//
4596// // HTML DOM Node copier
4597// DataLayer.registerComparator({
4598//
4599//      // function to detect Nodes.  In particular, we're looking
4600//      // for the cloneNode method.  The global document is also defined to
4601//      // be a Node, but is a special case in many ways.
4602//      can: function(source) {
4603//       
4604//        if ( window.Node ) {
4605//                return source instanceof Node;
4606//        } else {
4607//                // the document is a special Node and doesn't have many of
4608//                // the common properties so we use an identity check instead.
4609//                if ( source === document ) return true;
4610//                return (
4611//                        typeof source.nodeType === 'number' &&
4612//                        source.attributes &&
4613//                        source.childNodes &&
4614//                        source.cloneNode
4615//                );
4616//        }
4617//       },
4618//
4619//       create: function(source) {
4620//            // there can only be one (document).
4621//            if ( source === document ) return document;
4622//
4623//            // start with a shallow copy.  We'll handle the deep copy of
4624//            // its children ourselves.
4625//            return source.cloneNode(false);
4626//       },
4627//       
4628//       diff: function(base, source){
4629//     
4630//       },
4631//
4632//       populate: function(deepCopy, source, result) {
4633//            // we're not copying the global document, so don't have to populate it either.
4634//            if ( source === document ) return document;
4635//
4636//            // if this Node has children, deep copy them one-by-one.
4637//            if ( source.childNodes && source.childNodes.length ) {
4638//                    for ( var i=0; i<source.childNodes.length; i++ ) {
4639//                            var childCopy = deepCopy(source.childNodes[i], result.childNodes[i] || false );
4640//                            result.appendChild(childCopy);
4641//                    }
4642//            }
4643//              return result;
4644//       }
4645// });
4646//
4647// DataLayer.init();
4648//
4649// // setTimeout(function(){
4650// // 
4651// //     
4652// //
4653// // }, 1000 );
4654//
4655// // var DataLayer = {
4656// //
4657// //     get: function( concept, filter ){
4658// //
4659// //   var data = this.storage.get( concept );
4660// //
4661// //   if( !filter )
4662// //       return( data );
4663// //
4664// //   return this.filter( data, filter );
4665// //     },
4666// //     
4667// //     filter:function( data, filter ){
4668// //       
4669// //   if( filter.charAt )
4670// //       filter = { URI: filter };
4671// //   
4672// //   var filtered = [];
4673// //
4674// //   $.each(data, function(i, obj){
4675// //     
4676// //       for( var attr in filter )
4677// //           if( filter[attr] !== obj[attr] )
4678// //               return( true );
4679// //
4680// //       filtered[i] = obj;
4681// //   });
4682// //
4683// //   return( filtered );
4684// //     },
4685// //
4686// //     find: function( concept, filter, callback ){
4687// //
4688// //   var data = this.get( concept, filter );
4689// //
4690// //   if( data )
4691// //       return callback( data );
4692// //
4693// //   //TODO: register callback like a weak listener
4694// //
4695// // //        $.ajax({
4696// // //              type: 'GET',
4697// // //              data: $.param( filter ),
4698// // //              success: callback, 
4699// // //              url: BASE_PATH + filter.URI || concept
4700// // //        });
4701// //   this.report( concept, filter );
4702// //     },
4703// //
4704// //     put: function( concept, data, filter ){
4705// //
4706// //   var beforeDiff = this.store( concept, $.extend({},data) );
4707// //
4708// //   this.report( concept, data, filter, beforeDiff );
4709// //     },
4710// //     
4711// //     
4712// //     /*var data = {
4713// //                   startTime: $.now(),
4714// //                   endTime: $.now() + 1800000,
4715// //                   summary: "meu querido evento",
4716// //                   description: "desc do evento",
4717// //                   location: "prognus software livre",
4718// //                   class: 1,
4719// //                   calendar: 1,
4720// //                   category: 1,
4721// //                   participants: [ {
4722// //                                      user: { isExternal: true, mail: "user7@prognus.org", name: "user7" }
4723// //                                 },{
4724// //                                      user: "1003"
4725// //                                 } ]
4726// //
4727// //             };*/
4728// //     
4729// //
4730// //     merge:function( data, target ){
4731// //       
4732// //   var diff = { New: {}, Update:{}, Delete: {} };
4733// //       
4734// //   for( var key in data )
4735// //   {
4736// //       if( !target[ key ] )
4737// //           diff.New[ key ] = target[ key ] = data[ key ];
4738// //
4739// //       
4740// //     
4741// //   }
4742// //       
4743// //     }
4744// //
4745// //     store: function( concept, data, filter ){
4746// //
4747// //   if( !data.spline )
4748// //       data = [ data ];
4749// //
4750// //   var target = this.storage.get( concept );
4751// //   
4752// //   var diff = { New: {}, Update:{}, Delete: {} };
4753// //
4754// //   for( var i = 0; i < data.length; i++ )
4755// //   {
4756// //       if( data[i].URI && target[ data[i].URI ] )
4757// //       {
4758// //           diff.Update[ data[i].URI ] = this.merge( target[ data[i].URI ], data[i] );
4759// //       }
4760// //       else
4761// //       {
4762// //           diff.New[] = data[i];
4763// //       }
4764// //   }
4765// //
4766// //   
4767// //
4768// //   this.broadcast( concept, data );
4769// //
4770// //   if( filter )
4771// //       target = this.filter( target, filter );
4772// //
4773// //   if( target )
4774// //       data = $.extend( target, data );
4775// //
4776// //   this.storage.set( concept, data );
4777// //
4778// // //        return;
4779// //     },
4780// //     
4781// //     set: function( concept, data, filter ){
4782// //
4783// //       
4784// //
4785// //     },
4786// //
4787// //     post: function( concept, data, filter, isNew ){
4788// //
4789// //   var callback = function(  ){ DataLayer.store( concept, data, filter ) };
4790// //
4791// //   //TODO: register callback like a weak listener
4792// //
4793// //   this.report( concept, data, filter, isNew );
4794// //     },
4795// //     
4796// //     report: function( concept, filter, postData, isNew ){
4797// //       
4798// //   $.ajax({
4799// //           type: postData ? isNew ? 'POST' : 'PUT' : 'GET',
4800// //           data: postData || $.param( filter ),
4801// //           success: function( data ){ DataLayer.broadcast( concept ) },
4802// //           url: BASE_PATH + filter.URI || concept
4803// //     });
4804// //     },
4805// //     
4806// //     del:function( concept, filter ){
4807// //
4808// //       
4809// //
4810// //     }
4811// //     
4812// //     broadcast: function( concept, data ){
4813// //
4814// //   
4815// //
4816// //     },
4817// //
4818// //     pool: function(){
4819// //       
4820// //     },
4821// //
4822// //     refresh: function(){
4823// //       
4824// //     }
4825// // };
4826//
4827// //
4828// // DataLayer = {
4829// //   
4830// //     get: function( concept, filter ){
4831// //
4832// //   var data = this.storage.get( concept );
4833// //
4834// //   if( !filter )
4835// //       return( data );
4836// //
4837// //   if( filter.charAt )
4838// //       filter = { URI: filter };
4839// //   
4840// //   var filtered = [];
4841// //
4842// //   $.each(data, function(i, obj){
4843// //     
4844// //       for( var attr in filter )
4845// //           if( filter[attr] !== obj[attr] )
4846// //               return( true );
4847// //
4848// //       filtered[i] = obj;
4849// //   });
4850// //
4851// //   return( filtered );
4852// //     },
4853// //
4854// //     find: function( concept, filter, callback ){
4855// //
4856// //   var data = this.get( concept, filter );
4857// //
4858// //   if( data )
4859// //       return callback( data );
4860// //
4861// //    $.ajax({
4862// //         type: 'GET',
4863// //         data: $.param( filter ),
4864// //         success: callback, 
4865// //         url: filter.URI || concept
4866// //   });
4867// //     },
4868// //
4869// //     put: function( concept, data, filter ){
4870// //
4871// //   var target = this.get( concept, filter );
4872// //
4873// //   if( target )
4874// //       data = $.extend( target, data );
4875// //       
4876// //   this.storage.set( concept, data );
4877// //   
4878// //   //diff
4879// //     },
4880// //     
4881// //     post: function( concept, data, filter ){
4882// //
4883// //   
4884// //
4885// //     },
4886// //     
4887// //     pool: function(){
4888// //       
4889// //     },
4890// //     
4891// //     queue: function(){
4892// //       
4893// //     },
4894// //     
4895// //     dequeue: function(){
4896// //       
4897// //     },
4898// //     
4899// //     refresh: function(){
4900// //       
4901// //     }
4902// // }
4903//
4904// // var DataLayer = {
4905//   
4906// //       cache: {},
4907//   
4908// //       get: function( concept, location ){
4909//     
4910//         /* if( location )
4911//          {*/
4912// //           var schema = $.data( this.cache, concept + ':schema' );
4913// //           var uri = [];
4914// //
4915// //           $.each( schema, function( i, addrs ){
4916// //                 uri[ uri.length ] = location[addrs];
4917// //           });
4918//
4919//              /*var filter = [], result = false;
4920//
4921//              while( !(result = $.data( this.cache, uri.join( '.' ) )) || !(uri = uri.join('.')) )
4922//                filter[ filter.length ] = uri.pop();
4923//   
4924//              if( !filter.length )
4925//              {
4926//                  var indexes = $.data( this.cache, uri + ':indexes' );
4927//
4928//                  if( indexes )
4929//                      Array.prototype.concat.apply( result, indexes );
4930//                 
4931//                  return( result );
4932//              }
4933//
4934//              for( var i = 0; i < result.length; i++ )
4935//              {
4936//                 
4937//              }
4938//
4939//              if( result.length )
4940//                  return( result );
4941//          }*/
4942//
4943// //       var data = $.data( this.cache, concept );
4944//
4945// //       if( !data )
4946// //           $.ajax( );
4947//
4948// //       return( data );
4949// //       },
4950//       
4951// //       data: function(){
4952// //
4953// //     
4954// //
4955// //       }
4956// //       
4957// //       search: function( concept, filter ){
4958// //
4959// //     var schema = $.data( this.cache, concept + ':schema' );
4960// //     var uri = [];
4961// //
4962// //     $.each( schema, function( i, addrs ){
4963// //           uri[ uri.length ] = location[addrs];
4964// //     });
4965// //       }
4966// //       put: function( concept, data, location ){
4967//
4968// //       if( location )
4969// //       {
4970// //           var schema = $.data( this.cache, concept + ':schema');
4971// //           var uri = [];
4972//
4973// //           $.each( schema, function( i, addrs ){
4974// //                 uri[ uri.length ] = location[addrs];
4975// //           });
4976//
4977// //           var result = false, filter = [];
4978//
4979// //           while( !(result = $.data( this.cache, uri.join('.')) )
4980// //               filter[ filter.length ] = uri.pop();
4981//
4982// //           $.data( this.cache, '
4983//
4984// //       }
4985//
4986// //           var model = this.storage.get( concept );
4987// //
4988// //           $.each( model, function( i, o ){
4989// //               $.each( location, function( ii, attr ){
4990// //                    if( o[ii] === attr )
4991// //                       return( false );
4992// //               });
4993// //           });
4994//
4995// //       return $.data( this.cache, concept, data );
4996//
4997// //       },
4998// //       del: function( concept, location ){
4999// //
5000// //       if( location )
5001// //       {
5002// //           var schema = $.data( this.cache, 'concepts', concept );
5003// //           var uri = [];
5004// //
5005// //           $.each( schema, function( i, addrs ){
5006// //                 uri[ uri.length ] = location[addrs];
5007// //           });
5008// //
5009// //           concept = uri.join( '.' );
5010//
5011// //           var model = this.storage.get( concept );
5012// //
5013// //           $.each( model, function( i, o ){
5014// //               $.each( location, function( ii, attr ){
5015// //                    if( o[ii] === attr )
5016// //                       return( false );
5017// //               });
5018// //           });
5019// //       }
5020// //       
5021// //   
5022// //       $.removeData( this.cache, concept );
5023// //       }
5024// // }
Note: See TracBrowser for help on using the repository browser.