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

Revision 5601, 121.5 KB checked in by airton, 12 years ago (diff)

Ticket #2088 - Melhorias no editor de regras de filtro de mensagens do Expresso - Pequenas correcoes

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