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

Revision 5531, 121.5 KB checked in by acoutinho, 12 years ago (diff)

Ticket #2434 - Correcoes de bugs e estabilizacao da troca de views

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