source: sandbox/2.5.1-evolucao/prototype/api/datalayer.js @ 8261

Revision 8261, 126.3 KB checked in by angelo, 10 years ago (diff)

Ticket #0000 - sincronizacao parcial das alteracoes do trunk com este sandbox

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