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

Revision 5514, 121.2 KB checked in by acoutinho, 12 years ago (diff)

Ticket #2434 - Implementacao anexos, acls e delegacao de participantes

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