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

Revision 6443, 126.2 KB checked in by natan, 12 years ago (diff)

Ticket #2845 - Atualizacao da API na busca de mensagens - Implementacao do lyfecycle na API atual

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