source: branches/2.4/prototype/api/datalayer.js @ 6453

Revision 6453, 125.4 KB checked in by eduardow, 12 years ago (diff)

Ticket #2846 - Melhorias e inconsistências gerais no modulo Expresso Calendar.

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