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

Revision 8218, 126.3 KB checked in by cristiano, 11 years ago (diff)

Ticket #3472 - Inconsistencia no cache do datalayer ao cancelar criação de evento

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