source: sandbox/2.4.1-3/prototype/api/datalayer.js @ 6523

Revision 6523, 126.2 KB checked in by acoutinho, 12 years ago (diff)

Ticket #2766 - Melhorias e correcoes na api rest, criacao de novo cliente

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